From b3feddfef372618c8a9d7a0abcaf18cfad866c18 Mon Sep 17 00:00:00 2001 From: daoge <3523206925@qq.com> Date: Tue, 3 Mar 2026 03:04:10 +0800 Subject: feat: TU19 (Dec 2014) Features & Content (#155) * try to resolve merge conflict * feat: TU19 (Dec 2014) Features & Content (#32) * December 2014 files * Working release build * Fix compilation issues * Add sound to Windows64Media * Add DLC content and force Tutorial DLC * Revert "Add DLC content and force Tutorial DLC" This reverts commit 97a43994725008e35fceb984d5549df9c8cea470. * Disable broken light packing * Disable breakpoint during DLC texture map load Allows DLC loading but the DLC textures are still broken * Fix post build not working * ... * fix vs2022 build * fix cmake build --------- Co-authored-by: Loki --- Minecraft.World/AABB.cpp | 310 +-- Minecraft.World/AABB.h | 2 +- Minecraft.World/Abilities.cpp | 4 +- Minecraft.World/AbsoptionMobEffect.cpp | 20 + Minecraft.World/AbsoptionMobEffect.h | 14 + Minecraft.World/AbstractContainerMenu.cpp | 344 +++- Minecraft.World/AbstractContainerMenu.h | 56 +- .../AbstractProjectileDispenseBehavior.cpp | 48 + .../AbstractProjectileDispenseBehavior.h | 17 + Minecraft.World/AddEntityPacket.h | 33 +- Minecraft.World/AddGlobalEntityPacket.cpp | 6 +- Minecraft.World/AddMobPacket.cpp | 2 +- Minecraft.World/AddMobPacket.h | 4 +- Minecraft.World/AddPlayerPacket.cpp | 2 +- Minecraft.World/AgableMob.cpp | 50 +- Minecraft.World/AgableMob.h | 7 +- Minecraft.World/AmbientCreature.cpp | 17 + Minecraft.World/AmbientCreature.h | 16 + Minecraft.World/Animal.cpp | 85 +- Minecraft.World/Animal.h | 6 +- Minecraft.World/AnimalChest.cpp | 11 + Minecraft.World/AnimalChest.h | 10 + Minecraft.World/AnvilMenu.cpp | 426 +++++ Minecraft.World/AnvilMenu.h | 55 + Minecraft.World/AnvilTile.cpp | 10 +- Minecraft.World/AnvilTile.h | 2 +- Minecraft.World/ArmorDyeRecipe.cpp | 8 +- Minecraft.World/ArmorItem.cpp | 43 +- Minecraft.World/ArmorItem.h | 35 +- Minecraft.World/ArmorRecipes.cpp | 16 +- Minecraft.World/ArmorSlot.cpp | 4 + Minecraft.World/ArrayWithLength.h | 1 + Minecraft.World/Arrow.cpp | 110 +- Minecraft.World/Arrow.h | 44 +- Minecraft.World/AttackDamageMobEffect.cpp | 19 + Minecraft.World/AttackDamageMobEffect.h | 13 + Minecraft.World/Attribute.cpp | 18 + Minecraft.World/Attribute.h | 71 + Minecraft.World/AttributeInstance.h | 22 + Minecraft.World/AttributeModifier.cpp | 129 ++ Minecraft.World/AttributeModifier.h | 69 + Minecraft.World/AvoidPlayerGoal.cpp | 29 +- Minecraft.World/AvoidPlayerGoal.h | 18 +- Minecraft.World/BaseAttribute.cpp | 31 + Minecraft.World/BaseAttribute.h | 20 + Minecraft.World/BaseAttributeMap.cpp | 82 + Minecraft.World/BaseAttributeMap.h | 29 + Minecraft.World/BaseEntityTile.cpp | 33 + Minecraft.World/BaseEntityTile.h | 15 + Minecraft.World/BaseMobSpawner.cpp | 401 ++++ Minecraft.World/BaseMobSpawner.h | 70 + Minecraft.World/BasePressurePlateTile.cpp | 189 ++ Minecraft.World/BasePressurePlateTile.h | 55 + Minecraft.World/BaseRailTile.cpp | 511 +++++ Minecraft.World/BaseRailTile.h | 89 + Minecraft.World/BasicTypeContainers.cpp | 2 + Minecraft.World/BasicTypeContainers.h | 1 + Minecraft.World/Bat.cpp | 258 +++ Minecraft.World/Bat.h | 58 + Minecraft.World/BeachBiome.cpp | 4 +- Minecraft.World/BeaconMenu.cpp | 140 ++ Minecraft.World/BeaconMenu.h | 44 + Minecraft.World/BeaconTile.cpp | 64 + Minecraft.World/BeaconTile.h | 19 + Minecraft.World/BeaconTileEntity.cpp | 372 ++++ Minecraft.World/BeaconTileEntity.h | 75 + Minecraft.World/BedItem.cpp | 8 +- Minecraft.World/BedTile.cpp | 238 +-- Minecraft.World/BedTile.h | 33 +- Minecraft.World/Behavior.h | 5 + Minecraft.World/BehaviorRegistry.cpp | 30 + Minecraft.World/BehaviorRegistry.h | 17 + Minecraft.World/Biome.cpp | 95 +- Minecraft.World/Biome.h | 77 +- Minecraft.World/BiomeDecorator.cpp | 30 +- Minecraft.World/BiomeSource.cpp | 67 +- Minecraft.World/BirchFeature.cpp | 79 +- Minecraft.World/Blaze.cpp | 18 +- Minecraft.World/Blaze.h | 2 +- Minecraft.World/BlockRegionUpdatePacket.cpp | 16 +- Minecraft.World/BlockSource.h | 36 + Minecraft.World/BlockSourceImpl.cpp | 68 + Minecraft.World/BlockSourceImpl.h | 29 + Minecraft.World/Boat.cpp | 62 +- Minecraft.World/Boat.h | 6 +- Minecraft.World/BoatItem.cpp | 32 +- Minecraft.World/BoatItem.h | 2 +- Minecraft.World/BodyControl.cpp | 2 +- Minecraft.World/BodyControl.h | 4 +- Minecraft.World/BonusChestFeature.cpp | 48 +- Minecraft.World/BossMob.h | 21 +- Minecraft.World/BottleItem.cpp | 6 +- Minecraft.World/BottleItem.h | 2 +- Minecraft.World/BoundingBox.cpp | 129 +- Minecraft.World/BoundingBox.h | 4 + Minecraft.World/BowItem.cpp | 4 +- Minecraft.World/BreakDoorGoal.cpp | 3 +- Minecraft.World/BreedGoal.cpp | 21 +- Minecraft.World/BreedGoal.h | 4 +- Minecraft.World/BrewingStandMenu.cpp | 22 +- Minecraft.World/BrewingStandTile.cpp | 109 +- Minecraft.World/BrewingStandTile.h | 33 +- Minecraft.World/BrewingStandTileEntity.cpp | 373 ++-- Minecraft.World/BrewingStandTileEntity.h | 51 +- Minecraft.World/BucketItem.cpp | 89 +- Minecraft.World/BucketItem.h | 15 +- Minecraft.World/Bush.cpp | 18 +- Minecraft.World/ButtonTile.cpp | 216 +-- Minecraft.World/ButtonTile.h | 36 +- Minecraft.World/ByteArrayTag.h | 10 +- Minecraft.World/ByteTag.h | 2 +- Minecraft.World/C4JThread.h | 9 + Minecraft.World/CactusFeature.cpp | 28 +- Minecraft.World/CactusTile.cpp | 49 +- Minecraft.World/CakeTile.cpp | 77 +- Minecraft.World/Calendar.cpp | 19 + Minecraft.World/Calendar.h | 10 + Minecraft.World/CanyonFeature.cpp | 168 +- Minecraft.World/CarrotOnAStickItem.cpp | 2 +- Minecraft.World/CarrotTile.cpp | 2 +- Minecraft.World/CauldronTile.cpp | 111 +- Minecraft.World/CauldronTile.h | 9 +- Minecraft.World/CaveFeature.cpp | 104 +- Minecraft.World/CaveSpider.cpp | 25 +- Minecraft.World/CaveSpider.h | 20 +- Minecraft.World/ChatPacket.cpp | 28 +- Minecraft.World/ChatPacket.h | 33 +- Minecraft.World/ChestTile.cpp | 312 +-- Minecraft.World/ChestTile.h | 40 +- Minecraft.World/ChestTileEntity.cpp | 279 ++- Minecraft.World/ChestTileEntity.h | 48 +- Minecraft.World/Chicken.cpp | 37 +- Minecraft.World/Chicken.h | 7 +- Minecraft.World/ChunkSource.h | 51 +- Minecraft.World/Class.h | 662 +++++-- Minecraft.World/ClassDiagram.cd | 2 + Minecraft.World/ClayFeature.cpp | 34 +- Minecraft.World/ClientInformationPacket.h | 11 +- Minecraft.World/ClientSideMerchant.cpp | 4 +- Minecraft.World/ClientSideMerchant.h | 22 +- Minecraft.World/ClothDyeRecipes.cpp | 126 +- Minecraft.World/CoalItem.cpp | 19 +- Minecraft.World/CoalItem.h | 6 + Minecraft.World/CocoaTile.cpp | 10 +- Minecraft.World/CocoaTile.h | 2 +- Minecraft.World/ColoredTile.cpp | 36 + Minecraft.World/ColoredTile.h | 21 + Minecraft.World/CombatEntry.cpp | 71 + Minecraft.World/CombatEntry.h | 29 + Minecraft.World/CombatTracker.cpp | 252 +++ Minecraft.World/CombatTracker.h | 54 + Minecraft.World/Command.cpp | 5 + Minecraft.World/Command.h | 13 + Minecraft.World/CommandBlock.cpp | 96 + Minecraft.World/CommandBlock.h | 22 + Minecraft.World/CommandBlockEntity.cpp | 121 ++ Minecraft.World/CommandBlockEntity.h | 41 + Minecraft.World/CommandDispatcher.cpp | 4 +- Minecraft.World/CommandDispatcher.h | 2 +- Minecraft.World/CommandsEnum.h | 1 + Minecraft.World/CommonStats.cpp | 4 +- Minecraft.World/ComparatorTile.cpp | 253 +++ Minecraft.World/ComparatorTile.h | 60 + Minecraft.World/ComparatorTileEntity.cpp | 36 + Minecraft.World/ComparatorTileEntity.h | 22 + Minecraft.World/ComplexItemDataPacket.cpp | 4 +- Minecraft.World/CompoundContainer.cpp | 35 +- Minecraft.World/CompoundContainer.h | 30 +- Minecraft.World/CompoundTag.h | 226 +-- Minecraft.World/CompressedTileStorage.cpp | 1 + Minecraft.World/Connection.cpp | 37 +- Minecraft.World/ConsoleSaveFileConverter.cpp | 13 +- Minecraft.World/ConsoleSaveFileOriginal.cpp | 9 + Minecraft.World/ConsoleSaveFileSplit.cpp | 1711 ----------------- Minecraft.World/ConsoleSaveFileSplit.h | 143 -- Minecraft.World/Container.h | 24 +- Minecraft.World/ContainerClickPacket.cpp | 10 +- Minecraft.World/ContainerClickPacket.h | 4 +- Minecraft.World/ContainerMenu.cpp | 19 +- Minecraft.World/ContainerMenu.h | 5 +- Minecraft.World/ContainerOpenPacket.cpp | 54 +- Minecraft.World/ContainerOpenPacket.h | 20 +- Minecraft.World/ControlledByPlayerGoal.cpp | 10 +- Minecraft.World/ControlledByPlayerGoal.h | 5 + Minecraft.World/Cow.cpp | 44 +- Minecraft.World/Cow.h | 5 +- Minecraft.World/CraftingContainer.cpp | 19 +- Minecraft.World/CraftingContainer.h | 5 +- Minecraft.World/CraftingMenu.cpp | 13 +- Minecraft.World/CraftingMenu.h | 5 + Minecraft.World/Creeper.cpp | 119 +- Minecraft.World/Creeper.h | 24 +- Minecraft.World/CropTile.cpp | 29 +- Minecraft.World/CropTile.h | 20 +- Minecraft.World/CustomLevelSource.cpp | 45 +- Minecraft.World/CustomLevelSource.h | 3 + Minecraft.World/DamageEnchantment.cpp | 8 +- Minecraft.World/DamageEnchantment.h | 2 +- Minecraft.World/DamageSource.cpp | 84 +- Minecraft.World/DamageSource.h | 21 +- Minecraft.World/DataInputStream.cpp | 7 + Minecraft.World/DataInputStream.h | 1 + Minecraft.World/DataOutputStream.cpp | 8 + Minecraft.World/DataOutputStream.h | 1 + Minecraft.World/DaylightDetectorTile.cpp | 114 ++ Minecraft.World/DaylightDetectorTile.h | 27 + Minecraft.World/DaylightDetectorTileEntity.cpp | 29 + Minecraft.World/DaylightDetectorTileEntity.h | 16 + Minecraft.World/DeadBushFeature.cpp | 28 +- Minecraft.World/DefaultDispenseItemBehavior.cpp | 82 + Minecraft.World/DefaultDispenseItemBehavior.h | 40 + Minecraft.World/DefaultGameModeCommand.cpp | 19 +- Minecraft.World/DefendVillageTargetGoal.cpp | 20 +- Minecraft.World/DefendVillageTargetGoal.h | 2 +- Minecraft.World/DelayedRelease.cpp | 2 +- Minecraft.World/DelayedRelease.h | 2 +- Minecraft.World/DerivedLevelData.cpp | 20 +- Minecraft.World/DerivedLevelData.h | 9 +- Minecraft.World/DesertBiome.cpp | 4 +- Minecraft.World/DesertWellFeature.cpp | 34 +- Minecraft.World/DetectorRailTile.cpp | 117 +- Minecraft.World/DetectorRailTile.h | 14 +- Minecraft.World/DiggerItem.cpp | 26 +- Minecraft.World/DiggerItem.h | 10 +- Minecraft.World/Dimension.cpp | 145 +- Minecraft.World/Dimension.h | 45 +- Minecraft.World/DiodeTile.cpp | 285 +-- Minecraft.World/DiodeTile.h | 90 +- Minecraft.World/Direction.cpp | 80 +- Minecraft.World/Direction.h | 31 +- Minecraft.World/DirectionalTile.cpp | 4 - Minecraft.World/DirectionalTile.h | 1 - Minecraft.World/DirectoryLevelStorage.cpp | 35 +- Minecraft.World/DirectoryLevelStorage.h | 2 +- Minecraft.World/DispenseItemBehavior.cpp | 10 + Minecraft.World/DispenseItemBehavior.h | 29 + Minecraft.World/DispenserTile.cpp | 448 +---- Minecraft.World/DispenserTile.h | 41 +- Minecraft.World/DispenserTileEntity.cpp | 105 +- Minecraft.World/DispenserTileEntity.h | 23 +- Minecraft.World/DoorItem.cpp | 8 +- Minecraft.World/DoorTile.cpp | 60 +- Minecraft.World/DoorTile.h | 15 +- Minecraft.World/DoubleTag.h | 2 +- Minecraft.World/DragonFireball.cpp | 21 +- Minecraft.World/DragonFireball.h | 9 +- Minecraft.World/DropperTile.cpp | 74 + Minecraft.World/DropperTile.h | 23 + Minecraft.World/DropperTileEntity.cpp | 19 + Minecraft.World/DropperTileEntity.h | 15 + Minecraft.World/DummyCriteria.cpp | 24 + Minecraft.World/DummyCriteria.h | 16 + Minecraft.World/DungeonFeature.cpp | 248 +-- Minecraft.World/DurangoStats.cpp | 22 +- Minecraft.World/DyePowderItem.cpp | 277 +-- Minecraft.World/DyePowderItem.h | 4 +- Minecraft.World/EatTileGoal.cpp | 7 +- Minecraft.World/EffectCommand.cpp | 86 + Minecraft.World/EffectCommand.h | 18 + Minecraft.World/EggItem.cpp | 8 +- Minecraft.World/EggTile.cpp | 64 +- Minecraft.World/EggTile.h | 18 +- Minecraft.World/EmptyLevelChunk.cpp | 35 +- Minecraft.World/EmptyLevelChunk.h | 5 +- Minecraft.World/EmptyMapItem.cpp | 43 + Minecraft.World/EmptyMapItem.h | 11 + Minecraft.World/EnchantItemCommand.cpp | 2 +- Minecraft.World/EnchantedBookItem.cpp | 7 +- Minecraft.World/EnchantedBookItem.h | 2 +- Minecraft.World/Enchantment.cpp | 14 +- Minecraft.World/Enchantment.h | 4 +- Minecraft.World/EnchantmentContainer.cpp | 7 +- Minecraft.World/EnchantmentContainer.h | 1 + Minecraft.World/EnchantmentHelper.cpp | 53 +- Minecraft.World/EnchantmentHelper.h | 30 +- Minecraft.World/EnchantmentMenu.cpp | 16 +- Minecraft.World/EnchantmentTableEntity.cpp | 39 +- Minecraft.World/EnchantmentTableEntity.h | 17 +- Minecraft.World/EnchantmentTableTile.cpp | 56 +- Minecraft.World/EnchantmentTableTile.h | 24 +- Minecraft.World/EndPodiumFeature.cpp | 2 +- Minecraft.World/EndTag.h | 2 +- Minecraft.World/EnderChestTile.cpp | 6 +- Minecraft.World/EnderChestTile.h | 8 +- Minecraft.World/EnderChestTileEntity.cpp | 4 +- Minecraft.World/EnderChestTileEntity.h | 2 +- Minecraft.World/EnderCrystal.cpp | 10 +- Minecraft.World/EnderCrystal.h | 2 +- Minecraft.World/EnderDragon.cpp | 381 ++-- Minecraft.World/EnderDragon.h | 48 +- Minecraft.World/EnderEyeItem.cpp | 27 +- Minecraft.World/EnderEyeItem.h | 2 +- Minecraft.World/EnderMan.cpp | 140 +- Minecraft.World/EnderMan.h | 10 +- Minecraft.World/EnderpearlItem.cpp | 6 +- Minecraft.World/EnderpearlItem.h | 2 +- Minecraft.World/Enemy.cpp | 11 +- Minecraft.World/Enemy.h | 21 +- Minecraft.World/Entity.cpp | 671 ++++--- Minecraft.World/Entity.h | 80 +- Minecraft.World/EntityActionAtPositionPacket.cpp | 2 +- Minecraft.World/EntityDamageSource.cpp | 37 +- Minecraft.World/EntityDamageSource.h | 8 +- Minecraft.World/EntityDiagram.cd | 805 ++++++++ Minecraft.World/EntityHorse.cpp | 1841 ++++++++++++++++++ Minecraft.World/EntityHorse.h | 342 ++++ Minecraft.World/EntityIO.cpp | 165 +- Minecraft.World/EntitySelector.cpp | 42 + Minecraft.World/EntitySelector.h | 32 + Minecraft.World/EntityTile.h | 10 +- Minecraft.World/ExperienceCommand.cpp | 68 +- Minecraft.World/ExperienceCommand.h | 4 +- Minecraft.World/ExperienceItem.cpp | 4 +- Minecraft.World/ExperienceItem.h | 2 +- Minecraft.World/ExperienceOrb.cpp | 7 +- Minecraft.World/ExperienceOrb.h | 2 +- Minecraft.World/Explosion.cpp | 145 +- Minecraft.World/Explosion.h | 1 + Minecraft.World/ExtremeHillsBiome.cpp | 18 +- Minecraft.World/ExtremeHillsBiome.h | 2 + Minecraft.World/EyeOfEnderSignal.cpp | 12 +- Minecraft.World/Facing.cpp | 2 + Minecraft.World/Facing.h | 14 +- Minecraft.World/FacingEnum.cpp | 47 + Minecraft.World/FacingEnum.h | 31 + Minecraft.World/FallingTile.cpp | 57 +- Minecraft.World/FallingTile.h | 4 + Minecraft.World/FarmTile.cpp | 102 +- Minecraft.World/Feature.cpp | 11 +- Minecraft.World/Feature.h | 2 + Minecraft.World/FenceGateTile.cpp | 53 +- Minecraft.World/FenceGateTile.h | 22 +- Minecraft.World/FenceTile.cpp | 146 +- Minecraft.World/FenceTile.h | 8 +- Minecraft.World/File.cpp | 2 +- Minecraft.World/FileHeader.cpp | 1 + Minecraft.World/FileHeader.h | 6 + Minecraft.World/FireChargeItem.cpp | 10 +- Minecraft.World/FireTile.cpp | 55 +- Minecraft.World/FireTile.h | 42 +- Minecraft.World/Fireball.cpp | 77 +- Minecraft.World/Fireball.h | 16 +- Minecraft.World/FireworksChargeItem.cpp | 211 ++ Minecraft.World/FireworksChargeItem.h | 24 + Minecraft.World/FireworksItem.cpp | 81 + Minecraft.World/FireworksItem.h | 31 + Minecraft.World/FireworksMenu.cpp | 150 ++ Minecraft.World/FireworksMenu.h | 43 + Minecraft.World/FireworksRecipe.cpp | 418 ++++ Minecraft.World/FireworksRecipe.h | 46 + Minecraft.World/FireworksRocketEntity.cpp | 181 ++ Minecraft.World/FireworksRocketEntity.h | 38 + Minecraft.World/FishingHook.cpp | 30 +- Minecraft.World/FishingRodItem.cpp | 10 +- Minecraft.World/FishingRodItem.h | 4 - Minecraft.World/FixedBiomeSource.cpp | 6 +- Minecraft.World/FlatGeneratorInfo.cpp | 250 +++ Minecraft.World/FlatGeneratorInfo.h | 41 + Minecraft.World/FlatLayerInfo.cpp | 78 + Minecraft.World/FlatLayerInfo.h | 26 + Minecraft.World/FlatLevelSource.cpp | 7 +- Minecraft.World/FlatLevelSource.h | 1 + Minecraft.World/FleeSunGoal.cpp | 6 +- Minecraft.World/FleeSunGoal.h | 4 +- Minecraft.World/FlintAndSteelItem.cpp | 8 +- Minecraft.World/FloatTag.h | 2 +- Minecraft.World/FlowerFeature.cpp | 23 +- Minecraft.World/FlowerPotTile.cpp | 12 +- Minecraft.World/FlyingMob.cpp | 6 + Minecraft.World/FlyingMob.h | 1 + Minecraft.World/FollowOwnerGoal.cpp | 15 +- Minecraft.World/FollowOwnerGoal.h | 6 +- Minecraft.World/FollowParentGoal.cpp | 6 +- Minecraft.World/FollowParentGoal.h | 4 +- Minecraft.World/FoodConstants.cpp | 1 + Minecraft.World/FoodConstants.h | 53 +- Minecraft.World/FoodData.cpp | 21 +- Minecraft.World/FoodItem.cpp | 2 +- Minecraft.World/FoodRecipies.cpp | 62 +- Minecraft.World/FurnaceMenu.cpp | 10 +- Minecraft.World/FurnaceMenu.h | 3 +- Minecraft.World/FurnaceRecipes.cpp | 6 +- Minecraft.World/FurnaceTile.cpp | 55 +- Minecraft.World/FurnaceTile.h | 26 +- Minecraft.World/FurnaceTileEntity.cpp | 164 +- Minecraft.World/FurnaceTileEntity.h | 40 +- Minecraft.World/GameDifficultyCommand.h | 75 + Minecraft.World/GameModeCommand.cpp | 29 +- Minecraft.World/GameModeCommand.h | 2 +- Minecraft.World/GameRuleCommand.h | 83 + Minecraft.World/GameRules.cpp | 193 ++ Minecraft.World/GameRules.h | 56 + Minecraft.World/Ghast.cpp | 210 +- Minecraft.World/Ghast.h | 17 +- Minecraft.World/Giant.cpp | 21 +- Minecraft.World/Giant.h | 7 +- Minecraft.World/GiveItemCommand.cpp | 11 +- Minecraft.World/GiveItemCommand.h | 1 + Minecraft.World/GlowstoneTile.cpp | 22 + Minecraft.World/GlowstoneTile.h | 13 + Minecraft.World/GoalSelector.cpp | 27 + Minecraft.World/GoalSelector.h | 1 + Minecraft.World/GoldenAppleItem.cpp | 4 +- Minecraft.World/GrassTile.cpp | 40 +- Minecraft.World/GravelTile.cpp | 5 +- Minecraft.World/GroundBushFeature.cpp | 4 +- Minecraft.World/HalfSlabTile.cpp | 79 +- Minecraft.World/HalfSlabTile.h | 8 +- Minecraft.World/HalfTransparentTile.h | 2 +- Minecraft.World/HangingEntity.cpp | 38 +- Minecraft.World/HangingEntity.h | 14 +- Minecraft.World/HangingEntityItem.cpp | 47 +- Minecraft.World/HangingEntityItem.h | 4 +- Minecraft.World/Hasher.cpp | 4 +- Minecraft.World/HatchetItem.cpp | 2 +- Minecraft.World/HayBlockTile.cpp | 23 + Minecraft.World/HayBlockTile.h | 18 + Minecraft.World/HealthBoostMobEffect.cpp | 16 + Minecraft.World/HealthBoostMobEffect.h | 14 + Minecraft.World/HealthCriteria.cpp | 27 + Minecraft.World/HealthCriteria.h | 12 + Minecraft.World/HeavyTile.cpp | 57 +- Minecraft.World/HeavyTile.h | 14 +- Minecraft.World/HellBiome.cpp | 11 +- Minecraft.World/HellFireFeature.cpp | 18 +- Minecraft.World/HellFlatLevelSource.cpp | 104 +- Minecraft.World/HellFlatLevelSource.h | 21 +- Minecraft.World/HellPortalFeature.cpp | 44 +- Minecraft.World/HellRandomLevelSource.cpp | 543 +++--- Minecraft.World/HellRandomLevelSource.h | 33 +- Minecraft.World/HellSpringFeature.cpp | 51 +- Minecraft.World/HellSpringFeature.h | 5 +- Minecraft.World/HitResult.cpp | 4 +- Minecraft.World/HoeItem.cpp | 8 +- Minecraft.World/Hopper.h | 14 + Minecraft.World/HopperMenu.cpp | 76 + Minecraft.World/HopperMenu.h | 24 + Minecraft.World/HopperTile.cpp | 211 ++ Minecraft.World/HopperTile.h | 56 + Minecraft.World/HopperTileEntity.cpp | 505 +++++ Minecraft.World/HopperTileEntity.h | 80 + Minecraft.World/HorseInventoryMenu.cpp | 132 ++ Minecraft.World/HorseInventoryMenu.h | 41 + Minecraft.World/HouseFeature.cpp | 263 +-- Minecraft.World/HtmlString.cpp | 57 + Minecraft.World/HtmlString.h | 16 + Minecraft.World/HugeMushroomFeature.cpp | 128 +- Minecraft.World/HugeMushroomTile.cpp | 58 +- Minecraft.World/HugeMushroomTile.h | 9 +- Minecraft.World/HurtByTargetGoal.cpp | 22 +- Minecraft.World/HurtByTargetGoal.h | 5 +- Minecraft.World/IceTile.cpp | 12 +- Minecraft.World/IndirectEntityDamageSource.cpp | 20 +- Minecraft.World/IndirectEntityDamageSource.h | 6 +- Minecraft.World/InputStream.cpp | 4 +- Minecraft.World/IntArrayTag.h | 10 +- Minecraft.World/IntTag.h | 2 +- Minecraft.World/Inventory.cpp | 86 +- Minecraft.World/Inventory.h | 44 +- Minecraft.World/InventoryMenu.cpp | 21 +- Minecraft.World/InventoryMenu.h | 3 +- Minecraft.World/Item.cpp | 448 +++-- Minecraft.World/Item.h | 117 +- Minecraft.World/ItemDispenseBehaviors.cpp | 457 +++++ Minecraft.World/ItemDispenseBehaviors.h | 117 ++ Minecraft.World/ItemEntity.cpp | 19 +- Minecraft.World/ItemEntity.h | 4 +- Minecraft.World/ItemFrame.cpp | 56 +- Minecraft.World/ItemFrame.h | 11 +- Minecraft.World/ItemInstance.cpp | 504 +++-- Minecraft.World/ItemInstance.h | 52 +- Minecraft.World/JukeboxTile.cpp | 167 ++ Minecraft.World/JukeboxTile.h | 55 + Minecraft.World/JungleBiome.cpp | 2 +- Minecraft.World/KillCommand.cpp | 9 +- Minecraft.World/KillCommand.h | 1 + Minecraft.World/LadderTile.cpp | 58 +- Minecraft.World/LakeFeature.cpp | 179 +- Minecraft.World/LargeCaveFeature.cpp | 250 +-- Minecraft.World/LargeFireball.cpp | 47 + Minecraft.World/LargeFireball.h | 24 + Minecraft.World/LargeHellCaveFeature.cpp | 247 ++- Minecraft.World/LargeHellCaveFeature.h | 4 +- Minecraft.World/LavaSlime.cpp | 21 +- Minecraft.World/LavaSlime.h | 4 + Minecraft.World/Layer.cpp | 2 +- Minecraft.World/LeafTile.cpp | 259 +-- Minecraft.World/LeapAtTargetGoal.cpp | 4 +- Minecraft.World/LeapAtTargetGoal.h | 2 +- Minecraft.World/LeashFenceKnotEntity.cpp | 157 ++ Minecraft.World/LeashFenceKnotEntity.h | 36 + Minecraft.World/LeashItem.cpp | 74 + Minecraft.World/LeashItem.h | 13 + Minecraft.World/Level.cpp | 1628 ++++++++-------- Minecraft.World/Level.h | 119 +- Minecraft.World/LevelChunk.cpp | 851 +++++---- Minecraft.World/LevelChunk.h | 118 +- Minecraft.World/LevelData.cpp | 424 +++-- Minecraft.World/LevelData.h | 174 +- Minecraft.World/LevelEvent.h | 33 +- Minecraft.World/LevelEventPacket.cpp | 9 +- Minecraft.World/LevelEventPacket.h | 4 +- Minecraft.World/LevelListener.h | 4 +- Minecraft.World/LevelParticlesPacket.cpp | 110 ++ Minecraft.World/LevelParticlesPacket.h | 39 + Minecraft.World/LevelSettings.cpp | 16 +- Minecraft.World/LevelSettings.h | 7 +- Minecraft.World/LevelSource.h | 1 + Minecraft.World/LevelType.cpp | 6 +- Minecraft.World/LevelType.h | 2 + Minecraft.World/LeverTile.cpp | 241 +-- Minecraft.World/LeverTile.h | 30 +- Minecraft.World/LightGemFeature.cpp | 44 +- Minecraft.World/LightningBolt.cpp | 69 +- Minecraft.World/LiquidTile.cpp | 357 ++-- Minecraft.World/LiquidTile.h | 10 +- Minecraft.World/LiquidTileDynamic.cpp | 343 ++-- Minecraft.World/LiquidTileDynamic.h | 11 +- Minecraft.World/LiquidTileStatic.cpp | 60 +- Minecraft.World/ListTag.h | 84 +- Minecraft.World/LivingEntity.cpp | 2005 ++++++++++++++++++++ Minecraft.World/LivingEntity.h | 323 ++++ Minecraft.World/LocatableSource.h | 8 + Minecraft.World/Location.h | 11 + Minecraft.World/LockedChestTile.cpp | 2 +- Minecraft.World/LongTag.h | 2 +- Minecraft.World/LookAtPlayerGoal.cpp | 17 +- Minecraft.World/LookControl.cpp | 15 +- Minecraft.World/MakeLoveGoal.cpp | 8 +- Minecraft.World/MapCloningRecipe.h | 63 + Minecraft.World/MapExtendingRecipe.h | 46 + Minecraft.World/MapItem.cpp | 55 +- Minecraft.World/MapItem.h | 2 +- Minecraft.World/MapItemSavedData.cpp | 50 +- Minecraft.World/MapItemSavedData.h | 14 +- Minecraft.World/McRegionChunkStorage.cpp | 7 + Minecraft.World/MegaTreeFeature.cpp | 10 +- Minecraft.World/MeleeAttackGoal.cpp | 50 +- Minecraft.World/MeleeAttackGoal.h | 14 +- Minecraft.World/MelonTile.cpp | 7 +- Minecraft.World/MelonTile.h | 9 +- Minecraft.World/MenuBackup.cpp | 10 +- Minecraft.World/Merchant.h | 2 +- Minecraft.World/MerchantContainer.cpp | 17 +- Minecraft.World/MerchantContainer.h | 5 +- Minecraft.World/MerchantMenu.cpp | 2 +- Minecraft.World/MineShaftFeature.cpp | 28 +- Minecraft.World/MineShaftFeature.h | 13 + Minecraft.World/MineShaftPieces.cpp | 116 +- Minecraft.World/MineShaftPieces.h | 54 +- Minecraft.World/MineShaftStart.cpp | 7 +- Minecraft.World/MineShaftStart.h | 5 + Minecraft.World/Minecart.cpp | 1127 +++++------ Minecraft.World/Minecart.h | 94 +- Minecraft.World/MinecartChest.cpp | 51 + Minecraft.World/MinecartChest.h | 23 + Minecraft.World/MinecartContainer.cpp | 233 +++ Minecraft.World/MinecartContainer.h | 48 + Minecraft.World/MinecartFurnace.cpp | 179 ++ Minecraft.World/MinecartFurnace.h | 51 + Minecraft.World/MinecartHopper.cpp | 165 ++ Minecraft.World/MinecartHopper.h | 64 + Minecraft.World/MinecartItem.cpp | 69 +- Minecraft.World/MinecartItem.h | 14 + Minecraft.World/MinecartRideable.cpp | 39 + Minecraft.World/MinecartRideable.h | 17 + Minecraft.World/MinecartSpawner.cpp | 95 + Minecraft.World/MinecartSpawner.h | 45 + Minecraft.World/MinecartTNT.cpp | 168 ++ Minecraft.World/MinecartTNT.h | 43 + Minecraft.World/Minecraft.World.cpp | 68 +- Minecraft.World/Minecraft.World.vcxproj | 893 +++++++-- Minecraft.World/Minecraft.World.vcxproj.filters | 1311 ++++++++++--- Minecraft.World/Mob.cpp | 1980 ++++++------------- Minecraft.World/Mob.h | 323 +--- Minecraft.World/MobCategory.cpp | 34 +- Minecraft.World/MobCategory.h | 11 +- Minecraft.World/MobEffect.cpp | 199 +- Minecraft.World/MobEffect.h | 103 +- Minecraft.World/MobEffectInstance.cpp | 80 +- Minecraft.World/MobEffectInstance.h | 18 +- Minecraft.World/MobGroupData.h | 8 + Minecraft.World/MobSpawner.cpp | 191 +- Minecraft.World/MobSpawner.h | 12 +- Minecraft.World/MobSpawnerTile.cpp | 2 +- Minecraft.World/MobSpawnerTile.h | 12 +- Minecraft.World/MobSpawnerTileEntity.cpp | 225 +-- Minecraft.World/MobSpawnerTileEntity.h | 50 +- Minecraft.World/ModifiableAttributeInstance.cpp | 185 ++ Minecraft.World/ModifiableAttributeInstance.h | 40 + Minecraft.World/Monster.cpp | 137 +- Minecraft.World/Monster.h | 20 +- Minecraft.World/MonsterRoomFeature.cpp | 68 +- Minecraft.World/MonsterRoomFeature.h | 9 +- Minecraft.World/MoveControl.cpp | 16 +- Minecraft.World/MoveControl.h | 6 +- Minecraft.World/MoveIndoorsGoal.cpp | 4 +- Minecraft.World/MoveThroughVillageGoal.cpp | 6 +- Minecraft.World/MoveThroughVillageGoal.h | 4 +- Minecraft.World/MoveTowardsRestrictionGoal.cpp | 6 +- Minecraft.World/MoveTowardsRestrictionGoal.h | 4 +- Minecraft.World/MoveTowardsTargetGoal.cpp | 8 +- Minecraft.World/MoveTowardsTargetGoal.h | 7 +- Minecraft.World/Mth.cpp | 131 +- Minecraft.World/Mth.h | 42 +- Minecraft.World/MultiEntityMob.h | 10 + Minecraft.World/MultiEntityMobPart.cpp | 42 + Minecraft.World/MultiEntityMobPart.h | 27 + Minecraft.World/MultiTextureTileItem.cpp | 29 +- Minecraft.World/MultiTextureTileItem.h | 3 +- Minecraft.World/Mushroom.cpp | 104 +- Minecraft.World/Mushroom.h | 7 +- Minecraft.World/MushroomCow.cpp | 21 +- Minecraft.World/MushroomCow.h | 2 +- Minecraft.World/MusicTileEntity.cpp | 6 +- Minecraft.World/MycelTile.cpp | 28 +- Minecraft.World/NameTagItem.cpp | 23 + Minecraft.World/NameTagItem.h | 11 + Minecraft.World/NearestAttackableTargetGoal.cpp | 60 +- Minecraft.World/NearestAttackableTargetGoal.h | 26 +- Minecraft.World/NetherBridgeFeature.cpp | 47 +- Minecraft.World/NetherBridgeFeature.h | 14 +- Minecraft.World/NetherBridgePieces.cpp | 252 ++- Minecraft.World/NetherBridgePieces.h | 466 +++-- Minecraft.World/NetherWartTile.cpp | 112 ++ Minecraft.World/NetherWartTile.h | 31 + Minecraft.World/NetherrackTile.cpp | 6 + Minecraft.World/NetherrackTile.h | 8 + Minecraft.World/NonTameRandomTargetGoal.cpp | 7 +- Minecraft.World/NonTameRandomTargetGoal.h | 2 +- Minecraft.World/NotGateTile.cpp | 216 +-- Minecraft.World/NotGateTile.h | 45 +- Minecraft.World/NoteBlockTile.cpp | 86 + Minecraft.World/NoteBlockTile.h | 16 + Minecraft.World/Objective.cpp | 38 + Minecraft.World/Objective.h | 26 + Minecraft.World/ObjectiveCriteria.cpp | 12 + Minecraft.World/ObjectiveCriteria.h | 17 + Minecraft.World/Ocelot.cpp | 361 ++++ Minecraft.World/Ocelot.h | 90 + Minecraft.World/OcelotAttackGoal.cpp | 61 + Minecraft.World/OcelotAttackGoal.h | 25 + Minecraft.World/OcelotSitOnTileGoal.cpp | 18 +- Minecraft.World/OcelotSitOnTileGoal.h | 8 +- Minecraft.World/OldChunkStorage.cpp | 52 +- Minecraft.World/OpenDoorGoal.cpp | 2 +- Minecraft.World/OreFeature.cpp | 104 +- Minecraft.World/OreRecipies.cpp | 34 +- Minecraft.World/OreRecipies.h | 4 +- Minecraft.World/OwnableEntity.h | 8 + Minecraft.World/OwnerHurtByTargetGoal.cpp | 17 +- Minecraft.World/OwnerHurtByTargetGoal.h | 3 +- Minecraft.World/OwnerHurtTargetGoal.cpp | 19 +- Minecraft.World/OwnerHurtTargetGoal.h | 3 +- Minecraft.World/Packet.cpp | 181 +- Minecraft.World/Packet.h | 28 +- Minecraft.World/PacketListener.cpp | 44 +- Minecraft.World/PacketListener.h | 23 +- Minecraft.World/Painting.cpp | 44 +- Minecraft.World/Painting.h | 9 +- Minecraft.World/PanicGoal.cpp | 8 +- Minecraft.World/PanicGoal.h | 4 +- Minecraft.World/ParticleTypes.h | 3 + Minecraft.World/PathFinder.cpp | 213 ++- Minecraft.World/PathFinder.h | 30 +- Minecraft.World/PathNavigation.cpp | 37 +- Minecraft.World/PathNavigation.h | 17 +- Minecraft.World/PathfinderMob.cpp | 133 +- Minecraft.World/PathfinderMob.h | 30 +- Minecraft.World/PickaxeItem.cpp | 60 +- Minecraft.World/PickaxeItem.h | 4 +- Minecraft.World/Pig.cpp | 47 +- Minecraft.World/Pig.h | 10 +- Minecraft.World/PigZombie.cpp | 159 +- Minecraft.World/PigZombie.h | 35 +- Minecraft.World/PistonBaseTile.cpp | 583 +++--- Minecraft.World/PistonBaseTile.h | 44 +- Minecraft.World/PistonExtensionTile.cpp | 226 ++- Minecraft.World/PistonExtensionTile.h | 35 +- Minecraft.World/PistonMovingPiece.cpp | 131 +- Minecraft.World/PistonMovingPiece.h | 32 +- Minecraft.World/PistonPieceEntity.cpp | 10 +- Minecraft.World/PlainsBiome.cpp | 2 + Minecraft.World/PlayGoal.cpp | 14 +- Minecraft.World/PlayGoal.h | 6 +- Minecraft.World/PlaySoundCommand.h | 88 + Minecraft.World/Player.cpp | 829 ++++---- Minecraft.World/Player.h | 157 +- Minecraft.World/PlayerAbilitiesPacket.cpp | 32 +- Minecraft.World/PlayerAbilitiesPacket.h | 1 - Minecraft.World/PlayerActionPacket.cpp | 8 +- Minecraft.World/PlayerActionPacket.h | 2 +- Minecraft.World/PlayerCommandPacket.cpp | 15 +- Minecraft.World/PlayerCommandPacket.h | 10 +- Minecraft.World/PlayerEnderChestContainer.cpp | 13 +- Minecraft.World/PlayerEnderChestContainer.h | 3 + Minecraft.World/PlayerIO.h | 2 +- Minecraft.World/PlayerInputPacket.cpp | 46 +- Minecraft.World/PlayerInputPacket.h | 14 +- Minecraft.World/PlayerSelector.h | 247 +++ Minecraft.World/PlayerTeam.cpp | 120 ++ Minecraft.World/PlayerTeam.h | 49 + Minecraft.World/PortalForcer.cpp | 263 ++- Minecraft.World/PortalForcer.h | 27 +- Minecraft.World/PortalTile.cpp | 222 +-- Minecraft.World/Pos.cpp | 67 +- Minecraft.World/Pos.h | 33 +- Minecraft.World/Position.h | 9 + Minecraft.World/PositionImpl.h | 34 + Minecraft.World/PotatoTile.cpp | 2 +- Minecraft.World/PotionBrewing.cpp | 15 +- Minecraft.World/PotionBrewing.h | 15 + Minecraft.World/PotionItem.cpp | 102 +- Minecraft.World/PotionItem.h | 4 +- Minecraft.World/PoweredMetalTile.cpp | 17 + Minecraft.World/PoweredMetalTile.h | 12 + Minecraft.World/PoweredRailTile.cpp | 187 ++ Minecraft.World/PoweredRailTile.h | 21 + Minecraft.World/PressurePlateTile.cpp | 215 +-- Minecraft.World/PressurePlateTile.h | 53 +- Minecraft.World/PrimedTnt.cpp | 14 +- Minecraft.World/PrimedTnt.h | 4 +- Minecraft.World/Projectile.h | 7 + Minecraft.World/ProtectionEnchantment.cpp | 6 +- Minecraft.World/PumpkinFeature.cpp | 22 +- Minecraft.World/PumpkinTile.cpp | 96 +- Minecraft.World/PumpkinTile.h | 8 +- Minecraft.World/QuartzBlockTile.cpp | 20 +- Minecraft.World/RailTile.cpp | 662 +------ Minecraft.World/RailTile.h | 82 +- Minecraft.World/RandomLevelSource.cpp | 768 ++++---- Minecraft.World/RandomLevelSource.h | 54 +- Minecraft.World/RandomScatteredLargeFeature.cpp | 96 +- Minecraft.World/RandomScatteredLargeFeature.h | 24 + Minecraft.World/RandomStrollGoal.cpp | 6 +- Minecraft.World/RandomStrollGoal.h | 4 +- Minecraft.World/RangedAttackGoal.cpp | 105 + Minecraft.World/RangedAttackGoal.h | 32 + Minecraft.World/RangedAttackMob.h | 7 + Minecraft.World/RangedAttribute.cpp | 31 + Minecraft.World/RangedAttribute.h | 21 + Minecraft.World/Recipes.cpp | 219 ++- Minecraft.World/Recipes.h | 6 +- Minecraft.World/RecordingItem.cpp | 34 +- Minecraft.World/RecordingItem.h | 8 +- Minecraft.World/RedStoneDustTile.cpp | 174 +- Minecraft.World/RedStoneDustTile.h | 34 +- Minecraft.World/RedStoneItem.cpp | 4 +- Minecraft.World/RedStoneOreTile.cpp | 10 +- Minecraft.World/RedStoneOreTile.h | 16 +- Minecraft.World/RedlightTile.cpp | 6 +- Minecraft.World/Redstone.cpp | 8 + Minecraft.World/Redstone.h | 9 + Minecraft.World/ReedTile.cpp | 12 +- Minecraft.World/ReedsFeature.cpp | 38 +- Minecraft.World/Region.cpp | 76 +- Minecraft.World/Region.h | 3 +- Minecraft.World/RegionFileCache.cpp | 6 + Minecraft.World/RegionFileCache.h | 1 + Minecraft.World/RepairContainer.cpp | 9 +- Minecraft.World/RepairContainer.h | 7 +- Minecraft.World/RepairResultSlot.cpp | 18 +- Minecraft.World/RepairResultSlot.h | 6 +- Minecraft.World/RepeaterTile.cpp | 132 ++ Minecraft.World/RepeaterTile.h | 40 + Minecraft.World/ResultContainer.cpp | 36 +- Minecraft.World/ResultContainer.h | 12 +- Minecraft.World/ResultSlot.cpp | 12 +- Minecraft.World/RotatedPillarTile.cpp | 77 + Minecraft.World/RotatedPillarTile.h | 35 + Minecraft.World/RunAroundLikeCrazyGoal.cpp | 62 + Minecraft.World/RunAroundLikeCrazyGoal.h | 21 + Minecraft.World/SaddleItem.cpp | 24 +- Minecraft.World/SaddleItem.h | 4 +- Minecraft.World/SandFeature.cpp | 38 +- Minecraft.World/Sapling.cpp | 65 +- Minecraft.World/Sapling.h | 10 +- Minecraft.World/SavedDataStorage.cpp | 4 + Minecraft.World/ScatteredFeaturePieces.cpp | 319 +++- Minecraft.World/ScatteredFeaturePieces.h | 50 +- Minecraft.World/Score.cpp | 68 + Minecraft.World/Score.h | 44 + Minecraft.World/ScoreHolder.h | 9 + Minecraft.World/Scoreboard.cpp | 328 ++++ Minecraft.World/Scoreboard.h | 59 + Minecraft.World/ScoreboardSaveData.h | 189 ++ Minecraft.World/SeedFoodItem.cpp | 4 +- Minecraft.World/SeedItem.cpp | 18 +- Minecraft.World/ServersideAttributeMap.cpp | 83 + Minecraft.World/ServersideAttributeMap.h | 24 + Minecraft.World/SetDisplayObjectivePacket.cpp | 46 + Minecraft.World/SetDisplayObjectivePacket.h | 24 + Minecraft.World/SetEntityDataPacket.cpp | 5 - Minecraft.World/SetEntityDataPacket.h | 1 - Minecraft.World/SetEntityLinkPacket.cpp | 57 + Minecraft.World/SetEntityLinkPacket.h | 29 + Minecraft.World/SetExperiencePacket.cpp | 5 - Minecraft.World/SetExperiencePacket.h | 1 - Minecraft.World/SetHealthPacket.cpp | 10 +- Minecraft.World/SetHealthPacket.h | 5 +- Minecraft.World/SetObjectivePacket.cpp | 42 + Minecraft.World/SetObjectivePacket.h | 28 + Minecraft.World/SetPlayerTeamPacket.cpp | 114 ++ Minecraft.World/SetPlayerTeamPacket.h | 35 + Minecraft.World/SetPlayerTimeoutCommand.h | 36 + Minecraft.World/SetScorePacket.cpp | 63 + Minecraft.World/SetScorePacket.h | 30 + Minecraft.World/SetTimePacket.cpp | 28 +- Minecraft.World/SetTimePacket.h | 5 +- Minecraft.World/SharedConstants.cpp | 2 +- Minecraft.World/SharedConstants.h | 3 +- Minecraft.World/SharedMonsterAttributes.cpp | 108 ++ Minecraft.World/SharedMonsterAttributes.h | 26 + Minecraft.World/ShearsItem.cpp | 24 +- Minecraft.World/ShearsItem.h | 2 +- Minecraft.World/Sheep.cpp | 88 +- Minecraft.World/Sheep.h | 10 +- Minecraft.World/ShortTag.h | 2 +- Minecraft.World/ShovelItem.cpp | 3 +- Minecraft.World/ShowSeedCommand.h | 38 + Minecraft.World/SignItem.cpp | 11 +- Minecraft.World/SignTile.cpp | 8 +- Minecraft.World/SignTile.h | 4 +- Minecraft.World/SignTileEntity.cpp | 16 + Minecraft.World/SignTileEntity.h | 3 + Minecraft.World/Silverfish.cpp | 58 +- Minecraft.World/Silverfish.h | 5 +- Minecraft.World/SimpleContainer.cpp | 40 +- Minecraft.World/SimpleContainer.h | 47 +- Minecraft.World/SimpleFoiledItem.cpp | 12 + Minecraft.World/SimpleFoiledItem.h | 11 + Minecraft.World/SitGoal.cpp | 2 +- Minecraft.World/Skeleton.cpp | 309 ++- Minecraft.World/Skeleton.h | 48 +- Minecraft.World/SkullItem.cpp | 10 +- Minecraft.World/SkullTile.cpp | 247 +-- Minecraft.World/SkullTile.h | 10 +- Minecraft.World/Slime.cpp | 64 +- Minecraft.World/Slime.h | 3 +- Minecraft.World/Slot.cpp | 5 + Minecraft.World/Slot.h | 1 + Minecraft.World/SmallFireball.cpp | 6 +- Minecraft.World/SmallFireball.h | 4 +- Minecraft.World/SmoothStoneBrickTile.cpp | 6 +- Minecraft.World/SnowItem.cpp | 45 + Minecraft.World/SnowItem.h | 11 + Minecraft.World/SnowMan.cpp | 37 +- Minecraft.World/SnowMan.h | 11 +- Minecraft.World/SnowTile.cpp | 4 +- Minecraft.World/Snowball.cpp | 6 +- Minecraft.World/Snowball.h | 2 +- Minecraft.World/SnowballItem.cpp | 8 +- Minecraft.World/Socket.cpp | 12 +- Minecraft.World/SoulSandTile.cpp | 21 + Minecraft.World/SoulSandTile.h | 11 + Minecraft.World/SoundTypes.h | 68 +- Minecraft.World/Source.h | 5 + Minecraft.World/SpawnEggItem.cpp | 378 ++++ Minecraft.World/SpawnEggItem.h | 48 + Minecraft.World/Spider.cpp | 112 +- Minecraft.World/Spider.h | 27 +- Minecraft.World/SpikeFeature.cpp | 124 +- Minecraft.World/SpreadPlayersCommand.h | 328 ++++ Minecraft.World/SpringFeature.cpp | 40 +- Minecraft.World/Squid.cpp | 28 +- Minecraft.World/Squid.h | 3 +- Minecraft.World/StainedGlassBlock.cpp | 54 + Minecraft.World/StainedGlassBlock.h | 27 + Minecraft.World/StainedGlassPaneBlock.cpp | 52 + Minecraft.World/StainedGlassPaneBlock.h | 23 + Minecraft.World/StairTile.cpp | 63 +- Minecraft.World/StairTile.h | 77 +- Minecraft.World/Stats.cpp | 32 +- Minecraft.World/StemTile.cpp | 163 +- Minecraft.World/StemTile.h | 29 +- Minecraft.World/StoneButtonTile.cpp | 12 + Minecraft.World/StoneButtonTile.h | 11 + Minecraft.World/StoneMonsterTile.cpp | 73 +- Minecraft.World/StoneSlabTile.cpp | 4 +- Minecraft.World/StoneSlabTileItem.cpp | 15 +- Minecraft.World/StoneTile.cpp | 2 +- Minecraft.World/StringHelpers.cpp | 14 + Minecraft.World/StringHelpers.h | 23 +- Minecraft.World/StringTag.h | 2 +- Minecraft.World/StrongholdFeature.cpp | 126 +- Minecraft.World/StrongholdFeature.h | 27 +- Minecraft.World/StrongholdPieces.cpp | 1764 +++++++++-------- Minecraft.World/StrongholdPieces.h | 381 ++-- Minecraft.World/StructureFeature.cpp | 167 +- Minecraft.World/StructureFeature.h | 70 +- Minecraft.World/StructureFeatureIO.cpp | 104 + Minecraft.World/StructureFeatureIO.h | 93 + Minecraft.World/StructureFeatureSavedData.cpp | 47 + Minecraft.World/StructureFeatureSavedData.h | 21 + Minecraft.World/StructurePiece.cpp | 57 +- Minecraft.World/StructurePiece.h | 135 +- Minecraft.World/StructureRecipies.cpp | 23 +- Minecraft.World/StructureStart.cpp | 121 +- Minecraft.World/StructureStart.h | 30 +- Minecraft.World/SwampBiome.cpp | 2 + Minecraft.World/SwellGoal.cpp | 8 +- Minecraft.World/SwellGoal.h | 2 +- Minecraft.World/SynchedEntityData.cpp | 168 +- Minecraft.World/SynchedEntityData.h | 18 +- Minecraft.World/Tag.cpp | 7 +- Minecraft.World/Tag.h | 5 +- Minecraft.World/TakeFlowerGoal.cpp | 2 +- Minecraft.World/TallGrass.cpp | 2 +- Minecraft.World/TallGrassFeature.cpp | 28 +- Minecraft.World/TamableAnimal.cpp | 38 +- Minecraft.World/TamableAnimal.h | 8 +- Minecraft.World/TargetGoal.cpp | 50 +- Minecraft.World/TargetGoal.h | 20 +- Minecraft.World/Team.cpp | 16 + Minecraft.World/Team.h | 13 + Minecraft.World/TeleportEntityPacket.cpp | 4 +- Minecraft.World/TemptGoal.cpp | 6 +- Minecraft.World/TemptGoal.h | 4 +- Minecraft.World/TheEndBiome.cpp | 15 +- Minecraft.World/TheEndBiomeDecorator.cpp | 15 +- Minecraft.World/TheEndLevelRandomLevelSource.cpp | 435 ++--- Minecraft.World/TheEndLevelRandomLevelSource.h | 35 +- Minecraft.World/TheEndPortal.cpp | 55 +- Minecraft.World/TheEndPortal.h | 28 +- Minecraft.World/TheEndPortalFrameTile.cpp | 56 +- Minecraft.World/TheEndPortalFrameTile.h | 20 +- Minecraft.World/ThinFenceTile.cpp | 4 +- Minecraft.World/ThinFenceTile.h | 2 +- Minecraft.World/ThornsEnchantment.cpp | 6 +- Minecraft.World/ThornsEnchantment.h | 2 +- Minecraft.World/Throwable.cpp | 54 +- Minecraft.World/Throwable.h | 10 +- Minecraft.World/ThrownEgg.cpp | 2 +- Minecraft.World/ThrownEgg.h | 2 +- Minecraft.World/ThrownEnderpearl.cpp | 25 +- Minecraft.World/ThrownEnderpearl.h | 2 +- Minecraft.World/ThrownExpBottle.cpp | 2 +- Minecraft.World/ThrownExpBottle.h | 2 +- Minecraft.World/ThrownPotion.cpp | 52 +- Minecraft.World/ThrownPotion.h | 6 +- Minecraft.World/TickNextTickData.cpp | 26 +- Minecraft.World/TickNextTickData.h | 9 +- Minecraft.World/Tile.cpp | 693 ++++--- Minecraft.World/Tile.h | 778 ++++---- Minecraft.World/TileDestructionPacket.cpp | 2 +- Minecraft.World/TileEditorOpenPacket.cpp | 44 + Minecraft.World/TileEditorOpenPacket.h | 25 + Minecraft.World/TileEntity.cpp | 26 +- Minecraft.World/TileEntity.h | 19 +- Minecraft.World/TileEventPacket.cpp | 4 +- Minecraft.World/TileItem.cpp | 102 +- Minecraft.World/TilePlanterItem.cpp | 40 +- Minecraft.World/TileUpdatePacket.cpp | 2 +- Minecraft.World/TimeCommand.cpp | 9 +- Minecraft.World/TimeCommand.h | 1 + Minecraft.World/TntTile.cpp | 53 +- Minecraft.World/TntTile.h | 25 +- Minecraft.World/ToggleDownfallCommand.cpp | 5 + Minecraft.World/ToggleDownfallCommand.h | 1 + Minecraft.World/ToolRecipies.cpp | 17 +- Minecraft.World/TopSnowTile.cpp | 75 +- Minecraft.World/TorchTile.cpp | 27 +- Minecraft.World/TorchTile.h | 29 +- Minecraft.World/TrapDoorTile.cpp | 19 +- Minecraft.World/TrapMenu.cpp | 2 +- Minecraft.World/TreeFeature.cpp | 3 +- Minecraft.World/TreeTile.cpp | 75 +- Minecraft.World/TreeTile.h | 16 +- Minecraft.World/TripWireSourceTile.cpp | 43 +- Minecraft.World/TripWireSourceTile.h | 4 +- Minecraft.World/TripWireTile.cpp | 18 +- Minecraft.World/UpdateAttributesPacket.cpp | 141 ++ Minecraft.World/UpdateAttributesPacket.h | 46 + Minecraft.World/UpdateMobEffectPacket.cpp | 29 +- Minecraft.World/UpdateMobEffectPacket.h | 1 + Minecraft.World/UseItemPacket.cpp | 10 +- Minecraft.World/Vec3.cpp | 175 +- Minecraft.World/Vec3.h | 4 + Minecraft.World/Village.cpp | 8 +- Minecraft.World/Village.h | 10 +- Minecraft.World/VillageFeature.cpp | 186 +- Minecraft.World/VillageFeature.h | 30 +- Minecraft.World/VillagePieces.cpp | 395 ++-- Minecraft.World/VillagePieces.h | 268 ++- Minecraft.World/VillageSiege.cpp | 2 +- Minecraft.World/Villager.cpp | 133 +- Minecraft.World/Villager.h | 25 +- Minecraft.World/VillagerGolem.cpp | 66 +- Minecraft.World/VillagerGolem.h | 8 +- Minecraft.World/Villages.cpp | 9 +- Minecraft.World/VineTile.cpp | 367 ++-- Minecraft.World/VinesFeature.cpp | 2 +- Minecraft.World/WallTile.cpp | 4 +- Minecraft.World/WaterAnimal.cpp | 22 + Minecraft.World/WaterAnimal.h | 3 + Minecraft.World/WaterLevelChunk.cpp | 5 + Minecraft.World/WaterLevelChunk.h | 1 + Minecraft.World/WaterLilyTile.cpp | 14 +- Minecraft.World/WaterLilyTileItem.cpp | 26 +- Minecraft.World/WaterLilyTileItem.h | 2 +- Minecraft.World/WaterlilyFeature.cpp | 22 +- Minecraft.World/WeaponItem.cpp | 58 +- Minecraft.World/WeaponItem.h | 10 +- Minecraft.World/WeaponRecipies.cpp | 9 +- Minecraft.World/WeatherCommand.h | 73 + Minecraft.World/WeighedTreasure.cpp | 2 +- Minecraft.World/WeighedTreasure.h | 2 +- Minecraft.World/WeightedPressurePlateTile.cpp | 46 + Minecraft.World/WeightedPressurePlateTile.h | 18 + Minecraft.World/Witch.cpp | 224 +++ Minecraft.World/Witch.h | 48 + Minecraft.World/WitherBoss.cpp | 584 ++++++ Minecraft.World/WitherBoss.h | 109 ++ Minecraft.World/WitherSkull.cpp | 130 ++ Minecraft.World/WitherSkull.h | 43 + Minecraft.World/Wolf.cpp | 183 +- Minecraft.World/Wolf.h | 24 +- Minecraft.World/WoodButtonTile.cpp | 12 + Minecraft.World/WoodButtonTile.h | 11 + Minecraft.World/WoodTile.cpp | 4 +- Minecraft.World/WoolCarpetTile.cpp | 4 +- Minecraft.World/WoolTileItem.cpp | 149 ++ Minecraft.World/WoolTileItem.h | 20 + Minecraft.World/WorkbenchTile.cpp | 1 + Minecraft.World/WorldlyContainer.h | 11 + Minecraft.World/WrittenBookItem.h | 82 + Minecraft.World/Zombie.cpp | 310 ++- Minecraft.World/Zombie.h | 80 +- Minecraft.World/net.minecraft.commands.common.h | 1 + Minecraft.World/net.minecraft.core.h | 16 + Minecraft.World/net.minecraft.network.packet.h | 11 +- .../net.minecraft.world.ContainerListener.h | 4 +- Minecraft.World/net.minecraft.world.damagesource.h | 2 + Minecraft.World/net.minecraft.world.effect.h | 3 + .../net.minecraft.world.entity.ai.attributes.h | 10 + .../net.minecraft.world.entity.ai.goal.h | 5 +- .../net.minecraft.world.entity.ambient.h | 4 + .../net.minecraft.world.entity.animal.h | 8 +- Minecraft.World/net.minecraft.world.entity.boss.h | 3 +- Minecraft.World/net.minecraft.world.entity.h | 10 +- Minecraft.World/net.minecraft.world.entity.item.h | 7 + .../net.minecraft.world.entity.monster.h | 7 +- .../net.minecraft.world.entity.projectile.h | 8 +- Minecraft.World/net.minecraft.world.h | 4 +- Minecraft.World/net.minecraft.world.inventory.h | 7 +- .../net.minecraft.world.item.crafting.h | 1 + Minecraft.World/net.minecraft.world.item.h | 19 +- Minecraft.World/net.minecraft.world.level.h | 9 +- .../net.minecraft.world.level.levelgen.flat.h | 4 + .../net.minecraft.world.level.levelgen.structure.h | 4 + .../net.minecraft.world.level.redstone.h | 3 + .../net.minecraft.world.level.tile.entity.h | 7 + Minecraft.World/net.minecraft.world.level.tile.h | 35 +- .../net.minecraft.world.scores.criteria.h | 5 + Minecraft.World/net.minecraft.world.scores.h | 9 + Minecraft.World/stdafx.h | 2 +- Minecraft.World/system.cpp | 7 +- Minecraft.World/x64headers/extraX64.h | 7 +- 1058 files changed, 52476 insertions(+), 23111 deletions(-) create mode 100644 Minecraft.World/AbsoptionMobEffect.cpp create mode 100644 Minecraft.World/AbsoptionMobEffect.h create mode 100644 Minecraft.World/AbstractProjectileDispenseBehavior.cpp create mode 100644 Minecraft.World/AbstractProjectileDispenseBehavior.h create mode 100644 Minecraft.World/AmbientCreature.cpp create mode 100644 Minecraft.World/AmbientCreature.h create mode 100644 Minecraft.World/AnimalChest.cpp create mode 100644 Minecraft.World/AnimalChest.h create mode 100644 Minecraft.World/AnvilMenu.cpp create mode 100644 Minecraft.World/AnvilMenu.h create mode 100644 Minecraft.World/AttackDamageMobEffect.cpp create mode 100644 Minecraft.World/AttackDamageMobEffect.h create mode 100644 Minecraft.World/Attribute.cpp create mode 100644 Minecraft.World/Attribute.h create mode 100644 Minecraft.World/AttributeInstance.h create mode 100644 Minecraft.World/AttributeModifier.cpp create mode 100644 Minecraft.World/AttributeModifier.h create mode 100644 Minecraft.World/BaseAttribute.cpp create mode 100644 Minecraft.World/BaseAttribute.h create mode 100644 Minecraft.World/BaseAttributeMap.cpp create mode 100644 Minecraft.World/BaseAttributeMap.h create mode 100644 Minecraft.World/BaseEntityTile.cpp create mode 100644 Minecraft.World/BaseEntityTile.h create mode 100644 Minecraft.World/BaseMobSpawner.cpp create mode 100644 Minecraft.World/BaseMobSpawner.h create mode 100644 Minecraft.World/BasePressurePlateTile.cpp create mode 100644 Minecraft.World/BasePressurePlateTile.h create mode 100644 Minecraft.World/BaseRailTile.cpp create mode 100644 Minecraft.World/BaseRailTile.h create mode 100644 Minecraft.World/Bat.cpp create mode 100644 Minecraft.World/Bat.h create mode 100644 Minecraft.World/BeaconMenu.cpp create mode 100644 Minecraft.World/BeaconMenu.h create mode 100644 Minecraft.World/BeaconTile.cpp create mode 100644 Minecraft.World/BeaconTile.h create mode 100644 Minecraft.World/BeaconTileEntity.cpp create mode 100644 Minecraft.World/BeaconTileEntity.h create mode 100644 Minecraft.World/Behavior.h create mode 100644 Minecraft.World/BehaviorRegistry.cpp create mode 100644 Minecraft.World/BehaviorRegistry.h create mode 100644 Minecraft.World/BlockSource.h create mode 100644 Minecraft.World/BlockSourceImpl.cpp create mode 100644 Minecraft.World/BlockSourceImpl.h create mode 100644 Minecraft.World/Calendar.cpp create mode 100644 Minecraft.World/Calendar.h create mode 100644 Minecraft.World/ClassDiagram.cd create mode 100644 Minecraft.World/ColoredTile.cpp create mode 100644 Minecraft.World/ColoredTile.h create mode 100644 Minecraft.World/CombatEntry.cpp create mode 100644 Minecraft.World/CombatEntry.h create mode 100644 Minecraft.World/CombatTracker.cpp create mode 100644 Minecraft.World/CombatTracker.h create mode 100644 Minecraft.World/CommandBlock.cpp create mode 100644 Minecraft.World/CommandBlock.h create mode 100644 Minecraft.World/CommandBlockEntity.cpp create mode 100644 Minecraft.World/CommandBlockEntity.h create mode 100644 Minecraft.World/ComparatorTile.cpp create mode 100644 Minecraft.World/ComparatorTile.h create mode 100644 Minecraft.World/ComparatorTileEntity.cpp create mode 100644 Minecraft.World/ComparatorTileEntity.h delete mode 100644 Minecraft.World/ConsoleSaveFileSplit.cpp delete mode 100644 Minecraft.World/ConsoleSaveFileSplit.h create mode 100644 Minecraft.World/DaylightDetectorTile.cpp create mode 100644 Minecraft.World/DaylightDetectorTile.h create mode 100644 Minecraft.World/DaylightDetectorTileEntity.cpp create mode 100644 Minecraft.World/DaylightDetectorTileEntity.h create mode 100644 Minecraft.World/DefaultDispenseItemBehavior.cpp create mode 100644 Minecraft.World/DefaultDispenseItemBehavior.h create mode 100644 Minecraft.World/DispenseItemBehavior.cpp create mode 100644 Minecraft.World/DispenseItemBehavior.h create mode 100644 Minecraft.World/DropperTile.cpp create mode 100644 Minecraft.World/DropperTile.h create mode 100644 Minecraft.World/DropperTileEntity.cpp create mode 100644 Minecraft.World/DropperTileEntity.h create mode 100644 Minecraft.World/DummyCriteria.cpp create mode 100644 Minecraft.World/DummyCriteria.h create mode 100644 Minecraft.World/EffectCommand.cpp create mode 100644 Minecraft.World/EffectCommand.h create mode 100644 Minecraft.World/EmptyMapItem.cpp create mode 100644 Minecraft.World/EmptyMapItem.h create mode 100644 Minecraft.World/EntityDiagram.cd create mode 100644 Minecraft.World/EntityHorse.cpp create mode 100644 Minecraft.World/EntityHorse.h create mode 100644 Minecraft.World/EntitySelector.cpp create mode 100644 Minecraft.World/EntitySelector.h create mode 100644 Minecraft.World/FacingEnum.cpp create mode 100644 Minecraft.World/FacingEnum.h create mode 100644 Minecraft.World/FireworksChargeItem.cpp create mode 100644 Minecraft.World/FireworksChargeItem.h create mode 100644 Minecraft.World/FireworksItem.cpp create mode 100644 Minecraft.World/FireworksItem.h create mode 100644 Minecraft.World/FireworksMenu.cpp create mode 100644 Minecraft.World/FireworksMenu.h create mode 100644 Minecraft.World/FireworksRecipe.cpp create mode 100644 Minecraft.World/FireworksRecipe.h create mode 100644 Minecraft.World/FireworksRocketEntity.cpp create mode 100644 Minecraft.World/FireworksRocketEntity.h create mode 100644 Minecraft.World/FlatGeneratorInfo.cpp create mode 100644 Minecraft.World/FlatGeneratorInfo.h create mode 100644 Minecraft.World/FlatLayerInfo.cpp create mode 100644 Minecraft.World/FlatLayerInfo.h create mode 100644 Minecraft.World/GameDifficultyCommand.h create mode 100644 Minecraft.World/GameRuleCommand.h create mode 100644 Minecraft.World/GameRules.cpp create mode 100644 Minecraft.World/GameRules.h create mode 100644 Minecraft.World/GlowstoneTile.cpp create mode 100644 Minecraft.World/GlowstoneTile.h create mode 100644 Minecraft.World/HayBlockTile.cpp create mode 100644 Minecraft.World/HayBlockTile.h create mode 100644 Minecraft.World/HealthBoostMobEffect.cpp create mode 100644 Minecraft.World/HealthBoostMobEffect.h create mode 100644 Minecraft.World/HealthCriteria.cpp create mode 100644 Minecraft.World/HealthCriteria.h create mode 100644 Minecraft.World/Hopper.h create mode 100644 Minecraft.World/HopperMenu.cpp create mode 100644 Minecraft.World/HopperMenu.h create mode 100644 Minecraft.World/HopperTile.cpp create mode 100644 Minecraft.World/HopperTile.h create mode 100644 Minecraft.World/HopperTileEntity.cpp create mode 100644 Minecraft.World/HopperTileEntity.h create mode 100644 Minecraft.World/HorseInventoryMenu.cpp create mode 100644 Minecraft.World/HorseInventoryMenu.h create mode 100644 Minecraft.World/HtmlString.cpp create mode 100644 Minecraft.World/HtmlString.h create mode 100644 Minecraft.World/ItemDispenseBehaviors.cpp create mode 100644 Minecraft.World/ItemDispenseBehaviors.h create mode 100644 Minecraft.World/JukeboxTile.cpp create mode 100644 Minecraft.World/JukeboxTile.h create mode 100644 Minecraft.World/LargeFireball.cpp create mode 100644 Minecraft.World/LargeFireball.h create mode 100644 Minecraft.World/LeashFenceKnotEntity.cpp create mode 100644 Minecraft.World/LeashFenceKnotEntity.h create mode 100644 Minecraft.World/LeashItem.cpp create mode 100644 Minecraft.World/LeashItem.h create mode 100644 Minecraft.World/LevelParticlesPacket.cpp create mode 100644 Minecraft.World/LevelParticlesPacket.h create mode 100644 Minecraft.World/LivingEntity.cpp create mode 100644 Minecraft.World/LivingEntity.h create mode 100644 Minecraft.World/LocatableSource.h create mode 100644 Minecraft.World/Location.h create mode 100644 Minecraft.World/MapCloningRecipe.h create mode 100644 Minecraft.World/MapExtendingRecipe.h create mode 100644 Minecraft.World/MinecartChest.cpp create mode 100644 Minecraft.World/MinecartChest.h create mode 100644 Minecraft.World/MinecartContainer.cpp create mode 100644 Minecraft.World/MinecartContainer.h create mode 100644 Minecraft.World/MinecartFurnace.cpp create mode 100644 Minecraft.World/MinecartFurnace.h create mode 100644 Minecraft.World/MinecartHopper.cpp create mode 100644 Minecraft.World/MinecartHopper.h create mode 100644 Minecraft.World/MinecartRideable.cpp create mode 100644 Minecraft.World/MinecartRideable.h create mode 100644 Minecraft.World/MinecartSpawner.cpp create mode 100644 Minecraft.World/MinecartSpawner.h create mode 100644 Minecraft.World/MinecartTNT.cpp create mode 100644 Minecraft.World/MinecartTNT.h create mode 100644 Minecraft.World/MobGroupData.h create mode 100644 Minecraft.World/ModifiableAttributeInstance.cpp create mode 100644 Minecraft.World/ModifiableAttributeInstance.h create mode 100644 Minecraft.World/MultiEntityMob.h create mode 100644 Minecraft.World/MultiEntityMobPart.cpp create mode 100644 Minecraft.World/MultiEntityMobPart.h create mode 100644 Minecraft.World/NameTagItem.cpp create mode 100644 Minecraft.World/NameTagItem.h create mode 100644 Minecraft.World/NetherWartTile.cpp create mode 100644 Minecraft.World/NetherWartTile.h create mode 100644 Minecraft.World/NetherrackTile.cpp create mode 100644 Minecraft.World/NetherrackTile.h create mode 100644 Minecraft.World/NoteBlockTile.cpp create mode 100644 Minecraft.World/NoteBlockTile.h create mode 100644 Minecraft.World/Objective.cpp create mode 100644 Minecraft.World/Objective.h create mode 100644 Minecraft.World/ObjectiveCriteria.cpp create mode 100644 Minecraft.World/ObjectiveCriteria.h create mode 100644 Minecraft.World/Ocelot.cpp create mode 100644 Minecraft.World/Ocelot.h create mode 100644 Minecraft.World/OcelotAttackGoal.cpp create mode 100644 Minecraft.World/OcelotAttackGoal.h create mode 100644 Minecraft.World/OwnableEntity.h create mode 100644 Minecraft.World/PlaySoundCommand.h create mode 100644 Minecraft.World/PlayerSelector.h create mode 100644 Minecraft.World/PlayerTeam.cpp create mode 100644 Minecraft.World/PlayerTeam.h create mode 100644 Minecraft.World/Position.h create mode 100644 Minecraft.World/PositionImpl.h create mode 100644 Minecraft.World/PoweredMetalTile.cpp create mode 100644 Minecraft.World/PoweredMetalTile.h create mode 100644 Minecraft.World/PoweredRailTile.cpp create mode 100644 Minecraft.World/PoweredRailTile.h create mode 100644 Minecraft.World/Projectile.h create mode 100644 Minecraft.World/RangedAttackGoal.cpp create mode 100644 Minecraft.World/RangedAttackGoal.h create mode 100644 Minecraft.World/RangedAttackMob.h create mode 100644 Minecraft.World/RangedAttribute.cpp create mode 100644 Minecraft.World/RangedAttribute.h create mode 100644 Minecraft.World/Redstone.cpp create mode 100644 Minecraft.World/Redstone.h create mode 100644 Minecraft.World/RepeaterTile.cpp create mode 100644 Minecraft.World/RepeaterTile.h create mode 100644 Minecraft.World/RotatedPillarTile.cpp create mode 100644 Minecraft.World/RotatedPillarTile.h create mode 100644 Minecraft.World/RunAroundLikeCrazyGoal.cpp create mode 100644 Minecraft.World/RunAroundLikeCrazyGoal.h create mode 100644 Minecraft.World/Score.cpp create mode 100644 Minecraft.World/Score.h create mode 100644 Minecraft.World/ScoreHolder.h create mode 100644 Minecraft.World/Scoreboard.cpp create mode 100644 Minecraft.World/Scoreboard.h create mode 100644 Minecraft.World/ScoreboardSaveData.h create mode 100644 Minecraft.World/ServersideAttributeMap.cpp create mode 100644 Minecraft.World/ServersideAttributeMap.h create mode 100644 Minecraft.World/SetDisplayObjectivePacket.cpp create mode 100644 Minecraft.World/SetDisplayObjectivePacket.h create mode 100644 Minecraft.World/SetEntityLinkPacket.cpp create mode 100644 Minecraft.World/SetEntityLinkPacket.h create mode 100644 Minecraft.World/SetObjectivePacket.cpp create mode 100644 Minecraft.World/SetObjectivePacket.h create mode 100644 Minecraft.World/SetPlayerTeamPacket.cpp create mode 100644 Minecraft.World/SetPlayerTeamPacket.h create mode 100644 Minecraft.World/SetPlayerTimeoutCommand.h create mode 100644 Minecraft.World/SetScorePacket.cpp create mode 100644 Minecraft.World/SetScorePacket.h create mode 100644 Minecraft.World/SharedMonsterAttributes.cpp create mode 100644 Minecraft.World/SharedMonsterAttributes.h create mode 100644 Minecraft.World/ShowSeedCommand.h create mode 100644 Minecraft.World/SimpleFoiledItem.cpp create mode 100644 Minecraft.World/SimpleFoiledItem.h create mode 100644 Minecraft.World/SnowItem.cpp create mode 100644 Minecraft.World/SnowItem.h create mode 100644 Minecraft.World/SoulSandTile.cpp create mode 100644 Minecraft.World/SoulSandTile.h create mode 100644 Minecraft.World/Source.h create mode 100644 Minecraft.World/SpawnEggItem.cpp create mode 100644 Minecraft.World/SpawnEggItem.h create mode 100644 Minecraft.World/SpreadPlayersCommand.h create mode 100644 Minecraft.World/StainedGlassBlock.cpp create mode 100644 Minecraft.World/StainedGlassBlock.h create mode 100644 Minecraft.World/StainedGlassPaneBlock.cpp create mode 100644 Minecraft.World/StainedGlassPaneBlock.h create mode 100644 Minecraft.World/StoneButtonTile.cpp create mode 100644 Minecraft.World/StoneButtonTile.h create mode 100644 Minecraft.World/StructureFeatureIO.cpp create mode 100644 Minecraft.World/StructureFeatureIO.h create mode 100644 Minecraft.World/StructureFeatureSavedData.cpp create mode 100644 Minecraft.World/StructureFeatureSavedData.h create mode 100644 Minecraft.World/Team.cpp create mode 100644 Minecraft.World/Team.h create mode 100644 Minecraft.World/TileEditorOpenPacket.cpp create mode 100644 Minecraft.World/TileEditorOpenPacket.h create mode 100644 Minecraft.World/UpdateAttributesPacket.cpp create mode 100644 Minecraft.World/UpdateAttributesPacket.h create mode 100644 Minecraft.World/WeatherCommand.h create mode 100644 Minecraft.World/WeightedPressurePlateTile.cpp create mode 100644 Minecraft.World/WeightedPressurePlateTile.h create mode 100644 Minecraft.World/Witch.cpp create mode 100644 Minecraft.World/Witch.h create mode 100644 Minecraft.World/WitherBoss.cpp create mode 100644 Minecraft.World/WitherBoss.h create mode 100644 Minecraft.World/WitherSkull.cpp create mode 100644 Minecraft.World/WitherSkull.h create mode 100644 Minecraft.World/WoodButtonTile.cpp create mode 100644 Minecraft.World/WoodButtonTile.h create mode 100644 Minecraft.World/WoolTileItem.cpp create mode 100644 Minecraft.World/WoolTileItem.h create mode 100644 Minecraft.World/WorldlyContainer.h create mode 100644 Minecraft.World/WrittenBookItem.h create mode 100644 Minecraft.World/net.minecraft.core.h create mode 100644 Minecraft.World/net.minecraft.world.entity.ai.attributes.h create mode 100644 Minecraft.World/net.minecraft.world.entity.ambient.h create mode 100644 Minecraft.World/net.minecraft.world.level.levelgen.flat.h create mode 100644 Minecraft.World/net.minecraft.world.level.redstone.h create mode 100644 Minecraft.World/net.minecraft.world.scores.criteria.h create mode 100644 Minecraft.World/net.minecraft.world.scores.h (limited to 'Minecraft.World') diff --git a/Minecraft.World/AABB.cpp b/Minecraft.World/AABB.cpp index 4c867f0d..8bc8e140 100644 --- a/Minecraft.World/AABB.cpp +++ b/Minecraft.World/AABB.cpp @@ -49,7 +49,7 @@ void AABB::ReleaseThreadStorage() AABB *AABB::newPermanent(double x0, double y0, double z0, double x1, double y1, double z1) { - return new AABB(x0, y0, z0, x1, y1, z1); + return new AABB(x0, y0, z0, x1, y1, z1); } void AABB::clearPool() @@ -66,277 +66,289 @@ AABB *AABB::newTemp(double x0, double y0, double z0, double x1, double y1, doubl AABB *thisAABB = &tls->pool[tls->poolPointer]; thisAABB->set(x0, y0, z0, x1, y1, z1); tls->poolPointer = ( tls->poolPointer + 1 ) % ThreadStorage::POOL_SIZE; - return thisAABB; + return thisAABB; } AABB::AABB(double x0, double y0, double z0, double x1, double y1, double z1) { - this->x0 = x0; - this->y0 = y0; - this->z0 = z0; - this->x1 = x1; - this->y1 = y1; - this->z1 = z1; + this->x0 = x0; + this->y0 = y0; + this->z0 = z0; + this->x1 = x1; + this->y1 = y1; + this->z1 = z1; } AABB *AABB::set(double x0, double y0, double z0, double x1, double y1, double z1) { - this->x0 = x0; - this->y0 = y0; - this->z0 = z0; - this->x1 = x1; - this->y1 = y1; - this->z1 = z1; - return this; + this->x0 = x0; + this->y0 = y0; + this->z0 = z0; + this->x1 = x1; + this->y1 = y1; + this->z1 = z1; + return this; } AABB *AABB::expand(double xa, double ya, double za) { - double _x0 = x0; - double _y0 = y0; - double _z0 = z0; - double _x1 = x1; - double _y1 = y1; - double _z1 = z1; + double _x0 = x0; + double _y0 = y0; + double _z0 = z0; + double _x1 = x1; + double _y1 = y1; + double _z1 = z1; - if (xa < 0) _x0 += xa; - if (xa > 0) _x1 += xa; + if (xa < 0) _x0 += xa; + if (xa > 0) _x1 += xa; - if (ya < 0) _y0 += ya; - if (ya > 0) _y1 += ya; + if (ya < 0) _y0 += ya; + if (ya > 0) _y1 += ya; - if (za < 0) _z0 += za; - if (za > 0) _z1 += za; + if (za < 0) _z0 += za; + if (za > 0) _z1 += za; - return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1); + return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1); } AABB *AABB::grow(double xa, double ya, double za) { - double _x0 = x0 - xa; - double _y0 = y0 - ya; - double _z0 = z0 - za; - double _x1 = x1 + xa; - double _y1 = y1 + ya; - double _z1 = z1 + za; + double _x0 = x0 - xa; + double _y0 = y0 - ya; + double _z0 = z0 - za; + double _x1 = x1 + xa; + double _y1 = y1 + ya; + double _z1 = z1 + za; - return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1); + return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1); +} + +AABB *AABB::minmax(AABB *other) +{ + double _x0 = min(x0, other->x0); + double _y0 = min(y0, other->y0); + double _z0 = min(z0, other->z0); + double _x1 = max(x1, other->x1); + double _y1 = max(y1, other->y1); + double _z1 = max(z1, other->z1); + + return newTemp(_x0, _y0, _z0, _x1, _y1, _z1); } AABB *AABB::cloneMove(double xa, double ya, double za) { - return AABB::newTemp(x0 + xa, y0 + ya, z0 + za, x1 + xa, y1 + ya, z1 + za); + return AABB::newTemp(x0 + xa, y0 + ya, z0 + za, x1 + xa, y1 + ya, z1 + za); } double AABB::clipXCollide(AABB *c, double xa) { - if (c->y1 <= y0 || c->y0 >= y1) return xa; - if (c->z1 <= z0 || c->z0 >= z1) return xa; + if (c->y1 <= y0 || c->y0 >= y1) return xa; + if (c->z1 <= z0 || c->z0 >= z1) return xa; - if (xa > 0 && c->x1 <= x0) + if (xa > 0 && c->x1 <= x0) { - double max = x0 - c->x1; - if (max < xa) xa = max; - } - if (xa < 0 && c->x0 >= x1) + double max = x0 - c->x1; + if (max < xa) xa = max; + } + if (xa < 0 && c->x0 >= x1) { - double max = x1 - c->x0; - if (max > xa) xa = max; - } + double max = x1 - c->x0; + if (max > xa) xa = max; + } - return xa; + return xa; } double AABB::clipYCollide(AABB *c, double ya) { - if (c->x1 <= x0 || c->x0 >= x1) return ya; - if (c->z1 <= z0 || c->z0 >= z1) return ya; + if (c->x1 <= x0 || c->x0 >= x1) return ya; + if (c->z1 <= z0 || c->z0 >= z1) return ya; - if (ya > 0 && c->y1 <= y0) + if (ya > 0 && c->y1 <= y0) { - double max = y0 - c->y1; - if (max < ya) ya = max; - } - if (ya < 0 && c->y0 >= y1) + double max = y0 - c->y1; + if (max < ya) ya = max; + } + if (ya < 0 && c->y0 >= y1) { - double max = y1 - c->y0; - if (max > ya) ya = max; - } + double max = y1 - c->y0; + if (max > ya) ya = max; + } - return ya; + return ya; } double AABB::clipZCollide(AABB *c, double za) { - if (c->x1 <= x0 || c->x0 >= x1) return za; - if (c->y1 <= y0 || c->y0 >= y1) return za; + if (c->x1 <= x0 || c->x0 >= x1) return za; + if (c->y1 <= y0 || c->y0 >= y1) return za; - if (za > 0 && c->z1 <= z0) + if (za > 0 && c->z1 <= z0) { - double max = z0 - c->z1; - if (max < za) za = max; - } - if (za < 0 && c->z0 >= z1) + double max = z0 - c->z1; + if (max < za) za = max; + } + if (za < 0 && c->z0 >= z1) { - double max = z1 - c->z0; - if (max > za) za = max; - } + double max = z1 - c->z0; + if (max > za) za = max; + } - return za; + return za; } bool AABB::intersects(AABB *c) { - if (c->x1 <= x0 || c->x0 >= x1) return false; - if (c->y1 <= y0 || c->y0 >= y1) return false; - if (c->z1 <= z0 || c->z0 >= z1) return false; - return true; + if (c->x1 <= x0 || c->x0 >= x1) return false; + if (c->y1 <= y0 || c->y0 >= y1) return false; + if (c->z1 <= z0 || c->z0 >= z1) return false; + return true; } bool AABB::intersectsInner(AABB *c) { - if (c->x1 < x0 || c->x0 > x1) return false; - if (c->y1 < y0 || c->y0 > y1) return false; - if (c->z1 < z0 || c->z0 > z1) return false; - return true; + if (c->x1 < x0 || c->x0 > x1) return false; + if (c->y1 < y0 || c->y0 > y1) return false; + if (c->z1 < z0 || c->z0 > z1) return false; + return true; } AABB *AABB::move(double xa, double ya, double za) { - x0 += xa; - y0 += ya; - z0 += za; - x1 += xa; - y1 += ya; - z1 += za; - return this; + x0 += xa; + y0 += ya; + z0 += za; + x1 += xa; + y1 += ya; + z1 += za; + return this; } bool AABB::intersects(double x02, double y02, double z02, double x12, double y12, double z12) { - if (x12 <= x0 || x02 >= x1) return false; - if (y12 <= y0 || y02 >= y1) return false; - if (z12 <= z0 || z02 >= z1) return false; - return true; + if (x12 <= x0 || x02 >= x1) return false; + if (y12 <= y0 || y02 >= y1) return false; + if (z12 <= z0 || z02 >= z1) return false; + return true; } bool AABB::contains(Vec3 *p) { - if (p->x <= x0 || p->x >= x1) return false; - if (p->y <= y0 || p->y >= y1) return false; - if (p->z <= z0 || p->z >= z1) return false; - return true; + if (p->x <= x0 || p->x >= x1) return false; + if (p->y <= y0 || p->y >= y1) return false; + if (p->z <= z0 || p->z >= z1) return false; + return true; } // 4J Added bool AABB::containsIncludingLowerBound(Vec3 *p) { - if (p->x < x0 || p->x >= x1) return false; - if (p->y < y0 || p->y >= y1) return false; - if (p->z < z0 || p->z >= z1) return false; - return true; + if (p->x < x0 || p->x >= x1) return false; + if (p->y < y0 || p->y >= y1) return false; + if (p->z < z0 || p->z >= z1) return false; + return true; } double AABB::getSize() { - double xs = x1 - x0; - double ys = y1 - y0; - double zs = z1 - z0; - return (xs + ys + zs) / 3.0f; + double xs = x1 - x0; + double ys = y1 - y0; + double zs = z1 - z0; + return (xs + ys + zs) / 3.0f; } AABB *AABB::shrink(double xa, double ya, double za) { - double _x0 = x0 + xa; - double _y0 = y0 + ya; - double _z0 = z0 + za; - double _x1 = x1 - xa; - double _y1 = y1 - ya; - double _z1 = z1 - za; + double _x0 = x0 + xa; + double _y0 = y0 + ya; + double _z0 = z0 + za; + double _x1 = x1 - xa; + double _y1 = y1 - ya; + double _z1 = z1 - za; - return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1); + return AABB::newTemp(_x0, _y0, _z0, _x1, _y1, _z1); } AABB *AABB::copy() { - return AABB::newTemp(x0, y0, z0, x1, y1, z1); + return AABB::newTemp(x0, y0, z0, x1, y1, z1); } HitResult *AABB::clip(Vec3 *a, Vec3 *b) { - Vec3 *xh0 = a->clipX(b, x0); - Vec3 *xh1 = a->clipX(b, x1); + Vec3 *xh0 = a->clipX(b, x0); + Vec3 *xh1 = a->clipX(b, x1); - Vec3 *yh0 = a->clipY(b, y0); - Vec3 *yh1 = a->clipY(b, y1); + Vec3 *yh0 = a->clipY(b, y0); + Vec3 *yh1 = a->clipY(b, y1); - Vec3 *zh0 = a->clipZ(b, z0); - Vec3 *zh1 = a->clipZ(b, z1); + Vec3 *zh0 = a->clipZ(b, z0); + Vec3 *zh1 = a->clipZ(b, z1); - if (!containsX(xh0)) xh0 = NULL; - if (!containsX(xh1)) xh1 = NULL; - if (!containsY(yh0)) yh0 = NULL; - if (!containsY(yh1)) yh1 = NULL; - if (!containsZ(zh0)) zh0 = NULL; - if (!containsZ(zh1)) zh1 = NULL; + if (!containsX(xh0)) xh0 = NULL; + if (!containsX(xh1)) xh1 = NULL; + if (!containsY(yh0)) yh0 = NULL; + if (!containsY(yh1)) yh1 = NULL; + if (!containsZ(zh0)) zh0 = NULL; + if (!containsZ(zh1)) zh1 = NULL; - Vec3 *closest = NULL; + Vec3 *closest = NULL; - if (xh0 != NULL && (closest == NULL || a->distanceToSqr(xh0) < a->distanceToSqr(closest))) closest = xh0; - if (xh1 != NULL && (closest == NULL || a->distanceToSqr(xh1) < a->distanceToSqr(closest))) closest = xh1; - if (yh0 != NULL && (closest == NULL || a->distanceToSqr(yh0) < a->distanceToSqr(closest))) closest = yh0; - if (yh1 != NULL && (closest == NULL || a->distanceToSqr(yh1) < a->distanceToSqr(closest))) closest = yh1; - if (zh0 != NULL && (closest == NULL || a->distanceToSqr(zh0) < a->distanceToSqr(closest))) closest = zh0; - if (zh1 != NULL && (closest == NULL || a->distanceToSqr(zh1) < a->distanceToSqr(closest))) closest = zh1; + if (xh0 != NULL && (closest == NULL || a->distanceToSqr(xh0) < a->distanceToSqr(closest))) closest = xh0; + if (xh1 != NULL && (closest == NULL || a->distanceToSqr(xh1) < a->distanceToSqr(closest))) closest = xh1; + if (yh0 != NULL && (closest == NULL || a->distanceToSqr(yh0) < a->distanceToSqr(closest))) closest = yh0; + if (yh1 != NULL && (closest == NULL || a->distanceToSqr(yh1) < a->distanceToSqr(closest))) closest = yh1; + if (zh0 != NULL && (closest == NULL || a->distanceToSqr(zh0) < a->distanceToSqr(closest))) closest = zh0; + if (zh1 != NULL && (closest == NULL || a->distanceToSqr(zh1) < a->distanceToSqr(closest))) closest = zh1; - if (closest == NULL) return NULL; + if (closest == NULL) return NULL; - int face = -1; + int face = -1; - if (closest == xh0) face = 4; - if (closest == xh1) face = 5; - if (closest == yh0) face = 0; - if (closest == yh1) face = 1; - if (closest == zh0) face = 2; - if (closest == zh1) face = 3; + if (closest == xh0) face = 4; + if (closest == xh1) face = 5; + if (closest == yh0) face = 0; + if (closest == yh1) face = 1; + if (closest == zh0) face = 2; + if (closest == zh1) face = 3; - return new HitResult(0, 0, 0, face, closest); + return new HitResult(0, 0, 0, face, closest); } bool AABB::containsX(Vec3 *v) { - if (v == NULL) return false; - return v->y >= y0 && v->y <= y1 && v->z >= z0 && v->z <= z1; + if (v == NULL) return false; + return v->y >= y0 && v->y <= y1 && v->z >= z0 && v->z <= z1; } bool AABB::containsY(Vec3 *v) { - if (v == NULL) return false; - return v->x >= x0 && v->x <= x1 && v->z >= z0 && v->z <= z1; + if (v == NULL) return false; + return v->x >= x0 && v->x <= x1 && v->z >= z0 && v->z <= z1; } bool AABB::containsZ(Vec3 *v) { - if (v == NULL) return false; - return v->x >= x0 && v->x <= x1 && v->y >= y0 && v->y <= y1; + if (v == NULL) return false; + return v->x >= x0 && v->x <= x1 && v->y >= y0 && v->y <= y1; } void AABB::set(AABB *b) { - this->x0 = b->x0; - this->y0 = b->y0; - this->z0 = b->z0; - this->x1 = b->x1; - this->y1 = b->y1; - this->z1 = b->z1; + x0 = b->x0; + y0 = b->y0; + z0 = b->z0; + x1 = b->x1; + y1 = b->y1; + z1 = b->z1; } wstring AABB::toString() { - return L"box[" + _toString(x0) + L", " + _toString(y0) + L", " + _toString(z0) + L" -> " + + return L"box[" + _toString(x0) + L", " + _toString(y0) + L", " + _toString(z0) + L" -> " + _toString(x1) + L", " + _toString(y1) + L", " + _toString(z1) + L"]"; } diff --git a/Minecraft.World/AABB.h b/Minecraft.World/AABB.h index 81405ea1..4f7a3531 100644 --- a/Minecraft.World/AABB.h +++ b/Minecraft.World/AABB.h @@ -42,7 +42,7 @@ public: AABB *set(double x0, double y0, double z0, double x1, double y1, double z1); AABB *expand(double xa, double ya, double za); AABB *grow(double xa, double ya, double za); -public: + AABB *minmax(AABB *other); AABB *cloneMove(double xa, double ya, double za); double clipXCollide(AABB *c, double xa); double clipYCollide(AABB *c, double ya); diff --git a/Minecraft.World/Abilities.cpp b/Minecraft.World/Abilities.cpp index 06006860..1177937b 100644 --- a/Minecraft.World/Abilities.cpp +++ b/Minecraft.World/Abilities.cpp @@ -63,7 +63,7 @@ float Abilities::getFlyingSpeed() void Abilities::setFlyingSpeed(float value) { - this->flyingSpeed = value; + flyingSpeed = value; } float Abilities::getWalkingSpeed() @@ -73,5 +73,5 @@ float Abilities::getWalkingSpeed() void Abilities::setWalkingSpeed(float value) { - this->walkingSpeed = value; + walkingSpeed = value; } \ No newline at end of file diff --git a/Minecraft.World/AbsoptionMobEffect.cpp b/Minecraft.World/AbsoptionMobEffect.cpp new file mode 100644 index 00000000..6f5e1647 --- /dev/null +++ b/Minecraft.World/AbsoptionMobEffect.cpp @@ -0,0 +1,20 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.effect.h" +#include "AbsoptionMobEffect.h" + +AbsoptionMobEffect::AbsoptionMobEffect(int id, bool isHarmful, eMinecraftColour color) : MobEffect(id, isHarmful, color) +{ +} + +void AbsoptionMobEffect::removeAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier) +{ + entity->setAbsorptionAmount(entity->getAbsorptionAmount() - 4 * (amplifier + 1)); + MobEffect::removeAttributeModifiers(entity, attributes, amplifier); +} + +void AbsoptionMobEffect::addAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier) +{ + entity->setAbsorptionAmount(entity->getAbsorptionAmount() + 4 * (amplifier + 1)); + MobEffect::addAttributeModifiers(entity, attributes, amplifier); +} diff --git a/Minecraft.World/AbsoptionMobEffect.h b/Minecraft.World/AbsoptionMobEffect.h new file mode 100644 index 00000000..568186b7 --- /dev/null +++ b/Minecraft.World/AbsoptionMobEffect.h @@ -0,0 +1,14 @@ +#pragma once + +class LivingEntity; + +#include "MobEffect.h" + +class AbsoptionMobEffect : public MobEffect +{ +public: + AbsoptionMobEffect(int id, bool isHarmful, eMinecraftColour color); + + void removeAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier); + void addAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier); +}; \ No newline at end of file diff --git a/Minecraft.World/AbstractContainerMenu.cpp b/Minecraft.World/AbstractContainerMenu.cpp index 71d30feb..082e8008 100644 --- a/Minecraft.World/AbstractContainerMenu.cpp +++ b/Minecraft.World/AbstractContainerMenu.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.redstone.h" #include "Slot.h" #include "AbstractContainerMenu.h" @@ -8,46 +9,36 @@ // TODO Make sure all derived classes also call this AbstractContainerMenu::AbstractContainerMenu() { - lastSlots = new vector >(); - slots = new vector(); containerId = 0; changeUid = 0; - m_bNeedsRendered = false; - containerListeners = new vector(); + quickcraftType = -1; + quickcraftStatus = 0; + + m_bNeedsRendered = false; } AbstractContainerMenu::~AbstractContainerMenu() { - delete lastSlots; - for( unsigned int i = 0; i < slots->size(); i++ ) + for( unsigned int i = 0; i < slots.size(); i++ ) { - delete slots->at(i); + delete slots.at(i); } - delete slots; - delete containerListeners; } Slot *AbstractContainerMenu::addSlot(Slot *slot) { - slot->index = (int)slots->size(); - slots->push_back(slot); - lastSlots->push_back(nullptr); + slot->index = (int)slots.size(); + slots.push_back(slot); + lastSlots.push_back(nullptr); return slot; } void AbstractContainerMenu::addSlotListener(ContainerListener *listener) { - // TODO 4J Add exceptions - /* - if (containerListeners->contains(listener)) { - throw new IllegalArgumentException("Listener already listening"); - } - */ - containerListeners->push_back(listener); - + containerListeners.push_back(listener); vector > *items = getItems(); listener->refreshContainer(this, items); @@ -55,11 +46,17 @@ void AbstractContainerMenu::addSlotListener(ContainerListener *listener) broadcastChanges(); } +void AbstractContainerMenu::removeSlotListener(ContainerListener *listener) +{ + AUTO_VAR(it, std::find(containerListeners.begin(), containerListeners.end(), listener) ); + if(it != containerListeners.end()) containerListeners.erase(it); +} + vector > *AbstractContainerMenu::getItems() { vector > *items = new vector >(); - AUTO_VAR(itEnd, slots->end()); - for (AUTO_VAR(it, slots->begin()); it != itEnd; it++) + AUTO_VAR(itEnd, slots.end()); + for (AUTO_VAR(it, slots.begin()); it != itEnd; it++) { items->push_back((*it)->getItem()); } @@ -68,8 +65,8 @@ vector > *AbstractContainerMenu::getItems() void AbstractContainerMenu::sendData(int id, int value) { - AUTO_VAR(itEnd, containerListeners->end()); - for (AUTO_VAR(it, containerListeners->begin()); it != itEnd; it++) + AUTO_VAR(itEnd, containerListeners.end()); + for (AUTO_VAR(it, containerListeners.begin()); it != itEnd; it++) { (*it)->setContainerData(this, id, value); } @@ -77,18 +74,20 @@ void AbstractContainerMenu::sendData(int id, int value) void AbstractContainerMenu::broadcastChanges() { - for (unsigned int i = 0; i < slots->size(); i++) + for (unsigned int i = 0; i < slots.size(); i++) { - shared_ptr current = slots->at(i)->getItem(); - shared_ptr expected = lastSlots->at(i); + shared_ptr current = slots.at(i)->getItem(); + shared_ptr expected = lastSlots.at(i); if (!ItemInstance::matches(expected, current)) { - expected = current == NULL ? nullptr : current->copy(); - (*lastSlots)[i] = expected; + // 4J Stu - Added 0 count check. There is a bug in the Java with anvils that means this broadcast + // happens while we are in the middle of quickmoving, and before the slot properly gets set to null + expected = (current == NULL || current->count == 0) ? nullptr : current->copy(); + lastSlots[i] = expected; m_bNeedsRendered = true; - AUTO_VAR(itEnd, containerListeners->end()); - for (AUTO_VAR(it, containerListeners->begin()); it != itEnd; it++) + AUTO_VAR(itEnd, containerListeners.end()); + for (AUTO_VAR(it, containerListeners.begin()); it != itEnd; it++) { (*it)->slotChanged(this, i, expected); } @@ -101,14 +100,14 @@ bool AbstractContainerMenu::needsRendered() bool needsRendered = m_bNeedsRendered; m_bNeedsRendered = false; - for (unsigned int i = 0; i < slots->size(); i++) + for (unsigned int i = 0; i < slots.size(); i++) { - shared_ptr current = slots->at(i)->getItem(); - shared_ptr expected = lastSlots->at(i); + shared_ptr current = slots.at(i)->getItem(); + shared_ptr expected = lastSlots.at(i); if (!ItemInstance::matches(expected, current)) { expected = current == NULL ? nullptr : current->copy(); - (*lastSlots)[i] = expected; + lastSlots[i] = expected; needsRendered = true; } } @@ -123,8 +122,8 @@ bool AbstractContainerMenu::clickMenuButton(shared_ptr player, int butto Slot *AbstractContainerMenu::getSlotFor(shared_ptr c, int index) { - AUTO_VAR(itEnd, slots->end()); - for (AUTO_VAR(it, slots->begin()); it != itEnd; it++) + AUTO_VAR(itEnd, slots.end()); + for (AUTO_VAR(it, slots.begin()); it != itEnd; it++) { Slot *slot = *it; //slots->at(i); if (slot->isAt(c, index)) @@ -137,12 +136,12 @@ Slot *AbstractContainerMenu::getSlotFor(shared_ptr c, int index) Slot *AbstractContainerMenu::getSlot(int index) { - return slots->at(index); + return slots.at(index); } shared_ptr AbstractContainerMenu::quickMoveStack(shared_ptr player, int slotIndex) { - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot != NULL) { return slot->getItem(); @@ -150,18 +149,97 @@ shared_ptr AbstractContainerMenu::quickMoveStack(shared_ptr AbstractContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player) +shared_ptr AbstractContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player, bool looped) // 4J Added looped param { shared_ptr clickedEntity = nullptr; shared_ptr inventory = player->inventory; - if ((clickType == CLICK_PICKUP || clickType == CLICK_QUICK_MOVE) && (buttonNum == 0 || buttonNum == 1)) + if (clickType == CLICK_QUICK_CRAFT) + { + int expectedStatus = quickcraftStatus; + quickcraftStatus = getQuickcraftHeader(buttonNum); + + if ((expectedStatus != QUICKCRAFT_HEADER_CONTINUE || quickcraftStatus != QUICKCRAFT_HEADER_END) && expectedStatus != quickcraftStatus) + { + resetQuickCraft(); + } + else if (inventory->getCarried() == NULL) + { + resetQuickCraft(); + } + else if (quickcraftStatus == QUICKCRAFT_HEADER_START) + { + quickcraftType = getQuickcraftType(buttonNum); + + if (isValidQuickcraftType(quickcraftType)) + { + quickcraftStatus = QUICKCRAFT_HEADER_CONTINUE; + quickcraftSlots.clear(); + } + else + { + resetQuickCraft(); + } + } + else if (quickcraftStatus == QUICKCRAFT_HEADER_CONTINUE) + { + Slot *slot = slots.at(slotIndex); + + if (slot != NULL && canItemQuickReplace(slot, inventory->getCarried(), true) && slot->mayPlace(inventory->getCarried()) && inventory->getCarried()->count > quickcraftSlots.size() && canDragTo(slot)) + { + quickcraftSlots.insert(slot); + } + } + else if (quickcraftStatus == QUICKCRAFT_HEADER_END) + { + if (!quickcraftSlots.empty()) + { + shared_ptr source = inventory->getCarried()->copy(); + int remaining = inventory->getCarried()->count; + + for(AUTO_VAR(it, quickcraftSlots.begin()); it != quickcraftSlots.end(); ++it) + { + Slot *slot = *it; + if (slot != NULL && canItemQuickReplace(slot, inventory->getCarried(), true) && slot->mayPlace(inventory->getCarried()) && inventory->getCarried()->count >= quickcraftSlots.size() && canDragTo(slot)) + { + shared_ptr copy = source->copy(); + int carry = slot->hasItem() ? slot->getItem()->count : 0; + getQuickCraftSlotCount(&quickcraftSlots, quickcraftType, copy, carry); + + if (copy->count > copy->getMaxStackSize()) copy->count = copy->getMaxStackSize(); + if (copy->count > slot->getMaxStackSize()) copy->count = slot->getMaxStackSize(); + + remaining -= copy->count - carry; + slot->set(copy); + } + } + + source->count = remaining; + if (source->count <= 0) + { + source = nullptr; + } + inventory->setCarried(source); + } + + resetQuickCraft(); + } + else + { + resetQuickCraft(); + } + } + else if (quickcraftStatus != QUICKCRAFT_HEADER_START) + { + resetQuickCraft(); + } + else if ((clickType == CLICK_PICKUP || clickType == CLICK_QUICK_MOVE) && (buttonNum == 0 || buttonNum == 1)) { - if (slotIndex == CLICKED_OUTSIDE) + if (slotIndex == SLOT_CLICKED_OUTSIDE) { if (inventory->getCarried() != NULL) { - if (slotIndex == CLICKED_OUTSIDE) + if (slotIndex == SLOT_CLICKED_OUTSIDE) { if (buttonNum == 0) { @@ -179,23 +257,38 @@ shared_ptr AbstractContainerMenu::clicked(int slotIndex, int butto } else if (clickType == CLICK_QUICK_MOVE) { - Slot *slot = slots->at(slotIndex); + if (slotIndex < 0) return nullptr; + Slot *slot = slots.at(slotIndex); if(slot != NULL && slot->mayPickup(player)) { shared_ptr piiClicked = quickMoveStack(player, slotIndex); if (piiClicked != NULL) { - //int oldSize = piiClicked->count; // 4J - Commented 1.8.2 and replaced with below int oldType = piiClicked->id; - clickedEntity = piiClicked->copy(); + // 4J Stu - We ignore the return value for loopClicks, so don't make a copy + if(!looped) + { + clickedEntity = piiClicked->copy(); + } + + // 4J Stu - Remove the reference to this before we start a recursive loop + piiClicked = nullptr; if (slot != NULL) { if (slot->getItem() != NULL && slot->getItem()->id == oldType) { - // 4J Stu - Brought forward loopClick from 1.2 to fix infinite recursion bug in creative - loopClick(slotIndex, buttonNum, true, player); + if(looped) + { + // Return a non-null value to indicate that we want to loop more + clickedEntity = shared_ptr(new ItemInstance(0,1,0)); + } + else + { + // 4J Stu - Brought forward loopClick from 1.2 to fix infinite recursion bug in creative + loopClick(slotIndex, buttonNum, true, player); + } } } } @@ -205,7 +298,7 @@ shared_ptr AbstractContainerMenu::clicked(int slotIndex, int butto { if (slotIndex < 0) return nullptr; - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot != NULL) { shared_ptr clicked = slot->getItem(); @@ -225,7 +318,10 @@ shared_ptr AbstractContainerMenu::clicked(int slotIndex, int butto { c = slot->getMaxStackSize(); } - slot->set(carried->remove(c)); + if (carried->count >= c) + { + slot->set(carried->remove(c)); + } if (carried->count == 0) { inventory->setCarried(nullptr); @@ -318,7 +414,7 @@ shared_ptr AbstractContainerMenu::clicked(int slotIndex, int butto } else if (clickType == CLICK_SWAP && buttonNum >= 0 && buttonNum < 9) { - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot->mayPickup(player)) { shared_ptr current = inventory->getItem(buttonNum); @@ -359,7 +455,7 @@ shared_ptr AbstractContainerMenu::clicked(int slotIndex, int butto } else if (clickType == CLICK_CLONE && player->abilities.instabuild && inventory->getCarried() == NULL && slotIndex >= 0) { - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot != NULL && slot->hasItem()) { shared_ptr copy = slot->getItem()->copy(); @@ -367,13 +463,66 @@ shared_ptr AbstractContainerMenu::clicked(int slotIndex, int butto inventory->setCarried(copy); } } + else if (clickType == CLICK_THROW && inventory->getCarried() == NULL && slotIndex >= 0) + { + Slot *slot = slots.at(slotIndex); + if (slot != NULL && slot->hasItem() && slot->mayPickup(player)) + { + shared_ptr item = slot->remove(buttonNum == 0 ? 1 : slot->getItem()->count); + slot->onTake(player, item); + player->drop(item); + } + } + else if (clickType == CLICK_PICKUP_ALL && slotIndex >= 0) + { + Slot *slot = slots.at(slotIndex); + shared_ptr carried = inventory->getCarried(); + + if (carried != NULL && (slot == NULL || !slot->hasItem() || !slot->mayPickup(player))) + { + int start = buttonNum == 0 ? 0 : slots.size() - 1; + int step = buttonNum == 0 ? 1 : -1; + + for (int pass = 0; pass < 2; pass++ ) + { + // In the first pass, we only get partial stacks. + for (int i = start; i >= 0 && i < slots.size() && carried->count < carried->getMaxStackSize(); i += step) + { + Slot *target = slots.at(i); + + if (target->hasItem() && canItemQuickReplace(target, carried, true) && target->mayPickup(player) && canTakeItemForPickAll(carried, target)) + { + if (pass == 0 && target->getItem()->count == target->getItem()->getMaxStackSize()) continue; + int count = min(carried->getMaxStackSize() - carried->count, target->getItem()->count); + shared_ptr removed = target->remove(count); + carried->count += count; + + if (removed->count <= 0) + { + target->set(nullptr); + } + target->onTake(player, removed); + } + } + } + } + + broadcastChanges(); + } return clickedEntity; } +bool AbstractContainerMenu::canTakeItemForPickAll(shared_ptr carried, Slot *target) +{ + return true; +} + // 4J Stu - Brought forward from 1.2 to fix infinite recursion bug in creative void AbstractContainerMenu::loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, shared_ptr player) { - clicked(slotIndex, buttonNum, CLICK_QUICK_MOVE, player); + while( clicked(slotIndex, buttonNum, CLICK_QUICK_MOVE, player, true) != NULL) + { + } } bool AbstractContainerMenu::mayCombine(Slot *slot, shared_ptr item) @@ -460,7 +609,7 @@ bool AbstractContainerMenu::moveItemStackTo(shared_ptr itemStack, while (itemStack->count > 0 && ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot))) { - Slot *slot = slots->at(destSlot); + Slot *slot = slots.at(destSlot); shared_ptr target = slot->getItem(); if (target != NULL && target->id == itemStack->id && (!itemStack->isStackedByData() || itemStack->getAuxValue() == target->getAuxValue()) && ItemInstance::tagMatches(itemStack, target) ) @@ -506,7 +655,7 @@ bool AbstractContainerMenu::moveItemStackTo(shared_ptr itemStack, } while ((!backwards && destSlot < endSlot) || (backwards && destSlot >= startSlot)) { - Slot *slot = slots->at(destSlot); + Slot *slot = slots.at(destSlot); shared_ptr target = slot->getItem(); if (target == NULL) @@ -535,3 +684,88 @@ bool AbstractContainerMenu::isOverrideResultClick(int slotNum, int buttonNum) { return false; } + +int AbstractContainerMenu::getQuickcraftType(int mask) +{ + return (mask >> 2) & 0x3; +} + +int AbstractContainerMenu::getQuickcraftHeader(int mask) +{ + return mask & 0x3; +} + +int AbstractContainerMenu::getQuickcraftMask(int header, int type) +{ + return (header & 0x3) | ((type & 0x3) << 2); +} + +bool AbstractContainerMenu::isValidQuickcraftType(int type) +{ + return type == QUICKCRAFT_TYPE_CHARITABLE || type == QUICKCRAFT_TYPE_GREEDY; +} + +void AbstractContainerMenu::resetQuickCraft() +{ + quickcraftStatus = QUICKCRAFT_HEADER_START; + quickcraftSlots.clear(); +} + +bool AbstractContainerMenu::canItemQuickReplace(Slot *slot, shared_ptr item, bool ignoreSize) +{ + bool canReplace = slot == NULL || !slot->hasItem(); + + if (slot != NULL && slot->hasItem() && item != NULL && item->sameItem(slot->getItem()) && ItemInstance::tagMatches(slot->getItem(), item)) + { + canReplace |= slot->getItem()->count + (ignoreSize ? 0 : item->count) <= item->getMaxStackSize(); + } + + return canReplace; +} + +void AbstractContainerMenu::getQuickCraftSlotCount(unordered_set *quickCraftSlots, int quickCraftingType, shared_ptr item, int carry) +{ + switch (quickCraftingType) + { + case QUICKCRAFT_TYPE_CHARITABLE: + item->count = Mth::floor(item->count / (float) quickCraftSlots->size()); + break; + case QUICKCRAFT_TYPE_GREEDY: + item->count = 1; + break; + } + + item->count += carry; +} + +bool AbstractContainerMenu::canDragTo(Slot *slot) +{ + return true; +} + +int AbstractContainerMenu::getRedstoneSignalFromContainer(shared_ptr container) +{ + if (container == NULL) return 0; + int count = 0; + float totalPct = 0; + + for (int i = 0; i < container->getContainerSize(); i++) + { + shared_ptr item = container->getItem(i); + + if (item != NULL) + { + totalPct += item->count / (float) min(container->getMaxStackSize(), item->getMaxStackSize()); + count++; + } + } + + totalPct /= container->getContainerSize(); + return Mth::floor(totalPct * (Redstone::SIGNAL_MAX - 1)) + (count > 0 ? 1 : 0); +} + +// 4J Added +bool AbstractContainerMenu::isValidIngredient(shared_ptr item, int slotId) +{ + return true; +} \ No newline at end of file diff --git a/Minecraft.World/AbstractContainerMenu.h b/Minecraft.World/AbstractContainerMenu.h index f34e1afc..5ac115de 100644 --- a/Minecraft.World/AbstractContainerMenu.h +++ b/Minecraft.World/AbstractContainerMenu.h @@ -14,28 +14,43 @@ class Container; class AbstractContainerMenu { public: - static const int CLICKED_OUTSIDE = -999; + static const int SLOT_CLICKED_OUTSIDE = -999; static const int CLICK_PICKUP = 0; static const int CLICK_QUICK_MOVE = 1; static const int CLICK_SWAP = 2; static const int CLICK_CLONE = 3; + static const int CLICK_THROW = 4; + static const int CLICK_QUICK_CRAFT = 5; + static const int CLICK_PICKUP_ALL = 6; + + static const int QUICKCRAFT_TYPE_CHARITABLE = 0; + static const int QUICKCRAFT_TYPE_GREEDY = 1; + static const int QUICKCRAFT_HEADER_START = 0; + static const int QUICKCRAFT_HEADER_CONTINUE = 1; + static const int QUICKCRAFT_HEADER_END = 2; // 4J Stu - Added these to fix problem with items picked up while in the creative menu replacing slots in the creative menu static const int CONTAINER_ID_CARRIED = -1; static const int CONTAINER_ID_INVENTORY = 0; static const int CONTAINER_ID_CREATIVE = -2; - vector > *lastSlots; - vector *slots; + vector > lastSlots; + vector slots; int containerId; private: short changeUid; + + int quickcraftType; + int quickcraftStatus; + unordered_set quickcraftSlots; + +private: bool m_bNeedsRendered; // 4J added protected: - vector *containerListeners; + vector containerListeners; // 4J Stu - The java does not have ctor here (being an abstract) but we need one to initialise the member variables // TODO Make sure all derived classes also call this @@ -46,18 +61,22 @@ protected: public: virtual ~AbstractContainerMenu(); virtual void addSlotListener(ContainerListener *listener); - vector > *getItems(); - void sendData(int id, int value); + virtual void removeSlotListener(ContainerListener *listener); + virtual vector > *getItems(); + virtual void sendData(int id, int value); virtual void broadcastChanges(); virtual bool needsRendered(); virtual bool clickMenuButton(shared_ptr player, int buttonId); - Slot *getSlotFor(shared_ptr c, int index); - Slot *getSlot(int index); + virtual Slot *getSlotFor(shared_ptr c, int index); + virtual Slot *getSlot(int index); virtual shared_ptr quickMoveStack(shared_ptr player, int slotIndex); - virtual shared_ptr clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player); + virtual shared_ptr clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player, bool looped = false); // 4J added looped param virtual bool mayCombine(Slot *slot, shared_ptr item); + virtual bool canTakeItemForPickAll(shared_ptr carried, Slot *target); + protected: virtual void loopClick(int slotIndex, int buttonNum, bool quickKeyHeld, shared_ptr player); + public: virtual void removed(shared_ptr player); virtual void slotsChanged();// 4J used to take a shared_ptr container but wasn't using it, so removed to simplify things @@ -76,7 +95,7 @@ public: virtual bool stillValid(shared_ptr player) = 0; // 4J Stu Added for UI - unsigned int getSize() { return (unsigned int)slots->size(); } + unsigned int getSize() { return (unsigned int)slots.size(); } protected: @@ -85,4 +104,21 @@ protected: public: virtual bool isOverrideResultClick(int slotNum, int buttonNum); + + static int getQuickcraftType(int mask); + static int getQuickcraftHeader(int mask); + static int getQuickcraftMask(int header, int type); + static bool isValidQuickcraftType(int type); + +protected: + void resetQuickCraft(); + +public: + static bool canItemQuickReplace(Slot *slot, shared_ptr item, bool ignoreSize); + static void getQuickCraftSlotCount(unordered_set *quickCraftSlots, int quickCraftingType, shared_ptr item, int carry); + bool canDragTo(Slot *slot); + static int getRedstoneSignalFromContainer(shared_ptr container); + + // 4J Added + virtual bool isValidIngredient(shared_ptr item, int slotId); }; diff --git a/Minecraft.World/AbstractProjectileDispenseBehavior.cpp b/Minecraft.World/AbstractProjectileDispenseBehavior.cpp new file mode 100644 index 00000000..ccff196f --- /dev/null +++ b/Minecraft.World/AbstractProjectileDispenseBehavior.cpp @@ -0,0 +1,48 @@ +#include "stdafx.h" + +#include "AbstractProjectileDispenseBehavior.h" +#include "DispenserTile.h" +#include "Projectile.h" +#include "Level.h" +#include "LevelEvent.h" +#include "ItemInstance.h" + +shared_ptr AbstractProjectileDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + Level *world = source->getWorld(); + if ( world->countInstanceOf(eTYPE_PROJECTILE, false) >= Level::MAX_DISPENSABLE_PROJECTILES ) + { + return DefaultDispenseItemBehavior::execute(source, dispensed, outcome); + } + + Position *position = DispenserTile::getDispensePosition(source); + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + + shared_ptr projectile = getProjectile(world, position); + + delete position; + + projectile->shoot(facing->getStepX(), facing->getStepY() + .1f, facing->getStepZ(), getPower(), getUncertainty()); + world->addEntity(dynamic_pointer_cast(projectile)); + + dispensed->remove(1); + return dispensed; +} + +void AbstractProjectileDispenseBehavior::playSound(BlockSource *source, eOUTCOME outcome) +{ + if (outcome != LEFT_ITEM) + { + source->getWorld()->levelEvent(LevelEvent::SOUND_LAUNCH, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + } +} + +float AbstractProjectileDispenseBehavior::getUncertainty() +{ + return 6.0f; +} + +float AbstractProjectileDispenseBehavior::getPower() +{ + return 1.1f; +} diff --git a/Minecraft.World/AbstractProjectileDispenseBehavior.h b/Minecraft.World/AbstractProjectileDispenseBehavior.h new file mode 100644 index 00000000..75053d6b --- /dev/null +++ b/Minecraft.World/AbstractProjectileDispenseBehavior.h @@ -0,0 +1,17 @@ +#pragma once +#include "DefaultDispenseItemBehavior.h" + +class Projectile; +class Position; + +class AbstractProjectileDispenseBehavior : public DefaultDispenseItemBehavior +{ +public: + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); + +protected: + virtual void playSound(BlockSource *source, eOUTCOME outcome); + virtual float getUncertainty(); + virtual float getPower(); + virtual shared_ptr getProjectile(Level *world, Position *position) = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/AddEntityPacket.h b/Minecraft.World/AddEntityPacket.h index 5ac7286c..29396479 100644 --- a/Minecraft.World/AddEntityPacket.h +++ b/Minecraft.World/AddEntityPacket.h @@ -8,35 +8,34 @@ class AddEntityPacket : public Packet, public enable_shared_from_this e, int type, int yRotp, int xRotp, int xp, int yp, int zp); + AddEntityPacket(shared_ptr e, int type, int yRotp, int xRotp, int xp, int yp, int zp); AddEntityPacket(shared_ptr e, int type, int data, int yRotp, int xRotp, int xp, int yp, int zp ); virtual void read(DataInputStream *dis); diff --git a/Minecraft.World/AddGlobalEntityPacket.cpp b/Minecraft.World/AddGlobalEntityPacket.cpp index bfb27331..9d688f74 100644 --- a/Minecraft.World/AddGlobalEntityPacket.cpp +++ b/Minecraft.World/AddGlobalEntityPacket.cpp @@ -26,13 +26,13 @@ AddGlobalEntityPacket::AddGlobalEntityPacket(shared_ptr e) x = Mth::floor(e->x * 32); y = Mth::floor(e->y * 32); z = Mth::floor(e->z * 32); - if (dynamic_pointer_cast(e) != NULL) + if ( e->instanceof(eTYPE_LIGHTNINGBOLT) ) { - this->type = LIGHTNING; + type = LIGHTNING; } else { - this->type = 0; + type = 0; } } diff --git a/Minecraft.World/AddMobPacket.cpp b/Minecraft.World/AddMobPacket.cpp index 7e744c04..878e2ee7 100644 --- a/Minecraft.World/AddMobPacket.cpp +++ b/Minecraft.World/AddMobPacket.cpp @@ -25,7 +25,7 @@ AddMobPacket::~AddMobPacket() delete unpack; } -AddMobPacket::AddMobPacket(shared_ptr mob, int yRotp, int xRotp, int xp, int yp, int zp, int yHeadRotp) +AddMobPacket::AddMobPacket(shared_ptr mob, int yRotp, int xRotp, int xp, int yp, int zp, int yHeadRotp) { id = mob->entityId; diff --git a/Minecraft.World/AddMobPacket.h b/Minecraft.World/AddMobPacket.h index 37de84c3..6af72655 100644 --- a/Minecraft.World/AddMobPacket.h +++ b/Minecraft.World/AddMobPacket.h @@ -4,7 +4,7 @@ using namespace std; #include "Packet.h" #include "SynchedEntityData.h" -class Mob; +class LivingEntity; class AddMobPacket : public Packet, public enable_shared_from_this { @@ -22,7 +22,7 @@ private: public: AddMobPacket(); ~AddMobPacket(); - AddMobPacket(shared_ptr mob, int yRotp, int xRotp, int xp, int yp, int zp, int yHeadRotp); + AddMobPacket(shared_ptr mob, int yRotp, int xRotp, int xp, int yp, int zp, int yHeadRotp); virtual void read(DataInputStream *dis); virtual void write(DataOutputStream *dos); diff --git a/Minecraft.World/AddPlayerPacket.cpp b/Minecraft.World/AddPlayerPacket.cpp index f3d8a32b..93984367 100644 --- a/Minecraft.World/AddPlayerPacket.cpp +++ b/Minecraft.World/AddPlayerPacket.cpp @@ -35,7 +35,7 @@ AddPlayerPacket::~AddPlayerPacket() AddPlayerPacket::AddPlayerPacket(shared_ptr player, PlayerUID xuid, PlayerUID OnlineXuid,int xp, int yp, int zp, int yRotp, int xRotp, int yHeadRotp) { id = player->entityId; - name = player->name; + name = player->getName(); // 4J Stu - Send "previously sent" value of position as well so that we stay in sync x = xp;//Mth::floor(player->x * 32); diff --git a/Minecraft.World/AgableMob.cpp b/Minecraft.World/AgableMob.cpp index 39bcadbe..307aa767 100644 --- a/Minecraft.World/AgableMob.cpp +++ b/Minecraft.World/AgableMob.cpp @@ -13,40 +13,51 @@ AgableMob::AgableMob(Level *level) : PathfinderMob(level) registeredBBHeight = 0; } -bool AgableMob::interact(shared_ptr player) +bool AgableMob::mobInteract(shared_ptr player) { shared_ptr item = player->inventory->getSelected(); - if (item != NULL && item->id == Item::monsterPlacer_Id) + if (item != NULL && item->id == Item::spawnEgg_Id) { if (!level->isClientSide) { eINSTANCEOF classToSpawn = EntityIO::getClass(item->getAuxValue()); if (classToSpawn != eTYPE_NOTSET && (classToSpawn & eTYPE_AGABLE_MOB) == eTYPE_AGABLE_MOB && classToSpawn == GetType() ) // 4J Added GetType() check to only spawn same type { - shared_ptr offspring = getBreedOffspring(dynamic_pointer_cast(shared_from_this())); - if (offspring != NULL) - { - offspring->setAge(-20 * 60 * 20); - offspring->moveTo(x, y, z, 0, 0); - - level->addEntity(offspring); + int error; + shared_ptr result = SpawnEggItem::canSpawn(item->getAuxValue(), level, &error); - if (!player->abilities.instabuild) + if (result != NULL) + { + shared_ptr offspring = getBreedOffspring(dynamic_pointer_cast(shared_from_this())); + if (offspring != NULL) { - item->count--; + offspring->setAge(BABY_START_AGE); + offspring->moveTo(x, y, z, 0, 0); - if (item->count <= 0) + level->addEntity(offspring); + + if (!player->abilities.instabuild) { - player->inventory->setItem(player->inventory->selected, nullptr); + item->count--; + + if (item->count <= 0) + { + player->inventory->setItem(player->inventory->selected, nullptr); + } } } } + else + { + SpawnEggItem::DisplaySpawnError(player, error); + } } } + return true; } - return PathfinderMob::interact(player); + return false; } void AgableMob::defineSynchedData() @@ -60,6 +71,17 @@ int AgableMob::getAge() return entityData->getInteger(DATA_AGE_ID); } +void AgableMob::ageUp(int seconds) +{ + int age = getAge(); + age += seconds * SharedConstants::TICKS_PER_SECOND; + if (age > 0) + { + age = 0; + } + setAge(age); +} + void AgableMob::setAge(int age) { entityData->set(DATA_AGE_ID, age); diff --git a/Minecraft.World/AgableMob.h b/Minecraft.World/AgableMob.h index 0020e876..49f76f9e 100644 --- a/Minecraft.World/AgableMob.h +++ b/Minecraft.World/AgableMob.h @@ -7,13 +7,17 @@ class AgableMob : public PathfinderMob private: static const int DATA_AGE_ID = 12; +public: + static const int BABY_START_AGE = -20 * 60 * 20; + +private: float registeredBBWidth; float registeredBBHeight; public: AgableMob(Level *level); - virtual bool interact(shared_ptr player); + virtual bool mobInteract(shared_ptr player); protected: virtual void defineSynchedData(); @@ -21,6 +25,7 @@ protected: public: virtual shared_ptr getBreedOffspring(shared_ptr target) = 0; virtual int getAge(); + virtual void ageUp(int seconds); virtual void setAge(int age); virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); diff --git a/Minecraft.World/AmbientCreature.cpp b/Minecraft.World/AmbientCreature.cpp new file mode 100644 index 00000000..9f01f0ec --- /dev/null +++ b/Minecraft.World/AmbientCreature.cpp @@ -0,0 +1,17 @@ +#include "stdafx.h" + +#include "AmbientCreature.h" + +AmbientCreature::AmbientCreature(Level *level) : Mob(level) +{ +} + +bool AmbientCreature::canBeLeashed() +{ + return false; +} + +bool AmbientCreature::mobInteract(shared_ptr player) +{ + return false; +} \ No newline at end of file diff --git a/Minecraft.World/AmbientCreature.h b/Minecraft.World/AmbientCreature.h new file mode 100644 index 00000000..ac7a75e0 --- /dev/null +++ b/Minecraft.World/AmbientCreature.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Mob.h" +#include "Creature.h" + +class AmbientCreature : public Mob, public Creature +{ + +public: + AmbientCreature(Level *level); + + virtual bool canBeLeashed(); + +protected: + virtual bool mobInteract(shared_ptr player); +}; \ No newline at end of file diff --git a/Minecraft.World/Animal.cpp b/Minecraft.World/Animal.cpp index 45fc304f..31de7d75 100644 --- a/Minecraft.World/Animal.cpp +++ b/Minecraft.World/Animal.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" + #include "com.mojang.nbt.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.item.h" @@ -9,11 +10,11 @@ #include "net.minecraft.world.entity.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "Random.h" #include "Animal.h" - - Animal::Animal(Level *level) : AgableMob( level ) { // inLove = 0; // 4J removed - now synched data @@ -64,7 +65,8 @@ void Animal::aiStep() void Animal::checkHurtTarget(shared_ptr target, float d) { - if (dynamic_pointer_cast(target) != NULL) + // 4J-JEV: Changed from dynamic cast to use eINSTANCEOF + if ( target->instanceof(eTYPE_PLAYER) ) { if (d < 3) { @@ -76,16 +78,14 @@ void Animal::checkHurtTarget(shared_ptr target, float d) } shared_ptr p = dynamic_pointer_cast(target); - if (p->getSelectedItem() != NULL && this->isFood(p->getSelectedItem())) - { - } - else + if (p->getSelectedItem() == NULL || !isFood(p->getSelectedItem())) { attackTarget = nullptr; } } - else if (dynamic_pointer_cast(target) != NULL) + // 4J-JEV: Changed from dynamic cast to use eINSTANCEOF + else if ( target->instanceof(eTYPE_ANIMAL) ) { shared_ptr a = dynamic_pointer_cast(target); if (getAge() > 0 && a->getAge() < 0) @@ -166,21 +166,25 @@ float Animal::getWalkTargetValue(int x, int y, int z) return level->getBrightness(x, y, z) - 0.5f; } -bool Animal::hurt(DamageSource *dmgSource, int dmg) +bool Animal::hurt(DamageSource *dmgSource, float dmg) { + if (isInvulnerable()) return false; if (dynamic_cast(dmgSource) != NULL) { shared_ptr source = dmgSource->getDirectEntity(); - if (dynamic_pointer_cast(source) != NULL && !dynamic_pointer_cast(source)->isAllowedToAttackAnimals() ) + // 4J-JEV: Changed from dynamic cast to use eINSTANCEOF + if ( source->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast(source)->isAllowedToAttackAnimals() ) { return false; } - if (source != NULL && source->GetType() == eTYPE_ARROW) + if ( (source != NULL) && source->instanceof(eTYPE_ARROW) ) { shared_ptr arrow = dynamic_pointer_cast(source); - if (dynamic_pointer_cast(arrow->owner) != NULL && ! dynamic_pointer_cast(arrow->owner)->isAllowedToAttackAnimals() ) + + // 4J: Check that the arrow's owner can attack animals (dispenser arrows are not owned) + if (arrow->owner != NULL && arrow->owner->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast(arrow->owner)->isAllowedToAttackAnimals() ) { return false; } @@ -188,6 +192,16 @@ bool Animal::hurt(DamageSource *dmgSource, int dmg) } fleeTime = 20 * 3; + + if (!useNewAi()) + { + AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + if (speed->getModifier(eModifierId_MOB_FLEEING) == NULL) + { + speed->addModifier(new AttributeModifier(*Animal::SPEED_MODIFIER_FLEEING)); + } + } + attackTarget = nullptr; setInLoveValue(0); @@ -293,10 +307,10 @@ bool Animal::isFood(shared_ptr itemInstance) return itemInstance->id == Item::wheat_Id; } -bool Animal::interact(shared_ptr player) +bool Animal::mobInteract(shared_ptr player) { shared_ptr item = player->inventory->getSelected(); - if (item != NULL && isFood(item) && getAge() == 0) + if (item != NULL && isFood(item) && getAge() == 0 && getInLoveValue() <= 0) { if (!player->abilities.instabuild) { @@ -344,7 +358,7 @@ bool Animal::interact(shared_ptr player) return false; } } - else if( (GetType() & eTYPE_MONSTER) == eTYPE_MONSTER) + else if( instanceof(eTYPE_MONSTER) ) { } @@ -352,20 +366,11 @@ bool Animal::interact(shared_ptr player) } setInLove(player); } - - - attackTarget = nullptr; - for (int i = 0; i < 7; i++) - { - double xa = random->nextGaussian() * 0.02; - double ya = random->nextGaussian() * 0.02; - double za = random->nextGaussian() * 0.02; - level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); - } + setInLove(); return true; } - return AgableMob::interact(player); + return AgableMob::mobInteract(player); } // 4J added @@ -391,6 +396,14 @@ shared_ptr Animal::getLoveCause() return loveCause.lock(); } +void Animal::setInLove() +{ + entityData->set(DATA_IN_LOVE, 20 * 30); + + attackTarget = nullptr; + level->broadcastEntityEvent(shared_from_this(), EntityEvent::IN_LOVE_HEARTS); +} + bool Animal::isInLove() { return entityData->getInteger(DATA_IN_LOVE) > 0; @@ -407,6 +420,24 @@ bool Animal::canMate(shared_ptr partner) return isInLove() && partner->isInLove(); } +void Animal::handleEntityEvent(byte id) +{ + if (id == EntityEvent::IN_LOVE_HEARTS) + { + for (int i = 0; i < 7; i++) + { + double xa = random->nextGaussian() * 0.02; + double ya = random->nextGaussian() * 0.02; + double za = random->nextGaussian() * 0.02; + level->addParticle(eParticleType_heart, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); + } + } + else + { + AgableMob::handleEntityEvent(id); + } +} + void Animal::updateDespawnProtectedState() { if( level->isClientSide ) return; @@ -455,4 +486,4 @@ void Animal::setDespawnProtected() m_maxWanderZ = zt; m_isDespawnProtected = true; -} +} \ No newline at end of file diff --git a/Minecraft.World/Animal.h b/Minecraft.World/Animal.h index 8c0cda8e..85a20439 100644 --- a/Minecraft.World/Animal.h +++ b/Minecraft.World/Animal.h @@ -35,7 +35,7 @@ public: virtual float getWalkTargetValue(int x, int y, int z); public: - virtual bool hurt(DamageSource *source, int dmg); + virtual bool hurt(DamageSource *source, float dmg); virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); @@ -52,7 +52,7 @@ protected: public: virtual bool isFood(shared_ptr itemInstance); - virtual bool interact(shared_ptr player); + virtual bool mobInteract(shared_ptr player); protected: int getInLoveValue(); // 4J added @@ -60,10 +60,12 @@ protected: public: void setInLoveValue(int value); // 4J added void setInLove(shared_ptr player); // 4J added, then modified to match latest Java for XboxOne achievements + virtual void setInLove(); shared_ptr getLoveCause(); bool isInLove(); void resetLove(); virtual bool canMate(shared_ptr partner); + virtual void handleEntityEvent(byte id); // 4J added for determining whether animals are enclosed or not private: diff --git a/Minecraft.World/AnimalChest.cpp b/Minecraft.World/AnimalChest.cpp new file mode 100644 index 00000000..42729c92 --- /dev/null +++ b/Minecraft.World/AnimalChest.cpp @@ -0,0 +1,11 @@ +#include "stdafx.h" + +#include "AnimalChest.h" + +AnimalChest::AnimalChest(const wstring &name, int size) : SimpleContainer(IDS_CONTAINER_ANIMAL, name, false, size) +{ +} + +AnimalChest::AnimalChest(int iTitle, const wstring &name, bool hasCustomName, int size) : SimpleContainer(iTitle, name, hasCustomName, size) +{ +} \ No newline at end of file diff --git a/Minecraft.World/AnimalChest.h b/Minecraft.World/AnimalChest.h new file mode 100644 index 00000000..a8b360fd --- /dev/null +++ b/Minecraft.World/AnimalChest.h @@ -0,0 +1,10 @@ +#pragma once + +#include "SimpleContainer.h" + +class AnimalChest : public SimpleContainer +{ +public: + AnimalChest(const wstring &name, int size); + AnimalChest(int iTitle, const wstring &name, bool hasCustomName, int size); // 4J Added iTitle param +}; \ No newline at end of file diff --git a/Minecraft.World/AnvilMenu.cpp b/Minecraft.World/AnvilMenu.cpp new file mode 100644 index 00000000..2ef00e3e --- /dev/null +++ b/Minecraft.World/AnvilMenu.cpp @@ -0,0 +1,426 @@ +#include "stdafx.h" +#include "net.minecraft.world.inventory.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.item.enchantment.h" +#include "AnvilMenu.h" + +AnvilMenu::AnvilMenu(shared_ptr inventory, Level *level, int xt, int yt, int zt, shared_ptr player) +{ + resultSlots = shared_ptr( new ResultContainer() ); + repairSlots = shared_ptr( new RepairContainer(this,IDS_REPAIR_AND_NAME, true, 2) ); + cost = 0; + repairItemCountCost = 0; + + this->level = level; + x = xt; + y = yt; + z = zt; + this->player = player; + + addSlot(new Slot(repairSlots, INPUT_SLOT, 27, 43 + 4)); + addSlot(new Slot(repairSlots, ADDITIONAL_SLOT, 76, 43 + 4)); + + // 4J Stu - Anonymous class here is now RepairResultSlot + addSlot(new RepairResultSlot(this, xt, yt, zt, resultSlots, RESULT_SLOT, 134, 43 + 4)); + + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(inventory, x + y * 9 + 9, 8 + x * 18, 84 + y * 18)); + } + } + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(inventory, x, 8 + x * 18, 142)); + } +} + +void AnvilMenu::slotsChanged(shared_ptr container) +{ + AbstractContainerMenu::slotsChanged(); + + if (container == repairSlots) createResult(); +} + +void AnvilMenu::createResult() +{ + shared_ptr input = repairSlots->getItem(INPUT_SLOT); + cost = 0; + int price = 0; + int tax = 0; + int namingCost = 0; + + if (DEBUG_COST) app.DebugPrintf("----"); + + if (input == NULL) + { + resultSlots->setItem(0, nullptr); + cost = 0; + return; + } + else + { + shared_ptr result = input->copy(); + shared_ptr addition = repairSlots->getItem(ADDITIONAL_SLOT); + unordered_map *enchantments = EnchantmentHelper::getEnchantments(result); + bool usingBook = false; + + tax += input->getBaseRepairCost() + (addition == NULL ? 0 : addition->getBaseRepairCost()); + if (DEBUG_COST) + { + app.DebugPrintf("Starting with base repair tax of %d (%d + %d)\n", tax, input->getBaseRepairCost(), (addition == NULL ? 0 : addition->getBaseRepairCost())); + } + + repairItemCountCost = 0; + + if (addition != NULL) + { + usingBook = addition->id == Item::enchantedBook_Id && Item::enchantedBook->getEnchantments(addition)->size() > 0; + + if (result->isDamageableItem() && Item::items[result->id]->isValidRepairItem(input, addition)) + { + int repairAmount = min(result->getDamageValue(), result->getMaxDamage() / 4); + if (repairAmount <= 0) + { + resultSlots->setItem(0, nullptr); + cost = 0; + return; + } + else + { + int count = 0; + while (repairAmount > 0 && count < addition->count) + { + int resultDamage = result->getDamageValue() - repairAmount; + result->setAuxValue(resultDamage); + price += max(1, repairAmount / 100) + enchantments->size(); + + repairAmount = min(result->getDamageValue(), result->getMaxDamage() / 4); + count++; + } + repairItemCountCost = count; + } + } + else if (!usingBook && (result->id != addition->id || !result->isDamageableItem())) + { + resultSlots->setItem(0, nullptr); + cost = 0; + return; + } + else + { + if (result->isDamageableItem() && !usingBook) + { + int remaining1 = input->getMaxDamage() - input->getDamageValue(); + int remaining2 = addition->getMaxDamage() - addition->getDamageValue(); + int additional = remaining2 + result->getMaxDamage() * 12 / 100; + int remaining = remaining1 + additional; + int resultDamage = result->getMaxDamage() - remaining; + if (resultDamage < 0) resultDamage = 0; + + if (resultDamage < result->getAuxValue()) + { + result->setAuxValue(resultDamage); + price += max(1, additional / 100); + if (DEBUG_COST) + { + app.DebugPrintf("Repairing; price is now %d (went up by %d)\n", price, max(1, additional / 100) ); + } + } + } + + unordered_map *additionalEnchantments = EnchantmentHelper::getEnchantments(addition); + + for(AUTO_VAR(it, additionalEnchantments->begin()); it != additionalEnchantments->end(); ++it) + { + int id = it->first; + Enchantment *enchantment = Enchantment::enchantments[id]; + AUTO_VAR(localIt, enchantments->find(id)); + int current = localIt != enchantments->end() ? localIt->second : 0; + int level = it->second; + level = (current == level) ? level += 1 : max(level, current); + int extra = level - current; + bool compatible = enchantment->canEnchant(input); + + if (player->abilities.instabuild || input->id == EnchantedBookItem::enchantedBook_Id) compatible = true; + + for(AUTO_VAR(it2, enchantments->begin()); it2 != enchantments->end(); ++it2) + { + int other = it2->first; + if (other != id && !enchantment->isCompatibleWith(Enchantment::enchantments[other])) + { + compatible = false; + + price += extra; + if (DEBUG_COST) + { + app.DebugPrintf("Enchantment incompatibility fee; price is now %d (went up by %d)\n", price, extra); + } + } + } + + if (!compatible) continue; + if (level > enchantment->getMaxLevel()) level = enchantment->getMaxLevel(); + (*enchantments)[id] = level; + int fee = 0; + + switch (enchantment->getFrequency()) + { + case Enchantment::FREQ_COMMON: + fee = 1; + break; + case Enchantment::FREQ_UNCOMMON: + fee = 2; + break; + case Enchantment::FREQ_RARE: + fee = 4; + break; + case Enchantment::FREQ_VERY_RARE: + fee = 8; + break; + } + + if (usingBook) fee = max(1, fee / 2); + + price += fee * extra; + if (DEBUG_COST) + { + app.DebugPrintf("Enchantment increase fee; price is now %d (went up by %d)\n", price, fee*extra); + } + } + delete additionalEnchantments; + } + } + + if (itemName.empty()) + { + if (input->hasCustomHoverName()) + { + namingCost = input->isDamageableItem() ? 7 : input->count * 5; + + price += namingCost; + if (DEBUG_COST) + { + app.DebugPrintf("Un-naming cost; price is now %d (went up by %d)", price, namingCost); + } + result->resetHoverName(); + } + } + else if (itemName.length() > 0 && !equalsIgnoreCase(itemName, input->getHoverName()) && itemName.length() > 0) + { + namingCost = input->isDamageableItem() ? 7 : input->count * 5; + + price += namingCost; + if (DEBUG_COST) + { + app.DebugPrintf("Naming cost; price is now %d (went up by %d)", price, namingCost); + } + + if (input->hasCustomHoverName()) + { + tax += namingCost / 2; + + if (DEBUG_COST) + { + app.DebugPrintf("Already-named tax; tax is now %d (went up by %d)", tax, (namingCost / 2)); + } + } + + result->setHoverName(itemName); + } + + int count = 0; + for(AUTO_VAR(it, enchantments->begin()); it != enchantments->end(); ++it) + { + int id = it->first; + Enchantment *enchantment = Enchantment::enchantments[id]; + int level = it->second; + int fee = 0; + + count++; + + switch (enchantment->getFrequency()) + { + case Enchantment::FREQ_COMMON: + fee = 1; + break; + case Enchantment::FREQ_UNCOMMON: + fee = 2; + break; + case Enchantment::FREQ_RARE: + fee = 4; + break; + case Enchantment::FREQ_VERY_RARE: + fee = 8; + break; + } + + if (usingBook) fee = max(1, fee / 2); + + tax += count + level * fee; + if (DEBUG_COST) + { + app.DebugPrintf("Enchantment tax; tax is now %d (went up by %d)", tax, (count + level * fee)); + } + } + + if (usingBook) tax = max(1, tax / 2); + + cost = tax + price; + if (price <= 0) + { + if (DEBUG_COST) app.DebugPrintf("No purchase, only tax; aborting"); + result = nullptr; + } + if (namingCost == price && namingCost > 0 && cost >= 40) + { + if (DEBUG_COST) app.DebugPrintf("Cost is too high; aborting"); + app.DebugPrintf("Naming an item only, cost too high; giving discount to cap cost to 39 levels"); + cost = 39; + } + if (cost >= 40 && !player->abilities.instabuild) + { + if (DEBUG_COST) app.DebugPrintf("Cost is too high; aborting"); + result = nullptr; + } + + if (result != NULL) + { + int baseCost = result->getBaseRepairCost(); + if (addition != NULL && baseCost < addition->getBaseRepairCost()) baseCost = addition->getBaseRepairCost(); + if (result->hasCustomHoverName()) baseCost -= 9; + if (baseCost < 0) baseCost = 0; + baseCost += 2; + + result->setRepairCost(baseCost); + EnchantmentHelper::setEnchantments(enchantments, result); + } + + resultSlots->setItem(0, result); + } + + broadcastChanges(); + + if (DEBUG_COST) + { + if (level->isClientSide) + { + app.DebugPrintf("CLIENT Cost is %d (%d price, %d tax)\n", cost, price, tax); + } + else + { + app.DebugPrintf("SERVER Cost is %d (%d price, %d tax)\n", cost, price, tax); + } + } +} + +void AnvilMenu::sendData(int id, int value) +{ + AbstractContainerMenu::sendData(id, value); +} + +void AnvilMenu::addSlotListener(ContainerListener *listener) +{ + AbstractContainerMenu::addSlotListener(listener); + listener->setContainerData(this, DATA_TOTAL_COST, cost); +} + +void AnvilMenu::setData(int id, int value) +{ + if (id == DATA_TOTAL_COST) cost = value; +} + +void AnvilMenu::removed(shared_ptr player) +{ + AbstractContainerMenu::removed(player); + if (level->isClientSide) return; + + for (int i = 0; i < repairSlots->getContainerSize(); i++) + { + shared_ptr item = repairSlots->removeItemNoUpdate(i); + if (item != NULL) + { + player->drop(item); + } + } +} + +bool AnvilMenu::stillValid(shared_ptr player) +{ + if (level->getTile(x, y, z) != Tile::anvil_Id) return false; + if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false; + return true; +} + +shared_ptr AnvilMenu::quickMoveStack(shared_ptr player, int slotIndex) +{ + shared_ptr clicked = nullptr; + Slot *slot = slots.at(slotIndex); + if (slot != NULL && slot->hasItem()) + { + shared_ptr stack = slot->getItem(); + clicked = stack->copy(); + + if (slotIndex == RESULT_SLOT) + { + if (!moveItemStackTo(stack, INV_SLOT_START, USE_ROW_SLOT_END, true)) + { + return nullptr; + } + slot->onQuickCraft(stack, clicked); + } + else if (slotIndex == INPUT_SLOT || slotIndex == ADDITIONAL_SLOT) + { + if (!moveItemStackTo(stack, INV_SLOT_START, USE_ROW_SLOT_END, false)) + { + return nullptr; + } + } + else if (slotIndex >= INV_SLOT_START && slotIndex < USE_ROW_SLOT_END) + { + if (!moveItemStackTo(stack, INPUT_SLOT, RESULT_SLOT, false)) + { + return nullptr; + } + } + if (stack->count == 0) + { + slot->set(nullptr); + } + else + { + slot->setChanged(); + } + if (stack->count == clicked->count) + { + return nullptr; + } + else + { + slot->onTake(player, stack); + } + } + return clicked; +} + +void AnvilMenu::setItemName(const wstring &name) +{ + itemName = name; + if (getSlot(RESULT_SLOT)->hasItem()) + { + shared_ptr item = getSlot(RESULT_SLOT)->getItem(); + + if (name.empty()) + { + item->resetHoverName(); + } + else + { + item->setHoverName(itemName); + } + } + createResult(); +} \ No newline at end of file diff --git a/Minecraft.World/AnvilMenu.h b/Minecraft.World/AnvilMenu.h new file mode 100644 index 00000000..a70145dd --- /dev/null +++ b/Minecraft.World/AnvilMenu.h @@ -0,0 +1,55 @@ +#pragma once + +#include "AbstractContainerMenu.h" + +class AnvilMenu : public AbstractContainerMenu +{ + friend class RepairResultSlot; +private: + static const bool DEBUG_COST = false; + +public: + static const int INPUT_SLOT = 0; + static const int ADDITIONAL_SLOT = 1; + static const int RESULT_SLOT = 2; + + static const int INV_SLOT_START = RESULT_SLOT + 1; + static const int INV_SLOT_END = INV_SLOT_START + 9 * 3; + static const int USE_ROW_SLOT_START = INV_SLOT_END; + static const int USE_ROW_SLOT_END = USE_ROW_SLOT_START + 9; + +public: + static const int DATA_TOTAL_COST = 0; + +private: + shared_ptr resultSlots; + + // 4J Stu - anonymous class here now RepairContainer + shared_ptr repairSlots; + + Level *level; + int x, y, z; + +public: + int cost; + +private: + int repairItemCountCost; + wstring itemName; + shared_ptr player; + +public: + using AbstractContainerMenu::slotsChanged; + + AnvilMenu(shared_ptr inventory, Level *level, int xt, int yt, int zt, shared_ptr player); + + void slotsChanged(shared_ptr container); + void createResult(); + void sendData(int id, int value); + void addSlotListener(ContainerListener *listener); + void setData(int id, int value); + void removed(shared_ptr player); + bool stillValid(shared_ptr player); + shared_ptr quickMoveStack(shared_ptr player, int slotIndex); + void setItemName(const wstring &name); +}; diff --git a/Minecraft.World/AnvilTile.cpp b/Minecraft.World/AnvilTile.cpp index e5fd736d..8789cb7c 100644 --- a/Minecraft.World/AnvilTile.cpp +++ b/Minecraft.World/AnvilTile.cpp @@ -55,16 +55,16 @@ void AnvilTile::registerIcons(IconRegister *iconRegister) } } -void AnvilTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void AnvilTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3; int dmg = level->getData(x, y, z) >> 2; dir = ++dir % 4; - if (dir == 0) level->setData(x, y, z, Direction::NORTH | (dmg << 2)); - if (dir == 1) level->setData(x, y, z, Direction::EAST | (dmg << 2)); - if (dir == 2) level->setData(x, y, z, Direction::SOUTH | (dmg << 2)); - if (dir == 3) level->setData(x, y, z, Direction::WEST | (dmg << 2)); + if (dir == 0) level->setData(x, y, z, Direction::NORTH | (dmg << 2), Tile::UPDATE_CLIENTS); + if (dir == 1) level->setData(x, y, z, Direction::EAST | (dmg << 2), Tile::UPDATE_CLIENTS); + if (dir == 2) level->setData(x, y, z, Direction::SOUTH | (dmg << 2), Tile::UPDATE_CLIENTS); + if (dir == 3) level->setData(x, y, z, Direction::WEST | (dmg << 2), Tile::UPDATE_CLIENTS); } bool AnvilTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly) diff --git a/Minecraft.World/AnvilTile.h b/Minecraft.World/AnvilTile.h index 1a4f0ed7..81210c14 100644 --- a/Minecraft.World/AnvilTile.h +++ b/Minecraft.World/AnvilTile.h @@ -35,7 +35,7 @@ public: bool isSolidRender(bool isServerLevel = false); Icon *getTexture(int face, int data); void registerIcons(IconRegister *iconRegister); - void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); + void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); int getRenderShape(); int getSpawnResourcesAuxValue(int data); diff --git a/Minecraft.World/ArmorDyeRecipe.cpp b/Minecraft.World/ArmorDyeRecipe.cpp index 3b74a8bb..0f9c8955 100644 --- a/Minecraft.World/ArmorDyeRecipe.cpp +++ b/Minecraft.World/ArmorDyeRecipe.cpp @@ -43,10 +43,7 @@ bool ArmorDyeRecipe::matches(shared_ptr craftSlots, Level *le shared_ptr ArmorDyeRecipe::assembleDyedArmor(shared_ptr craftSlots) { shared_ptr target = nullptr; - int colorTotals[3]; - colorTotals[0] = 0; - colorTotals[1] = 0; - colorTotals[2] = 0; + int colorTotals[3] = {0,0,0}; int intensityTotal = 0; int colourCounts = 0; ArmorItem *armor = NULL; @@ -64,6 +61,7 @@ shared_ptr ArmorDyeRecipe::assembleDyedArmor(shared_ptrgetMaterial() == ArmorItem::ArmorMaterial::CLOTH && target == NULL) { target = item->copy(); + target->count = 1; if (armor->hasCustomColor(item)) { @@ -87,7 +85,7 @@ shared_ptr ArmorDyeRecipe::assembleDyedArmor(shared_ptrid == Item::dye_powder_Id) { - int tileData = ClothTile::getTileDataForItemAuxValue(item->getAuxValue()); + int tileData = ColoredTile::getTileDataForItemAuxValue(item->getAuxValue()); int red = (int) (Sheep::COLOR[tileData][0] * 0xFF); int green = (int) (Sheep::COLOR[tileData][1] * 0xFF); int blue = (int) (Sheep::COLOR[tileData][2] * 0xFF); diff --git a/Minecraft.World/ArmorItem.cpp b/Minecraft.World/ArmorItem.cpp index 0b2c24e4..114b200b 100644 --- a/Minecraft.World/ArmorItem.cpp +++ b/Minecraft.World/ArmorItem.cpp @@ -1,7 +1,11 @@ #include "stdafx.h" #include "..\Minecraft.Client\Minecraft.h" #include "net.minecraft.world.h" +#include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.phys.h" +#include "net.minecraft.world.level.h" #include "com.mojang.nbt.h" #include "ArmorItem.h" @@ -17,6 +21,41 @@ const wstring ArmorItem::TEXTURE_EMPTY_SLOTS[] = { L"slot_empty_helmet", L"slot_empty_chestplate", L"slot_empty_leggings", L"slot_empty_boots" }; + +shared_ptr ArmorItem::ArmorDispenseItemBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + int x = source->getBlockX() + facing->getStepX(); + int y = source->getBlockY() + facing->getStepY(); + int z = source->getBlockZ() + facing->getStepZ(); + AABB *bb = AABB::newTemp(x, y, z, x + 1, y + 1, z + 1); + EntitySelector *selector = new MobCanWearArmourEntitySelector(dispensed); + vector > *entities = source->getWorld()->getEntitiesOfClass(typeid(LivingEntity), bb, selector); + delete selector; + + if (entities->size() > 0) + { + shared_ptr target = dynamic_pointer_cast( entities->at(0) ); + int offset = target->instanceof(eTYPE_PLAYER) ? 1 : 0; + int slot = Mob::getEquipmentSlotForItem(dispensed); + shared_ptr equip = dispensed->copy(); + equip->count = 1; + target->setEquippedSlot(slot - offset, equip); + if (target->instanceof(eTYPE_MOB)) dynamic_pointer_cast(target)->setDropChance(slot, 2); + dispensed->count--; + + outcome = ACTIVATED_ITEM; + + delete entities; + return dispensed; + } + else + { + delete entities; + return DefaultDispenseItemBehavior::execute(source, dispensed, outcome); + } +} + typedef ArmorItem::ArmorMaterial _ArmorMaterial; const int _ArmorMaterial::clothArray[] = {1,3,2,1}; @@ -86,6 +125,7 @@ ArmorItem::ArmorItem(int id, const ArmorMaterial *armorType, int icon, int slot) { setMaxDamage(armorType->getHealthForSlot(slot)); maxStackSize = 1; + DispenserTile::REGISTRY.add(this, new ArmorDispenseItemBehavior()); } int ArmorItem::getColor(shared_ptr item, int spriteLayer) @@ -100,7 +140,6 @@ int ArmorItem::getColor(shared_ptr item, int spriteLayer) return color; } -//@Override bool ArmorItem::hasMultipleSpriteLayers() { return armorType == ArmorMaterial::CLOTH; @@ -145,7 +184,6 @@ int ArmorItem::getColor(shared_ptr item) } } -//@Override Icon *ArmorItem::getLayerIcon(int auxValue, int spriteLayer) { if (spriteLayer == 1) @@ -198,7 +236,6 @@ bool ArmorItem::isValidRepairItem(shared_ptr source, shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); + }; + public: class ArmorMaterial { @@ -64,27 +72,20 @@ private: public: ArmorItem(int id, const ArmorMaterial *armorType, int icon, int slot); - //@Override - int getColor(shared_ptr item, int spriteLayer); - - //@Override - bool hasMultipleSpriteLayers(); + virtual int getColor(shared_ptr item, int spriteLayer); + virtual bool hasMultipleSpriteLayers(); virtual int getEnchantmentValue(); + virtual const ArmorMaterial *getMaterial(); + virtual bool hasCustomColor(shared_ptr item); + virtual int getColor(shared_ptr item); - const ArmorMaterial *getMaterial(); - bool hasCustomColor(shared_ptr item); - int getColor(shared_ptr item); - - //@Override - Icon *getLayerIcon(int auxValue, int spriteLayer); - void clearColor(shared_ptr item); - void setColor(shared_ptr item, int color); - - bool isValidRepairItem(shared_ptr source, shared_ptr repairItem); + virtual Icon *getLayerIcon(int auxValue, int spriteLayer); + virtual void clearColor(shared_ptr item); + virtual void setColor(shared_ptr item, int color); - //@Override - void registerIcons(IconRegister *iconRegister); + virtual bool isValidRepairItem(shared_ptr source, shared_ptr repairItem); + virtual void registerIcons(IconRegister *iconRegister); static Icon *getEmptyIcon(int slot); }; \ No newline at end of file diff --git a/Minecraft.World/ArmorRecipes.cpp b/Minecraft.World/ArmorRecipes.cpp index 8d3483b1..c74c02a3 100644 --- a/Minecraft.World/ArmorRecipes.cpp +++ b/Minecraft.World/ArmorRecipes.cpp @@ -49,25 +49,25 @@ void ArmorRecipes::_init() ADD_OBJECT(map[0],Item::diamond); ADD_OBJECT(map[0],Item::goldIngot); - ADD_OBJECT(map[1],Item::helmet_cloth); + ADD_OBJECT(map[1],Item::helmet_leather); // ADD_OBJECT(map[1],Item::helmet_chain); ADD_OBJECT(map[1],Item::helmet_iron); ADD_OBJECT(map[1],Item::helmet_diamond); ADD_OBJECT(map[1],Item::helmet_gold); - ADD_OBJECT(map[2],Item::chestplate_cloth); + ADD_OBJECT(map[2],Item::chestplate_leather); // ADD_OBJECT(map[2],Item::chestplate_chain); ADD_OBJECT(map[2],Item::chestplate_iron); ADD_OBJECT(map[2],Item::chestplate_diamond); ADD_OBJECT(map[2],Item::chestplate_gold); - ADD_OBJECT(map[3],Item::leggings_cloth); + ADD_OBJECT(map[3],Item::leggings_leather); // ADD_OBJECT(map[3],Item::leggings_chain); ADD_OBJECT(map[3],Item::leggings_iron); ADD_OBJECT(map[3],Item::leggings_diamond); ADD_OBJECT(map[3],Item::leggings_gold); - ADD_OBJECT(map[4],Item::boots_cloth); + ADD_OBJECT(map[4],Item::boots_leather); // ADD_OBJECT(map[4],Item::boots_chain); ADD_OBJECT(map[4],Item::boots_iron); ADD_OBJECT(map[4],Item::boots_diamond); @@ -79,7 +79,7 @@ ArmorRecipes::_eArmorType ArmorRecipes::GetArmorType(int iId) { switch(iId) { - case Item::helmet_cloth_Id: + case Item::helmet_leather_Id: case Item::helmet_chain_Id: case Item::helmet_iron_Id: case Item::helmet_diamond_Id: @@ -87,7 +87,7 @@ ArmorRecipes::_eArmorType ArmorRecipes::GetArmorType(int iId) return eArmorType_Helmet; break; - case Item::chestplate_cloth_Id: + case Item::chestplate_leather_Id: case Item::chestplate_chain_Id: case Item::chestplate_iron_Id: case Item::chestplate_diamond_Id: @@ -95,7 +95,7 @@ ArmorRecipes::_eArmorType ArmorRecipes::GetArmorType(int iId) return eArmorType_Chestplate; break; - case Item::leggings_cloth_Id: + case Item::leggings_leather_Id: case Item::leggings_chain_Id: case Item::leggings_iron_Id: case Item::leggings_diamond_Id: @@ -103,7 +103,7 @@ ArmorRecipes::_eArmorType ArmorRecipes::GetArmorType(int iId) return eArmorType_Leggings; break; - case Item::boots_cloth_Id: + case Item::boots_leather_Id: case Item::boots_chain_Id: case Item::boots_iron_Id: case Item::boots_diamond_Id: diff --git a/Minecraft.World/ArmorSlot.cpp b/Minecraft.World/ArmorSlot.cpp index 1efe0b71..27993d77 100644 --- a/Minecraft.World/ArmorSlot.cpp +++ b/Minecraft.World/ArmorSlot.cpp @@ -19,6 +19,10 @@ int ArmorSlot::getMaxStackSize() bool ArmorSlot::mayPlace(shared_ptr item) { + if (item == NULL) + { + return false; + } if ( dynamic_cast( item->getItem() ) != NULL) { return dynamic_cast( item->getItem() )->slot == slotNum; diff --git a/Minecraft.World/ArrayWithLength.h b/Minecraft.World/ArrayWithLength.h index 4e9f9941..e22724c6 100644 --- a/Minecraft.World/ArrayWithLength.h +++ b/Minecraft.World/ArrayWithLength.h @@ -83,6 +83,7 @@ class Enchantment; class ClipChunk; typedef arrayWithLength doubleArray; +typedef array2DWithLength coords2DArray; typedef arrayWithLength byteArray; typedef arrayWithLength charArray; typedef arrayWithLength shortArray; diff --git a/Minecraft.World/Arrow.cpp b/Minecraft.World/Arrow.cpp index 1b102c65..743f966b 100644 --- a/Minecraft.World/Arrow.cpp +++ b/Minecraft.World/Arrow.cpp @@ -7,6 +7,9 @@ #include "net.minecraft.world.item.h" #include "net.minecraft.world.damagesource.h" #include "net.minecraft.world.item.enchantment.h" +#include "net.minecraft.network.packet.h" +#include "..\Minecraft.Client\ServerPlayer.h" +#include "..\Minecraft.Client\PlayerConnection.h" #include "com.mojang.nbt.h" #include "Arrow.h" @@ -48,16 +51,18 @@ void Arrow::_init() Arrow::Arrow(Level *level) : Entity( level ) { _init(); - - this->setSize(0.5f, 0.5f); + + viewScale = 10; + setSize(0.5f, 0.5f); } -Arrow::Arrow(Level *level, shared_ptr mob, shared_ptr target, float power, float uncertainty) : Entity( level ) +Arrow::Arrow(Level *level, shared_ptr mob, shared_ptr target, float power, float uncertainty) : Entity( level ) { _init(); - - this->owner = mob; - if ( dynamic_pointer_cast( mob ) != NULL) pickup = PICKUP_ALLOWED; + + viewScale = 10; + owner = mob; + if ( mob->instanceof(eTYPE_PLAYER) ) pickup = PICKUP_ALLOWED; y = mob->y + mob->getHeadHeight() - 0.1f; @@ -82,29 +87,31 @@ Arrow::Arrow(Level *level, shared_ptr mob, shared_ptr target, float po Arrow::Arrow(Level *level, double x, double y, double z) : Entity( level ) { _init(); + + viewScale = 10; + setSize(0.5f, 0.5f); - this->setSize(0.5f, 0.5f); - - this->setPos(x, y, z); - this->heightOffset = 0; + setPos(x, y, z); + heightOffset = 0; } -Arrow::Arrow(Level *level, shared_ptr mob, float power) : Entity( level ) +Arrow::Arrow(Level *level, shared_ptr mob, float power) : Entity( level ) { _init(); - this->owner = mob; - if ( dynamic_pointer_cast( mob ) != NULL) pickup = PICKUP_ALLOWED; + viewScale = 10; + owner = mob; + if ( mob->instanceof(eTYPE_PLAYER) ) pickup = PICKUP_ALLOWED; setSize(0.5f, 0.5f); - this->moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot); + moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot); x -= Mth::cos(yRot / 180 * PI) * 0.16f; y -= 0.1f; z -= Mth::sin(yRot / 180 * PI) * 0.16f; - this->setPos(x, y, z); - this->heightOffset = 0; + setPos(x, y, z); + heightOffset = 0; xd = -Mth::sin(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI); zd = Mth::cos(yRot / 180 * PI) * Mth::cos(xRot / 180 * PI); @@ -128,9 +135,9 @@ void Arrow::shoot(double xd, double yd, double zd, float pow, float uncertainty) yd /= dist; zd /= dist; - xd += (random->nextGaussian()) * 0.0075f * uncertainty; - yd += (random->nextGaussian()) * 0.0075f * uncertainty; - zd += (random->nextGaussian()) * 0.0075f * uncertainty; + xd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) * 0.0075f * uncertainty; + yd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) * 0.0075f * uncertainty; + zd += (random->nextGaussian() * (random->nextBoolean() ? -1 : 1)) * 0.0075f * uncertainty; xd *= pow; yd *= pow; @@ -142,8 +149,8 @@ void Arrow::shoot(double xd, double yd, double zd, float pow, float uncertainty) double sd = sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (atan2(xd, zd) * 180 / PI); - xRotO = this->xRot = (float) (atan2(yd, sd) * 180 / PI); + yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI); + xRotO = xRot = (float) (atan2(yd, sd) * 180 / PI); life = 0; } @@ -161,8 +168,8 @@ void Arrow::lerpMotion(double xd, double yd, double zd) if (xRotO == 0 && yRotO == 0) { double sd = sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (atan2( xd, zd) * 180 / PI); - xRotO = this->xRot = (float) (atan2( yd, sd) * 180 / PI); + yRotO = yRot = (float) (atan2( xd, zd) * 180 / PI); + xRotO = xRot = (float) (atan2( yd, sd) * 180 / PI); xRotO = xRot; yRotO = yRot; app.DebugPrintf("%f %f : 0x%x\n",xRot,yRot,&yRot); @@ -179,8 +186,8 @@ void Arrow::tick() if (xRotO == 0 && yRotO == 0) { double sd = sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (atan2(xd, zd) * 180 / PI); - xRotO = this->xRot = (float) (atan2(yd, sd) * 180 / PI); + yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI); + xRotO = xRot = (float) (atan2(yd, sd) * 180 / PI); } @@ -269,6 +276,16 @@ void Arrow::tick() res = new HitResult(hitEntity); } + if ( (res != NULL) && (res->entity != NULL) && res->entity->instanceof(eTYPE_PLAYER)) + { + shared_ptr player = dynamic_pointer_cast(res->entity); + // 4J: Check for owner being null + if ( player->abilities.invulnerable || ((owner != NULL) && (owner->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast(owner)->canHarmPlayer(player)))) + { + res = NULL; + } + } + if (res != NULL) { if (res->entity != NULL) @@ -294,15 +311,19 @@ void Arrow::tick() // 4J Stu - We should not set the entity on fire unless we can cause some damage (this doesn't necessarily mean that the arrow hit lowered their health) // set targets on fire first because we want cooked // pork/chicken/steak - if (this->isOnFire()) + if (isOnFire() && res->entity->GetType() != eTYPE_ENDERMAN) { res->entity->setOnFire(5); } - shared_ptr mob = dynamic_pointer_cast(res->entity); - if (mob != NULL) + if (res->entity->instanceof(eTYPE_LIVINGENTITY)) { - mob->arrowCount++; + shared_ptr mob = dynamic_pointer_cast(res->entity); + + if (!level->isClientSide) + { + mob->setArrowCount(mob->getArrowCount() + 1); + } if (knockback > 0) { float pushLen = sqrt(xd * xd + zd * zd); @@ -316,12 +337,17 @@ void Arrow::tick() { ThornsEnchantment::doThornsAfterAttack(owner, mob, random); } + + if (owner != NULL && res->entity != owner && owner->GetType() == eTYPE_SERVERPLAYER) + { + dynamic_pointer_cast(owner)->connection->send( shared_ptr( new GameEventPacket(GameEventPacket::SUCCESSFUL_BOW_HIT, 0)) ); + } } // 4J : WESTY : For award, need to track if creeper was killed by arrow from the player. - if ( (dynamic_pointer_cast(owner) != NULL ) && // arrow owner is a player - ( res->entity->isAlive() == false ) && // target is now dead - ( dynamic_pointer_cast( res->entity ) != NULL ) ) // target is a creeper + if (owner != NULL && owner->instanceof(eTYPE_PLAYER) // arrow owner is a player + && !res->entity->isAlive() // target is now dead + && (res->entity->GetType() == eTYPE_CREEPER)) // target is a creeper { dynamic_pointer_cast(owner)->awardStat( @@ -330,9 +356,8 @@ void Arrow::tick() ); } - // 4J - sound change brought forward from 1.2.3 - level->playSound(shared_from_this(), eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f)); - remove(); + playSound( eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f)); + if (res->entity->GetType() != eTYPE_ENDERDRAGON) remove(); } else { @@ -365,11 +390,15 @@ void Arrow::tick() z -= (zd / dd) * 0.05f; } - // 4J - sound change brought forward from 1.2.3 - level->playSound(shared_from_this(), eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f)); + playSound(eSoundType_RANDOM_BOW_HIT, 1.0f, 1.2f / (random->nextFloat() * 0.2f + 0.9f)); inGround = true; shakeTime = 7; setCritArrow(false); + + if (lastTile != 0) + { + Tile::tiles[lastTile]->entityInside(level, xTile, yTile, zTile, shared_from_this() ); + } } } delete res; @@ -480,12 +509,17 @@ void Arrow::playerTouch(shared_ptr player) if (bRemove) { - level->playSound(shared_from_this(), eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f); + playSound(eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f); player->take(shared_from_this(), 1); remove(); } } +bool Arrow::makeStepSound() +{ + return false; +} + float Arrow::getShadowHeightOffs() { return 0; diff --git a/Minecraft.World/Arrow.h b/Minecraft.World/Arrow.h index b96aa210..9cfa2f84 100644 --- a/Minecraft.World/Arrow.h +++ b/Minecraft.World/Arrow.h @@ -2,11 +2,12 @@ using namespace std; #include "Entity.h" +#include "Projectile.h" class Level; class CompoundTag; -class Arrow : public Entity +class Arrow : public Entity, public Projectile { public: eINSTANCEOF GetType() { return eTYPE_ARROW; } @@ -26,35 +27,35 @@ private: static const int FLAG_CRIT = 1; private: - int xTile; - int yTile; - int zTile; - int lastTile; - int lastData; - bool inGround; + int xTile; + int yTile; + int zTile; + int lastTile; + int lastData; + bool inGround; public: int pickup; - int shakeTime; - shared_ptr owner; + int shakeTime; + shared_ptr owner; private: double baseDamage; - int knockback; + int knockback; private: int life; - int flightTime; + int flightTime; // 4J - added common ctor code. void _init(); public: Arrow(Level *level); - Arrow(Level *level, shared_ptr mob, shared_ptr target, float power, float uncertainty); - Arrow(Level *level, double x, double y, double z); - Arrow(Level *level, shared_ptr mob, float power); + Arrow(Level *level, shared_ptr mob, shared_ptr target, float power, float uncertainty); + Arrow(Level *level, double x, double y, double z); + Arrow(Level *level, shared_ptr mob, float power); protected: virtual void defineSynchedData(); @@ -63,11 +64,16 @@ public: void shoot(double xd, double yd, double zd, float pow, float uncertainty); virtual void lerpTo(double x, double y, double z, float yRot, float xRot, int steps); virtual void lerpMotion(double xd, double yd, double zd); - virtual void tick(); - virtual void addAdditonalSaveData(CompoundTag *tag); - virtual void readAdditionalSaveData(CompoundTag *tag); - virtual void playerTouch(shared_ptr player); - virtual float getShadowHeightOffs(); + virtual void tick(); + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void playerTouch(shared_ptr player); + +protected: + virtual bool makeStepSound(); + +public: + virtual float getShadowHeightOffs(); void setBaseDamage(double baseDamage); double getBaseDamage(); diff --git a/Minecraft.World/AttackDamageMobEffect.cpp b/Minecraft.World/AttackDamageMobEffect.cpp new file mode 100644 index 00000000..00ab0f95 --- /dev/null +++ b/Minecraft.World/AttackDamageMobEffect.cpp @@ -0,0 +1,19 @@ +#include "stdafx.h" + +#include "AttackDamageMobEffect.h" + +AttackDamageMobEffect::AttackDamageMobEffect(int id, bool isHarmful, eMinecraftColour color) : MobEffect(id, isHarmful, color) +{ +} + +double AttackDamageMobEffect::getAttributeModifierValue(int amplifier, AttributeModifier *original) +{ + if (id == MobEffect::weakness->id) + { + return -0.5f * (amplifier + 1); + } + else + { + return 1.3 * (amplifier + 1); + } +} \ No newline at end of file diff --git a/Minecraft.World/AttackDamageMobEffect.h b/Minecraft.World/AttackDamageMobEffect.h new file mode 100644 index 00000000..0597abfa --- /dev/null +++ b/Minecraft.World/AttackDamageMobEffect.h @@ -0,0 +1,13 @@ +#pragma once + +#include "MobEffect.h" + +class AttributeModifier; + +class AttackDamageMobEffect : public MobEffect +{ +public: + AttackDamageMobEffect(int id, bool isHarmful, eMinecraftColour color); + + double getAttributeModifierValue(int amplifier, AttributeModifier *original); +}; \ No newline at end of file diff --git a/Minecraft.World/Attribute.cpp b/Minecraft.World/Attribute.cpp new file mode 100644 index 00000000..7c280862 --- /dev/null +++ b/Minecraft.World/Attribute.cpp @@ -0,0 +1,18 @@ +#include "stdafx.h" +#include "Attribute.h" + +const int Attribute::AttributeNames [] = +{ + IDS_ATTRIBUTE_NAME_GENERIC_MAXHEALTH, + IDS_ATTRIBUTE_NAME_GENERIC_FOLLOWRANGE, + IDS_ATTRIBUTE_NAME_GENERIC_KNOCKBACKRESISTANCE, + IDS_ATTRIBUTE_NAME_GENERIC_MOVEMENTSPEED, + IDS_ATTRIBUTE_NAME_GENERIC_ATTACKDAMAGE, + IDS_ATTRIBUTE_NAME_HORSE_JUMPSTRENGTH, + IDS_ATTRIBUTE_NAME_ZOMBIE_SPAWNREINFORCEMENTS, +}; + +int Attribute::getName(eATTRIBUTE_ID id) +{ + return AttributeNames[id]; +} \ No newline at end of file diff --git a/Minecraft.World/Attribute.h b/Minecraft.World/Attribute.h new file mode 100644 index 00000000..1fb5246b --- /dev/null +++ b/Minecraft.World/Attribute.h @@ -0,0 +1,71 @@ +#pragma once +class AttributeModifier; + +// 4J: This ID is serialised into save data so new attributes must always be added after existing ones +enum eATTRIBUTE_ID +{ + // 1.6.4 + eAttributeId_GENERIC_MAXHEALTH, + eAttributeId_GENERIC_FOLLOWRANGE, + eAttributeId_GENERIC_KNOCKBACKRESISTANCE, + eAttributeId_GENERIC_MOVEMENTSPEED, + eAttributeId_GENERIC_ATTACKDAMAGE, + eAttributeId_HORSE_JUMPSTRENGTH, + eAttributeId_ZOMBIE_SPAWNREINFORCEMENTS, + + // 1.8+ + // New attributes go here + + eAttributeId_COUNT +}; + +class Attribute +{ +public: + static const int MAX_NAME_LENGTH = 64; + + /** + * 4J: Changed this from a string name to an ID + * Gets the ID of this attribute, for serialization. + * + * @return Name of this attribute. + */ + virtual eATTRIBUTE_ID getId() = 0; + + /** + * Sanitizes an attribute value, making sure it's not out of range and is an acceptable amount. + * + * + * @param value Value to sanitize. + * @return Sanitized value, safe for use. + */ + virtual double sanitizeValue(double value) = 0; + + /** + * Get the default value of this attribute, to be used upon creation. + * + * @return Default value. + */ + virtual double getDefaultValue() = 0; + + /** + * Checks if this attribute should be synced to the client. + * + * Attributes should be serverside only unless the client needs to know about it. + * + * @return True if the client should know about this attribute. + */ + virtual bool isClientSyncable() = 0; + + // 4J: Added to retrieve string ID for attribute + static int getName(eATTRIBUTE_ID id); + +protected: + static const int AttributeNames []; +}; + +#ifdef __ORBIS__ +typedef unordered_map> attrAttrModMap; +#else +typedef unordered_map attrAttrModMap; +#endif \ No newline at end of file diff --git a/Minecraft.World/AttributeInstance.h b/Minecraft.World/AttributeInstance.h new file mode 100644 index 00000000..e127f1a7 --- /dev/null +++ b/Minecraft.World/AttributeInstance.h @@ -0,0 +1,22 @@ +#pragma once +#include "AttributeModifier.h" + +class AttributeInstance +{ +public: + virtual ~AttributeInstance() {} + + virtual Attribute *getAttribute() = 0; + virtual double getBaseValue() = 0; + virtual void setBaseValue(double baseValue) = 0; + virtual double getValue() = 0; + + virtual unordered_set *getModifiers(int operation) = 0; + virtual void getModifiers(unordered_set& result) = 0; + virtual AttributeModifier *getModifier(eMODIFIER_ID id) = 0; + virtual void addModifiers(unordered_set *modifiers) = 0; + virtual void addModifier(AttributeModifier *modifier) = 0; + virtual void removeModifier(AttributeModifier *modifier) = 0; + virtual void removeModifier(eMODIFIER_ID id) = 0; + virtual void removeModifiers() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/AttributeModifier.cpp b/Minecraft.World/AttributeModifier.cpp new file mode 100644 index 00000000..c479853d --- /dev/null +++ b/Minecraft.World/AttributeModifier.cpp @@ -0,0 +1,129 @@ +#include "stdafx.h" + +#include "AttributeModifier.h" +#include "HtmlString.h" + +void AttributeModifier::_init(eMODIFIER_ID id, const wstring name, double amount, int operation) +{ + assert(operation < TOTAL_OPERATIONS); + this->amount = amount; + this->operation = operation; + this->name = name; + this->id = id; + this->serialize = true; +} + +AttributeModifier::AttributeModifier(double amount, int operation) +{ + // Create an anonymous attribute + _init(eModifierId_ANONYMOUS, name, amount, operation); +} + +AttributeModifier::AttributeModifier(eMODIFIER_ID id, double amount, int operation) +{ + _init(id, name, amount, operation); + + //Validate.notEmpty(name, "Modifier name cannot be empty"); + //Validate.inclusiveBetween(0, TOTAL_OPERATIONS - 1, operation, "Invalid operation"); +} + +eMODIFIER_ID AttributeModifier::getId() +{ + return id; +} + +wstring AttributeModifier::getName() +{ + return name; +} + +int AttributeModifier::getOperation() +{ + return operation; +} + +double AttributeModifier::getAmount() +{ + return amount; +} + +bool AttributeModifier::isSerializable() +{ + return serialize; +} + +AttributeModifier *AttributeModifier::setSerialize(bool serialize) +{ + this->serialize = serialize; + return this; +} + +bool AttributeModifier::equals(AttributeModifier *modifier) +{ + if (this == modifier) return true; + if (modifier == NULL) return false; //|| getClass() != o.getClass()) return false; + + if (id != modifier->id) return false; + + return true; +} + +wstring AttributeModifier::toString() +{ + return L""; + + /*return L"AttributeModifier{" + + L"amount=" + amount + + L", operation=" + operation + + L", name='" + name + '\'' + + L", id=" + id + + L", serialize=" + serialize + + L'}';*/ +} + +HtmlString AttributeModifier::getHoverText(eATTRIBUTE_ID attribute) +{ + double amount = getAmount(); + double displayAmount; + + if (getOperation() == AttributeModifier::OPERATION_MULTIPLY_BASE || getOperation() == AttributeModifier::OPERATION_MULTIPLY_TOTAL) + { + displayAmount = getAmount() * 100.0f; + } + else + { + displayAmount = getAmount(); + } + + eMinecraftColour color; + + if (amount > 0) + { + color = eHTMLColor_9; + } + else if (amount < 0) + { + displayAmount *= -1; + color = eHTMLColor_c; + } + + bool percentage = false; + switch(getOperation()) + { + case AttributeModifier::OPERATION_ADDITION: + percentage = false; + break; + case AttributeModifier::OPERATION_MULTIPLY_BASE: + case AttributeModifier::OPERATION_MULTIPLY_TOTAL: + percentage = true; + break; + default: + // No other operations + assert(0); + } + + wchar_t formatted[256]; + swprintf(formatted, 256, L"%ls%d%ls %ls", (amount > 0 ? L"+" : L"-"), (int) displayAmount, (percentage ? L"%" : L""), app.GetString(Attribute::getName(attribute))); + + return HtmlString(formatted, color); +} \ No newline at end of file diff --git a/Minecraft.World/AttributeModifier.h b/Minecraft.World/AttributeModifier.h new file mode 100644 index 00000000..c67fda1d --- /dev/null +++ b/Minecraft.World/AttributeModifier.h @@ -0,0 +1,69 @@ +#pragma once + +/* +4J - Both modifier uuid and name have been replaced by an id enum. Note that we have special value +"eModifierId_ANONYMOUS" for attribute modifiers that previously didn't have a fixed UUID and are never removed. + +To all intents and purposes anonymous modifiers don't have an ID and so are handled differently in some cases, for instance: + 1. You can have multiple modifiers with the anonymous ID on a single attribute instance + 2. Anonymous modifiers can't be removed from attribute instance by ID + +IMPORTANT: Saved out to file so don't change order. All new values should be added at the end. +*/ + +class HtmlString; + +enum eMODIFIER_ID +{ + eModifierId_ANONYMOUS = 0, + + eModifierId_ITEM_BASEDAMAGE, + + eModifierId_MOB_FLEEING, + eModifierId_MOB_SPRINTING, + + eModifierId_MOB_ENDERMAN_ATTACKSPEED, + eModifierId_MOB_PIG_ATTACKSPEED, + eModifierId_MOB_WITCH_DRINKSPEED, + eModifierId_MOB_ZOMBIE_BABYSPEED, + + eModifierId_POTION_DAMAGEBOOST, + eModifierId_POTION_HEALTHBOOST, + eModifierId_POTION_MOVESPEED, + eModifierId_POTION_MOVESLOWDOWN, + eModifierId_POTION_WEAKNESS, + + eModifierId_COUNT, +}; + +class AttributeModifier +{ +public: + static const int OPERATION_ADDITION = 0; + static const int OPERATION_MULTIPLY_BASE = 1; + static const int OPERATION_MULTIPLY_TOTAL = 2; + static const int TOTAL_OPERATIONS = 3; + +private: + double amount; + int operation; + wstring name; + eMODIFIER_ID id; + bool serialize; + + void _init(eMODIFIER_ID id, const wstring name, double amount, int operation); + +public: + AttributeModifier(double amount, int operation); + AttributeModifier(eMODIFIER_ID id, double amount, int operation); + + eMODIFIER_ID getId(); + wstring getName(); + int getOperation(); + double getAmount(); + bool isSerializable(); + AttributeModifier *setSerialize(bool serialize); + bool equals(AttributeModifier *modifier); + wstring toString(); + HtmlString getHoverText(eATTRIBUTE_ID attribute); // 4J: Added to keep modifier readable string creation in one place +}; \ No newline at end of file diff --git a/Minecraft.World/AvoidPlayerGoal.cpp b/Minecraft.World/AvoidPlayerGoal.cpp index c94d5cb1..53aebe89 100644 --- a/Minecraft.World/AvoidPlayerGoal.cpp +++ b/Minecraft.World/AvoidPlayerGoal.cpp @@ -10,16 +10,28 @@ #include "net.minecraft.world.phys.h" #include "AvoidPlayerGoal.h" -AvoidPlayerGoal::AvoidPlayerGoal(PathfinderMob *mob, const type_info& avoidType, float maxDist, float walkSpeed, float sprintSpeed) : avoidType(avoidType) +AvoidPlayerGoalEntitySelector::AvoidPlayerGoalEntitySelector(AvoidPlayerGoal *parent) +{ + m_parent = parent; +} + +bool AvoidPlayerGoalEntitySelector::matches(shared_ptr entity) const +{ + return entity->isAlive() && m_parent->mob->getSensing()->canSee(entity); +} + +AvoidPlayerGoal::AvoidPlayerGoal(PathfinderMob *mob, const type_info& avoidType, float maxDist, double walkSpeedModifier, double sprintSpeedModifier) : avoidType(avoidType) { this->mob = mob; //this->avoidType = avoidType; this->maxDist = maxDist; - this->walkSpeed = walkSpeed; - this->sprintSpeed = sprintSpeed; + this->walkSpeedModifier = walkSpeedModifier; + this->sprintSpeedModifier = sprintSpeedModifier; this->pathNav = mob->getNavigation(); setRequiredControlFlags(Control::MoveControlFlag); + entitySelector = new AvoidPlayerGoalEntitySelector(this); + toAvoid = weak_ptr(); path = NULL; } @@ -27,6 +39,7 @@ AvoidPlayerGoal::AvoidPlayerGoal(PathfinderMob *mob, const type_info& avoidType, AvoidPlayerGoal::~AvoidPlayerGoal() { if(path != NULL) delete path; + delete entitySelector; } bool AvoidPlayerGoal::canUse() @@ -40,7 +53,7 @@ bool AvoidPlayerGoal::canUse() } else { - vector > *entities = mob->level->getEntitiesOfClass(avoidType, mob->bb->grow(maxDist, 3, maxDist)); + vector > *entities = mob->level->getEntitiesOfClass(avoidType, mob->bb->grow(maxDist, 3, maxDist), entitySelector); if (entities->empty()) { delete entities; @@ -50,8 +63,6 @@ bool AvoidPlayerGoal::canUse() delete entities; } - if (!mob->getSensing()->canSee(toAvoid.lock())) return false; - Vec3 *pos = RandomPos::getPosAvoid(dynamic_pointer_cast(mob->shared_from_this()), 16, 7, Vec3::newTemp(toAvoid.lock()->x, toAvoid.lock()->y, toAvoid.lock()->z)); if (pos == NULL) return false; if (toAvoid.lock()->distanceToSqr(pos->x, pos->y, pos->z) < toAvoid.lock()->distanceToSqr(mob->shared_from_this())) return false; @@ -69,7 +80,7 @@ bool AvoidPlayerGoal::canContinueToUse() void AvoidPlayerGoal::start() { - pathNav->moveTo(path, walkSpeed); + pathNav->moveTo(path, walkSpeedModifier); path = NULL; } @@ -80,6 +91,6 @@ void AvoidPlayerGoal::stop() void AvoidPlayerGoal::tick() { - if (mob->distanceToSqr(toAvoid.lock()) < 7 * 7) mob->getNavigation()->setSpeed(sprintSpeed); - else mob->getNavigation()->setSpeed(walkSpeed); + if (mob->distanceToSqr(toAvoid.lock()) < 7 * 7) mob->getNavigation()->setSpeedModifier(sprintSpeedModifier); + else mob->getNavigation()->setSpeedModifier(walkSpeedModifier); } \ No newline at end of file diff --git a/Minecraft.World/AvoidPlayerGoal.h b/Minecraft.World/AvoidPlayerGoal.h index 0b17ee4f..267ccf7e 100644 --- a/Minecraft.World/AvoidPlayerGoal.h +++ b/Minecraft.World/AvoidPlayerGoal.h @@ -1,24 +1,38 @@ #pragma once #include "Goal.h" +#include "EntitySelector.h" class PathNavigation; class PathfinderMob; class Path; +class AvoidPlayerGoal; + +class AvoidPlayerGoalEntitySelector : public EntitySelector +{ +private: + AvoidPlayerGoal *m_parent; + +public: + AvoidPlayerGoalEntitySelector(AvoidPlayerGoal *parent); + bool matches(shared_ptr entity) const; +}; class AvoidPlayerGoal : public Goal { + friend class AvoidPlayerGoalEntitySelector; private: PathfinderMob *mob; // Owner of this goal - float walkSpeed, sprintSpeed; + double walkSpeedModifier, sprintSpeedModifier; weak_ptr toAvoid; float maxDist; Path *path; PathNavigation *pathNav; const type_info& avoidType; + EntitySelector *entitySelector; public: - AvoidPlayerGoal(PathfinderMob *mob, const type_info& avoidType, float maxDist, float walkSpeed, float sprintSpeed); + AvoidPlayerGoal(PathfinderMob *mob, const type_info& avoidType, float maxDist, double walkSpeedModifier, double sprintSpeedModifier); ~AvoidPlayerGoal(); virtual bool canUse(); diff --git a/Minecraft.World/BaseAttribute.cpp b/Minecraft.World/BaseAttribute.cpp new file mode 100644 index 00000000..ae7d32f7 --- /dev/null +++ b/Minecraft.World/BaseAttribute.cpp @@ -0,0 +1,31 @@ +#include "stdafx.h" + +#include "BaseAttribute.h" + +BaseAttribute::BaseAttribute(eATTRIBUTE_ID id, double defaultValue) +{ + this->id = id; + this->defaultValue = defaultValue; + syncable = false; +} + +eATTRIBUTE_ID BaseAttribute::getId() +{ + return id; +} + +double BaseAttribute::getDefaultValue() +{ + return defaultValue; +} + +bool BaseAttribute::isClientSyncable() +{ + return syncable; +} + +BaseAttribute *BaseAttribute::setSyncable(bool syncable) +{ + this->syncable = syncable; + return this; +} \ No newline at end of file diff --git a/Minecraft.World/BaseAttribute.h b/Minecraft.World/BaseAttribute.h new file mode 100644 index 00000000..8693daf7 --- /dev/null +++ b/Minecraft.World/BaseAttribute.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Attribute.h" + +class BaseAttribute : public Attribute +{ +private: + eATTRIBUTE_ID id; + double defaultValue; + bool syncable; + +protected: + BaseAttribute(eATTRIBUTE_ID id, double defaultValue); + +public: + virtual eATTRIBUTE_ID getId(); + virtual double getDefaultValue(); + virtual bool isClientSyncable(); + virtual BaseAttribute *setSyncable(bool syncable); +}; \ No newline at end of file diff --git a/Minecraft.World/BaseAttributeMap.cpp b/Minecraft.World/BaseAttributeMap.cpp new file mode 100644 index 00000000..5a920f24 --- /dev/null +++ b/Minecraft.World/BaseAttributeMap.cpp @@ -0,0 +1,82 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "BaseAttributeMap.h" + +BaseAttributeMap::~BaseAttributeMap() +{ + for(AUTO_VAR(it,attributesById.begin()); it != attributesById.end(); ++it) + { + delete it->second; + } +} + +AttributeInstance *BaseAttributeMap::getInstance(Attribute *attribute) +{ + return getInstance(attribute->getId()); +} + +AttributeInstance *BaseAttributeMap::getInstance(eATTRIBUTE_ID id) +{ + AUTO_VAR(it,attributesById.find(id)); + if(it != attributesById.end()) + { + return it->second; + } + else + { + return NULL; + } +} + +void BaseAttributeMap::getAttributes(vector& atts) +{ + for(AUTO_VAR(it,attributesById.begin()); it != attributesById.end(); ++it) + { + atts.push_back(it->second); + } +} + +void BaseAttributeMap::onAttributeModified(ModifiableAttributeInstance *attributeInstance) +{ +} + +void BaseAttributeMap::removeItemModifiers(shared_ptr item) +{ + attrAttrModMap *modifiers = item->getAttributeModifiers(); + + for(AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) + { + AttributeInstance *attribute = getInstance(it->first); + AttributeModifier *modifier = it->second; + + if (attribute != NULL) + { + attribute->removeModifier(modifier); + } + + delete modifier; + } + + delete modifiers; +} + +void BaseAttributeMap::addItemModifiers(shared_ptr item) +{ + attrAttrModMap *modifiers = item->getAttributeModifiers(); + + for(AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) + { + AttributeInstance *attribute = getInstance(it->first); + AttributeModifier *modifier = it->second; + + if (attribute != NULL) + { + attribute->removeModifier(modifier); + attribute->addModifier(new AttributeModifier(*modifier)); + } + + delete modifier; + } + + delete modifiers; +} diff --git a/Minecraft.World/BaseAttributeMap.h b/Minecraft.World/BaseAttributeMap.h new file mode 100644 index 00000000..928975b8 --- /dev/null +++ b/Minecraft.World/BaseAttributeMap.h @@ -0,0 +1,29 @@ +#pragma once + +class ModifiableAttributeInstance; + +class BaseAttributeMap +{ +protected: + //unordered_map attributesByObject; +#ifdef __ORBIS__ + unordered_map > attributesById; +#else + unordered_map attributesById; +#endif + +public : + virtual ~BaseAttributeMap(); + + virtual AttributeInstance *getInstance(Attribute *attribute); + virtual AttributeInstance *getInstance(eATTRIBUTE_ID name); + + virtual AttributeInstance *registerAttribute(Attribute *attribute) = 0; + + virtual void getAttributes(vector& atts); + virtual void onAttributeModified(ModifiableAttributeInstance *attributeInstance); + + // 4J: Changed these into specialised functions for adding/removing the modifiers of an item (it's cleaner) + virtual void removeItemModifiers(shared_ptr item); + virtual void addItemModifiers(shared_ptr item); +}; \ No newline at end of file diff --git a/Minecraft.World/BaseEntityTile.cpp b/Minecraft.World/BaseEntityTile.cpp new file mode 100644 index 00000000..2edfbf92 --- /dev/null +++ b/Minecraft.World/BaseEntityTile.cpp @@ -0,0 +1,33 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.entity.h" +#include "TileEntity.h" +#include "BaseEntityTile.h" + +BaseEntityTile::BaseEntityTile(int id, Material *material, bool isSolidRender /*= true*/) : Tile(id, material, isSolidRender) +{ + _isEntityTile = true; +} + +void BaseEntityTile::onPlace(Level *level, int x, int y, int z) +{ + Tile::onPlace(level, x, y, z); + //level->setTileEntity(x, y, z, newTileEntity(level)); +} + +void BaseEntityTile::onRemove(Level *level, int x, int y, int z, int id, int data) +{ + Tile::onRemove(level, x, y, z, id, data); + level->removeTileEntity(x, y, z); +} + +bool BaseEntityTile::triggerEvent(Level *level, int x, int y, int z, int b0, int b1) +{ + Tile::triggerEvent(level, x, y, z, b0, b1); + shared_ptr te = level->getTileEntity(x, y, z); + if (te != NULL) + { + return te->triggerEvent(b0, b1); + } + return false; +} \ No newline at end of file diff --git a/Minecraft.World/BaseEntityTile.h b/Minecraft.World/BaseEntityTile.h new file mode 100644 index 00000000..5136bab8 --- /dev/null +++ b/Minecraft.World/BaseEntityTile.h @@ -0,0 +1,15 @@ +#pragma once +#include "Tile.h" +#include "EntityTile.h" + +class TileEntity; + +class BaseEntityTile : public Tile, public EntityTile +{ +protected: + BaseEntityTile(int id, Material *material, bool isSolidRender = true); +public: + virtual void onPlace(Level *level, int x, int y, int z); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual bool triggerEvent(Level *level, int x, int y, int z, int b0, int b1); +}; \ No newline at end of file diff --git a/Minecraft.World/BaseMobSpawner.cpp b/Minecraft.World/BaseMobSpawner.cpp new file mode 100644 index 00000000..887177ed --- /dev/null +++ b/Minecraft.World/BaseMobSpawner.cpp @@ -0,0 +1,401 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" +#include "BaseMobSpawner.h" + +BaseMobSpawner::BaseMobSpawner() +{ + spawnPotentials = NULL; + spawnDelay = 20; + entityId = L"Pig"; + nextSpawnData = NULL; + spin = oSpin = 0.0; + + minSpawnDelay = SharedConstants::TICKS_PER_SECOND * 10; + maxSpawnDelay = SharedConstants::TICKS_PER_SECOND * 40; + spawnCount = 4; + displayEntity = nullptr; + maxNearbyEntities = 6; + requiredPlayerRange = 16; + spawnRange = 4; +} + +BaseMobSpawner::~BaseMobSpawner() +{ + if(spawnPotentials) + { + for(AUTO_VAR(it,spawnPotentials->begin()); it != spawnPotentials->end(); ++it) + { + delete *it; + } + delete spawnPotentials; + } +} + +wstring BaseMobSpawner::getEntityId() +{ + if (getNextSpawnData() == NULL) + { + if (entityId.compare(L"Minecart") == 0) + { + entityId = L"MinecartRideable"; + } + return entityId; + } + else + { + return getNextSpawnData()->type; + } +} + +void BaseMobSpawner::setEntityId(const wstring &entityId) +{ + this->entityId = entityId; +} + +bool BaseMobSpawner::isNearPlayer() +{ + return getLevel()->getNearestPlayer(getX() + 0.5, getY() + 0.5, getZ() + 0.5, requiredPlayerRange) != NULL; +} + +void BaseMobSpawner::tick() +{ + if (!isNearPlayer()) + { + return; + } + + if (getLevel()->isClientSide) + { + double xP = getX() + getLevel()->random->nextFloat(); + double yP = getY() + getLevel()->random->nextFloat(); + double zP = getZ() + getLevel()->random->nextFloat(); + getLevel()->addParticle(eParticleType_smoke, xP, yP, zP, 0, 0, 0); + getLevel()->addParticle(eParticleType_flame, xP, yP, zP, 0, 0, 0); + + if (spawnDelay > 0) spawnDelay--; + oSpin = spin; + spin = (int)(spin + 1000 / (spawnDelay + 200.0f)) % 360; + } + else + { + if (spawnDelay == -1) delay(); + + if (spawnDelay > 0) + { + spawnDelay--; + return; + } + + bool _delay = false; + + for (int c = 0; c < spawnCount; c++) + { + shared_ptr entity = EntityIO::newEntity(getEntityId(), getLevel()); + if (entity == NULL) return; + + int nearBy = getLevel()->getEntitiesOfClass( typeid(entity.get()), AABB::newTemp(getX(), getY(), getZ(), getX() + 1, getY() + 1, getZ() + 1)->grow(spawnRange * 2, 4, spawnRange * 2))->size(); + if (nearBy >= maxNearbyEntities) + { + delay(); + return; + } + + double xp = getX() + (getLevel()->random->nextDouble() - getLevel()->random->nextDouble()) * spawnRange; + double yp = getY() + getLevel()->random->nextInt(3) - 1; + double zp = getZ() + (getLevel()->random->nextDouble() - getLevel()->random->nextDouble()) * spawnRange; + shared_ptr mob = entity->instanceof(eTYPE_MOB) ? dynamic_pointer_cast( entity ) : nullptr; + + entity->moveTo(xp, yp, zp, getLevel()->random->nextFloat() * 360, 0); + + if (mob == NULL || mob->canSpawn()) + { + loadDataAndAddEntity(entity); + getLevel()->levelEvent(LevelEvent::PARTICLES_MOBTILE_SPAWN, getX(), getY(), getZ(), 0); + + if (mob != NULL) + { + mob->spawnAnim(); + } + + _delay = true; + } + } + + if (_delay) delay(); + } +} + +shared_ptr BaseMobSpawner::loadDataAndAddEntity(shared_ptr entity) +{ + if (getNextSpawnData() != NULL) + { + CompoundTag *data = new CompoundTag(); + entity->save(data); + + vector *tags = getNextSpawnData()->tag->getAllTags(); + for (AUTO_VAR(it, tags->begin()); it != tags->end(); ++it) + { + Tag *tag = *it; + data->put(tag->getName(), tag->copy()); + } + delete tags; + + entity->load(data); + if (entity->level != NULL) entity->level->addEntity(entity); + + // add mounts + shared_ptr rider = entity; + while (data->contains(Entity::RIDING_TAG)) + { + CompoundTag *ridingTag = data->getCompound(Entity::RIDING_TAG); + shared_ptr mount = EntityIO::newEntity(ridingTag->getString(L"id"), entity->level); + if (mount != NULL) + { + CompoundTag *mountData = new CompoundTag(); + mount->save(mountData); + + vector *ridingTags = ridingTag->getAllTags(); + for (AUTO_VAR(it, ridingTags->begin()); it != ridingTags->end(); ++it) + { + Tag *tag = *it; + mountData->put(tag->getName(), tag->copy()); + } + delete ridingTags; + mount->load(mountData); + mount->moveTo(rider->x, rider->y, rider->z, rider->yRot, rider->xRot); + + if (entity->level != NULL) entity->level->addEntity(mount); + rider->ride(mount); + } + rider = mount; + data = ridingTag; + } + + } + else if (entity->instanceof(eTYPE_LIVINGENTITY) && entity->level != NULL) + { + dynamic_pointer_cast( entity )->finalizeMobSpawn(NULL); + getLevel()->addEntity(entity); + } + + return entity; +} + +void BaseMobSpawner::delay() +{ + if (maxSpawnDelay <= minSpawnDelay) + { + spawnDelay = minSpawnDelay; + } + else + { + spawnDelay = minSpawnDelay + getLevel()->random->nextInt(maxSpawnDelay - minSpawnDelay); + } + + if ( (spawnPotentials != NULL) && (spawnPotentials->size() > 0) ) + { + setNextSpawnData( (SpawnData*) WeighedRandom::getRandomItem((Random*)getLevel()->random, (vector*)spawnPotentials) ); + } + + broadcastEvent(EVENT_SPAWN); +} + +void BaseMobSpawner::load(CompoundTag *tag) +{ + entityId = tag->getString(L"EntityId"); + spawnDelay = tag->getShort(L"Delay"); + + if (tag->contains(L"SpawnPotentials")) + { + spawnPotentials = new vector(); + ListTag *potentials = (ListTag *) tag->getList(L"SpawnPotentials"); + + for (int i = 0; i < potentials->size(); i++) + { + spawnPotentials->push_back(new SpawnData(potentials->get(i))); + } + } + else + { + spawnPotentials = NULL; + } + + if (tag->contains(L"SpawnData")) + { + setNextSpawnData(new SpawnData(tag->getCompound(L"SpawnData"), entityId)); + } + else + { + setNextSpawnData(NULL); + } + + if (tag->contains(L"MinSpawnDelay")) + { + minSpawnDelay = tag->getShort(L"MinSpawnDelay"); + maxSpawnDelay = tag->getShort(L"MaxSpawnDelay"); + spawnCount = tag->getShort(L"SpawnCount"); + } + + if (tag->contains(L"MaxNearbyEntities")) + { + maxNearbyEntities = tag->getShort(L"MaxNearbyEntities"); + requiredPlayerRange = tag->getShort(L"RequiredPlayerRange"); + } + + if (tag->contains(L"SpawnRange")) spawnRange = tag->getShort(L"SpawnRange"); + + if (getLevel() != NULL && getLevel()->isClientSide) + { + displayEntity = nullptr; + } +} + +void BaseMobSpawner::save(CompoundTag *tag) +{ + tag->putString(L"EntityId", getEntityId()); + tag->putShort(L"Delay", (short) spawnDelay); + tag->putShort(L"MinSpawnDelay", (short) minSpawnDelay); + tag->putShort(L"MaxSpawnDelay", (short) maxSpawnDelay); + tag->putShort(L"SpawnCount", (short) spawnCount); + tag->putShort(L"MaxNearbyEntities", (short) maxNearbyEntities); + tag->putShort(L"RequiredPlayerRange", (short) requiredPlayerRange); + tag->putShort(L"SpawnRange", (short) spawnRange); + + if (getNextSpawnData() != NULL) + { + tag->putCompound(L"SpawnData", (CompoundTag *) getNextSpawnData()->tag->copy()); + } + + if (getNextSpawnData() != NULL || (spawnPotentials != NULL && spawnPotentials->size() > 0)) + { + ListTag *list = new ListTag(); + + if (spawnPotentials != NULL && spawnPotentials->size() > 0) + { + for (AUTO_VAR(it, spawnPotentials->begin()); it != spawnPotentials->end(); ++it) + { + SpawnData *data = *it; + list->add(data->save()); + } + } + else + { + list->add(getNextSpawnData()->save()); + } + + tag->put(L"SpawnPotentials", list); + } +} + +shared_ptr BaseMobSpawner::getDisplayEntity() +{ + if (displayEntity == NULL) + { + shared_ptr e = EntityIO::newEntity(getEntityId(), NULL); + e = loadDataAndAddEntity(e); + displayEntity = e; + } + + return displayEntity; +} + +bool BaseMobSpawner::onEventTriggered(int id) +{ + if (id == EVENT_SPAWN && getLevel()->isClientSide) + { + spawnDelay = minSpawnDelay; + return true; + } + return false; +} + +BaseMobSpawner::SpawnData *BaseMobSpawner::getNextSpawnData() +{ + return nextSpawnData; +} + +void BaseMobSpawner::setNextSpawnData(SpawnData *nextSpawnData) +{ + this->nextSpawnData = nextSpawnData; +} + +BaseMobSpawner::SpawnData::SpawnData(CompoundTag *base) : WeighedRandomItem(base->getInt(L"Weight")) +{ + CompoundTag *tag = base->getCompound(L"Properties"); + wstring _type = base->getString(L"Type"); + + if (_type.compare(L"Minecart") == 0) + { + if (tag != NULL) + { + switch (tag->getInt(L"Type")) + { + case Minecart::TYPE_CHEST: + type = L"MinecartChest"; + break; + case Minecart::TYPE_FURNACE: + type = L"MinecartFurnace"; + break; + case Minecart::TYPE_RIDEABLE: + type = L"MinecartRideable"; + break; + } + } + else + { + type = L"MinecartRideable"; + } + } + + this->tag = tag; + this->type = _type; +} + +BaseMobSpawner::SpawnData::SpawnData(CompoundTag *tag, wstring _type) : WeighedRandomItem(1) +{ + if (_type.compare(L"Minecart") == 0) + { + if (tag != NULL) + { + switch (tag->getInt(L"Type")) + { + case Minecart::TYPE_CHEST: + _type = L"MinecartChest"; + break; + case Minecart::TYPE_FURNACE: + _type = L"MinecartFurnace"; + break; + case Minecart::TYPE_RIDEABLE: + _type = L"MinecartRideable"; + break; + } + } + else + { + _type = L"MinecartRideable"; + } + } + + this->tag = tag; + this->type = _type; +} + +BaseMobSpawner::SpawnData::~SpawnData() +{ + delete tag; +} + +CompoundTag *BaseMobSpawner::SpawnData::save() +{ + CompoundTag *result = new CompoundTag(); + + result->putCompound(L"Properties", tag); + result->putString(L"Type", type); + result->putInt(L"Weight", randomWeight); + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/BaseMobSpawner.h b/Minecraft.World/BaseMobSpawner.h new file mode 100644 index 00000000..88d820e0 --- /dev/null +++ b/Minecraft.World/BaseMobSpawner.h @@ -0,0 +1,70 @@ +#pragma once + +#include "WeighedRandom.h" + +class BaseMobSpawner +{ +public: + class SpawnData : public WeighedRandomItem + { + public: + CompoundTag *tag; + wstring type; + + SpawnData(CompoundTag *base); + SpawnData(CompoundTag *tag, wstring type); + ~SpawnData(); + + virtual CompoundTag *save(); + }; + +private: + static const int EVENT_SPAWN = 1; + +public: + int spawnDelay; + +private: + wstring entityId; + vector *spawnPotentials; + SpawnData *nextSpawnData; + +public: + double spin, oSpin; + +private: + int minSpawnDelay; + int maxSpawnDelay; + int spawnCount; + shared_ptr displayEntity; + int maxNearbyEntities; + int requiredPlayerRange; + int spawnRange; + +public: + BaseMobSpawner(); + ~BaseMobSpawner(); + + virtual wstring getEntityId(); + virtual void setEntityId(const wstring &entityId); + virtual bool isNearPlayer(); + virtual void tick(); + virtual shared_ptr loadDataAndAddEntity(shared_ptr entity); + +private: + virtual void delay(); + +public: + virtual void load(CompoundTag *tag); + virtual void save(CompoundTag *tag); + virtual shared_ptr getDisplayEntity(); + virtual bool onEventTriggered(int id); + virtual SpawnData *getNextSpawnData(); + virtual void setNextSpawnData(SpawnData *nextSpawnData); + + virtual void broadcastEvent(int id) = 0; + virtual Level *getLevel() = 0; + virtual int getX() = 0; + virtual int getY() = 0; + virtual int getZ() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/BasePressurePlateTile.cpp b/Minecraft.World/BasePressurePlateTile.cpp new file mode 100644 index 00000000..128a4216 --- /dev/null +++ b/Minecraft.World/BasePressurePlateTile.cpp @@ -0,0 +1,189 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" +#include "net.minecraft.h" +#include "net.minecraft.world.h" +#include "BasePressurePlateTile.h" + +BasePressurePlateTile::BasePressurePlateTile(int id, const wstring &tex, Material *material) : Tile(id, material, isSolidRender()) +{ + texture = tex; + setTicking(true); + + // 4J Stu - Move this to derived classes + //updateShape(getDataForSignal(Redstone::SIGNAL_MAX)); +} + +void BasePressurePlateTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) +{ + updateShape(level->getData(x, y, z)); +} + +void BasePressurePlateTile::updateShape(int data) +{ + bool pressed = getSignalForData(data) > Redstone::SIGNAL_NONE; + float o = 1 / 16.0f; + + if (pressed) + { + setShape(o, 0, o, 1 - o, 0.5f / 16.0f, 1 - o); + } + else + { + setShape(o, 0, o, 1 - o, 1 / 16.0f, 1 - o); + } +} + +int BasePressurePlateTile::getTickDelay(Level *level) +{ + return SharedConstants::TICKS_PER_SECOND; +} + +AABB *BasePressurePlateTile::getAABB(Level *level, int x, int y, int z) +{ + return NULL; +} + +bool BasePressurePlateTile::isSolidRender(bool isServerLevel) +{ + return false; +} + +bool BasePressurePlateTile::blocksLight() +{ + return false; +} + +bool BasePressurePlateTile::isCubeShaped() +{ + return false; +} + +bool BasePressurePlateTile::isPathfindable(LevelSource *level, int x, int y, int z) +{ + return true; +} + +bool BasePressurePlateTile::mayPlace(Level *level, int x, int y, int z) +{ + return level->isTopSolidBlocking(x, y - 1, z) || FenceTile::isFence(level->getTile(x, y - 1, z)); +} + +void BasePressurePlateTile::neighborChanged(Level *level, int x, int y, int z, int type) +{ + bool replace = false; + + if (!level->isTopSolidBlocking(x, y - 1, z) && !FenceTile::isFence(level->getTile(x, y - 1, z))) replace = true; + + if (replace) + { + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); + } +} + +void BasePressurePlateTile::tick(Level *level, int x, int y, int z, Random *random) +{ + if (level->isClientSide) return; + int signal = getSignalForData(level->getData(x, y, z)); + if (signal > Redstone::SIGNAL_NONE) checkPressed(level, x, y, z, signal); +} + +void BasePressurePlateTile::entityInside(Level *level, int x, int y, int z, shared_ptr entity) +{ + if (level->isClientSide) return; + int signal = getSignalForData(level->getData(x, y, z)); + if (signal == Redstone::SIGNAL_NONE) checkPressed(level, x, y, z, signal); +} + +void BasePressurePlateTile::checkPressed(Level *level, int x, int y, int z, int oldSignal) +{ + int signal = getSignalStrength(level, x, y, z); + bool wasPressed = oldSignal > Redstone::SIGNAL_NONE; + bool shouldBePressed = signal > Redstone::SIGNAL_NONE; + + if (oldSignal != signal) + { + level->setData(x, y, z, getDataForSignal(signal), Tile::UPDATE_CLIENTS); + updateNeighbours(level, x, y, z); + level->setTilesDirty(x, y, z, x, y, z); + } + + if (!shouldBePressed && wasPressed) + { + level->playSound(x + 0.5, y + 0.1, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, 0.5f); + } + else if (shouldBePressed && !wasPressed) + { + level->playSound(x + 0.5, y + 0.1, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, 0.6f); + } + + if (shouldBePressed) + { + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); + } +} + +AABB *BasePressurePlateTile::getSensitiveAABB(int x, int y, int z) +{ + float b = 2 / 16.0f; + return AABB::newTemp(x + b, y, z + b, x + 1 - b, y + 0.25, z + 1 - b); +} + +void BasePressurePlateTile::onRemove(Level *level, int x, int y, int z, int id, int data) +{ + if (getSignalForData(data) > 0) + { + updateNeighbours(level, x, y, z); + } + + Tile::onRemove(level, x, y, z, id, data); +} + +void BasePressurePlateTile::updateNeighbours(Level *level, int x, int y, int z) +{ + level->updateNeighborsAt(x, y, z, id); + level->updateNeighborsAt(x, y - 1, z, id); +} + +int BasePressurePlateTile::getSignal(LevelSource *level, int x, int y, int z, int dir) +{ + return getSignalForData(level->getData(x, y, z)); +} + +int BasePressurePlateTile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir) +{ + if (dir == Facing::UP) + { + return getSignalForData(level->getData(x, y, z)); + } + else + { + return Redstone::SIGNAL_NONE; + } +} + +bool BasePressurePlateTile::isSignalSource() +{ + return true; +} + +void BasePressurePlateTile::updateDefaultShape() +{ + float x = 8 / 16.0f; + float y = 2 / 16.0f; + float z = 8 / 16.0f; + setShape(0.5f - x, 0.5f - y, 0.5f - z, 0.5f + x, 0.5f + y, 0.5f + z); +} + +int BasePressurePlateTile::getPistonPushReaction() +{ + return Material::PUSH_DESTROY; +} + +void BasePressurePlateTile::registerIcons(IconRegister *iconRegister) +{ + icon = iconRegister->registerIcon(texture); +} \ No newline at end of file diff --git a/Minecraft.World/BasePressurePlateTile.h b/Minecraft.World/BasePressurePlateTile.h new file mode 100644 index 00000000..c0870dab --- /dev/null +++ b/Minecraft.World/BasePressurePlateTile.h @@ -0,0 +1,55 @@ +#pragma once + +#include "Tile.h" + +class BasePressurePlateTile : public Tile +{ +private: + wstring texture; + +protected: + BasePressurePlateTile(int id, const wstring &tex, Material *material); + +public: + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); + +protected: + virtual void updateShape(int data); + +public: + virtual int getTickDelay(Level *level); + virtual AABB *getAABB(Level *level, int x, int y, int z); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool blocksLight(); + virtual bool isCubeShaped(); + virtual bool isPathfindable(LevelSource *level, int x, int y, int z); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual void entityInside(Level *level, int x, int y, int z, shared_ptr entity); + +protected: + virtual void checkPressed(Level *level, int x, int y, int z, int oldSignal); + virtual AABB *getSensitiveAABB(int x, int y, int z); + +public: + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + +protected: + virtual void updateNeighbours(Level *level, int x, int y, int z); + +public: + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); + virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir); + virtual bool isSignalSource(); + virtual void updateDefaultShape(); + virtual int getPistonPushReaction(); + +protected: + virtual int getSignalStrength(Level *level, int x, int y, int z) = 0; + virtual int getSignalForData(int data) = 0; + virtual int getDataForSignal(int signal) = 0; + +public: + virtual void registerIcons(IconRegister *iconRegister); +}; \ No newline at end of file diff --git a/Minecraft.World/BaseRailTile.cpp b/Minecraft.World/BaseRailTile.cpp new file mode 100644 index 00000000..8ec23fd6 --- /dev/null +++ b/Minecraft.World/BaseRailTile.cpp @@ -0,0 +1,511 @@ +#include "stdafx.h" +#include "net.minecraft.world.phys.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.h" +#include "BaseRailTile.h" + +BaseRailTile::Rail::Rail(Level *level, int x, int y, int z) +{ + this->level = level; + this->x = x; + this->y = y; + this->z = z; + + int id = level->getTile(x, y, z); + + // 4J Stu - We saw a random crash near the end of development on XboxOne orignal version where the id here isn't a tile any more + // Adding this check in to avoid that crash + m_bValidRail = isRail(id); + if(m_bValidRail) + { + int direction = level->getData(x, y, z); + if (((BaseRailTile *) Tile::tiles[id])->usesDataBit) + { + usesDataBit = true; + direction = direction & ~RAIL_DATA_BIT; + } + else + { + usesDataBit = false; + } + updateConnections(direction); + } +} + +BaseRailTile::Rail::~Rail() +{ + for( int i = 0; i < connections.size(); i++ ) + { + delete connections[i]; + } +} + +void BaseRailTile::Rail::updateConnections(int direction) +{ + if(m_bValidRail) + { + for( int i = 0; i < connections.size(); i++ ) + { + delete connections[i]; + } + connections.clear(); + MemSect(50); + if (direction == DIR_FLAT_Z) + { + connections.push_back(new TilePos(x, y, z - 1)); + connections.push_back(new TilePos(x, y, z + 1)); + } else if (direction == DIR_FLAT_X) + { + connections.push_back(new TilePos(x - 1, y, z)); + connections.push_back(new TilePos(x + 1, y, z)); + } else if (direction == 2) + { + connections.push_back(new TilePos(x - 1, y, z)); + connections.push_back(new TilePos(x + 1, y + 1, z)); + } else if (direction == 3) + { + connections.push_back(new TilePos(x - 1, y + 1, z)); + connections.push_back(new TilePos(x + 1, y, z)); + } else if (direction == 4) + { + connections.push_back(new TilePos(x, y + 1, z - 1)); + connections.push_back(new TilePos(x, y, z + 1)); + } else if (direction == 5) + { + connections.push_back(new TilePos(x, y, z - 1)); + connections.push_back(new TilePos(x, y + 1, z + 1)); + } else if (direction == 6) + { + connections.push_back(new TilePos(x + 1, y, z)); + connections.push_back(new TilePos(x, y, z + 1)); + } else if (direction == 7) + { + connections.push_back(new TilePos(x - 1, y, z)); + connections.push_back(new TilePos(x, y, z + 1)); + } else if (direction == 8) + { + connections.push_back(new TilePos(x - 1, y, z)); + connections.push_back(new TilePos(x, y, z - 1)); + } else if (direction == 9) + { + connections.push_back(new TilePos(x + 1, y, z)); + connections.push_back(new TilePos(x, y, z - 1)); + } + MemSect(0); + } +} + +void BaseRailTile::Rail::removeSoftConnections() +{ + if(m_bValidRail) + { + for (unsigned int i = 0; i < connections.size(); i++) + { + Rail *rail = getRail(connections[i]); + if (rail == NULL || !rail->connectsTo(this)) + { + delete connections[i]; + connections.erase(connections.begin()+i); + i--; + } else + { + delete connections[i]; + MemSect(50); + connections[i] =new TilePos(rail->x, rail->y, rail->z); + MemSect(0); + } + delete rail; + } + } +} + +bool BaseRailTile::Rail::hasRail(int x, int y, int z) +{ + if(!m_bValidRail) return false; + if (isRail(level, x, y, z)) return true; + if (isRail(level, x, y + 1, z)) return true; + if (isRail(level, x, y - 1, z)) return true; + return false; +} + +BaseRailTile::Rail *BaseRailTile::Rail::getRail(TilePos *p) +{ + if(!m_bValidRail) return NULL; + if (isRail(level, p->x, p->y, p->z)) return new Rail(level, p->x, p->y, p->z); + if (isRail(level, p->x, p->y + 1, p->z)) return new Rail(level, p->x, p->y + 1, p->z); + if (isRail(level, p->x, p->y - 1, p->z)) return new Rail(level, p->x, p->y - 1, p->z); + return NULL; +} + + +bool BaseRailTile::Rail::connectsTo(Rail *rail) +{ + if(m_bValidRail) + { + AUTO_VAR(itEnd, connections.end()); + for (AUTO_VAR(it, connections.begin()); it != itEnd; it++) + { + TilePos *p = *it; //connections[i]; + if (p->x == rail->x && p->z == rail->z) + { + return true; + } + } + } + return false; +} + +bool BaseRailTile::Rail::hasConnection(int x, int y, int z) +{ + if(m_bValidRail) + { + AUTO_VAR(itEnd, connections.end()); + for (AUTO_VAR(it, connections.begin()); it != itEnd; it++) + { + TilePos *p = *it; //connections[i]; + if (p->x == x && p->z == z) + { + return true; + } + } + } + return false; +} + + +int BaseRailTile::Rail::countPotentialConnections() +{ + int count = 0; + + if(m_bValidRail) + { + if (hasRail(x, y, z - 1)) count++; + if (hasRail(x, y, z + 1)) count++; + if (hasRail(x - 1, y, z)) count++; + if (hasRail(x + 1, y, z)) count++; + } + + return count; +} + +bool BaseRailTile::Rail::canConnectTo(Rail *rail) +{ + if(!m_bValidRail) return false; + if (connectsTo(rail)) return true; + if (connections.size() == 2) + { + return false; + } + if (connections.empty()) + { + return true; + } + + return true; +} + +void BaseRailTile::Rail::connectTo(Rail *rail) +{ + if(m_bValidRail) + { + MemSect(50); + connections.push_back(new TilePos(rail->x, rail->y, rail->z)); + MemSect(0); + + bool n = hasConnection(x, y, z - 1); + bool s = hasConnection(x, y, z + 1); + bool w = hasConnection(x - 1, y, z); + bool e = hasConnection(x + 1, y, z); + + int dir = -1; + + if (n || s) dir = DIR_FLAT_Z; + if (w || e) dir = DIR_FLAT_X; + + if (!usesDataBit) + { + if (s && e && !n && !w) dir = 6; + if (s && w && !n && !e) dir = 7; + if (n && w && !s && !e) dir = 8; + if (n && e && !s && !w) dir = 9; + } + if (dir == DIR_FLAT_Z) + { + if (isRail(level, x, y + 1, z - 1)) dir = 4; + if (isRail(level, x, y + 1, z + 1)) dir = 5; + } + if (dir == DIR_FLAT_X) + { + if (isRail(level, x + 1, y + 1, z)) dir = 2; + if (isRail(level, x - 1, y + 1, z)) dir = 3; + } + + if (dir < 0) dir = DIR_FLAT_Z; + + int data = dir; + if (usesDataBit) + { + data = (level->getData(x, y, z) & RAIL_DATA_BIT) | dir; + } + + level->setData(x, y, z, data, Tile::UPDATE_ALL); + } +} + +bool BaseRailTile::Rail::hasNeighborRail(int x, int y, int z) +{ + if(!m_bValidRail) return false; + TilePos tp(x,y,z); + Rail *neighbor = getRail( &tp ); + if (neighbor == NULL) return false; + neighbor->removeSoftConnections(); + bool retval = neighbor->canConnectTo(this); + delete neighbor; + return retval; +} + +void BaseRailTile::Rail::place(bool hasSignal, bool first) +{ + if(m_bValidRail) + { + bool n = hasNeighborRail(x, y, z - 1); + bool s = hasNeighborRail(x, y, z + 1); + bool w = hasNeighborRail(x - 1, y, z); + bool e = hasNeighborRail(x + 1, y, z); + + int dir = -1; + + if ((n || s) && !w && !e) dir = DIR_FLAT_Z; + if ((w || e) && !n && !s) dir = DIR_FLAT_X; + + if (!usesDataBit) + { + if (s && e && !n && !w) dir = 6; + if (s && w && !n && !e) dir = 7; + if (n && w && !s && !e) dir = 8; + if (n && e && !s && !w) dir = 9; + } + if (dir == -1) + { + if (n || s) dir = DIR_FLAT_Z; + if (w || e) dir = DIR_FLAT_X; + + if (!usesDataBit) + { + if (hasSignal) + { + if (s && e) dir = 6; + if (w && s) dir = 7; + if (e && n) dir = 9; + if (n && w) dir = 8; + } else { + if (n && w) dir = 8; + if (e && n) dir = 9; + if (w && s) dir = 7; + if (s && e) dir = 6; + } + } + } + + if (dir == DIR_FLAT_Z) + { + if (isRail(level, x, y + 1, z - 1)) dir = 4; + if (isRail(level, x, y + 1, z + 1)) dir = 5; + } + if (dir == DIR_FLAT_X) + { + if (isRail(level, x + 1, y + 1, z)) dir = 2; + if (isRail(level, x - 1, y + 1, z)) dir = 3; + } + + if (dir < 0) dir = DIR_FLAT_Z; + + updateConnections(dir); + + int data = dir; + if (usesDataBit) + { + data = (level->getData(x, y, z) & RAIL_DATA_BIT) | dir; + } + + if (first || level->getData(x, y, z) != data) + { + level->setData(x, y, z, data, Tile::UPDATE_ALL); + + AUTO_VAR(itEnd, connections.end()); + for (AUTO_VAR(it, connections.begin()); it != itEnd; it++) + { + Rail *neighbor = getRail(*it); + if (neighbor == NULL) continue; + neighbor->removeSoftConnections(); + + if (neighbor->canConnectTo(this)) + { + neighbor->connectTo(this); + } + delete neighbor; + } + } + } +} + +bool BaseRailTile::isRail(Level *level, int x, int y, int z) +{ + return isRail(level->getTile(x, y, z)); +} + +bool BaseRailTile::isRail(int id) +{ + return id == Tile::rail_Id || id == Tile::goldenRail_Id || id == Tile::detectorRail_Id || id == Tile::activatorRail_Id; +} + +BaseRailTile::BaseRailTile(int id, bool usesDataBit) : Tile(id, Material::decoration, isSolidRender()) +{ + this->usesDataBit = usesDataBit; + setShape(0, 0, 0, 1, 2 / 16.0f, 1); + + iconTurn = NULL; +} + +bool BaseRailTile::isUsesDataBit() +{ + return usesDataBit; +} + +AABB *BaseRailTile::getAABB(Level *level, int x, int y, int z) +{ + return NULL; +} + +bool BaseRailTile::blocksLight() +{ + return false; +} + +bool BaseRailTile::isSolidRender(bool isServerLevel) +{ + return false; +} + +HitResult *BaseRailTile::clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b) +{ + updateShape(level, xt, yt, zt); + return Tile::clip(level, xt, yt, zt, a, b); +} + +void BaseRailTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param +{ + int data = level->getData(x, y, z); + if (data >= 2 && data <= 5) + { + setShape(0, 0, 0, 1, 2 / 16.0f + 0.5f, 1); + } else + { + setShape(0, 0, 0, 1, 2 / 16.0f, 1); + } +} + +bool BaseRailTile::isCubeShaped() +{ + return false; +} + +int BaseRailTile::getRenderShape() +{ + return Tile::SHAPE_RAIL; +} + +int BaseRailTile::getResourceCount(Random random) +{ + return 1; +} + +bool BaseRailTile::mayPlace(Level *level, int x, int y, int z) +{ + if (level->isTopSolidBlocking(x, y - 1, z)) + { + return true; + } + return false; +} + +void BaseRailTile::onPlace(Level *level, int x, int y, int z) +{ + if (!level->isClientSide) + { + updateDir(level, x, y, z, true); + + if (usesDataBit) + { + neighborChanged(level, x, y, z, id); + } + } +} + +void BaseRailTile::neighborChanged(Level *level, int x, int y, int z, int type) +{ + if (level->isClientSide) return; + + int data = level->getData(x, y, z); + int dir = data; + if (usesDataBit) { + dir = dir & RAIL_DIRECTION_MASK; + } + bool remove = false; + + if (!level->isTopSolidBlocking(x, y - 1, z)) remove = true; + if (dir == 2 && !level->isTopSolidBlocking(x + 1, y, z)) remove = true; + if (dir == 3 && !level->isTopSolidBlocking(x - 1, y, z)) remove = true; + if (dir == 4 && !level->isTopSolidBlocking(x, y, z - 1)) remove = true; + if (dir == 5 && !level->isTopSolidBlocking(x, y, z + 1)) remove = true; + + if (remove) + { + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); + } + else + { + updateState(level, x, y, z, data, dir, type); + } + +} + +void BaseRailTile::updateState(Level *level, int x, int y, int z, int data, int dir, int type) +{ +} + +void BaseRailTile::updateDir(Level *level, int x, int y, int z, bool first) +{ + if (level->isClientSide) return; + Rail *rail = new Rail(level, x, y, z); + rail->place(level->hasNeighborSignal(x, y, z), first); + delete rail; +} + +int BaseRailTile::getPistonPushReaction() +{ + // override the decoration material's reaction + return Material::PUSH_NORMAL; +} + +void BaseRailTile::onRemove(Level *level, int x, int y, int z, int id, int data) +{ + int dir = data; + if (usesDataBit) + { + dir &= RAIL_DIRECTION_MASK; + } + + Tile::onRemove(level, x, y, z, id, data); + + if (dir == 2 || dir == 3 || dir == 4 || dir == 5) + { + level->updateNeighborsAt(x, y + 1, z, id); + } + if (usesDataBit) + { + level->updateNeighborsAt(x, y, z, id); + level->updateNeighborsAt(x, y - 1, z, id); + } +} \ No newline at end of file diff --git a/Minecraft.World/BaseRailTile.h b/Minecraft.World/BaseRailTile.h new file mode 100644 index 00000000..105ddfde --- /dev/null +++ b/Minecraft.World/BaseRailTile.h @@ -0,0 +1,89 @@ +#pragma once +#include "Tile.h" +#include "TilePos.h" +#include "Definitions.h" + +class Random; +class HitResult; +class ChunkRebuildData; + +using namespace std; + +class BaseRailTile : public Tile +{ + friend class Tile; + friend class ChunkRebuildData; +public: + static const int DIR_FLAT_Z = 0; + static const int DIR_FLAT_X = 1; + // the data bit is used by boosters and detectors, so they can't turn + static const int RAIL_DATA_BIT = 8; + static const int RAIL_DIRECTION_MASK = 7; + +private: + Icon *iconTurn; + +protected: + bool usesDataBit; + + class Rail + { + friend class BaseRailTile; + friend class RailTile; + private: + Level *level; + int x, y, z; + bool usesDataBit; + vector connections; + bool m_bValidRail; // 4J added + + public: + Rail(Level *level, int x, int y, int z); + ~Rail(); + private: + void updateConnections(int direction); + void removeSoftConnections(); + bool hasRail(int x, int y, int z); + Rail *getRail(TilePos *p); + bool connectsTo(Rail *rail); + bool hasConnection(int x, int y, int z); + + protected: + int countPotentialConnections(); + + private: + bool canConnectTo(Rail *rail); + void connectTo(Rail *rail); + bool hasNeighborRail(int x, int y, int z); + public: + void place(bool hasSignal, bool first); + }; +public: + static bool isRail(Level *level, int x, int y, int z); + static bool isRail(int id); +protected: + BaseRailTile(int id, bool usesDataBit); +public: + using Tile::getResourceCount; + + bool isUsesDataBit(); + virtual AABB *getAABB(Level *level, int x, int y, int z); + virtual bool blocksLight(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual HitResult *clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b); + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param + virtual bool isCubeShaped(); + virtual int getRenderShape(); + virtual int getResourceCount(Random random); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual void onPlace(Level *level, int x, int y, int z); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + +protected: + virtual void updateState(Level *level, int x, int y, int z, int data, int dir, int type); + virtual void updateDir(Level *level, int x, int y, int z, bool first); + +public: + int getPistonPushReaction(); + void onRemove(Level *level, int x, int y, int z, int id, int data); +}; diff --git a/Minecraft.World/BasicTypeContainers.cpp b/Minecraft.World/BasicTypeContainers.cpp index ea9839c6..9ecc865c 100644 --- a/Minecraft.World/BasicTypeContainers.cpp +++ b/Minecraft.World/BasicTypeContainers.cpp @@ -14,6 +14,8 @@ const float Float::MAX_VALUE = FLT_MAX; const double Double::MAX_VALUE = DBL_MAX; +const double Double::MIN_NORMAL = DBL_MIN; + int Integer::parseInt(wstring &str, int radix /* = 10*/) { return wcstol( str.c_str(), NULL, radix ); diff --git a/Minecraft.World/BasicTypeContainers.h b/Minecraft.World/BasicTypeContainers.h index 094e9616..5f577a97 100644 --- a/Minecraft.World/BasicTypeContainers.h +++ b/Minecraft.World/BasicTypeContainers.h @@ -47,6 +47,7 @@ class Double { public: static const double MAX_VALUE; + static const double MIN_NORMAL; static bool isNaN( double a ) { #ifdef __PS3__ diff --git a/Minecraft.World/Bat.cpp b/Minecraft.World/Bat.cpp new file mode 100644 index 00000000..d3bd3521 --- /dev/null +++ b/Minecraft.World/Bat.cpp @@ -0,0 +1,258 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" +#include "Bat.h" + +Bat::Bat(Level *level) : AmbientCreature(level) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); + + targetPosition = NULL; + + setSize(.5f, .9f); + setResting(true); +} + +void Bat::defineSynchedData() +{ + AmbientCreature::defineSynchedData(); + + entityData->define(DATA_ID_FLAGS, (char) 0); +} + +float Bat::getSoundVolume() +{ + return 0.1f; +} + +float Bat::getVoicePitch() +{ + return AmbientCreature::getVoicePitch() * .95f; +} + +int Bat::getAmbientSound() +{ + if (isResting() && random->nextInt(4) != 0) + { + return -1; + } + return eSoundType_MOB_BAT_IDLE; //"mob.bat.idle"; +} + +int Bat::getHurtSound() +{ + return eSoundType_MOB_BAT_HURT; //"mob.bat.hurt"; +} + +int Bat::getDeathSound() +{ + return eSoundType_MOB_BAT_DEATH; //"mob.bat.death"; +} + +bool Bat::isPushable() +{ + // bats can't be pushed by other mobs + return false; +} + +void Bat::doPush(shared_ptr e) +{ + // bats don't push other mobs +} + +void Bat::pushEntities() +{ + // bats don't push other mobs +} + +void Bat::registerAttributes() +{ + AmbientCreature::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(6); +} + +bool Bat::isResting() +{ + return (entityData->getByte(DATA_ID_FLAGS) & FLAG_RESTING) != 0; +} + +void Bat::setResting(bool value) +{ + char current = entityData->getByte(DATA_ID_FLAGS); + if (value) + { + entityData->set(DATA_ID_FLAGS, (char) (current | FLAG_RESTING)); + } + else + { + entityData->set(DATA_ID_FLAGS, (char) (current & ~FLAG_RESTING)); + } +} + +bool Bat::useNewAi() +{ + return true; +} + +void Bat::tick() +{ + + AmbientCreature::tick(); + + if (isResting()) + { + xd = yd = zd = 0; + y = Mth::floor(y) + 1.0 - bbHeight; + } + else + { + yd *= .6f; + } + +} + +inline int signum(double x) { return (x > 0) - (x < 0); } + +void Bat::newServerAiStep() +{ + AmbientCreature::newServerAiStep(); + + if (isResting()) + { + if (!level->isSolidBlockingTile(Mth::floor(x), (int) y + 1, Mth::floor(z))) + { + setResting(false); + level->levelEvent(nullptr, LevelEvent::SOUND_BAT_LIFTOFF, (int) x, (int) y, (int) z, 0); + } + else + { + + if (random->nextInt(200) == 0) + { + yHeadRot = random->nextInt(360); + } + + if (level->getNearestPlayer(shared_from_this(), 4.0f) != NULL) + { + setResting(false); + level->levelEvent(nullptr, LevelEvent::SOUND_BAT_LIFTOFF, (int) x, (int) y, (int) z, 0); + } + } + } + else + { + + if (targetPosition != NULL && (!level->isEmptyTile(targetPosition->x, targetPosition->y, targetPosition->z) || targetPosition->y < 1)) + { + delete targetPosition; + targetPosition = NULL; + } + if (targetPosition == NULL || random->nextInt(30) == 0 || targetPosition->distSqr((int) x, (int) y, (int) z) < 4) + { + delete targetPosition; + targetPosition = new Pos((int) x + random->nextInt(7) - random->nextInt(7), (int) y + random->nextInt(6) - 2, (int) z + random->nextInt(7) - random->nextInt(7)); + } + + double dx = (targetPosition->x + .5) - x; + double dy = (targetPosition->y + .1) - y; + double dz = (targetPosition->z + .5) - z; + + xd = xd + (signum(dx) * .5f - xd) * .1f; + yd = yd + (signum(dy) * .7f - yd) * .1f; + zd = zd + (signum(dz) * .5f - zd) * .1f; + + float yRotD = (float) (atan2(zd, xd) * 180 / PI) - 90; + float rotDiff = Mth::wrapDegrees(yRotD - yRot); + yya = .5f; + yRot += rotDiff; + + if (random->nextInt(100) == 0 && level->isSolidBlockingTile(Mth::floor(x), (int) y + 1, Mth::floor(z))) + { + setResting(true); + } + + } +} + +bool Bat::makeStepSound() +{ + return false; +} + +void Bat::causeFallDamage(float distance) +{ +} + +void Bat::checkFallDamage(double ya, bool onGround) +{ + // this method is empty because flying creatures should + // not trigger the "fallOn" tile calls (such as trampling crops) +} + +bool Bat::isIgnoringTileTriggers() +{ + return true; +} + +bool Bat::hurt(DamageSource *source, float dmg) +{ + if (isInvulnerable()) return false; + if (!level->isClientSide) + { + if (isResting()) + { + setResting(false); + } + } + + return AmbientCreature::hurt(source, dmg); +} + +void Bat::readAdditionalSaveData(CompoundTag *tag) +{ + AmbientCreature::readAdditionalSaveData(tag); + + entityData->set(DATA_ID_FLAGS, tag->getByte(L"BatFlags")); +} + +void Bat::addAdditonalSaveData(CompoundTag *entityTag) +{ + AmbientCreature::addAdditonalSaveData(entityTag); + + entityTag->putByte(L"BatFlags", entityData->getByte(DATA_ID_FLAGS)); +} + + +bool Bat::canSpawn() +{ + int yt = Mth::floor(bb->y0); + if (yt >= level->seaLevel) return false; + + int xt = Mth::floor(x); + int zt = Mth::floor(z); + + int br = level->getRawBrightness(xt, yt, zt); + int maxLight = 4; + + if ((Calendar::GetDayOfMonth() + 1 == 10 && Calendar::GetDayOfMonth() >= 20) || (Calendar::GetMonth() + 1 == 11 && Calendar::GetMonth() <= 3)) + { + maxLight = 7; + } + else if (random->nextBoolean()) + { + return false; + } + + if (br > random->nextInt(maxLight)) return false; + + return AmbientCreature::canSpawn(); +} \ No newline at end of file diff --git a/Minecraft.World/Bat.h b/Minecraft.World/Bat.h new file mode 100644 index 00000000..118fc6ed --- /dev/null +++ b/Minecraft.World/Bat.h @@ -0,0 +1,58 @@ +#pragma once + +#include "AmbientCreature.h" + +class Bat : public AmbientCreature +{ +public: + eINSTANCEOF GetType() { return eTYPE_BAT; } + static Entity *create(Level *level) { return new Bat(level); } + +private: + static const int DATA_ID_FLAGS = 16; + static const int FLAG_RESTING = 1; + + Pos *targetPosition; + +public: + Bat(Level *level); + +protected: + virtual void defineSynchedData(); + virtual float getSoundVolume(); + virtual float getVoicePitch(); + virtual int getAmbientSound(); + virtual int getHurtSound(); + virtual int getDeathSound(); + +public: + virtual bool isPushable(); + +protected: + virtual void doPush(shared_ptr e); + virtual void pushEntities(); + virtual void registerAttributes(); + +public: + virtual bool isResting(); + virtual void setResting(bool value); + +protected: + virtual bool useNewAi(); + +public: + virtual void tick(); + +protected: + virtual void newServerAiStep(); + virtual bool makeStepSound(); + virtual void causeFallDamage(float distance); + virtual void checkFallDamage(double ya, bool onGround); + virtual bool isIgnoringTileTriggers(); + +public: + virtual bool hurt(DamageSource *source, float dmg); + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *entityTag); + virtual bool canSpawn(); +}; \ No newline at end of file diff --git a/Minecraft.World/BeachBiome.cpp b/Minecraft.World/BeachBiome.cpp index ba85908a..50e7cc1c 100644 --- a/Minecraft.World/BeachBiome.cpp +++ b/Minecraft.World/BeachBiome.cpp @@ -8,8 +8,8 @@ BeachBiome::BeachBiome(int id) : Biome(id) // remove default mob spawn settings friendlies.clear(); friendlies_chicken.clear(); // 4J added - this->topMaterial = (byte) Tile::sand_Id; - this->material = (byte) Tile::sand_Id; + topMaterial = (byte) Tile::sand_Id; + material = (byte) Tile::sand_Id; decorator->treeCount = -999; decorator->deadBushCount = 0; diff --git a/Minecraft.World/BeaconMenu.cpp b/Minecraft.World/BeaconMenu.cpp new file mode 100644 index 00000000..707e9ebf --- /dev/null +++ b/Minecraft.World/BeaconMenu.cpp @@ -0,0 +1,140 @@ +#include "stdafx.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "BeaconMenu.h" + +BeaconMenu::BeaconMenu(shared_ptr inventory, shared_ptr beacon) +{ + this->beacon = beacon; + + addSlot(paymentSlot = new BeaconMenu::PaymentSlot(beacon, PAYMENT_SLOT, 136, 110)); + + int xo = 36; + int yo = 137; + + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(inventory, x + y * 9 + 9, xo + x * 18, yo + y * 18)); + } + } + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(inventory, x, xo + x * 18, 58 + yo)); + } + + levels = beacon->getLevels(); + primaryPower = beacon->getPrimaryPower(); + secondaryPower = beacon->getSecondaryPower(); +} + + +void BeaconMenu::addSlotListener(ContainerListener *listener) +{ + AbstractContainerMenu::addSlotListener(listener); + + listener->setContainerData(this, 0, levels); + listener->setContainerData(this, 1, primaryPower); + listener->setContainerData(this, 2, secondaryPower); +} + +void BeaconMenu::setData(int id, int value) +{ + if (id == 0) beacon->setLevels(value); + if (id == 1) beacon->setPrimaryPower(value); + if (id == 2) beacon->setSecondaryPower(value); +} + +shared_ptr BeaconMenu::getBeacon() +{ + return beacon; +} + +bool BeaconMenu::stillValid(shared_ptr player) +{ + return beacon->stillValid(player); +} + +shared_ptr BeaconMenu::quickMoveStack(shared_ptr player, int slotIndex) +{ + shared_ptr clicked = nullptr; + Slot *slot = slots.at(slotIndex); + if (slot != NULL && slot->hasItem()) + { + shared_ptr stack = slot->getItem(); + clicked = stack->copy(); + + if (slotIndex == PAYMENT_SLOT) + { + if (!moveItemStackTo(stack, INV_SLOT_START, USE_ROW_SLOT_END, true)) + { + return nullptr; + } + slot->onQuickCraft(stack, clicked); + } + else if (!paymentSlot->hasItem() && paymentSlot->mayPlace(stack) && stack->count == 1) + { + if (!moveItemStackTo(stack, PAYMENT_SLOT, PAYMENT_SLOT + 1, false)) + { + return nullptr; + } + } + else if (slotIndex >= INV_SLOT_START && slotIndex < INV_SLOT_END) + { + if (!moveItemStackTo(stack, USE_ROW_SLOT_START, USE_ROW_SLOT_END, false)) + { + return nullptr; + } + } + else if (slotIndex >= USE_ROW_SLOT_START && slotIndex < USE_ROW_SLOT_END) + { + if (!moveItemStackTo(stack, INV_SLOT_START, INV_SLOT_END, false)) + { + return nullptr; + } + } + else + { + if (!moveItemStackTo(stack, INV_SLOT_START, USE_ROW_SLOT_END, false)) + { + return nullptr; + } + } + if (stack->count == 0) + { + slot->set(nullptr); + } + else + { + slot->setChanged(); + } + if (stack->count == clicked->count) + { + return nullptr; + } + else + { + slot->onTake(player, stack); + } + } + return clicked; +} + +BeaconMenu::PaymentSlot::PaymentSlot(shared_ptr container, int slot, int x, int y) : Slot(container, slot, x, y) +{ +} + +bool BeaconMenu::PaymentSlot::mayPlace(shared_ptr item) +{ + if (item != NULL) + { + return (item->id == Item::emerald_Id || item->id == Item::diamond_Id || item->id == Item::goldIngot_Id || item->id == Item::ironIngot_Id); + } + return false; +} + +int BeaconMenu::PaymentSlot::getMaxStackSize() +{ + return 1; +} \ No newline at end of file diff --git a/Minecraft.World/BeaconMenu.h b/Minecraft.World/BeaconMenu.h new file mode 100644 index 00000000..8d3afba6 --- /dev/null +++ b/Minecraft.World/BeaconMenu.h @@ -0,0 +1,44 @@ +#pragma once + +#include "AbstractContainerMenu.h" +#include "Slot.h" + +class BeaconTileEntity; + +class BeaconMenu : public AbstractContainerMenu +{ +private: + class PaymentSlot : public Slot + { + public: + PaymentSlot(shared_ptr container, int slot, int x, int y); + + bool mayPlace(shared_ptr item); + int getMaxStackSize(); + }; + +public: + static const int PAYMENT_SLOT = 0; + static const int INV_SLOT_START = PAYMENT_SLOT + 1; + static const int INV_SLOT_END = INV_SLOT_START + 9 * 3; + static const int USE_ROW_SLOT_START = INV_SLOT_END; + static const int USE_ROW_SLOT_END = USE_ROW_SLOT_START + 9; + +private: + shared_ptr beacon; + PaymentSlot *paymentSlot; + + // copied values because container/client system is retarded + int levels; + int primaryPower; + int secondaryPower; + +public: + BeaconMenu(shared_ptr inventory, shared_ptr beacon); + + void addSlotListener(ContainerListener *listener); + void setData(int id, int value); + shared_ptr getBeacon(); + bool stillValid(shared_ptr player); + shared_ptr quickMoveStack(shared_ptr player, int slotIndex); +}; \ No newline at end of file diff --git a/Minecraft.World/BeaconTile.cpp b/Minecraft.World/BeaconTile.cpp new file mode 100644 index 00000000..f002cbe2 --- /dev/null +++ b/Minecraft.World/BeaconTile.cpp @@ -0,0 +1,64 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "BeaconTile.h" + +BeaconTile::BeaconTile(int id) : BaseEntityTile(id, Material::glass, isSolidRender()) +{ + setDestroyTime(3.0f); +} + +shared_ptr BeaconTile::newTileEntity(Level *level) +{ + return shared_ptr( new BeaconTileEntity() ); +} + +bool BeaconTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly) +{ + if (level->isClientSide) return true; + + shared_ptr beacon = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + if (beacon != NULL) player->openBeacon(beacon); + + return true; +} + +bool BeaconTile::isSolidRender(bool isServerLevel) +{ + return false; +} + +bool BeaconTile::isCubeShaped() +{ + return false; +} + +bool BeaconTile::blocksLight() +{ + return false; +} + +int BeaconTile::getRenderShape() +{ + return SHAPE_BEACON; +} + +void BeaconTile::registerIcons(IconRegister *iconRegister) +{ + BaseEntityTile::registerIcons(iconRegister); +} + +void BeaconTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) +{ + BaseEntityTile::setPlacedBy(level, x, y, z, by, itemInstance); + if (itemInstance->hasCustomHoverName()) + { + dynamic_pointer_cast( level->getTileEntity(x, y, z))->setCustomName(itemInstance->getHoverName()); + } +} + +bool BeaconTile::TestUse() +{ + return true; +} \ No newline at end of file diff --git a/Minecraft.World/BeaconTile.h b/Minecraft.World/BeaconTile.h new file mode 100644 index 00000000..d213fa3d --- /dev/null +++ b/Minecraft.World/BeaconTile.h @@ -0,0 +1,19 @@ +#pragma once + +#include "BaseEntityTile.h" + +class BeaconTile : public BaseEntityTile +{ +public: + BeaconTile(int id); + + shared_ptr newTileEntity(Level *level); + bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); + bool isSolidRender(bool isServerLevel = false); + bool isCubeShaped(); + bool blocksLight(); + int getRenderShape(); + void registerIcons(IconRegister *iconRegister); + void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual bool TestUse(); +}; \ No newline at end of file diff --git a/Minecraft.World/BeaconTileEntity.cpp b/Minecraft.World/BeaconTileEntity.cpp new file mode 100644 index 00000000..4b9a3882 --- /dev/null +++ b/Minecraft.World/BeaconTileEntity.cpp @@ -0,0 +1,372 @@ +#include "stdafx.h" +#include "net.minecraft.network.packet.h" +#include "net.minecraft.world.effect.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" +#include "BeaconTileEntity.h" + +shared_ptr BeaconTileEntity::clone() +{ + shared_ptr result = shared_ptr( new BeaconTileEntity() ); + TileEntity::clone(result); + + result->primaryPower = primaryPower; + result->secondaryPower = secondaryPower; + result->levels = levels; + + return result; +} + +MobEffect *BeaconTileEntity::BEACON_EFFECTS[BeaconTileEntity::BEACON_EFFECTS_TIERS][BeaconTileEntity::BEACON_EFFECTS_EFFECTS]; + +void BeaconTileEntity::staticCtor() +{ + for(unsigned int tier = 0; tier < BEACON_EFFECTS_TIERS; ++tier) + { + for(unsigned int effect = 0; effect < BEACON_EFFECTS_EFFECTS; ++effect) + { + BEACON_EFFECTS[tier][effect] = NULL; + } + } + BEACON_EFFECTS[0][0] = MobEffect::movementSpeed; + BEACON_EFFECTS[0][1] = MobEffect::digSpeed; + BEACON_EFFECTS[1][0] = MobEffect::damageResistance; + BEACON_EFFECTS[1][1] = MobEffect::jump; + BEACON_EFFECTS[2][0] = MobEffect::damageBoost; + BEACON_EFFECTS[3][0] = MobEffect::regeneration; +} + +BeaconTileEntity::BeaconTileEntity() +{ + clientSideRenderTick = 0; + clientSideRenderScale = 0.0f; + + isActive = false; + levels = -1; + + primaryPower = 0; + secondaryPower = 0; + + paymentItem = nullptr; + name = L""; +} + +void BeaconTileEntity::tick() +{ + // 4J Stu - Added levels check to force an initial tick + if ( (!level->isClientSide && levels < 0) || (level->getGameTime() % (SharedConstants::TICKS_PER_SECOND * 4)) == 0) + { + updateShape(); + applyEffects(); + } + +} + +void BeaconTileEntity::applyEffects() +{ + if (isActive && levels > 0 && !level->isClientSide && primaryPower > 0) + { + + double range = (levels * 10) + 10; + int baseAmp = 0; + if (levels >= 4 && primaryPower == secondaryPower) + { + baseAmp = 1; + } + + AABB *bb = AABB::newTemp(x, y, z, x + 1, y + 1, z + 1)->grow(range, range, range); + bb->y1 = level->getMaxBuildHeight(); + vector > *players = level->getEntitiesOfClass(typeid(Player), bb); + for (AUTO_VAR(it,players->begin()); it != players->end(); ++it) + { + shared_ptr player = dynamic_pointer_cast(*it); + player->addEffect(new MobEffectInstance(primaryPower, SharedConstants::TICKS_PER_SECOND * 9, baseAmp, true)); + } + + if (levels >= 4 && primaryPower != secondaryPower && secondaryPower > 0) + { + for (AUTO_VAR(it,players->begin()); it != players->end(); ++it) + { + shared_ptr player = dynamic_pointer_cast(*it); + player->addEffect(new MobEffectInstance(secondaryPower, SharedConstants::TICKS_PER_SECOND * 9, 0, true)); + } + } + delete players; + } +} + +void BeaconTileEntity::updateShape() +{ + + if (!level->canSeeSky(x, y + 1, z)) + { + isActive = false; + levels = 0; + } + else + { + isActive = true; + + levels = 0; + for (int step = 1; step <= 4; step++) + { + + int ly = y - step; + if (ly < 0) + { + break; + } + + bool isOk = true; + for (int lx = x - step; lx <= x + step && isOk; lx++) + { + for (int lz = z - step; lz <= z + step; lz++) + { + int tile = level->getTile(lx, ly, lz); + if (tile != Tile::emeraldBlock_Id && tile != Tile::goldBlock_Id && tile != Tile::diamondBlock_Id && tile != Tile::ironBlock_Id) + { + isOk = false; + break; + } + } + } + if (isOk) + { + levels = step; + } + else + { + break; + } + } + if (levels == 0) + { + isActive = false; + } + } + +} + +float BeaconTileEntity::getAndUpdateClientSideScale() +{ + + if (!isActive) + { + return 0; + } + + int renderDelta = (int) (level->getGameTime() - clientSideRenderTick); + clientSideRenderTick = level->getGameTime(); + if (renderDelta > 1) + { + clientSideRenderScale -= ((float) renderDelta / (float) SCALE_TIME); + + if (clientSideRenderScale < 0) + { + clientSideRenderScale = 0; + } + } + clientSideRenderScale += (1.0f / (float) SCALE_TIME); + if (clientSideRenderScale > 1) + { + clientSideRenderScale = 1; + } + return clientSideRenderScale; +} + +int BeaconTileEntity::getPrimaryPower() +{ + return primaryPower; +} + +int BeaconTileEntity::getSecondaryPower() +{ + return secondaryPower; +} + +int BeaconTileEntity::getLevels() +{ + return levels; +} + +// client-side method used by GUI +void BeaconTileEntity::setLevels(int levels) +{ + this->levels = levels; +} + +void BeaconTileEntity::setPrimaryPower(int primaryPower) +{ + this->primaryPower = 0; + + // verify power + for (int tier = 0; tier < levels && tier < 3; tier++) + { + for(unsigned int e = 0; e < BEACON_EFFECTS_EFFECTS; ++e) + { + MobEffect *effect = BEACON_EFFECTS[tier][e]; + if(effect == NULL) break; + + if (effect->id == primaryPower) + { + this->primaryPower = primaryPower; + return; + } + } + } +} + +void BeaconTileEntity::setSecondaryPower(int secondaryPower) +{ + this->secondaryPower = 0; + + // verify power + if (levels >= 4) + { + for (int tier = 0; tier < 4; tier++) + { + for(unsigned int e = 0; e < BEACON_EFFECTS_EFFECTS; ++e) + { + MobEffect *effect = BEACON_EFFECTS[tier][e]; + if(effect == NULL) break; + + if (effect->id == secondaryPower) + { + this->secondaryPower = secondaryPower; + return; + } + } + } + } +} + +shared_ptr BeaconTileEntity::getUpdatePacket() +{ + CompoundTag *tag = new CompoundTag(); + save(tag); + return shared_ptr( new TileEntityDataPacket(x, y, z, TileEntityDataPacket::TYPE_BEACON, tag) ); +} + +double BeaconTileEntity::getViewDistance() +{ + return 256 * 256; +} + +void BeaconTileEntity::load(CompoundTag *tag) +{ + TileEntity::load(tag); + + primaryPower = tag->getInt(L"Primary"); + secondaryPower = tag->getInt(L"Secondary"); + levels = tag->getInt(L"Levels"); +} + +void BeaconTileEntity::save(CompoundTag *tag) +{ + TileEntity::save(tag); + + tag->putInt(L"Primary", primaryPower); + tag->putInt(L"Secondary", secondaryPower); + // this value is re-calculated, but save it anyway to avoid update lag + tag->putInt(L"Levels", levels); +} + +unsigned int BeaconTileEntity::getContainerSize() +{ + return 1; +} + +shared_ptr BeaconTileEntity::getItem(unsigned int slot) +{ + if (slot == 0) + { + return paymentItem; + } + return nullptr; +} + +shared_ptr BeaconTileEntity::removeItem(unsigned int slot, int count) +{ + if (slot == 0 && paymentItem != NULL) + { + if (count >= paymentItem->count) + { + shared_ptr returnItem = paymentItem; + paymentItem = nullptr; + return returnItem; + } + else + { + paymentItem->count -= count; + return shared_ptr( new ItemInstance(paymentItem->id, count, paymentItem->getAuxValue()) ); + } + } + return nullptr; +} + +shared_ptr BeaconTileEntity::removeItemNoUpdate(int slot) +{ + if (slot == 0 && paymentItem != NULL) + { + shared_ptr returnItem = paymentItem; + paymentItem = nullptr; + return returnItem; + } + return nullptr; +} + +void BeaconTileEntity::setItem(unsigned int slot, shared_ptr item) +{ + if (slot == 0) + { + paymentItem = item; + } +} + +wstring BeaconTileEntity::getName() +{ + return hasCustomName() ? name : app.GetString(IDS_CONTAINER_BEACON); +} + +wstring BeaconTileEntity::getCustomName() +{ + return hasCustomName() ? name : L""; +} + +bool BeaconTileEntity::hasCustomName() +{ + return !name.empty(); +} + +void BeaconTileEntity::setCustomName(const wstring &name) +{ + this->name = name; +} + +int BeaconTileEntity::getMaxStackSize() +{ + return 1; +} + +bool BeaconTileEntity::stillValid(shared_ptr player) +{ + if (level->getTileEntity(x, y, z) != shared_from_this()) return false; + if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false; + return true; +} + +void BeaconTileEntity::startOpen() +{ +} + +void BeaconTileEntity::stopOpen() +{ +} + +bool BeaconTileEntity::canPlaceItem(int slot, shared_ptr item) +{ + return (item->id == Item::emerald_Id || item->id == Item::diamond_Id || item->id == Item::goldIngot_Id || item->id == Item::ironIngot_Id); +} \ No newline at end of file diff --git a/Minecraft.World/BeaconTileEntity.h b/Minecraft.World/BeaconTileEntity.h new file mode 100644 index 00000000..1b6067a1 --- /dev/null +++ b/Minecraft.World/BeaconTileEntity.h @@ -0,0 +1,75 @@ +#pragma once +#include "TileEntity.h" +#include "Container.h" + +class BeaconTileEntity : public TileEntity, public Container +{ +public: + eINSTANCEOF GetType() { return eTYPE_BEACONTILEENTITY; } + static TileEntity *create() { return new BeaconTileEntity(); } + // 4J Added + virtual shared_ptr clone(); + +private: + static const int SCALE_TIME = SharedConstants::TICKS_PER_SECOND * 2; + +public: + static const int BEACON_EFFECTS_TIERS = 4; + static const int BEACON_EFFECTS_EFFECTS = 3; + static MobEffect *BEACON_EFFECTS[BEACON_EFFECTS_TIERS][BEACON_EFFECTS_EFFECTS]; + + static void staticCtor(); + +private: + __int64 clientSideRenderTick; + float clientSideRenderScale; + + bool isActive; + int levels; + + int primaryPower; + int secondaryPower; + + shared_ptr paymentItem; + wstring name; + +public: + BeaconTileEntity(); + + void tick(); + +private: + void applyEffects(); + void updateShape(); + +public: + float getAndUpdateClientSideScale(); + int getPrimaryPower(); + int getSecondaryPower(); + int getLevels(); + // client-side method used by GUI + void setLevels(int levels); + void setPrimaryPower(int primaryPower); + void setSecondaryPower(int secondaryPower); + shared_ptr getUpdatePacket(); + double getViewDistance(); + void load(CompoundTag *tag); + void save(CompoundTag *tag); + unsigned int getContainerSize(); + shared_ptr getItem(unsigned int slot); + shared_ptr removeItem(unsigned int slot, int count); + shared_ptr removeItemNoUpdate(int slot); + void setItem(unsigned int slot, shared_ptr item); + wstring getName(); + wstring getCustomName(); + bool hasCustomName(); + void setCustomName(const wstring &name); + int getMaxStackSize(); + bool stillValid(shared_ptr player); + void startOpen(); + void stopOpen(); + bool canPlaceItem(int slot, shared_ptr item); + + // 4J Stu - For container + virtual void setChanged() { TileEntity::setChanged(); } +}; \ No newline at end of file diff --git a/Minecraft.World/BedItem.cpp b/Minecraft.World/BedItem.cpp index 1ff50c6c..a55f277e 100644 --- a/Minecraft.World/BedItem.cpp +++ b/Minecraft.World/BedItem.cpp @@ -14,6 +14,8 @@ BedItem::BedItem(int id) : Item( id ) bool BedItem::useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { + if (level->isClientSide) return true; + if (face != Facing::UP) { return false; @@ -33,21 +35,21 @@ bool BedItem::useOn(shared_ptr itemInstance, shared_ptr pl if (dir == Direction::NORTH) zra = -1; if (dir == Direction::EAST) xra = 1; - if (!player->mayBuild(x, y, z) || !player->mayBuild(x + xra, y, z + zra)) return false; + if (!player->mayUseItemAt(x, y, z, face, itemInstance) || !player->mayUseItemAt(x + xra, y, z + zra, face, itemInstance)) return false; if (level->isEmptyTile(x, y, z) && level->isEmptyTile(x + xra, y, z + zra) && level->isTopSolidBlocking(x, y - 1, z) && level->isTopSolidBlocking(x + xra, y - 1, z + zra)) { // 4J-PB - Adding a test only version to allow tooltips to be displayed if(!bTestUseOnOnly) { - level->setTileAndData(x, y, z, tile->id, dir); + level->setTileAndData(x, y, z, tile->id, dir, Tile::UPDATE_ALL); // double-check that the bed was successfully placed if (level->getTile(x, y, z) == tile->id) { // 4J-JEV: Hook for durango 'BlockPlaced' event. player->awardStat(GenericStats::blocksPlaced(tile->id), GenericStats::param_blocksPlaced(tile->id,itemInstance->getAuxValue(),1)); - level->setTileAndData(x + xra, y, z + zra, tile->id, dir + BedTile::HEAD_PIECE_DATA); + level->setTileAndData(x + xra, y, z + zra, tile->id, dir + BedTile::HEAD_PIECE_DATA, Tile::UPDATE_ALL); } itemInstance->count--; diff --git a/Minecraft.World/BedTile.cpp b/Minecraft.World/BedTile.cpp index 7d32c6d3..2023e23f 100644 --- a/Minecraft.World/BedTile.cpp +++ b/Minecraft.World/BedTile.cpp @@ -9,7 +9,7 @@ int BedTile::HEAD_DIRECTION_OFFSETS[4][2] = { - { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } + { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } }; BedTile::BedTile(int id) : DirectionalTile(id, Material::cloth, isSolidRender()) @@ -24,7 +24,7 @@ BedTile::BedTile(int id) : DirectionalTile(id, Material::cloth, isSolidRender()) // 4J Added override void BedTile::updateDefaultShape() { - setShape(); + setShape(); } // 4J-PB - Adding a TestUse for tooltip display @@ -68,75 +68,76 @@ bool BedTile::TestUse(Level *level, int x, int y, int z, shared_ptr play bool BedTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param { if( soundOnly) return false; - if (level->isClientSide) return true; + if (level->isClientSide) return true; - int data = level->getData(x, y, z); + int data = level->getData(x, y, z); - if (!BedTile::isHeadPiece(data)) + if (!isHeadPiece(data)) { - // fetch head piece instead - int direction = getDirection(data); - x += HEAD_DIRECTION_OFFSETS[direction][0]; - z += HEAD_DIRECTION_OFFSETS[direction][1]; - if (level->getTile(x, y, z) != id) + // fetch head piece instead + int direction = getDirection(data); + x += HEAD_DIRECTION_OFFSETS[direction][0]; + z += HEAD_DIRECTION_OFFSETS[direction][1]; + if (level->getTile(x, y, z) != id) { - return true; - } - data = level->getData(x, y, z); - } + return true; + } + data = level->getData(x, y, z); + } - if (!level->dimension->mayRespawn()) + if (!level->dimension->mayRespawn() || level->getBiome(x, z) == Biome::hell) { - double xc = x + 0.5; - double yc = y + 0.5; - double zc = z + 0.5; - level->setTile(x, y, z, 0); - int direction = getDirection(data); - x += HEAD_DIRECTION_OFFSETS[direction][0]; - z += HEAD_DIRECTION_OFFSETS[direction][1]; - if (level->getTile(x, y, z) == id) { - level->setTile(x, y, z, 0); - xc = (xc + x + 0.5) / 2; - yc = (yc + y + 0.5) / 2; - zc = (zc + z + 0.5) / 2; - } - level->explode(nullptr, x + 0.5f, y + 0.5f, z + 0.5f, 5, true, true); - return true; - } - - if (BedTile::isOccupied(data)) + double xc = x + 0.5; + double yc = y + 0.5; + double zc = z + 0.5; + level->removeTile(x, y, z); + int direction = getDirection(data); + x += HEAD_DIRECTION_OFFSETS[direction][0]; + z += HEAD_DIRECTION_OFFSETS[direction][1]; + if (level->getTile(x, y, z) == id) + { + level->removeTile(x, y, z); + xc = (xc + x + 0.5) / 2; + yc = (yc + y + 0.5) / 2; + zc = (zc + z + 0.5) / 2; + } + level->explode(nullptr, x + 0.5f, y + 0.5f, z + 0.5f, 5, true, true); + return true; + } + + if (isOccupied(data)) { - shared_ptr sleepingPlayer = nullptr; + shared_ptr sleepingPlayer = nullptr; AUTO_VAR(itEnd, level->players.end()); - for (AUTO_VAR(it, level->players.begin()); it != itEnd; it++ ) + for (AUTO_VAR(it, level->players.begin()); it != itEnd; it++ ) { shared_ptr p = *it; - if (p->isSleeping()) + if (p->isSleeping()) { - Pos pos = p->bedPosition; - if (pos.x == x && pos.y == y && pos.z == z) + Pos pos = p->bedPosition; + if (pos.x == x && pos.y == y && pos.z == z) { - sleepingPlayer = p; - } - } - } + sleepingPlayer = p; + } + } + } - if (sleepingPlayer == NULL) + if (sleepingPlayer == NULL) { - BedTile::setOccupied(level, x, y, z, false); - } + setOccupied(level, x, y, z, false); + } else { player->displayClientMessage(IDS_TILE_BED_OCCUPIED ); - - return true; - } - } - Player::BedSleepingResult result = player->startSleepInBed(x, y, z); - if (result == Player::OK) + return true; + } + } + + Player::BedSleepingResult result = player->startSleepInBed(x, y, z); + if (result == Player::OK) { - BedTile::setOccupied(level, x, y, z, true); + setOccupied(level, x, y, z, true); // 4J-PB added // are there multiple players in the same world as us? if(level->AllPlayersAreSleeping()==false) @@ -144,18 +145,18 @@ bool BedTile::use(Level *level, int x, int y, int z, shared_ptr player, player->displayClientMessage(IDS_TILE_BED_PLAYERSLEEP); } return true; - } + } - if (result == Player::NOT_POSSIBLE_NOW) + if (result == Player::NOT_POSSIBLE_NOW) { player->displayClientMessage(IDS_TILE_BED_NO_SLEEP); - } + } else if (result == Player::NOT_SAFE) { - player->displayClientMessage(IDS_TILE_BED_NOTSAFE); - } + player->displayClientMessage(IDS_TILE_BED_NOTSAFE); + } - return true; + return true; } Icon *BedTile::getTexture(int face, int data) @@ -218,35 +219,35 @@ void BedTile::updateShape(LevelSource *level, int x, int y, int z, int forceData void BedTile::neighborChanged(Level *level, int x, int y, int z, int type) { - int data = level->getData(x, y, z); - int direction = getDirection(data); + int data = level->getData(x, y, z); + int direction = getDirection(data); - if (isHeadPiece(data)) + if (isHeadPiece(data)) { - if (level->getTile(x - HEAD_DIRECTION_OFFSETS[direction][0], y, z - HEAD_DIRECTION_OFFSETS[direction][1]) != id) + if (level->getTile(x - HEAD_DIRECTION_OFFSETS[direction][0], y, z - HEAD_DIRECTION_OFFSETS[direction][1]) != id) { - level->setTile(x, y, z, 0); - } - } else + level->removeTile(x, y, z); + } + } else { - if (level->getTile(x + HEAD_DIRECTION_OFFSETS[direction][0], y, z + HEAD_DIRECTION_OFFSETS[direction][1]) != id) + if (level->getTile(x + HEAD_DIRECTION_OFFSETS[direction][0], y, z + HEAD_DIRECTION_OFFSETS[direction][1]) != id) { - level->setTile(x, y, z, 0); - if (!level->isClientSide) + level->removeTile(x, y, z); + if (!level->isClientSide) { - Tile::spawnResources(level, x, y, z, data, 0); // 4J - had to add Tile:: here for C++ since this class doesn't have this overloaded method itself - } - } - } + Tile::spawnResources(level, x, y, z, data, 0); // 4J - had to add Tile:: here for C++ since this class doesn't have this overloaded method itself + } + } + } } int BedTile::getResource(int data, Random *random, int playerBonusLevel) { - if (isHeadPiece(data)) + if (isHeadPiece(data)) { - return 0; - } - return Item::bed->id; + return 0; + } + return Item::bed->id; } void BedTile::setShape() @@ -266,59 +267,59 @@ bool BedTile::isOccupied(int data) void BedTile::setOccupied(Level *level, int x, int y, int z, bool occupied) { - int data = level->getData(x, y, z); - if (occupied) + int data = level->getData(x, y, z); + if (occupied) { - data = data | OCCUPIED_DATA; - } else + data = data | OCCUPIED_DATA; + } else { - data = data & ~OCCUPIED_DATA; - } - level->setData(x, y, z, data); + data = data & ~OCCUPIED_DATA; + } + level->setData(x, y, z, data, Tile::UPDATE_NONE); } Pos *BedTile::findStandUpPosition(Level *level, int x, int y, int z, int skipCount) { - int data = level->getData(x, y, z); - int direction = DirectionalTile::getDirection(data); + int data = level->getData(x, y, z); + int direction = DirectionalTile::getDirection(data); - // try to find a clear location near the bed - for (int step = 0; step <= 1; step++) + // try to find a clear location near the bed + for (int step = 0; step <= 1; step++) { - int startX = x - BedTile::HEAD_DIRECTION_OFFSETS[direction][0] * step - 1; - int startZ = z - BedTile::HEAD_DIRECTION_OFFSETS[direction][1] * step - 1; - int endX = startX + 2; - int endZ = startZ + 2; + int startX = x - HEAD_DIRECTION_OFFSETS[direction][0] * step - 1; + int startZ = z - HEAD_DIRECTION_OFFSETS[direction][1] * step - 1; + int endX = startX + 2; + int endZ = startZ + 2; - for (int standX = startX; standX <= endX; standX++) + for (int standX = startX; standX <= endX; standX++) { - for (int standZ = startZ; standZ <= endZ; standZ++) + for (int standZ = startZ; standZ <= endZ; standZ++) { // 4J Stu - Changed to check isSolidBlockingTile rather than isEmpty for the blocks that we wish to place the player // This allows the player to spawn in blocks with snow, grass etc - if (level->isTopSolidBlocking(standX, y - 1, standZ) && - !level->isSolidBlockingTile(standX, y, standZ) && - !level->isSolidBlockingTile(standX, y + 1, standZ)) + if (level->isTopSolidBlocking(standX, y - 1, standZ) && + !level->getMaterial(standX, y, standZ)->isSolidBlocking() && + !level->getMaterial(standX, y + 1, standZ)->isSolidBlocking() ) { - if (skipCount > 0) { - skipCount--; - continue; - } - return new Pos(standX, y, standZ); - } - } - } - } - - return NULL; + if (skipCount > 0) { + skipCount--; + continue; + } + return new Pos(standX, y, standZ); + } + } + } + } + + return NULL; } void BedTile::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus) { - if (!isHeadPiece(data)) + if (!isHeadPiece(data)) { - Tile::spawnResources(level, x, y, z, data, odds, 0); - } + Tile::spawnResources(level, x, y, z, data, odds, 0); + } } int BedTile::getPistonPushReaction() @@ -329,4 +330,21 @@ int BedTile::getPistonPushReaction() int BedTile::cloneTileId(Level *level, int x, int y, int z) { return Item::bed_Id; +} + +void BedTile::playerWillDestroy(Level *level, int x, int y, int z, int data, shared_ptr player) +{ + if (player->abilities.instabuild) + { + if (isHeadPiece(data)) + { + int direction = getDirection(data); + x -= HEAD_DIRECTION_OFFSETS[direction][0]; + z -= HEAD_DIRECTION_OFFSETS[direction][1]; + if (level->getTile(x, y, z) == id) + { + level->removeTile(x, y, z); + } + } + } } \ No newline at end of file diff --git a/Minecraft.World/BedTile.h b/Minecraft.World/BedTile.h index 339080d3..0e54ba36 100644 --- a/Minecraft.World/BedTile.h +++ b/Minecraft.World/BedTile.h @@ -17,37 +17,38 @@ private: Icon **iconTop; public: - static const int HEAD_PIECE_DATA = 0x8; - static const int OCCUPIED_DATA = 0x4; + static const int HEAD_PIECE_DATA = 0x8; + static const int OCCUPIED_DATA = 0x4; - static int HEAD_DIRECTION_OFFSETS[4][2]; + static int HEAD_DIRECTION_OFFSETS[4][2]; + + BedTile(int id); - BedTile(int id); - virtual void updateDefaultShape(); virtual bool TestUse(Level *level, int x, int y, int z, shared_ptr player); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - virtual Icon *getTexture(int face, int data); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual Icon *getTexture(int face, int data); //@Override void registerIcons(IconRegister *iconRegister); - virtual int getRenderShape(); + virtual int getRenderShape(); virtual bool isCubeShaped(); virtual bool isSolidRender(bool isServerLevel = false); - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param virtual void neighborChanged(Level *level, int x, int y, int z, int type); - virtual int getResource(int data, Random *random,int playerBonusLevel); + virtual int getResource(int data, Random *random,int playerBonusLevel); private: using Tile::setShape; - void setShape(); + void setShape(); public: - static bool isHeadPiece(int data); - static bool isOccupied(int data); + static bool isHeadPiece(int data); + static bool isOccupied(int data); static void setOccupied(Level *level, int x, int y, int z, bool occupied); - static Pos *findStandUpPosition(Level *level, int x, int y, int z, int skipCount); + static Pos *findStandUpPosition(Level *level, int x, int y, int z, int skipCount); - virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); - virtual int getPistonPushReaction(); + virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); + virtual int getPistonPushReaction(); virtual int cloneTileId(Level *level, int x, int y, int z); + virtual void playerWillDestroy(Level *level, int x, int y, int z, int data, shared_ptr player); }; diff --git a/Minecraft.World/Behavior.h b/Minecraft.World/Behavior.h new file mode 100644 index 00000000..12db0e0b --- /dev/null +++ b/Minecraft.World/Behavior.h @@ -0,0 +1,5 @@ +#pragma once + +class Behavior +{ +}; \ No newline at end of file diff --git a/Minecraft.World/BehaviorRegistry.cpp b/Minecraft.World/BehaviorRegistry.cpp new file mode 100644 index 00000000..8689f129 --- /dev/null +++ b/Minecraft.World/BehaviorRegistry.cpp @@ -0,0 +1,30 @@ +#include "stdafx.h" + +#include "BehaviorRegistry.h" + +BehaviorRegistry::BehaviorRegistry(DispenseItemBehavior *defaultValue) +{ + defaultBehavior = defaultValue; +} + +BehaviorRegistry::~BehaviorRegistry() +{ + for(AUTO_VAR(it, storage.begin()); it != storage.end(); ++it) + { + delete it->second; + } + + delete defaultBehavior; +} + +DispenseItemBehavior *BehaviorRegistry::get(Item *key) +{ + AUTO_VAR(it, storage.find(key)); + + return (it == storage.end()) ? defaultBehavior : it->second; +} + +void BehaviorRegistry::add(Item *key, DispenseItemBehavior *value) +{ + storage.insert(make_pair(key, value)); +} \ No newline at end of file diff --git a/Minecraft.World/BehaviorRegistry.h b/Minecraft.World/BehaviorRegistry.h new file mode 100644 index 00000000..f882c1c4 --- /dev/null +++ b/Minecraft.World/BehaviorRegistry.h @@ -0,0 +1,17 @@ +#pragma once + +class DispenseItemBehavior; + +class BehaviorRegistry +{ +private: + unordered_map storage; + DispenseItemBehavior *defaultBehavior; + +public: + BehaviorRegistry(DispenseItemBehavior *defaultValue); + ~BehaviorRegistry(); + + DispenseItemBehavior *get(Item *key); + void add(Item *key, DispenseItemBehavior *value); +}; \ No newline at end of file diff --git a/Minecraft.World/Biome.cpp b/Minecraft.World/Biome.cpp index d2f4cd1c..169db77e 100644 --- a/Minecraft.World/Biome.cpp +++ b/Minecraft.World/Biome.cpp @@ -61,30 +61,30 @@ void Biome::staticCtor() Biome::hell = (new HellBiome(8))->setColor(0xff0000)->setName(L"Hell")->setNoRain()->setTemperatureAndDownfall(2, 0)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Hell, eMinecraftColour_Foliage_Hell, eMinecraftColour_Water_Hell,eMinecraftColour_Sky_Hell); Biome::sky = (new TheEndBiome(9))->setColor(0x8080ff)->setName(L"Sky")->setNoRain()->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Sky, eMinecraftColour_Foliage_Sky, eMinecraftColour_Water_Sky,eMinecraftColour_Sky_Sky); - + Biome::frozenOcean = (new OceanBiome(10))->setColor(0x9090a0)->setName(L"FrozenOcean")->setSnowCovered()->setDepthAndScale(-1, 0.5f)->setTemperatureAndDownfall(0, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_FrozenOcean, eMinecraftColour_Foliage_FrozenOcean, eMinecraftColour_Water_FrozenOcean,eMinecraftColour_Sky_FrozenOcean); Biome::frozenRiver = (new RiverBiome(11))->setColor(0xa0a0ff)->setName(L"FrozenRiver")->setSnowCovered()->setDepthAndScale(-0.5f, 0)->setTemperatureAndDownfall(0, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_FrozenRiver, eMinecraftColour_Foliage_FrozenRiver, eMinecraftColour_Water_FrozenRiver,eMinecraftColour_Sky_FrozenRiver); Biome::iceFlats = (new IceBiome(12))->setColor(0xffffff)->setName(L"Ice Plains")->setSnowCovered()->setTemperatureAndDownfall(0, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_IcePlains, eMinecraftColour_Foliage_IcePlains, eMinecraftColour_Water_IcePlains,eMinecraftColour_Sky_IcePlains); Biome::iceMountains = (new IceBiome(13))->setColor(0xa0a0a0)->setName(L"Ice Mountains")->setSnowCovered()->setDepthAndScale(0.3f, 1.3f)->setTemperatureAndDownfall(0, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_IceMountains, eMinecraftColour_Foliage_IceMountains, eMinecraftColour_Water_IceMountains,eMinecraftColour_Sky_IceMountains); - + Biome::mushroomIsland = (new MushroomIslandBiome(14))->setColor(0xff00ff)->setName(L"MushroomIsland")->setTemperatureAndDownfall(0.9f, 1.0f)->setDepthAndScale(0.2f, 1.0f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_MushroomIsland, eMinecraftColour_Foliage_MushroomIsland, eMinecraftColour_Water_MushroomIsland,eMinecraftColour_Sky_MushroomIsland); Biome::mushroomIslandShore = (new MushroomIslandBiome(15))->setColor(0xa000ff)->setName(L"MushroomIslandShore")->setTemperatureAndDownfall(0.9f, 1.0f)->setDepthAndScale(-1, 0.1f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_MushroomIslandShore, eMinecraftColour_Foliage_MushroomIslandShore, eMinecraftColour_Water_MushroomIslandShore,eMinecraftColour_Sky_MushroomIslandShore); Biome::beaches = (new BeachBiome(16))->setColor(0xfade55)->setName(L"Beach")->setTemperatureAndDownfall(0.8f, 0.4f)->setDepthAndScale(0.0f, 0.1f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Beach, eMinecraftColour_Foliage_Beach, eMinecraftColour_Water_Beach,eMinecraftColour_Sky_Beach); - Biome::desertHills = (new DesertBiome(17))->setColor(0xd25f12)->setName(L"DesertHills")->setNoRain()->setTemperatureAndDownfall(2, 0)->setDepthAndScale(0.3f, 0.8f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_DesertHills, eMinecraftColour_Foliage_DesertHills, eMinecraftColour_Water_DesertHills,eMinecraftColour_Sky_DesertHills); - Biome::forestHills = (new ForestBiome(18))->setColor(0x22551c)->setName(L"ForestHills")->setLeafColor(0x4EBA31)->setTemperatureAndDownfall(0.7f, 0.8f)->setDepthAndScale(0.3f, 0.7f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_ForestHills, eMinecraftColour_Foliage_ForestHills, eMinecraftColour_Water_ForestHills,eMinecraftColour_Sky_ForestHills); - Biome::taigaHills = (new TaigaBiome(19))->setColor(0x163933)->setName(L"TaigaHills")->setSnowCovered()->setLeafColor(0x4EBA31)->setTemperatureAndDownfall(0.05f, 0.8f)->setDepthAndScale(0.3f, 0.8f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_TaigaHills, eMinecraftColour_Foliage_TaigaHills, eMinecraftColour_Water_TaigaHills,eMinecraftColour_Sky_TaigaHills); - Biome::smallerExtremeHills = (new ExtremeHillsBiome(20))->setColor(0x72789a)->setName(L"Extreme Hills Edge")->setDepthAndScale(0.2f, 0.8f)->setTemperatureAndDownfall(0.2f, 0.3f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_ExtremeHillsEdge, eMinecraftColour_Foliage_ExtremeHillsEdge, eMinecraftColour_Water_ExtremeHillsEdge,eMinecraftColour_Sky_ExtremeHillsEdge); + Biome::desertHills = (new DesertBiome(17))->setColor(0xd25f12)->setName(L"DesertHills")->setNoRain()->setTemperatureAndDownfall(2, 0)->setDepthAndScale(0.3f, 0.8f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_DesertHills, eMinecraftColour_Foliage_DesertHills, eMinecraftColour_Water_DesertHills,eMinecraftColour_Sky_DesertHills); + Biome::forestHills = (new ForestBiome(18))->setColor(0x22551c)->setName(L"ForestHills")->setLeafColor(0x4EBA31)->setTemperatureAndDownfall(0.7f, 0.8f)->setDepthAndScale(0.3f, 0.7f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_ForestHills, eMinecraftColour_Foliage_ForestHills, eMinecraftColour_Water_ForestHills,eMinecraftColour_Sky_ForestHills); + Biome::taigaHills = (new TaigaBiome(19))->setColor(0x163933)->setName(L"TaigaHills")->setSnowCovered()->setLeafColor(0x4EBA31)->setTemperatureAndDownfall(0.05f, 0.8f)->setDepthAndScale(0.3f, 0.8f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_TaigaHills, eMinecraftColour_Foliage_TaigaHills, eMinecraftColour_Water_TaigaHills,eMinecraftColour_Sky_TaigaHills); + Biome::smallerExtremeHills = (new ExtremeHillsBiome(20))->setColor(0x72789a)->setName(L"Extreme Hills Edge")->setDepthAndScale(0.2f, 0.8f)->setTemperatureAndDownfall(0.2f, 0.3f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_ExtremeHillsEdge, eMinecraftColour_Foliage_ExtremeHillsEdge, eMinecraftColour_Water_ExtremeHillsEdge,eMinecraftColour_Sky_ExtremeHillsEdge); Biome::jungle = (new JungleBiome(21))->setColor(0x537b09)->setName(L"Jungle")->setLeafColor(0x537b09)->setTemperatureAndDownfall(1.2f, 0.9f)->setDepthAndScale(0.2f, 0.4f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_Jungle, eMinecraftColour_Foliage_Jungle, eMinecraftColour_Water_Jungle,eMinecraftColour_Sky_Jungle); Biome::jungleHills = (new JungleBiome(22))->setColor(0x2c4205)->setName(L"JungleHills")->setLeafColor(0x537b09)->setTemperatureAndDownfall(1.2f, 0.9f)->setDepthAndScale(1.8f, 0.5f)->setLeafFoliageWaterSkyColor(eMinecraftColour_Grass_JungleHills, eMinecraftColour_Foliage_JungleHills, eMinecraftColour_Water_JungleHills,eMinecraftColour_Sky_JungleHills); } - + Biome::Biome(int id) : id(id) { // 4J Stu Default inits color = 0; -// snowCovered = false; // 4J - this isn't set by the java game any more so removing to save confusion + // snowCovered = false; // 4J - this isn't set by the java game any more so removing to save confusion topMaterial = (byte) Tile::grass_Id; material = (byte) Tile::dirt_Id; @@ -103,9 +103,9 @@ Biome::Biome(int id) : id(id) /* 4J - removing these so that we can consistently return newly created trees via getTreeFeature, and let the calling function be resposible for deleting the returned tree normalTree = new TreeFeature(); - fancyTree = new BasicTree(); - birchTree = new BirchFeature(); - swampTree = new SwampTreeFeature(); + fancyTree = new BasicTree(); + birchTree = new BirchFeature(); + swampTree = new SwampTreeFeature(); */ biomes[id] = this; @@ -126,6 +126,8 @@ Biome::Biome(int id) : id(id) // wolves are added to forests and taigas waterFriendlies.push_back(new MobSpawnerData(eTYPE_SQUID, 10, 4, 4)); + + ambientFriendlies.push_back(new MobSpawnerData(eTYPE_BAT, 10, 8, 8)); } Biome::~Biome() @@ -150,7 +152,7 @@ Biome *Biome::setLeafFoliageWaterSkyColor(eMinecraftColour grassColor, eMinecraf Biome *Biome::setTemperatureAndDownfall(float temp, float downfall) { - this->temperature = temp; + temperature = temp; this->downfall = downfall; return this; } @@ -164,17 +166,17 @@ Biome *Biome::setDepthAndScale(float depth, float scale) Biome *Biome::setNoRain() { - _hasRain = false; - return this; + _hasRain = false; + return this; } Feature *Biome::getTreeFeature(Random *random) { - if (random->nextInt(10) == 0) + if (random->nextInt(10) == 0) { - return new BasicTree(false); // 4J used to return member fancyTree, now returning newly created object so that caller can be consistently resposible for cleanup - } - return new TreeFeature(false); // 4J used to return member normalTree, now returning newly created object so that caller can be consistently resposible for cleanup + return new BasicTree(false); // 4J used to return member fancyTree, now returning newly created object so that caller can be consistently resposible for cleanup + } + return new TreeFeature(false); // 4J used to return member normalTree, now returning newly created object so that caller can be consistently resposible for cleanup } Feature *Biome::getGrassFeature(Random *random) @@ -184,48 +186,49 @@ Feature *Biome::getGrassFeature(Random *random) Biome *Biome::setSnowCovered() { - this->snowCovered = true; - return this; + snowCovered = true; + return this; } Biome *Biome::setName(const wstring &name) { - this->m_name = name; - return this; + this->m_name = name; + return this; } Biome *Biome::setLeafColor(int leafColor) { - this->leafColor = leafColor; - return this; + this->leafColor = leafColor; + return this; } Biome *Biome::setColor(int color) { - this->color = color; - return this; + this->color = color; + return this; } int Biome::getSkyColor(float temp) { - //temp /= 3.0f; - //if (temp < -1) temp = -1; - //if (temp > 1) temp = 1; - //return Color::getHSBColor(224 / 360.0f - temp * 0.05f, 0.50f + temp * 0.1f, 1.0f).getRGB(); - + //temp /= 3.0f; + //if (temp < -1) temp = -1; + //if (temp > 1) temp = 1; + //return Color::getHSBColor(224 / 360.0f - temp * 0.05f, 0.50f + temp * 0.1f, 1.0f).getRGB(); + // 4J Stu - Load colour from texture pack return Minecraft::GetInstance()->getColourTable()->getColor( m_skyColor ); } vector *Biome::getMobs(MobCategory *category) { - if (category == MobCategory::monster) return &enemies; - if (category == MobCategory::creature) return &friendlies; - if (category == MobCategory::waterCreature) return &waterFriendlies; + if (category == MobCategory::monster) return &enemies; + if (category == MobCategory::creature) return &friendlies; + if (category == MobCategory::waterCreature) return &waterFriendlies; if (category == MobCategory::creature_chicken) return &friendlies_chicken; if (category == MobCategory::creature_wolf) return &friendlies_wolf; if (category == MobCategory::creature_mushroomcow) return &friendlies_mushroomcow; - return NULL; + if (category == MobCategory::ambient) return &ambientFriendlies; + return NULL; } bool Biome::hasSnow() @@ -235,15 +238,15 @@ bool Biome::hasSnow() if( getTemperature() >= 0.15f ) return false; - return true; + return true; } bool Biome::hasRain() { // 4J - snowCovered flag removed as it wasn't being set by the game anymore, replaced by call to hasSnow() if( hasSnow() ) return false; -// if (snowCovered) return false; - return _hasRain; + // if (snowCovered) return false; + return _hasRain; } bool Biome::isHumid() @@ -256,8 +259,8 @@ float Biome::getCreatureProbability() return 0.1f; } - int Biome::getDownfallInt() - { +int Biome::getDownfallInt() +{ return (int) (downfall * 65536); } @@ -285,19 +288,19 @@ void Biome::decorate(Level *level, Random *random, int xo, int zo) int Biome::getGrassColor() { - //double temp = Mth::clamp(getTemperature(), 0.0f, 1.0f); - //double rain = Mth::clamp(getDownfall(), 0.0f, 1.0f); + //double temp = Mth::clamp(getTemperature(), 0.0f, 1.0f); + //double rain = Mth::clamp(getDownfall(), 0.0f, 1.0f); - //return GrassColor::get(temp, rain); + //return GrassColor::get(temp, rain); return Minecraft::GetInstance()->getColourTable()->getColor( m_grassColor ); } int Biome::getFolageColor() { - //double temp = Mth::clamp(getTemperature(), 0.0f, 1.0f); - //double rain = Mth::clamp(getDownfall(), 0.0f, 1.0f); + //double temp = Mth::clamp(getTemperature(), 0.0f, 1.0f); + //double rain = Mth::clamp(getDownfall(), 0.0f, 1.0f); - //return FoliageColor::get(temp, rain); + //return FoliageColor::get(temp, rain); return Minecraft::GetInstance()->getColourTable()->getColor( m_foliageColor ); } diff --git a/Minecraft.World/Biome.h b/Minecraft.World/Biome.h index 1026bae6..f7de3166 100644 --- a/Minecraft.World/Biome.h +++ b/Minecraft.World/Biome.h @@ -51,54 +51,55 @@ public: public: wstring m_name; - int color; - byte topMaterial; - byte material; - int leafColor; - float depth; - float scale; - float temperature; - float downfall; + int color; + byte topMaterial; + byte material; + int leafColor; + float depth; + float scale; + float temperature; + float downfall; //int waterColor; // 4J Stu removed - BiomeDecorator *decorator; + BiomeDecorator *decorator; const int id; - class MobSpawnerData : public WeighedRandomItem + class MobSpawnerData : public WeighedRandomItem { public: eINSTANCEOF mobClass; int minCount; int maxCount; - MobSpawnerData(eINSTANCEOF mobClass, int probabilityWeight, int minCount, int maxCount) : WeighedRandomItem(probabilityWeight) + MobSpawnerData(eINSTANCEOF mobClass, int probabilityWeight, int minCount, int maxCount) : WeighedRandomItem(probabilityWeight) { this->mobClass = mobClass; this->minCount = minCount; this->maxCount = maxCount; - } - }; + } + }; protected: - vector enemies; - vector friendlies; - vector waterFriendlies; + vector enemies; + vector friendlies; + vector waterFriendlies; vector friendlies_chicken; vector friendlies_wolf; vector friendlies_mushroomcow; - + vector ambientFriendlies; + Biome(int id); ~Biome(); - + BiomeDecorator *createDecorator(); private: Biome *setTemperatureAndDownfall(float temp, float downfall); - Biome *setDepthAndScale(float depth, float scale); + Biome *setDepthAndScale(float depth, float scale); bool snowCovered; - bool _hasRain; + bool _hasRain; // 4J Added eMinecraftColour m_grassColor; @@ -106,47 +107,47 @@ private: eMinecraftColour m_waterColor; eMinecraftColour m_skyColor; - Biome *setNoRain(); + Biome *setNoRain(); protected: /* removing these so that we can consistently return newly created trees via getTreeFeature, and let the calling function be resposible for deleting the returned tree TreeFeature *normalTree; - BasicTree *fancyTree; - BirchFeature *birchTree; - SwampTreeFeature *swampTree; + BasicTree *fancyTree; + BirchFeature *birchTree; + SwampTreeFeature *swampTree; */ public: - virtual Feature *getTreeFeature(Random *random); + virtual Feature *getTreeFeature(Random *random); virtual Feature *getGrassFeature(Random *random); protected: Biome *setSnowCovered(); - Biome *setName(const wstring &name); - Biome *setLeafColor(int leafColor); - Biome *setColor(int color); + Biome *setName(const wstring &name); + Biome *setLeafColor(int leafColor); + Biome *setColor(int color); // 4J Added Biome *setLeafFoliageWaterSkyColor(eMinecraftColour grassColor, eMinecraftColour foliageColor, eMinecraftColour waterColour, eMinecraftColour skyColour); public: - virtual int getSkyColor(float temp); + virtual int getSkyColor(float temp); - vector *getMobs(MobCategory *category); + vector *getMobs(MobCategory *category); - virtual bool hasSnow(); - virtual bool hasRain(); + virtual bool hasSnow(); + virtual bool hasRain(); virtual bool isHumid(); - virtual float getCreatureProbability(); - virtual int getDownfallInt(); - virtual int getTemperatureInt(); + virtual float getCreatureProbability(); + virtual int getDownfallInt(); + virtual int getTemperatureInt(); virtual float getDownfall(); // 4J - brought forward from 1.2.3 virtual float getTemperature(); // 4J - brought forward from 1.2.3 - virtual void decorate(Level *level, Random *random, int xo, int zo); + virtual void decorate(Level *level, Random *random, int xo, int zo); - virtual int getGrassColor(); - virtual int getFolageColor(); + virtual int getGrassColor(); + virtual int getFolageColor(); virtual int getWaterColor(); // 4J Added }; \ No newline at end of file diff --git a/Minecraft.World/BiomeDecorator.cpp b/Minecraft.World/BiomeDecorator.cpp index 6ca7386c..a3cbf546 100644 --- a/Minecraft.World/BiomeDecorator.cpp +++ b/Minecraft.World/BiomeDecorator.cpp @@ -55,8 +55,8 @@ void BiomeDecorator::_init() lapisOreFeature = new OreFeature(Tile::lapisOre_Id, 6); yellowFlowerFeature = new FlowerFeature(Tile::flower_Id); roseFlowerFeature = new FlowerFeature(Tile::rose_Id); - brownMushroomFeature = new FlowerFeature(Tile::mushroom1_Id); - redMushroomFeature = new FlowerFeature(Tile::mushroom2_Id); + brownMushroomFeature = new FlowerFeature(Tile::mushroom_brown_Id); + redMushroomFeature = new FlowerFeature(Tile::mushroom_red_Id); hugeMushroomFeature = new HugeMushroomFeature(); reedsFeature = new ReedsFeature(); cactusFeature = new CactusFeature(); @@ -123,12 +123,12 @@ void BiomeDecorator::decorate() PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Decorate mushrooms/flowers/grass"); - for (int i = 0; i < hugeMushrooms; i++) + for (int i = 0; i < hugeMushrooms; i++) { - int x = xo + random->nextInt(16) + 8; - int z = zo + random->nextInt(16) + 8; - hugeMushroomFeature->place(level, random, x, level->getHeightmap(x, z), z); - } + int x = xo + random->nextInt(16) + 8; + int z = zo + random->nextInt(16) + 8; + hugeMushroomFeature->place(level, random, x, level->getHeightmap(x, z), z); + } for (int i = 0; i < flowerCount; i++) { @@ -176,15 +176,15 @@ void BiomeDecorator::decorate() } if(deadBushFeature != NULL)delete deadBushFeature; - for (int i = 0; i < waterlilyCount; i++) + for (int i = 0; i < waterlilyCount; i++) { - int x = xo + random->nextInt(16) + 8; - int z = zo + random->nextInt(16) + 8; - int y = random->nextInt(Level::genDepth); - while (y > 0 && level->getTile(x, y - 1, z) == 0) - y--; - waterlilyFeature->place(level, random, x, y, z); - } + int x = xo + random->nextInt(16) + 8; + int z = zo + random->nextInt(16) + 8; + int y = random->nextInt(Level::genDepth); + while (y > 0 && level->getTile(x, y - 1, z) == 0) + y--; + waterlilyFeature->place(level, random, x, y, z); + } for (int i = 0; i < mushroomCount; i++) { diff --git a/Minecraft.World/BiomeSource.cpp b/Minecraft.World/BiomeSource.cpp index b16efd31..8e2a5680 100644 --- a/Minecraft.World/BiomeSource.cpp +++ b/Minecraft.World/BiomeSource.cpp @@ -11,9 +11,9 @@ // 4J - removal of separate temperature & downfall layers brought forward from 1.2.3 void BiomeSource::_init() { - layer = nullptr; + layer = nullptr; zoomedLayer = nullptr; - + cache = new BiomeCache(this); playerSpawnBiomes.push_back(Biome::forest); @@ -39,7 +39,7 @@ void BiomeSource::_init(__int64 seed, LevelType *generator) BiomeSource::BiomeSource() { - _init(); + _init(); } // 4J added @@ -105,7 +105,7 @@ void BiomeSource::getDownfallBlock(floatArray &downfalls, int x, int z, int w, i BiomeCache::Block *BiomeSource::getBlockAt(int x, int y) { - return cache->getBlockAt(x, y); + return cache->getBlockAt(x, y); } float BiomeSource::getTemperature(int x, int y, int z) const @@ -277,6 +277,7 @@ void BiomeSource::getBiomeIndexBlock(byteArray& biomeIndices, int x, int z, int */ bool BiomeSource::containsOnly(int x, int z, int r, vector allowed) { + IntCache::releaseAll(); int x0 = ((x - r) >> 2); int z0 = ((z - r) >> 2); int x1 = ((x + r) >> 2); @@ -304,11 +305,12 @@ bool BiomeSource::containsOnly(int x, int z, int r, vector allowed) */ bool BiomeSource::containsOnly(int x, int z, int r, Biome *allowed) { + IntCache::releaseAll(); int x0 = ((x - r) >> 2); int z0 = ((z - r) >> 2); int x1 = ((x + r) >> 2); int z1 = ((z + r) >> 2); - + int w = x1 - x0; int h = z1 - z0; int biomesCount = w*h; @@ -330,6 +332,7 @@ bool BiomeSource::containsOnly(int x, int z, int r, Biome *allowed) */ TilePos *BiomeSource::findBiome(int x, int z, int r, Biome *toFind, Random *random) { + IntCache::releaseAll(); int x0 = ((x - r) >> 2); int z0 = ((z - r) >> 2); int x1 = ((x + r) >> 2); @@ -367,6 +370,7 @@ TilePos *BiomeSource::findBiome(int x, int z, int r, Biome *toFind, Random *rand */ TilePos *BiomeSource::findBiome(int x, int z, int r, vector allowed, Random *random) { + IntCache::releaseAll(); int x0 = ((x - r) >> 2); int z0 = ((z - r) >> 2); int x1 = ((x + r) >> 2); @@ -378,8 +382,7 @@ TilePos *BiomeSource::findBiome(int x, int z, int r, vector allowed, Ra intArray biomes = layer->getArea(x0, z0, w, h); TilePos *res = NULL; int found = 0; - int biomesCount = w*h; - for (unsigned int i = 0; i < biomesCount; i++) + for (unsigned int i = 0; i < w * h; i++) { int xx = (x0 + i % w) << 2; int zz = (z0 + i / w) << 2; @@ -420,7 +423,7 @@ __int64 BiomeSource::findSeed(LevelType *generator) mcprogress->progressStage(IDS_PROGRESS_NEW_WORLD_SEED); #ifndef _CONTENT_PACKAGE - if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<nextInt(3) + 5; + int treeHeight = random->nextInt(3) + 5; - bool free = true; - if (y < 1 || y + treeHeight + 1 > Level::maxBuildHeight) return false; + bool free = true; + if (y < 1 || y + treeHeight + 1 > Level::maxBuildHeight) return false; - for (int yy = y; yy <= y + 1 + treeHeight; yy++) + for (int yy = y; yy <= y + 1 + treeHeight; yy++) { - int r = 1; - if (yy == y) r = 0; - if (yy >= y + 1 + treeHeight - 2) r = 2; - for (int xx = x - r; xx <= x + r && free; xx++) + int r = 1; + if (yy == y) r = 0; + if (yy >= y + 1 + treeHeight - 2) r = 2; + for (int xx = x - r; xx <= x + r && free; xx++) { - for (int zz = z - r; zz <= z + r && free; zz++) + for (int zz = z - r; zz <= z + r && free; zz++) { - if (yy >= 0 && yy < Level::maxBuildHeight) + if (yy >= 0 && yy < Level::maxBuildHeight) { - int tt = level->getTile(xx, yy, zz); - if (tt != 0 && tt != Tile::leaves_Id) free = false; - } + int tt = level->getTile(xx, yy, zz); + if (tt != 0 && tt != Tile::leaves_Id) free = false; + } else { - free = false; - } - } - } - } + free = false; + } + } + } + } - if (!free) return false; + if (!free) return false; - int belowTile = level->getTile(x, y - 1, z); - if ((belowTile != Tile::grass_Id && belowTile != Tile::dirt_Id) || y >= Level::maxBuildHeight - treeHeight - 1) return false; + int belowTile = level->getTile(x, y - 1, z); + if ((belowTile != Tile::grass_Id && belowTile != Tile::dirt_Id) || y >= Level::maxBuildHeight - treeHeight - 1) return false; // 4J Stu Added to stop tree features generating areas previously place by game rule generation if(app.getLevelGenerationOptions() != NULL) @@ -54,28 +54,29 @@ bool BirchFeature::place(Level *level, Random *random, int x, int y, int z) } } - level->setTileNoUpdate(x, y - 1, z, Tile::dirt_Id); + placeBlock(level, x, y - 1, z, Tile::dirt_Id); - for (int yy = y - 3 + treeHeight; yy <= y + treeHeight; yy++) + for (int yy = y - 3 + treeHeight; yy <= y + treeHeight; yy++) { - int yo = yy - (y + treeHeight); - int offs = 1 - yo / 2; - for (int xx = x - offs; xx <= x + offs; xx++) + int yo = yy - (y + treeHeight); + int offs = 1 - yo / 2; + for (int xx = x - offs; xx <= x + offs; xx++) { - int xo = xx - (x); - for (int zz = z - offs; zz <= z + offs; zz++) + int xo = xx - (x); + for (int zz = z - offs; zz <= z + offs; zz++) { - int zo = zz - (z); - if (abs(xo) == offs && abs(zo) == offs && (random->nextInt(2) == 0 || yo == 0)) continue; - if (!Tile::solid[level->getTile(xx, yy, zz)]) placeBlock(level, xx, yy, zz, Tile::leaves_Id, LeafTile::BIRCH_LEAF); - } - } - } - for (int hh = 0; hh < treeHeight; hh++) + int zo = zz - (z); + if (abs(xo) == offs && abs(zo) == offs && (random->nextInt(2) == 0 || yo == 0)) continue; + int t = level->getTile(xx, yy, zz); + if (t == 0 || t == Tile::leaves_Id) placeBlock(level, xx, yy, zz, Tile::leaves_Id, LeafTile::BIRCH_LEAF); + } + } + } + for (int hh = 0; hh < treeHeight; hh++) { - int t = level->getTile(x, y + hh, z); - if (t == 0 || t == Tile::leaves_Id) placeBlock(level, x, y + hh, z, Tile::treeTrunk_Id, TreeTile::BIRCH_TRUNK); - } - return true; + int t = level->getTile(x, y + hh, z); + if (t == 0 || t == Tile::leaves_Id) placeBlock(level, x, y + hh, z, Tile::treeTrunk_Id, TreeTile::BIRCH_TRUNK); + } + return true; } \ No newline at end of file diff --git a/Minecraft.World/Blaze.cpp b/Minecraft.World/Blaze.cpp index 57726363..d87a83b2 100644 --- a/Minecraft.World/Blaze.cpp +++ b/Minecraft.World/Blaze.cpp @@ -5,6 +5,8 @@ #include "net.minecraft.world.phys.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.entity.projectile.h" #include "SharedConstants.h" #include "..\Minecraft.Client\Textures.h" @@ -18,16 +20,11 @@ Blaze::Blaze(Level *level) : Monster(level) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_BLAZE; // 4J Was "/mob/fire.png"; + registerAttributes(); + setHealth(getMaxHealth()); fireImmune = true; - attackDamage = 6; xpReward = XP_REWARD_LARGE; - // this.setSize(1.2f, 1.8f); // 4J Default inits allowedHeightOffset = 0.5f; @@ -35,9 +32,10 @@ Blaze::Blaze(Level *level) : Monster(level) attackCounter = 0; } -int Blaze::getMaxHealth() +void Blaze::registerAttributes() { - return 20; + Monster::registerAttributes(); + getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(6); } void Blaze::defineSynchedData() @@ -89,7 +87,7 @@ void Blaze::aiStep() allowedHeightOffset = .5f + (float) random->nextGaussian() * 3; } - if (getAttackTarget() != NULL && (getAttackTarget()->y + getAttackTarget()->getHeadHeight()) > (this->y + getHeadHeight() + allowedHeightOffset)) + if (getAttackTarget() != NULL && (getAttackTarget()->y + getAttackTarget()->getHeadHeight()) > (y + getHeadHeight() + allowedHeightOffset)) { yd = yd + (.3f - yd) * .3f; } diff --git a/Minecraft.World/Blaze.h b/Minecraft.World/Blaze.h index 4f60a4a4..7242e9c3 100644 --- a/Minecraft.World/Blaze.h +++ b/Minecraft.World/Blaze.h @@ -18,9 +18,9 @@ private: public: Blaze(Level *level); - virtual int getMaxHealth(); protected: + virtual void registerAttributes(); virtual void defineSynchedData(); virtual int getAmbientSound(); virtual int getHurtSound(); diff --git a/Minecraft.World/BlockRegionUpdatePacket.cpp b/Minecraft.World/BlockRegionUpdatePacket.cpp index d85321a5..bec943d8 100644 --- a/Minecraft.World/BlockRegionUpdatePacket.cpp +++ b/Minecraft.World/BlockRegionUpdatePacket.cpp @@ -11,6 +11,8 @@ #include "Dimension.h" +#define BLOCK_REGION_UPDATE_FULLCHUNK 0x01 +#define BLOCK_REGION_UPDATE_ZEROHEIGHT 0x02 // added so we can still send a byte for ys, which really needs the range 0-256 BlockRegionUpdatePacket::~BlockRegionUpdatePacket() { @@ -82,10 +84,10 @@ BlockRegionUpdatePacket::BlockRegionUpdatePacket(int x, int y, int z, int xs, in size = inputSize; } } - + void BlockRegionUpdatePacket::read(DataInputStream *dis) //throws IOException { - bIsFullChunk = dis->readBoolean(); + byte chunkFlags = dis->readByte(); x = dis->readInt(); y = dis->readShort(); z = dis->readInt(); @@ -93,6 +95,10 @@ void BlockRegionUpdatePacket::read(DataInputStream *dis) //throws IOException ys = dis->read() + 1; zs = dis->read() + 1; + bIsFullChunk = (chunkFlags & BLOCK_REGION_UPDATE_FULLCHUNK) ? true : false; + if(chunkFlags & BLOCK_REGION_UPDATE_ZEROHEIGHT) + ys = 0; + size = dis->readInt(); levelIdx = ( size >> 30 ) & 3; size &= 0x3fffffff; @@ -131,7 +137,11 @@ void BlockRegionUpdatePacket::read(DataInputStream *dis) //throws IOException void BlockRegionUpdatePacket::write(DataOutputStream *dos) // throws IOException { - dos->writeBoolean(bIsFullChunk); + byte chunkFlags = 0; + if(bIsFullChunk) chunkFlags |= BLOCK_REGION_UPDATE_FULLCHUNK; + if(ys == 0) chunkFlags |= BLOCK_REGION_UPDATE_ZEROHEIGHT; + + dos->writeByte(chunkFlags); dos->writeInt(x); dos->writeShort(y); dos->writeInt(z); diff --git a/Minecraft.World/BlockSource.h b/Minecraft.World/BlockSource.h new file mode 100644 index 00000000..ec5d5ce8 --- /dev/null +++ b/Minecraft.World/BlockSource.h @@ -0,0 +1,36 @@ +#pragma once + +#include "LocatableSource.h" + +class Tile; +class Material; +class TileEntity; + +class BlockSource : public LocatableSource +{ +public: + /** + * @return The X coordinate for the middle of the block + */ + virtual double getX() = 0; + + /** + * @return The Y coordinate for the middle of the block + */ + virtual double getY() = 0; + + /** + * @return The Z coordinate for the middle of the block + */ + virtual double getZ() = 0; + + virtual int getBlockX() = 0; + virtual int getBlockY() = 0; + virtual int getBlockZ() = 0; + + virtual Tile *getType() = 0; + virtual int getData() = 0; + virtual Material *getMaterial() = 0; + + virtual shared_ptr getEntity() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/BlockSourceImpl.cpp b/Minecraft.World/BlockSourceImpl.cpp new file mode 100644 index 00000000..d5a3c79b --- /dev/null +++ b/Minecraft.World/BlockSourceImpl.cpp @@ -0,0 +1,68 @@ +#include "stdafx.h" +#include "BlockSourceImpl.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.tile.entity.h" + +BlockSourceImpl::BlockSourceImpl(Level *world, int x, int y, int z) +{ + this->world = world; + this->x = x; + this->y = y; + this->z = z; +} + +Level *BlockSourceImpl::getWorld() +{ + return world; +} + +double BlockSourceImpl::getX() +{ + return x + 0.5; +} + +double BlockSourceImpl::getY() +{ + return y + 0.5; +} + +double BlockSourceImpl::getZ() +{ + return z + 0.5; +} + +int BlockSourceImpl::getBlockX() +{ + return x; +} + +int BlockSourceImpl::getBlockY() +{ + return y; +} + +int BlockSourceImpl::getBlockZ() +{ + return z; +} + +Tile *BlockSourceImpl::getType() +{ + return Tile::tiles[world->getTile(x, y, z)]; +} + +int BlockSourceImpl::getData() +{ + return world->getData(x, y, z); +} + +Material *BlockSourceImpl::getMaterial() +{ + return world->getMaterial(x, y, z); +} + +shared_ptr BlockSourceImpl::getEntity() +{ + return world->getTileEntity(x, y, z); +} \ No newline at end of file diff --git a/Minecraft.World/BlockSourceImpl.h b/Minecraft.World/BlockSourceImpl.h new file mode 100644 index 00000000..69decbaa --- /dev/null +++ b/Minecraft.World/BlockSourceImpl.h @@ -0,0 +1,29 @@ +#pragma once + +#include "BlockSource.h" + +class Level; + +class BlockSourceImpl : public BlockSource +{ +private: + Level *world; + int x; + int y; + int z; + +public: + BlockSourceImpl(Level *world, int x, int y, int z); + + Level *getWorld(); + double getX(); + double getY(); + double getZ(); + int getBlockX(); + int getBlockY(); + int getBlockZ(); + Tile *getType(); + int getData(); + Material *getMaterial(); + shared_ptr getEntity(); +}; \ No newline at end of file diff --git a/Minecraft.World/Boat.cpp b/Minecraft.World/Boat.cpp index 39211e44..c0c6a2cf 100644 --- a/Minecraft.World/Boat.cpp +++ b/Minecraft.World/Boat.cpp @@ -52,7 +52,7 @@ void Boat::defineSynchedData() { entityData->define(DATA_ID_HURT, 0); entityData->define(DATA_ID_HURTDIR, 1); - entityData->define(DATA_ID_DAMAGE, 0); + entityData->define(DATA_ID_DAMAGE, 0.0f); } @@ -90,8 +90,9 @@ double Boat::getRideHeight() return bbHeight * 0.0f - 0.3f; } -bool Boat::hurt(DamageSource *source, int hurtDamage) +bool Boat::hurt(DamageSource *source, float hurtDamage) { + if (isInvulnerable()) return false; if (level->isClientSide || removed) return true; // 4J-JEV: Fix for #88212, @@ -100,9 +101,10 @@ bool Boat::hurt(DamageSource *source, int hurtDamage) { shared_ptr attacker = source->getDirectEntity(); - if (dynamic_pointer_cast(attacker) != NULL && - !dynamic_pointer_cast(attacker)->isAllowedToHurtEntity( shared_from_this() )) + if ( attacker->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast(attacker)->isAllowedToHurtEntity( shared_from_this() )) + { return false; + } } setHurtDir(-getHurtDir()); @@ -117,13 +119,13 @@ bool Boat::hurt(DamageSource *source, int hurtDamage) markHurt(); // 4J Stu - Brought froward from 12w36 to fix #46611 - TU5: Gameplay: Minecarts and boat requires more hits than one to be destroyed in creative mode - shared_ptr player = dynamic_pointer_cast(source->getEntity()); - if (player != NULL && player->abilities.instabuild) setDamage(100); + // 4J-PB - Fix for XB1 #175735 - [CRASH] [Multi-Plat]: Code: Gameplay: Placing a boat on harmful surfaces causes the game to crash + bool creativePlayer = (source->getEntity() != NULL) && source->getEntity()->instanceof(eTYPE_PLAYER) && dynamic_pointer_cast(source->getEntity())->abilities.instabuild; - if (getDamage() > 20 * 2) + if (creativePlayer || getDamage() > 20 * 2) { if (rider.lock() != NULL) rider.lock()->ride( shared_from_this() ); - spawnAtLocation(Item::boat_Id, 1, 0); + if (!creativePlayer) spawnAtLocation(Item::boat_Id, 1, 0); remove(); } return true; @@ -171,9 +173,9 @@ void Boat::lerpTo(double x, double y, double z, float yRot, float xRot, int step lyr = yRot; lxr = xRot; - this->xd = lxd; - this->yd = lyd; - this->zd = lzd; + xd = lxd; + yd = lyd; + zd = lzd; } void Boat::lerpMotion(double xd, double yd, double zd) @@ -247,8 +249,8 @@ void Boat::tick() xRot += (float) ( (lxr - xRot) / lSteps ); lSteps--; - this->setPos(xt, yt, zt); - this->setRot(yRot, xRot); + setPos(xt, yt, zt); + setRot(yRot, xRot); } else { @@ -260,7 +262,7 @@ void Boat::tick() //this->setPos(xt, yt, zt); // 4J Stu - Fix for various boat bugs, ensure that we check collision on client-side movement - this->move(xd,yd,zd); + move(xd,yd,zd); if (onGround) { @@ -317,10 +319,18 @@ void Boat::tick() } - if (rider.lock() != NULL) + if ( rider.lock() != NULL && rider.lock()->instanceof(eTYPE_LIVINGENTITY) ) { - xd += rider.lock()->xd * acceleration; - zd += rider.lock()->zd * acceleration; + shared_ptr livingRider = dynamic_pointer_cast(rider.lock()); + double forward = livingRider->yya; + + if (forward > 0) + { + double riderXd = -sin(livingRider->yRot * PI / 180); + double riderZd = cos(livingRider->yRot * PI / 180); + xd += riderXd * acceleration * 0.05f; + zd += riderZd * acceleration * 0.05f; + } } double curSpeed = sqrt(xd * xd + zd * zd); @@ -355,7 +365,7 @@ void Boat::tick() if ((horizontalCollision && lastSpeed > 0.20)) { - if (!level->isClientSide) + if (!level->isClientSide && !removed) { remove(); for (int i = 0; i < 3; i++) @@ -394,7 +404,7 @@ void Boat::tick() if(level->isClientSide) return; - vector > *entities = level->getEntities(shared_from_this(), this->bb->grow(0.2f, 0, 0.2f)); + vector > *entities = level->getEntities(shared_from_this(), bb->grow(0.2f, 0, 0.2f)); if (entities != NULL && !entities->empty()) { AUTO_VAR(itEnd, entities->end()); @@ -417,16 +427,14 @@ void Boat::tick() { int yy = Mth::floor(y) + j; int tile = level->getTile(xx, yy, zz); - int data = level->getData(xx, yy, zz); if (tile == Tile::topSnow_Id) { - level->setTile(xx, yy, zz, 0); + level->removeTile(xx, yy, zz); } else if (tile == Tile::waterLily_Id) { - Tile::waterLily->spawnResources(level, xx, yy, zz, data, 0.3f, 0); - level->setTile(xx, yy, zz, 0); + level->destroyTile(xx, yy, zz, true); } } @@ -469,7 +477,7 @@ wstring Boat::getName() bool Boat::interact(shared_ptr player) { - if (rider.lock() != NULL && dynamic_pointer_cast(rider.lock())!=NULL && rider.lock() != player) return true; + if ( (rider.lock() != NULL) && rider.lock()->instanceof(eTYPE_PLAYER) && (rider.lock() != player) ) return true; if (!level->isClientSide) { // 4J HEG - Fixed issue with player not being able to dismount boat (issue #4446) @@ -478,14 +486,14 @@ bool Boat::interact(shared_ptr player) return true; } -void Boat::setDamage(int damage) +void Boat::setDamage(float damage) { entityData->set(DATA_ID_DAMAGE, damage); } -int Boat::getDamage() +float Boat::getDamage() { - return entityData->getInteger(DATA_ID_DAMAGE); + return entityData->getFloat(DATA_ID_DAMAGE); } void Boat::setHurtTime(int hurtTime) diff --git a/Minecraft.World/Boat.h b/Minecraft.World/Boat.h index 1039e8f9..7e79ef2d 100644 --- a/Minecraft.World/Boat.h +++ b/Minecraft.World/Boat.h @@ -47,7 +47,7 @@ public: Boat(Level *level, double x, double y, double z); virtual double getRideHeight(); - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); virtual void animateHurt(); virtual bool isPickable(); @@ -71,8 +71,8 @@ public: wstring getName(); virtual bool interact(shared_ptr player); - virtual void setDamage(int damage); - virtual int getDamage(); + virtual void setDamage(float damage); + virtual float getDamage(); virtual void setHurtTime(int hurtTime); virtual int getHurtTime(); virtual void setHurtDir(int hurtDir); diff --git a/Minecraft.World/BoatItem.cpp b/Minecraft.World/BoatItem.cpp index 3499bc02..d5628f09 100644 --- a/Minecraft.World/BoatItem.cpp +++ b/Minecraft.World/BoatItem.cpp @@ -9,10 +9,10 @@ BoatItem::BoatItem(int id) : Item( id ) { - this->maxStackSize = 1; + maxStackSize = 1; } -bool BoatItem::TestUse(Level *level, shared_ptr player) +bool BoatItem::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { // 4J-PB - added for tooltips to test use // 4J TODO really we should have the crosshair hitresult telling us if it hit water, and at what distance, so we don't need to do this again @@ -105,22 +105,28 @@ shared_ptr BoatItem::use(shared_ptr itemInstance, Le int yt = hr->y; int zt = hr->z; - if (!level->isClientSide) + if (level->getTile(xt, yt, zt) == Tile::topSnow_Id) yt--; + if( level->countInstanceOf(eTYPE_BOAT, true) < Level::MAX_XBOX_BOATS ) // 4J - added limit { - if (level->getTile(xt, yt, zt) == Tile::topSnow_Id) yt--; - if( level->countInstanceOf(eTYPE_BOAT, true) < Level::MAX_XBOX_BOATS ) // 4J - added limit + shared_ptr boat = shared_ptr( new Boat(level, xt + 0.5f, yt + 1.0f, zt + 0.5f) ); + boat->yRot = ((Mth::floor(player->yRot * 4.0F / 360.0F + 0.5) & 0x3) - 1) * 90; + if (!level->getCubes(boat, boat->bb->grow(-.1, -.1, -.1))->empty()) { - level->addEntity( shared_ptr( new Boat(level, xt + 0.5f, yt + 1.0f, zt + 0.5f) ) ); - if (!player->abilities.instabuild) - { - itemInstance->count--; - } + return itemInstance; } - else + if (!level->isClientSide) { - // display a message to say max boats has been hit - player->displayClientMessage(IDS_MAX_BOATS ); + level->addEntity(boat); } + if (!player->abilities.instabuild) + { + itemInstance->count--; + } + } + else + { + // display a message to say max boats has been hit + player->displayClientMessage(IDS_MAX_BOATS ); } } delete hr; diff --git a/Minecraft.World/BoatItem.h b/Minecraft.World/BoatItem.h index 81bc4e18..dc78e896 100644 --- a/Minecraft.World/BoatItem.h +++ b/Minecraft.World/BoatItem.h @@ -11,7 +11,7 @@ public: BoatItem(int id); - virtual bool TestUse(Level *level, shared_ptr player); + virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); /* diff --git a/Minecraft.World/BodyControl.cpp b/Minecraft.World/BodyControl.cpp index b74cc4dd..b39ebc45 100644 --- a/Minecraft.World/BodyControl.cpp +++ b/Minecraft.World/BodyControl.cpp @@ -5,7 +5,7 @@ const float BodyControl::maxClampAngle = 75.0f; -BodyControl::BodyControl(Mob *mob) +BodyControl::BodyControl(LivingEntity *mob) { this->mob = mob; diff --git a/Minecraft.World/BodyControl.h b/Minecraft.World/BodyControl.h index 951b2197..410f9ce9 100644 --- a/Minecraft.World/BodyControl.h +++ b/Minecraft.World/BodyControl.h @@ -5,13 +5,13 @@ class BodyControl : public Control { private: - Mob *mob; + LivingEntity *mob; static const float maxClampAngle; int timeStill; float lastHeadY; public: - BodyControl(Mob *mob); + BodyControl(LivingEntity *mob); void clientTick(); diff --git a/Minecraft.World/BonusChestFeature.cpp b/Minecraft.World/BonusChestFeature.cpp index 2d7690ee..6d083f54 100644 --- a/Minecraft.World/BonusChestFeature.cpp +++ b/Minecraft.World/BonusChestFeature.cpp @@ -37,7 +37,7 @@ bool BonusChestFeature::place(Level *level, Random *random, int x, int y, int z, y++; } - for (int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { int x2, y2, z2; @@ -45,7 +45,7 @@ bool BonusChestFeature::place(Level *level, Random *random, int x, int y, int z, { x2 = x; y2 = y - 1; // 4J - the position passed in is actually two above the top solid block, as the calling function adds 1 to getTopSolidBlock, and that actually returns the block above anyway. - // this would explain why there is a while loop above here (not used in force mode) to move the y back down again, shouldn't really be needed if 1 wasn't added to the getTopSolidBlock return value. + // this would explain why there is a while loop above here (not used in force mode) to move the y back down again, shouldn't really be needed if 1 wasn't added to the getTopSolidBlock return value. z2 = z; } else @@ -55,34 +55,34 @@ bool BonusChestFeature::place(Level *level, Random *random, int x, int y, int z, z2 = z + random->nextInt(4) - random->nextInt(4); } - if (force || ( level->isEmptyTile(x2, y2, z2) && level->isTopSolidBlocking(x2, y2 - 1, z2))) + if (force || ( level->isEmptyTile(x2, y2, z2) && level->isTopSolidBlocking(x2, y2 - 1, z2))) { - level->setTile(x2, y2, z2, Tile::chest_Id); - shared_ptr chest = dynamic_pointer_cast(level->getTileEntity(x2, y2, z2)); - if (chest != NULL) + level->setTileAndData(x2, y2, z2, Tile::chest_Id, 0, Tile::UPDATE_CLIENTS); + shared_ptr chest = dynamic_pointer_cast(level->getTileEntity(x2, y2, z2)); + if (chest != NULL) { - WeighedTreasure::addChestItems(random, treasureList, chest, numRolls); + WeighedTreasure::addChestItems(random, treasureList, chest, numRolls); chest->isBonusChest = true; // 4J added - } - if (level->isEmptyTile(x2 - 1, y2, z2) && level->isTopSolidBlocking(x2 - 1, y2 - 1, z2)) + } + if (level->isEmptyTile(x2 - 1, y2, z2) && level->isTopSolidBlocking(x2 - 1, y2 - 1, z2)) { - level->setTile(x2 - 1, y2, z2, Tile::torch_Id); - } - if (level->isEmptyTile(x2 + 1, y2, z2) && level->isTopSolidBlocking(x2 - 1, y2 - 1, z2)) + level->setTileAndData(x2 - 1, y2, z2, Tile::torch_Id, 0, Tile::UPDATE_CLIENTS); + } + if (level->isEmptyTile(x2 + 1, y2, z2) && level->isTopSolidBlocking(x2 - 1, y2 - 1, z2)) { - level->setTile(x2 + 1, y2, z2, Tile::torch_Id); - } - if (level->isEmptyTile(x2, y2, z2 - 1) && level->isTopSolidBlocking(x2 - 1, y2 - 1, z2)) + level->setTileAndData(x2 + 1, y2, z2, Tile::torch_Id, 0, Tile::UPDATE_CLIENTS); + } + if (level->isEmptyTile(x2, y2, z2 - 1) && level->isTopSolidBlocking(x2 - 1, y2 - 1, z2)) { - level->setTile(x2, y2, z2 - 1, Tile::torch_Id); - } - if (level->isEmptyTile(x2, y2, z2 + 1) && level->isTopSolidBlocking(x2 - 1, y2 - 1, z2)) + level->setTileAndData(x2, y2, z2 - 1, Tile::torch_Id, 0, Tile::UPDATE_CLIENTS); + } + if (level->isEmptyTile(x2, y2, z2 + 1) && level->isTopSolidBlocking(x2 - 1, y2 - 1, z2)) { - level->setTile(x2, y2, z2 + 1, Tile::torch_Id); - } - return true; - } - } + level->setTileAndData(x2, y2, z2 + 1, Tile::torch_Id, 0, Tile::UPDATE_CLIENTS); + } + return true; + } + } - return false; + return false; } diff --git a/Minecraft.World/BossMob.h b/Minecraft.World/BossMob.h index 50a6d3ef..bd24c46c 100644 --- a/Minecraft.World/BossMob.h +++ b/Minecraft.World/BossMob.h @@ -1,22 +1,9 @@ #pragma once -#include "Mob.h" - -class Level; -class BossMobPart; - -class BossMob : public Mob +class BossMob { -protected: - int maxHealth; - public: - BossMob(Level *level); - - virtual int getMaxHealth(); - virtual bool hurt(shared_ptr bossMobPart, DamageSource *source, int damage); - virtual bool hurt(DamageSource *source, int damage); - -protected: - virtual bool reallyHurt(DamageSource *source, int damage); + virtual float getMaxHealth() = 0; + virtual float getHealth() = 0; + virtual wstring getAName() = 0; }; \ No newline at end of file diff --git a/Minecraft.World/BottleItem.cpp b/Minecraft.World/BottleItem.cpp index 3aecafee..0f8e3c35 100644 --- a/Minecraft.World/BottleItem.cpp +++ b/Minecraft.World/BottleItem.cpp @@ -31,7 +31,7 @@ shared_ptr BottleItem::use(shared_ptr itemInstance, { return itemInstance; } - if (!player->mayBuild(xt, yt, zt)) + if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) { return itemInstance; } @@ -60,7 +60,7 @@ shared_ptr BottleItem::use(shared_ptr itemInstance, } // 4J-PB - added to allow tooltips -bool BottleItem::TestUse(Level *level, shared_ptr player) +bool BottleItem::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { HitResult *hr = getPlayerPOVHitResult(level, player, true); if (hr == NULL) return false; @@ -76,7 +76,7 @@ bool BottleItem::TestUse(Level *level, shared_ptr player) { return false; } - if (!player->mayBuild(xt, yt, zt)) + if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) { return false; } diff --git a/Minecraft.World/BottleItem.h b/Minecraft.World/BottleItem.h index a8f5bc09..95423c09 100644 --- a/Minecraft.World/BottleItem.h +++ b/Minecraft.World/BottleItem.h @@ -13,7 +13,7 @@ public: Icon *getIcon(int auxValue); virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); - virtual bool TestUse(Level *level, shared_ptr player); + virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); //@Override void registerIcons(IconRegister *iconRegister); diff --git a/Minecraft.World/BoundingBox.cpp b/Minecraft.World/BoundingBox.cpp index eb828ed0..24972bf9 100644 --- a/Minecraft.World/BoundingBox.cpp +++ b/Minecraft.World/BoundingBox.cpp @@ -14,6 +14,19 @@ BoundingBox::BoundingBox() z1 = 0; } +BoundingBox::BoundingBox(intArray sourceData) +{ + if (sourceData.length == 6) + { + x0 = sourceData[0]; + y0 = sourceData[1]; + z0 = sourceData[2]; + x1 = sourceData[3]; + y1 = sourceData[4]; + z1 = sourceData[5]; + } +} + BoundingBox *BoundingBox::getUnknownBox() { return new BoundingBox(INT_MAX, INT_MAX, INT_MAX, INT_MIN, INT_MIN, INT_MIN ); @@ -21,56 +34,56 @@ BoundingBox *BoundingBox::getUnknownBox() BoundingBox *BoundingBox::orientBox(int footX, int footY, int footZ, int offX, int offY, int offZ, int width, int height, int depth, int orientation) { - switch (orientation) + switch (orientation) { - default: - return new BoundingBox(footX + offX, footY + offY, footZ + offZ, footX + width - 1 + offX, footY + height - 1 + offY, footZ + depth - 1 + offZ); + default: + return new BoundingBox(footX + offX, footY + offY, footZ + offZ, footX + width - 1 + offX, footY + height - 1 + offY, footZ + depth - 1 + offZ); case Direction::NORTH: - // foot is at x0, y0, z1 - return new BoundingBox(footX + offX, footY + offY, footZ - depth + 1 + offZ, footX + width - 1 + offX, footY + height - 1 + offY, footZ + offZ); + // foot is at x0, y0, z1 + return new BoundingBox(footX + offX, footY + offY, footZ - depth + 1 + offZ, footX + width - 1 + offX, footY + height - 1 + offY, footZ + offZ); case Direction::SOUTH: - // foot is at x0, y0, z0 - return new BoundingBox(footX + offX, footY + offY, footZ + offZ, footX + width - 1 + offX, footY + height - 1 + offY, footZ + depth - 1 + offZ); + // foot is at x0, y0, z0 + return new BoundingBox(footX + offX, footY + offY, footZ + offZ, footX + width - 1 + offX, footY + height - 1 + offY, footZ + depth - 1 + offZ); case Direction::WEST: - // foot is at x1, y0, z0, but width and depth are flipped - return new BoundingBox(footX - depth + 1 + offZ, footY + offY, footZ + offX, footX + offZ, footY + height - 1 + offY, footZ + width - 1 + offX); + // foot is at x1, y0, z0, but width and depth are flipped + return new BoundingBox(footX - depth + 1 + offZ, footY + offY, footZ + offX, footX + offZ, footY + height - 1 + offY, footZ + width - 1 + offX); case Direction::EAST: - // foot is at x0, y0, z0, but width and depth are flipped - return new BoundingBox(footX + offZ, footY + offY, footZ + offX, footX + depth - 1 + offZ, footY + height - 1 + offY, footZ + width - 1 + offX); - } + // foot is at x0, y0, z0, but width and depth are flipped + return new BoundingBox(footX + offZ, footY + offY, footZ + offX, footX + depth - 1 + offZ, footY + height - 1 + offY, footZ + width - 1 + offX); + } } BoundingBox::BoundingBox(BoundingBox *other) { - this->x0 = other->x0; - this->y0 = other->y0; - this->z0 = other->z0; - this->x1 = other->x1; - this->y1 = other->y1; - this->z1 = other->z1; + x0 = other->x0; + y0 = other->y0; + z0 = other->z0; + x1 = other->x1; + y1 = other->y1; + z1 = other->z1; } BoundingBox::BoundingBox(int x0, int y0, int z0, int x1, int y1, int z1) { - this->x0 = x0; - this->y0 = y0; - this->z0 = z0; - this->x1 = x1; - this->y1 = y1; - this->z1 = z1; + this->x0 = x0; + this->y0 = y0; + this->z0 = z0; + this->x1 = x1; + this->y1 = y1; + this->z1 = z1; } BoundingBox::BoundingBox(int x0, int z0, int x1, int z1) { - this->x0 = x0; - this->z0 = z0; - this->x1 = x1; - this->z1 = z1; + this->x0 = x0; + this->z0 = z0; + this->x1 = x1; + this->z1 = z1; // the bounding box for this constructor is limited to world size, // excluding bedrock level - this->y0 = 1; - this->y1 = 512; + y0 = 1; + y1 = 512; } bool BoundingBox::intersects(BoundingBox *other) @@ -90,39 +103,39 @@ bool BoundingBox::intersects(int x0, int z0, int x1, int z1) void BoundingBox::expand(BoundingBox *other) { - this->x0 = Math::_min(this->x0, other->x0); - this->y0 = Math::_min(this->y0, other->y0); - this->z0 = Math::_min(this->z0, other->z0); - this->x1 = Math::_max(this->x1, other->x1); - this->y1 = Math::_max(this->y1, other->y1); - this->z1 = Math::_max(this->z1, other->z1); + x0 = Math::_min(x0, other->x0); + y0 = Math::_min(y0, other->y0); + z0 = Math::_min(z0, other->z0); + x1 = Math::_max(x1, other->x1); + y1 = Math::_max(y1, other->y1); + z1 = Math::_max(z1, other->z1); } BoundingBox *BoundingBox::getIntersection(BoundingBox *other) { - if (!intersects(other)) + if (!intersects(other)) { - return NULL; - } - BoundingBox *result = new BoundingBox(); - result->x0 = Math::_max(this->x0, other->x0); - result->y0 = Math::_max(this->y0, other->y0); - result->z0 = Math::_max(this->z0, other->z0); - result->x1 = Math::_min(this->x1, other->x1); - result->y1 = Math::_min(this->y1, other->y1); - result->z1 = Math::_min(this->z1, other->z1); + return NULL; + } + BoundingBox *result = new BoundingBox(); + result->x0 = Math::_max(x0, other->x0); + result->y0 = Math::_max(y0, other->y0); + result->z0 = Math::_max(z0, other->z0); + result->x1 = Math::_min(x1, other->x1); + result->y1 = Math::_min(y1, other->y1); + result->z1 = Math::_min(z1, other->z1); - return result; + return result; } void BoundingBox::move(int dx, int dy, int dz) { - x0 += dx; - y0 += dy; - z0 += dz; - x1 += dx; - y1 += dy; - z1 += dz; + x0 += dx; + y0 += dy; + z0 += dz; + x1 += dx; + y1 += dy; + z1 += dz; } bool BoundingBox::isInside(int x, int y, int z) @@ -163,4 +176,14 @@ int BoundingBox::getZCenter() wstring BoundingBox::toString() { return L"(" + _toString(x0) + L", " + _toString(y0) + L", " + _toString(z0) + L"; " + _toString(x1) + L", " + _toString(y1) + L", " + _toString(z1) + L")"; +} + +IntArrayTag *BoundingBox::createTag(const wstring &name) +{ + // 4J-JEV: If somebody knows a better way to do this, please tell me. + int *data = new int[6](); + data[0] = x0; data[1] = y0; data[2] = z0; + data[3] = x1; data[4] = y1; data[5] = z1; + + return new IntArrayTag( name, intArray(data,6) ); } \ No newline at end of file diff --git a/Minecraft.World/BoundingBox.h b/Minecraft.World/BoundingBox.h index 23abd66d..ac29883f 100644 --- a/Minecraft.World/BoundingBox.h +++ b/Minecraft.World/BoundingBox.h @@ -1,11 +1,14 @@ #pragma once +#include "ArrayWithLength.h" + class BoundingBox { public: int x0, y0, z0, x1, y1, z1; BoundingBox(); + BoundingBox(intArray sourceData); static BoundingBox *getUnknownBox(); static BoundingBox *orientBox(int footX, int footY, int footZ, int offX, int offY, int offZ, int width, int height, int depth, int orientation); BoundingBox(BoundingBox *other); @@ -28,4 +31,5 @@ public: int getZCenter(); wstring toString(); + IntArrayTag *createTag(const wstring &name); }; \ No newline at end of file diff --git a/Minecraft.World/BowItem.cpp b/Minecraft.World/BowItem.cpp index ed2376b0..949b71e7 100644 --- a/Minecraft.World/BowItem.cpp +++ b/Minecraft.World/BowItem.cpp @@ -46,9 +46,9 @@ void BowItem::releaseUsing(shared_ptr itemInstance, Level *level, { arrow->setOnFire(100); } - itemInstance->hurt(1, player); + itemInstance->hurtAndBreak(1, player); - level->playSound(player, eSoundType_RANDOM_BOW, 1.0f, 1 / (random->nextFloat() * 0.4f + 1.2f) + pow * 0.5f); + level->playEntitySound(player, eSoundType_RANDOM_BOW, 1.0f, 1 / (random->nextFloat() * 0.4f + 1.2f) + pow * 0.5f); if (infiniteArrows) { diff --git a/Minecraft.World/BreakDoorGoal.cpp b/Minecraft.World/BreakDoorGoal.cpp index e4581c67..f63b4eb0 100644 --- a/Minecraft.World/BreakDoorGoal.cpp +++ b/Minecraft.World/BreakDoorGoal.cpp @@ -15,6 +15,7 @@ BreakDoorGoal::BreakDoorGoal(Mob *mob) : DoorInteractGoal(mob) bool BreakDoorGoal::canUse() { if (!DoorInteractGoal::canUse()) return false; + if (!mob->level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) return false; return !doorTile->isOpen(mob->level, doorX, doorY, doorZ); } @@ -57,7 +58,7 @@ void BreakDoorGoal::tick() { if (mob->level->difficulty == Difficulty::HARD) { - mob->level->setTile(doorX, doorY, doorZ, 0); + mob->level->removeTile(doorX, doorY, doorZ); mob->level->levelEvent(LevelEvent::SOUND_ZOMBIE_DOOR_CRASH, doorX, doorY, doorZ, 0); mob->level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, doorX, doorY, doorZ, doorTile->id); } diff --git a/Minecraft.World/BreedGoal.cpp b/Minecraft.World/BreedGoal.cpp index 2145d371..ce2d8fff 100644 --- a/Minecraft.World/BreedGoal.cpp +++ b/Minecraft.World/BreedGoal.cpp @@ -4,19 +4,20 @@ #include "net.minecraft.world.entity.animal.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.phys.h" +#include "BasicTypeContainers.h" #include "BreedGoal.h" #include "ExperienceOrb.h" #include "GenericStats.h" -BreedGoal::BreedGoal(Animal *animal, float speed) +BreedGoal::BreedGoal(Animal *animal, double speedModifier) { partner = weak_ptr(); loveTime = 0; this->animal = animal; this->level = animal->level; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); } @@ -41,26 +42,28 @@ void BreedGoal::stop() void BreedGoal::tick() { animal->getLookControl()->setLookAt(partner.lock(), 10, animal->getMaxHeadXRot()); - animal->getNavigation()->moveTo(partner.lock(), speed); + animal->getNavigation()->moveTo(partner.lock(), speedModifier); ++loveTime; - if (loveTime == 20 * 3) breed(); + if (loveTime >= 20 * 3 && animal->distanceToSqr(partner.lock()) < 3*3) breed(); } shared_ptr BreedGoal::getFreePartner() { float r = 8; vector > *others = level->getEntitiesOfClass(typeid(*animal), animal->bb->grow(r, r, r)); + double dist = Double::MAX_VALUE; + shared_ptr partner = nullptr; for(AUTO_VAR(it, others->begin()); it != others->end(); ++it) { shared_ptr p = dynamic_pointer_cast(*it); - if (animal->canMate(p)) + if (animal->canMate(p) && animal->distanceToSqr(p) < dist) { - delete others; - return p; + partner = p; + dist = animal->distanceToSqr(p); } } delete others; - return nullptr; + return partner; } void BreedGoal::breed() @@ -97,7 +100,7 @@ void BreedGoal::breed() partner.lock()->setAge(5 * 60 * 20); animal->resetLove(); partner.lock()->resetLove(); - offspring->setAge(-20 * 60 * 20); + offspring->setAge(AgableMob::BABY_START_AGE); offspring->moveTo(animal->x, animal->y, animal->z, 0, 0); offspring->setDespawnProtected(); level->addEntity(offspring); diff --git a/Minecraft.World/BreedGoal.h b/Minecraft.World/BreedGoal.h index d2b47e7d..cb6b4f52 100644 --- a/Minecraft.World/BreedGoal.h +++ b/Minecraft.World/BreedGoal.h @@ -12,10 +12,10 @@ private: Level *level; weak_ptr partner; int loveTime; - float speed; + double speedModifier; public: - BreedGoal(Animal *animal, float speed); + BreedGoal(Animal *animal, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/BrewingStandMenu.cpp b/Minecraft.World/BrewingStandMenu.cpp index af1fac5c..55eb953f 100644 --- a/Minecraft.World/BrewingStandMenu.cpp +++ b/Minecraft.World/BrewingStandMenu.cpp @@ -41,7 +41,7 @@ void BrewingStandMenu::broadcastChanges() AbstractContainerMenu::broadcastChanges(); //for (int i = 0; i < containerListeners->size(); i++) - for(AUTO_VAR(it, containerListeners->begin()); it != containerListeners->end(); ++it) + for(AUTO_VAR(it, containerListeners.begin()); it != containerListeners.end(); ++it) { ContainerListener *listener = *it; //containerListeners.at(i); if (tc != brewingStand->getBrewTime()) @@ -65,11 +65,11 @@ bool BrewingStandMenu::stillValid(shared_ptr player) shared_ptr BrewingStandMenu::quickMoveStack(shared_ptr player, int slotIndex) { shared_ptr clicked = nullptr; - Slot *slot = slots->at(slotIndex); - Slot *IngredientSlot = slots->at(INGREDIENT_SLOT); - Slot *PotionSlot1 = slots->at(BOTTLE_SLOT_START); - Slot *PotionSlot2 = slots->at(BOTTLE_SLOT_START+1); - Slot *PotionSlot3 = slots->at(BOTTLE_SLOT_START+2); + Slot *slot = slots.at(slotIndex); + Slot *IngredientSlot = slots.at(INGREDIENT_SLOT); + Slot *PotionSlot1 = slots.at(BOTTLE_SLOT_START); + Slot *PotionSlot2 = slots.at(BOTTLE_SLOT_START+1); + Slot *PotionSlot3 = slots.at(BOTTLE_SLOT_START+2); if (slot != NULL && slot->hasItem()) { @@ -101,7 +101,7 @@ shared_ptr BrewingStandMenu::quickMoveStack(shared_ptr pla else if (slotIndex >= INV_SLOT_START && slotIndex < INV_SLOT_END) { // 4J-PB - if the item is an ingredient, quickmove it into the ingredient slot - if( (Item::items[stack->id]->hasPotionBrewingFormula() || (stack->id == Item::netherStalkSeeds_Id) ) && + if( (Item::items[stack->id]->hasPotionBrewingFormula() || (stack->id == Item::netherwart_seeds_Id) ) && (!IngredientSlot->hasItem() || (stack->id==IngredientSlot->getItem()->id) ) ) { if(!moveItemStackTo(stack, INGREDIENT_SLOT, INGREDIENT_SLOT+1, false)) @@ -125,7 +125,7 @@ shared_ptr BrewingStandMenu::quickMoveStack(shared_ptr pla else if (slotIndex >= USE_ROW_SLOT_START && slotIndex < USE_ROW_SLOT_END) { // 4J-PB - if the item is an ingredient, quickmove it into the ingredient slot - if((Item::items[stack->id]->hasPotionBrewingFormula() || (stack->id == Item::netherStalkSeeds_Id)) && + if((Item::items[stack->id]->hasPotionBrewingFormula() || (stack->id == Item::netherwart_seeds_Id)) && (!IngredientSlot->hasItem() || (stack->id==IngredientSlot->getItem()->id) )) { if(!moveItemStackTo(stack, INGREDIENT_SLOT, INGREDIENT_SLOT+1, false)) @@ -190,9 +190,7 @@ int BrewingStandMenu::PotionSlot::getMaxStackSize() void BrewingStandMenu::PotionSlot::onTake(shared_ptr player, shared_ptr carried) { - carried->onCraftedBy(this->player->level, dynamic_pointer_cast( this->player->shared_from_this() ), 1); - if (carried->id == Item::potion_Id && carried->getAuxValue() > 0) - this->player->awardStat(GenericStats::potion(),GenericStats::param_potion()); + if (carried->id == Item::potion_Id && carried->getAuxValue() > 0) this->player->awardStat(GenericStats::potion(),GenericStats::param_potion()); Slot::onTake(player, carried); } @@ -222,7 +220,7 @@ bool BrewingStandMenu::IngredientsSlot::mayPlace(shared_ptr item) } else { - return Item::items[item->id]->hasPotionBrewingFormula() || item->id == Item::netherStalkSeeds_Id || item->id == Item::bucket_water_Id; + return Item::items[item->id]->hasPotionBrewingFormula() || item->id == Item::netherwart_seeds_Id || item->id == Item::bucket_water_Id; } } return false; diff --git a/Minecraft.World/BrewingStandTile.cpp b/Minecraft.World/BrewingStandTile.cpp index 5f09ba02..1aeb52d8 100644 --- a/Minecraft.World/BrewingStandTile.cpp +++ b/Minecraft.World/BrewingStandTile.cpp @@ -5,10 +5,9 @@ #include "net.minecraft.world.item.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.h" +#include "net.minecraft.world.inventory.h" -const wstring BrewingStandTile::TEXTURE_BASE = L"brewingStand_base"; - -BrewingStandTile::BrewingStandTile(int id) : EntityTile(id, Material::metal, isSolidRender()) +BrewingStandTile::BrewingStandTile(int id) : BaseEntityTile(id, Material::metal, isSolidRender()) { random = new Random(); iconBase = NULL; @@ -41,10 +40,10 @@ bool BrewingStandTile::isCubeShaped() void BrewingStandTile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source) { - setShape(7.0f / 16.0f, 0, 7.0f / 16.0f, 9.0f / 16.0f, 14.0f / 16.0f, 9.0f / 16.0f); - EntityTile::addAABBs(level, x, y, z, box, boxes, source); - updateDefaultShape(); - EntityTile::addAABBs(level, x, y, z, box, boxes, source); + setShape(7.0f / 16.0f, 0, 7.0f / 16.0f, 9.0f / 16.0f, 14.0f / 16.0f, 9.0f / 16.0f); + BaseEntityTile::addAABBs(level, x, y, z, box, boxes, source); + updateDefaultShape(); + BaseEntityTile::addAABBs(level, x, y, z, box, boxes, source); } void BrewingStandTile::updateDefaultShape() @@ -56,62 +55,70 @@ bool BrewingStandTile::use(Level *level, int x, int y, int z, shared_ptr { if(soundOnly) return false; - if (level->isClientSide) + if (level->isClientSide) { - return true; - } - shared_ptr brewingStand = dynamic_pointer_cast(level->getTileEntity(x, y, z)); - if (brewingStand != NULL) player->openBrewingStand(brewingStand); + return true; + } + shared_ptr brewingStand = dynamic_pointer_cast(level->getTileEntity(x, y, z)); + if (brewingStand != NULL) player->openBrewingStand(brewingStand); return true; } +void BrewingStandTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) +{ + if (itemInstance->hasCustomHoverName()) + { + dynamic_pointer_cast( level->getTileEntity(x, y, z))->setCustomName(itemInstance->getHoverName()); + } +} + void BrewingStandTile::animateTick(Level *level, int xt, int yt, int zt, Random *random) { - double x = xt + 0.4f + random->nextFloat() * 0.2f; - double y = yt + 0.7f + random->nextFloat() * 0.3f; - double z = zt + 0.4f + random->nextFloat() * 0.2f; + double x = xt + 0.4f + random->nextFloat() * 0.2f; + double y = yt + 0.7f + random->nextFloat() * 0.3f; + double z = zt + 0.4f + random->nextFloat() * 0.2f; - level->addParticle(eParticleType_smoke, x, y, z, 0, 0, 0); + level->addParticle(eParticleType_smoke, x, y, z, 0, 0, 0); } void BrewingStandTile::onRemove(Level *level, int x, int y, int z, int id, int data) { - shared_ptr tileEntity = level->getTileEntity(x, y, z); - if (tileEntity != NULL && ( dynamic_pointer_cast(tileEntity) != NULL) ) + shared_ptr tileEntity = level->getTileEntity(x, y, z); + if (tileEntity != NULL && ( dynamic_pointer_cast(tileEntity) != NULL) ) { - shared_ptr container = dynamic_pointer_cast(tileEntity); - for (int i = 0; i < container->getContainerSize(); i++) + shared_ptr container = dynamic_pointer_cast(tileEntity); + for (int i = 0; i < container->getContainerSize(); i++) { - shared_ptr item = container->getItem(i); - if (item != NULL) + shared_ptr item = container->getItem(i); + if (item != NULL) { - float xo = random->nextFloat() * 0.8f + 0.1f; - float yo = random->nextFloat() * 0.8f + 0.1f; - float zo = random->nextFloat() * 0.8f + 0.1f; + float xo = random->nextFloat() * 0.8f + 0.1f; + float yo = random->nextFloat() * 0.8f + 0.1f; + float zo = random->nextFloat() * 0.8f + 0.1f; - while (item->count > 0) + while (item->count > 0) { - int count = random->nextInt(21) + 10; - if (count > item->count) count = item->count; - item->count -= count; - - shared_ptr itemEntity = shared_ptr(new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr( new ItemInstance(item->id, count, item->getAuxValue())))); - float pow = 0.05f; - itemEntity->xd = (float) random->nextGaussian() * pow; - itemEntity->yd = (float) random->nextGaussian() * pow + 0.2f; - itemEntity->zd = (float) random->nextGaussian() * pow; - if (item->hasTag()) + int count = random->nextInt(21) + 10; + if (count > item->count) count = item->count; + item->count -= count; + + shared_ptr itemEntity = shared_ptr(new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr( new ItemInstance(item->id, count, item->getAuxValue())))); + float pow = 0.05f; + itemEntity->xd = (float) random->nextGaussian() * pow; + itemEntity->yd = (float) random->nextGaussian() * pow + 0.2f; + itemEntity->zd = (float) random->nextGaussian() * pow; + if (item->hasTag()) { - itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); - } - level->addEntity(itemEntity); - } - } - } - } - EntityTile::onRemove(level, x, y, z, id, data); + itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); + } + level->addEntity(itemEntity); + } + } + } + } + BaseEntityTile::onRemove(level, x, y, z, id, data); } int BrewingStandTile::getResource(int data, Random *random, int playerBonusLevel) @@ -124,10 +131,20 @@ int BrewingStandTile::cloneTileId(Level *level, int x, int y, int z) return Item::brewingStand_Id; } +bool BrewingStandTile::hasAnalogOutputSignal() +{ + return true; +} + +int BrewingStandTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + return AbstractContainerMenu::getRedstoneSignalFromContainer(dynamic_pointer_cast(level->getTileEntity(x, y, z))); +} + void BrewingStandTile::registerIcons(IconRegister *iconRegister) { - EntityTile::registerIcons(iconRegister); - iconBase = iconRegister->registerIcon(TEXTURE_BASE); + BaseEntityTile::registerIcons(iconRegister); + iconBase = iconRegister->registerIcon(getIconName() + L"_base"); } Icon *BrewingStandTile::getBaseTexture() diff --git a/Minecraft.World/BrewingStandTile.h b/Minecraft.World/BrewingStandTile.h index fc8ff462..bb1fed99 100644 --- a/Minecraft.World/BrewingStandTile.h +++ b/Minecraft.World/BrewingStandTile.h @@ -1,14 +1,12 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" class IconRegister; class ChunkRebuildData; -class BrewingStandTile : public EntityTile +class BrewingStandTile : public BaseEntityTile { friend ChunkRebuildData; -public: - static const wstring TEXTURE_BASE; private: Random *random; Icon *iconBase; @@ -16,17 +14,20 @@ private: public: BrewingStandTile(int id); ~BrewingStandTile(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual int getRenderShape(); - virtual shared_ptr newTileEntity(Level *level); - virtual bool isCubeShaped(); - virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); - virtual void updateDefaultShape(); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - virtual void animateTick(Level *level, int xt, int yt, int zt, Random *random); - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); - virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual bool isSolidRender(bool isServerLevel = false); + virtual int getRenderShape(); + virtual shared_ptr newTileEntity(Level *level); + virtual bool isCubeShaped(); + virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); + virtual void updateDefaultShape(); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual void animateTick(Level *level, int xt, int yt, int zt, Random *random); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual int getResource(int data, Random *random, int playerBonusLevel); virtual int cloneTileId(Level *level, int x, int y, int z); - void registerIcons(IconRegister *iconRegister); - Icon *getBaseTexture(); + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); + virtual void registerIcons(IconRegister *iconRegister); + virtual Icon *getBaseTexture(); }; \ No newline at end of file diff --git a/Minecraft.World/BrewingStandTileEntity.cpp b/Minecraft.World/BrewingStandTileEntity.cpp index 20cb3737..00170d7b 100644 --- a/Minecraft.World/BrewingStandTileEntity.cpp +++ b/Minecraft.World/BrewingStandTileEntity.cpp @@ -2,16 +2,22 @@ #include "com.mojang.nbt.h" #include "BrewingStandTileEntity.h" #include "SharedConstants.h" +#include "net.minecraft.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.item.alchemy.h" +int slotsForUp [] = { BrewingStandTileEntity::INGREDIENT_SLOT }; +int slotsForOtherFaces [] = { 0, 1, 2 }; +intArray BrewingStandTileEntity::SLOTS_FOR_UP = intArray(slotsForUp, 1); +intArray BrewingStandTileEntity::SLOTS_FOR_OTHER_FACES = intArray(slotsForOtherFaces, 3); BrewingStandTileEntity::BrewingStandTileEntity() { brewTime = 0; items = ItemInstanceArray(4); + name = L""; } BrewingStandTileEntity::~BrewingStandTileEntity() @@ -19,9 +25,24 @@ BrewingStandTileEntity::~BrewingStandTileEntity() delete [] items.data; } -int BrewingStandTileEntity::getName() +wstring BrewingStandTileEntity::getName() { - return IDS_TILE_BREWINGSTAND; + return hasCustomName() ? name : app.GetString(IDS_TILE_BREWINGSTAND); +} + +wstring BrewingStandTileEntity::getCustomName() +{ + return hasCustomName() ? name : L""; +} + +bool BrewingStandTileEntity::hasCustomName() +{ + return !name.empty(); +} + +void BrewingStandTileEntity::setCustomName(const wstring &name) +{ + this->name = name; } unsigned int BrewingStandTileEntity::getContainerSize() @@ -31,41 +52,41 @@ unsigned int BrewingStandTileEntity::getContainerSize() void BrewingStandTileEntity::tick() { - if (brewTime > 0) + if (brewTime > 0) { - brewTime--; + brewTime--; - if (brewTime == 0) + if (brewTime == 0) { - // apply ingredients to all potions - doBrew(); - setChanged(); - } + // apply ingredients to all potions + doBrew(); + setChanged(); + } else if (!isBrewable()) { - brewTime = 0; - setChanged(); - } + brewTime = 0; + setChanged(); + } else if (ingredientId != items[INGREDIENT_SLOT]->id) { - brewTime = 0; - setChanged(); - } - } + brewTime = 0; + setChanged(); + } + } else if (isBrewable()) { - brewTime = SharedConstants::TICKS_PER_SECOND * PotionBrewing::BREWING_TIME_SECONDS; - ingredientId = items[INGREDIENT_SLOT]->id; - } + brewTime = SharedConstants::TICKS_PER_SECOND * PotionBrewing::BREWING_TIME_SECONDS; + ingredientId = items[INGREDIENT_SLOT]->id; + } - int newCount = getPotionBits(); - if (newCount != lastPotionCount) + int newCount = getPotionBits(); + if (newCount != lastPotionCount) { - lastPotionCount = newCount; - level->setData(x, y, z, newCount); - } + lastPotionCount = newCount; + level->setData(x, y, z, newCount, Tile::UPDATE_CLIENTS); + } - TileEntity::tick(); + TileEntity::tick(); } int BrewingStandTileEntity::getBrewTime() @@ -75,34 +96,34 @@ int BrewingStandTileEntity::getBrewTime() bool BrewingStandTileEntity::isBrewable() { - if (items[INGREDIENT_SLOT] == NULL || items[INGREDIENT_SLOT]->count <= 0) + if (items[INGREDIENT_SLOT] == NULL || items[INGREDIENT_SLOT]->count <= 0) { - return false; - } - shared_ptr ingredient = items[INGREDIENT_SLOT]; - if (PotionBrewing::SIMPLIFIED_BREWING) + return false; + } + shared_ptr ingredient = items[INGREDIENT_SLOT]; + if (PotionBrewing::SIMPLIFIED_BREWING) { - if (!Item::items[ingredient->id]->hasPotionBrewingFormula()) + if (!Item::items[ingredient->id]->hasPotionBrewingFormula()) { - return false; - } + return false; + } - bool oneResult = false; - for (int dest = 0; dest < 3; dest++) + bool oneResult = false; + for (int dest = 0; dest < 3; dest++) { - if (items[dest] != NULL && items[dest]->id == Item::potion_Id) + if (items[dest] != NULL && items[dest]->id == Item::potion_Id) { - int currentBrew = items[dest]->getAuxValue(); - int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) ); + int currentBrew = items[dest]->getAuxValue(); + int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) ); - if (!PotionItem::isThrowable(currentBrew) && PotionItem::isThrowable(newBrew)) + if (!PotionItem::isThrowable(currentBrew) && PotionItem::isThrowable(newBrew)) { - oneResult = true; - break; - } + oneResult = true; + break; + } - vector *currentEffects = Item::potion->getMobEffects(currentBrew); - vector *newEffects = Item::potion->getMobEffects(newBrew); + vector *currentEffects = Item::potion->getMobEffects(currentBrew); + vector *newEffects = Item::potion->getMobEffects(newBrew); // 4J - this code replaces an expression "currentEffects.equals(newEffects)" in the java. // TODO - find out whether actually checking pointers to MobEffectInstance classes for equality @@ -119,72 +140,72 @@ bool BrewingStandTileEntity::isBrewable() } } - if ((currentBrew > 0 && currentEffects == newEffects) || + if ((currentBrew > 0 && currentEffects == newEffects) || (currentEffects != NULL && (equals || newEffects == NULL))) { - } + } else if (currentBrew != newBrew) { - oneResult = true; - break; - } - } - } - return oneResult; - - } + oneResult = true; + break; + } + } + } + return oneResult; + + } else { - if (!Item::items[ingredient->id]->hasPotionBrewingFormula() && ingredient->id != Item::bucket_water_Id && ingredient->id != Item::netherStalkSeeds_Id) + if (!Item::items[ingredient->id]->hasPotionBrewingFormula() && ingredient->id != Item::bucket_water_Id && ingredient->id != Item::netherwart_seeds_Id) { - return false; - } - bool isWater = ingredient->id == Item::bucket_water_Id; + return false; + } + bool isWater = ingredient->id == Item::bucket_water_Id; - // at least one destination potion must have a result - bool oneResult = false; - for (int dest = 0; dest < 3; dest++) + // at least one destination potion must have a result + bool oneResult = false; + for (int dest = 0; dest < 3; dest++) { - if (items[dest] != NULL && items[dest]->id == Item::potion_Id) + if (items[dest] != NULL && items[dest]->id == Item::potion_Id) { - int currentBrew = items[dest]->getAuxValue(); - int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) ); - if (currentBrew != newBrew) + int currentBrew = items[dest]->getAuxValue(); + int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) ); + if (currentBrew != newBrew) { - oneResult = true; - break; - } - } + oneResult = true; + break; + } + } else if (isWater && items[dest] != NULL && items[dest]->id == Item::glassBottle_Id) { - oneResult = true; - break; - } - } - return oneResult; - } + oneResult = true; + break; + } + } + return oneResult; + } } void BrewingStandTileEntity::doBrew() { - if (!isBrewable()) + if (!isBrewable()) { - return; - } + return; + } - shared_ptr ingredient = items[INGREDIENT_SLOT]; + shared_ptr ingredient = items[INGREDIENT_SLOT]; - if (PotionBrewing::SIMPLIFIED_BREWING) + if (PotionBrewing::SIMPLIFIED_BREWING) { - for (int dest = 0; dest < 3; dest++) + for (int dest = 0; dest < 3; dest++) { - if (items[dest] != NULL && items[dest]->id == Item::potion_Id) + if (items[dest] != NULL && items[dest]->id == Item::potion_Id) { - int currentBrew = items[dest]->getAuxValue(); - int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) ); + int currentBrew = items[dest]->getAuxValue(); + int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) ); - vector *currentEffects = Item::potion->getMobEffects(currentBrew); - vector *newEffects = Item::potion->getMobEffects(newBrew); + vector *currentEffects = Item::potion->getMobEffects(currentBrew); + vector *newEffects = Item::potion->getMobEffects(newBrew); // 4J - this code replaces an expression "currentEffects.equals(newEffects)" in the java. // TODO - find out whether actually checking pointers to MobEffectInstance classes for equality @@ -201,55 +222,55 @@ void BrewingStandTileEntity::doBrew() } } - if ((currentBrew > 0 && currentEffects == newEffects) || + if ((currentBrew > 0 && currentEffects == newEffects) || (currentEffects != NULL && (equals || newEffects == NULL))) { - if (!PotionItem::isThrowable(currentBrew) && PotionItem::isThrowable(newBrew)) + if (!PotionItem::isThrowable(currentBrew) && PotionItem::isThrowable(newBrew)) { - items[dest]->setAuxValue(newBrew); - } + items[dest]->setAuxValue(newBrew); + } - } + } else if (currentBrew != newBrew) { - items[dest]->setAuxValue(newBrew); - } + items[dest]->setAuxValue(newBrew); + } - } - } + } + } - } + } else { - bool isWater = ingredient->id == Item::bucket_water_Id; + bool isWater = ingredient->id == Item::bucket_water_Id; - for (int dest = 0; dest < 3; dest++) + for (int dest = 0; dest < 3; dest++) { - if (items[dest] != NULL && items[dest]->id == Item::potion_Id) + if (items[dest] != NULL && items[dest]->id == Item::potion_Id) { - int currentBrew = items[dest]->getAuxValue(); - int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) ); - items[dest]->setAuxValue(newBrew); - } + int currentBrew = items[dest]->getAuxValue(); + int newBrew = NORMALISE_POTION_AUXVAL( applyIngredient(currentBrew, ingredient) ); + items[dest]->setAuxValue(newBrew); + } else if (isWater && items[dest] != NULL && items[dest]->id == Item::glassBottle_Id) { - items[dest] = shared_ptr(new ItemInstance(Item::potion)); - } - } - } + items[dest] = shared_ptr(new ItemInstance(Item::potion)); + } + } + } - if (Item::items[ingredient->id]->hasCraftingRemainingItem()) + if (Item::items[ingredient->id]->hasCraftingRemainingItem()) { - items[INGREDIENT_SLOT] = shared_ptr(new ItemInstance(Item::items[ingredient->id]->getCraftingRemainingItem())); - } + items[INGREDIENT_SLOT] = shared_ptr(new ItemInstance(Item::items[ingredient->id]->getCraftingRemainingItem())); + } else { - items[INGREDIENT_SLOT]->count--; - if (items[INGREDIENT_SLOT]->count <= 0) + items[INGREDIENT_SLOT]->count--; + if (items[INGREDIENT_SLOT]->count <= 0) { - items[INGREDIENT_SLOT] = nullptr; - } - } + items[INGREDIENT_SLOT] = nullptr; + } + } } int BrewingStandTileEntity::applyIngredient(int currentBrew, shared_ptr ingredient) @@ -266,7 +287,7 @@ int BrewingStandTileEntity::applyIngredient(int currentBrew, shared_ptrid == Item::netherStalkSeeds_Id) + if (ingredient->id == Item::netherwart_seeds_Id) { return PotionBrewing::stirr(currentBrew); } @@ -278,42 +299,44 @@ int BrewingStandTileEntity::applyIngredient(int currentBrew, shared_ptr *inventoryList = (ListTag *) base->getList(L"Items"); + ListTag *inventoryList = (ListTag *) base->getList(L"Items"); delete [] items.data; - items = ItemInstanceArray(getContainerSize()); - for (int i = 0; i < inventoryList->size(); i++) + items = ItemInstanceArray(getContainerSize()); + for (int i = 0; i < inventoryList->size(); i++) { - CompoundTag *tag = inventoryList->get(i); - int slot = tag->getByte(L"Slot"); - if (slot >= 0 && slot < items.length) items[slot] = ItemInstance::fromTag(tag); - } + CompoundTag *tag = inventoryList->get(i); + int slot = tag->getByte(L"Slot"); + if (slot >= 0 && slot < items.length) items[slot] = ItemInstance::fromTag(tag); + } - brewTime = base->getShort(L"BrewTime"); + brewTime = base->getShort(L"BrewTime"); + if (base->contains(L"CustomName")) name = base->getString(L"CustomName"); } void BrewingStandTileEntity::save(CompoundTag *base) { - TileEntity::save(base); + TileEntity::save(base); - base->putShort(L"BrewTime", (short) (brewTime)); - ListTag *listTag = new ListTag(); + base->putShort(L"BrewTime", (short) (brewTime)); + ListTag *listTag = new ListTag(); - for (int i = 0; i < items.length; i++) + for (int i = 0; i < items.length; i++) { - if (items[i] != NULL) + if (items[i] != NULL) { - CompoundTag *tag = new CompoundTag(); - tag->putByte(L"Slot", (byte) i); - items[i]->save(tag); - listTag->add(tag); - } - } - base->put(L"Items", listTag); + CompoundTag *tag = new CompoundTag(); + tag->putByte(L"Slot", (byte) i); + items[i]->save(tag); + listTag->add(tag); + } + } + base->put(L"Items", listTag); + if (hasCustomName()) base->putString(L"CustomName", name); } shared_ptr BrewingStandTileEntity::getItem(unsigned int slot) @@ -354,7 +377,7 @@ shared_ptr BrewingStandTileEntity::removeItem(unsigned int slot, i } return nullptr; } - + shared_ptr BrewingStandTileEntity::removeItemNoUpdate(int slot) { if (slot >= 0 && slot < items.length) @@ -368,22 +391,23 @@ shared_ptr BrewingStandTileEntity::removeItemNoUpdate(int slot) void BrewingStandTileEntity::setItem(unsigned int slot, shared_ptr item) { - if (slot >= 0 && slot < items.length) + if (slot >= 0 && slot < items.length) { - items[slot] = item; - } + items[slot] = item; + } } int BrewingStandTileEntity::getMaxStackSize() { - return 1; + // this value is not used for the potion slots + return 64; } bool BrewingStandTileEntity::stillValid(shared_ptr player) { - if (level->getTileEntity(x, y, z) != shared_from_this()) return false; - if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false; - return true; + if (level->getTileEntity(x, y, z) != shared_from_this()) return false; + if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false; + return true; } void BrewingStandTileEntity::startOpen() @@ -394,22 +418,59 @@ void BrewingStandTileEntity::stopOpen() { } +bool BrewingStandTileEntity::canPlaceItem(int slot, shared_ptr item) +{ + if (slot == INGREDIENT_SLOT) + { + if (PotionBrewing::SIMPLIFIED_BREWING) + { + return Item::items[item->id]->hasPotionBrewingFormula(); + } + else + { + return Item::items[item->id]->hasPotionBrewingFormula() || item->id == Item::netherwart_seeds_Id || item->id == Item::bucket_water_Id; + } + } + + return item->id == Item::potion_Id || item->id == Item::glassBottle_Id; +} + void BrewingStandTileEntity::setBrewTime(int value) { - this->brewTime = value; + brewTime = value; } int BrewingStandTileEntity::getPotionBits() { - int newCount = 0; - for (int potion = 0; potion < 3; potion++) + int newCount = 0; + for (int potion = 0; potion < 3; potion++) { - if (items[potion] != NULL) + if (items[potion] != NULL) { - newCount |= (1 << potion); - } - } - return newCount; + newCount |= (1 << potion); + } + } + return newCount; +} + +intArray BrewingStandTileEntity::getSlotsForFace(int face) +{ + if (face == Facing::UP) + { + return SLOTS_FOR_UP; + } + + return SLOTS_FOR_OTHER_FACES; +} + +bool BrewingStandTileEntity::canPlaceItemThroughFace(int slot, shared_ptr item, int face) +{ + return canPlaceItem(slot, item); +} + +bool BrewingStandTileEntity::canTakeItemThroughFace(int slot, shared_ptr item, int face) +{ + return true; } // 4J Added @@ -419,8 +480,8 @@ shared_ptr BrewingStandTileEntity::clone() TileEntity::clone(result); result->brewTime = brewTime; - result->lastPotionCount = lastPotionCount; - result->ingredientId = ingredientId; + result->lastPotionCount = lastPotionCount; + result->ingredientId = ingredientId; for (unsigned int i = 0; i < items.length; i++) { diff --git a/Minecraft.World/BrewingStandTileEntity.h b/Minecraft.World/BrewingStandTileEntity.h index 733e1073..52d3a0f1 100644 --- a/Minecraft.World/BrewingStandTileEntity.h +++ b/Minecraft.World/BrewingStandTileEntity.h @@ -1,50 +1,61 @@ #pragma once #include "TileEntity.h" -#include "Container.h" +#include "WorldlyContainer.h" -class BrewingStandTileEntity : public TileEntity, public Container +class BrewingStandTileEntity : public TileEntity, public WorldlyContainer { public: eINSTANCEOF GetType() { return eTYPE_BREWINGSTANDTILEENTITY; } static TileEntity *create() { return new BrewingStandTileEntity(); } + static const int INGREDIENT_SLOT = 3; + private: ItemInstanceArray items; - static const int INGREDIENT_SLOT = 3; + static intArray SLOTS_FOR_UP; + static intArray SLOTS_FOR_OTHER_FACES; - int brewTime; - int lastPotionCount; - int ingredientId; + int brewTime; + int lastPotionCount; + int ingredientId; + wstring name; public: BrewingStandTileEntity(); ~BrewingStandTileEntity(); - virtual int getName(); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual bool hasCustomName(); + virtual void setCustomName(const wstring &name); virtual unsigned int getContainerSize(); virtual void tick(); - int getBrewTime(); + int getBrewTime(); private: bool isBrewable(); - void doBrew(); + void doBrew(); int applyIngredient(int currentBrew, shared_ptr ingredient); public: virtual void load(CompoundTag *base); - virtual void save(CompoundTag *base); - virtual shared_ptr getItem(unsigned int slot); - virtual shared_ptr removeItem(unsigned int slot, int i); + virtual void save(CompoundTag *base); + virtual shared_ptr getItem(unsigned int slot); + virtual shared_ptr removeItem(unsigned int slot, int i); virtual shared_ptr removeItemNoUpdate(int slot); - virtual void setItem(unsigned int slot, shared_ptr item); - virtual int getMaxStackSize(); - virtual bool stillValid(shared_ptr player); - virtual void startOpen(); - virtual void stopOpen(); - virtual void setBrewTime(int value); - virtual void setChanged() {} // 4J added - int getPotionBits(); + virtual void setItem(unsigned int slot, shared_ptr item); + virtual int getMaxStackSize(); + virtual bool stillValid(shared_ptr player); + virtual void startOpen(); + virtual void stopOpen(); + virtual bool canPlaceItem(int slot, shared_ptr item); + virtual void setBrewTime(int value); + virtual void setChanged() { TileEntity::setChanged(); } // 4J added + int getPotionBits(); + virtual intArray getSlotsForFace(int face); + virtual bool canPlaceItemThroughFace(int slot, shared_ptr item, int face); + virtual bool canTakeItemThroughFace(int slot, shared_ptr item, int face); // 4J Added virtual shared_ptr clone(); diff --git a/Minecraft.World/BucketItem.cpp b/Minecraft.World/BucketItem.cpp index d3570cd7..a3bd7bee 100644 --- a/Minecraft.World/BucketItem.cpp +++ b/Minecraft.World/BucketItem.cpp @@ -24,12 +24,8 @@ BucketItem::BucketItem(int id, int content) : Item( id ) this->content = content; } -bool BucketItem::TestUse(Level *level, shared_ptr player) +bool BucketItem::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { -// double x = player->xo + (player->x - player->xo); -// double y = player->yo + (player->y - player->yo) + 1.62 - player->heightOffset; -// double z = player->zo + (player->z - player->zo); - bool pickLiquid = content == 0; HitResult *hr = getPlayerPOVHitResult(level, player, pickLiquid); if (hr == NULL) return false; @@ -48,7 +44,7 @@ bool BucketItem::TestUse(Level *level, shared_ptr player) if (content == 0) { - if (!player->mayBuild(xt, yt, zt)) return false; + if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) return false; if (level->getMaterial(xt, yt, zt) == Material::water && level->getData(xt, yt, zt) == 0) { delete hr; @@ -73,8 +69,8 @@ bool BucketItem::TestUse(Level *level, shared_ptr player) if (hr->f == 3) zt++; if (hr->f == 4) xt--; if (hr->f == 5) xt++; - - if (!player->mayBuild(xt, yt, zt)) return false; + + if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) return false; if (level->isEmptyTile(xt, yt, zt) || !level->getMaterial(xt, yt, zt)->isSolid()) { @@ -126,17 +122,17 @@ shared_ptr BucketItem::use(shared_ptr itemInstance, app.DebugPrintf("Sending ChatPacket::e_ChatCannotPlaceLava to player\n"); servPlayer->connection->send( shared_ptr( new ChatPacket(L"", ChatPacket::e_ChatCannotPlaceLava ) ) ); } - + delete hr; return itemInstance; } if (content == 0) { - if (!player->mayBuild(xt, yt, zt)) return itemInstance; + if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) return itemInstance; if (level->getMaterial(xt, yt, zt) == Material::water && level->getData(xt, yt, zt) == 0) { - level->setTile(xt, yt, zt, 0); + level->removeTile(xt, yt, zt); delete hr; if (player->abilities.instabuild) { @@ -160,11 +156,11 @@ shared_ptr BucketItem::use(shared_ptr itemInstance, { if( level->dimension->id == -1 ) player->awardStat( - GenericStats::netherLavaCollected(), - GenericStats::param_noArgs() - ); + GenericStats::netherLavaCollected(), + GenericStats::param_noArgs() + ); - level->setTile(xt, yt, zt, 0); + level->removeTile(xt, yt, zt); delete hr; if (player->abilities.instabuild) { @@ -197,65 +193,50 @@ shared_ptr BucketItem::use(shared_ptr itemInstance, if (hr->f == 3) zt++; if (hr->f == 4) xt--; if (hr->f == 5) xt++; - - if (!player->mayBuild(xt, yt, zt)) return itemInstance; + + if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) return itemInstance; - if (emptyBucket(level, x, y, z, xt, yt, zt) && !player->abilities.instabuild) + if (emptyBucket(level, xt, yt, zt) && !player->abilities.instabuild) { return shared_ptr( new ItemInstance(Item::bucket_empty) ); } } } - else - { - if (content == 0) - { - if (hr->entity->GetType() == eTYPE_COW) - { - delete hr; - if (--itemInstance->count <= 0) - { - return shared_ptr( new ItemInstance(Item::milk) ); - } - else - { - if (!player->inventory->add(shared_ptr( new ItemInstance(Item::milk)))) - { - player->drop(shared_ptr(new ItemInstance(Item::milk_Id, 1, 0))); - } - return itemInstance; - } - } - } - } delete hr; return itemInstance; } -bool BucketItem::emptyBucket(Level *level, double x, double y, double z, int xt, int yt, int zt) +bool BucketItem::emptyBucket(Level *level, int xt, int yt, int zt) { - if (content <= 0) return false; + if (content <= 0) return false; - if (level->isEmptyTile(xt, yt, zt) || !level->getMaterial(xt, yt, zt)->isSolid()) + Material *material = level->getMaterial(xt, yt, zt); + bool nonSolid = !material->isSolid(); + + if (level->isEmptyTile(xt, yt, zt) || nonSolid) { - if (level->dimension->ultraWarm && content == Tile::water_Id) + if (level->dimension->ultraWarm && content == Tile::water_Id) { - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_RANDOM_FIZZ, 0.5f, 2.6f + (level->random->nextFloat() - level->random->nextFloat()) * 0.8f); + level->playSound(xt + 0.5f, yt + 0.5f, zt + 0.5f, eSoundType_RANDOM_FIZZ, 0.5f, 2.6f + (level->random->nextFloat() - level->random->nextFloat()) * 0.8f); - for (int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { - level->addParticle(eParticleType_largesmoke, xt + Math::random(), yt + Math::random(), zt + Math::random(), 0, 0, 0); - } - } + level->addParticle(eParticleType_largesmoke, xt + Math::random(), yt + Math::random(), zt + Math::random(), 0, 0, 0); + } + } else { - level->setTileAndData(xt, yt, zt, content, 0); - } + if (!level->isClientSide && nonSolid && !material->isLiquid()) + { + level->destroyTile(xt, yt, zt, true); + } + level->setTileAndData(xt, yt, zt, content, 0, Tile::UPDATE_ALL); + } - return true; - } + return true; + } - return false; + return false; } diff --git a/Minecraft.World/BucketItem.h b/Minecraft.World/BucketItem.h index 500d19d8..0fd90e9c 100644 --- a/Minecraft.World/BucketItem.h +++ b/Minecraft.World/BucketItem.h @@ -13,19 +13,8 @@ private: public: BucketItem(int id, int content); - virtual bool TestUse(Level *level, shared_ptr player); + virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); - // TU9 - bool emptyBucket(Level *level, double x, double y, double z, int xt, int yt, int zt); - - /* - * public boolean useOn(ItemInstance instance, Player player, Level level, - * int x, int y, int z, int face) { if (content == 0) { } else { if (face == - * 0) y--; if (face == 1) y++; if (face == 2) z--; if (face == 3) z++; if - * (face == 4) x--; if (face == 5) x++; int targetType = level.getTile(x, y, - * z); if (targetType == 0) { level.setTile(x, y, z, content); } - * player->inventory.items[player->inventory.selected] = new - * ItemInstance(Item.bucket_empty); } return true; } - */ + bool emptyBucket(Level *level, int xt, int yt, int zt); }; \ No newline at end of file diff --git a/Minecraft.World/Bush.cpp b/Minecraft.World/Bush.cpp index e6cd7c85..6f8e8d91 100644 --- a/Minecraft.World/Bush.cpp +++ b/Minecraft.World/Bush.cpp @@ -5,13 +5,13 @@ void Bush::_init() { - setTicking(true); - updateDefaultShape(); + setTicking(true); + updateDefaultShape(); } Bush::Bush(int id, Material *material) : Tile(id, material, isSolidRender()) { - _init(); + _init(); } Bush::Bush(int id) : Tile(id, Material::plant, isSolidRender()) @@ -22,8 +22,8 @@ Bush::Bush(int id) : Tile(id, Material::plant, isSolidRender()) // 4J Added override void Bush::updateDefaultShape() { - float ss = 0.2f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, ss * 3, 0.5f + ss); + float ss = 0.2f; + setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, ss * 3, 0.5f + ss); } bool Bush::mayPlace(Level *level, int x, int y, int z) @@ -49,11 +49,11 @@ void Bush::tick(Level *level, int x, int y, int z, Random *random) void Bush::checkAlive(Level *level, int x, int y, int z) { - if (!canSurvive(level, x, y, z)) + if (!canSurvive(level, x, y, z)) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); - } + this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->setTileAndData(x, y, z, 0, 0, UPDATE_CLIENTS); + } } bool Bush::canSurvive(Level *level, int x, int y, int z) diff --git a/Minecraft.World/ButtonTile.cpp b/Minecraft.World/ButtonTile.cpp index 16055a7e..045d5597 100644 --- a/Minecraft.World/ButtonTile.cpp +++ b/Minecraft.World/ButtonTile.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.h" #include "ButtonTile.h" @@ -15,7 +16,7 @@ ButtonTile::ButtonTile(int id, bool sensitive) : Tile(id, Material::decoration,i Icon *ButtonTile::getTexture(int face, int data) { if(id == Tile::button_wood_Id) return Tile::wood->getTexture(Facing::UP); - else return Tile::rock->getTexture(Facing::UP); + else return Tile::stone->getTexture(Facing::UP); } AABB *ButtonTile::getAABB(Level *level, int x, int y, int z) @@ -23,7 +24,7 @@ AABB *ButtonTile::getAABB(Level *level, int x, int y, int z) return NULL; } -int ButtonTile::getTickDelay() +int ButtonTile::getTickDelay(Level *level) { return sensitive ? 30 : 20; } @@ -45,100 +46,100 @@ bool ButtonTile::isCubeShaped() bool ButtonTile::mayPlace(Level *level, int x, int y, int z, int face) { - if (face == 2 && level->isSolidBlockingTile(x, y, z + 1)) return true; - if (face == 3 && level->isSolidBlockingTile(x, y, z - 1)) return true; - if (face == 4 && level->isSolidBlockingTile(x + 1, y, z)) return true; - if (face == 5 && level->isSolidBlockingTile(x - 1, y, z)) return true; - return false; + if (face == 2 && level->isSolidBlockingTile(x, y, z + 1)) return true; + if (face == 3 && level->isSolidBlockingTile(x, y, z - 1)) return true; + if (face == 4 && level->isSolidBlockingTile(x + 1, y, z)) return true; + if (face == 5 && level->isSolidBlockingTile(x - 1, y, z)) return true; + return false; } bool ButtonTile::mayPlace(Level *level, int x, int y, int z) { - if (level->isSolidBlockingTile(x - 1, y, z)) + if (level->isSolidBlockingTile(x - 1, y, z)) { - return true; - } + return true; + } else if (level->isSolidBlockingTile(x + 1, y, z)) { - return true; - } + return true; + } else if (level->isSolidBlockingTile(x, y, z - 1)) { - return true; - } + return true; + } else if (level->isSolidBlockingTile(x, y, z + 1)) { - return true; - } - return false; + return true; + } + return false; } int ButtonTile::getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) { - int dir = level->getData(x, y, z); + int dir = level->getData(x, y, z); - int oldFlip = dir & 8; - dir &= 7; + int oldFlip = dir & 8; + dir &= 7; - if (face == 2 && level->isSolidBlockingTile(x, y, z + 1)) dir = 4; - else if (face == 3 && level->isSolidBlockingTile(x, y, z - 1)) dir = 3; - else if (face == 4 && level->isSolidBlockingTile(x + 1, y, z)) dir = 2; - else if (face == 5 && level->isSolidBlockingTile(x - 1, y, z)) dir = 1; - else dir = findFace(level, x, y, z); + if (face == 2 && level->isSolidBlockingTile(x, y, z + 1)) dir = 4; + else if (face == 3 && level->isSolidBlockingTile(x, y, z - 1)) dir = 3; + else if (face == 4 && level->isSolidBlockingTile(x + 1, y, z)) dir = 2; + else if (face == 5 && level->isSolidBlockingTile(x - 1, y, z)) dir = 1; + else dir = findFace(level, x, y, z); - return dir + oldFlip; + return dir + oldFlip; } int ButtonTile::findFace(Level *level, int x, int y, int z) { - if (level->isSolidBlockingTile(x - 1, y, z)) + if (level->isSolidBlockingTile(x - 1, y, z)) { - return 1; - } + return 1; + } else if (level->isSolidBlockingTile(x + 1, y, z)) { - return 2; - } + return 2; + } else if (level->isSolidBlockingTile(x, y, z - 1)) { - return 3; - } + return 3; + } else if (level->isSolidBlockingTile(x, y, z + 1)) { - return 4; - } - return 1; + return 4; + } + return 1; } void ButtonTile::neighborChanged(Level *level, int x, int y, int z, int type) { - if (checkCanSurvive(level, x, y, z)) + if (checkCanSurvive(level, x, y, z)) { - int dir = level->getData(x, y, z) & 7; - bool replace = false; + int dir = level->getData(x, y, z) & 7; + bool replace = false; - if (!level->isSolidBlockingTile(x - 1, y, z) && dir == 1) replace = true; - if (!level->isSolidBlockingTile(x + 1, y, z) && dir == 2) replace = true; - if (!level->isSolidBlockingTile(x, y, z - 1) && dir == 3) replace = true; - if (!level->isSolidBlockingTile(x, y, z + 1) && dir == 4) replace = true; + if (!level->isSolidBlockingTile(x - 1, y, z) && dir == 1) replace = true; + if (!level->isSolidBlockingTile(x + 1, y, z) && dir == 2) replace = true; + if (!level->isSolidBlockingTile(x, y, z - 1) && dir == 3) replace = true; + if (!level->isSolidBlockingTile(x, y, z + 1) && dir == 4) replace = true; - if (replace) + if (replace) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); - } - } + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); + } + } } bool ButtonTile::checkCanSurvive(Level *level, int x, int y, int z) { - if (!mayPlace(level, x, y, z)) + if (!mayPlace(level, x, y, z)) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); - return false; - } - return true; + this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); + return false; + } + return true; } void ButtonTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param @@ -149,31 +150,31 @@ void ButtonTile::updateShape(LevelSource *level, int x, int y, int z, int forceD void ButtonTile::updateShape(int data) { - int dir = data & 7; - bool pressed = (data & 8) > 0; + int dir = data & 7; + bool pressed = (data & 8) > 0; - float h0 = 6 / 16.0f; - float h1 = 10 / 16.0f; - float r = 3 / 16.0f; - float d = 2 / 16.0f; - if (pressed) d = 1 / 16.0f; + float h0 = 6 / 16.0f; + float h1 = 10 / 16.0f; + float r = 3 / 16.0f; + float d = 2 / 16.0f; + if (pressed) d = 1 / 16.0f; - if (dir == 1) + if (dir == 1) { - setShape(0, h0, 0.5f - r, d, h1, 0.5f + r); - } + setShape(0, h0, 0.5f - r, d, h1, 0.5f + r); + } else if (dir == 2) { - setShape(1 - d, h0, 0.5f - r, 1, h1, 0.5f + r); - } + setShape(1 - d, h0, 0.5f - r, 1, h1, 0.5f + r); + } else if (dir == 3) { - setShape(0.5f - r, h0, 0, 0.5f + r, h1, d); - } + setShape(0.5f - r, h0, 0, 0.5f + r, h1, d); + } else if (dir == 4) { - setShape(0.5f - r, h0, 1 - d, 0.5f + r, h1, 1); - } + setShape(0.5f - r, h0, 1 - d, 0.5f + r, h1, 1); + } } void ButtonTile::attack(Level *level, int x, int y, int z, shared_ptr player) @@ -189,57 +190,58 @@ bool ButtonTile::TestUse() bool ButtonTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param { - if( soundOnly) + if (soundOnly) { // 4J - added - just do enough to play the sound level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, 0.6f); return false; } - int data = level->getData(x, y, z); - int dir = data & 7; - int open = 8 - (data & 8); - if (open == 0) return true; - level->setData(x, y, z, dir + open); - level->setTilesDirty(x, y, z, x, y, z); + int data = level->getData(x, y, z); + int dir = data & 7; + int open = 8 - (data & 8); + if (open == 0) return true; + + level->setData(x, y, z, dir + open, Tile::UPDATE_ALL); + level->setTilesDirty(x, y, z, x, y, z); - level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, 0.6f); + level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, 0.6f); - updateNeighbours(level, x, y, z, dir); + updateNeighbours(level, x, y, z, dir); - level->addToTickNextTick(x, y, z, id, getTickDelay()); + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); - return true; + return true; } void ButtonTile::onRemove(Level *level, int x, int y, int z, int id, int data) { - if ((data & 8) > 0) + if ((data & 8) > 0) { - int dir = data & 7; - updateNeighbours(level, x, y, z, dir); - } - Tile::onRemove(level, x, y, z, id, data); + int dir = data & 7; + updateNeighbours(level, x, y, z, dir); + } + Tile::onRemove(level, x, y, z, id, data); } -bool ButtonTile::getSignal(LevelSource *level, int x, int y, int z, int dir) +int ButtonTile::getSignal(LevelSource *level, int x, int y, int z, int dir) { - return (level->getData(x, y, z) & 8) > 0; + return (level->getData(x, y, z) & 8) > 0 ? Redstone::SIGNAL_MAX : Redstone::SIGNAL_NONE; } -bool ButtonTile::getDirectSignal(Level *level, int x, int y, int z, int dir) +int ButtonTile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir) { - int data = level->getData(x, y, z); - if ((data & 8) == 0) return false; - int myDir = data & 7; + int data = level->getData(x, y, z); + if ((data & 8) == 0) return Redstone::SIGNAL_NONE; + int myDir = data & 7; - if (myDir == 5 && dir == 1) return true; - if (myDir == 4 && dir == 2) return true; - if (myDir == 3 && dir == 3) return true; - if (myDir == 2 && dir == 4) return true; - if (myDir == 1 && dir == 5) return true; + if (myDir == 5 && dir == 1) return Redstone::SIGNAL_MAX; + if (myDir == 4 && dir == 2) return Redstone::SIGNAL_MAX; + if (myDir == 3 && dir == 3) return Redstone::SIGNAL_MAX; + if (myDir == 2 && dir == 4) return Redstone::SIGNAL_MAX; + if (myDir == 1 && dir == 5) return Redstone::SIGNAL_MAX; - return false; + return false; } bool ButtonTile::isSignalSource() @@ -261,7 +263,7 @@ void ButtonTile::tick(Level *level, int x, int y, int z, Random *random) } else { - level->setData(x, y, z, data & 7); + level->setData(x, y, z, data & 7, Tile::UPDATE_ALL); int dir = data & 7; updateNeighbours(level, x, y, z, dir); @@ -273,10 +275,10 @@ void ButtonTile::tick(Level *level, int x, int y, int z, Random *random) void ButtonTile::updateDefaultShape() { - float x = 3 / 16.0f; - float y = 2 / 16.0f; - float z = 2 / 16.0f; - setShape(0.5f - x, 0.5f - y, 0.5f - z, 0.5f + x, 0.5f + y, 0.5f + z); + float x = 3 / 16.0f; + float y = 2 / 16.0f; + float z = 2 / 16.0f; + setShape(0.5f - x, 0.5f - y, 0.5f - z, 0.5f + x, 0.5f + y, 0.5f + z); } void ButtonTile::entityInside(Level *level, int x, int y, int z, shared_ptr entity) @@ -307,7 +309,7 @@ void ButtonTile::checkPressed(Level *level, int x, int y, int z) if (shouldBePressed && !wasPressed) { - level->setData(x, y, z, dir | 8); + level->setData(x, y, z, dir | 8, Tile::UPDATE_ALL); updateNeighbours(level, x, y, z, dir); level->setTilesDirty(x, y, z, x, y, z); @@ -315,7 +317,7 @@ void ButtonTile::checkPressed(Level *level, int x, int y, int z) } if (!shouldBePressed && wasPressed) { - level->setData(x, y, z, dir); + level->setData(x, y, z, dir, Tile::UPDATE_ALL); updateNeighbours(level, x, y, z, dir); level->setTilesDirty(x, y, z, x, y, z); @@ -324,7 +326,7 @@ void ButtonTile::checkPressed(Level *level, int x, int y, int z) if (shouldBePressed) { - level->addToTickNextTick(x, y, z, id, getTickDelay()); + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); } } @@ -357,7 +359,7 @@ void ButtonTile::updateNeighbours(Level *level, int x, int y, int z, int dir) bool ButtonTile::shouldTileTick(Level *level, int x,int y,int z) { int currentData = level->getData(x, y, z); - return (currentData & 8) != 0; + return (currentData & 8) != 0; } void ButtonTile::registerIcons(IconRegister *iconRegister) diff --git a/Minecraft.World/ButtonTile.h b/Minecraft.World/ButtonTile.h index e06158e0..96c49cdf 100644 --- a/Minecraft.World/ButtonTile.h +++ b/Minecraft.World/ButtonTile.h @@ -19,13 +19,13 @@ protected: public: Icon *getTexture(int face, int data); virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual int getTickDelay(); - virtual bool blocksLight(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); - virtual bool mayPlace(Level *level, int x, int y, int z, int face); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); + virtual int getTickDelay(Level *level); + virtual bool blocksLight(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); + virtual bool mayPlace(Level *level, int x, int y, int z, int face); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); private: int findFace(Level *level, int x, int y, int z); @@ -37,30 +37,30 @@ private: bool checkCanSurvive(Level *level, int x, int y, int z); public: - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param private: void updateShape(int data); public: - virtual void attack(Level *level, int x, int y, int z, shared_ptr player); + virtual void attack(Level *level, int x, int y, int z, shared_ptr player); virtual bool TestUse(); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); - virtual bool getSignal(LevelSource *level, int x, int y, int z, int dir); - virtual bool getDirectSignal(Level *level, int x, int y, int z, int dir); - virtual bool isSignalSource(); - virtual void tick(Level *level, int x, int y, int z, Random *random); - virtual void updateDefaultShape(); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); + virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir); + virtual bool isSignalSource(); + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual void updateDefaultShape(); void entityInside(Level *level, int x, int y, int z, shared_ptr entity); private: void checkPressed(Level *level, int x, int y, int z); - void updateNeighbours(Level *level, int x, int y, int z, int dir); + void updateNeighbours(Level *level, int x, int y, int z, int dir); public: void registerIcons(IconRegister *iconRegister); - + // 4J Added so we can check before we try to add a tile to the tick list if it's actually going to do seomthing virtual bool shouldTileTick(Level *level, int x,int y,int z); }; \ No newline at end of file diff --git a/Minecraft.World/ByteArrayTag.h b/Minecraft.World/ByteArrayTag.h index 1b2437c0..598515ac 100644 --- a/Minecraft.World/ByteArrayTag.h +++ b/Minecraft.World/ByteArrayTag.h @@ -6,9 +6,11 @@ class ByteArrayTag : public Tag { public: byteArray data; + bool m_ownData; - ByteArrayTag(const wstring &name) : Tag(name) { } - ByteArrayTag(const wstring &name, byteArray data) : Tag(name) {this->data = data; } // 4J - added ownData param + ByteArrayTag(const wstring &name) : Tag(name) { m_ownData = false; } + ByteArrayTag(const wstring &name, byteArray data, bool ownData = false) : Tag(name) {this->data = data; m_ownData = ownData;} // 4J - added ownData param + ~ByteArrayTag() { if(m_ownData) delete [] data.data; } void write(DataOutput *dos) { @@ -16,7 +18,7 @@ public: dos->write(data); } - void load(DataInput *dis) + void load(DataInput *dis, int tagDepth) { int length = dis->readInt(); @@ -48,6 +50,6 @@ public: { byteArray cp = byteArray(data.length); System::arraycopy(data, 0, &cp, 0, data.length); - return new ByteArrayTag(getName(), cp); + return new ByteArrayTag(getName(), cp, true); } }; \ No newline at end of file diff --git a/Minecraft.World/ByteTag.h b/Minecraft.World/ByteTag.h index 0d2b3965..6b319c0b 100644 --- a/Minecraft.World/ByteTag.h +++ b/Minecraft.World/ByteTag.h @@ -9,7 +9,7 @@ public: ByteTag(const wstring &name, byte data) : Tag(name) {this->data = data; } void write(DataOutput *dos) { dos->writeByte(data); } - void load(DataInput *dis) { data = dis->readByte(); } + void load(DataInput *dis, int tagDepth) { data = dis->readByte(); } byte getId() { return TAG_Byte; } wstring toString() diff --git a/Minecraft.World/C4JThread.h b/Minecraft.World/C4JThread.h index 9a303c7b..3d5f050c 100644 --- a/Minecraft.World/C4JThread.h +++ b/Minecraft.World/C4JThread.h @@ -223,3 +223,12 @@ private: }; void SetThreadName( DWORD dwThreadID, LPCSTR szThreadName ); + +class CriticalSectionScopeLock +{ + CRITICAL_SECTION* m_pCS; +public: + CriticalSectionScopeLock(CRITICAL_SECTION* pCS) { m_pCS = pCS; EnterCriticalSection(m_pCS); } + ~CriticalSectionScopeLock() { LeaveCriticalSection(m_pCS); } +}; + diff --git a/Minecraft.World/CactusFeature.cpp b/Minecraft.World/CactusFeature.cpp index 175c4ddb..13f5535a 100644 --- a/Minecraft.World/CactusFeature.cpp +++ b/Minecraft.World/CactusFeature.cpp @@ -5,23 +5,23 @@ bool CactusFeature::place(Level *level, Random *random, int x, int y, int z) { - for (int i = 0; i < 10; i++) { - int x2 = x + random->nextInt(8) - random->nextInt(8); - int y2 = y + random->nextInt(4) - random->nextInt(4); - int z2 = z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(x2, y2, z2)) + for (int i = 0; i < 10; i++) { + int x2 = x + random->nextInt(8) - random->nextInt(8); + int y2 = y + random->nextInt(4) - random->nextInt(4); + int z2 = z + random->nextInt(8) - random->nextInt(8); + if (level->isEmptyTile(x2, y2, z2)) { - int h = 1 + random->nextInt(random->nextInt(3) + 1); - for (int yy = 0; yy < h; yy++) + int h = 1 + random->nextInt(random->nextInt(3) + 1); + for (int yy = 0; yy < h; yy++) { - if (Tile::cactus->canSurvive(level, x2, y2+yy, z2)) + if (Tile::cactus->canSurvive(level, x2, y2+yy, z2)) { - level->setTileNoUpdate(x2, y2+yy, z2, Tile::cactus_Id); - } - } - } - } + level->setTileAndData(x2, y2+yy, z2, Tile::cactus_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } + } - return true; + return true; } diff --git a/Minecraft.World/CactusTile.cpp b/Minecraft.World/CactusTile.cpp index b72570e1..cdce293c 100644 --- a/Minecraft.World/CactusTile.cpp +++ b/Minecraft.World/CactusTile.cpp @@ -12,7 +12,7 @@ CactusTile::CactusTile(int id) : Tile(id, Material::cactus,isSolidRender()) { setTicking(true); iconTop = NULL; - iconBottom = NULL; + iconBottom = NULL; } void CactusTile::tick(Level *level, int x, int y, int z, Random *random) @@ -29,11 +29,13 @@ void CactusTile::tick(Level *level, int x, int y, int z, Random *random) int age = level->getData(x, y, z); if (age == 15) { - level->setTile(x, y + 1, z, id); - level->setData(x, y, z, 0); - } else + level->setTileAndUpdate(x, y + 1, z, id); + level->setData(x, y, z, 0, Tile::UPDATE_NONE); + neighborChanged(level, x, y + 1, z, id); + } + else { - level->setData(x, y, z, age + 1); + level->setData(x, y, z, age + 1, Tile::UPDATE_NONE); } } } @@ -41,22 +43,22 @@ void CactusTile::tick(Level *level, int x, int y, int z, Random *random) AABB *CactusTile::getAABB(Level *level, int x, int y, int z) { - float r = 1 / 16.0f; - return AABB::newTemp(x + r, y, z + r, x + 1 - r, y + 1 - r, z + 1 - r); + float r = 1 / 16.0f; + return AABB::newTemp(x + r, y, z + r, x + 1 - r, y + 1 - r, z + 1 - r); } AABB *CactusTile::getTileAABB(Level *level, int x, int y, int z) { - float r = 1 / 16.0f; - return AABB::newTemp(x + r, y, z + r, x + 1 - r, y + 1, z + 1 - r); + float r = 1 / 16.0f; + return AABB::newTemp(x + r, y, z + r, x + 1 - r, y + 1, z + 1 - r); } Icon *CactusTile::getTexture(int face, int data) { - if (face == Facing::UP) return iconTop; - if (face == Facing::DOWN) return iconBottom; - else return icon; + if (face == Facing::UP) return iconTop; + if (face == Facing::DOWN) return iconBottom; + else return icon; } bool CactusTile::isCubeShaped() @@ -76,28 +78,27 @@ int CactusTile::getRenderShape() bool CactusTile::mayPlace(Level *level, int x, int y, int z) { - if (!Tile::mayPlace(level, x, y, z)) return false; + if (!Tile::mayPlace(level, x, y, z)) return false; - return canSurvive(level, x, y, z); + return canSurvive(level, x, y, z); } void CactusTile::neighborChanged(Level *level, int x, int y, int z, int type) { - if (!canSurvive(level, x, y, z)) + if (!canSurvive(level, x, y, z)) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->destroyTile(x, y, z, true); } } bool CactusTile::canSurvive(Level *level, int x, int y, int z) { - if (level->getMaterial(x - 1, y, z)->isSolid()) return false; - if (level->getMaterial(x + 1, y, z)->isSolid()) return false; - if (level->getMaterial(x, y, z - 1)->isSolid()) return false; - if (level->getMaterial(x, y, z + 1)->isSolid()) return false; - int below = level->getTile(x, y - 1, z); - return below == Tile::cactus_Id || below == Tile::sand_Id; + if (level->getMaterial(x - 1, y, z)->isSolid()) return false; + if (level->getMaterial(x + 1, y, z)->isSolid()) return false; + if (level->getMaterial(x, y, z - 1)->isSolid()) return false; + if (level->getMaterial(x, y, z + 1)->isSolid()) return false; + int below = level->getTile(x, y - 1, z); + return below == Tile::cactus_Id || below == Tile::sand_Id; } void CactusTile::entityInside(Level *level, int x, int y, int z, shared_ptr entity) @@ -114,5 +115,5 @@ void CactusTile::registerIcons(IconRegister *iconRegister) bool CactusTile::shouldTileTick(Level *level, int x,int y,int z) { - return level->isEmptyTile(x, y + 1, z); + return level->isEmptyTile(x, y + 1, z); } diff --git a/Minecraft.World/CakeTile.cpp b/Minecraft.World/CakeTile.cpp index 1254e10e..55dff176 100644 --- a/Minecraft.World/CakeTile.cpp +++ b/Minecraft.World/CakeTile.cpp @@ -20,44 +20,44 @@ CakeTile::CakeTile(int id) : Tile(id, Material::cake,isSolidRender()) void CakeTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { - int d = level->getData(x, y, z); - float r = 1 / 16.0f; - float r2 = (1 + d * 2) / 16.0f; - float h = 8 / 16.0f; - this->setShape(r2, 0, r, 1 - r, h, 1 - r); + int d = level->getData(x, y, z); + float r = 1 / 16.0f; + float r2 = (1 + d * 2) / 16.0f; + float h = 8 / 16.0f; + this->setShape(r2, 0, r, 1 - r, h, 1 - r); } void CakeTile::updateDefaultShape() { - float r = 1 / 16.0f; - float h = 8 / 16.0f; - this->setShape(r, 0, r, 1 - r, h, 1 - r); + float r = 1 / 16.0f; + float h = 8 / 16.0f; + this->setShape(r, 0, r, 1 - r, h, 1 - r); } AABB *CakeTile::getAABB(Level *level, int x, int y, int z) { - int d = level->getData(x, y, z); - float r = 1 / 16.0f; - float r2 = (1 + d * 2) / 16.0f; - float h = 8 / 16.0f; - return AABB::newTemp(x + r2, y, z + r, x + 1 - r, y + h - r, z + 1 - r); + int d = level->getData(x, y, z); + float r = 1 / 16.0f; + float r2 = (1 + d * 2) / 16.0f; + float h = 8 / 16.0f; + return AABB::newTemp(x + r2, y, z + r, x + 1 - r, y + h - r, z + 1 - r); } AABB *CakeTile::getTileAABB(Level *level, int x, int y, int z) { - int d = level->getData(x, y, z); - float r = 1 / 16.0f; - float r2 = (1 + d * 2) / 16.0f; - float h = 8 / 16.0f; - return AABB::newTemp(x + r2, y, z + r, x + 1 - r, y + h, z + 1 - r); + int d = level->getData(x, y, z); + float r = 1 / 16.0f; + float r2 = (1 + d * 2) / 16.0f; + float h = 8 / 16.0f; + return AABB::newTemp(x + r2, y, z + r, x + 1 - r, y + h, z + 1 - r); } Icon *CakeTile::getTexture(int face, int data) { - if (face == Facing::UP) return iconTop; - if (face == Facing::DOWN) return iconBottom; - if (data > 0 && face == Facing::WEST) return iconInner; - return icon; + if (face == Facing::UP) return iconTop; + if (face == Facing::DOWN) return iconBottom; + if (data > 0 && face == Facing::WEST) return iconInner; + return icon; } void CakeTile::registerIcons(IconRegister *iconRegister) @@ -87,8 +87,8 @@ bool CakeTile::TestUse() bool CakeTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param { if( soundOnly ) return false; - eat(level, x, y, z, player); - return true; + eat(level, x, y, z, player); + return true; } void CakeTile::attack(Level *level, int x, int y, int z, shared_ptr player) @@ -98,35 +98,34 @@ void CakeTile::attack(Level *level, int x, int y, int z, shared_ptr play void CakeTile::eat(Level *level, int x, int y, int z, shared_ptr player) { - if (player->canEat(false)) + if (player->canEat(false)) { - player->getFoodData()->eat(2, FoodConstants::FOOD_SATURATION_POOR); + player->getFoodData()->eat(2, FoodConstants::FOOD_SATURATION_POOR); - int d = level->getData(x, y, z) + 1; - if (d >= 6) + int d = level->getData(x, y, z) + 1; + if (d >= 6) { - level->setTile(x, y, z, 0); - } else + level->removeTile(x, y, z); + } + else { - level->setData(x, y, z, d); - level->setTileDirty(x, y, z); - } - } + level->setData(x, y, z, d, Tile::UPDATE_CLIENTS); + } + } } bool CakeTile::mayPlace(Level *level, int x, int y, int z) { - if (!Tile::mayPlace(level, x, y, z)) return false; + if (!Tile::mayPlace(level, x, y, z)) return false; - return canSurvive(level, x, y, z); + return canSurvive(level, x, y, z); } void CakeTile::neighborChanged(Level *level, int x, int y, int z, int type) { - if (!canSurvive(level, x, y, z)) + if (!canSurvive(level, x, y, z)) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); } } diff --git a/Minecraft.World/Calendar.cpp b/Minecraft.World/Calendar.cpp new file mode 100644 index 00000000..e6d8d644 --- /dev/null +++ b/Minecraft.World/Calendar.cpp @@ -0,0 +1,19 @@ +#include "stdafx.h" +#include "Calendar.h" +#include + +unsigned int Calendar::GetDayOfMonth() +{ + time_t t = time(0); + struct tm *now = localtime(&t); + + return now->tm_mday; +} + +unsigned int Calendar::GetMonth() +{ + time_t t = time(0); + struct tm *now = localtime(&t); + + return now->tm_mon; +} \ No newline at end of file diff --git a/Minecraft.World/Calendar.h b/Minecraft.World/Calendar.h new file mode 100644 index 00000000..436c756a --- /dev/null +++ b/Minecraft.World/Calendar.h @@ -0,0 +1,10 @@ +#pragma once + +class Calendar +{ +public: + Calendar(); + + static unsigned int GetDayOfMonth(); + static unsigned int GetMonth(); +}; \ No newline at end of file diff --git a/Minecraft.World/CanyonFeature.cpp b/Minecraft.World/CanyonFeature.cpp index b96c97e0..6d1dda64 100644 --- a/Minecraft.World/CanyonFeature.cpp +++ b/Minecraft.World/CanyonFeature.cpp @@ -9,26 +9,26 @@ void CanyonFeature::addTunnel(__int64 seed, int xOffs, int zOffs, byteArray bloc MemSect(49); Random *random = new Random(seed); MemSect(0); - double xMid = xOffs * 16 + 8; - double zMid = zOffs * 16 + 8; + double xMid = xOffs * 16 + 8; + double zMid = zOffs * 16 + 8; - float yRota = 0; - float xRota = 0; - // int dist = CAVE_RADIUS * 16 - 16; - // if (step>0) dist = step*2; + float yRota = 0; + float xRota = 0; + // int dist = CAVE_RADIUS * 16 - 16; + // if (step>0) dist = step*2; - if (dist <= 0) + if (dist <= 0) { - int max = radius * 16 - 16; - dist = max - random->nextInt(max / 4); - } - bool singleStep = false; + int max = radius * 16 - 16; + dist = max - random->nextInt(max / 4); + } + bool singleStep = false; - if (step == -1) + if (step == -1) { - step = dist / 2; - singleStep = true; - } + step = dist / 2; + singleStep = true; + } float f = 1; for (int i = 0; i < Level::genDepth; i++) @@ -40,94 +40,94 @@ void CanyonFeature::addTunnel(__int64 seed, int xOffs, int zOffs, byteArray bloc rs[i] = f * f; } - for (; step < dist; step++) + for (; step < dist; step++) { - double rad = 1.5 + (Mth::sin(step * PI / dist) * thickness) * 1; - double yRad = rad * yScale; + double rad = 1.5 + (Mth::sin(step * PI / dist) * thickness) * 1; + double yRad = rad * yScale; rad *= (random->nextFloat() * 0.25 + 0.75); yRad *= (random->nextFloat() * 0.25 + 0.75); - float xc = Mth::cos(xRot); - float xs = Mth::sin(xRot); - xCave += Mth::cos(yRot) * xc; - yCave += xs; - zCave += Mth::sin(yRot) * xc; + float xc = Mth::cos(xRot); + float xs = Mth::sin(xRot); + xCave += Mth::cos(yRot) * xc; + yCave += xs; + zCave += Mth::sin(yRot) * xc; xRot *= 0.7f; - xRot += xRota * 0.05f; - yRot += yRota * 0.05f; + xRot += xRota * 0.05f; + yRot += yRota * 0.05f; - xRota *= 0.80f; - yRota *= 0.50f; - xRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 2; - yRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 4; + xRota *= 0.80f; + yRota *= 0.50f; + xRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 2; + yRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 4; - if (!singleStep && random->nextInt(4) == 0) continue; + if (!singleStep && random->nextInt(4) == 0) continue; - { - double xd = xCave - xMid; - double zd = zCave - zMid; - double remaining = dist - step; - double rr = (thickness + 2) + 16; - if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) + { + double xd = xCave - xMid; + double zd = zCave - zMid; + double remaining = dist - step; + double rr = (thickness + 2) + 16; + if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) { delete random; - return; - } - } + return; + } + } - if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; + if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; - int x0 = Mth::floor(xCave - rad) - xOffs * 16 - 1; - int x1 = Mth::floor(xCave + rad) - xOffs * 16 + 1; + int x0 = Mth::floor(xCave - rad) - xOffs * 16 - 1; + int x1 = Mth::floor(xCave + rad) - xOffs * 16 + 1; - int y0 = Mth::floor(yCave - yRad) - 1; - int y1 = Mth::floor(yCave + yRad) + 1; + int y0 = Mth::floor(yCave - yRad) - 1; + int y1 = Mth::floor(yCave + yRad) + 1; - int z0 = Mth::floor(zCave - rad) - zOffs * 16 - 1; - int z1 = Mth::floor(zCave + rad) - zOffs * 16 + 1; + int z0 = Mth::floor(zCave - rad) - zOffs * 16 - 1; + int z1 = Mth::floor(zCave + rad) - zOffs * 16 + 1; - if (x0 < 0) x0 = 0; - if (x1 > 16) x1 = 16; + if (x0 < 0) x0 = 0; + if (x1 > 16) x1 = 16; - if (y0 < 1) y0 = 1; - if (y1 > Level::genDepth - 8) y1 = Level::genDepth - 8; + if (y0 < 1) y0 = 1; + if (y1 > Level::genDepth - 8) y1 = Level::genDepth - 8; - if (z0 < 0) z0 = 0; - if (z1 > 16) z1 = 16; + if (z0 < 0) z0 = 0; + if (z1 > 16) z1 = 16; - bool detectedWater = false; - for (int xx = x0; !detectedWater && xx < x1; xx++) + bool detectedWater = false; + for (int xx = x0; !detectedWater && xx < x1; xx++) { - for (int zz = z0; !detectedWater && zz < z1; zz++) + for (int zz = z0; !detectedWater && zz < z1; zz++) { - for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) + for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) { - int p = (xx * 16 + zz) * Level::genDepth + yy; - if (yy < 0 || yy >= Level::genDepth) continue; - if (blocks[p] == Tile::water_Id || blocks[p] == Tile::calmWater_Id) + int p = (xx * 16 + zz) * Level::genDepth + yy; + if (yy < 0 || yy >= Level::genDepth) continue; + if (blocks[p] == Tile::water_Id || blocks[p] == Tile::calmWater_Id) { - detectedWater = true; - } - if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) + detectedWater = true; + } + if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) { - yy = y0; - } - } - } - } - if (detectedWater) continue; - - for (int xx = x0; xx < x1; xx++) + yy = y0; + } + } + } + } + if (detectedWater) continue; + + for (int xx = x0; xx < x1; xx++) { - double xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; - for (int zz = z0; zz < z1; zz++) + double xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; + for (int zz = z0; zz < z1; zz++) { - double zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; - int p = (xx * 16 + zz) * Level::genDepth + y1; - bool hasGrass = false; + double zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; + int p = (xx * 16 + zz) * Level::genDepth + y1; + bool hasGrass = false; if (xd * xd + zd * zd < 1) { for (int yy = y1 - 1; yy >= y0; yy--) @@ -137,7 +137,7 @@ void CanyonFeature::addTunnel(__int64 seed, int xOffs, int zOffs, byteArray bloc { int block = blocks[p]; if (block == Tile::grass_Id) hasGrass = true; - if (block == Tile::rock_Id || block == Tile::dirt_Id || block == Tile::grass_Id) + if (block == Tile::stone_Id || block == Tile::dirt_Id || block == Tile::grass_Id) { if (yy < 10) { @@ -153,20 +153,20 @@ void CanyonFeature::addTunnel(__int64 seed, int xOffs, int zOffs, byteArray bloc p--; } } - } - } - if (singleStep) break; - } + } + } + if (singleStep) break; + } delete random; } void CanyonFeature::addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks) { - if (random->nextInt(50) != 0) return; + if (random->nextInt(50) != 0) return; - double xCave = x * 16 + random->nextInt(16); - double yCave = random->nextInt(random->nextInt(40) + 8) + 20; - double zCave = z * 16 + random->nextInt(16); + double xCave = x * 16 + random->nextInt(16); + double yCave = random->nextInt(random->nextInt(40) + 8) + 20; + double zCave = z * 16 + random->nextInt(16); int tunnels = 1; diff --git a/Minecraft.World/CarrotOnAStickItem.cpp b/Minecraft.World/CarrotOnAStickItem.cpp index 9845cc25..3701fce1 100644 --- a/Minecraft.World/CarrotOnAStickItem.cpp +++ b/Minecraft.World/CarrotOnAStickItem.cpp @@ -31,7 +31,7 @@ shared_ptr CarrotOnAStickItem::use(shared_ptr itemIn if (pig->getControlGoal()->canBoost() && itemInstance->getMaxDamage() - itemInstance->getAuxValue() >= 7) { pig->getControlGoal()->boost(); - itemInstance->hurt(7, player); + itemInstance->hurtAndBreak(7, player); if (itemInstance->count == 0) { diff --git a/Minecraft.World/CarrotTile.cpp b/Minecraft.World/CarrotTile.cpp index 3eba830b..677ab78a 100644 --- a/Minecraft.World/CarrotTile.cpp +++ b/Minecraft.World/CarrotTile.cpp @@ -37,6 +37,6 @@ void CarrotTile::registerIcons(IconRegister *iconRegister) { for (int i = 0; i < 4; i++) { - icons[i] = iconRegister->registerIcon(L"carrots_" + _toString(i)); + icons[i] = iconRegister->registerIcon(getIconName() + L"_stage_" + _toString(i)); } } \ No newline at end of file diff --git a/Minecraft.World/CauldronTile.cpp b/Minecraft.World/CauldronTile.cpp index 4d5640ca..f7a8d044 100644 --- a/Minecraft.World/CauldronTile.cpp +++ b/Minecraft.World/CauldronTile.cpp @@ -13,9 +13,9 @@ const wstring CauldronTile::TEXTURE_BOTTOM = L"cauldron_bottom"; CauldronTile::CauldronTile(int id) : Tile(id, Material::metal, isSolidRender()) { - iconInner = NULL; - iconTop = NULL; - iconBottom = NULL; + iconInner = NULL; + iconTop = NULL; + iconBottom = NULL; } Icon *CauldronTile::getTexture(int face, int data) @@ -48,19 +48,19 @@ Icon *CauldronTile::getTexture(const wstring &name) void CauldronTile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source) { - setShape(0, 0, 0, 1, 5.0f / 16.0f, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - float thickness = 2.0f / 16.0f; - setShape(0, 0, 0, thickness, 1, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - setShape(0, 0, 0, 1, 1, thickness); - Tile::addAABBs(level, x, y, z, box, boxes, source); - setShape(1 - thickness, 0, 0, 1, 1, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - setShape(0, 0, 1 - thickness, 1, 1, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - - updateDefaultShape(); + setShape(0, 0, 0, 1, 5.0f / 16.0f, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + float thickness = 2.0f / 16.0f; + setShape(0, 0, 0, thickness, 1, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(0, 0, 0, 1, 1, thickness); + Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(1 - thickness, 0, 0, 1, 1, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(0, 0, 1 - thickness, 1, 1, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + + updateDefaultShape(); } void CauldronTile::updateDefaultShape() @@ -87,43 +87,45 @@ bool CauldronTile::use(Level *level, int x, int y, int z, shared_ptr pla { if(soundOnly) return false; - if (level->isClientSide) + if (level->isClientSide) { - return true; - } + return true; + } - shared_ptr item = player->inventory->getSelected(); - if (item == NULL) + shared_ptr item = player->inventory->getSelected(); + if (item == NULL) { - return true; - } + return true; + } - int currentData = level->getData(x, y, z); + int currentData = level->getData(x, y, z); + int fillLevel = getFillLevel(currentData); - if (item->id == Item::bucket_water_Id) + if (item->id == Item::bucket_water_Id) { - if (currentData < 3) + if (fillLevel < 3) { - if (!player->abilities.instabuild) + if (!player->abilities.instabuild) { - player->inventory->setItem(player->inventory->selected, shared_ptr(new ItemInstance(Item::bucket_empty))); - } + player->inventory->setItem(player->inventory->selected, shared_ptr(new ItemInstance(Item::bucket_empty))); + } - level->setData(x, y, z, 3); - } - return true; - } + level->setData(x, y, z, 3, Tile::UPDATE_CLIENTS); + level->updateNeighbourForOutputSignal(x, y, z, id); + } + return true; + } else if (item->id == Item::glassBottle_Id) { - if (currentData > 0) + if (fillLevel > 0) { - shared_ptr potion = shared_ptr(new ItemInstance(Item::potion, 1, 0)); - if (!player->inventory->add(potion)) + shared_ptr potion = shared_ptr(new ItemInstance(Item::potion, 1, 0)); + if (!player->inventory->add(potion)) { - level->addEntity(shared_ptr(new ItemEntity(level, x + 0.5, y + 1.5, z + 0.5, potion))); - } + level->addEntity(shared_ptr(new ItemEntity(level, x + 0.5, y + 1.5, z + 0.5, potion))); + } // 4J Stu - Brought forward change to update inventory when filling bottles with water - else if (dynamic_pointer_cast( player ) != NULL) + else if (player->instanceof(eTYPE_SERVERPLAYER)) { dynamic_pointer_cast( player )->refreshContainer(player->inventoryMenu); } @@ -136,21 +138,23 @@ bool CauldronTile::use(Level *level, int x, int y, int z, shared_ptr pla player->inventory->setItem(player->inventory->selected, nullptr); } } - level->setData(x, y, z, currentData - 1); - } + level->setData(x, y, z, fillLevel - 1, Tile::UPDATE_CLIENTS); + level->updateNeighbourForOutputSignal(x, y, z, id); + } } - else if (currentData > 0) + else if (fillLevel > 0) { ArmorItem *armor = dynamic_cast(item->getItem()); if(armor && armor->getMaterial() == ArmorItem::ArmorMaterial::CLOTH) { armor->clearColor(item); - level->setData(x, y, z, currentData - 1); + level->setData(x, y, z, fillLevel - 1, Tile::UPDATE_CLIENTS); + level->updateNeighbourForOutputSignal(x, y, z, id); return true; } } - return true; + return true; } @@ -162,7 +166,7 @@ void CauldronTile::handleRain(Level *level, int x, int y, int z) if (data < 3) { - level->setData(x, y, z, data + 1); + level->setData(x, y, z, data + 1, Tile::UPDATE_CLIENTS); } } @@ -174,4 +178,21 @@ int CauldronTile::getResource(int data, Random *random, int playerBonusLevel) int CauldronTile::cloneTileId(Level *level, int x, int y, int z) { return Item::cauldron_Id; +} + +bool CauldronTile::hasAnalogOutputSignal() +{ + return true; +} + +int CauldronTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + int data = level->getData(x, y, z); + + return getFillLevel(data); +} + +int CauldronTile::getFillLevel(int data) +{ + return data; } \ No newline at end of file diff --git a/Minecraft.World/CauldronTile.h b/Minecraft.World/CauldronTile.h index 4ed3fc90..dbe5f7b8 100644 --- a/Minecraft.World/CauldronTile.h +++ b/Minecraft.World/CauldronTile.h @@ -7,12 +7,12 @@ class CauldronTile : public Tile { public: static const wstring TEXTURE_INSIDE; - static const wstring TEXTURE_BOTTOM; + static const wstring TEXTURE_BOTTOM; private: Icon *iconInner; - Icon *iconTop; - Icon *iconBottom; + Icon *iconTop; + Icon *iconBottom; public: CauldronTile(int id); @@ -30,4 +30,7 @@ public: virtual void handleRain(Level *level, int x, int y, int z); virtual int getResource(int data, Random *random, int playerBonusLevel); virtual int cloneTileId(Level *level, int x, int y, int z); + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); + static int getFillLevel(int data); }; diff --git a/Minecraft.World/CaveFeature.cpp b/Minecraft.World/CaveFeature.cpp index aad92805..698ee3da 100644 --- a/Minecraft.World/CaveFeature.cpp +++ b/Minecraft.World/CaveFeature.cpp @@ -4,35 +4,35 @@ #include "net.minecraft.world.level.tile.h" using namespace std; - bool CaveFeature::place(Level *level, Random *random, int x, int y, int z) - { - float dir = random->nextFloat() * PI; - double rd = 8; +bool CaveFeature::place(Level *level, Random *random, int x, int y, int z) +{ + float dir = random->nextFloat() * PI; + double rd = 8; - double x0 = x + 8 + Mth::sin(dir) * rd; - double x1 = x + 8 - Mth::sin(dir) * rd; - double z0 = z + 8 + Mth::cos(dir) * rd; - double z1 = z + 8 - Mth::cos(dir) * rd; + double x0 = x + 8 + Mth::sin(dir) * rd; + double x1 = x + 8 - Mth::sin(dir) * rd; + double z0 = z + 8 + Mth::cos(dir) * rd; + double z1 = z + 8 - Mth::cos(dir) * rd; - double y0 = y + random->nextInt(8) + 2; - double y1 = y + random->nextInt(8) + 2; + double y0 = y + random->nextInt(8) + 2; + double y1 = y + random->nextInt(8) + 2; - double radius = random->nextDouble() * 4 + 2; - double fuss = random->nextDouble() * 0.6; + double radius = random->nextDouble() * 4 + 2; + double fuss = random->nextDouble() * 0.6; - __int64 seed = random->nextLong(); - random->setSeed(seed); - vector toRemove; + __int64 seed = random->nextLong(); + random->setSeed(seed); + vector toRemove; - for (int d = 0; d <= 16; d++) + for (int d = 0; d <= 16; d++) { - double xx = x0 + (x1 - x0) * d / 16; - double yy = y0 + (y1 - y0) * d / 16; - double zz = z0 + (z1 - z0) * d / 16; + double xx = x0 + (x1 - x0) * d / 16; + double yy = y0 + (y1 - y0) * d / 16; + double zz = z0 + (z1 - z0) * d / 16; - double ss = random->nextDouble(); - double r = (Mth::sin(d / 16.0f * PI) * radius + 1) * ss + 1; - double hr = (Mth::sin(d / 16.0f * PI) * radius + 1) * ss + 1; + double ss = random->nextDouble(); + double r = (Mth::sin(d / 16.0f * PI) * radius + 1) * ss + 1; + double hr = (Mth::sin(d / 16.0f * PI) * radius + 1) * ss + 1; // 4J Stu Added to stop cave features generating areas previously place by game rule generation if(app.getLevelGenerationOptions() != NULL) @@ -46,47 +46,47 @@ using namespace std; } } - for (int x2 = (int) (xx - r / 2); x2 <= (int) (xx + r / 2); x2++) - for (int y2 = (int) (yy - hr / 2); y2 <= (int) (yy + hr / 2); y2++) - for (int z2 = (int) (zz - r / 2); z2 <= (int) (zz + r / 2); z2++) + for (int x2 = (int) (xx - r / 2); x2 <= (int) (xx + r / 2); x2++) + for (int y2 = (int) (yy - hr / 2); y2 <= (int) (yy + hr / 2); y2++) + for (int z2 = (int) (zz - r / 2); z2 <= (int) (zz + r / 2); z2++) { - double xd = ((x2 + 0.5) - xx) / (r / 2); - double yd = ((y2 + 0.5) - yy) / (hr / 2); - double zd = ((z2 + 0.5) - zz) / (r / 2); - if (xd * xd + yd * yd + zd * zd < random->nextDouble() * fuss + (1 - fuss)) + double xd = ((x2 + 0.5) - xx) / (r / 2); + double yd = ((y2 + 0.5) - yy) / (hr / 2); + double zd = ((z2 + 0.5) - zz) / (r / 2); + if (xd * xd + yd * yd + zd * zd < random->nextDouble() * fuss + (1 - fuss)) { - if (!level->isEmptyTile(x2, y2, z2)) + if (!level->isEmptyTile(x2, y2, z2)) { - for (int x3 = (x2 - 2); x3 <= (x2 + 1); x3++) - for (int y3 = (y2 - 1); y3 <= (y2 + 1); y3++) - for (int z3 = (z2 - 1); z3 <= (z2 + 1); z3++) + for (int x3 = (x2 - 2); x3 <= (x2 + 1); x3++) + for (int y3 = (y2 - 1); y3 <= (y2 + 1); y3++) + for (int z3 = (z2 - 1); z3 <= (z2 + 1); z3++) { - if (x3 <= x || z3 <= z || x3 >= x + 16 - 1 || z3 >= z + 16 - 1) return false; - if (level->getMaterial(x3, y3, z3)->isLiquid()) return false; - } - toRemove.push_back(new TilePos(x2, y2, z2)); - } - } - } - } - + if (x3 <= x || z3 <= z || x3 >= x + 16 - 1 || z3 >= z + 16 - 1) return false; + if (level->getMaterial(x3, y3, z3)->isLiquid()) return false; + } + toRemove.push_back(new TilePos(x2, y2, z2)); + } + } + } + } + AUTO_VAR(itEnd, toRemove.end()); for (AUTO_VAR(it, toRemove.begin()); it != itEnd; it++) { - TilePos *p = *it; //toRemove[i]; - level->setTileNoUpdate(p->x, p->y, p->z, 0); - } - + TilePos *p = *it; //toRemove[i]; + level->setTileAndData(p->x, p->y, p->z, 0, 0, Tile::UPDATE_CLIENTS); + } + itEnd = toRemove.end(); for (AUTO_VAR(it, toRemove.begin()); it != itEnd; it++) { - TilePos *p = *it; //toRemove[i]; - if (level->getTile(p->x, p->y - 1, p->z) == Tile::dirt_Id && level->getDaytimeRawBrightness(p->x, p->y, p->z) > 8) + TilePos *p = *it; //toRemove[i]; + if (level->getTile(p->x, p->y - 1, p->z) == Tile::dirt_Id && level->getDaytimeRawBrightness(p->x, p->y, p->z) > 8) { - level->setTileNoUpdate(p->x, p->y - 1, p->z, Tile::grass_Id); - } + level->setTileAndData(p->x, p->y - 1, p->z, Tile::grass_Id, 0, Tile::UPDATE_CLIENTS); + } delete p; - } + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/CaveSpider.cpp b/Minecraft.World/CaveSpider.cpp index 5f7c6028..d9396c43 100644 --- a/Minecraft.World/CaveSpider.cpp +++ b/Minecraft.World/CaveSpider.cpp @@ -1,5 +1,7 @@ #include "stdafx.h" #include "SharedConstants.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.effect.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.h" @@ -11,28 +13,23 @@ CaveSpider::CaveSpider(Level *level) : Spider(level) { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); - this->textureIdx = TN_MOB_CAVE_SPIDER; // 4J was "/mob/cavespider.png"; this->setSize(0.7f, 0.5f); } -int CaveSpider::getMaxHealth() +void CaveSpider::registerAttributes() { - return 12; -} + Spider::registerAttributes(); -float CaveSpider::getModelScale() -{ - return .7f; + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(12); } - bool CaveSpider::doHurtTarget(shared_ptr target) { if (Spider::doHurtTarget(target)) { - if ( dynamic_pointer_cast(target) != NULL) + if ( target->instanceof(eTYPE_LIVINGENTITY) ) { int poisonTime = 0; if (level->difficulty <= Difficulty::EASY) @@ -48,8 +45,9 @@ bool CaveSpider::doHurtTarget(shared_ptr target) poisonTime = 15; } - if (poisonTime > 0) { - dynamic_pointer_cast(target)->addEffect(new MobEffectInstance(MobEffect::poison->id, poisonTime * SharedConstants::TICKS_PER_SECOND, 0)); + if (poisonTime > 0) + { + dynamic_pointer_cast(target)->addEffect(new MobEffectInstance(MobEffect::poison->id, poisonTime * SharedConstants::TICKS_PER_SECOND, 0)); } } @@ -58,7 +56,8 @@ bool CaveSpider::doHurtTarget(shared_ptr target) return false; } -void CaveSpider::finalizeMobSpawn() +MobGroupData *CaveSpider::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param { // do nothing + return groupData; } \ No newline at end of file diff --git a/Minecraft.World/CaveSpider.h b/Minecraft.World/CaveSpider.h index 26f07e5f..79824e68 100644 --- a/Minecraft.World/CaveSpider.h +++ b/Minecraft.World/CaveSpider.h @@ -4,15 +4,17 @@ class CaveSpider : public Spider { - public: - eINSTANCEOF GetType() { return eTYPE_CAVESPIDER; } - static Entity *create(Level *level) { return new CaveSpider(level); } +public: + eINSTANCEOF GetType() { return eTYPE_CAVESPIDER; } + static Entity *create(Level *level) { return new CaveSpider(level); } - public: - CaveSpider(Level *level); +public: + CaveSpider(Level *level); - virtual int getMaxHealth(); - virtual float getModelScale(); - virtual bool doHurtTarget(shared_ptr target); - void finalizeMobSpawn(); +protected: + void registerAttributes(); + +public: + virtual bool doHurtTarget(shared_ptr target); + MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param }; \ No newline at end of file diff --git a/Minecraft.World/ChatPacket.cpp b/Minecraft.World/ChatPacket.cpp index 140de15d..2988962e 100644 --- a/Minecraft.World/ChatPacket.cpp +++ b/Minecraft.World/ChatPacket.cpp @@ -13,13 +13,31 @@ ChatPacket::ChatPacket() m_messageType = e_ChatCustom; } -// Old chat packet constructor, adds message, custom data and additional message to arg vectors -ChatPacket::ChatPacket(const wstring& message, EChatPacketMessage type /*= e_ChatCustom*/, int customData /*= -1*/, const wstring& additionalMessage /*= L""*/) +ChatPacket::ChatPacket(const wstring& message, EChatPacketMessage type /*= e_ChatCustom*/, int customData /*= -1*/) { m_messageType = type; if (customData != -1) m_intArgs.push_back(customData); - if (message != L"" || additionalMessage != L"") m_stringArgs.push_back(message); - if (additionalMessage != L"") m_stringArgs.push_back(additionalMessage); + + m_stringArgs.push_back(message); +} + +ChatPacket::ChatPacket(const wstring& message, EChatPacketMessage type, int sourceEntityType, const wstring& sourceName) +{ + m_messageType = type; + if (sourceEntityType != -1) m_intArgs.push_back(sourceEntityType); + + m_stringArgs.push_back(message); + m_stringArgs.push_back(sourceName); +} + +ChatPacket::ChatPacket(const wstring& message, EChatPacketMessage type, int sourceEntityType, const wstring& sourceName, const wstring& itemName) +{ + m_messageType = type; + if (sourceEntityType != -1) m_intArgs.push_back(sourceEntityType); + + m_stringArgs.push_back(message); + m_stringArgs.push_back(sourceName); + m_stringArgs.push_back(itemName); } // Read chat packet (throws IOException) @@ -56,7 +74,7 @@ void ChatPacket::write(DataOutputStream *dos) for(int i = 0; i < m_stringArgs.size(); i++) { writeUtf(m_stringArgs[i], dos); -} + } for(int i = 0; i < m_intArgs.size(); i++) { diff --git a/Minecraft.World/ChatPacket.h b/Minecraft.World/ChatPacket.h index c480dfd0..ca9e4955 100644 --- a/Minecraft.World/ChatPacket.h +++ b/Minecraft.World/ChatPacket.h @@ -5,7 +5,7 @@ using namespace std; class ChatPacket : public Packet, public enable_shared_from_this { - // longest allowed string is "<" + name + "> " + message + // longest allowed string is "<" + name + "> " + message private: static const unsigned int MAX_LENGTH; @@ -46,11 +46,32 @@ public: e_ChatDeathThrown, e_ChatDeathIndirectMagic, e_ChatDeathDragonBreath, - e_ChatDeathWither, e_ChatDeathAnvil, e_ChatDeathFallingBlock, e_ChatDeathThorns, + e_ChatDeathFellAccidentLadder, + e_ChatDeathFellAccidentVines, + e_ChatDeathFellAccidentWater, + e_ChatDeathFellAccidentGeneric, + e_ChatDeathFellKiller, + e_ChatDeathFellAssist, + e_ChatDeathFellAssistItem, + e_ChatDeathFellFinish, + e_ChatDeathFellFinishItem, + e_ChatDeathInFirePlayer, + e_ChatDeathOnFirePlayer, + e_ChatDeathLavaPlayer, + e_ChatDeathDrownPlayer, + e_ChatDeathCactusPlayer, + e_ChatDeathExplosionPlayer, + e_ChatDeathWither, + e_ChatDeathPlayerItem, + e_ChatDeathArrowItem, + e_ChatDeathFireballItem, + e_ChatDeathThrownItem, + e_ChatDeathIndirectMagicItem, + e_ChatPlayerEnteredEnd, e_ChatPlayerLeftEnd, @@ -71,6 +92,7 @@ public: e_ChatPlayerMaxBredWolves, // Tell the player they can't put this wolf in love mode because no breeding can be done e_ChatPlayerCantShearMooshroom, // Tell the player they can't shear because the limits have been reached e_ChatPlayerMaxBoats, + e_ChatPlayerMaxBats, e_ChatCommandTeleportSuccess, e_ChatCommandTeleportMe, @@ -84,7 +106,12 @@ public: EChatPacketMessage m_messageType; ChatPacket(); - ChatPacket(const wstring& message, EChatPacketMessage type = e_ChatCustom, int customData = -1, const wstring& additionalMessage = L""); + + // 4J: Seperated the one convoluted ctor into three more readable ctors. The last two ctors are only used for death messages and I'd really + // like to consolodate them and/or the logic that uses them at some point. + ChatPacket(const wstring& message, EChatPacketMessage type = e_ChatCustom, int customData = -1); + ChatPacket(const wstring& message, EChatPacketMessage type, int sourceEntityType, const wstring& sourceName); + ChatPacket(const wstring& message, EChatPacketMessage type, int sourceEntityType, const wstring& sourceName, const wstring& itemName); virtual void read(DataInputStream *dis); virtual void write(DataOutputStream *dos); diff --git a/Minecraft.World/ChestTile.cpp b/Minecraft.World/ChestTile.cpp index b7964e72..a4894c86 100644 --- a/Minecraft.World/ChestTile.cpp +++ b/Minecraft.World/ChestTile.cpp @@ -2,17 +2,19 @@ #include "net.minecraft.world.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.entity.animal.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.redstone.h" #include "net.minecraft.world.level.tile.entity.h" #include "net.minecraft.world.phys.h" #include "ChestTile.h" #include "Facing.h" -#include "Ozelot.h" -ChestTile::ChestTile(int id) : EntityTile(id, Material::wood, isSolidRender() ) +ChestTile::ChestTile(int id, int type) : BaseEntityTile(id, Material::wood, isSolidRender() ) { random = new Random(); + this->type = type; setShape(1 / 16.0f, 0, 1 / 16.0f, 15 / 16.0f, 14 / 16.0f, 15 / 16.0f); } @@ -63,150 +65,155 @@ void ChestTile::updateShape(LevelSource *level, int x, int y, int z, int forceDa void ChestTile::onPlace(Level *level, int x, int y, int z) { - EntityTile::onPlace(level, x, y, z); - recalcLockDir(level, x, y, z); - - int n = level->getTile(x, y, z - 1); // face = 2 - int s = level->getTile(x, y, z + 1); // face = 3 - int w = level->getTile(x - 1, y, z); // face = 4 - int e = level->getTile(x + 1, y, z); // face = 5 - if (n == id) recalcLockDir(level, x, y, z - 1); - if (s == id) recalcLockDir(level, x, y, z + 1); - if (w == id) recalcLockDir(level, x - 1, y, z); - if (e == id) recalcLockDir(level, x + 1, y, z); + BaseEntityTile::onPlace(level, x, y, z); + recalcLockDir(level, x, y, z); + + int n = level->getTile(x, y, z - 1); // face = 2 + int s = level->getTile(x, y, z + 1); // face = 3 + int w = level->getTile(x - 1, y, z); // face = 4 + int e = level->getTile(x + 1, y, z); // face = 5 + if (n == id) recalcLockDir(level, x, y, z - 1); + if (s == id) recalcLockDir(level, x, y, z + 1); + if (w == id) recalcLockDir(level, x - 1, y, z); + if (e == id) recalcLockDir(level, x + 1, y, z); } -void ChestTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void ChestTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { - int n = level->getTile(x, y, z - 1); // face = 2 - int s = level->getTile(x, y, z + 1); // face = 3 - int w = level->getTile(x - 1, y, z); // face = 4 - int e = level->getTile(x + 1, y, z); // face = 5 + int n = level->getTile(x, y, z - 1); // face = 2 + int s = level->getTile(x, y, z + 1); // face = 3 + int w = level->getTile(x - 1, y, z); // face = 4 + int e = level->getTile(x + 1, y, z); // face = 5 - int facing = 0; - int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3; + int facing = 0; + int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3; - if (dir == 0) facing = Facing::NORTH; - if (dir == 1) facing = Facing::EAST; - if (dir == 2) facing = Facing::SOUTH; - if (dir == 3) facing = Facing::WEST; + if (dir == 0) facing = Facing::NORTH; + if (dir == 1) facing = Facing::EAST; + if (dir == 2) facing = Facing::SOUTH; + if (dir == 3) facing = Facing::WEST; - if (n != id && s != id && w != id && e != id) + if (n != id && s != id && w != id && e != id) { - level->setData(x, y, z, facing); - } + level->setData(x, y, z, facing, Tile::UPDATE_ALL); + } else { - if ((n == id || s == id) && (facing == Facing::WEST || facing == Facing::EAST)) + if ((n == id || s == id) && (facing == Facing::WEST || facing == Facing::EAST)) { - if (n == id) level->setData(x, y, z - 1, facing); - else level->setData(x, y, z + 1, facing); - level->setData(x, y, z, facing); - } - if ((w == id || e == id) && (facing == Facing::NORTH || facing == Facing::SOUTH)) + if (n == id) level->setData(x, y, z - 1, facing, Tile::UPDATE_ALL); + else level->setData(x, y, z + 1, facing, Tile::UPDATE_ALL); + level->setData(x, y, z, facing, Tile::UPDATE_ALL); + } + if ((w == id || e == id) && (facing == Facing::NORTH || facing == Facing::SOUTH)) { - if (w == id) level->setData(x - 1, y, z, facing); - else level->setData(x + 1, y, z, facing); - level->setData(x, y, z, facing); - } - } + if (w == id) level->setData(x - 1, y, z, facing, Tile::UPDATE_ALL); + else level->setData(x + 1, y, z, facing, Tile::UPDATE_ALL); + level->setData(x, y, z, facing, Tile::UPDATE_ALL); + } + } + + if (itemInstance->hasCustomHoverName()) + { + dynamic_pointer_cast( level->getTileEntity(x, y, z))->setCustomName(itemInstance->getHoverName()); + } } void ChestTile::recalcLockDir(Level *level, int x, int y, int z) { - if (level->isClientSide) + if (level->isClientSide) { - return; - } + return; + } - int n = level->getTile(x, y, z - 1); // face = 2 - int s = level->getTile(x, y, z + 1); // face = 3 - int w = level->getTile(x - 1, y, z); // face = 4 - int e = level->getTile(x + 1, y, z); // face = 5 + int n = level->getTile(x, y, z - 1); // face = 2 + int s = level->getTile(x, y, z + 1); // face = 3 + int w = level->getTile(x - 1, y, z); // face = 4 + int e = level->getTile(x + 1, y, z); // face = 5 - // Long! - int lockDir = 4; - if (n == id || s == id) + // Long! + int lockDir = 4; + if (n == id || s == id) { - int w2 = level->getTile(x - 1, y, n == id ? z - 1 : z + 1); - int e2 = level->getTile(x + 1, y, n == id ? z - 1 : z + 1); + int w2 = level->getTile(x - 1, y, n == id ? z - 1 : z + 1); + int e2 = level->getTile(x + 1, y, n == id ? z - 1 : z + 1); - lockDir = 5; + lockDir = 5; - int otherDir = -1; - if (n == id) otherDir = level->getData(x, y, z - 1); - else otherDir = level->getData(x, y, z + 1); - if (otherDir == 4) lockDir = 4; + int otherDir = -1; + if (n == id) otherDir = level->getData(x, y, z - 1); + else otherDir = level->getData(x, y, z + 1); + if (otherDir == 4) lockDir = 4; - if ((Tile::solid[w] || Tile::solid[w2]) && !Tile::solid[e] && !Tile::solid[e2]) lockDir = 5; - if ((Tile::solid[e] || Tile::solid[e2]) && !Tile::solid[w] && !Tile::solid[w2]) lockDir = 4; - } + if ((Tile::solid[w] || Tile::solid[w2]) && !Tile::solid[e] && !Tile::solid[e2]) lockDir = 5; + if ((Tile::solid[e] || Tile::solid[e2]) && !Tile::solid[w] && !Tile::solid[w2]) lockDir = 4; + } else if (w == id || e == id) { - int n2 = level->getTile(w == id ? x - 1 : x + 1, y, z - 1); - int s2 = level->getTile(w == id ? x - 1 : x + 1, y, z + 1); - - lockDir = 3; - int otherDir = -1; - if (w == id) otherDir = level->getData(x - 1, y, z); - else otherDir = level->getData(x + 1, y, z); - if (otherDir == 2) lockDir = 2; - - if ((Tile::solid[n] || Tile::solid[n2]) && !Tile::solid[s] && !Tile::solid[s2]) lockDir = 3; - if ((Tile::solid[s] || Tile::solid[s2]) && !Tile::solid[n] && !Tile::solid[n2]) lockDir = 2; - } + int n2 = level->getTile(w == id ? x - 1 : x + 1, y, z - 1); + int s2 = level->getTile(w == id ? x - 1 : x + 1, y, z + 1); + + lockDir = 3; + int otherDir = -1; + if (w == id) otherDir = level->getData(x - 1, y, z); + else otherDir = level->getData(x + 1, y, z); + if (otherDir == 2) lockDir = 2; + + if ((Tile::solid[n] || Tile::solid[n2]) && !Tile::solid[s] && !Tile::solid[s2]) lockDir = 3; + if ((Tile::solid[s] || Tile::solid[s2]) && !Tile::solid[n] && !Tile::solid[n2]) lockDir = 2; + } else { - lockDir = 3; - if (Tile::solid[n] && !Tile::solid[s]) lockDir = 3; - if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; - if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; - if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; - } - - level->setData(x, y, z, lockDir); + lockDir = 3; + if (Tile::solid[n] && !Tile::solid[s]) lockDir = 3; + if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; + if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; + if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; + } + + level->setData(x, y, z, lockDir, Tile::UPDATE_ALL); } bool ChestTile::mayPlace(Level *level, int x, int y, int z) { - int chestCount = 0; + int chestCount = 0; - if (level->getTile(x - 1, y, z) == id) chestCount++; - if (level->getTile(x + 1, y, z) == id) chestCount++; - if (level->getTile(x, y, z - 1) == id) chestCount++; - if (level->getTile(x, y, z + 1) == id) chestCount++; + if (level->getTile(x - 1, y, z) == id) chestCount++; + if (level->getTile(x + 1, y, z) == id) chestCount++; + if (level->getTile(x, y, z - 1) == id) chestCount++; + if (level->getTile(x, y, z + 1) == id) chestCount++; - if (chestCount > 1) return false; + if (chestCount > 1) return false; - if (isFullChest(level, x - 1, y, z)) return false; - if (isFullChest(level, x + 1, y, z)) return false; - if (isFullChest(level, x, y, z - 1)) return false; - if (isFullChest(level, x, y, z + 1)) return false; - return true; + if (isFullChest(level, x - 1, y, z)) return false; + if (isFullChest(level, x + 1, y, z)) return false; + if (isFullChest(level, x, y, z - 1)) return false; + if (isFullChest(level, x, y, z + 1)) return false; + return true; } bool ChestTile::isFullChest(Level *level, int x, int y, int z) { - if (level->getTile(x, y, z) != id) return false; - if (level->getTile(x - 1, y, z) == id) return true; - if (level->getTile(x + 1, y, z) == id) return true; - if (level->getTile(x, y, z - 1) == id) return true; - if (level->getTile(x, y, z + 1) == id) return true; - return false; + if (level->getTile(x, y, z) != id) return false; + if (level->getTile(x - 1, y, z) == id) return true; + if (level->getTile(x + 1, y, z) == id) return true; + if (level->getTile(x, y, z - 1) == id) return true; + if (level->getTile(x, y, z + 1) == id) return true; + return false; } void ChestTile::neighborChanged(Level *level, int x, int y, int z, int type) { - EntityTile::neighborChanged(level, x, y, z, type); - shared_ptr(cte) = dynamic_pointer_cast(level->getTileEntity(x, y, z)); - if (cte != NULL) cte->clearCache(); + BaseEntityTile::neighborChanged(level, x, y, z, type); + shared_ptr(cte) = dynamic_pointer_cast(level->getTileEntity(x, y, z)); + if (cte != NULL) cte->clearCache(); } void ChestTile::onRemove(Level *level, int x, int y, int z, int id, int data) { - shared_ptr container = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + shared_ptr container = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); if (container != NULL ) { for (unsigned int i = 0; i < container->getContainerSize(); i++) @@ -231,10 +238,10 @@ void ChestTile::onRemove(Level *level, int x, int y, int z, int id, int data) itemEntity->xd = (float) random->nextGaussian() * pow; itemEntity->yd = (float) random->nextGaussian() * pow + 0.2f; itemEntity->zd = (float) random->nextGaussian() * pow; - if (item->hasTag()) + if (item->hasTag()) { - itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); - } + itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); + } level->addEntity(itemEntity); } @@ -243,8 +250,9 @@ void ChestTile::onRemove(Level *level, int x, int y, int z, int id, int data) container->setItem(i,nullptr); } } + level->updateNeighbourForOutputSignal(x, y, z, id); } - EntityTile::onRemove(level, x, y, z, id, data); + BaseEntityTile::onRemove(level, x, y, z, id, data); } // 4J-PB - Adding a TestUse for tooltip display @@ -258,59 +266,103 @@ bool ChestTile::use(Level *level, int x, int y, int z, shared_ptr player { if( soundOnly ) return true; - if (level->isClientSide) + if (level->isClientSide) { - return true; - } + return true; + } + shared_ptr container = getContainer(level, x, y, z); + + if (container != NULL) + { + player->openContainer(container); + } + + return true; +} + +shared_ptr ChestTile::getContainer(Level *level, int x, int y, int z) +{ + shared_ptr container = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + if (container == NULL) return nullptr; + + if (level->isSolidBlockingTile(x, y + 1, z)) return nullptr; + if (isCatSittingOnChest(level,x, y, z)) return nullptr; + + if (level->getTile(x - 1, y, z) == id && (level->isSolidBlockingTile(x - 1, y + 1, z) || isCatSittingOnChest(level, x - 1, y, z))) return nullptr; + if (level->getTile(x + 1, y, z) == id && (level->isSolidBlockingTile(x + 1, y + 1, z) || isCatSittingOnChest(level, x + 1, y, z))) return nullptr; + if (level->getTile(x, y, z - 1) == id && (level->isSolidBlockingTile(x, y + 1, z - 1) || isCatSittingOnChest(level, x, y, z - 1))) return nullptr; + if (level->getTile(x, y, z + 1) == id && (level->isSolidBlockingTile(x, y + 1, z + 1) || isCatSittingOnChest(level, x, y, z + 1))) return nullptr; + + if (level->getTile(x - 1, y, z) == id) container = shared_ptr( new CompoundContainer(IDS_CHEST_LARGE, dynamic_pointer_cast( level->getTileEntity(x - 1, y, z) ), container) ); + if (level->getTile(x + 1, y, z) == id) container = shared_ptr( new CompoundContainer(IDS_CHEST_LARGE, container, dynamic_pointer_cast( level->getTileEntity(x + 1, y, z) )) ); + if (level->getTile(x, y, z - 1) == id) container = shared_ptr( new CompoundContainer(IDS_CHEST_LARGE, dynamic_pointer_cast( level->getTileEntity(x, y, z - 1) ), container) ); + if (level->getTile(x, y, z + 1) == id) container = shared_ptr( new CompoundContainer(IDS_CHEST_LARGE, container, dynamic_pointer_cast( level->getTileEntity(x, y, z + 1) )) ); - shared_ptr container = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); - if (container == NULL) return true; + return container; +} - if (level->isSolidBlockingTile(x, y + 1, z)) return true; - if (isCatSittingOnChest(level,x, y, z)) return true; +shared_ptr ChestTile::newTileEntity(Level *level) +{ + MemSect(50); + shared_ptr retval = shared_ptr( new ChestTileEntity() ); + MemSect(0); + return retval; +} - if (level->getTile(x - 1, y, z) == id && (level->isSolidBlockingTile(x - 1, y + 1, z) || isCatSittingOnChest(level, x - 1, y, z))) return true; - if (level->getTile(x + 1, y, z) == id && (level->isSolidBlockingTile(x + 1, y + 1, z) || isCatSittingOnChest(level, x + 1, y, z))) return true; - if (level->getTile(x, y, z - 1) == id && (level->isSolidBlockingTile(x, y + 1, z - 1) || isCatSittingOnChest(level, x, y, z - 1))) return true; - if (level->getTile(x, y, z + 1) == id && (level->isSolidBlockingTile(x, y + 1, z + 1) || isCatSittingOnChest(level, x, y, z + 1))) return true; +bool ChestTile::isSignalSource() +{ + return type == TYPE_TRAP; +} - if (level->getTile(x - 1, y, z) == id) container = shared_ptr( new CompoundContainer(IDS_CHEST_LARGE, dynamic_pointer_cast( level->getTileEntity(x - 1, y, z) ), container) ); - if (level->getTile(x + 1, y, z) == id) container = shared_ptr( new CompoundContainer(IDS_CHEST_LARGE, container, dynamic_pointer_cast( level->getTileEntity(x + 1, y, z) )) ); - if (level->getTile(x, y, z - 1) == id) container = shared_ptr( new CompoundContainer(IDS_CHEST_LARGE, dynamic_pointer_cast( level->getTileEntity(x, y, z - 1) ), container) ); - if (level->getTile(x, y, z + 1) == id) container = shared_ptr( new CompoundContainer(IDS_CHEST_LARGE, container, dynamic_pointer_cast( level->getTileEntity(x, y, z + 1) )) ); +int ChestTile::getSignal(LevelSource *level, int x, int y, int z, int dir) +{ + if (!isSignalSource()) return Redstone::SIGNAL_NONE; - player->openContainer(container); + int openCount = dynamic_pointer_cast( level->getTileEntity(x, y, z))->openCount; + return Mth::clamp(openCount, Redstone::SIGNAL_NONE, Redstone::SIGNAL_MAX); +} - return true; +int ChestTile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir) +{ + if (dir == Facing::UP) + { + return getSignal(level, x, y, z, dir); + } + else + { + return Redstone::SIGNAL_NONE; + } } -// 4J-PB - added from 1.5 bool ChestTile::isCatSittingOnChest(Level *level, int x, int y, int z) { - vector > *entities = level->getEntitiesOfClass(typeid(Ozelot), AABB::newTemp(x, y + 1, z, x + 1, y + 2, z + 1)); + vector > *entities = level->getEntitiesOfClass(typeid(Ocelot), AABB::newTemp(x, y + 1, z, x + 1, y + 2, z + 1)); for(AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) { - shared_ptr ocelot = dynamic_pointer_cast(*it); + shared_ptr ocelot = dynamic_pointer_cast(*it); if(ocelot->isSitting()) { + delete entities; return true; } } - + delete entities; return false; } -shared_ptr ChestTile::newTileEntity(Level *level) +bool ChestTile::hasAnalogOutputSignal() { - MemSect(50); - shared_ptr retval = shared_ptr( new ChestTileEntity() ); - MemSect(0); - return retval; + return true; +} + +int ChestTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + return AbstractContainerMenu::getRedstoneSignalFromContainer(getContainer(level, x, y, z)); } void ChestTile::registerIcons(IconRegister *iconRegister) { // Register wood as the chest's icon, because it's used by the particles // when destroying the chest - icon = iconRegister->registerIcon(L"wood"); + icon = iconRegister->registerIcon(L"planks_oak"); } diff --git a/Minecraft.World/ChestTile.h b/Minecraft.World/ChestTile.h index ee2185cb..4fefeea9 100644 --- a/Minecraft.World/ChestTile.h +++ b/Minecraft.World/ChestTile.h @@ -1,38 +1,60 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" #include "Material.h" class Player; class Random; -class ChestTile : public EntityTile +class ChestTile : public BaseEntityTile { friend class Tile; + friend class Minecraft; + public: + static const int TYPE_BASIC = 0; + static const int TYPE_TRAP = 1; + static const int EVENT_SET_OPEN_COUNT = 1; + private: Random *random; + +public: + int type; + protected: - ChestTile(int id); + ChestTile(int id, int type); ~ChestTile(); + public: virtual bool isSolidRender(bool isServerLevel = false); virtual bool isCubeShaped(); virtual int getRenderShape(); virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity = shared_ptr()); virtual void onPlace(Level *level, int x, int y, int z); - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); void recalcLockDir(Level *level, int x, int y, int z); - virtual bool mayPlace(Level *level, int x, int y, int z); + virtual bool mayPlace(Level *level, int x, int y, int z); + private: bool isFullChest(Level *level, int x, int y, int z); - bool isCatSittingOnChest(Level *level, int x, int y, int z); + public: virtual void neighborChanged(Level *level, int x, int y, int z, int type); virtual void onRemove(Level *level, int x, int y, int z, int id, int data); virtual bool TestUse(); virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - shared_ptr newTileEntity(Level *level); - //@Override - void registerIcons(IconRegister *iconRegister); + virtual shared_ptr getContainer(Level *level, int x, int y, int z); + virtual shared_ptr newTileEntity(Level *level); + virtual bool isSignalSource(); + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); + virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir); + +private: + bool isCatSittingOnChest(Level *level, int x, int y, int z); + +public: + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); + virtual void registerIcons(IconRegister *iconRegister); }; \ No newline at end of file diff --git a/Minecraft.World/ChestTileEntity.cpp b/Minecraft.World/ChestTileEntity.cpp index 406b81b5..39f957bd 100644 --- a/Minecraft.World/ChestTileEntity.cpp +++ b/Minecraft.World/ChestTileEntity.cpp @@ -1,19 +1,25 @@ -using namespace std; - #include "stdafx.h" #include "com.mojang.nbt.h" +#include "net.minecraft.world.h" #include "net.minecraft.world.level.h" #include "TileEntity.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.inventory.h" #include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" #include "ChestTileEntity.h" +#include "ContainerOpenPacket.h" #include "SoundTypes.h" +int ChestTileEntity::getContainerType() +{ + if (isBonusChest) return ContainerOpenPacket::BONUS_CHEST; + else return ContainerOpenPacket::CONTAINER; +} - -ChestTileEntity::ChestTileEntity(bool isBonusChest/* = false*/) : TileEntity() +void ChestTileEntity::_init(bool isBonusChest) { items = new ItemInstanceArray(9 * 4); @@ -24,6 +30,21 @@ ChestTileEntity::ChestTileEntity(bool isBonusChest/* = false*/) : TileEntity() oOpenness = 0.0f; openCount = 0; tickInterval = 0; + + type = -1; + name = L""; +} + +ChestTileEntity::ChestTileEntity(bool isBonusChest/* = false*/) : TileEntity() +{ + _init(isBonusChest); +} + +ChestTileEntity::ChestTileEntity(int type, bool isBonusChest/* = false*/) : TileEntity() +{ + _init(isBonusChest); + + this->type = type; } ChestTileEntity::~ChestTileEntity() @@ -50,7 +71,7 @@ shared_ptr ChestTileEntity::removeItem(unsigned int slot, int coun { shared_ptr item = items->data[slot]; items->data[slot] = nullptr; - this->setChanged(); + setChanged(); // 4J Stu - Fix for duplication glitch if(item->count <= 0) return nullptr; return item; @@ -59,7 +80,7 @@ shared_ptr ChestTileEntity::removeItem(unsigned int slot, int coun { shared_ptr i = items->data[slot]->remove(count); if (items->data[slot]->count == 0) items->data[slot] = nullptr; - this->setChanged(); + setChanged(); // 4J Stu - Fix for duplication glitch if(i->count <= 0) return nullptr; return i; @@ -86,11 +107,25 @@ void ChestTileEntity::setItem(unsigned int slot, shared_ptr item) this->setChanged(); } -int ChestTileEntity::getName() +wstring ChestTileEntity::getName() +{ + return hasCustomName() ? name : app.GetString(IDS_TILE_CHEST); +} + +wstring ChestTileEntity::getCustomName() { - return IDS_TILE_CHEST; + return hasCustomName() ? name : L""; } +bool ChestTileEntity::hasCustomName() +{ + return !name.empty(); +} + +void ChestTileEntity::setCustomName(const wstring &name) +{ + this->name = name; +} void ChestTileEntity::load(CompoundTag *base) { @@ -102,6 +137,7 @@ void ChestTileEntity::load(CompoundTag *base) delete items; } items = new ItemInstanceArray(getContainerSize()); + if (base->contains(L"CustomName")) name = base->getString(L"CustomName"); for (int i = 0; i < inventoryList->size(); i++) { CompoundTag *tag = inventoryList->get(i); @@ -127,6 +163,7 @@ void ChestTileEntity::save(CompoundTag *base) } } base->put(L"Items", listTag); + if (hasCustomName()) base->putString(L"CustomName", name); base->putBoolean(L"bonus", isBonusChest); } @@ -149,127 +186,217 @@ void ChestTileEntity::setChanged() void ChestTileEntity::clearCache() { - TileEntity::clearCache(); - hasCheckedNeighbors = false; + TileEntity::clearCache(); + hasCheckedNeighbors = false; +} + +void ChestTileEntity::heyImYourNeighbor(shared_ptr neighbor, int from) +{ + if (neighbor->isRemoved()) + { + hasCheckedNeighbors = false; + } + else if (hasCheckedNeighbors) + { + switch (from) + { + case Direction::NORTH: + if (n.lock() != neighbor) hasCheckedNeighbors = false; + break; + case Direction::SOUTH: + if (s.lock() != neighbor) hasCheckedNeighbors = false; + break; + case Direction::EAST: + if (e.lock() != neighbor) hasCheckedNeighbors = false; + break; + case Direction::WEST: + if (w.lock() != neighbor) hasCheckedNeighbors = false; + break; + } + } } void ChestTileEntity::checkNeighbors() { - if (hasCheckedNeighbors) return; + if (hasCheckedNeighbors) return; - hasCheckedNeighbors = true; - n = weak_ptr(); - e = weak_ptr(); - w = weak_ptr(); - s = weak_ptr(); + hasCheckedNeighbors = true; + n = weak_ptr(); + e = weak_ptr(); + w = weak_ptr(); + s = weak_ptr(); - if (level->getTile(x - 1, y, z) == Tile::chest_Id) + if (isSameChest(x - 1, y, z)) { - w = dynamic_pointer_cast(level->getTileEntity(x - 1, y, z)); - } - if (level->getTile(x + 1, y, z) == Tile::chest_Id) + w = dynamic_pointer_cast(level->getTileEntity(x - 1, y, z)); + } + if (isSameChest(x + 1, y, z)) { - e = dynamic_pointer_cast(level->getTileEntity(x + 1, y, z)); - } - if (level->getTile(x, y, z - 1) == Tile::chest_Id) + e = dynamic_pointer_cast(level->getTileEntity(x + 1, y, z)); + } + if (isSameChest(x, y, z - 1)) { - n = dynamic_pointer_cast(level->getTileEntity(x, y, z - 1)); - } - if (level->getTile(x, y, z + 1) == Tile::chest_Id) + n = dynamic_pointer_cast(level->getTileEntity(x, y, z - 1)); + } + if (isSameChest(x, y, z + 1)) { - s = dynamic_pointer_cast(level->getTileEntity(x, y, z + 1)); - } + s = dynamic_pointer_cast(level->getTileEntity(x, y, z + 1)); + } - if (n.lock() != NULL) n.lock()->clearCache(); - if (s.lock() != NULL) s.lock()->clearCache(); - if (e.lock() != NULL) e.lock()->clearCache(); - if (w.lock() != NULL) w.lock()->clearCache(); + shared_ptr cteThis = dynamic_pointer_cast(shared_from_this()); + if (n.lock() != NULL) n.lock()->heyImYourNeighbor(cteThis, Direction::SOUTH); + if (s.lock() != NULL) s.lock()->heyImYourNeighbor(cteThis, Direction::NORTH); + if (e.lock() != NULL) e.lock()->heyImYourNeighbor(cteThis, Direction::WEST); + if (w.lock() != NULL) w.lock()->heyImYourNeighbor(cteThis, Direction::EAST); +} + +bool ChestTileEntity::isSameChest(int x, int y, int z) +{ + Tile *tile = Tile::tiles[level->getTile(x, y, z)]; + if (tile == NULL || !(dynamic_cast(tile) != NULL)) return false; + return ((ChestTile *) tile)->type == getType(); } void ChestTileEntity::tick() { - TileEntity::tick(); - checkNeighbors(); + TileEntity::tick(); + checkNeighbors(); - if (++tickInterval % 20 * 4 == 0) + ++tickInterval; + if (!level->isClientSide && openCount != 0 && (tickInterval + x + y + z) % (SharedConstants::TICKS_PER_SECOND * 10) == 0) { - //level->tileEvent(x, y, z, ChestTile::EVENT_SET_OPEN_COUNT, openCount); - } + // level.tileEvent(x, y, z, Tile.chest.id, ChestTile.EVENT_SET_OPEN_COUNT, openCount); - oOpenness = openness; + openCount = 0; - float speed = 0.10f; - if (openCount > 0 && openness == 0) + float range = 5; + vector > *players = level->getEntitiesOfClass(typeid(Player), AABB::newTemp(x - range, y - range, z - range, x + 1 + range, y + 1 + range, z + 1 + range)); + for (AUTO_VAR(it,players->begin()); it != players->end(); ++it) + { + shared_ptr player = dynamic_pointer_cast(*it); + + ContainerMenu *containerMenu = dynamic_cast(player->containerMenu); + if (containerMenu != NULL) + { + shared_ptr container = containerMenu->getContainer(); + shared_ptr thisContainer = dynamic_pointer_cast(shared_from_this()); + shared_ptr compoundContainer = dynamic_pointer_cast( container ); + if ( (container == thisContainer) || (compoundContainer != NULL && compoundContainer->contains(thisContainer)) ) + { + openCount++; + } + } + } + delete players; + } + + oOpenness = openness; + + float speed = 0.10f; + if (openCount > 0 && openness == 0) { - if (n.lock() == NULL && w.lock() == NULL) + if (n.lock() == NULL && w.lock() == NULL) { - double xc = x + 0.5; - double zc = z + 0.5; - if (s.lock() != NULL) zc += 0.5; - if (e.lock() != NULL) xc += 0.5; + double xc = x + 0.5; + double zc = z + 0.5; + if (s.lock() != NULL) zc += 0.5; + if (e.lock() != NULL) xc += 0.5; // 4J-PB - Seems the chest open volume is much louder than other sounds from user reports. We'll tone it down a bit - level->playSound(xc, y + 0.5, zc, eSoundType_RANDOM_CHEST_OPEN, 0.2f, level->random->nextFloat() * 0.1f + 0.9f); - } - } - if ((openCount == 0 && openness > 0) || (openCount > 0 && openness < 1)) + level->playSound(xc, y + 0.5, zc, eSoundType_RANDOM_CHEST_OPEN, 0.2f, level->random->nextFloat() * 0.1f + 0.9f); + } + } + if ((openCount == 0 && openness > 0) || (openCount > 0 && openness < 1)) { float oldOpen = openness; - if (openCount > 0) openness += speed; - else openness -= speed; - if (openness > 1) + if (openCount > 0) openness += speed; + else openness -= speed; + if (openness > 1) { - openness = 1; - } + openness = 1; + } float lim = 0.5f; - if (openness < lim && oldOpen >= lim) + if (openness < lim && oldOpen >= lim) { // Fix for #64546 - Customer Encountered: TU7: Chests placed by the Player are closing too fast. - //openness = 0; - if (n.lock() == NULL && w.lock() == NULL) + //openness = 0; + if (n.lock() == NULL && w.lock() == NULL) { - double xc = x + 0.5; - double zc = z + 0.5; - if (s.lock() != NULL) zc += 0.5; - if (e.lock() != NULL) xc += 0.5; + double xc = x + 0.5; + double zc = z + 0.5; + if (s.lock() != NULL) zc += 0.5; + if (e.lock() != NULL) xc += 0.5; // 4J-PB - Seems the chest open volume is much louder than other sounds from user reports. We'll tone it down a bit - level->playSound(xc, y + 0.5, zc, eSoundType_RANDOM_CHEST_CLOSE, 0.2f, level->random->nextFloat() * 0.1f + 0.9f); - } + level->playSound(xc, y + 0.5, zc, eSoundType_RANDOM_CHEST_CLOSE, 0.2f, level->random->nextFloat() * 0.1f + 0.9f); + } } - if (openness < 0) + if (openness < 0) { - openness = 0; - } - } + openness = 0; + } + } } -void ChestTileEntity::triggerEvent(int b0, int b1) +bool ChestTileEntity::triggerEvent(int b0, int b1) { - if (b0 == ChestTile::EVENT_SET_OPEN_COUNT) + if (b0 == ChestTile::EVENT_SET_OPEN_COUNT) { - openCount = b1; - } + openCount = b1; + return true; + } + return TileEntity::triggerEvent(b0, b1); } void ChestTileEntity::startOpen() { + if (openCount < 0) + { + openCount = 0; + } openCount++; - level->tileEvent(x, y, z, Tile::chest_Id, ChestTile::EVENT_SET_OPEN_COUNT, openCount); + level->tileEvent(x, y, z, getTile()->id, ChestTile::EVENT_SET_OPEN_COUNT, openCount); + level->updateNeighborsAt(x, y, z, getTile()->id); + level->updateNeighborsAt(x, y - 1, z, getTile()->id); } void ChestTileEntity::stopOpen() { + if (getTile() == NULL || !( dynamic_cast( getTile() ) != NULL)) return; openCount--; - level->tileEvent(x, y, z, Tile::chest_Id, ChestTile::EVENT_SET_OPEN_COUNT, openCount); + level->tileEvent(x, y, z, getTile()->id, ChestTile::EVENT_SET_OPEN_COUNT, openCount); + level->updateNeighborsAt(x, y, z, getTile()->id); + level->updateNeighborsAt(x, y - 1, z, getTile()->id); +} + +bool ChestTileEntity::canPlaceItem(int slot, shared_ptr item) +{ + return true; } void ChestTileEntity::setRemoved() { - clearCache(); - checkNeighbors(); - TileEntity::setRemoved(); + TileEntity::setRemoved(); + clearCache(); + checkNeighbors(); +} + +int ChestTileEntity::getType() +{ + if (type == -1) + { + if (level != NULL && dynamic_cast( getTile() ) != NULL) + { + type = ((ChestTile *) getTile())->type; + } + else + { + return ChestTile::TYPE_BASIC; + } + } + + return type; } // 4J Added diff --git a/Minecraft.World/ChestTileEntity.h b/Minecraft.World/ChestTileEntity.h index 5eeb3c44..77c11e99 100644 --- a/Minecraft.World/ChestTileEntity.h +++ b/Minecraft.World/ChestTileEntity.h @@ -16,10 +16,16 @@ public: eINSTANCEOF GetType() { return eTYPE_CHESTTILEENTITY; } static TileEntity *create() { return new ChestTileEntity(); } -using TileEntity::setChanged; + int getContainerType(); // 4J-Added; + + using TileEntity::setChanged; + +private: + void _init(bool isBonusChest); public: ChestTileEntity(bool isBonusChest = false); // 4J added param + ChestTileEntity(int type, bool isBonusChest = false); // 4J added param virtual ~ChestTileEntity(); private: @@ -28,35 +34,53 @@ private: public: bool isBonusChest; // 4J added bool hasCheckedNeighbors; - weak_ptr n; - weak_ptr e; - weak_ptr w; - weak_ptr s; + weak_ptr n; + weak_ptr e; + weak_ptr w; + weak_ptr s; float openness, oOpenness; int openCount; private: int tickInterval; + int type; + wstring name; + public: virtual unsigned int getContainerSize(); virtual shared_ptr getItem(unsigned int slot); virtual shared_ptr removeItem(unsigned int slot, int count); virtual shared_ptr removeItemNoUpdate(int slot); virtual void setItem(unsigned int slot, shared_ptr item); - virtual int getName(); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual bool hasCustomName(); + virtual void setCustomName(const wstring &name); virtual void load(CompoundTag *base); virtual void save(CompoundTag *base); virtual int getMaxStackSize(); virtual bool stillValid(shared_ptr player); virtual void setChanged(); virtual void clearCache(); - virtual void checkNeighbors(); - virtual void tick(); - virtual void triggerEvent(int b0, int b1); - virtual void startOpen(); - virtual void stopOpen(); - virtual void setRemoved(); + +private: + virtual void heyImYourNeighbor(shared_ptr neighbor, int from); + +public: + virtual void checkNeighbors(); + +private: + bool isSameChest(int x, int y, int z); + +public: + virtual void tick(); + virtual bool triggerEvent(int b0, int b1); + virtual void startOpen(); + virtual void stopOpen(); + virtual bool canPlaceItem(int slot, shared_ptr item); + virtual void setRemoved(); + virtual int getType(); // 4J Added virtual shared_ptr clone(); diff --git a/Minecraft.World/Chicken.cpp b/Minecraft.World/Chicken.cpp index 0104b2bf..5f4cf2a7 100644 --- a/Minecraft.World/Chicken.cpp +++ b/Minecraft.World/Chicken.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "com.mojang.nbt.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.goal.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.level.h" @@ -24,22 +26,19 @@ Chicken::Chicken(Level *level) : Animal( level ) { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); + setHealth(getMaxHealth()); _init(); - this->textureIdx = TN_MOB_CHICKEN; // 4J - was L"/mob/chicken.png"; - this->setSize(0.3f, 0.7f); // 4J Changed from 0.4 to 0.7 in 1.8.2 + setSize(0.3f, 0.7f); // 4J Changed from 0.4 to 0.7 in 1.8.2 eggTime = random->nextInt(20 * 60 * 5) + 20 * 60 * 5; - float walkSpeed = 0.25f; goalSelector.addGoal(0, new FloatGoal(this)); - goalSelector.addGoal(1, new PanicGoal(this, 0.38f)); - goalSelector.addGoal(2, new BreedGoal(this, walkSpeed)); - goalSelector.addGoal(3, new TemptGoal(this, 0.25f, Item::seeds_wheat_Id, false)); - goalSelector.addGoal(4, new FollowParentGoal(this, 0.28f)); - goalSelector.addGoal(5, new RandomStrollGoal(this, walkSpeed)); + goalSelector.addGoal(1, new PanicGoal(this, 1.4)); + goalSelector.addGoal(2, new BreedGoal(this, 1.0)); + goalSelector.addGoal(3, new TemptGoal(this, 1.0, Item::seeds_wheat_Id, false)); + goalSelector.addGoal(4, new FollowParentGoal(this, 1.1)); + goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 6)); goalSelector.addGoal(7, new RandomLookAroundGoal(this)); } @@ -49,9 +48,12 @@ bool Chicken::useNewAi() return true; } -int Chicken::getMaxHealth() +void Chicken::registerAttributes() { - return 4; + Animal::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(4); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f); } void Chicken::aiStep() @@ -79,7 +81,7 @@ void Chicken::aiStep() { if (!level->isClientSide && --eggTime <= 0) { - level->playSound(shared_from_this(), eSoundType_MOB_CHICKENPLOP, 1.0f, (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); + playSound( eSoundType_MOB_CHICKENPLOP, 1.0f, (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); spawnAtLocation(Item::egg->id, 1); eggTime = random->nextInt(20 * 60 * 5) + 20 * 60 * 5; } @@ -107,6 +109,11 @@ int Chicken::getDeathSound() return eSoundType_MOB_CHICKEN_HURT; } +void Chicken::playStepSound(int xt, int yt, int zt, int t) +{ + playSound(eSoundType_MOB_CHICKEN_STEP, 0.15f, 1); +} + int Chicken::getDeathLoot() { return Item::feather->id; @@ -146,5 +153,5 @@ shared_ptr Chicken::getBreedOffspring(shared_ptr target) bool Chicken::isFood(shared_ptr itemInstance) { - return (itemInstance->id == Item::seeds_wheat_Id) || (itemInstance->id == Item::netherStalkSeeds_Id) || (itemInstance->id == Item::seeds_melon_Id) || (itemInstance->id == Item::seeds_pumpkin_Id); + return (itemInstance->id == Item::seeds_wheat_Id) || (itemInstance->id == Item::netherwart_seeds_Id) || (itemInstance->id == Item::seeds_melon_Id) || (itemInstance->id == Item::seeds_pumpkin_Id); } diff --git a/Minecraft.World/Chicken.h b/Minecraft.World/Chicken.h index a162a5eb..0f406219 100644 --- a/Minecraft.World/Chicken.h +++ b/Minecraft.World/Chicken.h @@ -24,7 +24,11 @@ private: public: Chicken(Level *level); virtual bool useNewAi(); - virtual int getMaxHealth(); + +protected: + void registerAttributes(); + +public: virtual void aiStep(); protected: @@ -32,6 +36,7 @@ protected: virtual int getAmbientSound(); virtual int getHurtSound(); virtual int getDeathSound(); + virtual void playStepSound(int xt, int yt, int zt, int t); virtual int getDeathLoot(); virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); diff --git a/Minecraft.World/ChunkSource.h b/Minecraft.World/ChunkSource.h index 242f30a0..c537651c 100644 --- a/Minecraft.World/ChunkSource.h +++ b/Minecraft.World/ChunkSource.h @@ -8,16 +8,30 @@ class TilePos; #ifdef _LARGE_WORLDS // 4J Stu - Our default map (at zoom level 3) is 1024x1024 blocks (or 64 chunks) #define LEVEL_MAX_WIDTH (5*64) //(6*54) + +#define LEVEL_WIDTH_CLASSIC 54 +#define LEVEL_WIDTH_SMALL 64 +#define LEVEL_WIDTH_MEDIUM (3*64) +#define LEVEL_WIDTH_LARGE (5*64) + #else #define LEVEL_MAX_WIDTH 54 #endif #define LEVEL_MIN_WIDTH 54 #define LEVEL_LEGACY_WIDTH 54 + + // Scale was 8 in the Java game, but that would make our nether tiny // Every 1 block you move in the nether maps to HELL_LEVEL_SCALE blocks in the overworld #ifdef _LARGE_WORLDS #define HELL_LEVEL_MAX_SCALE 8 + +#define HELL_LEVEL_SCALE_CLASSIC 3 +#define HELL_LEVEL_SCALE_SMALL 3 +#define HELL_LEVEL_SCALE_MEDIUM 6 +#define HELL_LEVEL_SCALE_LARGE 8 + #else #define HELL_LEVEL_MAX_SCALE 3 #endif @@ -39,29 +53,42 @@ class ChunkSource public: // 4J Added so that we can store the maximum dimensions of this world int m_XZSize; +#ifdef _LARGE_WORLDS + bool m_classicEdgeMoat; + bool m_smallEdgeMoat; + bool m_mediumEdgeMoat; +#endif public: virtual ~ChunkSource() {} - virtual bool hasChunk(int x, int y) = 0; + virtual bool hasChunk(int x, int y) = 0; virtual bool reallyHasChunk(int x, int y) { return hasChunk(x,y); } // 4J added - virtual LevelChunk *getChunk(int x, int z) = 0; + virtual LevelChunk *getChunk(int x, int z) = 0; virtual void lightChunk(LevelChunk *lc) {} // 4J added - virtual LevelChunk *create(int x, int z) = 0; - virtual void postProcess(ChunkSource *parent, int x, int z) = 0; + virtual LevelChunk *create(int x, int z) = 0; + virtual void postProcess(ChunkSource *parent, int x, int z) = 0; virtual bool saveAllEntities() { return false; } // 4J Added - virtual bool save(bool force, ProgressListener *progressListener) = 0; - virtual bool tick() = 0; - virtual bool shouldSave() = 0; + virtual bool save(bool force, ProgressListener *progressListener) = 0; + virtual bool tick() = 0; + virtual bool shouldSave() = 0; virtual LevelChunk **getCache() { return NULL; } // 4J added virtual void dataReceived(int x, int z) {} // 4J added - /** - * Returns some stats that are rendered when the user holds F3. - */ - virtual wstring gatherStats() = 0; + /** + * Returns some stats that are rendered when the user holds F3. + */ + virtual wstring gatherStats() = 0; virtual vector *getMobsAt(MobCategory *mobCategory, int x, int y, int z) = 0; - virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z) = 0; + virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z) = 0; + + /** + * Recreates "logic structures" for a chunk that has been loaded from disk. + * For example, fortress bridges in the Nether. + */ + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ) = 0; + + // virtual void flushSave() = 0; // 4J removed }; diff --git a/Minecraft.World/Class.h b/Minecraft.World/Class.h index 5dbbf965..31fc4dad 100644 --- a/Minecraft.World/Class.h +++ b/Minecraft.World/Class.h @@ -7,117 +7,244 @@ class InputStream; // simplify declaring classes with this added functionality. +// 0b FFFF CCCC CCCC CCCC CCCC CCCC CCEE EEEE +// |||| |||| |||| |||| |||| |||| |||| |||| +// |||| |||| |||| |||| |||| |||| |||| |||\- BIT00: ENUM: +// |||| |||| |||| |||| |||| |||| |||| ||\-- BIT01: ENUM: +// |||| |||| |||| |||| |||| |||| |||| |\--- BIT02: ENUM: +// |||| |||| |||| |||| |||| |||| |||| \---- BIT03: ENUM: +// |||| |||| |||| |||| |||| |||| |||| +// |||| |||| |||| |||| |||| |||| |||\------ BIT04: ENUM: +// |||| |||| |||| |||| |||| |||| ||\------- BIT05: ENUM: +// |||| |||| |||| |||| |||| |||| |\-------- BIT06: CLASS: WATER_MOB +// |||| |||| |||| |||| |||| |||| \--------- BIT07: CLASS: AMBIENT_MOB +// |||| |||| |||| |||| |||| |||| +// |||| |||| |||| |||| |||| |||\----------- BIT08: CLASS: !ENTITY (so we can hide TILE_ENTITY and DISPENSER_TILE_ENTITY bits which aren't relevant for entities) +// |||| |||| |||| |||| |||| ||\------------ BIT09: CLASS: MINECART_CONTAINER +// |||| |||| |||| |||| |||| |\------------- BIT10: CLASS: SLIME +// |||| |||| |||| |||| |||| \-------------- BIT11: CLASS: ZOMBIE +// |||| |||| |||| |||| |||| +// |||| |||| |||| |||| |||\---------------- BIT12: CLASS: SPIDER +// |||| |||| |||| |||| ||\----------------- BIT13: CLASS: COW +// |||| |||| |||| |||| |\------------------ BIT14: CLASS: TAMABLE +// |||| |||| |||| |||| \------------------- BIT15: CLASS: ANIMAL +// |||| |||| |||| |||| +// |||| |||| |||| |||\--------------------- BIT16: CLASS: MONSTER +// |||| |||| |||| ||\---------------------- BIT17: CLASS: GOLEM +// |||| |||| |||| |\----------------------- BIT18: CLASS: AGABLE_MOB +// |||| |||| |||| \------------------------ BIT19: CLASS: PATHFINDER_MOB +// |||| |||| |||| +// |||| |||| |||\-------------------------- BIT20: CLASS: PLAYER +// |||| |||| ||\--------------------------- BIT21: CLASS: MOB +// |||| |||| |\---------------------------- BIT22: CLASS: HANGING_ENTITY +// |||| |||| \----------------------------- BIT23: CLASS: THROWABLE +// |||| |||| +// |||| |||\------------------------------- BIT24: CLASS: FIREBALL +// |||| ||\-------------------------------- BIT25: CLASS: MINECART +// |||| |\--------------------------------- BIT26: CLASS: LIVING_ENTITY +// |||| \---------------------------------- BIT27: CLASS: ENTITY +// |||| +// |||\------------------------------------ BIT28: FLAGS: valid in spawner flag +// ||\------------------------------------- BIT29: FLAGS: Spawnlimitcheck +// |\-------------------------------------- BIT30: FLAGS: Enemy +// \--------------------------------------- BIT31: FLAGS: projectile + + +#define Bit(a) ((1)<<(a)) + +const unsigned int BIT_NOT_LIVING_ENTITY = Bit(25); + +// Classes + +const unsigned int BIT_FLYING_MOB = Bit( 9); +const unsigned int BIT_WATER_MOB = Bit(10); +const unsigned int BIT_AMBIENT_MOB = Bit(11); + +const unsigned int BIT_NOT_ENTITY = Bit(12); +const unsigned int BIT_SLIME = Bit(13); +const unsigned int BIT_ZOMBIE = Bit(14); +const unsigned int BIT_SPIDER = Bit(15); + +const unsigned int BIT_COW = Bit(16); +const unsigned int BIT_TAMABLE = Bit(17); +const unsigned int BIT_ANIMAL = Bit(18); +const unsigned int BIT_MONSTER = Bit(19); const unsigned int BIT_MINECART_CONTAINER = Bit(19) | BIT_NOT_LIVING_ENTITY; + +const unsigned int BIT_GOLEM = Bit(20); const unsigned int BIT_HANGING_ENTITY = Bit(20) | BIT_NOT_LIVING_ENTITY; +const unsigned int BIT_AGABLE_MOB = Bit(21); const unsigned int BIT_THROWABLE = Bit(21) | BIT_NOT_LIVING_ENTITY; +const unsigned int BIT_PATHFINDER_MOB = Bit(22); const unsigned int BIT_FIREBALL = Bit(22) | BIT_NOT_LIVING_ENTITY; +const unsigned int BIT_PLAYER = Bit(23); const unsigned int BIT_MINECART = Bit(23) | BIT_NOT_LIVING_ENTITY; + +const unsigned int BIT_MOB = Bit(24); const unsigned int BIT_GLOBAL_ENTITY = Bit(24) | BIT_NOT_LIVING_ENTITY; +//const unsigned int BIT_NOT_LIVING_ENTITY = Bit(25); +const unsigned int BIT_LIVING_ENTITY = Bit(26); +const unsigned int BIT_ENTITY = Bit(27); + +// Flags +const unsigned int BIT_VALID_IN_SPAWNER = Bit(28); +const unsigned int BIT_ANIMALS_SPAWN_LIMIT_CHECK = Bit(29); +const unsigned int BIT_ENEMY = Bit(30); +const unsigned int BIT_PROJECTILE = Bit(31U); + +// Tile Entities +const unsigned int BIT_TILE_ENTITY = Bit(24) | BIT_NOT_ENTITY; +const unsigned int BIT_DISPENSERTILEENTITY = Bit(25) | BIT_NOT_ENTITY; +const unsigned int BIT_OTHER_NOT_ENTITIES = Bit(26) | BIT_NOT_ENTITY; + + +// 4J-JEV: These abstract classes only have one subclass, so ignore them. +//const unsigned int BIT_WATER_MOB = Bit(15); +//const unsigned int BIT_FLYING_MOB = Bit(17); +//const unsigned int BIT_AMBIENT_MOB = Bit(18); +//const unsigned int BIT_GLOBAL_ENTITY = Bit(); + +// #define ETYPE(a,b,c) ( (a) | (b) | (c) ) + // 4J Stu - This Enum can be used as a more lightweight version of the above, without having do dynamic casts // 4J-PB - for replacement of instanceof enum eINSTANCEOF { eTYPE_NOTSET=0, + + // Flags. + eTYPE_VALID_IN_SPAWNER_FLAG = BIT_VALID_IN_SPAWNER, + eTYPE_ANIMALS_SPAWN_LIMIT_CHECK = BIT_ANIMALS_SPAWN_LIMIT_CHECK, + eTYPE_ENEMY = BIT_ENEMY, + eTYPE_PROJECTILE = BIT_PROJECTILE, - // 4J-RR arranging these pathfinder types in a bitfield fashion so that a single and can determine whether they are derived from - // the 3 subclasses of pathfinders (water animals, animals, and monsters) that the mob spawner uses - eTYPE_WATERANIMAL = 0x100, - eTYPE_SQUID = 0x101, - - eTYPE_ANIMAL = 0x200, - - // 4J Stu - These have the ANIMAL, AGABLE_MOB and ANIMALS_SPAWN_LIMIT_CHECK bits set - eTYPE_COW = 0x82201, - eTYPE_SHEEP = 0x82202, - eTYPE_PIG = 0x82203, - eTYPE_SNOWMAN = 0x82204, - eTYPE_OZELOT = 0x82205, - - // 4J Stu - When adding new categories, please also update ConsoleSchematicFile::generateSchematicFile so these can be saved out to schematics - // 4J Stu- These have the ANIMAL and AGABLE_MOB bits set, but NOT ANIMALS_SPAWN_LIMIT_CHECK - eTYPE_CHICKEN = 0x2206, - eTYPE_WOLF = 0x2207, - eTYPE_MUSHROOMCOW = 0x2208, - - // 4J Stu - If you add new hostile mobs here you should also update the string lookup function at CConsoleMinecraftApp::getEntityName - eTYPE_MONSTER = 0x400, - eTYPE_ENEMY = 0x800, - eTYPE_CREEPER = 0xC01, - eTYPE_GIANT = 0xC02, - eTYPE_SKELETON = 0xC03, - eTYPE_SPIDER = 0xC04, - eTYPE_ZOMBIE = 0xC05, - eTYPE_PIGZOMBIE = 0xC06, - eTYPE_ENDERMAN = 0xC07, - eTYPE_SILVERFISH = 0xC08, - eTYPE_CAVESPIDER = 0xC09, - eTYPE_BLAZE = 0xC0A, - - eTYPE_GHAST = 0xC0B, // Now considering as a monster even though class inheritance doesn't work like this - but otherwise breaks mob spawning - eTYPE_SLIME = 0xC0C, // Now considering as a monster even though class inheritance doesn't work like this - but otherwise breaks mob spawning - eTYPE_LAVASLIME = 0xC0D, - - eTYPE_VILLAGERGOLEM = 0x1000, - - eTYPE_AGABLE_MOB = 0x2000, - - eTYPE_PLAYER = 0x8000, - eTYPE_SERVERPLAYER= 0x8001, - - // Include AGABLE_MOB - eTYPE_VILLAGER = 0x12000, - - eTYPE_PROJECTILE = 0x40000, - eTYPE_ARROW = 0x40001, - eTYPE_FIREBALL = 0x40002, - eTYPE_FISHINGHOOK = 0x40003, - eTYPE_SNOWBALL = 0x40004, - eTYPE_THROWNEGG = 0x40005, - eTYPE_EYEOFENDERSIGNAL = 0x40006, - eTYPE_SMALL_FIREBALL = 0x40007, - eTYPE_THROWNENDERPEARL = 0x40008, - eTYPE_THROWNPOTION = 0x40009, - eTYPE_THROWNEXPBOTTLE = 0x4000A, - - eTYPE_ANIMALS_SPAWN_LIMIT_CHECK = 0x80000, - - // Never used, exists to ensure all later entities don't match the bitmasks above - eTYPE_OTHERS = 0x100000, - - eTYPE_NETHER_SPHERE, - eTYPE_ENDER_CRYSTAL, - eTYPE_ENDERDRAGON, - eTYPE_BOSS_MOB_PART, - - eTYPE_ENTITY, - - eTYPE_MOB, - - eTYPE_LIGHTNINGBOLT, - - eTYPE_PAINTING, - eTYPE_ITEMENTITY, - eTYPE_FALLINGTILE, - eTYPE_BOAT, - eTYPE_MINECART, - eTYPE_PRIMEDTNT, - - eTYPE_TILEENTITY, - eTYPE_CHESTTILEENTITY, - eTYPE_DISPENSERTILEENTITY, - eTYPE_MOBSPAWNERTILEENTITY, - eTYPE_FURNACETILEENTITY, - eTYPE_SIGNTILEENTITY, - eTYPE_MUSICTILEENTITY, - eTYPE_RECORDPLAYERTILE, - eTYPE_PISTONPIECEENTITY, - eTYPE_BREWINGSTANDTILEENTITY, - eTYPE_ENCHANTMENTTABLEENTITY, - eTYPE_THEENDPORTALTILEENTITY, - eTYPE_SKULLTILEENTITY, - eTYPE_ENDERCHESTTILEENTITY, + eTYPE_ENTITY = BIT_ENTITY, - eType_NODE, + eTYPE_LIVINGENTITY = eTYPE_ENTITY | BIT_LIVING_ENTITY, - eType_ITEM, - eType_ITEMINSTANCE, - eType_MAPITEM, - eType_TILE, - eType_FIRETILE, + eTYPE_MOB = eTYPE_LIVINGENTITY | BIT_MOB, + + eTYPE_PATHFINDER_MOB = eTYPE_MOB | BIT_PATHFINDER_MOB, + + eTYPE_AGABLE_MOB = eTYPE_PATHFINDER_MOB | BIT_AGABLE_MOB, + + eTYPE_VILLAGER = eTYPE_AGABLE_MOB | 0x1, //0x12000, + + // 4J Stu - When adding new categories, please also update ConsoleSchematicFile::generateSchematicFile so these can be saved out to schematics + eTYPE_ANIMAL = eTYPE_AGABLE_MOB | BIT_ANIMAL, + + eTYPE_TAMABLE_ANIMAL = eTYPE_ANIMAL | BIT_TAMABLE, + + eTYPE_OCELOT = eTYPE_TAMABLE_ANIMAL | eTYPE_ANIMALS_SPAWN_LIMIT_CHECK | 0x1, + eTYPE_WOLF = eTYPE_TAMABLE_ANIMAL | 0x2, + + eTYPE_HORSE = eTYPE_ANIMAL | eTYPE_ANIMALS_SPAWN_LIMIT_CHECK | 0x1, + eTYPE_SHEEP = eTYPE_ANIMAL | eTYPE_ANIMALS_SPAWN_LIMIT_CHECK | 0x2, + eTYPE_PIG = eTYPE_ANIMAL | eTYPE_ANIMALS_SPAWN_LIMIT_CHECK | 0x3, + eTYPE_CHICKEN = eTYPE_ANIMAL | 0x4, + + eTYPE_COW = eTYPE_ANIMAL | eTYPE_ANIMALS_SPAWN_LIMIT_CHECK | BIT_COW, + eTYPE_MUSHROOMCOW = eTYPE_COW | 0x1, + + + eTYPE_WATERANIMAL = eTYPE_PATHFINDER_MOB | BIT_WATER_MOB, //0x100, + eTYPE_SQUID = eTYPE_WATERANIMAL| 0x1, + + eTYPE_GOLEM = eTYPE_PATHFINDER_MOB | BIT_GOLEM, + + eTYPE_SNOWMAN = eTYPE_GOLEM | eTYPE_ANIMALS_SPAWN_LIMIT_CHECK | 0x1, //0x4, + eTYPE_VILLAGERGOLEM = eTYPE_GOLEM | 0x2, //0x1000, + + + // 4J Stu - If you add new hostile mobs here you should also update the string lookup function at CConsoleMinecraftApp::getEntityName + eTYPE_MONSTER = eTYPE_ENEMY | eTYPE_PATHFINDER_MOB | BIT_MONSTER, + + eTYPE_SPIDER = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | BIT_SPIDER, + eTYPE_CAVESPIDER = eTYPE_SPIDER | 0x1, + + eTYPE_ZOMBIE = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | BIT_ZOMBIE, + eTYPE_PIGZOMBIE = eTYPE_ZOMBIE | 0x1, + + eTYPE_CREEPER = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x1, + eTYPE_GIANT = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x2, + eTYPE_SKELETON = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x3, + eTYPE_ENDERMAN = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x4, + eTYPE_SILVERFISH = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x5, + eTYPE_BLAZE = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x6, + eTYPE_WITCH = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x7, + eTYPE_WITHERBOSS = eTYPE_MONSTER | eTYPE_VALID_IN_SPAWNER_FLAG | 0x8, + + + eTYPE_AMBIENT = eTYPE_MOB | BIT_AMBIENT_MOB, + eTYPE_BAT = eTYPE_AMBIENT | eTYPE_VALID_IN_SPAWNER_FLAG | 0x1, + + eTYPE_FLYING_MOB = eTYPE_MOB | BIT_FLYING_MOB, + eTYPE_GHAST = eTYPE_FLYING_MOB | eTYPE_VALID_IN_SPAWNER_FLAG | eTYPE_ENEMY | 0x1, + + eTYPE_SLIME = eTYPE_MOB | eTYPE_VALID_IN_SPAWNER_FLAG | eTYPE_ENEMY | BIT_SLIME, + eTYPE_LAVASLIME = eTYPE_SLIME | 0x1, + + eTYPE_ENDERDRAGON = eTYPE_MOB | 0x5, + + eTYPE_PLAYER = eTYPE_LIVINGENTITY | BIT_PLAYER, //0x8000, + eTYPE_SERVERPLAYER = eTYPE_PLAYER | 0x1, + eTYPE_REMOTEPLAYER = eTYPE_PLAYER | 0x2, + eTYPE_LOCALPLAYER = eTYPE_PLAYER | 0x3, + + eTYPE_GLOBAL_ENTITY = eTYPE_ENTITY | BIT_GLOBAL_ENTITY, + eTYPE_LIGHTNINGBOLT = eTYPE_GLOBAL_ENTITY | 0x1, + + eTYPE_MINECART = eTYPE_ENTITY | BIT_MINECART, //0x200000, + + eTYPE_MINECART_RIDEABLE = eTYPE_MINECART | 0x1, + eTYPE_MINECART_SPAWNER = eTYPE_MINECART | 0x6, + eTYPE_MINECART_FURNACE = eTYPE_MINECART | 0x3, + eTYPE_MINECART_TNT = eTYPE_MINECART | 0x4, + + eTYPE_MINECART_CONTAINER = eTYPE_MINECART | BIT_MINECART_CONTAINER, + + eTYPE_MINECART_CHEST = eTYPE_MINECART_CONTAINER | 0x2, + eTYPE_MINECART_HOPPER = eTYPE_MINECART_CONTAINER | 0x5, + + + eTYPE_FIREBALL = eTYPE_ENTITY | eTYPE_PROJECTILE | BIT_FIREBALL, //0x2, + + eTYPE_DRAGON_FIREBALL = eTYPE_FIREBALL | 0x1, + eTYPE_WITHER_SKULL = eTYPE_FIREBALL | 0x2, + eTYPE_LARGE_FIREBALL = eTYPE_FIREBALL | 0x3, + eTYPE_SMALL_FIREBALL = eTYPE_FIREBALL | 0x4, + + + eTYPE_THROWABLE = eTYPE_ENTITY | eTYPE_PROJECTILE | BIT_THROWABLE, + + eTYPE_SNOWBALL = eTYPE_THROWABLE | 0x1, + eTYPE_THROWNEGG = eTYPE_THROWABLE | 0x2, + eTYPE_THROWNENDERPEARL = eTYPE_THROWABLE | 0x3, + eTYPE_THROWNPOTION = eTYPE_THROWABLE | 0x4, + eTYPE_THROWNEXPBOTTLE = eTYPE_THROWABLE | 0x5, + + + eTYPE_HANGING_ENTITY = eTYPE_ENTITY | BIT_HANGING_ENTITY, + + eTYPE_PAINTING = eTYPE_HANGING_ENTITY | 0x1, + eTYPE_ITEM_FRAME = eTYPE_HANGING_ENTITY | 0x2, + eTYPE_LEASHFENCEKNOT = eTYPE_HANGING_ENTITY | 0x3, + + + // Other Entities. + + eTYPE_OTHER_ENTITIES = eTYPE_ENTITY + 1, + + eTYPE_EXPERIENCEORB = (eTYPE_OTHER_ENTITIES + 2), // 1.8.2 + eTYPE_EYEOFENDERSIGNAL = (eTYPE_OTHER_ENTITIES + 3) | eTYPE_PROJECTILE, + eTYPE_FIREWORKS_ROCKET = (eTYPE_OTHER_ENTITIES + 4) | eTYPE_PROJECTILE, + eTYPE_FISHINGHOOK = (eTYPE_OTHER_ENTITIES + 5) | eTYPE_PROJECTILE, + eTYPE_DELAYEDRELEASE = (eTYPE_OTHER_ENTITIES + 6), // 1.8.2 + eTYPE_BOAT = (eTYPE_OTHER_ENTITIES + 7), + eTYPE_FALLINGTILE = (eTYPE_OTHER_ENTITIES + 8), + eTYPE_ITEMENTITY = (eTYPE_OTHER_ENTITIES + 9), + eTYPE_PRIMEDTNT = (eTYPE_OTHER_ENTITIES + 10), + eTYPE_ARROW = (eTYPE_OTHER_ENTITIES + 11) | eTYPE_PROJECTILE, + eTYPE_MULTIENTITY_MOB_PART = (eTYPE_OTHER_ENTITIES + 12), + eTYPE_NETHER_SPHERE = (eTYPE_OTHER_ENTITIES + 13), + eTYPE_ENDER_CRYSTAL = (eTYPE_OTHER_ENTITIES + 14), + + + // === PARTICLES === // eType_BREAKINGITEMPARTICLE, eType_BUBBLEPARTICLE, @@ -137,8 +264,6 @@ enum eINSTANCEOF eType_WATERDROPPARTICLE, // 1.8.2 - eTYPE_DELAYEDRELEASE, - eTYPE_EXPERIENCEORB, eType_CRITPARTICLE, eType_CRITPARTICLE2, eType_HUGEEXPLOSIONPARTICLE, @@ -153,10 +278,329 @@ enum eINSTANCEOF eTYPE_SPELLPARTICLE, //TU9 - eTYPE_HANGING_ENTITY, - eTYPE_ITEM_FRAME, eTYPE_DRAGONBREATHPARTICLE, - eTYPE_DRAGON_FIREBALL, - eType_ENDERPARTICLE, + + eType_FIREWORKSSTARTERPARTICLE, + eType_FIREWORKSSPARKPARTICLE, + eType_FIREWORKSOVERLAYPARTICLE, + + // === Tile Entities === // + + eTYPE_TILEENTITY = BIT_TILE_ENTITY, + + eTYPE_CHESTTILEENTITY = eTYPE_TILEENTITY | 0x01, + eTYPE_MOBSPAWNERTILEENTITY = eTYPE_TILEENTITY | 0x02, + eTYPE_FURNACETILEENTITY = eTYPE_TILEENTITY | 0x03, + eTYPE_SIGNTILEENTITY = eTYPE_TILEENTITY | 0x04, + eTYPE_MUSICTILEENTITY = eTYPE_TILEENTITY | 0x05, + eTYPE_RECORDPLAYERTILE = eTYPE_TILEENTITY | 0x06, + eTYPE_PISTONPIECEENTITY = eTYPE_TILEENTITY | 0x07, + eTYPE_BREWINGSTANDTILEENTITY = eTYPE_TILEENTITY | 0x08, + eTYPE_ENCHANTMENTTABLEENTITY = eTYPE_TILEENTITY | 0x09, + eTYPE_THEENDPORTALTILEENTITY = eTYPE_TILEENTITY | 0x0A, + eTYPE_SKULLTILEENTITY = eTYPE_TILEENTITY | 0x0B, + eTYPE_ENDERCHESTTILEENTITY = eTYPE_TILEENTITY | 0x0C, + eTYPE_BEACONTILEENTITY = eTYPE_TILEENTITY | 0x0D, + eTYPE_COMMANDBLOCKTILEENTITY = eTYPE_TILEENTITY | 0x0E, + eTYPE_COMPARATORTILEENTITY = eTYPE_TILEENTITY | 0x0F, + eTYPE_DAYLIGHTDETECTORTILEENTITY = eTYPE_TILEENTITY | 0x10, + eTYPE_HOPPERTILEENTITY = eTYPE_TILEENTITY | 0x11, + + eTYPE_DISPENSERTILEENTITY = eTYPE_TILEENTITY | BIT_DISPENSERTILEENTITY, + eTYPE_DROPPERTILEENTITY = eTYPE_DISPENSERTILEENTITY | 0x1, + + + // === Never used === // + // exists to ensure all later entities don't match the bitmasks above + + eTYPE_OTHERS = BIT_OTHER_NOT_ENTITIES, + + eType_NODE, + eType_ITEM, + eType_ITEMINSTANCE, + eType_MAPITEM, + eType_TILE, + eType_FIRETILE, +}; + +inline bool eTYPE_DERIVED_FROM(eINSTANCEOF super, eINSTANCEOF sub) +{ + if ( (super & 0x3F) != 0x00 ) return super == sub; + else return (super & sub) == super; +} + +inline bool eTYPE_FLAGSET(eINSTANCEOF flag, eINSTANCEOF claz) +{ + return (flag & claz) == flag; +} + + +/// FOR CHECKING /// + +#if !(defined _WINDOWS64) + +class SubClass +{ + static void checkDerivations() {} }; + +#else + +class SubClass +{ +public: + bool m_isTerminal; + const string m_name; + const eINSTANCEOF m_id; + vector m_parents; + + static unordered_map s_ids; + + SubClass(const string &name, eINSTANCEOF id) + : m_name(name), m_id(id) + { + s_ids.insert( pair(id,this) ); + m_isTerminal = true; + } + + SubClass *addParent(eINSTANCEOF id) + { + SubClass *parent = s_ids.at(id); + parent->m_isTerminal = false; + + m_parents.push_back(id); + + for (AUTO_VAR(itr, parent->m_parents.begin()); itr != parent->m_parents.end(); itr++) + { + m_parents.push_back(*itr); + } + + return this; + } + + bool justFlag() + { + return (m_id & 0xF00000) == m_id; + } + +#define SUBCLASS(x) (new SubClass( #x , x )) + + static void checkDerivations() + { + vector *classes = new vector(); + + classes->push_back( SUBCLASS(eTYPE_VALID_IN_SPAWNER_FLAG) ); + classes->push_back( SUBCLASS(eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) ); + classes->push_back( SUBCLASS(eTYPE_ENEMY) ); + classes->push_back( SUBCLASS(eTYPE_PROJECTILE) ); + + classes->push_back( SUBCLASS(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eTYPE_LIVINGENTITY)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eTYPE_MOB)->addParent(eTYPE_LIVINGENTITY) ); + classes->push_back( SUBCLASS(eTYPE_PATHFINDER_MOB)->addParent(eTYPE_MOB) ); + classes->push_back( SUBCLASS(eTYPE_AGABLE_MOB)->addParent(eTYPE_PATHFINDER_MOB) ); + classes->push_back( SUBCLASS(eTYPE_VILLAGER)->addParent(eTYPE_AGABLE_MOB) ); + classes->push_back( SUBCLASS(eTYPE_ANIMAL)->addParent(eTYPE_AGABLE_MOB) ); + classes->push_back( SUBCLASS(eTYPE_TAMABLE_ANIMAL )->addParent( eTYPE_ANIMAL ) ); + classes->push_back( SUBCLASS(eTYPE_OCELOT )->addParent( eTYPE_TAMABLE_ANIMAL)->addParent(eTYPE_ANIMALS_SPAWN_LIMIT_CHECK ) ); + classes->push_back( SUBCLASS(eTYPE_WOLF )->addParent( eTYPE_TAMABLE_ANIMAL ) ); + classes->push_back( SUBCLASS(eTYPE_HORSE )->addParent( eTYPE_ANIMAL)->addParent(eTYPE_ANIMALS_SPAWN_LIMIT_CHECK ) ); + classes->push_back( SUBCLASS(eTYPE_SHEEP )->addParent( eTYPE_ANIMAL)->addParent(eTYPE_ANIMALS_SPAWN_LIMIT_CHECK ) ); + classes->push_back( SUBCLASS(eTYPE_PIG )->addParent( eTYPE_ANIMAL)->addParent(eTYPE_ANIMALS_SPAWN_LIMIT_CHECK ) ); + classes->push_back( SUBCLASS(eTYPE_CHICKEN )->addParent( eTYPE_ANIMAL ) ); + classes->push_back( SUBCLASS(eTYPE_COW )->addParent( eTYPE_ANIMAL)->addParent(eTYPE_ANIMALS_SPAWN_LIMIT_CHECK ) ); + classes->push_back( SUBCLASS(eTYPE_MUSHROOMCOW )->addParent( eTYPE_COW ) ); + classes->push_back( SUBCLASS(eTYPE_WATERANIMAL )->addParent(eTYPE_PATHFINDER_MOB) ); + classes->push_back( SUBCLASS(eTYPE_SQUID )->addParent( eTYPE_WATERANIMAL ) ); + classes->push_back( SUBCLASS(eTYPE_GOLEM )->addParent( eTYPE_PATHFINDER_MOB ) ); + classes->push_back( SUBCLASS(eTYPE_SNOWMAN )->addParent( eTYPE_GOLEM)->addParent(eTYPE_ANIMALS_SPAWN_LIMIT_CHECK ) ); + classes->push_back( SUBCLASS(eTYPE_VILLAGERGOLEM )->addParent( eTYPE_GOLEM ) ); + classes->push_back( SUBCLASS(eTYPE_MONSTER )->addParent( eTYPE_ENEMY)->addParent(eTYPE_PATHFINDER_MOB ) ); + classes->push_back( SUBCLASS(eTYPE_SPIDER )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_CAVESPIDER )->addParent( eTYPE_SPIDER ) ); + classes->push_back( SUBCLASS(eTYPE_ZOMBIE )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_PIGZOMBIE )->addParent( eTYPE_ZOMBIE ) ); + classes->push_back( SUBCLASS(eTYPE_CREEPER )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_GIANT )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_SKELETON )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_ENDERMAN )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_SILVERFISH )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_BLAZE )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_WITCH )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_WITHERBOSS )->addParent( eTYPE_MONSTER)->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_AMBIENT )->addParent( eTYPE_MOB ) ); + classes->push_back( SUBCLASS(eTYPE_BAT )->addParent( eTYPE_AMBIENT )->addParent(eTYPE_VALID_IN_SPAWNER_FLAG ) ); + classes->push_back( SUBCLASS(eTYPE_FLYING_MOB )->addParent( eTYPE_MOB ) ); + classes->push_back( SUBCLASS(eTYPE_GHAST )->addParent( eTYPE_FLYING_MOB )->addParent(eTYPE_VALID_IN_SPAWNER_FLAG)->addParent(eTYPE_ENEMY ) ); + classes->push_back( SUBCLASS(eTYPE_SLIME )->addParent( eTYPE_MOB )->addParent(eTYPE_VALID_IN_SPAWNER_FLAG)->addParent(eTYPE_ENEMY ) ); + classes->push_back( SUBCLASS(eTYPE_LAVASLIME )->addParent( eTYPE_SLIME ) ); + classes->push_back( SUBCLASS(eTYPE_ENDERDRAGON )->addParent( eTYPE_MOB ) ); + classes->push_back( SUBCLASS(eTYPE_PLAYER )->addParent( eTYPE_LIVINGENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_SERVERPLAYER )->addParent( eTYPE_PLAYER ) ); + classes->push_back( SUBCLASS(eTYPE_REMOTEPLAYER )->addParent( eTYPE_PLAYER ) ); + classes->push_back( SUBCLASS(eTYPE_LOCALPLAYER )->addParent( eTYPE_PLAYER ) ); + classes->push_back( SUBCLASS(eTYPE_MINECART )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_MINECART_RIDEABLE )->addParent( eTYPE_MINECART ) ); + classes->push_back( SUBCLASS(eTYPE_MINECART_SPAWNER )->addParent( eTYPE_MINECART ) ); + classes->push_back( SUBCLASS(eTYPE_MINECART_FURNACE )->addParent( eTYPE_MINECART ) ); + classes->push_back( SUBCLASS(eTYPE_MINECART_TNT )->addParent( eTYPE_MINECART ) ); + classes->push_back( SUBCLASS(eTYPE_MINECART_CONTAINER )->addParent( eTYPE_MINECART ) ); + classes->push_back( SUBCLASS(eTYPE_MINECART_CHEST )->addParent( eTYPE_MINECART_CONTAINER ) ); + classes->push_back( SUBCLASS(eTYPE_MINECART_HOPPER )->addParent( eTYPE_MINECART_CONTAINER ) ); + classes->push_back( SUBCLASS(eTYPE_FIREBALL )->addParent( eTYPE_ENTITY)->addParent(eTYPE_PROJECTILE ) ); + classes->push_back( SUBCLASS(eTYPE_DRAGON_FIREBALL )->addParent( eTYPE_FIREBALL ) ); + classes->push_back( SUBCLASS(eTYPE_WITHER_SKULL )->addParent( eTYPE_FIREBALL ) ); + classes->push_back( SUBCLASS(eTYPE_LARGE_FIREBALL )->addParent( eTYPE_FIREBALL ) ); + classes->push_back( SUBCLASS(eTYPE_SMALL_FIREBALL )->addParent( eTYPE_FIREBALL ) ); + classes->push_back( SUBCLASS(eTYPE_THROWABLE )->addParent( eTYPE_ENTITY)->addParent(eTYPE_PROJECTILE ) ); + classes->push_back( SUBCLASS(eTYPE_SNOWBALL )->addParent( eTYPE_THROWABLE ) ); + classes->push_back( SUBCLASS(eTYPE_THROWNEGG )->addParent( eTYPE_THROWABLE ) ); + classes->push_back( SUBCLASS(eTYPE_THROWNENDERPEARL )->addParent( eTYPE_THROWABLE ) ); + classes->push_back( SUBCLASS(eTYPE_THROWNPOTION )->addParent( eTYPE_THROWABLE ) ); + classes->push_back( SUBCLASS(eTYPE_THROWNEXPBOTTLE )->addParent( eTYPE_THROWABLE ) ); + classes->push_back( SUBCLASS(eTYPE_HANGING_ENTITY )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_PAINTING )->addParent( eTYPE_HANGING_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_ITEM_FRAME )->addParent( eTYPE_HANGING_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_LEASHFENCEKNOT )->addParent( eTYPE_HANGING_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_GLOBAL_ENTITY )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_LIGHTNINGBOLT )->addParent( eTYPE_GLOBAL_ENTITY ) ); + + //classes->push_back( SUBCLASS(eTYPE_OTHER_ENTITIES )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_EXPERIENCEORB )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_EYEOFENDERSIGNAL )->addParent( eTYPE_ENTITY)->addParent(eTYPE_PROJECTILE ) ); + classes->push_back( SUBCLASS(eTYPE_FIREWORKS_ROCKET )->addParent( eTYPE_ENTITY)->addParent(eTYPE_PROJECTILE ) ); + classes->push_back( SUBCLASS(eTYPE_FISHINGHOOK )->addParent( eTYPE_ENTITY)->addParent(eTYPE_PROJECTILE ) ); + classes->push_back( SUBCLASS(eTYPE_DELAYEDRELEASE )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_BOAT )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_FALLINGTILE )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_ITEMENTITY )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_PRIMEDTNT )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_ARROW )->addParent( eTYPE_ENTITY )->addParent(eTYPE_PROJECTILE ) ); + classes->push_back( SUBCLASS(eTYPE_MULTIENTITY_MOB_PART )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_NETHER_SPHERE )->addParent( eTYPE_ENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_ENDER_CRYSTAL )->addParent( eTYPE_ENTITY ) ); + + classes->push_back( SUBCLASS(eType_BREAKINGITEMPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_BUBBLEPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_EXPLODEPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_FLAMEPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_FOOTSTEPPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_HEARTPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_LAVAPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_NOTEPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_NETHERPORTALPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_REDDUSTPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_SMOKEPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_SNOWSHOVELPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_SPLASHPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_TAKEANIMATIONPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_TERRAINPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_WATERDROPPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_CRITPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_CRITPARTICLE2)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_HUGEEXPLOSIONPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_HUGEEXPLOSIONSEEDPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_PLAYERCLOUDPARTICLEPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_SUSPENDEDPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_SUSPENDEDTOWNPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eTYPE_DRIPPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eTYPE_ENCHANTMENTTABLEPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eTYPE_SPELLPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eTYPE_DRAGONBREATHPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_ENDERPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_FIREWORKSSTARTERPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_FIREWORKSSPARKPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eType_FIREWORKSOVERLAYPARTICLE)->addParent(eTYPE_ENTITY) ); + classes->push_back( SUBCLASS(eTYPE_TILEENTITY) ); + classes->push_back( SUBCLASS(eTYPE_CHESTTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_MOBSPAWNERTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_FURNACETILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_SIGNTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_MUSICTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_RECORDPLAYERTILE )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_PISTONPIECEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_BREWINGSTANDTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_ENCHANTMENTTABLEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_THEENDPORTALTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_SKULLTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_ENDERCHESTTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_BEACONTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_COMMANDBLOCKTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_COMPARATORTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_DAYLIGHTDETECTORTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_HOPPERTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_DISPENSERTILEENTITY )->addParent( eTYPE_TILEENTITY ) ); + classes->push_back( SUBCLASS(eTYPE_DROPPERTILEENTITY )->addParent( eTYPE_DISPENSERTILEENTITY ) ); + + //classes->push_back( SUBCLASS(eTYPE_OTHERS) ); + classes->push_back( SUBCLASS(eType_NODE) ); + classes->push_back( SUBCLASS(eType_ITEM) ); + classes->push_back( SUBCLASS(eType_ITEMINSTANCE) ); + classes->push_back( SUBCLASS(eType_MAPITEM) ); + classes->push_back( SUBCLASS(eType_TILE) ); + classes->push_back( SUBCLASS(eType_FIRETILE) ); + + vector< pair > m_falsePositives; + vector< pair > m_falseNegatives; + + vector::iterator it1; + for (it1=classes->begin(); it1!=classes->end(); it1++) + { + SubClass *current = *it1; + //if ( current->justFlag() ) continue; + + vector::iterator it2; + for (it2=classes->begin(); it2!=classes->end(); it2++) + { + SubClass *comparing = *it2; + //if ( comparing->justFlag() ) continue; + + // We shouldn't be comparing to leaf classes anyway. + //if ( comparing->m_isTerminal ) continue; + + eINSTANCEOF typeCurr, typeComp; + typeCurr = current->m_id; + typeComp = comparing->m_id; + + bool shouldDerive, doesDerive; + + { + vector::iterator it3; + it3 = find(current->m_parents.begin(), current->m_parents.end(), typeComp); + shouldDerive = (typeComp == typeCurr) || (it3 != current->m_parents.end()); + } + + doesDerive = eTYPE_DERIVED_FROM(typeComp, typeCurr); + + if (shouldDerive != doesDerive) + { + vector< pair > *errorArray; + if (shouldDerive) errorArray = &m_falseNegatives; + else errorArray = &m_falsePositives; + + errorArray->push_back( pair(comparing, current) ); + } + } + } + + vector< pair >::iterator itrErr; + for (itrErr = m_falsePositives.begin(); itrErr != m_falsePositives.end(); itrErr++) + { + SubClass *sub = itrErr->first, *super = itrErr->second; + printf( "[Class.h] Error: '%s' incorrectly derives from '%s'.\n", sub->m_name.c_str(), super->m_name.c_str() ); + } + for (itrErr = m_falseNegatives.begin(); itrErr != m_falseNegatives.end(); itrErr++) + { + SubClass *sub = itrErr->first, *super = itrErr->second; + printf( "[Class.h] Error: '%s' doesn't derive '%s'.\n", sub->m_name.c_str(), super->m_name.c_str() ); + } + + if ( (m_falsePositives.size() > 0) || (m_falseNegatives.size() > 0) ) + { + __debugbreak(); + } + } +}; + +#endif \ No newline at end of file diff --git a/Minecraft.World/ClassDiagram.cd b/Minecraft.World/ClassDiagram.cd new file mode 100644 index 00000000..7b894197 --- /dev/null +++ b/Minecraft.World/ClassDiagram.cd @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Minecraft.World/ClayFeature.cpp b/Minecraft.World/ClayFeature.cpp index 88fd4512..277849f0 100644 --- a/Minecraft.World/ClayFeature.cpp +++ b/Minecraft.World/ClayFeature.cpp @@ -12,27 +12,27 @@ ClayFeature::ClayFeature(int radius) bool ClayFeature::place(Level *level, Random *random, int x, int y, int z) { - if (level->getMaterial(x, y, z) != Material::water) return false; + if (level->getMaterial(x, y, z) != Material::water) return false; - int r = random->nextInt(radius - 2) + 2; - int yr = 1; - for (int xx = x - r; xx <= x + r; xx++) + int r = random->nextInt(radius - 2) + 2; + int yr = 1; + for (int xx = x - r; xx <= x + r; xx++) { - for (int zz = z - r; zz <= z + r; zz++) + for (int zz = z - r; zz <= z + r; zz++) { - int xd = xx - x; - int zd = zz - z; - if (xd * xd + zd * zd > r * r) continue; - for (int yy = y - yr; yy <= y + yr; yy++) + int xd = xx - x; + int zd = zz - z; + if (xd * xd + zd * zd > r * r) continue; + for (int yy = y - yr; yy <= y + yr; yy++) { - int t = level->getTile(xx, yy, zz); - if (t == Tile::dirt_Id || t == Tile::clay_Id) + int t = level->getTile(xx, yy, zz); + if (t == Tile::dirt_Id || t == Tile::clay_Id) { - level->setTileNoUpdate(xx, yy, zz, tile); - } - } - } - } + level->setTileAndData(xx, yy, zz, tile, 0, Tile::UPDATE_CLIENTS); + } + } + } + } - return true; + return true; } diff --git a/Minecraft.World/ClientInformationPacket.h b/Minecraft.World/ClientInformationPacket.h index e5e2cc42..e9d73a5d 100644 --- a/Minecraft.World/ClientInformationPacket.h +++ b/Minecraft.World/ClientInformationPacket.h @@ -14,12 +14,13 @@ class ClientInformationPacket : public Packet public ClientInformationPacket() { } - public ClientInformationPacket(String language, int viewDistance, int chatVisibility, boolean chatColors, int difficulty) { + public ClientInformationPacket(String language, int viewDistance, int chatVisibility, boolean chatColors, int difficulty, boolean showCape) { this.language = language; this.viewDistance = viewDistance; this.chatVisibility = chatVisibility; this.chatColors = chatColors; this.difficulty = difficulty; + this.showCape = showCape; } @Override @@ -32,6 +33,7 @@ class ClientInformationPacket : public Packet chatColors = (chat & 0x8) == 0x8; difficulty = dis.readByte(); + showCape = dis.readBoolean(); } @Override @@ -40,6 +42,7 @@ class ClientInformationPacket : public Packet dos.writeByte(viewDistance); dos.writeByte(chatVisibility | (chatColors ? 1 : 0) << 3); dos.writeByte(difficulty); + dos.writeBoolean(showCape); } @Override @@ -49,7 +52,7 @@ class ClientInformationPacket : public Packet @Override public int getEstimatedSize() { - return 0; + return 7; } public String getLanguage() { @@ -72,6 +75,10 @@ class ClientInformationPacket : public Packet return difficulty; } + public boolean getShowCape() { + return showCape; + } + public void setDifficulty(int difficulty) { this.difficulty = difficulty; } diff --git a/Minecraft.World/ClientSideMerchant.cpp b/Minecraft.World/ClientSideMerchant.cpp index 5d021c22..ba179300 100644 --- a/Minecraft.World/ClientSideMerchant.cpp +++ b/Minecraft.World/ClientSideMerchant.cpp @@ -3,7 +3,7 @@ #include "net.minecraft.world.inventory.h" #include "ClientSideMerchant.h" -ClientSideMerchant::ClientSideMerchant(shared_ptr source, int name) +ClientSideMerchant::ClientSideMerchant(shared_ptr source, const wstring &name) { this->source = source; // 4J Stu - Need to do this after creating as a shared_ptr @@ -58,7 +58,7 @@ void ClientSideMerchant::notifyTradeUpdated(shared_ptr item) { } -int ClientSideMerchant::getDisplayName() +wstring ClientSideMerchant::getDisplayName() { return m_name; } \ No newline at end of file diff --git a/Minecraft.World/ClientSideMerchant.h b/Minecraft.World/ClientSideMerchant.h index 33f0c0b1..085768ca 100644 --- a/Minecraft.World/ClientSideMerchant.h +++ b/Minecraft.World/ClientSideMerchant.h @@ -10,21 +10,21 @@ class ClientSideMerchant : public Merchant, public enable_shared_from_this source; - MerchantRecipeList *currentOffers; - int m_name; + shared_ptr source; + MerchantRecipeList *currentOffers; + wstring m_name; public: - ClientSideMerchant(shared_ptr source, int name); + ClientSideMerchant(shared_ptr source, const wstring &name); ~ClientSideMerchant(); void createContainer(); // 4J Added - Container *getContainer(); - shared_ptr getTradingPlayer(); - void setTradingPlayer(shared_ptr player); - MerchantRecipeList *getOffers(shared_ptr forPlayer); - void overrideOffers(MerchantRecipeList *recipeList); - void notifyTrade(MerchantRecipe *activeRecipe); + Container *getContainer(); + shared_ptr getTradingPlayer(); + void setTradingPlayer(shared_ptr player); + MerchantRecipeList *getOffers(shared_ptr forPlayer); + void overrideOffers(MerchantRecipeList *recipeList); + void notifyTrade(MerchantRecipe *activeRecipe); void notifyTradeUpdated(shared_ptr item); - int getDisplayName(); + wstring getDisplayName(); }; \ No newline at end of file diff --git a/Minecraft.World/ClothDyeRecipes.cpp b/Minecraft.World/ClothDyeRecipes.cpp index 5ad38d82..c0625d2e 100644 --- a/Minecraft.World/ClothDyeRecipes.cpp +++ b/Minecraft.World/ClothDyeRecipes.cpp @@ -1,105 +1,125 @@ #include "stdafx.h" #include "net.minecraft.world.Item.h" -#include "DyePowderItem.h" -#include "Tile.h" -#include "ClothTile.h" +#include "net.minecraft.world.level.tile.h" #include "Recipy.h" #include "Recipes.h" #include "ClothDyeRecipes.h" void ClothDyeRecipes::addRecipes(Recipes *r) { - // recipes for converting cloth to colored cloth using dye - for (int i = 0; i < 16; i++) + // recipes for converting cloth to colored cloth using dye + for (int i = 0; i < 16; i++) { - r->addShapelessRecipy(new ItemInstance(Tile::cloth, 1, ClothTile::getItemAuxValueForTileData(i)), // + r->addShapelessRecipy(new ItemInstance(Tile::wool, 1, ColoredTile::getItemAuxValueForTileData(i)), // L"zzg", - new ItemInstance(Item::dye_powder, 1, i), new ItemInstance(Item::items[Tile::cloth_Id], 1, 0),L'D'); - } + new ItemInstance(Item::dye_powder, 1, i), new ItemInstance(Item::items[Tile::wool_Id], 1, 0),L'D'); + r->addShapedRecipy(new ItemInstance(Tile::clayHardened_colored, 8, ColoredTile::getItemAuxValueForTileData(i)), // + L"sssczczg", + L"###", + L"#X#", + L"###", + L'#', new ItemInstance(Tile::clayHardened), + L'X', new ItemInstance(Item::dye_powder, 1, i),L'D'); + +#if 0 + r->addShapedRecipy(new ItemInstance(Tile::stained_glass, 8, ColoredTile::getItemAuxValueForTileData(i)), // + L"sssczczg", + L"###", + L"#X#", + L"###", + L'#', new ItemInstance(Tile::glass), + L'X', new ItemInstance(Item::dye_powder, 1, i), L'D'); + r->addShapedRecipy(new ItemInstance(Tile::stained_glass_pane, 16, i), // + L"ssczg", + L"###", + L"###", + L'#', new ItemInstance(Tile::stained_glass, 1, i), L'D'); +#endif + } - // some dye recipes - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::YELLOW), + // some dye recipes + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::YELLOW), L"tg", Tile::flower,L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::RED), + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::RED), L"tg", Tile::rose,L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 3, DyePowderItem::WHITE), + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 3, DyePowderItem::WHITE), L"ig", Item::bone,L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::PINK), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::PINK), // L"zzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::ORANGE), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::ORANGE), // L"zzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::YELLOW),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::YELLOW),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::LIME), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::LIME), // L"zzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::GREEN), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::GREEN), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::GRAY), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::GRAY), // L"zzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLACK), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLACK), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::SILVER), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::SILVER), // L"zzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::GRAY), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::GRAY), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 3, DyePowderItem::SILVER), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 3, DyePowderItem::SILVER), // L"zzzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLACK), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLACK), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::LIGHT_BLUE), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::LIGHT_BLUE), // L"zzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::CYAN), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::CYAN), // L"zzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::GREEN),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::GREEN),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::PURPLE), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::PURPLE), // L"zzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::MAGENTA), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 2, DyePowderItem::MAGENTA), // L"zzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::PURPLE), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::PINK),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::PURPLE), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::PINK),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 3, DyePowderItem::MAGENTA), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 3, DyePowderItem::MAGENTA), // L"zzzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::PINK),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::PINK),L'D'); - r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 4, DyePowderItem::MAGENTA), // + r->addShapelessRecipy(new ItemInstance(Item::dye_powder, 4, DyePowderItem::MAGENTA), // L"zzzzg", - new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), - new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); + new ItemInstance(Item::dye_powder, 1, DyePowderItem::BLUE), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::RED), + new ItemInstance(Item::dye_powder, 1, DyePowderItem::WHITE),L'D'); for (int i = 0; i < 16; i++) { r->addShapedRecipy(new ItemInstance(Tile::woolCarpet, 3, i), L"sczg", L"##", - L'#', new ItemInstance(Tile::cloth, 1, i), + L'#', new ItemInstance(Tile::wool, 1, i), L'D' ); } diff --git a/Minecraft.World/CoalItem.cpp b/Minecraft.World/CoalItem.cpp index 362689e0..94030122 100644 --- a/Minecraft.World/CoalItem.cpp +++ b/Minecraft.World/CoalItem.cpp @@ -1,9 +1,8 @@ -using namespace std; - #include "stdafx.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.h" #include "CoalItem.h" CoalItem::CoalItem(int id) : Item( id ) @@ -20,3 +19,19 @@ unsigned int CoalItem::getDescriptionId(shared_ptr instance) } return IDS_ITEM_COAL; } + +Icon *CoalItem::getIcon(int auxValue) +{ + if (auxValue == CHAR_COAL) + { + return charcoalIcon; + } + return Item::getIcon(auxValue); +} + +void CoalItem::registerIcons(IconRegister *iconRegister) +{ + Item::registerIcons(iconRegister); + + charcoalIcon = iconRegister->registerIcon(L"charcoal"); +} \ No newline at end of file diff --git a/Minecraft.World/CoalItem.h b/Minecraft.World/CoalItem.h index 24814548..3843c5de 100644 --- a/Minecraft.World/CoalItem.h +++ b/Minecraft.World/CoalItem.h @@ -7,6 +7,9 @@ class ItemInstance; class CoalItem : public Item { +private: + Icon *charcoalIcon; + public: static const int STONE_COAL = 0; static const int CHAR_COAL = 1; @@ -14,4 +17,7 @@ public: CoalItem(int id); virtual unsigned int getDescriptionId(shared_ptr instance); + + Icon *getIcon(int auxValue); + void registerIcons(IconRegister *iconRegister); }; \ No newline at end of file diff --git a/Minecraft.World/CocoaTile.cpp b/Minecraft.World/CocoaTile.cpp index 1f575014..095f9b52 100644 --- a/Minecraft.World/CocoaTile.cpp +++ b/Minecraft.World/CocoaTile.cpp @@ -32,7 +32,7 @@ void CocoaTile::tick(Level *level, int x, int y, int z, Random *random) if (!canSurvive(level, x, y, z)) { this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->setTileAndData(x, y, z, 0, 0, UPDATE_CLIENTS); } else if (level->random->nextInt(5) == 0) { @@ -41,7 +41,7 @@ void CocoaTile::tick(Level *level, int x, int y, int z, Random *random) if (age < 2) { age++; - level->setData(x, y, z, (age << 2) | (getDirection(data))); + level->setData(x, y, z, (age << 2) | (getDirection(data)), Tile::UPDATE_CLIENTS); } } } @@ -112,10 +112,10 @@ void CocoaTile::updateShape(LevelSource *level, int x, int y, int z, int forceDa } } -void CocoaTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) +void CocoaTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { int dir = (((Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3) + 0) % 4; - level->setData(x, y, z, dir); + level->setData(x, y, z, dir, Tile::UPDATE_CLIENTS); } int CocoaTile::getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) @@ -132,7 +132,7 @@ void CocoaTile::neighborChanged(Level *level, int x, int y, int z, int type) if (!canSurvive(level, x, y, z)) { this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->setTileAndData(x, y, z, 0, 0, UPDATE_CLIENTS); } } diff --git a/Minecraft.World/CocoaTile.h b/Minecraft.World/CocoaTile.h index 267225ea..bcbb1d2f 100644 --- a/Minecraft.World/CocoaTile.h +++ b/Minecraft.World/CocoaTile.h @@ -26,7 +26,7 @@ public: virtual AABB *getAABB(Level *level, int x, int y, int z); virtual AABB *getTileAABB(Level *level, int x, int y, int z); virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); virtual void neighborChanged(Level *level, int x, int y, int z, int type); static int getAge(int data); diff --git a/Minecraft.World/ColoredTile.cpp b/Minecraft.World/ColoredTile.cpp new file mode 100644 index 00000000..6c8c1712 --- /dev/null +++ b/Minecraft.World/ColoredTile.cpp @@ -0,0 +1,36 @@ +#include "stdafx.h" +#include "net.minecraft.world.h" +#include "net.minecraft.world.item.h" +#include "ColoredTile.h" + +ColoredTile::ColoredTile(int id, Material *material) : Tile(id, material) +{ +} + +Icon *ColoredTile::getTexture(int face, int data) +{ + return icons[data % ICON_COUNT]; +} + +int ColoredTile::getSpawnResourcesAuxValue(int data) +{ + return data; +} + +int ColoredTile::getTileDataForItemAuxValue(int auxValue) +{ + return (~auxValue & 0xf); +} + +int ColoredTile::getItemAuxValueForTileData(int data) +{ + return (~data & 0xf); +} + +void ColoredTile::registerIcons(IconRegister *iconRegister) +{ + for (int i = 0; i < ICON_COUNT; i++) + { + icons[i] = iconRegister->registerIcon(getIconName() + L"_" + DyePowderItem::COLOR_TEXTURES[getItemAuxValueForTileData(i)]); + } +} \ No newline at end of file diff --git a/Minecraft.World/ColoredTile.h b/Minecraft.World/ColoredTile.h new file mode 100644 index 00000000..19310dda --- /dev/null +++ b/Minecraft.World/ColoredTile.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Tile.h" + +class ColoredTile : public Tile +{ + friend class ChunkRebuildData; + +private: + static const int ICON_COUNT = 16; + Icon *icons[ICON_COUNT]; + +public: + ColoredTile(int id, Material *material); + + Icon *getTexture(int face, int data); + virtual int getSpawnResourcesAuxValue(int data); + static int getTileDataForItemAuxValue(int auxValue); + static int getItemAuxValueForTileData(int data); + virtual void registerIcons(IconRegister *iconRegister); +}; \ No newline at end of file diff --git a/Minecraft.World/CombatEntry.cpp b/Minecraft.World/CombatEntry.cpp new file mode 100644 index 00000000..903d95bb --- /dev/null +++ b/Minecraft.World/CombatEntry.cpp @@ -0,0 +1,71 @@ +#include "stdafx.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.entity.h" +#include "BasicTypeContainers.h" +#include "CombatEntry.h" + +CombatEntry::CombatEntry(DamageSource *source, int time, float health, float damage, CombatTracker::eLOCATION location, float fallDistance) +{ + this->source = NULL; + if(source != NULL) + { + // 4J: this might actually be a derived damage source so use copy func + this->source = source->copy(); + } + this->time = time; + this->damage = damage; + this->health = health; + this->location = location; + this->fallDistance = fallDistance; +} + +CombatEntry::~CombatEntry() +{ + delete source; +} + +DamageSource *CombatEntry::getSource() +{ + return source; +} + +int CombatEntry::getTime() +{ + return time; +} + +float CombatEntry::getDamage() +{ + return damage; +} + +float CombatEntry::getHealthBeforeDamage() +{ + return health; +} + +float CombatEntry::getHealthAfterDamage() +{ + return health - damage; +} + +bool CombatEntry::isCombatRelated() +{ + return source->getEntity() && source->getEntity()->instanceof(eTYPE_LIVINGENTITY); +} + +CombatTracker::eLOCATION CombatEntry::getLocation() +{ + return location; +} + +wstring CombatEntry::getAttackerName() +{ + return getSource()->getEntity() == NULL ? L"" : getSource()->getEntity()->getNetworkName(); +} + +float CombatEntry::getFallDistance() +{ + if (source == DamageSource::outOfWorld) return Float::MAX_VALUE; + return fallDistance; +} \ No newline at end of file diff --git a/Minecraft.World/CombatEntry.h b/Minecraft.World/CombatEntry.h new file mode 100644 index 00000000..5d5be6ae --- /dev/null +++ b/Minecraft.World/CombatEntry.h @@ -0,0 +1,29 @@ +#pragma once +#include "CombatTracker.h" + +class DamageSource; + +class CombatEntry +{ +private: + DamageSource *source; + int time; + float damage; + float health; + CombatTracker::eLOCATION location; // 4J: Location is now an enum, not a string + float fallDistance; + +public: + CombatEntry(DamageSource *source, int time, float health, float damage, CombatTracker::eLOCATION nextLocation, float fallDistance); + ~CombatEntry(); + + DamageSource *getSource(); + int getTime(); + float getDamage(); + float getHealthBeforeDamage(); + float getHealthAfterDamage(); + bool isCombatRelated(); + CombatTracker::eLOCATION getLocation(); + wstring getAttackerName(); + float getFallDistance(); +}; \ No newline at end of file diff --git a/Minecraft.World/CombatTracker.cpp b/Minecraft.World/CombatTracker.cpp new file mode 100644 index 00000000..77aac68a --- /dev/null +++ b/Minecraft.World/CombatTracker.cpp @@ -0,0 +1,252 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" +#include "net.minecraft.world.damagesource.h" +#include "CombatTracker.h" + +CombatTracker::CombatTracker(LivingEntity *mob) +{ + this->mob = mob; +} + +CombatTracker::~CombatTracker() +{ + for (AUTO_VAR(it,entries.begin()); it != entries.end(); ++it) + { + delete (*it); + } +} + + +void CombatTracker::prepareForDamage() +{ + resetPreparedStatus(); + + if (mob->onLadder()) + { + int type = mob->level->getTile(Mth::floor(mob->x), Mth::floor(mob->bb->y0), Mth::floor(mob->z)); + + if (type == Tile::ladder->id) + { + nextLocation = eLocation_LADDER; + } + else if (type == Tile::vine->id) + { + nextLocation = eLocation_VINES; + } + } + else if (mob->isInWater()) + { + nextLocation = eLocation_WATER; + } +} + +void CombatTracker::recordDamage(DamageSource *source, float health, float damage) +{ + recheckStatus(); + prepareForDamage(); + + CombatEntry *entry = new CombatEntry(source, mob->tickCount, health, damage, nextLocation, mob->fallDistance); + + entries.push_back(entry); + lastDamageTime = mob->tickCount; + takingDamage = true; + inCombat |= entry->isCombatRelated(); +} + +shared_ptr CombatTracker::getDeathMessagePacket() +{ + if (entries.size() == 0) return shared_ptr(new ChatPacket(mob->getNetworkName())); + + CombatEntry *knockOffEntry = getMostSignificantFall(); + CombatEntry *killingBlow = entries[entries.size() - 1]; + + shared_ptr result; + + shared_ptr killingEntity = killingBlow->getSource()->getEntity(); + + if (knockOffEntry != NULL && killingBlow->getSource()->equals(DamageSource::fall)) + { + shared_ptr attackerEntity = knockOffEntry->getSource()->getEntity(); + + if (knockOffEntry->getSource()->equals(DamageSource::fall) || knockOffEntry->getSource()->equals(DamageSource::outOfWorld)) + { + ChatPacket::EChatPacketMessage message; + + switch(getFallLocation(knockOffEntry)) + { + case eLocation_GENERIC: + message = ChatPacket::e_ChatDeathFellAccidentGeneric; + break; + case eLocation_LADDER: + message = ChatPacket::e_ChatDeathFellAccidentLadder; + break; + case eLocation_VINES: + message = ChatPacket::e_ChatDeathFellAccidentVines; + break; + case eLocation_WATER: + message = ChatPacket::e_ChatDeathFellAccidentWater; + break; + } + + result = shared_ptr(new ChatPacket(mob->getNetworkName(), message)); + } + else if (attackerEntity != NULL && (killingEntity == NULL || attackerEntity != killingEntity)) + { + shared_ptr attackerItem = attackerEntity->instanceof(eTYPE_LIVINGENTITY) ? dynamic_pointer_cast(attackerEntity)->getCarriedItem() : nullptr; + + if (attackerItem != NULL && attackerItem->hasCustomHoverName()) + { + result = shared_ptr(new ChatPacket(mob->getNetworkName(), ChatPacket::e_ChatDeathFellAssistItem, attackerEntity->GetType(), attackerEntity->getNetworkName(), attackerItem->getHoverName())); + } + else + { + result = shared_ptr(new ChatPacket(mob->getNetworkName(), ChatPacket::e_ChatDeathFellAssist, attackerEntity->GetType(), attackerEntity->getNetworkName())); + } + } + else if (killingEntity != NULL) + { + shared_ptr killerItem = killingEntity->instanceof(eTYPE_LIVINGENTITY) ? dynamic_pointer_cast(killingEntity)->getCarriedItem() : nullptr; + if (killerItem != NULL && killerItem->hasCustomHoverName()) + { + result = shared_ptr(new ChatPacket(mob->getNetworkName(), ChatPacket::e_ChatDeathFellFinishItem, killingEntity->GetType(), killingEntity->getNetworkName(), killerItem->getHoverName())); + } + else + { + result = shared_ptr(new ChatPacket(mob->getNetworkName(), ChatPacket::e_ChatDeathFellFinish, killingEntity->GetType(), killingEntity->getNetworkName())); + } + } + else + { + result = shared_ptr(new ChatPacket(mob->getNetworkName(), ChatPacket::e_ChatDeathFellKiller)); + } + } + else + { + result = killingBlow->getSource()->getDeathMessagePacket(dynamic_pointer_cast(mob->shared_from_this())); + } + + return result; +} + +shared_ptr CombatTracker::getKiller() +{ + shared_ptr bestMob = nullptr; + shared_ptr bestPlayer = nullptr; + float bestMobDamage = 0; + float bestPlayerDamage = 0; + + for (AUTO_VAR(it,entries.begin()); it != entries.end(); ++it) + { + CombatEntry *entry = *it; + if ( entry->getSource() != NULL && entry->getSource()->getEntity() != NULL && entry->getSource()->getEntity()->instanceof(eTYPE_PLAYER) && (bestPlayer == NULL || entry->getDamage() > bestPlayerDamage)) + { + bestPlayerDamage = entry->getDamage(); + bestPlayer = dynamic_pointer_cast(entry->getSource()->getEntity()); + } + + if ( entry->getSource() != NULL && entry->getSource()->getEntity() != NULL && entry->getSource()->getEntity()->instanceof(eTYPE_LIVINGENTITY) && (bestMob == NULL || entry->getDamage() > bestMobDamage)) + { + bestMobDamage = entry->getDamage(); + bestMob = dynamic_pointer_cast(entry->getSource()->getEntity()); + } + } + + if (bestPlayer != NULL && bestPlayerDamage >= bestMobDamage / 3) + { + return bestPlayer; + } + else + { + return bestMob; + } +} + +CombatEntry *CombatTracker::getMostSignificantFall() +{ + CombatEntry *result = NULL; + CombatEntry *alternative = NULL; + int altDamage = 0; + float bestFall = 0; + + for (int i = 0; i < entries.size(); i++) + { + CombatEntry *entry = entries.at(i); + CombatEntry *previous = i > 0 ? entries.at(i - 1) : NULL; + + bool isFall = entry->getSource()->equals(DamageSource::fall); + bool isOutOfWorld = entry->getSource()->equals(DamageSource::outOfWorld); + + if ((isFall || isOutOfWorld) && (entry->getFallDistance() > 0) && (result == NULL || entry->getFallDistance() > bestFall)) + { + if (i > 0) + { + result = previous; + } + else + { + result = entry; + } + bestFall = entry->getFallDistance(); + } + + if (entry->getLocation() != eLocation_GENERIC && (alternative == NULL || entry->getDamage() > altDamage)) + { + alternative = entry; + } + } + + if (bestFall > 5 && result != NULL) + { + return result; + } + else if (altDamage > 5 && alternative != NULL) + { + return alternative; + } + else + { + return NULL; + } +} + +CombatTracker::eLOCATION CombatTracker::getFallLocation(CombatEntry *entry) +{ + return entry->getLocation(); + +} + +bool CombatTracker::isTakingDamage() +{ + recheckStatus(); + return takingDamage; +} + +bool CombatTracker::isInCombat() +{ + recheckStatus(); + return inCombat; +} + +void CombatTracker::resetPreparedStatus() +{ + nextLocation = eLocation_GENERIC; +} + +void CombatTracker::recheckStatus() +{ + int reset = inCombat ? RESET_COMBAT_STATUS_TIME : RESET_DAMAGE_STATUS_TIME; + + if (takingDamage && mob->tickCount - lastDamageTime > reset) + { + for (AUTO_VAR(it,entries.begin()); it != entries.end(); ++it) + { + delete (*it); + } + entries.clear(); + takingDamage = false; + inCombat = false; + } +} \ No newline at end of file diff --git a/Minecraft.World/CombatTracker.h b/Minecraft.World/CombatTracker.h new file mode 100644 index 00000000..8c3b7717 --- /dev/null +++ b/Minecraft.World/CombatTracker.h @@ -0,0 +1,54 @@ +#pragma once + +#include "SharedConstants.h" + +class CombatEntry; +class LivingEntity; +class ChatPacket; + +class CombatTracker +{ +public: + static const int RESET_DAMAGE_STATUS_TIME = SharedConstants::TICKS_PER_SECOND * 5; + static const int RESET_COMBAT_STATUS_TIME = SharedConstants::TICKS_PER_SECOND * 15; + + // 4J: This enum replaces + enum eLOCATION + { + eLocation_GENERIC = 0, + eLocation_LADDER, + eLocation_VINES, + eLocation_WATER, + + eLocation_COUNT, + }; + +private: + vector entries; + LivingEntity *mob; //Owner + int lastDamageTime; + bool inCombat; + bool takingDamage; + eLOCATION nextLocation; // 4J: Location is now an enum, not a string + +public: + CombatTracker(LivingEntity *mob); + ~CombatTracker(); + + void prepareForDamage(); + void recordDamage(DamageSource *source, float health, float damage); + shared_ptr getDeathMessagePacket(); // 4J: Changed this to return a chat packet + shared_ptr getKiller(); + +private: + CombatEntry *getMostSignificantFall(); + eLOCATION getFallLocation(CombatEntry *entry); + +public: + bool isTakingDamage(); + bool isInCombat(); + +private: + void resetPreparedStatus(); + void recheckStatus(); +}; \ No newline at end of file diff --git a/Minecraft.World/Command.cpp b/Minecraft.World/Command.cpp index f6d0e592..bf546f6e 100644 --- a/Minecraft.World/Command.cpp +++ b/Minecraft.World/Command.cpp @@ -7,6 +7,11 @@ AdminLogCommand *Command::logger; +int Command::getPermissionLevel() +{ + return LEVEL_OWNERS; +} + bool Command::canExecute(shared_ptr source) { return source->hasPermission(getId()); diff --git a/Minecraft.World/Command.h b/Minecraft.World/Command.h index 815c24ba..8c060a6f 100644 --- a/Minecraft.World/Command.h +++ b/Minecraft.World/Command.h @@ -11,11 +11,24 @@ class ServerPlayer; class Command { +public: + // commands such as "help" and "emote" + static const int LEVEL_ALL = 0; + // commands such as "mute" + static const int LEVEL_MODERATORS = 1; + // commands such as "seed", "tp", "spawnpoint" and "give" + static const int LEVEL_GAMEMASTERS = 2; + // commands such as "whitelist", "ban", etc + static const int LEVEL_ADMINS = 3; + // commands such as "stop", "save-all", etc + static const int LEVEL_OWNERS = 4; + private: static AdminLogCommand *logger; public: virtual EGameCommand getId() = 0; + virtual int getPermissionLevel(); virtual void execute(shared_ptr source, byteArray commandData) = 0; virtual bool canExecute(shared_ptr source); diff --git a/Minecraft.World/CommandBlock.cpp b/Minecraft.World/CommandBlock.cpp new file mode 100644 index 00000000..e1b6b8dd --- /dev/null +++ b/Minecraft.World/CommandBlock.cpp @@ -0,0 +1,96 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "CommandBlock.h" + +CommandBlock::CommandBlock(int id) : BaseEntityTile(id, Material::metal, isSolidRender() ) +{ +} + +shared_ptr CommandBlock::newTileEntity(Level *level) +{ + return shared_ptr( new CommandBlockEntity() ); +} + +void CommandBlock::neighborChanged(Level *level, int x, int y, int z, int type) +{ + if (!level->isClientSide) + { + + bool signal = level->hasNeighborSignal(x, y, z); + int data = level->getData(x, y, z); + bool isTriggered = (data & TRIGGER_BIT) != 0; + + if (signal && !isTriggered) + { + level->setData(x, y, z, data | TRIGGER_BIT, Tile::UPDATE_NONE); + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); + } + else if (!signal && isTriggered) + { + level->setData(x, y, z, data & ~TRIGGER_BIT, Tile::UPDATE_NONE); + } + } +} + +void CommandBlock::tick(Level *level, int x, int y, int z, Random *random) +{ + shared_ptr tileEntity = level->getTileEntity(x, y, z); + + if (tileEntity != NULL && dynamic_pointer_cast( tileEntity ) != NULL) + { + shared_ptr commandBlock = dynamic_pointer_cast( tileEntity ); + commandBlock->setSuccessCount(commandBlock->performCommand(level)); + level->updateNeighbourForOutputSignal(x, y, z, id); + } +} + +int CommandBlock::getTickDelay(Level *level) +{ + return 1; +} + +bool CommandBlock::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly) +{ + shared_ptr amce = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + + if (amce != NULL) + { + player->openTextEdit(amce); + } + + return true; +} + +bool CommandBlock::hasAnalogOutputSignal() +{ + return true; +} + +int CommandBlock::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + shared_ptr tileEntity = level->getTileEntity(x, y, z); + + if (tileEntity != NULL && dynamic_pointer_cast( tileEntity ) != NULL) + { + return dynamic_pointer_cast( tileEntity )->getSuccessCount(); + } + + return Redstone::SIGNAL_NONE; +} + +void CommandBlock::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) +{ + shared_ptr cblock = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + + if (itemInstance->hasCustomHoverName()) + { + cblock->setName(itemInstance->getHoverName()); + } +} + +int CommandBlock::getResourceCount(Random *random) +{ + return 0; +} \ No newline at end of file diff --git a/Minecraft.World/CommandBlock.h b/Minecraft.World/CommandBlock.h new file mode 100644 index 00000000..eac83b51 --- /dev/null +++ b/Minecraft.World/CommandBlock.h @@ -0,0 +1,22 @@ +#pragma once + +#include "BaseEntityTile.h" + +class CommandBlock : public BaseEntityTile +{ +private: + static const int TRIGGER_BIT = 1; + +public: + CommandBlock(int id); + + virtual shared_ptr newTileEntity(Level *level); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual int getTickDelay(Level *level); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual int getResourceCount(Random *random); +}; \ No newline at end of file diff --git a/Minecraft.World/CommandBlockEntity.cpp b/Minecraft.World/CommandBlockEntity.cpp new file mode 100644 index 00000000..1c518f4f --- /dev/null +++ b/Minecraft.World/CommandBlockEntity.cpp @@ -0,0 +1,121 @@ +#include "stdafx.h" +#include "net.minecraft.network.packet.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.commands.h" +#include "..\Minecraft.Client\MinecraftServer.h" +#include "CommandBlockEntity.h" + +CommandBlockEntity::CommandBlockEntity() +{ + successCount = 0; + command = L""; + name = L"@"; +} + +void CommandBlockEntity::setCommand(const wstring &command) +{ + this->command = command; + setChanged(); +} + +wstring CommandBlockEntity::getCommand() +{ + return command; +} + +int CommandBlockEntity::performCommand(Level *level) +{ +#if 0 + if (level->isClientSide) + { + return 0; + } + + MinecraftServer *instance = MinecraftServer::getInstance(); + if (instance != NULL && instance->isCommandBlockEnabled()) + { + CommandDispatcher *commandDispatcher = instance->getCommandDispatcher(); + return commandDispatcher->performCommand(dynamic_pointer_cast(shared_from_this()), command, byteArray() ); + } + return 0; +#else + // 4J-JEV: Cannot decide what to do with the command field. + assert(false); + return 0; +#endif +} + +wstring CommandBlockEntity::getName() +{ + return name; +} + +void CommandBlockEntity::setName(const wstring &name) +{ + this->name = name; +} + +void CommandBlockEntity::sendMessage(const wstring& message, ChatPacket::EChatPacketMessage type, int customData , const wstring& additionalMessage) +{ +} + +bool CommandBlockEntity::hasPermission(EGameCommand command) +{ + return false; +} + +void CommandBlockEntity::save(CompoundTag *tag) +{ + TileEntity::save(tag); + tag->putString(L"Command", command); + tag->putInt(L"SuccessCount", successCount); + tag->putString(L"CustomName", name); +} + +void CommandBlockEntity::load(CompoundTag *tag) +{ + TileEntity::load(tag); + command = tag->getString(L"Command"); + successCount = tag->getInt(L"SuccessCount"); + if (tag->contains(L"CustomName")) name = tag->getString(L"CustomName"); +} + +Pos *CommandBlockEntity::getCommandSenderWorldPosition() +{ + return new Pos(x, y, z); +} + +Level *CommandBlockEntity::getCommandSenderWorld() +{ + return getLevel(); +} + +shared_ptr CommandBlockEntity::getUpdatePacket() +{ + CompoundTag *tag = new CompoundTag(); + save(tag); + return shared_ptr( new TileEntityDataPacket(x, y, z, TileEntityDataPacket::TYPE_ADV_COMMAND, tag) ); +} + +int CommandBlockEntity::getSuccessCount() +{ + return successCount; +} + +void CommandBlockEntity::setSuccessCount(int successCount) +{ + this->successCount = successCount; +} + +// 4J Added +shared_ptr CommandBlockEntity::clone() +{ + shared_ptr result = shared_ptr( new CommandBlockEntity() ); + TileEntity::clone(result); + + result->successCount = successCount; + result->command = command; + result->name = name; + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/CommandBlockEntity.h b/Minecraft.World/CommandBlockEntity.h new file mode 100644 index 00000000..3a3c10b6 --- /dev/null +++ b/Minecraft.World/CommandBlockEntity.h @@ -0,0 +1,41 @@ +#pragma once + +#include "TileEntity.h" +#include "CommandSender.h" + +class ChatMessageComponent; + +class CommandBlockEntity : public TileEntity, public CommandSender +{ +public: + eINSTANCEOF GetType() { return eTYPE_COMMANDBLOCKTILEENTITY; } + static TileEntity *create() { return new CommandBlockEntity(); } + + // 4J Added + virtual shared_ptr clone(); + +private: + int successCount; + wstring command; + wstring name; + +public: + CommandBlockEntity(); + + void setCommand(const wstring &command); + wstring getCommand(); + int performCommand(Level *level); + wstring getName(); + void setName(const wstring &name); + virtual void sendMessage(const wstring& message, ChatPacket::EChatPacketMessage type = ChatPacket::e_ChatCustom, int customData = -1, const wstring& additionalMessage = L""); + virtual bool hasPermission(EGameCommand command); + //void sendMessage(ChatMessageComponent *message); + //bool hasPermission(int permissionLevel, const wstring &commandName); + void save(CompoundTag *tag); + void load(CompoundTag *tag); + Pos *getCommandSenderWorldPosition(); + Level *getCommandSenderWorld(); + shared_ptr getUpdatePacket(); + int getSuccessCount(); + void setSuccessCount(int successCount); +}; \ No newline at end of file diff --git a/Minecraft.World/CommandDispatcher.cpp b/Minecraft.World/CommandDispatcher.cpp index 68b74ca9..545063db 100644 --- a/Minecraft.World/CommandDispatcher.cpp +++ b/Minecraft.World/CommandDispatcher.cpp @@ -2,7 +2,7 @@ #include "net.minecraft.commands.h" #include "CommandDispatcher.h" -void CommandDispatcher::performCommand(shared_ptr sender, EGameCommand command, byteArray commandData) +int CommandDispatcher::performCommand(shared_ptr sender, EGameCommand command, byteArray commandData) { AUTO_VAR(it, commandsById.find(command)); @@ -24,6 +24,8 @@ void CommandDispatcher::performCommand(shared_ptr sender, EGameCo { app.DebugPrintf("Command %d not found!\n", command); } + + return 0; } Command *CommandDispatcher::addCommand(Command *command) diff --git a/Minecraft.World/CommandDispatcher.h b/Minecraft.World/CommandDispatcher.h index 600f1db1..34d1b109 100644 --- a/Minecraft.World/CommandDispatcher.h +++ b/Minecraft.World/CommandDispatcher.h @@ -14,6 +14,6 @@ private: unordered_set commands; public: - void performCommand(shared_ptr sender, EGameCommand command, byteArray commandData); + int performCommand(shared_ptr sender, EGameCommand command, byteArray commandData); Command *addCommand(Command *command); }; \ No newline at end of file diff --git a/Minecraft.World/CommandsEnum.h b/Minecraft.World/CommandsEnum.h index 46793e21..ba46a5ee 100644 --- a/Minecraft.World/CommandsEnum.h +++ b/Minecraft.World/CommandsEnum.h @@ -3,6 +3,7 @@ enum EGameCommand { eGameCommand_DefaultGameMode, + eGameCommand_Effect, eGameCommand_EnchantItem, eGameCommand_Experience, eGameCommand_GameMode, diff --git a/Minecraft.World/CommonStats.cpp b/Minecraft.World/CommonStats.cpp index 8231070c..abef92aa 100644 --- a/Minecraft.World/CommonStats.cpp +++ b/Minecraft.World/CommonStats.cpp @@ -55,7 +55,7 @@ Stat *CommonStats::get_breedEntity(eINSTANCEOF mobType) Stat *CommonStats::get_tamedEntity(eINSTANCEOF mobType) { - if (mobType == eTYPE_OZELOT) return GenericStats::lionTamer(); + if (mobType == eTYPE_OCELOT) return GenericStats::lionTamer(); else if (mobType == eTYPE_WOLF) return Stats::befriendsWolf; else return NULL; } @@ -93,7 +93,7 @@ Stat *CommonStats::get_itemsCollected(int itemId, int itemAux) // stor itemsBought(emerald) so I don't have to make yet another massive // StatArray for Items Bought. #if (defined _EXTENDED_ACHIEVEMENTS) && (!defined _XBOX_ONE) - if (itemId == Tile::cloth_Id) return Stats::rainbowCollection[itemAux]; + if (itemId == Tile::wool_Id) return Stats::rainbowCollection[itemAux]; #endif if (itemId != Item::emerald_Id) return Stats::itemsCollected[itemId]; diff --git a/Minecraft.World/ComparatorTile.cpp b/Minecraft.World/ComparatorTile.cpp new file mode 100644 index 00000000..f611424d --- /dev/null +++ b/Minecraft.World/ComparatorTile.cpp @@ -0,0 +1,253 @@ +#include "stdafx.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.h" +#include "ComparatorTile.h" + +ComparatorTile::ComparatorTile(int id, bool on) : DiodeTile(id, on) +{ + _isEntityTile = true; +} + +int ComparatorTile::getResource(int data, Random *random, int playerBonusLevel) +{ + return Item::comparator_Id; +} + +int ComparatorTile::cloneTileId(Level *level, int x, int y, int z) +{ + return Item::comparator_Id; +} + +int ComparatorTile::getTurnOnDelay(int data) +{ + return 2; +} + +DiodeTile *ComparatorTile::getOnTile() +{ + return Tile::comparator_on; +} + +DiodeTile *ComparatorTile::getOffTile() +{ + return Tile::comparator_off; +} + +int ComparatorTile::getRenderShape() +{ + return SHAPE_COMPARATOR; +} + +Icon *ComparatorTile::getTexture(int face, int data) +{ + bool isOn = on || (data & BIT_IS_LIT) != 0; + // down is used by the torch tesselator + if (face == Facing::DOWN) + { + if (isOn) + { + return Tile::redstoneTorch_on->getTexture(face); + } + return Tile::redstoneTorch_off->getTexture(face); + } + if (face == Facing::UP) + { + if (isOn) + { + return Tile::comparator_on->icon; + } + return icon; + } + // edge of stone half-step + return Tile::stoneSlab->getTexture(Facing::UP); +} + +bool ComparatorTile::isOn(int data) +{ + return on || (data & BIT_IS_LIT) != 0; +} + +int ComparatorTile::getOutputSignal(LevelSource *levelSource, int x, int y, int z, int data) +{ + return getComparator(levelSource, x, y, z)->getOutputSignal(); +} + +int ComparatorTile::calculateOutputSignal(Level *level, int x, int y, int z, int data) +{ + if (!isReversedOutputSignal(data)) + { + return getInputSignal(level, x, y, z, data); + } + else + { + return max(getInputSignal(level, x, y, z, data) - getAlternateSignal(level, x, y, z, data), Redstone::SIGNAL_NONE); + } +} + +bool ComparatorTile::isReversedOutputSignal(int data) +{ + return (data & BIT_OUTPUT_SUBTRACT) == BIT_OUTPUT_SUBTRACT; +} + +bool ComparatorTile::shouldTurnOn(Level *level, int x, int y, int z, int data) +{ + int input = getInputSignal(level, x, y, z, data); + if (input >= Redstone::SIGNAL_MAX) return true; + if (input == Redstone::SIGNAL_NONE) return false; + + int alt = getAlternateSignal(level, x, y, z, data); + if (alt == Redstone::SIGNAL_NONE) return true; + + return input >= alt; +} + +int ComparatorTile::getInputSignal(Level *level, int x, int y, int z, int data) +{ + int result = DiodeTile::getInputSignal(level, x, y, z, data); + + int dir = getDirection(data); + int xx = x + Direction::STEP_X[dir]; + int zz = z + Direction::STEP_Z[dir]; + int tile = level->getTile(xx, y, zz); + + if (tile > 0) + { + if (Tile::tiles[tile]->hasAnalogOutputSignal()) + { + result = Tile::tiles[tile]->getAnalogOutputSignal(level, xx, y, zz, Direction::DIRECTION_OPPOSITE[dir]); + } + else if (result < Redstone::SIGNAL_MAX && Tile::isSolidBlockingTile(tile)) + { + xx += Direction::STEP_X[dir]; + zz += Direction::STEP_Z[dir]; + tile = level->getTile(xx, y, zz); + + if (tile > 0 && Tile::tiles[tile]->hasAnalogOutputSignal()) + { + result = Tile::tiles[tile]->getAnalogOutputSignal(level, xx, y, zz, Direction::DIRECTION_OPPOSITE[dir]); + } + } + } + + return result; +} + +shared_ptr ComparatorTile::getComparator(LevelSource *level, int x, int y, int z) +{ + return dynamic_pointer_cast( level->getTileEntity(x, y, z) ); +} + +bool ComparatorTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly) +{ + int data = level->getData(x, y, z); + bool isOn = on || ( (data & BIT_IS_LIT) != 0 ); + bool subtract = !isReversedOutputSignal(data); + int outputBit = subtract ? BIT_OUTPUT_SUBTRACT : 0; + outputBit |= isOn ? BIT_IS_LIT : 0; + + level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, subtract ? 0.55f : 0.5f); + + if (!soundOnly) + { + level->setData(x, y, z, outputBit | (data & DIRECTION_MASK), Tile::UPDATE_CLIENTS); + refreshOutputState(level, x, y, z, level->random); + } + + return true; +} + +void ComparatorTile::checkTickOnNeighbor(Level *level, int x, int y, int z, int type) +{ + if (!level->isTileToBeTickedAt(x, y, z, id)) + { + int data = level->getData(x, y, z); + int outputValue = calculateOutputSignal(level, x, y, z, data); + int oldValue = getComparator(level, x, y, z)->getOutputSignal(); + + if (outputValue != oldValue || (isOn(data) != shouldTurnOn(level, x, y, z, data))) + { + // prioritize locking comparators + if (shouldPrioritize(level, x, y, z, data)) + { + level->addToTickNextTick(x, y, z, id, getTurnOnDelay(0), -1); + } + else + { + level->addToTickNextTick(x, y, z, id, getTurnOnDelay(0), 0); + } + } + } +} + +void ComparatorTile::refreshOutputState(Level *level, int x, int y, int z, Random *random) +{ + int data = level->getData(x, y, z); + int outputValue = calculateOutputSignal(level, x, y, z, data); + int oldValue = getComparator(level, x, y, z)->getOutputSignal(); + getComparator(level, x, y, z)->setOutputSignal(outputValue); + + if (oldValue != outputValue || !isReversedOutputSignal(data)) + { + bool sourceOn = shouldTurnOn(level, x, y, z, data); + bool isOn = on || (data & BIT_IS_LIT) != 0; + if (isOn && !sourceOn) + { + level->setData(x, y, z, data & ~BIT_IS_LIT, Tile::UPDATE_CLIENTS); + } + else if (!isOn && sourceOn) + { + level->setData(x, y, z, data | BIT_IS_LIT, Tile::UPDATE_CLIENTS); + } + updateNeighborsInFront(level, x, y, z); + } +} + +void ComparatorTile::tick(Level *level, int x, int y, int z, Random *random) +{ + if (on) + { + // clean-up old tiles with the 'on' id + int data = level->getData(x, y, z); + level->setTileAndData(x, y, z, getOffTile()->id, data | BIT_IS_LIT, Tile::UPDATE_NONE); + } + refreshOutputState(level, x, y, z, random); +} + +void ComparatorTile::onPlace(Level *level, int x, int y, int z) +{ + DiodeTile::onPlace(level, x, y, z); + level->setTileEntity(x, y, z, newTileEntity(level)); +} + +void ComparatorTile::onRemove(Level *level, int x, int y, int z, int id, int data) +{ + DiodeTile::onRemove(level, x, y, z, id, data); + level->removeTileEntity(x, y, z); + + updateNeighborsInFront(level, x, y, z); +} + +bool ComparatorTile::triggerEvent(Level *level, int x, int y, int z, int b0, int b1) +{ + DiodeTile::triggerEvent(level, x, y, z, b0, b1); + shared_ptr te = level->getTileEntity(x, y, z); + if (te != NULL) + { + return te->triggerEvent(b0, b1); + } + return false; +} + +shared_ptr ComparatorTile::newTileEntity(Level *level) +{ + return shared_ptr( new ComparatorTileEntity() ); +} + +bool ComparatorTile::TestUse() +{ + return true; +} \ No newline at end of file diff --git a/Minecraft.World/ComparatorTile.h b/Minecraft.World/ComparatorTile.h new file mode 100644 index 00000000..3358d3ab --- /dev/null +++ b/Minecraft.World/ComparatorTile.h @@ -0,0 +1,60 @@ +#pragma once + +#include "DiodeTile.h" +#include "EntityTile.h" + +class ComparatorTileEntity; + +class ComparatorTile : public DiodeTile, public EntityTile +{ +private: + static const int BIT_OUTPUT_SUBTRACT = 0x4; + static const int BIT_IS_LIT = 0x8; + +public: + ComparatorTile(int id, bool on); + + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual int cloneTileId(Level *level, int x, int y, int z); + +protected: + virtual int getTurnOnDelay(int data); + virtual DiodeTile *getOnTile(); + virtual DiodeTile *getOffTile(); + +public: + virtual int getRenderShape(); + virtual Icon *getTexture(int face, int data); + +protected: + virtual bool isOn(int data); + virtual int getOutputSignal(LevelSource *levelSource, int x, int y, int z, int data); + +private: + virtual int calculateOutputSignal(Level *level, int x, int y, int z, int data); + +public: + virtual bool isReversedOutputSignal(int data); + +protected: + virtual bool shouldTurnOn(Level *level, int x, int y, int z, int data); + virtual int getInputSignal(Level *level, int x, int y, int z, int data); + virtual shared_ptr getComparator(LevelSource *level, int x, int y, int z); + +public: + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); + +protected: + virtual void checkTickOnNeighbor(Level *level, int x, int y, int z, int type); + +private: + virtual void refreshOutputState(Level *level, int x, int y, int z, Random *random); + +public: + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual void onPlace(Level *level, int x, int y, int z); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual bool triggerEvent(Level *level, int x, int y, int z, int b0, int b1); + virtual shared_ptr newTileEntity(Level *level); + virtual bool TestUse(); +}; \ No newline at end of file diff --git a/Minecraft.World/ComparatorTileEntity.cpp b/Minecraft.World/ComparatorTileEntity.cpp new file mode 100644 index 00000000..9a58d23c --- /dev/null +++ b/Minecraft.World/ComparatorTileEntity.cpp @@ -0,0 +1,36 @@ +#include "stdafx.h" + +#include "ComparatorTileEntity.h" + +void ComparatorTileEntity::save(CompoundTag *tag) +{ + TileEntity::save(tag); + tag->putInt(L"OutputSignal", output); +} + +void ComparatorTileEntity::load(CompoundTag *tag) +{ + TileEntity::load(tag); + output = tag->getInt(L"OutputSignal"); +} + +int ComparatorTileEntity::getOutputSignal() +{ + return output; +} + +void ComparatorTileEntity::setOutputSignal(int value) +{ + output = value; +} + +// 4J Added +shared_ptr ComparatorTileEntity::clone() +{ + shared_ptr result = shared_ptr( new ComparatorTileEntity() ); + TileEntity::clone(result); + + result->output = output; + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/ComparatorTileEntity.h b/Minecraft.World/ComparatorTileEntity.h new file mode 100644 index 00000000..edbf367f --- /dev/null +++ b/Minecraft.World/ComparatorTileEntity.h @@ -0,0 +1,22 @@ +#pragma once + +#include "TileEntity.h" + +class ComparatorTileEntity : public TileEntity +{ +public: + eINSTANCEOF GetType() { return eTYPE_COMPARATORTILEENTITY; } + static TileEntity *create() { return new ComparatorTileEntity(); } + + // 4J Added + virtual shared_ptr clone(); + +private: + int output; + +public: + void save(CompoundTag *tag); + void load(CompoundTag *tag); + int getOutputSignal(); + void setOutputSignal(int value); +}; \ No newline at end of file diff --git a/Minecraft.World/ComplexItemDataPacket.cpp b/Minecraft.World/ComplexItemDataPacket.cpp index 4c365bbd..38c39cb6 100644 --- a/Minecraft.World/ComplexItemDataPacket.cpp +++ b/Minecraft.World/ComplexItemDataPacket.cpp @@ -32,7 +32,7 @@ void ComplexItemDataPacket::read(DataInputStream *dis) //throws IOException itemType = dis->readShort(); itemId = dis->readShort(); - data = charArray(dis->readShort() & 0xffff); + data = charArray(dis->readUnsignedShort() & 0xffff); dis->readFully(data); } @@ -40,7 +40,7 @@ void ComplexItemDataPacket::write(DataOutputStream *dos) //throws IOException { dos->writeShort(itemType); dos->writeShort(itemId); - dos->writeShort(data.length); + dos->writeUnsignedShort(data.length); byteArray ba( (byte*)data.data, data.length ); dos->write(ba); diff --git a/Minecraft.World/CompoundContainer.cpp b/Minecraft.World/CompoundContainer.cpp index 29bf60dd..674f15db 100644 --- a/Minecraft.World/CompoundContainer.cpp +++ b/Minecraft.World/CompoundContainer.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" #include "net.minecraft.world.entity.player.h" - +#include "ContainerOpenPacket.h" #include "CompoundContainer.h" CompoundContainer::CompoundContainer(int name, shared_ptr c1, shared_ptr c2) @@ -12,14 +12,38 @@ CompoundContainer::CompoundContainer(int name, shared_ptr c1, shared_ this->c2 = c2; } +int CompoundContainer::getContainerType() +{ + return ContainerOpenPacket::LARGE_CHEST; +} + unsigned int CompoundContainer::getContainerSize() { return c1->getContainerSize() + c2->getContainerSize(); } -int CompoundContainer::getName() +bool CompoundContainer::contains(shared_ptr c) +{ + return c1 == c || c2 == c; +} + +wstring CompoundContainer::getName() +{ + if (c1->hasCustomName()) return c1->getName(); + if (c2->hasCustomName()) return c2->getName(); + return app.GetString(name); +} + +wstring CompoundContainer::getCustomName() +{ + if (c1->hasCustomName()) return c1->getName(); + if (c2->hasCustomName()) return c2->getName(); + return L""; +} + +bool CompoundContainer::hasCustomName() { - return name; + return c1->hasCustomName() || c2->hasCustomName(); } shared_ptr CompoundContainer::getItem(unsigned int slot) @@ -72,4 +96,9 @@ void CompoundContainer::stopOpen() { c1->stopOpen(); c2->stopOpen(); +} + +bool CompoundContainer::canPlaceItem(int slot, shared_ptr item) +{ + return true; } \ No newline at end of file diff --git a/Minecraft.World/CompoundContainer.h b/Minecraft.World/CompoundContainer.h index b0b8b934..126a712a 100644 --- a/Minecraft.World/CompoundContainer.h +++ b/Minecraft.World/CompoundContainer.h @@ -14,23 +14,21 @@ private: public: CompoundContainer(int name, shared_ptr c1, shared_ptr c2); - unsigned int getContainerSize(); - - int getName(); - - shared_ptr getItem(unsigned int slot); - - shared_ptr removeItem(unsigned int slot, int i); - shared_ptr removeItemNoUpdate(int slot); - - void setItem(unsigned int slot, shared_ptr item); - - int getMaxStackSize(); - - void setChanged(); - - bool stillValid(shared_ptr player); + virtual int getContainerType(); + virtual unsigned int getContainerSize(); + virtual bool contains(shared_ptr c); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual bool hasCustomName(); + virtual shared_ptr getItem(unsigned int slot); + virtual shared_ptr removeItem(unsigned int slot, int i); + virtual shared_ptr removeItemNoUpdate(int slot); + virtual void setItem(unsigned int slot, shared_ptr item); + virtual int getMaxStackSize(); + virtual void setChanged(); + virtual bool stillValid(shared_ptr player); virtual void startOpen(); virtual void stopOpen(); + virtual bool canPlaceItem(int slot, shared_ptr item); }; \ No newline at end of file diff --git a/Minecraft.World/CompoundTag.h b/Minecraft.World/CompoundTag.h index 32c31583..29d35041 100644 --- a/Minecraft.World/CompoundTag.h +++ b/Minecraft.World/CompoundTag.h @@ -20,7 +20,7 @@ public: CompoundTag() : Tag(L"") {} CompoundTag(const wstring &name) : Tag(name) {} - void write(DataOutput *dos) + void write(DataOutput *dos) { AUTO_VAR(itEnd, tags.end()); for( unordered_map::iterator it = tags.begin(); it != itEnd; it++ ) @@ -28,180 +28,188 @@ public: Tag::writeNamedTag(it->second, dos); } dos->writeByte(Tag::TAG_End); - } + } - void load(DataInput *dis) + void load(DataInput *dis, int tagDepth) { - tags.clear(); - Tag *tag; - while ((tag = Tag::readNamedTag(dis))->getId() != Tag::TAG_End) + if(tagDepth > MAX_DEPTH) + { +#ifndef _CONTENT_PACKAGE + printf("Tried to read NBT tag with too high complexity, depth > %d" , MAX_DEPTH); + __debugbreak(); +#endif + return; + } + tags.clear(); + Tag *tag; + while ((tag = Tag::readNamedTag(dis))->getId() != Tag::TAG_End) { tags[tag->getName()] = tag; - } + } delete tag; - } + } - vector *getAllTags() // 4J - was collection + vector *getAllTags() // 4J - was collection { // 4J - was return tags.values(); vector *ret = new vector; - + AUTO_VAR(itEnd, tags.end()); for( unordered_map::iterator it = tags.begin(); it != itEnd; it++ ) { ret->push_back(it->second); } - return ret; - } + return ret; + } - byte getId() + byte getId() { - return TAG_Compound; - } + return TAG_Compound; + } - void put(wchar_t *name, Tag *tag) + void put(const wstring &name, Tag *tag) { - tags[name] = tag->setName(wstring( name )); - } + tags[name] = tag->setName(name); + } - void putByte(wchar_t * name, byte value) + void putByte(const wstring &name, byte value) { - tags[name] = (new ByteTag(name,value)); - } + tags[name] = (new ByteTag(name,value)); + } - void putShort(wchar_t * name, short value) + void putShort(const wstring &name, short value) { - tags[name] = (new ShortTag(name,value)); - } + tags[name] = (new ShortTag(name,value)); + } - void putInt(wchar_t * name, int value) + void putInt(const wstring &name, int value) { - tags[name] = (new IntTag(name,value)); - } + tags[name] = (new IntTag(name,value)); + } - void putLong(wchar_t * name, __int64 value) + void putLong(const wstring &name, __int64 value) { - tags[name] = (new LongTag(name,value)); - } + tags[name] = (new LongTag(name,value)); + } - void putFloat(wchar_t * name, float value) + void putFloat(const wstring &name, float value) { - tags[name] = (new FloatTag(name,value)); - } + tags[name] = (new FloatTag(name,value)); + } - void putDouble(wchar_t * name, double value) + void putDouble(const wstring &name, double value) { - tags[name] = (new DoubleTag(name,value)); - } + tags[name] = (new DoubleTag(name,value)); + } - void putString(wchar_t *name, const wstring& value) + void putString(const wstring &name, const wstring& value) { - tags[name] = (new StringTag(name,value)); - } + tags[name] = (new StringTag(name,value)); + } - void putByteArray(wchar_t * name, byteArray value) + void putByteArray(const wstring &name, byteArray value) { - tags[name] = (new ByteArrayTag(name,value)); - } + tags[name] = (new ByteArrayTag(name,value)); + } - void putIntArray(wchar_t * name, intArray value) + void putIntArray(const wstring &name, intArray value) { tags[name] = (new IntArrayTag(name, value)); } - void putCompound(wchar_t * name, CompoundTag *value) + void putCompound(const wstring &name, CompoundTag *value) { - tags[name] = value->setName( wstring( name ) ); - } + tags[name] = value->setName( wstring( name ) ); + } - void putBoolean(wchar_t * string, bool val) + void putBoolean(const wstring &name, bool val) { - putByte(string, val?(byte)1:0); - } + putByte(name, val?(byte)1:0); + } - Tag *get(wchar_t *name) + Tag *get(const wstring &name) { AUTO_VAR(it, tags.find(name)); if(it != tags.end()) return it->second; return NULL; - } - - bool contains(wchar_t * name) + } + + bool contains(const wstring &name) { return tags.find(name) != tags.end(); - } + } - byte getByte(wchar_t * name) + byte getByte(const wstring &name) { - if (tags.find(name) == tags.end()) return (byte)0; - return ((ByteTag *) tags[name])->data; - } + if (tags.find(name) == tags.end()) return (byte)0; + return ((ByteTag *) tags[name])->data; + } - short getShort(wchar_t * name) + short getShort(const wstring &name) { - if (tags.find(name) == tags.end()) return (short)0; - return ((ShortTag *) tags[name])->data; - } + if (tags.find(name) == tags.end()) return (short)0; + return ((ShortTag *) tags[name])->data; + } - int getInt(wchar_t * name) + int getInt(const wstring &name) { - if (tags.find(name) == tags.end()) return (int)0; - return ((IntTag *) tags[name])->data; - } + if (tags.find(name) == tags.end()) return (int)0; + return ((IntTag *) tags[name])->data; + } - __int64 getLong(wchar_t * name) + __int64 getLong(const wstring &name) { - if (tags.find(name) == tags.end()) return (__int64)0; - return ((LongTag *) tags[name])->data; - } + if (tags.find(name) == tags.end()) return (__int64)0; + return ((LongTag *) tags[name])->data; + } - float getFloat(wchar_t * name) + float getFloat(const wstring &name) { - if (tags.find(name) == tags.end()) return (float)0; - return ((FloatTag *) tags[name])->data; - } + if (tags.find(name) == tags.end()) return (float)0; + return ((FloatTag *) tags[name])->data; + } - double getDouble(wchar_t * name) + double getDouble(const wstring &name) { - if (tags.find(name) == tags.end()) return (double)0; - return ((DoubleTag *) tags[name])->data; - } + if (tags.find(name) == tags.end()) return (double)0; + return ((DoubleTag *) tags[name])->data; + } - wstring getString(wchar_t * name) + wstring getString(const wstring &name) { - if (tags.find(name) == tags.end()) return wstring( L"" ); - return ((StringTag *) tags[name])->data; - } + if (tags.find(name) == tags.end()) return wstring( L"" ); + return ((StringTag *) tags[name])->data; + } - byteArray getByteArray(wchar_t * name) + byteArray getByteArray(const wstring &name) { - if (tags.find(name) == tags.end()) return byteArray(); - return ((ByteArrayTag *) tags[name])->data; - } + if (tags.find(name) == tags.end()) return byteArray(); + return ((ByteArrayTag *) tags[name])->data; + } - intArray getIntArray(wchar_t * name) + intArray getIntArray(const wstring &name) { - if (tags.find(name) == tags.end()) return intArray(0); + if (tags.find(name) == tags.end()) return intArray(); return ((IntArrayTag *) tags[name])->data; } - CompoundTag *getCompound(wchar_t * name) + CompoundTag *getCompound(const wstring &name) { - if (tags.find(name) == tags.end()) return new CompoundTag(name); - return (CompoundTag *) tags[name]; - } + if (tags.find(name) == tags.end()) return new CompoundTag(name); + return (CompoundTag *) tags[name]; + } - ListTag *getList(wchar_t * name) + ListTag *getList(const wstring &name) { - if (tags.find(name) == tags.end()) return new ListTag(name); - return (ListTag *) tags[name]; - } + if (tags.find(name) == tags.end()) return new ListTag(name); + return (ListTag *) tags[name]; + } - bool getBoolean(wchar_t *string) + bool getBoolean(const wstring &string) { - return getByte(string)!=0; - } + return getByte(string)!=0; + } void remove(const wstring &name) { @@ -210,38 +218,38 @@ public: //tags.remove(name); } - wstring toString() + wstring toString() { static const int bufSize = 32; static wchar_t buf[bufSize]; swprintf(buf,bufSize,L"%d entries",tags.size()); return wstring( buf ); - } + } - void print(char *prefix, ostream out) + void print(char *prefix, ostream out) { /* - Tag::print(prefix, out); + Tag::print(prefix, out); out << prefix << "{" << endl; char *newPrefix = new char[ strlen(prefix) + 4 ]; strcpy( newPrefix, prefix); strcat( newPrefix, " "); - + AUTO_VAR(itEnd, tags.end()); for( unordered_map::iterator it = tags.begin(); it != itEnd; it++ ) { - it->second->print(newPrefix, out); + it->second->print(newPrefix, out); } delete[] newPrefix; out << prefix << "}" << endl; */ - } + } - bool isEmpty() + bool isEmpty() { return tags.empty(); - } + } virtual ~CompoundTag() { @@ -255,7 +263,7 @@ public: Tag *copy() { CompoundTag *tag = new CompoundTag(getName()); - + AUTO_VAR(itEnd, tags.end()); for( AUTO_VAR(it, tags.begin()); it != itEnd; it++ ) { diff --git a/Minecraft.World/CompressedTileStorage.cpp b/Minecraft.World/CompressedTileStorage.cpp index 896bd58d..12c1ba3b 100644 --- a/Minecraft.World/CompressedTileStorage.cpp +++ b/Minecraft.World/CompressedTileStorage.cpp @@ -11,6 +11,7 @@ static const int sc_maxCompressTiles = 64; static CompressedTileStorage_compress_dataIn g_compressTileDataIn[sc_maxCompressTiles] __attribute__((__aligned__(16))); static int g_currentCompressTiles = 0; +//#define DISABLE_SPU_CODE #endif //__PS3__ // Note: See header for an overview of this class diff --git a/Minecraft.World/Connection.cpp b/Minecraft.World/Connection.cpp index 4392fe54..09f72be0 100644 --- a/Minecraft.World/Connection.cpp +++ b/Minecraft.World/Connection.cpp @@ -174,8 +174,10 @@ void Connection::send(shared_ptr packet) void Connection::queueSend(shared_ptr packet) { if (quitting) return; + EnterCriticalSection(&writeLock); estimatedRemaining += packet->getEstimatedSize() + 1; outgoing_slow.push(packet); + LeaveCriticalSection(&writeLock); } bool Connection::writeTick() @@ -204,8 +206,20 @@ bool Connection::writeTick() #ifndef _CONTENT_PACKAGE // 4J Added for debugging + int playerId = 0; if( !socket->isLocal() ) - Packet::recordOutgoingPacket(packet); + { + Socket *socket = getSocket(); + if( socket ) + { + INetworkPlayer *player = socket->getPlayer(); + if( player ) + { + playerId = player->GetSmallId(); + } + } + Packet::recordOutgoingPacket(packet,playerId); + } #endif // 4J Stu - Changed this so that rather than writing to the network stream through a buffered stream we want to: @@ -241,7 +255,11 @@ bool Connection::writeTick() // 4J Stu - Changed this so that rather than writing to the network stream through a buffered stream we want to: // a) Only push whole "game" packets to QNet, rather than amalgamated chunks of data that may include many packets, and partial packets // b) To be able to change the priority and queue of a packet if required +#ifdef _XBOX int flags = QNET_SENDDATA_LOW_PRIORITY | QNET_SENDDATA_SECONDARY; +#else + int flags = NON_QNET_SENDDATA_ACK_REQUIRED; +#endif sos->writeWithFlags( baos->buf, 0, baos->size(), flags ); baos->reset(); } @@ -253,7 +271,22 @@ bool Connection::writeTick() #ifndef _CONTENT_PACKAGE // 4J Added for debugging if( !socket->isLocal() ) - Packet::recordOutgoingPacket(packet); + { + int playerId = 0; + if( !socket->isLocal() ) + { + Socket *socket = getSocket(); + if( socket ) + { + INetworkPlayer *player = socket->getPlayer(); + if( player ) + { + playerId = player->GetSmallId(); + } + } + Packet::recordOutgoingPacket(packet,playerId); + } + } #endif writeSizes[packet->getId()] += packet->getEstimatedSize() + 1; diff --git a/Minecraft.World/ConsoleSaveFileConverter.cpp b/Minecraft.World/ConsoleSaveFileConverter.cpp index 9a3d572d..16b025a5 100644 --- a/Minecraft.World/ConsoleSaveFileConverter.cpp +++ b/Minecraft.World/ConsoleSaveFileConverter.cpp @@ -133,7 +133,9 @@ void ConsoleSaveFileConverter::ConvertSave(ConsoleSaveFile *sourceSave, ConsoleS if(progress) { +#ifndef _WINDOWS64 progress->progressStage(IDS_SAVETRANSFER_STAGE_CONVERTING); +#endif } // Overworld @@ -167,10 +169,11 @@ void ConsoleSaveFileConverter::ConvertSave(ConsoleSaveFile *sourceSave, ConsoleS bos.flush(); dos->close(); dos->deleteChildStream(); - delete dos; + delete dos; + dis->deleteChildStream(); + delete dis; } - delete dis; ++currentProgress; if(progress) progress->progressStagePercentage( (currentProgress*100)/progressTarget); @@ -212,9 +215,10 @@ void ConsoleSaveFileConverter::ConvertSave(ConsoleSaveFile *sourceSave, ConsoleS dos->close(); dos->deleteChildStream(); delete dos; + dis->deleteChildStream(); + delete dis; } - delete dis; ++currentProgress; if(progress) progress->progressStagePercentage((currentProgress*100)/progressTarget); @@ -254,9 +258,10 @@ void ConsoleSaveFileConverter::ConvertSave(ConsoleSaveFile *sourceSave, ConsoleS dos->close(); dos->deleteChildStream(); delete dos; + dis->deleteChildStream(); + delete dis; } - delete dis; ++currentProgress; if(progress) progress->progressStagePercentage((currentProgress*100)/progressTarget); diff --git a/Minecraft.World/ConsoleSaveFileOriginal.cpp b/Minecraft.World/ConsoleSaveFileOriginal.cpp index 139d99ac..c07808d4 100644 --- a/Minecraft.World/ConsoleSaveFileOriginal.cpp +++ b/Minecraft.World/ConsoleSaveFileOriginal.cpp @@ -637,6 +637,15 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail ) { LockSaveAccess(); +#ifdef __PSVITA__ + // On Vita we've had problems with saves being corrupted on rapid save/save-exiting so seems prudent to wait for idle + while( StorageManager.GetSaveState() != C4JStorage::ESaveGame_Idle ) + { + app.DebugPrintf("Flush wait\n"); + Sleep(10); + } +#endif + finalizeWrite(); // Get the frequency of the timer diff --git a/Minecraft.World/ConsoleSaveFileSplit.cpp b/Minecraft.World/ConsoleSaveFileSplit.cpp deleted file mode 100644 index 2d83f217..00000000 --- a/Minecraft.World/ConsoleSaveFileSplit.cpp +++ /dev/null @@ -1,1711 +0,0 @@ -#include "stdafx.h" -#include "StringHelpers.h" -#include "ConsoleSaveFileSplit.h" -#include "ConsoleSaveFileConverter.h" -#include "File.h" -#include -#include "compression.h" -#include "..\Minecraft.Client\Minecraft.h" -#include "..\Minecraft.Client\MinecraftServer.h" -#include "..\Minecraft.Client\ServerLevel.h" -#include "..\Minecraft.World\net.minecraft.world.level.h" -#include "..\Minecraft.World\LevelData.h" -#include "..\Minecraft.Client\Common\GameRules\LevelGenerationOptions.h" -#include "..\Minecraft.World\net.minecraft.world.level.chunk.storage.h" - -#define RESERVE_ALLOCATION MEM_RESERVE -#define COMMIT_ALLOCATION MEM_COMMIT - -unsigned int ConsoleSaveFileSplit::pagesCommitted = 0; -void *ConsoleSaveFileSplit::pvHeap = NULL; - -ConsoleSaveFileSplit::RegionFileReference::RegionFileReference(int index, unsigned int regionIndex, unsigned int length/*=0*/, unsigned char *data/*=NULL*/) -{ - fileEntry = new FileEntry(); - fileEntry->currentFilePointer = 0; - fileEntry->data.length = 0; - fileEntry->data.regionIndex = regionIndex; - this->data = 0; - this->index = index; - this->dirty = false; - this->dataCompressed = data; - this->dataCompressedSize = length; - this->lastWritten = 0; -} - -ConsoleSaveFileSplit::RegionFileReference::~RegionFileReference() -{ - free(data); - delete fileEntry; -} - -// Compress from data to dataCompressed. Uses a special compression method that is designed just to efficiently store runs of zeros, with little overhead on other stuff. -// Compresed format is a 4 byte uncompressed size, followed by data as follows: -// -// Byte value Meaning -// -// 1 - 255 Normal data -// 0 followed by 1 - 255 Run of 1 - 255 0s -// 0 followed by 0, followed by 256 to 65791 (as 2 bytes) Run of 256 to 65791 zeros - -void ConsoleSaveFileSplit::RegionFileReference::Compress() -{ - unsigned char *dataIn = data; - unsigned char *dataInLast = data + fileEntry->data.length; - -// int64_t startTime = System::currentTimeMillis(); - - // One pass through to work out storage space required for compressed data - unsigned int outputSize = 4; // 4 bytes required to store the uncompressed size for faster decompression - unsigned int runLength = 0; - while( dataIn != dataInLast ) - { - unsigned char thisByte = *dataIn++; - if( ( thisByte != 0 ) || ( runLength == ( 65535 + 256 ) ) ) - { - // We've got a non-zero value, or we've hit our maximum run length. - // If there was a preceeding run of zeros, encode that nwo - if( runLength != 0 ) - { - if( runLength < 256 ) - { - // Runs of 1 to 255 encoded as 0 followed by one byte of run length - outputSize += 2; - } - else - { - // Runs of 256 to 65791 encoded as two 0s followed by two bytes of run length - 256 - outputSize += 4; - } - // Run is now processed - runLength = 0; - } - // Now handle the current byte - if( thisByte == 0 ) - { - runLength++; - } - else - { - // Non-zero, just copy over to output - outputSize++; - } - } - else - { - // It's a zero - keep counting size of the run - runLength++; - } - } - // Handle any outstanding run - if ( runLength != 0 ) - { - if( runLength < 256 ) - { - // Runs of 1 to 255 encoded as 0 followed by one byte of run length - outputSize += 2; - } - else - { - // Runs of 256 to 65791 encoded as two 0s followed by two bytes of run length - 256 - outputSize += 4; - } - // Run is now processed - runLength = 0; - } - - // Now actually allocate & write the compress data. First 4 bytes store the uncompressed size - dataCompressed = (unsigned char *)malloc(outputSize); - *((unsigned int *)dataCompressed) = fileEntry->data.length; - unsigned char *dataOut = dataCompressed + 4; - dataIn = data; - - // Now same process as before, but actually writing - while( dataIn != dataInLast ) - { - unsigned char thisByte = *dataIn++; - if( ( thisByte != 0 ) || ( runLength == ( 65535 + 256 ) ) ) - { - // We've got a non-zero value, or we've hit our maximum run length. - // If there was a preceeding run of zeros, encode that nwo - if( runLength != 0 ) - { - if( runLength < 256 ) - { - // Runs of 1 to 255 encoded as 0 followed by one byte of run length - *dataOut++ = 0; - *dataOut++ = runLength; - } - else - { - // Runs of 256 to 65791 encoded as two 0s followed by two bytes of run length - 256 - *dataOut++ = 0; - *dataOut++ = 0; - unsigned int largeRunLength = runLength - 256; - *dataOut++ = ( largeRunLength >> 8 ) & 0xff; - *dataOut++ = ( largeRunLength ) & 0xff; - } - // Run is now processed - runLength = 0; - } - // Now handle the current byte - if( thisByte == 0 ) - { - runLength++; - } - else - { - // Non-zero, just copy over to output - *dataOut++ = thisByte; - } - } - else - { - // It's a zero - keep counting size of the run - runLength++; - } - } - // Handle any outstanding run - if( runLength != 0 ) - { - if( runLength < 256 ) - { - // Runs of 1 to 255 encoded as 0 followed by one byte of run length - *dataOut++ = 0; - *dataOut++ = runLength; - } - else - { - // Runs of 256 to 65791 encoded as two 0s followed by two bytes of run length - 256 - *dataOut++ = 0; - *dataOut++ = 0; - unsigned int largeRunLength = runLength - 256; - *dataOut++ = ( largeRunLength >> 8 ) & 0xff; - *dataOut++ = ( largeRunLength ) & 0xff; - } - // Run is now processed - runLength = 0; - } - assert(( dataOut - dataCompressed ) == outputSize ); - dataCompressedSize = outputSize; -// int64_t endTime = System::currentTimeMillis(); -// app.DebugPrintf("Compressing region file 0x%.8x from %d to %d bytes - %dms\n", fileEntry->data.regionIndex, fileEntry->data.length, dataCompressedSize, endTime - startTime); -} - -// Decompress from dataCompressed -> data. See comment in Compress method for format -void ConsoleSaveFileSplit::RegionFileReference::Decompress() -{ -// int64_t startTime = System::currentTimeMillis(); - fileEntry->data.length = *((unsigned int *)dataCompressed); - - // If this is unusually large, then test how big it would be when expanded before trying to allocate. Matching the expanded size - // is (currently) our means of knowing that this file is ok - if( fileEntry->data.length > 1 * 1024 * 1024 ) - { - unsigned int uncompressedSize = 0; - unsigned char *dataIn = dataCompressed + 4; - unsigned char *dataInLast = dataCompressed + dataCompressedSize; - - while (dataIn != dataInLast) - { - unsigned char thisByte = *dataIn++; - if( thisByte == 0 ) - { - thisByte = *dataIn++; - if( thisByte == 0 ) - { - unsigned int runLength = (*dataIn++) << 8; - runLength |= (*dataIn++); - runLength += 256; - uncompressedSize += runLength; - } - else - { - unsigned int runLength = thisByte; - uncompressedSize += runLength; - } - } - else - { - uncompressedSize++; - } - } - - if( fileEntry->data.length != uncompressedSize ) - { - // Treat as if it was an empty region file - fileEntry->data.length = 0; - assert(0); - return; - } - } - - - data = (unsigned char *)malloc(fileEntry->data.length); - unsigned char *dataIn = dataCompressed + 4; - unsigned char *dataInLast = dataCompressed + dataCompressedSize; - unsigned char *dataOut = data; - - while (dataIn != dataInLast) - { - unsigned char thisByte = *dataIn++; - if( thisByte == 0 ) - { - thisByte = *dataIn++; - if( thisByte == 0 ) - { - unsigned int runLength = (*dataIn++) << 8; - runLength |= (*dataIn++); - runLength += 256; - for( unsigned int i = 0; i < runLength; i++ ) - { - *dataOut++ = 0; - } - } - else - { - unsigned int runLength = thisByte; - for( unsigned int i = 0; i < runLength; i++ ) - { - *dataOut++ = 0; - } - } - } - else - { - *dataOut++ = thisByte; - } - } - // If we failed to correctly decompress, then treat as if it was an empty region file - if( ( dataOut - data ) != fileEntry->data.length ) - { - free(data); - fileEntry->data.length = 0; - data = NULL; - assert(0); - } -// int64_t endTime = System::currentTimeMillis(); -// app.DebugPrintf("Decompressing region file from 0x%.8x %d to %d bytes - %dms\n", fileEntry->data.regionIndex, dataCompressedSize, fileEntry->data.length, endTime - startTime);// -} - -unsigned int ConsoleSaveFileSplit::RegionFileReference::GetCompressedSize() -{ - unsigned char *dataIn = data; - unsigned char *dataInLast = data + fileEntry->data.length; - - unsigned int outputSize = 4; // 4 bytes required to store the uncompressed size for faster decompression - unsigned int runLength = 0; - while( dataIn != dataInLast ) - { - unsigned char thisByte = *dataIn++; - if( ( thisByte != 0 ) || ( runLength == ( 65535 + 256 ) ) ) - { - // We've got a non-zero value, or we've hit our maximum run length. - // If there was a preceeding run of zeros, encode that nwo - if( runLength != 0 ) - { - if( runLength < 256 ) - { - // Runs of 1 to 255 encoded as 0 followed by one byte of run length - outputSize += 2; - } - else - { - // Runs of 256 to 65791 encoded as two 0s followed by two bytes of run length - 256 - outputSize += 4; - } - // Run is now processed - runLength = 0; - } - // Now handle the current byte - if( thisByte == 0 ) - { - runLength++; - } - else - { - // Non-zero, just copy over to output - outputSize++; - } - } - else - { - // It's a zero - keep counting size of the run - runLength++; - } - } - // Handle any outstanding run - if ( runLength != 0 ) - { - if( runLength < 256 ) - { - // Runs of 1 to 255 encoded as 0 followed by one byte of run length - outputSize += 2; - } - else - { - // Runs of 256 to 65791 encoded as two 0s followed by two bytes of run length - 256 - outputSize += 4; - } - // Run is now processed - runLength = 0; - } - return outputSize; -} - -// Release dataCompressed -void ConsoleSaveFileSplit::RegionFileReference::ReleaseCompressed() -{ -// app.DebugPrintf("Releasing compressed data for region file from 0x%.8x\n", fileEntry->data.regionIndex ); - free(dataCompressed); - dataCompressed = NULL; - dataCompressedSize = NULL; -} - -FileEntry *ConsoleSaveFileSplit::GetRegionFileEntry(unsigned int regionIndex) -{ - // Is a region file - determine if we've got it as a separate file - AUTO_VAR(it, regionFiles.find(regionIndex) ); - if( it != regionFiles.end() ) - { - // Already got it - return it->second->fileEntry; - } - - int index = StorageManager.AddSubfile(regionIndex); - RegionFileReference *newRef = new RegionFileReference(index, regionIndex); - regionFiles[regionIndex] = newRef; - - return newRef->fileEntry; -} - -ConsoleSaveFileSplit::ConsoleSaveFileSplit(const wstring &fileName, LPVOID pvSaveData /*= NULL*/, DWORD dFileSize /*= 0*/, bool forceCleanSave /*= false*/, ESavePlatform plat /*= SAVE_FILE_PLATFORM_LOCAL*/) -{ - DWORD fileSize = dFileSize; - - // Load a save from the game rules - bool bLevelGenBaseSave = false; - LevelGenerationOptions *levelGen = app.getLevelGenerationOptions(); - if( pvSaveData == NULL && levelGen != NULL && levelGen->requiresBaseSave()) - { - pvSaveData = levelGen->getBaseSaveData(fileSize); - if(pvSaveData && fileSize != 0) bLevelGenBaseSave = true; - } - - if( pvSaveData == NULL || fileSize == 0) - fileSize = StorageManager.GetSaveSize(); - - if( forceCleanSave ) - fileSize = 0; - - _init(fileName, pvSaveData, fileSize, plat); - - if(bLevelGenBaseSave) - { - levelGen->deleteBaseSaveData(); - } -} - -ConsoleSaveFileSplit::ConsoleSaveFileSplit(ConsoleSaveFile *sourceSave, bool alreadySmallRegions, ProgressListener *progress) -{ - _init(sourceSave->getFilename(), NULL, 0, sourceSave->getSavePlatform()); - - header.setOriginalSaveVersion(sourceSave->getOriginalSaveVersion()); - header.setSaveVersion(sourceSave->getSaveVersion()); - - if(alreadySmallRegions) - { - - vector *sourceFiles = sourceSave->getFilesWithPrefix(L""); - - DWORD bytesWritten; - for(AUTO_VAR(it, sourceFiles->begin()); it != sourceFiles->end(); ++it) - { - FileEntry *sourceEntry = *it; - sourceSave->setFilePointer(sourceEntry,0,NULL,FILE_BEGIN); - - FileEntry *targetEntry = createFile(ConsoleSavePath(sourceEntry->data.filename)); - - writeFile(targetEntry, sourceSave->getWritePointer(sourceEntry), sourceEntry->getFileSize(), &bytesWritten); - } - - delete sourceFiles; - } - else - { - ConsoleSaveFileConverter::ConvertSave(sourceSave, this, progress); - } -} - -void ConsoleSaveFileSplit::_init(const wstring &fileName, LPVOID pvSaveData, DWORD fileSize, ESavePlatform plat) -{ - InitializeCriticalSectionAndSpinCount(&m_lock,5120); - - m_lastTickTime = 0; - - // One time initialise of static stuff required for our storage - if( pvHeap == NULL ) - { - // Reserve a chunk of 64MB of virtual address space for our saves, using 64KB pages. - // We'll only be committing these as required to grow the storage we need, which will - // the storage to grow without having to use realloc. - pvHeap = VirtualAlloc(NULL, MAX_PAGE_COUNT * CSF_PAGE_SIZE, RESERVE_ALLOCATION, PAGE_READWRITE ); - } - - pvSaveMem = pvHeap; - m_fileName = fileName; - - // Get details of region files. From this point on we are responsible for the memory that the storage manager initially allocated for them - unsigned int regionCount = StorageManager.GetSubfileCount(); - for( unsigned int i = 0; i < regionCount; i++ ) - { - unsigned int regionIndex; - unsigned char *regionDataCompressed; - unsigned int regionSizeCompressed; - - StorageManager.GetSubfileDetails(i, ®ionIndex, ®ionDataCompressed, ®ionSizeCompressed); - - RegionFileReference *regionFileRef = new RegionFileReference(i, regionIndex, regionSizeCompressed, regionDataCompressed); - if( regionSizeCompressed > 0 ) - { - regionFileRef->Decompress(); - } - else - { - regionFileRef->fileEntry->data.length = 0; - } - regionFileRef->ReleaseCompressed(); - regionFiles[regionIndex] = regionFileRef; - } - - DWORD heapSize = max( fileSize, (DWORD)(1024 * 1024 * 2)); // 4J Stu - Our files are going to be bigger than 2MB so allocate high to start with - - // Initially committ enough room to store headSize bytes (using CSF_PAGE_SIZE pages, so rounding up here). We should only ever have one save file at a time, - // and the pages should be decommitted in the dtor, so pages committed should always be zero at this point. - if( pagesCommitted != 0 ) - { -#ifndef _CONTENT_PACKAGE - __debugbreak(); -#endif - } - - unsigned int pagesRequired = ( heapSize + (CSF_PAGE_SIZE - 1 ) ) / CSF_PAGE_SIZE; - - void *pvRet = VirtualAlloc(pvHeap, pagesRequired * CSF_PAGE_SIZE, COMMIT_ALLOCATION, PAGE_READWRITE); - if( pvRet == NULL ) - { -#ifndef _CONTENT_PACKAGE - // Out of physical memory - __debugbreak(); -#endif - } - pagesCommitted = pagesRequired; - - if( fileSize > 0) - { - if(pvSaveData != NULL) - { - memcpy(pvSaveMem, pvSaveData, fileSize); - } - else - { - unsigned int storageLength; - StorageManager.GetSaveData( pvSaveMem, &storageLength ); - app.DebugPrintf("Filesize - %d, Adjusted size - %d\n",fileSize,storageLength); - fileSize = storageLength; - } - - int compressed = *(int*)pvSaveMem; - if( compressed == 0 ) - { - unsigned int decompSize = *( (int*)pvSaveMem+1 ); - - // An invalid save, so clear the memory and start from scratch - if(decompSize == 0) - { - // 4J Stu - Saves created between 2/12/2011 and 7/12/2011 will have this problem - app.DebugPrintf("Invalid save data format\n"); - ZeroMemory( pvSaveMem, fileSize ); - // Clear the first 8 bytes that reference the header - header.WriteHeader( pvSaveMem ); - } - else - { - unsigned char *buf = new unsigned char[decompSize]; - - if( Compression::getCompression()->Decompress(buf, &decompSize, (unsigned char *)pvSaveMem+8, fileSize-8 ) == S_OK) - { - - // Only ReAlloc if we need to (we might already have enough) and align to 512 byte boundaries - DWORD currentHeapSize = pagesCommitted * CSF_PAGE_SIZE; - - DWORD desiredSize = decompSize; - - if( desiredSize > currentHeapSize ) - { - unsigned int pagesRequired = ( desiredSize + (CSF_PAGE_SIZE - 1 ) ) / CSF_PAGE_SIZE; - void *pvRet = VirtualAlloc(pvHeap, pagesRequired * CSF_PAGE_SIZE, COMMIT_ALLOCATION, PAGE_READWRITE); - if( pvRet == NULL ) - { - // Out of physical memory - __debugbreak(); - } - pagesCommitted = pagesRequired; - } - - memcpy(pvSaveMem, buf, decompSize); - } - else - { - // Corrupt save, although most of the terrain should actually be ok - app.DebugPrintf("Failed to decompress save data!\n"); -#ifndef _CONTENT_PACKAGE - __debugbreak(); -#endif - ZeroMemory( pvSaveMem, fileSize ); - // Clear the first 8 bytes that reference the header - header.WriteHeader( pvSaveMem ); - } - - delete[] buf; - } - } - - header.ReadHeader( pvSaveMem, plat ); - - } - else - { - // Clear the first 8 bytes that reference the header - header.WriteHeader( pvSaveMem ); - } -} - -ConsoleSaveFileSplit::~ConsoleSaveFileSplit() -{ - VirtualFree( pvHeap, MAX_PAGE_COUNT * CSF_PAGE_SIZE, MEM_DECOMMIT ); - pagesCommitted = 0; - // Make sure we don't have any thumbnail data still waiting round - we can't need it now we've destroyed the save file anyway -#if defined _XBOX - app.GetSaveThumbnail(NULL,NULL); -#elif defined __PS3__ - app.GetSaveThumbnail(NULL,NULL, NULL,NULL); -#endif - - for(AUTO_VAR(it,regionFiles.begin()); it != regionFiles.end(); it++ ) - { - delete it->second; - } - - StorageManager.ResetSubfiles(); - DeleteCriticalSection(&m_lock); -} - -// Add the file to our table of internal files if not already there -// Open our actual save file ready for reading/writing, and the set the file pointer to the start of this file -FileEntry *ConsoleSaveFileSplit::createFile( const ConsoleSavePath &fileName ) -{ - LockSaveAccess(); - - // Determine if the file is a region file that should be split off into its own file - unsigned int regionFileIndex; - bool isRegionFile = GetNumericIdentifierFromName(fileName.getName(), ®ionFileIndex); - if( isRegionFile ) - { - // First, for backwards compatibility, check if it is already in the main file - will just use that if so - if( !header.fileExists( fileName.getName() ) ) - { - // Find or create a new region file - FileEntry *file = GetRegionFileEntry(regionFileIndex); - ReleaseSaveAccess(); - return file; - } - } - - FileEntry *file = header.AddFile( fileName.getName() ); - ReleaseSaveAccess(); - - return file; -} - -void ConsoleSaveFileSplit::deleteFile( FileEntry *file ) -{ - if( file == NULL ) return; - - assert( file->isRegionFile() == false ); - - LockSaveAccess(); - - DWORD numberOfBytesRead = 0; - DWORD numberOfBytesWritten = 0; - - const int bufferSize = 4096; - int amountToRead = bufferSize; - byte buffer[bufferSize]; - DWORD bufferDataSize = 0; - - - char *readStartOffset = (char *)pvSaveMem + file->data.startOffset + file->getFileSize(); - - char *writeStartOffset = (char *)pvSaveMem + file->data.startOffset; - - char *endOfDataOffset = (char *)pvSaveMem + header.GetStartOfNextData(); - - while(true) - { - // Fill buffer from file - if( readStartOffset + bufferSize > endOfDataOffset ) - { - amountToRead = (int)(endOfDataOffset - readStartOffset); - } - else - { - amountToRead = bufferSize; - } - - if( amountToRead == 0 ) - break; - - memcpy( buffer, readStartOffset, amountToRead ); - numberOfBytesRead = amountToRead; - - bufferDataSize = amountToRead; - readStartOffset += numberOfBytesRead; - - // Write buffer to file - memcpy( (void *)writeStartOffset, buffer, bufferDataSize ); - numberOfBytesWritten = bufferDataSize; - - writeStartOffset += numberOfBytesWritten; - } - - header.RemoveFile( file ); - - finalizeWrite(); - - ReleaseSaveAccess(); -} - -void ConsoleSaveFileSplit::setFilePointer(FileEntry *file,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod) -{ - LockSaveAccess(); - - if( file->isRegionFile() ) - { - file->currentFilePointer = lDistanceToMove; - } - else - { - file->currentFilePointer = file->data.startOffset + lDistanceToMove; - } - - if( dwMoveMethod == FILE_END) - { - file->currentFilePointer += file->getFileSize(); - } - - ReleaseSaveAccess(); -} - -// If this file needs to grow, move the data after along -void ConsoleSaveFileSplit::PrepareForWrite( FileEntry *file, DWORD nNumberOfBytesToWrite ) -{ - int bytesToGrowBy = ( (file->currentFilePointer - file->data.startOffset) + nNumberOfBytesToWrite) - file->getFileSize(); - if( bytesToGrowBy <= 0 ) - return; - - // 4J Stu - Not forcing a minimum size, it is up to the caller to write data in sensible amounts - // This lets us keep some of the smaller files small - //if( bytesToGrowBy < 1024 ) - // bytesToGrowBy = 1024; - - // Move all the data beyond us - PIXBeginNamedEvent(0,"Growing file by %d bytes", bytesToGrowBy); - MoveDataBeyond(file, bytesToGrowBy); - PIXEndNamedEvent(); - - // Update our length - if( file->data.length < 0 ) - file->data.length = 0; - file->data.length += bytesToGrowBy; - - // Write the header with the updated data - finalizeWrite(); -} - -BOOL ConsoleSaveFileSplit::writeFile(FileEntry *file,LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten) -{ - assert( pvSaveMem != NULL ); - if( pvSaveMem == NULL ) - { - return 0; - } - - LockSaveAccess(); - - if( file->isRegionFile() ) - { - unsigned int sizeRequired = file->currentFilePointer + nNumberOfBytesToWrite; - RegionFileReference *fileRef = regionFiles[file->data.regionIndex]; - if( sizeRequired > file->getFileSize() ) - { - fileRef->data = (unsigned char *)realloc(fileRef->data, sizeRequired); - file->data.length = sizeRequired; - } - - memcpy( fileRef->data + file->currentFilePointer, lpBuffer, nNumberOfBytesToWrite ); - -// app.DebugPrintf(">>>>>>>>>>>>>> writing a region file's data 0x%.8x, 0x%x offset %d of %d bytes (writing %d bytes)\n",file->data.regionIndex,fileRef->data,file->currentFilePointer, file->getFileSize(), nNumberOfBytesToWrite); - - file->currentFilePointer += nNumberOfBytesToWrite; - file->updateLastModifiedTime(); - fileRef->dirty = true; - } - else - { - PrepareForWrite( file, nNumberOfBytesToWrite ); - - char *writeStartOffset = (char *)pvSaveMem + file->currentFilePointer; - //printf("Write: pvSaveMem = %0xd, currentFilePointer = %d, writeStartOffset = %0xd\n", pvSaveMem, file->currentFilePointer, writeStartOffset); - - memcpy( (void *)writeStartOffset, lpBuffer, nNumberOfBytesToWrite ); - *lpNumberOfBytesWritten = nNumberOfBytesToWrite; - - if(file->data.length < 0) - file->data.length = 0; - - file->currentFilePointer += *lpNumberOfBytesWritten; - - //wprintf(L"Wrote %d bytes to %s, new file pointer is %I64d\n", *lpNumberOfBytesWritten, file->data.filename, file->currentFilePointer); - - file->updateLastModifiedTime(); - } - - ReleaseSaveAccess(); - - return 1; -} - -BOOL ConsoleSaveFileSplit::zeroFile(FileEntry *file, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten) -{ - assert( pvSaveMem != NULL ); - if( pvSaveMem == NULL ) - { - return 0; - } - - LockSaveAccess(); - - if( file->isRegionFile() ) - { - unsigned int sizeRequired = file->currentFilePointer + nNumberOfBytesToWrite; - RegionFileReference *fileRef = regionFiles[file->data.regionIndex]; - if( sizeRequired > file->getFileSize() ) - { - fileRef->data = (unsigned char *)realloc(fileRef->data, sizeRequired); - file->data.length = sizeRequired; - } - - memset( fileRef->data + file->currentFilePointer, 0, nNumberOfBytesToWrite ); - -// app.DebugPrintf(">>>>>>>>>>>>>> writing a region file's data 0x%.8x, 0x%x offset %d of %d bytes (writing %d bytes)\n",file->data.regionIndex,fileRef->data,file->currentFilePointer, file->getFileSize(), nNumberOfBytesToWrite); - - file->currentFilePointer += nNumberOfBytesToWrite; - file->updateLastModifiedTime(); - fileRef->dirty = true; - } - else - { - PrepareForWrite( file, nNumberOfBytesToWrite ); - - char *writeStartOffset = (char *)pvSaveMem + file->currentFilePointer; - //printf("Write: pvSaveMem = %0xd, currentFilePointer = %d, writeStartOffset = %0xd\n", pvSaveMem, file->currentFilePointer, writeStartOffset); - - memset( (void *)writeStartOffset, 0, nNumberOfBytesToWrite ); - *lpNumberOfBytesWritten = nNumberOfBytesToWrite; - - if(file->data.length < 0) - file->data.length = 0; - - file->currentFilePointer += *lpNumberOfBytesWritten; - - //wprintf(L"Wrote %d bytes to %s, new file pointer is %I64d\n", *lpNumberOfBytesWritten, file->data.filename, file->currentFilePointer); - - file->updateLastModifiedTime(); - } - - ReleaseSaveAccess(); - - return 1; -} - -BOOL ConsoleSaveFileSplit::readFile( FileEntry *file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead) -{ - DWORD actualBytesToRead; - assert( pvSaveMem != NULL ); - if( pvSaveMem == NULL ) - { - return 0; - } - - LockSaveAccess(); - - if( file->isRegionFile() ) - { - actualBytesToRead = nNumberOfBytesToRead; - if( file->currentFilePointer + nNumberOfBytesToRead > file->data.length ) - { - actualBytesToRead = file->data.length - file->currentFilePointer; - } - RegionFileReference *fileRef = regionFiles[file->data.regionIndex]; - memcpy( lpBuffer, fileRef->data + file->currentFilePointer, actualBytesToRead ); - *lpNumberOfBytesRead = actualBytesToRead; - - file->currentFilePointer += actualBytesToRead; - } - else - { - char *readStartOffset = (char *)pvSaveMem + file->currentFilePointer; - //printf("Read: pvSaveMem = %0xd, currentFilePointer = %d, readStartOffset = %0xd\n", pvSaveMem, file->currentFilePointer, readStartOffset); - - assert( nNumberOfBytesToRead <= file->getFileSize() ); - - actualBytesToRead = nNumberOfBytesToRead; - if( file->currentFilePointer + nNumberOfBytesToRead > file->data.startOffset + file->data.length ) - { - actualBytesToRead = (file->data.startOffset + file->data.length) - file->currentFilePointer; - } - - memcpy( lpBuffer, readStartOffset, actualBytesToRead ); - *lpNumberOfBytesRead = actualBytesToRead; - - file->currentFilePointer += *lpNumberOfBytesRead; - - //wprintf(L"Read %d bytes from %s, new file pointer is %I64d\n", *lpNumberOfBytesRead, file->data.filename, file->currentFilePointer); - } - - - - ReleaseSaveAccess(); - - return 1; -} - -BOOL ConsoleSaveFileSplit::closeHandle( FileEntry *file ) -{ - LockSaveAccess(); - finalizeWrite(); - ReleaseSaveAccess(); - - return TRUE; -} - -// In this method, attempt to write any dirty region files, subject to maintaining a maximum write output rate. Writing is prioritised by time since the region was last written. -void ConsoleSaveFileSplit::tick() -{ - int64_t currentTime = System::currentTimeMillis(); - - // Don't do anything if the save system is up to something... - if( StorageManager.GetSaveState() != C4JStorage::ESaveGame_Idle ) - { - return; - } - - // ...or we shouldn't be saving... - if( StorageManager.GetSaveDisabled() ) - { - return; - } - - // ... or we haven't passed the required time since last assessing what to do - if( ( currentTime - m_lastTickTime ) < WRITE_TICK_RATE_MS ) - { - return; - } - - LockSaveAccess(); - - m_lastTickTime = currentTime; - - // Get total amount of data written over the time period we are interested in averaging over. Remove any older data. - unsigned int bytesWritten = 0; - for( AUTO_VAR(it, writeHistory.begin()); it != writeHistory.end(); ) - { - if( ( currentTime - it->writeTime ) > ( WRITE_BANDWIDTH_MEASUREMENT_PERIOD_SECONDS * 1000 ) ) - { - it = writeHistory.erase(it); - } - else - { - bytesWritten += it->writeSize; - it++; - } - } - - // Compile a vector of dirty regions. - vector dirtyRegions; - for( AUTO_VAR(it, regionFiles.begin()); it != regionFiles.end(); it++ ) - { - DirtyRegionFile dirtyRegion; - - if( it->second->dirty ) - { - dirtyRegion.fileRef = it->second->fileEntry->getRegionFileIndex(); - dirtyRegion.lastWritten = it->second->lastWritten; - dirtyRegions.push_back( dirtyRegion ); - } - } - - // Sort into ascending order, by lastWritten time. First elements will therefore be the ones least recently saved - std::sort( dirtyRegions.begin(), dirtyRegions.end() ); - - bool writeRequired = false; - unsigned int bytesInTimePeriod = bytesWritten; - unsigned int bytesAddedThisTick = 0; - for( int i = 0; i < dirtyRegions.size(); i++ ) - { - RegionFileReference *regionRef = regionFiles[dirtyRegions[i].fileRef]; - unsigned int compressedSize = regionRef->GetCompressedSize(); - bytesInTimePeriod += compressedSize; - bytesAddedThisTick += compressedSize; - - // Always consider at least one item for writing, even if it breaks the rule on the maximum number of bytes we would like to send per tick - if( ( i > 0 ) && ( bytesAddedThisTick > WRITE_MAX_WRITE_PER_TICK ) ) - { - break; - } - - // Could we add this without breaking our bytes per second cap? - if ( ( bytesInTimePeriod / WRITE_BANDWIDTH_MEASUREMENT_PERIOD_SECONDS ) > WRITE_BANDWIDTH_BYTESPERSECOND ) - { - break; - } - - // Can add for writing - WriteHistory writeEvent; - writeEvent.writeSize = compressedSize; - writeEvent.writeTime = System::currentTimeMillis(); - writeHistory.push_back(writeEvent); - - regionRef->Compress(); -// app.DebugPrintf("Tick: Writing region 0x%.8x, compressed as %d bytes\n",regionRef->fileEntry->getRegionFileIndex(), regionRef->dataCompressedSize); - StorageManager.UpdateSubfile(regionRef->index, regionRef->dataCompressed, regionRef->dataCompressedSize); - regionRef->dirty = false; - regionRef->lastWritten = System::currentTimeMillis(); - - writeRequired = true; - } -#ifndef _CONTENT_PACKAGE - { - unsigned int totalDirty = 0; - unsigned int totalDirtyBytes = 0; - __int64 oldestDirty = currentTime; - for( AUTO_VAR(it, regionFiles.begin()); it != regionFiles.end(); it++ ) - { - if( it->second->dirty ) - { - if( it->second->lastWritten < oldestDirty ) - { - oldestDirty = it->second->lastWritten; - } - totalDirty++; - totalDirtyBytes += it->second->fileEntry->getFileSize(); - } - } -#ifdef _DURANGO - PIXReportCounter(L"Dirty regions", (float)totalDirty); - PIXReportCounter(L"Dirty MB", (float)totalDirtyBytes / ( 1024 * 1024) ); - PIXReportCounter(L"Dirty oldest age", ((float) currentTime - oldestDirty ) ); - PIXReportCounter(L"Region writing bandwidth",((float)bytesInTimePeriod/ WRITE_BANDWIDTH_MEASUREMENT_PERIOD_SECONDS) / ( 1024 * 1024)); -#endif - } -#endif - - if( writeRequired ) - { - StorageManager.SaveSubfiles(SaveRegionFilesCallback, this); - } - - ReleaseSaveAccess(); -} - -void ConsoleSaveFileSplit::finalizeWrite() -{ - LockSaveAccess(); - header.WriteHeader( pvSaveMem ); - ReleaseSaveAccess(); -} - -void ConsoleSaveFileSplit::MoveDataBeyond(FileEntry *file, DWORD nNumberOfBytesToWrite) -{ - DWORD numberOfBytesRead = 0; - DWORD numberOfBytesWritten = 0; - - const DWORD bufferSize = 4096; - DWORD amountToRead = bufferSize; - //assert( nNumberOfBytesToWrite <= bufferSize ); - static byte buffer1[bufferSize]; - static byte buffer2[bufferSize]; - DWORD buffer1Size = 0; - DWORD buffer2Size = 0; - - // Only ReAlloc if we need to (we might already have enough) and align to 512 byte boundaries - DWORD currentHeapSize = pagesCommitted * CSF_PAGE_SIZE; - - DWORD desiredSize = header.GetFileSize() + nNumberOfBytesToWrite; - - if( desiredSize > currentHeapSize ) - { - unsigned int pagesRequired = ( desiredSize + (CSF_PAGE_SIZE - 1 ) ) / CSF_PAGE_SIZE; - void *pvRet = VirtualAlloc(pvHeap, pagesRequired * CSF_PAGE_SIZE, COMMIT_ALLOCATION, PAGE_READWRITE); - if( pvRet == NULL ) - { - // Out of physical memory - __debugbreak(); - } - pagesCommitted = pagesRequired; - } - - // This is the start of where we want the space to be, and the start of the data that we need to move - char *spaceStartOffset = (char *)pvSaveMem + file->data.startOffset + file->getFileSize(); - - // This is the end of where we want the space to be - char *spaceEndOffset = spaceStartOffset + nNumberOfBytesToWrite; - - // This is the current end of the data that we want to move - char *beginEndOfDataOffset = (char *)pvSaveMem + header.GetStartOfNextData(); - - // This is where the end of the data is going to be - char *finishEndOfDataOffset = beginEndOfDataOffset + nNumberOfBytesToWrite; - - // This is where we are going to read from (with the amount we want to read subtracted before we read) - char *readStartOffset = beginEndOfDataOffset; - - // This is where we can safely write to (with the amount we want write subtracted before we write) - char *writeStartOffset = finishEndOfDataOffset; - - //printf("\n******* MOVEDATABEYOND *******\n"); - //printf("Space start: %d, space end: %d\n", spaceStartOffset - (char *)pvSaveMem, spaceEndOffset - (char *)pvSaveMem); - //printf("Current end of data: %d, new end of data: %d\n", beginEndOfDataOffset - (char *)pvSaveMem, finishEndOfDataOffset - (char *)pvSaveMem); - - // Optimisation for things that are being moved in whole region file sector (4K chunks). We could generalise this a bit more but seems safest at the moment to identify this particular type - // of move and code explicitly for this situation - if( ( nNumberOfBytesToWrite & 4095 ) == 0 ) - { - if( nNumberOfBytesToWrite > 0 ) - { - // Get addresses for start & end of the region we are copying from as uintptr_t, for easier maths - uintptr_t uiFromStart = (uintptr_t)spaceStartOffset; - uintptr_t uiFromEnd = (uintptr_t)beginEndOfDataOffset; - - // Round both of these values to get 4096 byte chunks that we will need to at least partially move - uintptr_t uiFromStartChunk = uiFromStart & ~((uintptr_t)4095); - uintptr_t uiFromEndChunk = (uiFromEnd - 1 ) & ~((uintptr_t)4095); - - // Loop through all the affected source 4096 chunks, going backwards so we don't overwrite anything we'll need in the future - for( uintptr_t uiCurrentChunk = uiFromEndChunk; uiCurrentChunk >= uiFromStartChunk; uiCurrentChunk -= 4096 ) - { - // Establish chunk we'll need to copy - uintptr_t uiCopyStart = uiCurrentChunk; - uintptr_t uiCopyEnd = uiCurrentChunk + 4096; - // Clamp chunk to the bounds of the full region we are trying to copy - if( uiCopyStart < uiFromStart ) - { - // Needs to be clampged against the start of our region - uiCopyStart = uiFromStart; - } - if ( uiCopyEnd > uiFromEnd ) - { - // Needs to be clamped to the end of our region - uiCopyEnd = uiFromEnd; - } - XMemCpy( (void *)(uiCopyStart + nNumberOfBytesToWrite), ( void *)uiCopyStart, uiCopyEnd - uiCopyStart ); - } - } - } - else - { - while(true) - { - // Copy buffer 1 to buffer 2 - memcpy( buffer2, buffer1, buffer1Size); - buffer2Size = buffer1Size; - - // Fill buffer 1 from file - if( (readStartOffset - bufferSize) < spaceStartOffset ) - { - amountToRead = (DWORD)(readStartOffset - spaceStartOffset); - } - else - { - amountToRead = bufferSize; - } - - // Push the read point back by the amount of bytes that we are going to read - readStartOffset -= amountToRead; - - //printf("About to read %u from %d\n", amountToRead, readStartOffset - (char *)pvSaveMem ); - - memcpy( buffer1, readStartOffset, amountToRead ); - numberOfBytesRead = amountToRead; - - buffer1Size = amountToRead; - - // Move back the write pointer by the amount of bytes we are going to write - writeStartOffset -= buffer2Size; - - // Write buffer 2 to file - if( (writeStartOffset + buffer2Size) <= finishEndOfDataOffset) - { - //printf("About to write %u to %d\n", buffer2Size, writeStartOffset - (char *)pvSaveMem ); - memcpy( (void *)writeStartOffset, buffer2, buffer2Size ); - numberOfBytesWritten = buffer2Size; - } - else - { - assert((writeStartOffset + buffer2Size) <= finishEndOfDataOffset); - numberOfBytesWritten = 0; - } - - if( numberOfBytesRead == 0 ) - { - //printf("\n************** MOVE COMPLETED *************** \n\n"); - assert( writeStartOffset == spaceEndOffset ); - break; - } - } - } - - header.AdjustStartOffsets( file, nNumberOfBytesToWrite ); -} - -// Attempt to convert a filename into a numeric identifier, which we use for region files. File names supported are of the form: -// -// Filename Encoded as -// -// r.x.z.mcr 00 00 xx zz -// DIM-1r.x.z.mcr 00 01 xx zz -// DIM1/r.x.z.mcr 00 02 xx zz - -bool ConsoleSaveFileSplit::GetNumericIdentifierFromName(const wstring &fileName, unsigned int *idOut) -{ - // Determine whether it is one of our region file names if the file extension is ".mbr" - if( fileName.length() < 4 ) return false; - wstring extension = fileName.substr(fileName.length()-4,4); - if( extension != wstring(L".mcr") ) return false; - - unsigned int id = 0; - int x, z; - - const wchar_t *cstr = fileName.c_str(); - const wchar_t *body = cstr + 2; - - // If this filename starts with a "r" then assume it is of the format "r.x.z.mcr" - don't do anything as default value we've set are correct - if( cstr[0] != L'r' ) - { - // Must be prefixed by "DIM-1r." or "DIM1/r." - body = cstr + 7; - // Differentiate between these 2 options - if( cstr[3] == L'-' ) - { - // "DIM-1r." - id = 0x00010000; - } - else - { - // "DIM/1r." - id = 0x00020000; - } - } - // Get x/z coords - swscanf_s(body, L"%d.%d.mcr", &x, &z ); - - // Pack full id - id |= ( ( x << 8 ) & 0x0000ff00 ); - id |= ( z & 0x000000ff ); - - *idOut = id; - - return true; -} - -// Convert a numeric file identifier (for region files) back into a normal filename. See comment above. - -wstring ConsoleSaveFileSplit::GetNameFromNumericIdentifier(unsigned int idIn) -{ - wstring prefix; - - switch(idIn & 0x00ff0000 ) - { - case 0: - prefix = L""; - break; - case 1: - prefix = L"DIM-1"; - break; - case 2: - prefix = L"DIM1/"; - break; - } - signed char regionX = ( idIn >> 8 ) & 255; - signed char regionZ = idIn & 255; - wstring region = ( prefix + wstring(L"r.") + _toString(regionX) + L"." + _toString(regionZ) + L".mcr" ); - - return region; -} - -// Compress any dirty region files, and tell the storage manager about them so that it will process them when we ask it to save sub files -void ConsoleSaveFileSplit::processSubfilesForWrite() -{ -#if 0 - // 4J Stu - There are debug reasons where we want to force a save of all regions - StorageManager.ResetSubfiles(); - for(AUTO_VAR(it,regionFiles.begin()); it != regionFiles.end(); it++ ) - { - RegionFileReference* region = it->second; - int index = StorageManager.AddSubfile(region->fileEntry->data.regionIndex); - //if( region->dirty ) - { - region->Compress(); - StorageManager.UpdateSubfile(index, region->dataCompressed, region->dataCompressedSize); - region->dirty = false; - region->lastWritten = System::currentTimeMillis(); - } - } -#else - for(AUTO_VAR(it,regionFiles.begin()); it != regionFiles.end(); it++ ) - { - RegionFileReference* region = it->second; - if( region->dirty ) - { - region->Compress(); - StorageManager.UpdateSubfile(region->index, region->dataCompressed, region->dataCompressedSize); - region->dirty = false; - region->lastWritten = System::currentTimeMillis(); - } - } -#endif -} - -// Clean up any memory allocated for compressed data when we have finished writing -void ConsoleSaveFileSplit::processSubfilesAfterWrite() -{ - // This is called from the StorageManager.Tick() which should always be on the main thread - for(AUTO_VAR(it,regionFiles.begin()); it != regionFiles.end(); it++ ) - { - RegionFileReference* region = it->second; - region->ReleaseCompressed(); - } -} - -bool ConsoleSaveFileSplit::doesFileExist(ConsoleSavePath file) -{ - LockSaveAccess(); - bool exists = header.fileExists( file.getName() ); - ReleaseSaveAccess(); - - return exists; -} - -void ConsoleSaveFileSplit::Flush(bool autosave, bool updateThumbnail) -{ - LockSaveAccess(); - -#ifdef _XBOX_ONE - MinecraftServer *server = MinecraftServer::getInstance(); -#endif - - // The storage manage might potentially be busy doing a sub-file write initiated from the tick. Wait until this is totally processed. - while( StorageManager.GetSaveState() != C4JStorage::ESaveGame_Idle ) - { -#ifdef _XBOX_ONE - if (server && server->IsSuspending()) - { - // If the server is mid-suspend we need to tick the storage manager ourselves - StorageManager.Tick(); - } -#endif - - app.DebugPrintf("Flush wait\n"); - Sleep(10); - } - - finalizeWrite(); - - m_autosave = autosave; - if(!m_autosave) processSubfilesForWrite(); - - // Get the frequency of the timer - LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime; - float fElapsedTime = 0.0f; - QueryPerformanceFrequency( &qwTicksPerSec ); - float fSecsPerTick = 1.0f / (float)qwTicksPerSec.QuadPart; - - unsigned int fileSize = header.GetFileSize(); - - // Assume that the compression will make it smaller so initially attempt to allocate the current file size - // We add 4 bytes to the start so that we can signal compressed data - // And another 4 bytes to store the decompressed data size - unsigned int compLength = fileSize+8; - - // 4J Stu - Added TU-1 interim - - // Attempt to allocate the required memory - // We do not own this, it belongs to the StorageManager - byte *compData = (byte *)StorageManager.AllocateSaveData( compLength ); - - // If we failed to allocate then compData will be NULL - // Pre-calculate the compressed data size so that we can attempt to allocate a smaller buffer - if(compData == NULL) - { - // Length should be 0 here so that the compression call knows that we want to know the length back - compLength = 0; - - // Pre-calculate the buffer size required for the compressed data - PIXBeginNamedEvent(0,"Pre-calc save compression"); - // Save the start time - QueryPerformanceCounter( &qwTime ); - Compression::getCompression()->Compress(NULL,&compLength,pvSaveMem,fileSize); - QueryPerformanceCounter( &qwNewTime ); - - qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; - fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart)); - - app.DebugPrintf("Check buffer size: Elapsed time %f\n", fElapsedTime); - PIXEndNamedEvent(); - - // We add 4 bytes to the start so that we can signal compressed data - // And another 4 bytes to store the decompressed data size - compLength = compLength+8; - - // Attempt to allocate the required memory - compData = (byte *)StorageManager.AllocateSaveData( compLength ); - } - - if(compData != NULL) - { - // Re-compress all save data before we save it to disk - PIXBeginNamedEvent(0,"Actual save compression"); - // Save the start time - QueryPerformanceCounter( &qwTime ); - Compression::getCompression()->Compress(compData+8,&compLength,pvSaveMem,fileSize); - QueryPerformanceCounter( &qwNewTime ); - - qwDeltaTime.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; - fElapsedTime = fSecsPerTick * ((FLOAT)(qwDeltaTime.QuadPart)); - - app.DebugPrintf("Compress: Elapsed time %f\n", fElapsedTime); - PIXEndNamedEvent(); - - ZeroMemory(compData,8); - int saveVer = 0; - memcpy( compData, &saveVer, sizeof(int) ); - memcpy( compData+4, &fileSize, sizeof(int) ); - - app.DebugPrintf("Save data compressed from %d to %d\n", fileSize, compLength); - - if(updateThumbnail) - { - PBYTE pbThumbnailData=NULL; - DWORD dwThumbnailDataSize=0; - - PBYTE pbDataSaveImage=NULL; - DWORD dwDataSizeSaveImage=0; - -#if ( defined _XBOX || defined _DURANGO ) - app.GetSaveThumbnail(&pbThumbnailData,&dwThumbnailDataSize); -#elif ( defined __PS3__ || defined __ORBIS__ ) - app.GetSaveThumbnail(&pbThumbnailData,&dwThumbnailDataSize,&pbDataSaveImage,&dwDataSizeSaveImage); -#endif - - BYTE bTextMetadata[88]; - ZeroMemory(bTextMetadata,88); - - __int64 seed = 0; - bool hasSeed = false; - if(MinecraftServer::getInstance()!= NULL && MinecraftServer::getInstance()->levels[0]!=NULL) - { - seed = MinecraftServer::getInstance()->levels[0]->getLevelData()->getSeed(); - hasSeed = true; - } - - int iTextMetadataBytes = app.CreateImageTextData(bTextMetadata, seed, hasSeed, app.GetGameHostOption(eGameHostOption_All), Minecraft::GetInstance()->getCurrentTexturePackId()); - - // set the icon and save image - StorageManager.SetSaveImages(pbThumbnailData,dwThumbnailDataSize,pbDataSaveImage,dwDataSizeSaveImage,bTextMetadata,iTextMetadataBytes); - app.DebugPrintf("Save thumbnail size %d\n",dwThumbnailDataSize); - - } - - INT saveOrCheckpointId = 0; - bool validSave = StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); - TelemetryManager->RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), saveOrCheckpointId, compLength+8); - - // save the data - StorageManager.SaveSaveData( &ConsoleSaveFileSplit::SaveSaveDataCallback, this ); -#ifndef _CONTENT_PACKAGE - if( app.DebugSettingsOn()) - { - if(app.GetWriteSavesToFolderEnabled() ) - { - DebugFlushToFile(compData, compLength+8); - } - } -#endif - ReleaseSaveAccess(); - } -} - -int ConsoleSaveFileSplit::SaveSaveDataCallback(LPVOID lpParam,bool bRes) -{ - ConsoleSaveFileSplit *pClass=(ConsoleSaveFileSplit *)lpParam; - - // Don't save sub files on autosave (their always being saved anyway) - if (!pClass->m_autosave) - { - // This is called from the StorageManager.Tick() which should always be on the main thread - StorageManager.SaveSubfiles(SaveRegionFilesCallback, pClass); - } - return 0; -} - -int ConsoleSaveFileSplit::SaveRegionFilesCallback(LPVOID lpParam,bool bRes) -{ - ConsoleSaveFileSplit *pClass=(ConsoleSaveFileSplit *)lpParam; - - // This is called from the StorageManager.Tick() which should always be on the main thread - pClass->processSubfilesAfterWrite(); - - return 0; -} - -#ifndef _CONTENT_PACKAGE -void ConsoleSaveFileSplit::DebugFlushToFile(void *compressedData /*= NULL*/, unsigned int compressedDataSize /*= 0*/) -{ - LockSaveAccess(); - - finalizeWrite(); - - unsigned int fileSize = header.GetFileSize(); - - DWORD numberOfBytesWritten = 0; - - File targetFileDir(L"Saves"); - - if(!targetFileDir.exists()) - targetFileDir.mkdir(); - - wchar_t *fileName = new wchar_t[XCONTENT_MAX_FILENAME_LENGTH+1]; - - SYSTEMTIME t; - GetSystemTime( &t ); - - //14 chars for the digits - //11 chars for the separators + suffix - //25 chars total - wstring cutFileName = m_fileName; - if(m_fileName.length() > XCONTENT_MAX_FILENAME_LENGTH - 25) - { - cutFileName = m_fileName.substr(0, XCONTENT_MAX_FILENAME_LENGTH - 25); - } - swprintf(fileName, XCONTENT_MAX_FILENAME_LENGTH+1, L"\\v%04d-%ls%02d.%02d.%02d.%02d.%02d.mcs",VER_PRODUCTBUILD,cutFileName.c_str(), t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond); - -#ifdef _UNICODE - wstring wtemp = targetFileDir.getPath() + wstring(fileName); - LPCWSTR lpFileName = wtemp.c_str(); -#else - LPCSTR lpFileName = wstringtofilename( targetFileDir.getPath() + wstring(fileName) ); -#endif - - HANDLE hSaveFile = CreateFile( lpFileName, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL); - - if(compressedData != NULL && compressedDataSize > 0) - { - WriteFile(hSaveFile,compressedData,compressedDataSize,&numberOfBytesWritten,NULL); - assert(numberOfBytesWritten == compressedDataSize); - } - else - { - WriteFile(hSaveFile,pvSaveMem,fileSize,&numberOfBytesWritten,NULL); - assert(numberOfBytesWritten == fileSize); - } - CloseHandle( hSaveFile ); - - delete[] fileName; - - ReleaseSaveAccess(); -} -#endif - -unsigned int ConsoleSaveFileSplit::getSizeOnDisk() -{ - return header.GetFileSize(); -} - -wstring ConsoleSaveFileSplit::getFilename() -{ - return m_fileName; -} - -vector *ConsoleSaveFileSplit::getFilesWithPrefix(const wstring &prefix) -{ - return header.getFilesWithPrefix( prefix ); -} - -vector *ConsoleSaveFileSplit::getRegionFilesByDimension(unsigned int dimensionIndex) -{ - vector *files = NULL; - - for( AUTO_VAR(it,regionFiles.begin()); it != regionFiles.end(); ++it ) - { - unsigned int entryDimension = ( (it->first) >> 16) & 0xFF; - - if(entryDimension == dimensionIndex) - { - if( files == NULL ) - { - files = new vector(); - } - - files->push_back(it->second->fileEntry); - } - } - - return files; -} - -#if defined(__PS3__) || defined(__ORBIS__) -wstring ConsoleSaveFileSplit::getPlayerDataFilenameForLoad(const PlayerUID& pUID) -{ - return header.getPlayerDataFilenameForLoad( pUID ); -} -wstring ConsoleSaveFileSplit::getPlayerDataFilenameForSave(const PlayerUID& pUID) -{ - return header.getPlayerDataFilenameForSave( pUID ); -} -vector *ConsoleSaveFileSplit::getValidPlayerDatFiles() -{ - return header.getValidPlayerDatFiles(); -} -#endif - -int ConsoleSaveFileSplit::getSaveVersion() -{ - return header.getSaveVersion(); -} - -int ConsoleSaveFileSplit::getOriginalSaveVersion() -{ - return header.getOriginalSaveVersion(); -} - -void ConsoleSaveFileSplit::LockSaveAccess() -{ - EnterCriticalSection(&m_lock); -} - -void ConsoleSaveFileSplit::ReleaseSaveAccess() -{ - LeaveCriticalSection(&m_lock); -} - -ESavePlatform ConsoleSaveFileSplit::getSavePlatform() -{ - return header.getSavePlatform(); -} - -bool ConsoleSaveFileSplit::isSaveEndianDifferent() -{ - return header.isSaveEndianDifferent(); -} - -void ConsoleSaveFileSplit::setLocalPlatform() -{ - header.setLocalPlatform(); -} - -void ConsoleSaveFileSplit::setPlatform(ESavePlatform plat) -{ - header.setPlatform(plat); -} - -ByteOrder ConsoleSaveFileSplit::getSaveEndian() -{ - return header.getSaveEndian(); -} - -ByteOrder ConsoleSaveFileSplit::getLocalEndian() -{ - return header.getLocalEndian(); -} - -void ConsoleSaveFileSplit::setEndian(ByteOrder endian) -{ - header.setEndian(endian); -} - -void ConsoleSaveFileSplit::ConvertRegionFile(File sourceFile) -{ - DWORD numberOfBytesWritten = 0; - DWORD numberOfBytesRead = 0; - - RegionFile sourceRegionFile(this, &sourceFile); - - for(unsigned int x = 0; x < 32; ++x) - { - for(unsigned int z = 0; z < 32; ++z) - { - DataInputStream *dis = sourceRegionFile.getChunkDataInputStream(x,z); - - if(dis) - { - byteArray inData(1024*1024); - int read = dis->read(inData); - dis->close(); - dis->deleteChildStream(); - delete dis; - - DataOutputStream *dos = sourceRegionFile.getChunkDataOutputStream(x,z); - dos->write(inData, 0, read); - - - dos->close(); - dos->deleteChildStream(); - delete dos; - delete inData.data; - - } - - } - } - sourceRegionFile.writeAllOffsets(); // saves all the endian swapped offsets back out to the file (not all of these are written in the above processing). - -} - -void ConsoleSaveFileSplit::ConvertToLocalPlatform() -{ - if(getSavePlatform() == SAVE_FILE_PLATFORM_LOCAL) - { - // already in the correct format - return; - } - // convert each of the region files to the local platform - vector *allFilesInSave = getFilesWithPrefix(wstring(L"")); - for(AUTO_VAR(it, allFilesInSave->begin()); it < allFilesInSave->end(); ++it) - { - FileEntry *fe = *it; - wstring fName( fe->data.filename ); - wstring suffix(L".mcr"); - if( fName.compare(fName.length() - suffix.length(), suffix.length(), suffix) == 0 ) - { - app.DebugPrintf("Processing a region file: %ls\n",fName.c_str()); - ConvertRegionFile(File(fe->data.filename) ); - } - else - { - app.DebugPrintf("%ls is not a region file, ignoring\n", fName.c_str()); - } - } - - setLocalPlatform(); // set the platform of this save to the local platform, now that it's been coverted -} diff --git a/Minecraft.World/ConsoleSaveFileSplit.h b/Minecraft.World/ConsoleSaveFileSplit.h deleted file mode 100644 index 0b2017a2..00000000 --- a/Minecraft.World/ConsoleSaveFileSplit.h +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once - -#include "FileHeader.h" -#include "ConsoleSavePath.h" -#include "ConsoleSaveFile.h" - -class ProgressRenderer; - -class ConsoleSaveFileSplit : public ConsoleSaveFile -{ -private: - FileHeader header; - - static const int WRITE_BANDWIDTH_BYTESPERSECOND = 1048576; // Average bytes per second we will cap to when writing region files during the tick() method - static const int WRITE_BANDWIDTH_MEASUREMENT_PERIOD_SECONDS = 10; // Time period over which the bytes per second average is calculated - static const int WRITE_TICK_RATE_MS = 500; // Time between attempts to work out which regions we should write during the tick - static const int WRITE_MAX_WRITE_PER_TICK = WRITE_BANDWIDTH_BYTESPERSECOND; // Maximum number of bytes we can add in a single tick - - class WriteHistory - { - public: - int64_t writeTime; - unsigned int writeSize; - } ; - - class DirtyRegionFile - { - public: - int64_t lastWritten; - unsigned int fileRef; - bool operator<(const DirtyRegionFile& rhs) { return lastWritten < rhs.lastWritten; } - }; - - class RegionFileReference - { - public: - RegionFileReference(int index, unsigned int regionIndex, unsigned int length = 0, unsigned char *data = NULL); - ~RegionFileReference(); - void Compress(); // Compress from data to dataCompressed - void Decompress(); // Decompress from dataCompressed -> data - unsigned int GetCompressedSize(); // Gets byte size for what this region will compress to - void ReleaseCompressed(); // Release dataCompressed - FileEntry *fileEntry; - unsigned char *data; - unsigned char *dataCompressed; - unsigned int dataCompressedSize; - int index; - bool dirty; - int64_t lastWritten; - }; - unordered_map regionFiles; - vector writeHistory; - int64_t m_lastTickTime; - - FileEntry *GetRegionFileEntry(unsigned int regionIndex); - - wstring m_fileName; - bool m_autosave; - -// HANDLE hHeap; - static void *pvHeap; - static unsigned int pagesCommitted; -#ifdef _LARGE_WORLDS - static const unsigned int CSF_PAGE_SIZE = 64 * 1024; - static const unsigned int MAX_PAGE_COUNT = 32 * 1024; // 2GB virtual allocation -#else - static const unsigned int CSF_PAGE_SIZE = 64 * 1024; - static const unsigned int MAX_PAGE_COUNT = 1024; -#endif - LPVOID pvSaveMem; - - CRITICAL_SECTION m_lock; - - void PrepareForWrite( FileEntry *file, DWORD nNumberOfBytesToWrite ); - void MoveDataBeyond(FileEntry *file, DWORD nNumberOfBytesToWrite); - - bool GetNumericIdentifierFromName(const wstring &fileName, unsigned int *idOut); - wstring GetNameFromNumericIdentifier(unsigned int idIn); - void processSubfilesForWrite(); - void processSubfilesAfterWrite(); -public: - static int SaveSaveDataCallback(LPVOID lpParam,bool bRes); - static int SaveRegionFilesCallback(LPVOID lpParam,bool bRes); - -private: - void _init(const wstring &fileName, LPVOID pvSaveData, DWORD fileSize, ESavePlatform plat); - -public: - ConsoleSaveFileSplit(const wstring &fileName, LPVOID pvSaveData = NULL, DWORD fileSize = 0, bool forceCleanSave = false, ESavePlatform plat = SAVE_FILE_PLATFORM_LOCAL); - ConsoleSaveFileSplit(ConsoleSaveFile *sourceSave, bool alreadySmallRegions = true, ProgressListener *progress = NULL); - virtual ~ConsoleSaveFileSplit(); - - // 4J Stu - Initial implementation is intended to have a similar interface to the standard Xbox file access functions - - virtual FileEntry *createFile( const ConsoleSavePath &fileName ); - virtual void deleteFile( FileEntry *file ); - - virtual void setFilePointer(FileEntry *file,LONG lDistanceToMove,PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod); - virtual BOOL writeFile( FileEntry *file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten ); - virtual BOOL zeroFile(FileEntry *file, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten); - virtual BOOL readFile( FileEntry *file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead ); - virtual BOOL closeHandle( FileEntry *file ); - - virtual void finalizeWrite(); - virtual void tick(); - - virtual bool doesFileExist(ConsoleSavePath file); - - virtual void Flush(bool autosave, bool updateThumbnail = true); - -#ifndef _CONTENT_PACKAGE - virtual void DebugFlushToFile(void *compressedData = NULL, unsigned int compressedDataSize = 0); -#endif - virtual unsigned int getSizeOnDisk(); - - virtual wstring getFilename(); - - virtual vector *getFilesWithPrefix(const wstring &prefix); - virtual vector *getRegionFilesByDimension(unsigned int dimensionIndex); - -#if defined(__PS3__) || defined(__ORBIS__) - virtual wstring getPlayerDataFilenameForLoad(const PlayerUID& pUID); - virtual wstring getPlayerDataFilenameForSave(const PlayerUID& pUID); - virtual vector *getValidPlayerDatFiles(); -#endif //__PS3__ - - virtual int getSaveVersion(); - virtual int getOriginalSaveVersion(); - - virtual void LockSaveAccess(); - virtual void ReleaseSaveAccess(); - - virtual ESavePlatform getSavePlatform(); - virtual bool isSaveEndianDifferent(); - virtual void setLocalPlatform(); - virtual void setPlatform(ESavePlatform plat); - virtual ByteOrder getSaveEndian(); - virtual ByteOrder getLocalEndian(); - virtual void setEndian(ByteOrder endian); - - virtual void ConvertRegionFile(File sourceFile); - virtual void ConvertToLocalPlatform(); -}; \ No newline at end of file diff --git a/Minecraft.World/Container.h b/Minecraft.World/Container.h index 7aa63728..8fa21345 100644 --- a/Minecraft.World/Container.h +++ b/Minecraft.World/Container.h @@ -7,17 +7,23 @@ class Player; class Container { public: - static const int LARGE_MAX_STACK_SIZE = 64; + static const int LARGE_MAX_STACK_SIZE = 64; - virtual unsigned int getContainerSize() = 0; - virtual shared_ptr getItem(unsigned int slot) = 0; - virtual shared_ptr removeItem(unsigned int slot, int count) = 0; + // 4J-JEV: Added to distinguish between ender, bonus, small and large chests + virtual int getContainerType() { return -1; } + + virtual unsigned int getContainerSize() = 0; + virtual shared_ptr getItem(unsigned int slot) = 0; + virtual shared_ptr removeItem(unsigned int slot, int count) = 0; virtual shared_ptr removeItemNoUpdate(int slot) = 0; - virtual void setItem(unsigned int slot, shared_ptr item) = 0; - virtual int getName() = 0; - virtual int getMaxStackSize() = 0; - virtual void setChanged() = 0; - virtual bool stillValid(shared_ptr player) = 0; + virtual void setItem(unsigned int slot, shared_ptr item) = 0; + virtual wstring getName() = 0; + virtual wstring getCustomName() = 0; // 4J Stu added for sending over the network + virtual bool hasCustomName() = 0; + virtual int getMaxStackSize() = 0; + virtual void setChanged() = 0; + virtual bool stillValid(shared_ptr player) = 0; virtual void startOpen() = 0; virtual void stopOpen() = 0; + virtual bool canPlaceItem(int slot, shared_ptr item) = 0; }; \ No newline at end of file diff --git a/Minecraft.World/ContainerClickPacket.cpp b/Minecraft.World/ContainerClickPacket.cpp index 5b3ca24f..a9712183 100644 --- a/Minecraft.World/ContainerClickPacket.cpp +++ b/Minecraft.World/ContainerClickPacket.cpp @@ -18,16 +18,16 @@ ContainerClickPacket::ContainerClickPacket() buttonNum = 0; uid = 0; item = nullptr; - quickKey = false; + clickType = 0; } -ContainerClickPacket::ContainerClickPacket(int containerId, int slotNum, int buttonNum, bool quickKey, shared_ptr item, short uid) +ContainerClickPacket::ContainerClickPacket(int containerId, int slotNum, int buttonNum, int clickType, shared_ptr item, short uid) { this->containerId = containerId; this->slotNum = slotNum; this->buttonNum = buttonNum; this->uid = uid; - this->quickKey = quickKey; + this->clickType = clickType; // 4J - make a copy of the relevant bits of this item, as we want our packets to have full ownership of any data they reference this->item = item ? item->copy() : nullptr; } @@ -43,7 +43,7 @@ void ContainerClickPacket::read(DataInputStream *dis) //throws IOException slotNum = dis->readShort(); buttonNum = dis->readByte(); uid = dis->readShort(); - quickKey = dis->readBoolean(); + clickType = dis->readByte(); item = readItem(dis); } @@ -54,7 +54,7 @@ void ContainerClickPacket::write(DataOutputStream *dos) // throws IOException dos->writeShort(slotNum); dos->writeByte(buttonNum); dos->writeShort(uid); - dos->writeBoolean(quickKey); + dos->writeByte(clickType); writeItem(item, dos); } diff --git a/Minecraft.World/ContainerClickPacket.h b/Minecraft.World/ContainerClickPacket.h index 8bea7da5..51686166 100644 --- a/Minecraft.World/ContainerClickPacket.h +++ b/Minecraft.World/ContainerClickPacket.h @@ -11,11 +11,11 @@ public: int buttonNum; short uid; shared_ptr item; - bool quickKey; + int clickType; ContainerClickPacket(); ~ContainerClickPacket(); - ContainerClickPacket(int containerId, int slotNum, int buttonNum, bool quickKey, shared_ptr item, short uid); + ContainerClickPacket(int containerId, int slotNum, int buttonNum, int clickType, shared_ptr item, short uid); virtual void handle(PacketListener *listener); virtual void read(DataInputStream *dis); diff --git a/Minecraft.World/ContainerMenu.cpp b/Minecraft.World/ContainerMenu.cpp index 57190024..b1fd4d6b 100644 --- a/Minecraft.World/ContainerMenu.cpp +++ b/Minecraft.World/ContainerMenu.cpp @@ -11,7 +11,7 @@ ContainerMenu::ContainerMenu(shared_ptr inventory, shared_ptr container) : AbstractContainerMenu() { this->container = container; - this->containerRows = container->getContainerSize() / 9; + containerRows = container->getContainerSize() / 9; container->startOpen(); int yo = (containerRows - 4) * 18; @@ -45,7 +45,7 @@ bool ContainerMenu::stillValid(shared_ptr player) shared_ptr ContainerMenu::quickMoveStack(shared_ptr player, int slotIndex) { shared_ptr clicked = nullptr; - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot != NULL && slot->hasItem()) { shared_ptr stack = slot->getItem(); @@ -53,7 +53,7 @@ shared_ptr ContainerMenu::quickMoveStack(shared_ptr player if (slotIndex < containerRows * 9) { - if(!moveItemStackTo(stack, containerRows * 9, (int)slots->size(), true)) + if(!moveItemStackTo(stack, containerRows * 9, (int)slots.size(), true)) { // 4J Stu - Brought forward from 1.2 return nullptr; @@ -85,9 +85,14 @@ void ContainerMenu::removed(shared_ptr player) container->stopOpen(); } -shared_ptr ContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player) +shared_ptr ContainerMenu::getContainer() { - shared_ptr out = AbstractContainerMenu::clicked(slotIndex, buttonNum, clickType, player); + return container; +} + +shared_ptr ContainerMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player, bool looped) // 4J Added looped param +{ + shared_ptr out = AbstractContainerMenu::clicked(slotIndex, buttonNum, clickType, player, looped); #ifdef _EXTENDED_ACHIEVEMENTS shared_ptr localPlayer = dynamic_pointer_cast(player); @@ -98,7 +103,7 @@ shared_ptr ContainerMenu::clicked(int slotIndex, int buttonNum, in for (int i = 0; i < container->getContainerSize(); i++) { shared_ptr item = container->getItem(i); - if ( (item != nullptr) && (item->id == Tile::stoneBrick_Id) ) + if ( (item != nullptr) && (item->id == Tile::cobblestone_Id) ) { cobblecount += item->GetCount(); } @@ -107,7 +112,7 @@ shared_ptr ContainerMenu::clicked(int slotIndex, int buttonNum, in // 4J-JEV: This check performed on XboxOne servers, for other platforms check here. #ifndef _DURANGO StatsCounter *sc = Minecraft::GetInstance()->stats[localPlayer->GetXboxPad()]; - int minedCount = sc->getTotalValue(GenericStats::blocksMined(Tile::rock_Id)) + sc->getTotalValue(GenericStats::blocksMined(Tile::stoneBrick_Id)); + int minedCount = sc->getTotalValue(GenericStats::blocksMined(Tile::stone_Id)) + sc->getTotalValue(GenericStats::blocksMined(Tile::cobblestone_Id)); if (cobblecount >= 1728 && minedCount >= 1728 ) #endif { diff --git a/Minecraft.World/ContainerMenu.h b/Minecraft.World/ContainerMenu.h index e6da0782..5d70ecc5 100644 --- a/Minecraft.World/ContainerMenu.h +++ b/Minecraft.World/ContainerMenu.h @@ -15,8 +15,9 @@ public: virtual bool stillValid(shared_ptr player); virtual shared_ptr quickMoveStack(shared_ptr player, int slotIndex); - void removed(shared_ptr player); + virtual void removed(shared_ptr player); + virtual shared_ptr getContainer(); // 4J ADDED, - virtual shared_ptr clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player); + virtual shared_ptr clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player, bool looped = false); }; diff --git a/Minecraft.World/ContainerOpenPacket.cpp b/Minecraft.World/ContainerOpenPacket.cpp index 7cb530cf..d5268922 100644 --- a/Minecraft.World/ContainerOpenPacket.cpp +++ b/Minecraft.World/ContainerOpenPacket.cpp @@ -4,20 +4,30 @@ #include "PacketListener.h" #include "ContainerOpenPacket.h" -ContainerOpenPacket::ContainerOpenPacket() -{ - containerId = 0; - type = 0; - title = 0; - size = 0; -} - -ContainerOpenPacket::ContainerOpenPacket(int containerId, int type, int title, int size) +void ContainerOpenPacket::_init(int containerId, int type, const wstring &title, int size, bool customName, int entityId) { this->containerId = containerId; this->type = type; this->title = title; this->size = size; + this->customName = customName; + this->entityId = entityId; +} + +ContainerOpenPacket::ContainerOpenPacket() +{ + _init(0, 0, L"", 0, false, 0); + +} + +ContainerOpenPacket::ContainerOpenPacket(int containerId, int type, const wstring &title, int size, bool customName) +{ + _init(containerId, type, title, size, customName, 0); +} + +ContainerOpenPacket::ContainerOpenPacket(int containerId, int type, const wstring &title, int size, bool customName, int entityId) +{ + _init(containerId, type, title, size, customName, entityId); } void ContainerOpenPacket::handle(PacketListener *listener) @@ -30,19 +40,39 @@ void ContainerOpenPacket::read(DataInputStream *dis) //throws IOException { containerId = dis->readByte() & 0xff; type = dis->readByte() & 0xff; - title = dis->readShort(); size = dis->readByte() & 0xff; + customName = dis->readBoolean(); + if (type == HORSE) + { + entityId = dis->readInt(); + } + if(customName) + { + title = readUtf(dis,64); + } } void ContainerOpenPacket::write(DataOutputStream *dos) //throws IOException { dos->writeByte(containerId & 0xff); dos->writeByte(type & 0xff); - dos->writeShort(title & 0xffff); dos->writeByte(size & 0xff); + dos->writeBoolean(customName); + if (type == HORSE) + { + dos->writeInt(entityId); + } + if(customName) + { + writeUtf(title, dos); + } } int ContainerOpenPacket::getEstimatedSize() { - return 5; + if (type == HORSE) + { + return 10; + } + return 6; } diff --git a/Minecraft.World/ContainerOpenPacket.h b/Minecraft.World/ContainerOpenPacket.h index dbc65b9a..896b7dd9 100644 --- a/Minecraft.World/ContainerOpenPacket.h +++ b/Minecraft.World/ContainerOpenPacket.h @@ -15,14 +15,30 @@ public: static const int TRADER_NPC = 6; static const int BEACON = 7; static const int REPAIR_TABLE = 8; + static const int HOPPER = 9; + static const int DROPPER = 10; + static const int HORSE = 11; + static const int FIREWORKS = 12; // 4J Added + static const int BONUS_CHEST = 13; // 4J Added + static const int LARGE_CHEST = 14; // 4J Added + static const int ENDER_CHEST = 15; // 4J Added + static const int MINECART_CHEST = 16; // 4J Added + static const int MINECART_HOPPER = 17; // 4J Added int containerId; int type; - int title; // 4J Stu - Changed from string int size; + bool customName; + wstring title; + int entityId; +private: + void _init(int containerId, int type, const wstring &title, int size, bool customName, int entityId); + +public: ContainerOpenPacket(); - ContainerOpenPacket(int containerId, int type, int title, int size); + ContainerOpenPacket(int containerId, int type, const wstring &title, int size, bool customName); + ContainerOpenPacket(int containerId, int type, const wstring &title, int size, bool customName, int entityId); virtual void handle(PacketListener *listener); virtual void read(DataInputStream *dis); diff --git a/Minecraft.World/ControlledByPlayerGoal.cpp b/Minecraft.World/ControlledByPlayerGoal.cpp index 1e035494..cea227cd 100644 --- a/Minecraft.World/ControlledByPlayerGoal.cpp +++ b/Minecraft.World/ControlledByPlayerGoal.cpp @@ -36,8 +36,7 @@ void ControlledByPlayerGoal::stop() bool ControlledByPlayerGoal::canUse() { - shared_ptr player = dynamic_pointer_cast( mob->rider.lock() ); - return mob->isAlive() && player && (boosting || mob->canBeControlledByRider()); + return mob->isAlive() && mob->rider.lock() != NULL && mob->rider.lock()->instanceof(eTYPE_PLAYER) && (boosting || mob->canBeControlledByRider()); } void ControlledByPlayerGoal::tick() @@ -120,7 +119,7 @@ void ControlledByPlayerGoal::tick() if (carriedItem != NULL && carriedItem->id == Item::carrotOnAStick_Id) { - carriedItem->hurt(1, player); + carriedItem->hurtAndBreak(1, player); if (carriedItem->count == 0) { @@ -134,6 +133,11 @@ void ControlledByPlayerGoal::tick() mob->travel(0, moveSpeed); } +bool ControlledByPlayerGoal::isNoJumpTile(int tile) +{ + return Tile::tiles[tile] != NULL && (Tile::tiles[tile]->getRenderShape() == Tile::SHAPE_STAIRS || (dynamic_cast(Tile::tiles[tile]) != NULL) ); +} + bool ControlledByPlayerGoal::isBoosting() { return boosting; diff --git a/Minecraft.World/ControlledByPlayerGoal.h b/Minecraft.World/ControlledByPlayerGoal.h index f49eaaf1..25bd579c 100644 --- a/Minecraft.World/ControlledByPlayerGoal.h +++ b/Minecraft.World/ControlledByPlayerGoal.h @@ -26,6 +26,11 @@ public: void stop(); bool canUse(); void tick(); + +private: + bool isNoJumpTile(int tile); + +public: bool isBoosting(); void boost(); bool canBoost(); diff --git a/Minecraft.World/Cow.cpp b/Minecraft.World/Cow.cpp index c259183e..05e70102 100644 --- a/Minecraft.World/Cow.cpp +++ b/Minecraft.World/Cow.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "com.mojang.nbt.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.navigation.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.level.tile.h" @@ -7,6 +8,7 @@ #include "net.minecraft.world.level.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.stats.h" #include "Cow.h" #include "..\Minecraft.Client\Textures.h" @@ -19,20 +21,18 @@ Cow::Cow(Level *level) : Animal( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_COW; // 4J was L"/mob/cow.png"; this->setSize(0.9f, 1.3f); getNavigation()->setAvoidWater(true); goalSelector.addGoal(0, new FloatGoal(this)); - goalSelector.addGoal(1, new PanicGoal(this, 0.38f)); - goalSelector.addGoal(2, new BreedGoal(this, 0.2f)); - goalSelector.addGoal(3, new TemptGoal(this, 0.25f, Item::wheat_Id, false)); - goalSelector.addGoal(4, new FollowParentGoal(this, 0.25f)); - goalSelector.addGoal(5, new RandomStrollGoal(this, 0.2f)); + goalSelector.addGoal(1, new PanicGoal(this, 2.0f)); + goalSelector.addGoal(2, new BreedGoal(this, 1.0f)); + goalSelector.addGoal(3, new TemptGoal(this, 1.25f, Item::wheat_Id, false)); + goalSelector.addGoal(4, new FollowParentGoal(this, 1.25f)); + goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0f)); goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 6)); goalSelector.addGoal(7, new RandomLookAroundGoal(this)); } @@ -42,9 +42,12 @@ bool Cow::useNewAi() return true; } -int Cow::getMaxHealth() +void Cow::registerAttributes() { - return 10; + Animal::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(10); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.2f); } int Cow::getAmbientSound() @@ -62,6 +65,11 @@ int Cow::getDeathSound() return eSoundType_MOB_COW_HURT; } +void Cow::playStepSound(int xt, int yt, int zt, int t) +{ + playSound(eSoundType_MOB_COW_STEP, 0.15f, 1); +} + float Cow::getSoundVolume() { return 0.4f; @@ -95,25 +103,25 @@ void Cow::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) } } -bool Cow::interact(shared_ptr player) +bool Cow::mobInteract(shared_ptr player) { shared_ptr item = player->inventory->getSelected(); - if (item != NULL && item->id == Item::bucket_empty->id) + if (item != NULL && item->id == Item::bucket_empty->id && !player->abilities.instabuild) { player->awardStat(GenericStats::cowsMilked(),GenericStats::param_cowsMilked()); - if (--item->count <= 0) + if (item->count-- == 0) { - player->inventory->setItem(player->inventory->selected, shared_ptr( new ItemInstance(Item::milk) ) ); + player->inventory->setItem(player->inventory->selected, shared_ptr( new ItemInstance(Item::bucket_milk) ) ); } - else if (!player->inventory->add(shared_ptr( new ItemInstance(Item::milk) ))) + else if (!player->inventory->add(shared_ptr( new ItemInstance(Item::bucket_milk) ))) { - player->drop(shared_ptr( new ItemInstance(Item::milk) )); + player->drop(shared_ptr( new ItemInstance(Item::bucket_milk) )); } return true; } - return Animal::interact(player); + return Animal::mobInteract(player); } shared_ptr Cow::getBreedOffspring(shared_ptr target) diff --git a/Minecraft.World/Cow.h b/Minecraft.World/Cow.h index a1a91aba..24210631 100644 --- a/Minecraft.World/Cow.h +++ b/Minecraft.World/Cow.h @@ -16,17 +16,18 @@ public: public: Cow(Level *level); virtual bool useNewAi(); - virtual int getMaxHealth(); protected: + virtual void registerAttributes(); virtual int getAmbientSound(); virtual int getHurtSound(); virtual int getDeathSound(); virtual float getSoundVolume(); virtual int getDeathLoot(); + virtual void playStepSound(int xt, int yt, int zt, int t); virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); public: - virtual bool interact(shared_ptr player); + virtual bool mobInteract(shared_ptr player); virtual shared_ptr getBreedOffspring(shared_ptr target); }; diff --git a/Minecraft.World/CraftingContainer.cpp b/Minecraft.World/CraftingContainer.cpp index fbcc5678..7057edfe 100644 --- a/Minecraft.World/CraftingContainer.cpp +++ b/Minecraft.World/CraftingContainer.cpp @@ -41,9 +41,19 @@ shared_ptr CraftingContainer::getItem(unsigned int x, unsigned int return getItem(pos); } -int CraftingContainer::getName() +wstring CraftingContainer::getName() { - return 0; + return L""; +} + +wstring CraftingContainer::getCustomName() +{ + return L""; +} + +bool CraftingContainer::hasCustomName() +{ + return false; } shared_ptr CraftingContainer::removeItemNoUpdate(int slot) @@ -95,6 +105,11 @@ void CraftingContainer::setChanged() } bool CraftingContainer::stillValid(shared_ptr player) +{ + return true; +} + +bool CraftingContainer::canPlaceItem(int slot, shared_ptr item) { return true; } \ No newline at end of file diff --git a/Minecraft.World/CraftingContainer.h b/Minecraft.World/CraftingContainer.h index 863249a2..fc8c2967 100644 --- a/Minecraft.World/CraftingContainer.h +++ b/Minecraft.World/CraftingContainer.h @@ -18,7 +18,9 @@ public: virtual unsigned int getContainerSize(); virtual shared_ptr getItem(unsigned int slot); shared_ptr getItem(unsigned int x, unsigned int y); - virtual int getName(); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual bool hasCustomName(); virtual shared_ptr removeItemNoUpdate(int slot); virtual shared_ptr removeItem(unsigned int slot, int count); virtual void setItem(unsigned int slot, shared_ptr item); @@ -29,4 +31,5 @@ public: void startOpen() { } // TODO Auto-generated method stub void stopOpen() { } // TODO Auto-generated method stub + virtual bool canPlaceItem(int slot, shared_ptr item); }; \ No newline at end of file diff --git a/Minecraft.World/CraftingMenu.cpp b/Minecraft.World/CraftingMenu.cpp index eeb2a6e3..c104bbec 100644 --- a/Minecraft.World/CraftingMenu.cpp +++ b/Minecraft.World/CraftingMenu.cpp @@ -23,9 +23,9 @@ CraftingMenu::CraftingMenu(shared_ptr inventory, Level *level, int xt resultSlots = shared_ptr( new ResultContainer() ); this->level = level; - this->x = xt; - this->y = yt; - this->z = zt; + x = xt; + y = yt; + z = zt; addSlot(new ResultSlot( inventory->player, craftSlots, resultSlots, 0, 120 + 4, 31 + 4)); for (int y = 0; y < 3; y++) @@ -81,7 +81,7 @@ bool CraftingMenu::stillValid(shared_ptr player) shared_ptr CraftingMenu::quickMoveStack(shared_ptr player, int slotIndex) { shared_ptr clicked = nullptr; - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot != NULL && slot->hasItem()) { shared_ptr stack = slot->getItem(); @@ -135,4 +135,9 @@ shared_ptr CraftingMenu::quickMoveStack(shared_ptr player, } } return clicked; +} + +bool CraftingMenu::canTakeItemForPickAll(shared_ptr carried, Slot *target) +{ + return target->container != resultSlots && AbstractContainerMenu::canTakeItemForPickAll(carried, target); } \ No newline at end of file diff --git a/Minecraft.World/CraftingMenu.h b/Minecraft.World/CraftingMenu.h index 0452eccc..b10344c0 100644 --- a/Minecraft.World/CraftingMenu.h +++ b/Minecraft.World/CraftingMenu.h @@ -32,4 +32,9 @@ public: virtual void removed(shared_ptr player); virtual bool stillValid(shared_ptr player); virtual shared_ptr quickMoveStack(shared_ptr player, int slotIndex); + virtual bool canTakeItemForPickAll(shared_ptr carried, Slot *target); + + int getX() { return x; } + int getY() { return y; } + int getZ() { return z; } }; \ No newline at end of file diff --git a/Minecraft.World/Creeper.cpp b/Minecraft.World/Creeper.cpp index 3f6c66a7..29be2c0c 100644 --- a/Minecraft.World/Creeper.cpp +++ b/Minecraft.World/Creeper.cpp @@ -3,11 +3,13 @@ #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.entity.ai.goal.target.h" #include "net.minecraft.world.entity.ai.navigation.h" #include "net.minecraft.world.entity.animal.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.damagesource.h" #include "GeneralStat.h" #include "Skeleton.h" @@ -22,6 +24,8 @@ void Creeper::_init() { swell = 0; oldSwell = 0; + maxSwell = 30; + explosionRadius = 3; } Creeper::Creeper(Level *level) : Monster( level ) @@ -29,105 +33,124 @@ Creeper::Creeper(Level *level) : Monster( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); + setHealth(getMaxHealth()); _init(); - - this->textureIdx = TN_MOB_CREEPER; // 4J was L"/mob/creeper.png"; goalSelector.addGoal(1, new FloatGoal(this)); goalSelector.addGoal(2, new SwellGoal(this)); - goalSelector.addGoal(3, new AvoidPlayerGoal(this, typeid(Ozelot), 6, 0.25f, 0.30f)); - goalSelector.addGoal(4, new MeleeAttackGoal(this, 0.25f, false)); - goalSelector.addGoal(5, new RandomStrollGoal(this, 0.20f)); + goalSelector.addGoal(3, new AvoidPlayerGoal(this, typeid(Ocelot), 6, 1.0, 1.2)); + goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, false)); + goalSelector.addGoal(5, new RandomStrollGoal(this, 0.8)); goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 8)); goalSelector.addGoal(6, new RandomLookAroundGoal(this)); - targetSelector.addGoal(1, new NearestAttackableTargetGoal(this, typeid(Player), 16, 0, true)); + targetSelector.addGoal(1, new NearestAttackableTargetGoal(this, typeid(Player), 0, true)); targetSelector.addGoal(2, new HurtByTargetGoal(this, false)); } +void Creeper::registerAttributes() +{ + Monster::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f); +} + bool Creeper::useNewAi() { return true; } -int Creeper::getMaxHealth() +int Creeper::getMaxFallDistance() +{ + if (getTarget() == NULL) return 3; + // As long as they survive the fall they should try. + return 3 + (int) (getHealth() - 1); +} + +void Creeper::causeFallDamage(float distance) { - return 20; + Monster::causeFallDamage(distance); + + swell += distance * 1.5f; + if (swell > maxSwell - 5) swell = maxSwell - 5; } void Creeper::defineSynchedData() { - Monster::defineSynchedData(); + Monster::defineSynchedData(); - entityData->define(DATA_SWELL_DIR, (byte) -1); - entityData->define(DATA_IS_POWERED, (byte) 0); + entityData->define(DATA_SWELL_DIR, (byte) -1); + entityData->define(DATA_IS_POWERED, (byte) 0); } void Creeper::addAdditonalSaveData(CompoundTag *entityTag) { - Monster::addAdditonalSaveData(entityTag); - if (entityData->getByte(DATA_IS_POWERED) == 1) entityTag->putBoolean(L"powered", true); + Monster::addAdditonalSaveData(entityTag); + if (entityData->getByte(DATA_IS_POWERED) == 1) entityTag->putBoolean(L"powered", true); + entityTag->putShort(L"Fuse", (short) maxSwell); + entityTag->putByte(L"ExplosionRadius", (byte) explosionRadius); } void Creeper::readAdditionalSaveData(CompoundTag *tag) { - Monster::readAdditionalSaveData(tag); - entityData->set(DATA_IS_POWERED, (byte) (tag->getBoolean(L"powered") ? 1 : 0)); + Monster::readAdditionalSaveData(tag); + entityData->set(DATA_IS_POWERED, (byte) (tag->getBoolean(L"powered") ? 1 : 0)); + if (tag->contains(L"Fuse")) maxSwell = tag->getShort(L"Fuse"); + if (tag->contains(L"ExplosionRadius")) explosionRadius = tag->getByte(L"ExplosionRadius"); } void Creeper::tick() { - oldSwell = swell; - if (isAlive()) + oldSwell = swell; + if (isAlive()) { - int swellDir = getSwellDir(); - if (swellDir > 0 && swell == 0) + int swellDir = getSwellDir(); + if (swellDir > 0 && swell == 0) { - level->playSound(shared_from_this(), eSoundType_RANDOM_FUSE, 1, 0.5f); - } - swell += swellDir; - if (swell < 0) swell = 0; - if (swell >= MAX_SWELL) + playSound(eSoundType_RANDOM_FUSE, 1, 0.5f); + } + swell += swellDir; + if (swell < 0) swell = 0; + if (swell >= maxSwell) { - swell = MAX_SWELL; + swell = maxSwell; if (!level->isClientSide) { - bool destroyBlocks = true; //level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); - if (isPowered()) level->explode(shared_from_this(), x, y, z, 6, destroyBlocks); - else level->explode(shared_from_this(), x, y, z, 3,destroyBlocks); + bool destroyBlocks = level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING); + if (isPowered()) level->explode(shared_from_this(), x, y, z, explosionRadius * 2, destroyBlocks); + else level->explode(shared_from_this(), x, y, z, explosionRadius, destroyBlocks); remove(); } } - } - Monster::tick(); + } + Monster::tick(); } int Creeper::getHurtSound() { - return eSoundType_MOB_CREEPER_HURT; + return eSoundType_MOB_CREEPER_HURT; } int Creeper::getDeathSound() { - return eSoundType_MOB_CREEPER_DEATH; + return eSoundType_MOB_CREEPER_DEATH; } void Creeper::die(DamageSource *source) { - Monster::die(source); + Monster::die(source); - if ( dynamic_pointer_cast(source->getEntity()) != NULL ) + if ( source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_SKELETON) ) { - spawnAtLocation(Item::record_01_Id + random->nextInt(12), 1); - } + int recordId = Item::record_01_Id + random->nextInt(Item::record_12_Id - Item::record_01_Id + 1); + spawnAtLocation(recordId, 1); + } - shared_ptr player = dynamic_pointer_cast(source->getEntity()); - if ( (dynamic_pointer_cast(source->getDirectEntity()) != NULL) && (player != NULL) ) + if ( source->getDirectEntity() != NULL && source->getDirectEntity()->instanceof(eTYPE_ARROW) && source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_PLAYER) ) { + shared_ptr player = dynamic_pointer_cast(source->getEntity()); player->awardStat(GenericStats::archer(), GenericStats::param_archer()); } } @@ -139,31 +162,31 @@ bool Creeper::doHurtTarget(shared_ptr target) bool Creeper::isPowered() { - return entityData->getByte(DATA_IS_POWERED) == 1; + return entityData->getByte(DATA_IS_POWERED) == 1; } float Creeper::getSwelling(float a) { - return (oldSwell + (swell - oldSwell) * a) / (MAX_SWELL - 2); + return (oldSwell + (swell - oldSwell) * a) / (maxSwell - 2); } int Creeper::getDeathLoot() { - return Item::sulphur->id; + return Item::gunpowder_Id; } int Creeper::getSwellDir() { - return (int) (char) entityData->getByte(DATA_SWELL_DIR); + return (int) (char) entityData->getByte(DATA_SWELL_DIR); } void Creeper::setSwellDir(int dir) { - entityData->set(DATA_SWELL_DIR, (byte) dir); + entityData->set(DATA_SWELL_DIR, (byte) dir); } void Creeper::thunderHit(const LightningBolt *lightningBolt) { - Monster::thunderHit(lightningBolt); - entityData->set(DATA_IS_POWERED, (byte) 1); + Monster::thunderHit(lightningBolt); + entityData->set(DATA_IS_POWERED, (byte) 1); } diff --git a/Minecraft.World/Creeper.h b/Minecraft.World/Creeper.h index a5da0e10..d5cd4cff 100644 --- a/Minecraft.World/Creeper.h +++ b/Minecraft.World/Creeper.h @@ -14,30 +14,36 @@ public: private: static const int DATA_SWELL_DIR = 16; - static const int DATA_IS_POWERED = 17; + static const int DATA_IS_POWERED = 17; - int swell; - int oldSwell; - - static const int MAX_SWELL = 30; + int oldSwell; + int swell; + int maxSwell; + int explosionRadius; void _init(); public: Creeper(Level *level); +protected: + void registerAttributes(); + +public: virtual bool useNewAi(); - virtual int getMaxHealth(); + + virtual int getMaxFallDistance(); protected: + virtual void causeFallDamage(float distance); virtual void defineSynchedData(); public: virtual void addAdditonalSaveData(CompoundTag *entityTag); - virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void readAdditionalSaveData(CompoundTag *tag); protected: - virtual void tick(); + virtual void tick(); protected: virtual int getHurtSound(); @@ -47,7 +53,7 @@ public: virtual void die(DamageSource *source); virtual bool doHurtTarget(shared_ptr target); virtual bool isPowered(); - float getSwelling(float a); + float getSwelling(float a); protected: int getDeathLoot(); diff --git a/Minecraft.World/CropTile.cpp b/Minecraft.World/CropTile.cpp index 0c19d889..29c5b1c9 100644 --- a/Minecraft.World/CropTile.cpp +++ b/Minecraft.World/CropTile.cpp @@ -40,18 +40,20 @@ void CropTile::tick(Level *level, int x, int y, int z, Random *random) { float growthSpeed = getGrowthSpeed(level, x, y, z); - if (random->nextInt((int) (25 / growthSpeed) + 1) == 0) + if (random->nextInt((int) (25 / growthSpeed) + 1) == 0) { age++; - level->setData(x, y, z, age); + level->setData(x, y, z, age, Tile::UPDATE_CLIENTS); } } } } -void CropTile::growCropsToMax(Level *level, int x, int y, int z) +void CropTile::growCrops(Level *level, int x, int y, int z) { - level->setData(x, y, z, 7); + int stage = level->getData(x, y, z) + Mth::nextInt(level->random, 2, 5); + if (stage > 7) stage = 7; + level->setData(x, y, z, stage, Tile::UPDATE_CLIENTS); } float CropTile::getGrowthSpeed(Level *level, int x, int y, int z) @@ -68,9 +70,9 @@ float CropTile::getGrowthSpeed(Level *level, int x, int y, int z) int d2 = level->getTile(x + 1, y, z + 1); int d3 = level->getTile(x - 1, y, z + 1); - bool horizontal = w == this->id || e == this->id; - bool vertical = n == this->id || s == this->id; - bool diagonal = d0 == this->id || d1 == this->id || d2 == this->id || d3 == this->id; + bool horizontal = w == id || e == id; + bool vertical = n == id || s == id; + bool diagonal = d0 == id || d1 == id || d2 == id || d3 == id; for (int xx = x - 1; xx <= x + 1; xx++) for (int zz = z - 1; zz <= z + 1; zz++) @@ -89,9 +91,9 @@ float CropTile::getGrowthSpeed(Level *level, int x, int y, int z) speed += tileSpeed; } - if (diagonal || (horizontal && vertical)) speed /= 2; + if (diagonal || (horizontal && vertical)) speed /= 2; - return speed; + return speed; } @@ -117,9 +119,9 @@ int CropTile::getBasePlantId() } /** - * Using this method instead of destroy() to determine if seeds should be - * dropped - */ +* Using this method instead of destroy() to determine if seeds should be +* dropped +*/ void CropTile::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus) { Bush::spawnResources(level, x, y, z, data, odds, 0); @@ -128,7 +130,8 @@ void CropTile::spawnResources(Level *level, int x, int y, int z, int data, float { return; } - if (data >= 7) { + if (data >= 7) + { int count = 3 + playerBonus; for (int i = 0; i < count; i++) { diff --git a/Minecraft.World/CropTile.h b/Minecraft.World/CropTile.h index 998c5367..165fd4af 100644 --- a/Minecraft.World/CropTile.h +++ b/Minecraft.World/CropTile.h @@ -15,29 +15,29 @@ private: protected: CropTile(int id); - virtual bool mayPlaceOn(int tile); + virtual bool mayPlaceOn(int tile); public: // 4J Added override virtual void updateDefaultShape(); virtual void tick(Level *level, int x, int y, int z, Random *random); - void growCropsToMax(Level *level, int x, int y, int z); + virtual void growCrops(Level *level, int x, int y, int z); private: float getGrowthSpeed(Level *level, int x, int y, int z); public: virtual Icon *getTexture(int face, int data); - virtual int getRenderShape(); + virtual int getRenderShape(); protected: virtual int getBaseSeedId(); virtual int getBasePlantId(); public: - /** - * Using this method instead of destroy() to determine if seeds should be - * dropped - */ - virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); - virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual int getResourceCount(Random *random); + /** + * Using this method instead of destroy() to determine if seeds should be + * dropped + */ + virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual int getResourceCount(Random *random); virtual int cloneTileId(Level *level, int x, int y, int z); //@Override virtual void registerIcons(IconRegister *iconRegister); diff --git a/Minecraft.World/CustomLevelSource.cpp b/Minecraft.World/CustomLevelSource.cpp index 216e63b9..61316299 100644 --- a/Minecraft.World/CustomLevelSource.cpp +++ b/Minecraft.World/CustomLevelSource.cpp @@ -7,6 +7,7 @@ #include "net.minecraft.world.level.levelgen.synth.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.storage.h" +#include "net.minecraft.world.entity.h" #include "CustomLevelSource.h" const double CustomLevelSource::SNOW_SCALE = 0.3; @@ -103,15 +104,16 @@ CustomLevelSource::CustomLevelSource(Level *level, __int64 seed, bool generateSt caveFeature = new LargeCaveFeature(); strongholdFeature = new StrongholdFeature(); - villageFeature = new VillageFeature(0,m_XZSize); + villageFeature = new VillageFeature(m_XZSize); mineShaftFeature = new MineShaftFeature(); + scatteredFeature = new RandomScatteredLargeFeature(); canyonFeature = new CanyonFeature(); this->level = level; random = new Random(seed); pprandom = new Random(seed); // 4J - added, so that we can have a separate random for doing post-processing in parallel with creation - perlinNoise3 = new PerlinNoise(random, 4); + perlinNoise3 = new PerlinNoise(random, 4); #endif } @@ -127,7 +129,7 @@ CustomLevelSource::~CustomLevelSource() this->level = level; delete random; - delete perlinNoise3; + delete perlinNoise3; #endif } @@ -202,7 +204,7 @@ void CustomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) // 4J - this comparison used to just be with 0.0f but is now varied by block above if (yc * CHUNK_HEIGHT + y < mapHeight) { - tileId = (byte) Tile::rock_Id; + tileId = (byte) Tile::stone_Id; } else if (yc * CHUNK_HEIGHT + y < waterHeight) { @@ -215,7 +217,7 @@ void CustomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) if( emin == 0 ) { // This matches code in MultiPlayerChunkCache that makes the geometry which continues at the edge of the world - if( yc * CHUNK_HEIGHT + y <= ( level->getSeaLevel() - 10 ) ) tileId = Tile::rock_Id; + if( yc * CHUNK_HEIGHT + y <= ( level->getSeaLevel() - 10 ) ) tileId = Tile::stone_Id; else if( yc * CHUNK_HEIGHT + y < level->getSeaLevel() ) tileId = Tile::calmWater_Id; } @@ -298,14 +300,14 @@ void CustomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, Bi { run = -1; } - else if (old == Tile::rock_Id) + else if (old == Tile::stone_Id) { if (run == -1) { if (runDepth <= 0) { top = 0; - material = (byte) Tile::rock_Id; + material = (byte) Tile::stone_Id; } else if (y >= waterHeight - 4 && y <= waterHeight + 1) { @@ -393,6 +395,7 @@ LevelChunk *CustomLevelSource::getChunk(int xOffs, int zOffs) mineShaftFeature->apply(this, level, xOffs, zOffs, blocks); villageFeature->apply(this, level, xOffs, zOffs, blocks); strongholdFeature->apply(this, level, xOffs, zOffs, blocks); + scatteredFeature->apply(this, level, xOffs, zOffs, blocks); } // canyonFeature.apply(this, level, xOffs, zOffs, blocks); // townFeature.apply(this, level, xOffs, zOffs, blocks); @@ -466,7 +469,7 @@ void CustomLevelSource::calcWaterDepths(ChunkSource *parent, int xt, int zt) int od = level->getData(xp + x2, y, zp + z2); if (od < 7 && od < d) { - level->setData(xp + x2, y, zp + z2, d); + level->setData(xp + x2, y, zp + z2, d, Tile::UPDATE_CLIENTS); } } } @@ -474,10 +477,10 @@ void CustomLevelSource::calcWaterDepths(ChunkSource *parent, int xt, int zt) } if (hadWater) { - level->setTileAndDataNoUpdate(xp, y, zp, Tile::calmWater_Id, 7); + level->setTileAndData(xp, y, zp, Tile::calmWater_Id, 7, Tile::UPDATE_CLIENTS); for (int y2 = 0; y2 < y; y2++) { - level->setTileAndDataNoUpdate(xp, y2, zp, Tile::calmWater_Id, 8); + level->setTileAndData(xp, y2, zp, Tile::calmWater_Id, 8, Tile::UPDATE_CLIENTS); } } } @@ -516,6 +519,7 @@ void CustomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) mineShaftFeature->postProcess(level, pprandom, xt, zt); hasVillage = villageFeature->postProcess(level, pprandom, xt, zt); strongholdFeature->postProcess(level, pprandom, xt, zt); + scatteredFeature->postProcess(level, random, xt, zt); } PIXEndNamedEvent(); @@ -581,11 +585,11 @@ void CustomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) if (level->shouldFreezeIgnoreNeighbors(x + xo, y - 1, z + zo)) { - level->setTileNoUpdate(x + xo, y - 1, z + zo, Tile::ice_Id); // 4J - changed from setTile, otherwise we end up creating a *lot* of dynamic water tiles as these ice tiles are set + level->setTileAndData(x + xo, y - 1, z + zo, Tile::ice_Id,0, Tile::UPDATE_INVISIBLE); // 4J - changed from setTile, otherwise we end up creating a *lot* of dynamic water tiles as these ice tiles are set } if (level->shouldSnow(x + xo, y, z + zo)) { - level->setTile(x + xo, y, z + zo, Tile::topSnow_Id); + level->setTileAndData(x + xo, y, z + zo, Tile::topSnow_Id,0, Tile::UPDATE_CLIENTS); } } } @@ -622,6 +626,10 @@ vector *CustomLevelSource::getMobsAt(MobCategory *mobCa { return NULL; } + if (mobCategory == MobCategory::monster && scatteredFeature->isSwamphut(x, y, z)) + { + return scatteredFeature->getSwamphutEnemies(); + } return biome->getMobs(mobCategory); #else return NULL; @@ -638,3 +646,16 @@ TilePos *CustomLevelSource::findNearestMapFeature(Level *level, const wstring& f #endif return NULL; } + +void CustomLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ) +{ + if (generateStructures) + { +#ifdef _OVERRIDE_HEIGHTMAP + mineShaftFeature->apply(this, level, chunkX, chunkZ, NULL); + villageFeature->apply(this, level, chunkX, chunkZ, NULL); + strongholdFeature->apply(this, level, chunkX, chunkZ, NULL); + scatteredFeature->apply(this, level, chunkX, chunkZ, NULL); +#endif + } +} \ No newline at end of file diff --git a/Minecraft.World/CustomLevelSource.h b/Minecraft.World/CustomLevelSource.h index af01a478..7739fc95 100644 --- a/Minecraft.World/CustomLevelSource.h +++ b/Minecraft.World/CustomLevelSource.h @@ -12,6 +12,7 @@ class LargeFeature; class StrongholdFeature; class VillageFeature; class MineShaftFeature; +class RandomScatteredLargeFeature; class CustomLevelSource : public ChunkSource { @@ -32,6 +33,7 @@ private: StrongholdFeature *strongholdFeature; VillageFeature *villageFeature; MineShaftFeature *mineShaftFeature; + RandomScatteredLargeFeature *scatteredFeature; LargeFeature *canyonFeature; Level *level; #endif @@ -76,4 +78,5 @@ public: public: virtual vector *getMobsAt(MobCategory *mobCategory, int x, int y, int z); virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ); }; diff --git a/Minecraft.World/DamageEnchantment.cpp b/Minecraft.World/DamageEnchantment.cpp index 686abc62..ce5a7c1f 100644 --- a/Minecraft.World/DamageEnchantment.cpp +++ b/Minecraft.World/DamageEnchantment.cpp @@ -27,19 +27,19 @@ int DamageEnchantment::getMaxLevel() return 5; } -int DamageEnchantment::getDamageBonus(int level, shared_ptr target) +float DamageEnchantment::getDamageBonus(int level, shared_ptr target) { if (type == ALL) { - return Mth::floor(level * 2.75f); + return level *1.25f; } if (type == UNDEAD && target->getMobType() == UNDEAD) { - return Mth::floor(level * 4.5f); + return level * 2.5f; } if (type == ARTHROPODS && target->getMobType() == ARTHROPOD) { - return Mth::floor(level * 4.5f); + return level * 2.5f; } return 0; } diff --git a/Minecraft.World/DamageEnchantment.h b/Minecraft.World/DamageEnchantment.h index 00f9b047..a6abffdc 100644 --- a/Minecraft.World/DamageEnchantment.h +++ b/Minecraft.World/DamageEnchantment.h @@ -23,7 +23,7 @@ public: virtual int getMinCost(int level); virtual int getMaxCost(int level); virtual int getMaxLevel(); - virtual int getDamageBonus(int level, shared_ptr target); + virtual float getDamageBonus(int level, shared_ptr target); virtual int getDescriptionId(); virtual bool isCompatibleWith(Enchantment *other) const; virtual bool canEnchant(shared_ptr item); diff --git a/Minecraft.World/DamageSource.cpp b/Minecraft.World/DamageSource.cpp index 29ea727e..1ed1c65f 100644 --- a/Minecraft.World/DamageSource.cpp +++ b/Minecraft.World/DamageSource.cpp @@ -2,65 +2,76 @@ #include "net.minecraft.world.entity.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.entity.projectile.h" +#include "net.minecraft.world.level.h" #include "net.minecraft.world.damagesource.h" #include "net.minecraft.world.food.h" #include "net.minecraft.network.packet.h" -DamageSource *DamageSource::inFire = (new DamageSource(ChatPacket::e_ChatDeathInFire))->setIsFire(); -DamageSource *DamageSource::onFire = (new DamageSource(ChatPacket::e_ChatDeathOnFire))->bypassArmor()->setIsFire(); -DamageSource *DamageSource::lava = (new DamageSource(ChatPacket::e_ChatDeathLava))->setIsFire(); +DamageSource *DamageSource::inFire = (new DamageSource(ChatPacket::e_ChatDeathInFire, ChatPacket::e_ChatDeathInFirePlayer))->setIsFire(); +DamageSource *DamageSource::onFire = (new DamageSource(ChatPacket::e_ChatDeathOnFire, ChatPacket::e_ChatDeathOnFirePlayer))->bypassArmor()->setIsFire(); +DamageSource *DamageSource::lava = (new DamageSource(ChatPacket::e_ChatDeathLava, ChatPacket::e_ChatDeathLavaPlayer))->setIsFire(); DamageSource *DamageSource::inWall = (new DamageSource(ChatPacket::e_ChatDeathInWall))->bypassArmor(); -DamageSource *DamageSource::drown = (new DamageSource(ChatPacket::e_ChatDeathDrown))->bypassArmor(); +DamageSource *DamageSource::drown = (new DamageSource(ChatPacket::e_ChatDeathDrown, ChatPacket::e_ChatDeathDrownPlayer))->bypassArmor(); DamageSource *DamageSource::starve = (new DamageSource(ChatPacket::e_ChatDeathStarve))->bypassArmor(); -DamageSource *DamageSource::cactus = new DamageSource(ChatPacket::e_ChatDeathCactus); +DamageSource *DamageSource::cactus = new DamageSource(ChatPacket::e_ChatDeathCactus, ChatPacket::e_ChatDeathCactusPlayer); DamageSource *DamageSource::fall = (new DamageSource(ChatPacket::e_ChatDeathFall))->bypassArmor(); DamageSource *DamageSource::outOfWorld = (new DamageSource(ChatPacket::e_ChatDeathOutOfWorld))->bypassArmor()->bypassInvul(); DamageSource *DamageSource::genericSource = (new DamageSource(ChatPacket::e_ChatDeathGeneric))->bypassArmor(); -DamageSource *DamageSource::explosion = (new DamageSource(ChatPacket::e_ChatDeathExplosion))->setScalesWithDifficulty(); -DamageSource *DamageSource::controlledExplosion = (new DamageSource(ChatPacket::e_ChatDeathExplosion)); DamageSource *DamageSource::magic = (new DamageSource(ChatPacket::e_ChatDeathMagic))->bypassArmor()->setMagic(); DamageSource *DamageSource::dragonbreath = (new DamageSource(ChatPacket::e_ChatDeathDragonBreath))->bypassArmor(); DamageSource *DamageSource::wither = (new DamageSource(ChatPacket::e_ChatDeathWither))->bypassArmor(); DamageSource *DamageSource::anvil = (new DamageSource(ChatPacket::e_ChatDeathAnvil)); DamageSource *DamageSource::fallingBlock = (new DamageSource(ChatPacket::e_ChatDeathFallingBlock)); -DamageSource *DamageSource::mobAttack(shared_ptr mob) +DamageSource *DamageSource::mobAttack(shared_ptr mob) { - return new EntityDamageSource(ChatPacket::e_ChatDeathMob, mob); + return new EntityDamageSource(ChatPacket::e_ChatDeathMob, ChatPacket::e_ChatDeathMob, mob); } DamageSource *DamageSource::playerAttack(shared_ptr player) { - return new EntityDamageSource(ChatPacket::e_ChatDeathPlayer, player); + return new EntityDamageSource(ChatPacket::e_ChatDeathPlayer, ChatPacket::e_ChatDeathPlayerItem, player); } DamageSource *DamageSource::arrow(shared_ptr arrow, shared_ptr owner) { - return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathArrow, arrow, owner))->setProjectile(); + return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathArrow, ChatPacket::e_ChatDeathArrowItem, arrow, owner))->setProjectile(); } DamageSource *DamageSource::fireball(shared_ptr fireball, shared_ptr owner) { if (owner == NULL) { - return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathOnFire, fireball, fireball))->setIsFire()->setProjectile(); + return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathOnFire, ChatPacket::e_ChatDeathOnFire, fireball, fireball))->setIsFire()->setProjectile(); } - return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathFireball, fireball, owner))->setIsFire()->setProjectile(); + return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathFireball, ChatPacket::e_ChatDeathArrowItem, fireball, owner))->setIsFire()->setProjectile(); } DamageSource *DamageSource::thrown(shared_ptr entity, shared_ptr owner) { - return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathThrown, entity, owner))->setProjectile(); + return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathThrown, ChatPacket::e_ChatDeathThrownItem, entity, owner))->setProjectile(); } DamageSource *DamageSource::indirectMagic(shared_ptr entity, shared_ptr owner) { - return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathIndirectMagic, entity, owner) )->bypassArmor()->setMagic();; + return (new IndirectEntityDamageSource(ChatPacket::e_ChatDeathIndirectMagic, ChatPacket::e_ChatDeathIndirectMagicItem, entity, owner) )->bypassArmor()->setMagic();; } DamageSource *DamageSource::thorns(shared_ptr source) { - return (new EntityDamageSource(ChatPacket::e_ChatDeathThorns, source))->setMagic(); + return (new EntityDamageSource(ChatPacket::e_ChatDeathThorns, ChatPacket::e_ChatDeathThorns, source))->setMagic(); +} + +DamageSource *DamageSource::explosion(Explosion *explosion) +{ + if ( (explosion != NULL) && (explosion->getSourceMob() != NULL) ) + { + return (new EntityDamageSource(ChatPacket::e_ChatDeathExplosionPlayer, ChatPacket::e_ChatDeathExplosionPlayer, explosion->getSourceMob()))->setScalesWithDifficulty()->setExplosion(); + } + else + { + return (new DamageSource(ChatPacket::e_ChatDeathExplosion))->setScalesWithDifficulty()->setExplosion(); + } } bool DamageSource::isProjectile() @@ -70,7 +81,18 @@ bool DamageSource::isProjectile() DamageSource *DamageSource::setProjectile() { - this->_isProjectile = true; + _isProjectile = true; + return this; +} + +bool DamageSource::isExplosion() +{ + return _isExplosion; +} + +DamageSource *DamageSource::setExplosion() +{ + _isExplosion = true; return this; } @@ -91,7 +113,7 @@ bool DamageSource::isBypassInvul() //DamageSource::DamageSource(const wstring &msgId) -DamageSource::DamageSource(ChatPacket::EChatPacketMessage msgId) +DamageSource::DamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId) { // 4J added initialisors _bypassArmor = false; @@ -101,9 +123,11 @@ DamageSource::DamageSource(ChatPacket::EChatPacketMessage msgId) isFireSource = false; _isProjectile = false; _isMagic = false; + _isExplosion = false; //this->msgId = msgId; m_msgId = msgId; + m_msgWithItemId = msgWithItemId; } shared_ptr DamageSource::getDirectEntity() @@ -164,9 +188,17 @@ DamageSource *DamageSource::setMagic() // //return I18n.get(L"death." + msgId, player.name); //} -shared_ptr DamageSource::getDeathMessagePacket(shared_ptr player) +shared_ptr DamageSource::getDeathMessagePacket(shared_ptr player) { - return shared_ptr( new ChatPacket(player->name, m_msgId ) ); + shared_ptr source = player->getKillCredit(); + if(source != NULL) + { + return shared_ptr( new ChatPacket(player->getNetworkName(), m_msgWithItemId != ChatPacket::e_ChatCustom ? m_msgWithItemId : m_msgId, source->GetType(), source->getNetworkName() ) ); + } + else + { + return shared_ptr( new ChatPacket(player->getNetworkName(), m_msgId ) ); + } } bool DamageSource::isFire() @@ -177,4 +209,16 @@ bool DamageSource::isFire() ChatPacket::EChatPacketMessage DamageSource::getMsgId() { return m_msgId; +} + +// 4J: Very limited check for equality (used to detect fall damage, etc) +bool DamageSource::equals(DamageSource *source) +{ + return m_msgId == source->m_msgId && m_msgWithItemId == source->m_msgWithItemId; +} + +// 4J: Copy function +DamageSource *DamageSource::copy() +{ + return new DamageSource(*this); } \ No newline at end of file diff --git a/Minecraft.World/DamageSource.h b/Minecraft.World/DamageSource.h index 2e1d249d..1173db4d 100644 --- a/Minecraft.World/DamageSource.h +++ b/Minecraft.World/DamageSource.h @@ -1,11 +1,12 @@ #pragma once using namespace std; -class Mob; +class LivingEntity; class Entity; class Arrow; class Fireball; class Player; +class Explosion; #include "ChatPacket.h" @@ -22,22 +23,20 @@ public: static DamageSource *fall; static DamageSource *outOfWorld; static DamageSource *genericSource; - static DamageSource *explosion; - static DamageSource *controlledExplosion; static DamageSource *magic; static DamageSource *dragonbreath; static DamageSource *wither; static DamageSource *anvil; static DamageSource *fallingBlock; - static DamageSource *mobAttack(shared_ptr mob); + static DamageSource *mobAttack(shared_ptr mob); static DamageSource *playerAttack(shared_ptr player); static DamageSource *arrow(shared_ptr arrow, shared_ptr owner); static DamageSource *fireball(shared_ptr fireball, shared_ptr owner); static DamageSource *thrown(shared_ptr entity, shared_ptr owner); static DamageSource *indirectMagic(shared_ptr entity, shared_ptr owner); static DamageSource *thorns(shared_ptr source); - + static DamageSource *explosion(Explosion *explosion); private: bool _bypassArmor; bool _bypassInvul; @@ -47,10 +46,13 @@ private: bool _isProjectile; bool _scalesWithDifficulty; bool _isMagic; + bool _isExplosion; public: bool isProjectile(); DamageSource *setProjectile(); + bool isExplosion(); + DamageSource *setExplosion(); bool isBypassArmor(); float getFoodExhaustion(); @@ -58,10 +60,11 @@ public: //wstring msgId; ChatPacket::EChatPacketMessage m_msgId; // 4J Made int so we can localise + ChatPacket::EChatPacketMessage m_msgWithItemId; // 4J: Renamed from m_msgWithSourceId (it was already renamed in places, just made consistent) protected: //DamageSource(const wstring &msgId); - DamageSource(ChatPacket::EChatPacketMessage msgId); + DamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId = ChatPacket::e_ChatCustom); public: virtual ~DamageSource() {} @@ -83,8 +86,12 @@ public: // 4J Stu - Made return a packet //virtual wstring getLocalizedDeathMessage(shared_ptr player); - virtual shared_ptr getDeathMessagePacket(shared_ptr player); + virtual shared_ptr getDeathMessagePacket(shared_ptr player); bool isFire(); ChatPacket::EChatPacketMessage getMsgId(); // 4J Stu - Used to return String + + // 4J Added + bool equals(DamageSource *source); + virtual DamageSource *copy(); }; \ No newline at end of file diff --git a/Minecraft.World/DataInputStream.cpp b/Minecraft.World/DataInputStream.cpp index 2291bf48..97721c94 100644 --- a/Minecraft.World/DataInputStream.cpp +++ b/Minecraft.World/DataInputStream.cpp @@ -257,6 +257,13 @@ short DataInputStream::readShort() return (short)((a << 8) | (b & 0xff)); } +unsigned short DataInputStream::readUnsignedShort() +{ + int a = stream->read(); + int b = stream->read(); + return (unsigned short)((a << 8) | (b & 0xff)); +} + //Reads in a string that has been encoded using a modified UTF-8 format. The general contract of readUTF is that it reads a representation //of a Unicode character string encoded in modified UTF-8 format; this string of characters is then returned as a String. //First, two bytes are read and used to construct an unsigned 16-bit integer in exactly the manner of the readUnsignedShort method . diff --git a/Minecraft.World/DataInputStream.h b/Minecraft.World/DataInputStream.h index f69d490a..0b228a0d 100644 --- a/Minecraft.World/DataInputStream.h +++ b/Minecraft.World/DataInputStream.h @@ -18,6 +18,7 @@ public: virtual bool readBoolean(); virtual byte readByte(); virtual unsigned char readUnsignedByte(); + virtual unsigned short readUnsignedShort(); virtual wchar_t readChar(); virtual bool readFully(byteArray b); virtual bool readFully(charArray b); diff --git a/Minecraft.World/DataOutputStream.cpp b/Minecraft.World/DataOutputStream.cpp index 8e277c23..8d350f0b 100644 --- a/Minecraft.World/DataOutputStream.cpp +++ b/Minecraft.World/DataOutputStream.cpp @@ -142,6 +142,14 @@ void DataOutputStream::writeShort(short a) written += 2; } +void DataOutputStream::writeUnsignedShort(unsigned short a) +{ + stream->write( (a >> 8) & 0xff ); + stream->write( a & 0xff ); + // TODO 4J Stu - Error handling? + written += 2; +} + //Writes a char to the underlying output stream as a 2-byte value, high byte first. //If no exception is thrown, the counter written is incremented by 2. //Parameters: diff --git a/Minecraft.World/DataOutputStream.h b/Minecraft.World/DataOutputStream.h index 01be8309..8a8c0e12 100644 --- a/Minecraft.World/DataOutputStream.h +++ b/Minecraft.World/DataOutputStream.h @@ -28,6 +28,7 @@ public: virtual void writeInt(int a); virtual void writeLong(__int64 a); virtual void writeShort(short a); + virtual void writeUnsignedShort(unsigned short a); virtual void writeChar(wchar_t a); virtual void writeChars(const wstring& a); virtual void writeBoolean(bool b); diff --git a/Minecraft.World/DaylightDetectorTile.cpp b/Minecraft.World/DaylightDetectorTile.cpp new file mode 100644 index 00000000..1bc9943e --- /dev/null +++ b/Minecraft.World/DaylightDetectorTile.cpp @@ -0,0 +1,114 @@ +#include "stdafx.h" +#include "net.minecraft.h" +#include "net.minecraft.world.level.dimension.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.world.h" +#include "JavaMath.h" +#include "DaylightDetectorTile.h" + +DaylightDetectorTile::DaylightDetectorTile(int id) : BaseEntityTile(id, Material::wood, isSolidRender() ) +{ + updateDefaultShape(); +} + +void DaylightDetectorTile::updateDefaultShape() +{ + setShape(0, 0, 0, 1, 6.0f / 16.0f, 1); +} + +void DaylightDetectorTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) +{ + setShape(0, 0, 0, 1, 6.0f / 16.0f, 1); +} + +int DaylightDetectorTile::getSignal(LevelSource *level, int x, int y, int z, int dir) +{ + return level->getData(x, y, z); +} + +void DaylightDetectorTile::tick(Level *level, int x, int y, int z, Random *random) +{ + // updateSignalStrength(level, x, y, z); +} + +void DaylightDetectorTile::neighborChanged(Level *level, int x, int y, int z, int type) +{ + // level.addToTickNextTick(x, y, z, id, getTickDelay()); +} + +void DaylightDetectorTile::onPlace(Level *level, int x, int y, int z) +{ + // level.addToTickNextTick(x, y, z, id, getTickDelay()); +} + +void DaylightDetectorTile::updateSignalStrength(Level *level, int x, int y, int z) +{ + if (level->dimension->hasCeiling) return; + + int current = level->getData(x, y, z); + int target = level->getBrightness(LightLayer::Sky, x, y, z) - level->skyDarken; + float sunAngle = level->getSunAngle(1); + + // tilt sunAngle towards zenith (to make the transition to night + // smoother) + if (sunAngle < PI) + { + sunAngle = sunAngle + (0 - sunAngle) * .2f; + } + else + { + sunAngle = sunAngle + (PI * 2.0f - sunAngle) * .2f; + } + + target = Math::round((float) target * Mth::cos(sunAngle)); + if (target < 0) + { + target = 0; + } + if (target > Redstone::SIGNAL_MAX) + { + target = Redstone::SIGNAL_MAX; + } + + if (current != target) + { + level->setData(x, y, z, target, UPDATE_ALL); + } +} + +bool DaylightDetectorTile::isCubeShaped() +{ + return false; +} + +bool DaylightDetectorTile::isSolidRender(bool isServerLevel) +{ + return false; +} + +bool DaylightDetectorTile::isSignalSource() +{ + return true; +} + +shared_ptr DaylightDetectorTile::newTileEntity(Level *level) +{ + return shared_ptr( new DaylightDetectorTileEntity() ); +} + +Icon *DaylightDetectorTile::getTexture(int face, int data) +{ + if (face == Facing::UP) + { + return icons[0]; + } + return icons[1]; +} + +void DaylightDetectorTile::registerIcons(IconRegister *iconRegister) +{ + icons[0] = iconRegister->registerIcon(getIconName() + L"_top"); + icons[1] = iconRegister->registerIcon(getIconName() + L"_side"); +} \ No newline at end of file diff --git a/Minecraft.World/DaylightDetectorTile.h b/Minecraft.World/DaylightDetectorTile.h new file mode 100644 index 00000000..635504d2 --- /dev/null +++ b/Minecraft.World/DaylightDetectorTile.h @@ -0,0 +1,27 @@ +#pragma once + +#include "BaseEntityTile.h" + +class DaylightDetectorTile : public BaseEntityTile +{ + friend class ChunkRebuildData; +private: + Icon *icons[2]; + +public: + DaylightDetectorTile(int id); + + virtual void updateDefaultShape(); // 4J Added override + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual void onPlace(Level *level, int x, int y, int z); + virtual void updateSignalStrength(Level *level, int x, int y, int z); + virtual bool isCubeShaped(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isSignalSource(); + virtual shared_ptr newTileEntity(Level *level); + virtual Icon *getTexture(int face, int data); + virtual void registerIcons(IconRegister *iconRegister); +}; \ No newline at end of file diff --git a/Minecraft.World/DaylightDetectorTileEntity.cpp b/Minecraft.World/DaylightDetectorTileEntity.cpp new file mode 100644 index 00000000..5a329413 --- /dev/null +++ b/Minecraft.World/DaylightDetectorTileEntity.cpp @@ -0,0 +1,29 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "DaylightDetectorTileEntity.h" + +DaylightDetectorTileEntity::DaylightDetectorTileEntity() +{ +} + +void DaylightDetectorTileEntity::tick() +{ + if (level != NULL && !level->isClientSide && (level->getGameTime() % SharedConstants::TICKS_PER_SECOND) == 0) + { + tile = getTile(); + if (tile != NULL && dynamic_cast(tile) != NULL) + { + ((DaylightDetectorTile *) tile)->updateSignalStrength(level, x, y, z); + } + } +} + +// 4J Added +shared_ptr DaylightDetectorTileEntity::clone() +{ + shared_ptr result = shared_ptr( new DaylightDetectorTileEntity() ); + TileEntity::clone(result); + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/DaylightDetectorTileEntity.h b/Minecraft.World/DaylightDetectorTileEntity.h new file mode 100644 index 00000000..b4036f8e --- /dev/null +++ b/Minecraft.World/DaylightDetectorTileEntity.h @@ -0,0 +1,16 @@ +#pragma once + +class DaylightDetectorTileEntity : public TileEntity +{ +public: + eINSTANCEOF GetType() { return eTYPE_DAYLIGHTDETECTORTILEENTITY; } + static TileEntity *create() { return new DaylightDetectorTileEntity(); } + + // 4J Added + virtual shared_ptr clone(); + +public: + DaylightDetectorTileEntity(); + + void tick(); +}; \ No newline at end of file diff --git a/Minecraft.World/DeadBushFeature.cpp b/Minecraft.World/DeadBushFeature.cpp index e27a36c6..23bdd488 100644 --- a/Minecraft.World/DeadBushFeature.cpp +++ b/Minecraft.World/DeadBushFeature.cpp @@ -10,24 +10,24 @@ DeadBushFeature::DeadBushFeature(int tile) bool DeadBushFeature::place(Level *level, Random *random, int x, int y, int z) { - int t = 0; - while (((t = level->getTile(x, y, z)) == 0 || t == Tile::leaves_Id) && y > 0) - y--; + int t = 0; + while (((t = level->getTile(x, y, z)) == 0 || t == Tile::leaves_Id) && y > 0) + y--; - for (int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { - int x2 = x + random->nextInt(8) - random->nextInt(8); - int y2 = y + random->nextInt(4) - random->nextInt(4); - int z2 = z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(x2, y2, z2) ) + int x2 = x + random->nextInt(8) - random->nextInt(8); + int y2 = y + random->nextInt(4) - random->nextInt(4); + int z2 = z + random->nextInt(8) - random->nextInt(8); + if (level->isEmptyTile(x2, y2, z2) ) { - if (Tile::tiles[tile]->canSurvive(level, x2, y2, z2)) + if (Tile::tiles[tile]->canSurvive(level, x2, y2, z2)) { - level->setTileNoUpdate(x2, y2, z2, tile); - } - } - } + level->setTileAndData(x2, y2, z2, tile, 0, Tile::UPDATE_CLIENTS); + } + } + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/DefaultDispenseItemBehavior.cpp b/Minecraft.World/DefaultDispenseItemBehavior.cpp new file mode 100644 index 00000000..8fd13282 --- /dev/null +++ b/Minecraft.World/DefaultDispenseItemBehavior.cpp @@ -0,0 +1,82 @@ +#include "stdafx.h" +#include "net.minecraft.h" +#include "net.minecraft.core.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.entity.item.h" +#include "DefaultDispenseItemBehavior.h" + +shared_ptr DefaultDispenseItemBehavior::dispense(BlockSource *source, shared_ptr dispensed) +{ + eOUTCOME outcome = DISPENCED_ITEM; + shared_ptr result = execute(source, dispensed, outcome); + + playSound(source, outcome); + playAnimation(source, DispenserTile::getFacing(source->getData()), outcome); + + return result; +} + +shared_ptr DefaultDispenseItemBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + Position *position = DispenserTile::getDispensePosition(source); + + shared_ptr itemInstance = dispensed->remove(1); + + spawnItem(source->getWorld(), itemInstance, 6, facing, position); + + delete position; + + outcome = DISPENCED_ITEM; + return dispensed; +} + +void DefaultDispenseItemBehavior::spawnItem(Level *world, shared_ptr item, int accuracy, FacingEnum *facing, Position *position) +{ + double spawnX = position->getX(); + double spawnY = position->getY(); + double spawnZ = position->getZ(); + + shared_ptr itemEntity = shared_ptr(new ItemEntity(world, spawnX, spawnY - 0.3, spawnZ, item)); + + double pow = world->random->nextDouble() * 0.1 + 0.2; + itemEntity->xd = facing->getStepX() * pow; + itemEntity->yd = .2f; + itemEntity->zd = facing->getStepZ() * pow; + + itemEntity->xd += world->random->nextGaussian() * 0.0075f * accuracy; + itemEntity->yd += world->random->nextGaussian() * 0.0075f * accuracy; + itemEntity->zd += world->random->nextGaussian() * 0.0075f * accuracy; + + world->addEntity(itemEntity); +} + +void DefaultDispenseItemBehavior::playSound(BlockSource *source, eOUTCOME outcome) +{ + if (outcome != LEFT_ITEM) + { + source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + } + else + { + // some negative sound effect? + source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK_FAIL, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + } +} + +void DefaultDispenseItemBehavior::playAnimation(BlockSource *source, FacingEnum *facing, eOUTCOME outcome) +{ + if (outcome != LEFT_ITEM) + { + source->getWorld()->levelEvent(LevelEvent::PARTICLES_SHOOT, source->getBlockX(), source->getBlockY(), source->getBlockZ(), getLevelEventDataFrom(facing)); + } + else + { + } +} + +int DefaultDispenseItemBehavior::getLevelEventDataFrom(FacingEnum *facing) +{ + return facing->getStepX() + 1 + (facing->getStepZ() + 1) * 3; +} \ No newline at end of file diff --git a/Minecraft.World/DefaultDispenseItemBehavior.h b/Minecraft.World/DefaultDispenseItemBehavior.h new file mode 100644 index 00000000..a680f2a4 --- /dev/null +++ b/Minecraft.World/DefaultDispenseItemBehavior.h @@ -0,0 +1,40 @@ +#pragma once +#include "DispenseItemBehavior.h" + +class FacingEnum; +class Position; + +class DefaultDispenseItemBehavior : public DispenseItemBehavior +{ +protected: + enum eOUTCOME + { + // Item has special behaviour that was executed successfully. + ACTIVATED_ITEM = 0, + + // Item was dispenced onto the ground as a pickup. + DISPENCED_ITEM = 1, + + // Execution failed, the item was left unaffected. + LEFT_ITEM = 2, + }; + +public: + DefaultDispenseItemBehavior() {}; + virtual ~DefaultDispenseItemBehavior() {}; + virtual shared_ptr dispense(BlockSource *source, shared_ptr dispensed); + +protected: + // 4J-JEV: Added value used to play FAILED sound effect upon reaching spawn limits. + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); + +public: + static void spawnItem(Level *world, shared_ptr item, int accuracy, FacingEnum *facing, Position *position); + +protected: + virtual void playSound(BlockSource *source, eOUTCOME outcome); + virtual void playAnimation(BlockSource *source, FacingEnum *facing, eOUTCOME outcome); + +private: + virtual int getLevelEventDataFrom(FacingEnum *facing); +}; \ No newline at end of file diff --git a/Minecraft.World/DefaultGameModeCommand.cpp b/Minecraft.World/DefaultGameModeCommand.cpp index 529733f7..b0a58176 100644 --- a/Minecraft.World/DefaultGameModeCommand.cpp +++ b/Minecraft.World/DefaultGameModeCommand.cpp @@ -9,18 +9,27 @@ EGameCommand DefaultGameModeCommand::getId() void DefaultGameModeCommand::execute(shared_ptr source, byteArray commandData) { - //if (args.length > 0) - //{ + //if (args.length > 0) { // GameType newMode = getModeForString(source, args[0]); // doSetGameType(newMode); - // String modeName = I18n.get("gameMode." + newMode.getName()); - // logAdminAction(source, "commands.defaultgamemode.success", modeName); + // logAdminAction(source, "commands.defaultgamemode.success", ChatMessageComponent.forTranslation("gameMode." + newMode.getName())); + // return; //} + + //throw new UsageException("commands.defaultgamemode.usage"); } void DefaultGameModeCommand::doSetGameType(GameType *newGameType) { - //MinecraftServer::getInstance()->setDefaultGameMode(newGameType); + //MinecraftServer minecraftServer = MinecraftServer.getInstance(); + //minecraftServer.setDefaultGameMode(newGameType); + + //if (minecraftServer.getForceGameType()) { + // for (ServerPlayer player : MinecraftServer.getInstance().getPlayers().players) { + // player.setGameMode(newGameType); + // player.fallDistance = 0; // reset falldistance so flying people do not die :P + // } + //} } \ No newline at end of file diff --git a/Minecraft.World/DefendVillageTargetGoal.cpp b/Minecraft.World/DefendVillageTargetGoal.cpp index ad6b3fd8..6ed6af53 100644 --- a/Minecraft.World/DefendVillageTargetGoal.cpp +++ b/Minecraft.World/DefendVillageTargetGoal.cpp @@ -3,7 +3,7 @@ #include "net.minecraft.world.entity.animal.h" #include "DefendVillageTargetGoal.h" -DefendVillageTargetGoal::DefendVillageTargetGoal(VillagerGolem *golem) : TargetGoal(golem, 16, false, true) +DefendVillageTargetGoal::DefendVillageTargetGoal(VillagerGolem *golem) : TargetGoal(golem, false, true) { this->golem = golem; setRequiredControlFlags(TargetGoal::TargetFlag); @@ -13,8 +13,22 @@ bool DefendVillageTargetGoal::canUse() { shared_ptr village = golem->getVillage(); if (village == NULL) return false; - potentialTarget = weak_ptr(village->getClosestAggressor(dynamic_pointer_cast(golem->shared_from_this()))); - return canAttack(potentialTarget.lock(), false); + potentialTarget = weak_ptr(village->getClosestAggressor(dynamic_pointer_cast(golem->shared_from_this()))); + shared_ptr potTarget = potentialTarget.lock(); + if (!canAttack(potTarget, false)) + { + // look for bad players + if (mob->getRandom()->nextInt(20) == 0) + { + potentialTarget = village->getClosestBadStandingPlayer(dynamic_pointer_cast(golem->shared_from_this() )); + return canAttack(potTarget, false); + } + return false; + } + else + { + return true; + } } void DefendVillageTargetGoal::start() diff --git a/Minecraft.World/DefendVillageTargetGoal.h b/Minecraft.World/DefendVillageTargetGoal.h index d74d95b0..9956ae0a 100644 --- a/Minecraft.World/DefendVillageTargetGoal.h +++ b/Minecraft.World/DefendVillageTargetGoal.h @@ -8,7 +8,7 @@ class DefendVillageTargetGoal : public TargetGoal { private: VillagerGolem *golem; // Owner of this goal - weak_ptr potentialTarget; + weak_ptr potentialTarget; public: DefendVillageTargetGoal(VillagerGolem *golem); diff --git a/Minecraft.World/DelayedRelease.cpp b/Minecraft.World/DelayedRelease.cpp index ebd0398f..ce8e1188 100644 --- a/Minecraft.World/DelayedRelease.cpp +++ b/Minecraft.World/DelayedRelease.cpp @@ -27,7 +27,7 @@ void DelayedRelease::tick() } } -bool DelayedRelease::hurt(DamageSource *source, int damage) +bool DelayedRelease::hurt(DamageSource *source, float damage) { return false; } diff --git a/Minecraft.World/DelayedRelease.h b/Minecraft.World/DelayedRelease.h index aaccc843..babef9cf 100644 --- a/Minecraft.World/DelayedRelease.h +++ b/Minecraft.World/DelayedRelease.h @@ -21,7 +21,7 @@ protected: public: virtual void tick(); - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); protected: virtual void defineSynchedData(); diff --git a/Minecraft.World/DerivedLevelData.cpp b/Minecraft.World/DerivedLevelData.cpp index 71c4d87b..198b8c76 100644 --- a/Minecraft.World/DerivedLevelData.cpp +++ b/Minecraft.World/DerivedLevelData.cpp @@ -43,9 +43,14 @@ int DerivedLevelData::getZSpawn() return wrapped->getZSpawn(); } -__int64 DerivedLevelData::getTime() +__int64 DerivedLevelData::getGameTime() { - return wrapped->getTime(); + return wrapped->getGameTime(); +} + +__int64 DerivedLevelData::getDayTime() +{ + return wrapped->getDayTime(); } __int64 DerivedLevelData::getSizeOnDisk() @@ -114,7 +119,11 @@ void DerivedLevelData::setZSpawn(int zSpawn) { } -void DerivedLevelData::setTime(__int64 time) +void DerivedLevelData::setGameTime(__int64 time) +{ +} + +void DerivedLevelData::setDayTime(__int64 time) { } @@ -198,6 +207,11 @@ void DerivedLevelData::setInitialized(bool initialized) { } +GameRules *DerivedLevelData::getGameRules() +{ + return wrapped->getGameRules(); +} + int DerivedLevelData::getXZSize() { return wrapped->getXZSize(); diff --git a/Minecraft.World/DerivedLevelData.h b/Minecraft.World/DerivedLevelData.h index a39f7d04..ad612cc9 100644 --- a/Minecraft.World/DerivedLevelData.h +++ b/Minecraft.World/DerivedLevelData.h @@ -2,6 +2,8 @@ #include "LevelData.h" +class GameRules; + class DerivedLevelData : public LevelData { private: @@ -20,7 +22,8 @@ public: int getXSpawn(); int getYSpawn(); int getZSpawn(); - __int64 getTime(); + __int64 getGameTime(); + __int64 getDayTime(); __int64 getSizeOnDisk(); CompoundTag *getLoadedPlayerTag(); wstring getLevelName(); @@ -35,7 +38,8 @@ public: void setXSpawn(int xSpawn); void setYSpawn(int ySpawn); void setZSpawn(int zSpawn); - void setTime(__int64 time); + void setGameTime(__int64 time); + void setDayTime(__int64 time); void setSizeOnDisk(__int64 sizeOnDisk); void setLoadedPlayerTag(CompoundTag *loadedPlayerTag); void setDimension(int dimension); @@ -55,6 +59,7 @@ public: void setAllowCommands(bool allowCommands); bool isInitialized(); void setInitialized(bool initialized); + GameRules *getGameRules(); int getXZSize(); // 4J Added int getHellScale(); // 4J Addded }; diff --git a/Minecraft.World/DesertBiome.cpp b/Minecraft.World/DesertBiome.cpp index 6928861e..c36b0908 100644 --- a/Minecraft.World/DesertBiome.cpp +++ b/Minecraft.World/DesertBiome.cpp @@ -10,8 +10,8 @@ DesertBiome::DesertBiome(int id) : Biome(id) friendlies.clear(); friendlies_chicken.clear(); // 4J added friendlies_wolf.clear(); // 4J added - this->topMaterial = (BYTE) Tile::sand_Id; - this->material = (BYTE) Tile::sand_Id; + topMaterial = (BYTE) Tile::sand_Id; + material = (BYTE) Tile::sand_Id; decorator->treeCount = -999; decorator->deadBushCount = 2; diff --git a/Minecraft.World/DesertWellFeature.cpp b/Minecraft.World/DesertWellFeature.cpp index c89006bf..62e19bb8 100644 --- a/Minecraft.World/DesertWellFeature.cpp +++ b/Minecraft.World/DesertWellFeature.cpp @@ -33,17 +33,17 @@ bool DesertWellFeature::place(Level *level, Random *random, int x, int y, int z) { for (int oz = -2; oz <= 2; oz++) { - level->setTileNoUpdate(x + ox, y + oy, z + oz, Tile::sandStone_Id); + level->setTileAndData(x + ox, y + oy, z + oz, Tile::sandStone_Id, 0, Tile::UPDATE_CLIENTS); } } } // place water cross - level->setTileNoUpdate(x, y, z, Tile::water_Id); - level->setTileNoUpdate(x - 1, y, z, Tile::water_Id); - level->setTileNoUpdate(x + 1, y, z, Tile::water_Id); - level->setTileNoUpdate(x, y, z - 1, Tile::water_Id); - level->setTileNoUpdate(x, y, z + 1, Tile::water_Id); + level->setTileAndData(x, y, z, Tile::water_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x - 1, y, z, Tile::water_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + 1, y, z, Tile::water_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y, z - 1, Tile::water_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y, z + 1, Tile::water_Id, 0, Tile::UPDATE_CLIENTS); // place "fence" for (int ox = -2; ox <= 2; ox++) @@ -52,14 +52,14 @@ bool DesertWellFeature::place(Level *level, Random *random, int x, int y, int z) { if (ox == -2 || ox == 2 || oz == -2 || oz == 2) { - level->setTileNoUpdate(x + ox, y + 1, z + oz, Tile::sandStone_Id); + level->setTileAndData(x + ox, y + 1, z + oz, Tile::sandStone_Id, 0, Tile::UPDATE_CLIENTS); } } } - level->setTileAndDataNoUpdate(x + 2, y + 1, z, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB); - level->setTileAndDataNoUpdate(x - 2, y + 1, z, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB); - level->setTileAndDataNoUpdate(x, y + 1, z + 2, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB); - level->setTileAndDataNoUpdate(x, y + 1, z - 2, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB); + level->setTileAndData(x + 2, y + 1, z, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB, Tile::UPDATE_CLIENTS); + level->setTileAndData(x - 2, y + 1, z, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y + 1, z + 2, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y + 1, z - 2, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB, Tile::UPDATE_CLIENTS); // place roof for (int ox = -1; ox <= 1; ox++) @@ -68,11 +68,11 @@ bool DesertWellFeature::place(Level *level, Random *random, int x, int y, int z) { if (ox == 0 && oz == 0) { - level->setTileNoUpdate(x + ox, y + 4, z + oz, Tile::sandStone_Id); + level->setTileAndData(x + ox, y + 4, z + oz, Tile::sandStone_Id, 0, Tile::UPDATE_CLIENTS); } else { - level->setTileAndDataNoUpdate(x + ox, y + 4, z + oz, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB); + level->setTileAndData(x + ox, y + 4, z + oz, Tile::stoneSlabHalf_Id, StoneSlabTile::SAND_SLAB, Tile::UPDATE_CLIENTS); } } } @@ -80,10 +80,10 @@ bool DesertWellFeature::place(Level *level, Random *random, int x, int y, int z) // place pillars for (int oy = 1; oy <= 3; oy++) { - level->setTileNoUpdate(x - 1, y + oy, z - 1, Tile::sandStone_Id); - level->setTileNoUpdate(x - 1, y + oy, z + 1, Tile::sandStone_Id); - level->setTileNoUpdate(x + 1, y + oy, z - 1, Tile::sandStone_Id); - level->setTileNoUpdate(x + 1, y + oy, z + 1, Tile::sandStone_Id); + level->setTileAndData(x - 1, y + oy, z - 1, Tile::sandStone_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x - 1, y + oy, z + 1, Tile::sandStone_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + 1, y + oy, z - 1, Tile::sandStone_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + 1, y + oy, z + 1, Tile::sandStone_Id, 0, Tile::UPDATE_CLIENTS); } return true; diff --git a/Minecraft.World/DetectorRailTile.cpp b/Minecraft.World/DetectorRailTile.cpp index e01ec259..16265ceb 100644 --- a/Minecraft.World/DetectorRailTile.cpp +++ b/Minecraft.World/DetectorRailTile.cpp @@ -1,5 +1,7 @@ #include "stdafx.h" +#include "net.minecraft.world.inventory.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" #include "net.minecraft.world.entity.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.phys.h" @@ -7,13 +9,13 @@ #include "DetectorRailTile.h" #include "net.minecraft.h" -DetectorRailTile::DetectorRailTile(int id) : RailTile(id, true) +DetectorRailTile::DetectorRailTile(int id) : BaseRailTile(id, true) { setTicking(true); icons = NULL; } -int DetectorRailTile::getTickDelay() +int DetectorRailTile::getTickDelay(Level *level) { return 20; } @@ -25,79 +27,110 @@ bool DetectorRailTile::isSignalSource() void DetectorRailTile::entityInside(Level *level, int x, int y, int z, shared_ptr entity) { - if (level->isClientSide) + if (level->isClientSide) { - return; - } + return; + } - int data = level->getData(x, y, z); - if ((data & RAIL_DATA_BIT) != 0) + int data = level->getData(x, y, z); + if ((data & RAIL_DATA_BIT) != 0) { - return; - } + return; + } - checkPressed(level, x, y, z, data); + checkPressed(level, x, y, z, data); } void DetectorRailTile::tick(Level *level, int x, int y, int z, Random *random) { - if (level->isClientSide) return; + if (level->isClientSide) return; - int data = level->getData(x, y, z); - if ((data & RAIL_DATA_BIT) == 0) + int data = level->getData(x, y, z); + if ((data & RAIL_DATA_BIT) == 0) { - return; - } + return; + } - checkPressed(level, x, y, z, data); + checkPressed(level, x, y, z, data); } -bool DetectorRailTile::getSignal(LevelSource *level, int x, int y, int z, int dir) +int DetectorRailTile::getSignal(LevelSource *level, int x, int y, int z, int dir) { - return (level->getData(x, y, z) & RAIL_DATA_BIT) != 0; + return (level->getData(x, y, z) & RAIL_DATA_BIT) != 0 ? Redstone::SIGNAL_MAX : Redstone::SIGNAL_NONE; } -bool DetectorRailTile::getDirectSignal(Level *level, int x, int y, int z, int facing) +int DetectorRailTile::getDirectSignal(LevelSource *level, int x, int y, int z, int facing) { - if ((level->getData(x, y, z) & RAIL_DATA_BIT) == 0) return false; - return (facing == Facing::UP); + if ((level->getData(x, y, z) & RAIL_DATA_BIT) == 0) return Redstone::SIGNAL_NONE; + return (facing == Facing::UP) ? Redstone::SIGNAL_MAX : Redstone::SIGNAL_NONE; } void DetectorRailTile::checkPressed(Level *level, int x, int y, int z, int currentData) { - bool wasPressed = (currentData & RAIL_DATA_BIT) != 0; - bool shouldBePressed = false; + bool wasPressed = (currentData & RAIL_DATA_BIT) != 0; + bool shouldBePressed = false; - float b = 2 / 16.0f; + float b = 2 / 16.0f; vector > *entities = level->getEntitiesOfClass(typeid(Minecart), AABB::newTemp(x + b, y, z + b, x + 1 - b, y + 1 - b, z + 1 - b)); - if (!entities->empty()) + if (!entities->empty()) { - shouldBePressed = true; - } + shouldBePressed = true; + } - if (shouldBePressed && !wasPressed) + if (shouldBePressed && !wasPressed) { - level->setData(x, y, z, currentData | RAIL_DATA_BIT); - level->updateNeighborsAt(x, y, z, id); - level->updateNeighborsAt(x, y - 1, z, id); - level->setTilesDirty(x, y, z, x, y, z); - } - if (!shouldBePressed && wasPressed) + level->setData(x, y, z, currentData | RAIL_DATA_BIT, Tile::UPDATE_ALL); + level->updateNeighborsAt(x, y, z, id); + level->updateNeighborsAt(x, y - 1, z, id); + level->setTilesDirty(x, y, z, x, y, z); + } + if (!shouldBePressed && wasPressed) { - level->setData(x, y, z, currentData & RAIL_DIRECTION_MASK); - level->updateNeighborsAt(x, y, z, id); - level->updateNeighborsAt(x, y - 1, z, id); - level->setTilesDirty(x, y, z, x, y, z); - } + level->setData(x, y, z, currentData & RAIL_DIRECTION_MASK, Tile::UPDATE_ALL); + level->updateNeighborsAt(x, y, z, id); + level->updateNeighborsAt(x, y - 1, z, id); + level->setTilesDirty(x, y, z, x, y, z); + } - if (shouldBePressed) + if (shouldBePressed) { - level->addToTickNextTick(x, y, z, id, getTickDelay()); - } + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); + } + + level->updateNeighbourForOutputSignal(x, y, z, id); delete entities; } +void DetectorRailTile::onPlace(Level *level, int x, int y, int z) +{ + BaseRailTile::onPlace(level, x, y, z); + checkPressed(level, x, y, z, level->getData(x, y, z)); +} + +bool DetectorRailTile::hasAnalogOutputSignal() +{ + return true; +} + +int DetectorRailTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + if ((level->getData(x, y, z) & RAIL_DATA_BIT) > 0) + { + float b = 2 / 16.0f; + vector > *entities = level->getEntitiesOfClass(typeid(Minecart), AABB::newTemp(x + b, y, z + b, x + 1 - b, y + 1 - b, z + 1 - b), EntitySelector::CONTAINER_ENTITY_SELECTOR); + + if (entities->size() > 0) + { + shared_ptr out = entities->at(0); + delete entities; + return AbstractContainerMenu::getRedstoneSignalFromContainer(dynamic_pointer_cast(out)); + } + } + + return Redstone::SIGNAL_NONE; +} + void DetectorRailTile::registerIcons(IconRegister *iconRegister) { icons = new Icon*[2]; diff --git a/Minecraft.World/DetectorRailTile.h b/Minecraft.World/DetectorRailTile.h index dd0e6374..4e919912 100644 --- a/Minecraft.World/DetectorRailTile.h +++ b/Minecraft.World/DetectorRailTile.h @@ -1,12 +1,12 @@ #pragma once -#include "RailTile.h" +#include "BaseRailTile.h" class Entity; class Random; class Level; class ChunkRebuildData; -class DetectorRailTile : public RailTile +class DetectorRailTile : public BaseRailTile { friend class ChunkRebuildData; private: @@ -14,12 +14,16 @@ private: public: DetectorRailTile(int id); - virtual int getTickDelay(); + virtual int getTickDelay(Level *level); virtual bool isSignalSource(); virtual void entityInside(Level *level, int x, int y, int z, shared_ptr entity); virtual void tick(Level *level, int x, int y, int z, Random *random); - virtual bool getSignal(LevelSource *level, int x, int y, int z, int dir); - virtual bool getDirectSignal(Level *level, int x, int y, int z, int facing); + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); + virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int facing); + virtual void onPlace(Level *level, int x, int y, int z); + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); + private: virtual void checkPressed(Level *level, int x, int y, int z, int currentData); public: diff --git a/Minecraft.World/DiggerItem.cpp b/Minecraft.World/DiggerItem.cpp index 144b1a11..25310806 100644 --- a/Minecraft.World/DiggerItem.cpp +++ b/Minecraft.World/DiggerItem.cpp @@ -1,10 +1,12 @@ #include "stdafx.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.level.tile.h" #include "DiggerItem.h" -DiggerItem::DiggerItem(int id, int attackDamage, const Tier *tier, TileArray *tiles) : Item( id ), tier( tier ) +DiggerItem::DiggerItem(int id, float attackDamage, const Tier *tier, TileArray *tiles) : Item( id ), tier( tier ) { //this->tier = tier; this->tiles = tiles; @@ -21,24 +23,19 @@ float DiggerItem::getDestroySpeed(shared_ptr itemInstance, Tile *t return 1; } -bool DiggerItem::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) +bool DiggerItem::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) { - itemInstance->hurt(2, attacker); + itemInstance->hurtAndBreak(2, attacker); return true; } -bool DiggerItem::mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner) +bool DiggerItem::mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner) { // Don't damage tools if the tile can be destroyed in one hit. - if (Tile::tiles[tile]->getDestroySpeed(level, x, y, z) != 0.0) itemInstance->hurt(1, owner); + if (Tile::tiles[tile]->getDestroySpeed(level, x, y, z) != 0.0) itemInstance->hurtAndBreak(1, owner); return true; } -int DiggerItem::getAttackDamage(shared_ptr entity) -{ - return attackDamage; -} - bool DiggerItem::isHandEquipped() { return true; @@ -61,4 +58,13 @@ bool DiggerItem::isValidRepairItem(shared_ptr source, shared_ptrgetId()] = new AttributeModifier(eModifierId_ITEM_BASEDAMAGE, attackDamage, AttributeModifier::OPERATION_ADDITION); + + return result; } \ No newline at end of file diff --git a/Minecraft.World/DiggerItem.h b/Minecraft.World/DiggerItem.h index 4a4eeb07..fd148c2b 100644 --- a/Minecraft.World/DiggerItem.h +++ b/Minecraft.World/DiggerItem.h @@ -11,21 +11,21 @@ private: protected: float speed; private: - int attackDamage; + float attackDamage; protected: const Tier *tier; - DiggerItem(int id, int attackDamage, const Tier *tier, TileArray *tiles); + DiggerItem(int id, float attackDamage, const Tier *tier, TileArray *tiles); public: virtual float getDestroySpeed(shared_ptr itemInstance, Tile *tile); - virtual bool hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker); - virtual bool mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner); - virtual int getAttackDamage(shared_ptr entity); + virtual bool hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker); + virtual bool mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner); virtual bool isHandEquipped(); virtual int getEnchantmentValue(); const Tier *getTier(); bool isValidRepairItem(shared_ptr source, shared_ptr repairItem); + virtual attrAttrModMap *getDefaultAttributeModifiers(); }; \ No newline at end of file diff --git a/Minecraft.World/Dimension.cpp b/Minecraft.World/Dimension.cpp index 35e66698..697da010 100644 --- a/Minecraft.World/Dimension.cpp +++ b/Minecraft.World/Dimension.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "net.minecraft.world.level.levelgen.flat.h" #include "net.minecraft.world.level.levelgen.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.storage.h" @@ -13,42 +14,47 @@ #include "..\Minecraft.Client\Minecraft.h" #include "..\Minecraft.Client\Common\Colours\ColourTable.h" +const float Dimension::MOON_BRIGHTNESS_PER_PHASE[8] = {1.0f, 0.75f, 0.5f, 0.25f, 0, 0.25f, 0.5f, 0.75f}; + void Dimension::init(Level *level) { - this->level = level; - this->levelType = level->getLevelData()->getGenerator(); - init(); - updateLightRamp(); + this->level = level; + levelType = level->getLevelData()->getGenerator(); + levelTypeOptions = level->getLevelData()->getGeneratorOptions(); + init(); + updateLightRamp(); } void Dimension::updateLightRamp() { - float ambientLight = 0.00f; - for (int i = 0; i <= Level::MAX_BRIGHTNESS; i++) + float ambientLight = 0.00f; + for (int i = 0; i <= Level::MAX_BRIGHTNESS; i++) { - float v = (1 - i / (float) (Level::MAX_BRIGHTNESS)); - brightnessRamp[i] = ((1 - v) / (v * 3 + 1)) * (1 - ambientLight) + ambientLight; - } + float v = (1 - i / (float) (Level::MAX_BRIGHTNESS)); + brightnessRamp[i] = ((1 - v) / (v * 3 + 1)) * (1 - ambientLight) + ambientLight; + } } void Dimension::init() { #ifdef _OVERRIDE_HEIGHTMAP // 4J Stu - Added to enable overriding the heightmap from a loaded in data file - if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<getLevelData()->getGenerator() == LevelType::lvl_flat) - { - biomeSource = new FixedBiomeSource(Biome::plains, 0.5f, 0.5f); - } - else - { - biomeSource = new BiomeSource(level); - } + if (level->getLevelData()->getGenerator() == LevelType::lvl_flat) + { + FlatGeneratorInfo *generator = FlatGeneratorInfo::fromValue(level->getLevelData()->getGeneratorOptions()); + biomeSource = new FixedBiomeSource(Biome::biomes[generator->getBiome()], 0.5f, 0.5f); + delete generator; + } + else + { + biomeSource = new BiomeSource(level); + } } Dimension::Dimension() @@ -57,6 +63,7 @@ Dimension::Dimension() hasCeiling = false; brightnessRamp = new float[Level::MAX_BRIGHTNESS + 1]; id = 0; + levelTypeOptions = L""; } Dimension::~Dimension() @@ -71,20 +78,20 @@ ChunkSource *Dimension::createRandomLevelSource() const { #ifdef _OVERRIDE_HEIGHTMAP // 4J Stu - Added to enable overriding the heightmap from a loaded in data file - if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<getSeed(), level->getLevelData()->isGenerateMapFeatures()); } else #endif - if (levelType == LevelType::lvl_flat) - { - return new FlatLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures()); - } - else - { - return new RandomLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures()); - } + if (levelType == LevelType::lvl_flat) + { + return new FlatLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures()); + } + else + { + return new RandomLevelSource(level, level->getSeed(), level->getLevelData()->isGenerateMapFeatures()); + } } ChunkSource *Dimension::createFlatLevelSource() const @@ -99,28 +106,28 @@ ChunkStorage *Dimension::createStorage(File dir) bool Dimension::isValidSpawn(int x, int z) const { - int topTile = level->getTopTile(x, z); + int topTile = level->getTopTile(x, z); - if (topTile != Tile::grass_Id) return false; + if (topTile != Tile::grass_Id) return false; - return true; + return true; } float Dimension::getTimeOfDay(__int64 time, float a) const { - int dayStep = (int) (time % Level::TICKS_PER_DAY); - float td = (dayStep + a) / Level::TICKS_PER_DAY - 0.25f; - if (td < 0) td += 1; - if (td > 1) td -= 1; - float tdo = td; - td = 1 - (float) ((cos(td * PI) + 1) / 2); - td = tdo + (td - tdo) / 3.0f; - return td; + int dayStep = (int) (time % Level::TICKS_PER_DAY); + float td = (dayStep + a) / Level::TICKS_PER_DAY - 0.25f; + if (td < 0) td += 1; + if (td > 1) td -= 1; + float tdo = td; + td = 1 - (float) ((cos(td * PI) + 1) / 2); + td = tdo + (td - tdo) / 3.0f; + return td; } -int Dimension::getMoonPhase(__int64 time, float a) const +int Dimension::getMoonPhase(__int64 time) const { - return ((int) (time / Level::TICKS_PER_DAY)) % 8; + return ((int) (time / Level::TICKS_PER_DAY)) % 8; } bool Dimension::isNaturalDimension() @@ -136,42 +143,42 @@ float *Dimension::getSunriseColor(float td, float a) unsigned int clr2 = Minecraft::GetInstance()->getColourTable()->getColor( eMinecraftColour_Sky_Dawn_Bright ); // 0xFFE533 double r2 = ( (clr2>>16)&0xFF )/255.0f, g2 = ( (clr2>>8)&0xFF )/255.0, b2 = ( clr2&0xFF )/255.0; - float span = 0.4f; - float tt = Mth::cos(td * PI * 2) - 0.0f; - float mid = -0.0f; - if (tt >= mid - span && tt <= mid + span) + float span = 0.4f; + float tt = Mth::cos(td * PI * 2) - 0.0f; + float mid = -0.0f; + if (tt >= mid - span && tt <= mid + span) { - float aa = ((tt - mid) / span) * 0.5f + 0.5f; - float mix = 1 - (((1 - sin(aa * PI))) * 0.99f); - mix = mix * mix; - //sunriseCol[0] = (aa * 0.3f + 0.7f); - //sunriseCol[1] = (aa * aa * 0.7f + 0.2f); - //sunriseCol[2] = (aa * aa * 0.0f + 0.2f); + float aa = ((tt - mid) / span) * 0.5f + 0.5f; + float mix = 1 - (((1 - sin(aa * PI))) * 0.99f); + mix = mix * mix; + //sunriseCol[0] = (aa * 0.3f + 0.7f); + //sunriseCol[1] = (aa * aa * 0.7f + 0.2f); + //sunriseCol[2] = (aa * aa * 0.0f + 0.2f); sunriseCol[0] = (aa * (r2-r1) + r1); sunriseCol[1] = (aa * (g2-g1) + g1); sunriseCol[2] = (aa * (b2-b1) + b1); - sunriseCol[3] = mix; - return sunriseCol; - } + sunriseCol[3] = mix; + return sunriseCol; + } - return NULL; + return NULL; } Vec3 *Dimension::getFogColor(float td, float a) const { - float br = Mth::cos(td * PI * 2) * 2 + 0.5f; - if (br < 0.0f) br = 0.0f; - if (br > 1.0f) br = 1.0f; - + float br = Mth::cos(td * PI * 2) * 2 + 0.5f; + if (br < 0.0f) br = 0.0f; + if (br > 1.0f) br = 1.0f; + unsigned int baseFogColour = Minecraft::GetInstance()->getColourTable()->getColor( eMinecraftColour_Default_Fog_Colour ); - float r = ((baseFogColour >> 16) & 0xff) / 255.0f; - float g = ((baseFogColour >> 8) & 0xff) / 255.0f; - float b = ((baseFogColour) & 0xff) / 255.0f; - r *= br * 0.94f + 0.06f; - g *= br * 0.94f + 0.06f; - b *= br * 0.91f + 0.09f; + float r = ((baseFogColour >> 16) & 0xff) / 255.0f; + float g = ((baseFogColour >> 8) & 0xff) / 255.0f; + float b = ((baseFogColour) & 0xff) / 255.0f; + r *= br * 0.94f + 0.06f; + g *= br * 0.94f + 0.06f; + b *= br * 0.91f + 0.09f; - return Vec3::newTemp(r, g, b); + return Vec3::newTemp(r, g, b); } bool Dimension::mayRespawn() const @@ -181,11 +188,11 @@ bool Dimension::mayRespawn() const Dimension *Dimension::getNew(int id) { - if (id == -1) return new HellDimension(); - if (id == 0) return new NormalDimension(); - if (id == 1) return new TheEndDimension(); + if (id == -1) return new HellDimension(); + if (id == 0) return new NormalDimension(); + if (id == 1) return new TheEndDimension(); - return NULL; + return NULL; } float Dimension::getCloudHeight() diff --git a/Minecraft.World/Dimension.h b/Minecraft.World/Dimension.h index 36df385e..5cccd68b 100644 --- a/Minecraft.World/Dimension.h +++ b/Minecraft.World/Dimension.h @@ -12,44 +12,47 @@ class LevelType; class Dimension { public: - Level *level; + static const float MOON_BRIGHTNESS_PER_PHASE[8]; + + Level *level; LevelType *levelType; - BiomeSource *biomeSource; - bool ultraWarm ; - bool hasCeiling; - float *brightnessRamp; - int id; + wstring levelTypeOptions; + BiomeSource *biomeSource; + bool ultraWarm ; + bool hasCeiling; + float *brightnessRamp; + int id; - virtual void init(Level *level); + virtual void init(Level *level); protected: - virtual void updateLightRamp(); - virtual void init(); + virtual void updateLightRamp(); + virtual void init(); public: Dimension(); ~Dimension(); virtual ChunkSource *createRandomLevelSource() const; virtual ChunkSource *createFlatLevelSource() const; - virtual ChunkStorage *createStorage(File dir); + virtual ChunkStorage *createStorage(File dir); - virtual bool isValidSpawn(int x, int z) const; + virtual bool isValidSpawn(int x, int z) const; - virtual float getTimeOfDay(__int64 time, float a) const; - virtual int getMoonPhase(__int64 time, float a) const; + virtual float getTimeOfDay(__int64 time, float a) const; + virtual int getMoonPhase(__int64 time) const; virtual bool isNaturalDimension(); private: - static const int fogColor = 0xc0d8ff; + static const int fogColor = 0xc0d8ff; - float sunriseCol[4]; + float sunriseCol[4]; public: - virtual float *getSunriseColor(float td, float a); - virtual Vec3 *getFogColor(float td, float a) const; - virtual bool mayRespawn() const; - static Dimension *getNew(int id); - virtual float getCloudHeight(); - virtual bool hasGround(); + virtual float *getSunriseColor(float td, float a); + virtual Vec3 *getFogColor(float td, float a) const; + virtual bool mayRespawn() const; + static Dimension *getNew(int id); + virtual float getCloudHeight(); + virtual bool hasGround(); virtual Pos *getSpawnPos(); int getSpawnYPosition(); diff --git a/Minecraft.World/DiodeTile.cpp b/Minecraft.World/DiodeTile.cpp index c28778d3..e5bbfede 100644 --- a/Minecraft.World/DiodeTile.cpp +++ b/Minecraft.World/DiodeTile.cpp @@ -1,14 +1,13 @@ #include "stdafx.h" #include "net.minecraft.h" +#include "net.minecraft.world.level.redstone.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.entity.h" #include "net.minecraft.world.h" #include "DiodeTile.h" -const double DiodeTile::DELAY_RENDER_OFFSETS[4] = { -1.0f / 16.0f, 1.0f / 16.0f, 3.0f / 16.0f, 5.0f / 16.0f }; -const int DiodeTile::DELAYS[4] = { 1, 2, 3, 4 }; - DiodeTile::DiodeTile(int id, bool on) : DirectionalTile(id, Material::decoration,isSolidRender()) { this->on = on; @@ -47,20 +46,22 @@ bool DiodeTile::canSurvive(Level *level, int x, int y, int z) void DiodeTile::tick(Level *level, int x, int y, int z, Random *random) { int data = level->getData(x, y, z); - bool sourceOn = getSourceSignal(level, x, y, z, data); - if (on && !sourceOn) - { - level->setTileAndData(x, y, z, Tile::diode_off_Id, data); - } - else if (!on) + if (!isLocked(level, x, y, z, data)) { - // when off-diodes are ticked, they always turn on for one tick and - // then off again if necessary - level->setTileAndData(x, y, z, Tile::diode_on_Id, data); - if (!sourceOn) + bool sourceOn = shouldTurnOn(level, x, y, z, data); + if (on && !sourceOn) + { + level->setTileAndData(x, y, z, getOffTile()->id, data, Tile::UPDATE_CLIENTS); + } + else if (!on) { - int delay = (data & DELAY_MASK) >> DELAY_SHIFT; - level->addToTickNextTick(x, y, z, Tile::diode_on_Id, DELAYS[delay] * 2); + // when off-diodes are ticked, they always turn on for one tick and + // then off again if necessary + level->setTileAndData(x, y, z, getOnTile()->id, data, Tile::UPDATE_CLIENTS); + if (!sourceOn) + { + level->addToTickNextTick(x, y, z, getOnTile()->id, getTurnOffDelay(data), -1); + } } } } @@ -72,9 +73,9 @@ Icon *DiodeTile::getTexture(int face, int data) { if (on) { - return Tile::notGate_on->getTexture(face); + return Tile::redstoneTorch_on->getTexture(face); } - return Tile::notGate_off->getTexture(face); + return Tile::redstoneTorch_off->getTexture(face); } if (face == Facing::UP) { @@ -84,11 +85,6 @@ Icon *DiodeTile::getTexture(int face, int data) return Tile::stoneSlab->getTexture(Facing::UP); } -void DiodeTile::registerIcons(IconRegister *iconRegister) -{ - icon = iconRegister->registerIcon(on ? L"repeater_lit" : L"repeater"); -} - bool DiodeTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { if (face == Facing::DOWN || face == Facing::UP) @@ -104,26 +100,32 @@ int DiodeTile::getRenderShape() return SHAPE_DIODE; } -bool DiodeTile::getDirectSignal(Level *level, int x, int y, int z, int dir) +bool DiodeTile::isOn(int data) +{ + return on; +} + +int DiodeTile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir) { return getSignal(level, x, y, z, dir); } -bool DiodeTile::getSignal(LevelSource *level, int x, int y, int z, int facing) +int DiodeTile::getSignal(LevelSource *level, int x, int y, int z, int facing) { - if (!on) + int data = level->getData(x, y, z); + if (!isOn(data)) { - return false; + return Redstone::SIGNAL_NONE; } - int dir = getDirection(level->getData(x, y, z)); + int dir = getDirection(data); - if (dir == Direction::SOUTH && facing == Facing::SOUTH) return true; - if (dir == Direction::WEST && facing == Facing::WEST) return true; - if (dir == Direction::NORTH && facing == Facing::NORTH) return true; - if (dir == Direction::EAST && facing == Facing::EAST) return true; + if (dir == Direction::SOUTH && facing == Facing::SOUTH) return getOutputSignal(level, x, y, z, data); + if (dir == Direction::WEST && facing == Facing::WEST) return getOutputSignal(level, x, y, z, data); + if (dir == Direction::NORTH && facing == Facing::NORTH) return getOutputSignal(level, x, y, z, data); + if (dir == Direction::EAST && facing == Facing::EAST) return getOutputSignal(level, x, y, z, data); - return false; + return Redstone::SIGNAL_NONE; } void DiodeTile::neighborChanged(Level *level, int x, int y, int z, int type) @@ -131,7 +133,7 @@ void DiodeTile::neighborChanged(Level *level, int x, int y, int z, int type) if (!canSurvive(level, x, y, z)) { this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); level->updateNeighborsAt(x + 1, y, z, id); level->updateNeighborsAt(x - 1, y, z, id); level->updateNeighborsAt(x, y, z + 1, id); @@ -141,49 +143,91 @@ void DiodeTile::neighborChanged(Level *level, int x, int y, int z, int type) return; } + checkTickOnNeighbor(level, x, y, z, type); +} + +void DiodeTile::checkTickOnNeighbor(Level *level, int x, int y, int z, int type) +{ int data = level->getData(x, y, z); - bool sourceOn = getSourceSignal(level, x, y, z, data); - int delay = (data & DELAY_MASK) >> DELAY_SHIFT; - if ( (on && !sourceOn) || (!on && sourceOn)) + if (!isLocked(level, x, y, z, data)) { - level->addToTickNextTick(x, y, z, id, DELAYS[delay] * 2); + bool sourceOn = shouldTurnOn(level, x, y, z, data); + if ((on && !sourceOn || !on && sourceOn) && !level->isTileToBeTickedAt(x, y, z, id)) + { + int prio = -1; + + // if the tile in front is a repeater, we prioritize this update + if (shouldPrioritize(level, x, y, z, data)) + { + prio = -3; + } + else if (on) + { + prio = -2; + } + + level->addToTickNextTick(x, y, z, id, getTurnOnDelay(data), prio); + } } } -bool DiodeTile::getSourceSignal(Level *level, int x, int y, int z, int data) +bool DiodeTile::isLocked(LevelSource *level, int x, int y, int z, int data) +{ + return false; +} + +bool DiodeTile::shouldTurnOn(Level *level, int x, int y, int z, int data) +{ + return getInputSignal(level, x, y, z, data) > Redstone::SIGNAL_NONE; +} + +int DiodeTile::getInputSignal(Level *level, int x, int y, int z, int data) { int dir = getDirection(data); + + int xx = x + Direction::STEP_X[dir]; + int zz = z + Direction::STEP_Z[dir]; + int input = level->getSignal(xx, y, zz, Direction::DIRECTION_FACING[dir]); + + if (input >= Redstone::SIGNAL_MAX) return input; + return max(input, level->getTile(xx, y, zz) == Tile::redStoneDust_Id ? level->getData(xx, y, zz) : Redstone::SIGNAL_NONE); +} + +int DiodeTile::getAlternateSignal(LevelSource *level, int x, int y, int z, int data) +{ + int dir = getDirection(data); + switch (dir) { - case Direction::SOUTH: - return level->getSignal(x, y, z + 1, Facing::SOUTH) || (level->getTile(x, y, z + 1) == Tile::redStoneDust_Id && level->getData(x, y, z + 1) > 0); - case Direction::NORTH: - return level->getSignal(x, y, z - 1, Facing::NORTH) || (level->getTile(x, y, z - 1) == Tile::redStoneDust_Id && level->getData(x, y, z - 1) > 0); - case Direction::EAST: - return level->getSignal(x + 1, y, z, Facing::EAST) || (level->getTile(x + 1, y, z) == Tile::redStoneDust_Id && level->getData(x + 1, y, z) > 0); - case Direction::WEST: - return level->getSignal(x - 1, y, z, Facing::WEST) || (level->getTile(x - 1, y, z) == Tile::redStoneDust_Id && level->getData(x - 1, y, z) > 0); + case Direction::SOUTH: + case Direction::NORTH: + return max(getAlternateSignalAt(level, x - 1, y, z, Facing::WEST), getAlternateSignalAt(level, x + 1, y, z, Facing::EAST)); + case Direction::EAST: + case Direction::WEST: + return max(getAlternateSignalAt(level, x, y, z + 1, Facing::SOUTH), getAlternateSignalAt(level, x, y, z - 1, Facing::NORTH)); } - return false; -} -// 4J-PB - Adding a TestUse for tooltip display -bool DiodeTile::TestUse() -{ - return true; + return Redstone::SIGNAL_NONE; } -bool DiodeTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param +int DiodeTile::getAlternateSignalAt(LevelSource *level, int x, int y, int z, int facing) { - if( soundOnly) return false; + int tile = level->getTile(x, y, z); - int data = level->getData(x, y, z); - int delay = (data & DELAY_MASK) >> DELAY_SHIFT; - delay = ((delay + 1) << DELAY_SHIFT) & DELAY_MASK; + if (isAlternateInput(tile)) + { + if (tile == Tile::redStoneDust_Id) + { + return level->getData(x, y, z); + } + else + { + return level->getDirectSignal(x, y, z, facing); + } + } - level->setData(x, y, z, delay | (data & DIRECTION_MASK)); - return true; + return Redstone::SIGNAL_NONE; } bool DiodeTile::isSignalSource() @@ -191,12 +235,12 @@ bool DiodeTile::isSignalSource() return true; } -void DiodeTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void DiodeTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { int dir = (((Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3) + 2) % 4; - level->setData(x, y, z, dir); + level->setData(x, y, z, dir, Tile::UPDATE_ALL); - bool sourceOn = getSourceSignal(level, x, y, z, dir); + bool sourceOn = shouldTurnOn(level, x, y, z, dir); if (sourceOn) { level->addToTickNextTick(x, y, z, id, 1); @@ -205,17 +249,37 @@ void DiodeTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr b void DiodeTile::onPlace(Level *level, int x, int y, int z) { - level->updateNeighborsAt(x + 1, y, z, id); - level->updateNeighborsAt(x - 1, y, z, id); - level->updateNeighborsAt(x, y, z + 1, id); - level->updateNeighborsAt(x, y, z - 1, id); - level->updateNeighborsAt(x, y - 1, z, id); - level->updateNeighborsAt(x, y + 1, z, id); + updateNeighborsInFront(level, x, y, z); +} + +void DiodeTile::updateNeighborsInFront(Level *level, int x, int y, int z) +{ + int dir = getDirection(level->getData(x, y, z)); + if (dir == Direction::WEST) + { + level->neighborChanged(x + 1, y, z, id); + level->updateNeighborsAtExceptFromFacing(x + 1, y, z, id, Facing::WEST); + } + if (dir == Direction::EAST) + { + level->neighborChanged(x - 1, y, z, id); + level->updateNeighborsAtExceptFromFacing(x - 1, y, z, id, Facing::EAST); + } + if (dir == Direction::NORTH) + { + level->neighborChanged(x, y, z + 1, id); + level->updateNeighborsAtExceptFromFacing(x, y, z + 1, id, Facing::NORTH); + } + if (dir == Direction::SOUTH) + { + level->neighborChanged(x, y, z - 1, id); + level->updateNeighborsAtExceptFromFacing(x, y, z - 1, id, Facing::SOUTH); + } } void DiodeTile::destroy(Level *level, int x, int y, int z, int data) { - if (on) + if (on) { level->updateNeighborsAt(x + 1, y, z, id); level->updateNeighborsAt(x - 1, y, z, id); @@ -224,7 +288,7 @@ void DiodeTile::destroy(Level *level, int x, int y, int z, int data) level->updateNeighborsAt(x, y - 1, z, id); level->updateNeighborsAt(x, y + 1, z, id); } - Tile::destroy(level, x, y, z, data); + Tile::destroy(level, x, y, z, data); } bool DiodeTile::isSolidRender(bool isServerLevel) @@ -232,68 +296,45 @@ bool DiodeTile::isSolidRender(bool isServerLevel) return false; } -int DiodeTile::getResource(int data, Random *random, int playerBonusLevel) +bool DiodeTile::isAlternateInput(int tile) { - return Item::diode->id; + Tile *tt = Tile::tiles[tile]; + return tt != NULL && tt->isSignalSource(); } -void DiodeTile::animateTick(Level *level, int xt, int yt, int zt, Random *random) +int DiodeTile::getOutputSignal(LevelSource *level, int x, int y, int z, int data) { - if (!on) return; - int data = level->getData(xt, yt, zt); - int dir = getDirection(data); + return Redstone::SIGNAL_MAX; +} - double x = xt + 0.5f + (random->nextFloat() - 0.5f) * 0.2; - double y = yt + 0.4f + (random->nextFloat() - 0.5f) * 0.2; - double z = zt + 0.5f + (random->nextFloat() - 0.5f) * 0.2; +bool DiodeTile::isDiode(int id) +{ + return Tile::diode_off->isSameDiode(id) || Tile::comparator_off->isSameDiode(id); +} - double xo = 0; - double zo = 0; +bool DiodeTile::isSameDiode(int id) +{ + return id == getOnTile()->id || id == getOffTile()->id; +} - if (random->nextInt(2) == 0) - { - // spawn on receiver - switch (dir) - { - case Direction::SOUTH: - zo = -5.0f / 16.0f; - break; - case Direction::NORTH: - zo = 5.0f / 16.0f; - break; - case Direction::EAST: - xo = -5.0f / 16.0f; - break; - case Direction::WEST: - xo = 5.0f / 16.0f; - break; - } - } - else +bool DiodeTile::shouldPrioritize(Level *level, int x, int y, int z, int data) +{ + int dir = getDirection(data); + if (isDiode(level->getTile(x - Direction::STEP_X[dir], y, z - Direction::STEP_Z[dir]))) { - // spawn on transmitter - int delay = (data & DELAY_MASK) >> DELAY_SHIFT; - switch (dir) - { - case Direction::SOUTH: - zo = DiodeTile::DELAY_RENDER_OFFSETS[delay]; - break; - case Direction::NORTH: - zo = -DiodeTile::DELAY_RENDER_OFFSETS[delay]; - break; - case Direction::EAST: - xo = DiodeTile::DELAY_RENDER_OFFSETS[delay]; - break; - case Direction::WEST: - xo = -DiodeTile::DELAY_RENDER_OFFSETS[delay]; - break; - } + int odata = level->getData(x - Direction::STEP_X[dir], y, z - Direction::STEP_Z[dir]); + int odir = getDirection(odata); + return odir != dir; } - level->addParticle(eParticleType_reddust, x + xo, y, z + zo, 0, 0, 0); - + return false; } -int DiodeTile::cloneTileId(Level *level, int x, int y, int z) +int DiodeTile::getTurnOffDelay(int data) { - return Item::diode_Id; + return getTurnOnDelay(data); } + +bool DiodeTile::isMatching(int id) +{ + return isSameDiode(id); +} \ No newline at end of file diff --git a/Minecraft.World/DiodeTile.h b/Minecraft.World/DiodeTile.h index 003b011f..16f3347b 100644 --- a/Minecraft.World/DiodeTile.h +++ b/Minecraft.World/DiodeTile.h @@ -8,43 +8,71 @@ class Level; class DiodeTile : public DirectionalTile { friend class Tile; +protected: + bool on; + +protected: + DiodeTile(int id, bool on); +public: + virtual void updateDefaultShape(); // 4J Added override + virtual bool isCubeShaped(); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual bool canSurvive(Level *level, int x, int y, int z); + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual Icon *getTexture(int face, int data); + virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); + virtual int getRenderShape(); + +protected: + virtual bool isOn(int data); + public: - static const int DELAY_MASK = DIRECTION_INV_MASK; - static const int DELAY_SHIFT = 2; + virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir); + virtual int getSignal(LevelSource *level, int x, int y, int z, int facing); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); - static const double DELAY_RENDER_OFFSETS[4]; - static const int DELAYS[4]; +protected: + virtual void checkTickOnNeighbor(Level *level, int x, int y, int z, int type); -private: - bool on; +public: + virtual bool isLocked(LevelSource *level, int x, int y, int z, int data); protected: - DiodeTile(int id, bool on); + virtual bool shouldTurnOn(Level *level, int x, int y, int z, int data); + virtual int getInputSignal(Level *level, int x, int y, int z, int data); + virtual int getAlternateSignal(LevelSource *level, int x, int y, int z, int data); + virtual int getAlternateSignalAt(LevelSource *level, int x, int y, int z, int facing); + public: - virtual void updateDefaultShape(); // 4J Added override - virtual bool isCubeShaped(); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual bool canSurvive(Level *level, int x, int y, int z); - virtual void tick(Level *level, int x, int y, int z, Random *random); - virtual Icon *getTexture(int face, int data); - //@Override - void registerIcons(IconRegister *iconRegister); - virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); - virtual int getRenderShape(); - virtual bool getDirectSignal(Level *level, int x, int y, int z, int dir); - virtual bool getSignal(LevelSource *level, int x, int y, int z, int facing); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); -private: - virtual bool getSourceSignal(Level *level, int x, int y, int z, int data); + virtual bool isSignalSource(); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual void onPlace(Level *level, int x, int y, int z); + +protected: + virtual void updateNeighborsInFront(Level *level, int x, int y, int z); + public: - virtual bool TestUse(); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - virtual bool isSignalSource(); - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); - virtual void onPlace(Level *level, int x, int y, int z); virtual void destroy(Level *level, int x, int y, int z, int data); - virtual bool isSolidRender(bool isServerLevel = false); - virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual void animateTick(Level *level, int xt, int yt, int zt, Random *random); - virtual int cloneTileId(Level *level, int x, int y, int z); + virtual bool isSolidRender(bool isServerLevel = false); + virtual int getResource(int data, Random *random, int playerBonusLevel) = 0; + virtual int cloneTileId(Level *level, int x, int y, int z) = 0; + +protected: + virtual bool isAlternateInput(int tile); + virtual int getOutputSignal(LevelSource *level, int x, int y, int z, int data); + +public: + static bool isDiode(int id); + virtual bool isSameDiode(int id); + virtual bool shouldPrioritize(Level *level, int x, int y, int z, int data); + +protected: + virtual int getTurnOffDelay(int data); + + virtual int getTurnOnDelay(int data) = 0; + virtual DiodeTile *getOnTile() = 0; + virtual DiodeTile *getOffTile() = 0; + +public: + virtual bool isMatching(int id); }; diff --git a/Minecraft.World/Direction.cpp b/Minecraft.World/Direction.cpp index 408bbab5..f758798b 100644 --- a/Minecraft.World/Direction.cpp +++ b/Minecraft.World/Direction.cpp @@ -4,18 +4,20 @@ const int Direction::STEP_X[] = { - 0, -1, 0, 1 + 0, -1, 0, 1 }; const int Direction::STEP_Z[] = { - 1, 0, -1, 0 + 1, 0, -1, 0 }; +const wstring Direction::NAMES[] = {L"SOUTH", L"WEST", L"NORTH", L"EAST" }; + // for [direction] it gives [tile-face] int Direction::DIRECTION_FACING[4] = { - Facing::SOUTH, Facing::WEST, Facing::NORTH, Facing::EAST + Facing::SOUTH, Facing::WEST, Facing::NORTH, Facing::EAST }; // for [facing] it gives [direction] @@ -26,37 +28,71 @@ int Direction::FACING_DIRECTION[] = int Direction::DIRECTION_OPPOSITE[4] = { - Direction::NORTH, Direction::EAST, Direction::SOUTH, Direction::WEST + NORTH, EAST, SOUTH, WEST }; // for [direction] it gives [90 degrees clockwise direction] int Direction::DIRECTION_CLOCKWISE[] = { - Direction::WEST, Direction::NORTH, Direction::EAST, Direction::SOUTH + WEST, NORTH, EAST, SOUTH }; // for [direction] it gives [90 degrees counter clockwise direction] int Direction::DIRECTION_COUNTER_CLOCKWISE[] = { - Direction::EAST, Direction::SOUTH, Direction::WEST, Direction::NORTH + EAST, SOUTH, WEST, NORTH }; int Direction::RELATIVE_DIRECTION_FACING[4][6] = { - // south - { - Facing::UP, Facing::DOWN, Facing::SOUTH, Facing::NORTH, Facing::EAST, Facing::WEST - }, - // west - { - Facing::UP, Facing::DOWN, Facing::EAST, Facing::WEST, Facing::NORTH, Facing::SOUTH - }, - // north - { - Facing::UP, Facing::DOWN, Facing::NORTH, Facing::SOUTH, Facing::WEST, Facing::EAST - }, - // east - { - Facing::UP, Facing::DOWN, Facing::WEST, Facing::EAST, Facing::SOUTH, Facing::NORTH - } + // south + { + Facing::UP, Facing::DOWN, Facing::SOUTH, Facing::NORTH, Facing::EAST, Facing::WEST + }, + // west + { + Facing::UP, Facing::DOWN, Facing::EAST, Facing::WEST, Facing::NORTH, Facing::SOUTH + }, + // north + { + Facing::UP, Facing::DOWN, Facing::NORTH, Facing::SOUTH, Facing::WEST, Facing::EAST + }, + // east + { + Facing::UP, Facing::DOWN, Facing::WEST, Facing::EAST, Facing::SOUTH, Facing::NORTH + } }; + +int Direction::getDirection(double xd, double zd) +{ + if (Mth::abs((float) xd) > Mth::abs((float) zd)) + { + if (xd > 0) + { + return WEST; + } + else + { + return EAST; + } + } + else + { + if (zd > 0) + { + return NORTH; + } + else + { + return SOUTH; + } + } +} + +int Direction::getDirection(int x0, int z0, int x1, int z1) +{ + int xd = x0 - x1; + int zd = z0 - z1; + + return getDirection(xd, zd); +} \ No newline at end of file diff --git a/Minecraft.World/Direction.h b/Minecraft.World/Direction.h index aadd2bbb..61c6ef58 100644 --- a/Minecraft.World/Direction.h +++ b/Minecraft.World/Direction.h @@ -4,29 +4,34 @@ class Direction { public: static const int UNDEFINED = -1; - static const int SOUTH = 0; - static const int WEST = 1; - static const int NORTH = 2; - static const int EAST = 3; + static const int SOUTH = 0; + static const int WEST = 1; + static const int NORTH = 2; + static const int EAST = 3; static const int STEP_X[]; static const int STEP_Z[]; - // for [direction] it gives [tile-face] - static int DIRECTION_FACING[]; + static const wstring NAMES[];; - // for [facing] it gives [direction] + // for [direction] it gives [tile-face] + static int DIRECTION_FACING[]; + + // for [facing] it gives [direction] static int FACING_DIRECTION[]; - // for [direction] it gives [opposite direction] - static int DIRECTION_OPPOSITE[]; + // for [direction] it gives [opposite direction] + static int DIRECTION_OPPOSITE[]; - // for [direction] it gives [90 degrees clockwise direction] + // for [direction] it gives [90 degrees clockwise direction] static int DIRECTION_CLOCKWISE[]; - // for [direction] it gives [90 degrees counter-clockwise direction] + // for [direction] it gives [90 degrees counter-clockwise direction] static int DIRECTION_COUNTER_CLOCKWISE[]; - // for [direction][world-facing] it gives [tile-facing] - static int RELATIVE_DIRECTION_FACING[4][6]; + // for [direction][world-facing] it gives [tile-facing] + static int RELATIVE_DIRECTION_FACING[4][6]; + + static int getDirection(double xd, double zd); + static int getDirection(int x0, int z0, int x1, int z1); }; \ No newline at end of file diff --git a/Minecraft.World/DirectionalTile.cpp b/Minecraft.World/DirectionalTile.cpp index 783e88bd..e1231a00 100644 --- a/Minecraft.World/DirectionalTile.cpp +++ b/Minecraft.World/DirectionalTile.cpp @@ -2,10 +2,6 @@ #include "DirectionalTile.h" -DirectionalTile::DirectionalTile(int id, Material *material) : Tile(id, material) -{ -} - DirectionalTile::DirectionalTile(int id, Material *material, bool isSolidRender) : Tile(id, material, isSolidRender) { } diff --git a/Minecraft.World/DirectionalTile.h b/Minecraft.World/DirectionalTile.h index cc4715c6..5de80567 100644 --- a/Minecraft.World/DirectionalTile.h +++ b/Minecraft.World/DirectionalTile.h @@ -9,7 +9,6 @@ public: static const int DIRECTION_INV_MASK = 0xC; protected: - DirectionalTile(int id, Material *material); DirectionalTile(int id, Material *material, bool isSolidRender); public: diff --git a/Minecraft.World/DirectoryLevelStorage.cpp b/Minecraft.World/DirectoryLevelStorage.cpp index 27514c9b..ba9bec6a 100644 --- a/Minecraft.World/DirectoryLevelStorage.cpp +++ b/Minecraft.World/DirectoryLevelStorage.cpp @@ -328,7 +328,7 @@ LevelData *DirectoryLevelStorage::prepareLevel() } m_bHasLoadedMapDataMappings = true; - } + } // 4J Jev, removed try/catch @@ -344,7 +344,7 @@ LevelData *DirectoryLevelStorage::prepareLevel() return ret; } - return NULL; + return NULL; } void DirectoryLevelStorage::saveLevelData(LevelData *levelData, vector > *players) @@ -428,18 +428,15 @@ void DirectoryLevelStorage::save(shared_ptr player) } } - // 4J Changed return val to bool to check if new player or loaded player -bool DirectoryLevelStorage::load(shared_ptr player) +// 4J Changed return val to bool to check if new player or loaded player +CompoundTag *DirectoryLevelStorage::load(shared_ptr player) { - bool newPlayer = true; CompoundTag *tag = loadPlayerDataTag( player->getXuid() ); if (tag != NULL) { - newPlayer = false; player->load(tag); - delete tag; } - return newPlayer; + return tag; } CompoundTag *DirectoryLevelStorage::loadPlayerDataTag(PlayerUID xuid) @@ -506,20 +503,20 @@ void DirectoryLevelStorage::clearOldPlayerFiles() sort(playerFiles->begin(), playerFiles->end(), FileEntry::newestFirst ); for(unsigned int i = MAX_PLAYER_DATA_SAVES; i < playerFiles->size(); ++i ) - { + { FileEntry *file = playerFiles->at(i); wstring xuidStr = replaceAll( replaceAll(file->data.filename,playerDir.getName(),L""),L".dat",L""); #if defined(__PS3__) || defined(__ORBIS__) || defined(_DURANGO) - PlayerUID xuid(xuidStr); + PlayerUID xuid(xuidStr); #else - PlayerUID xuid = _fromString(xuidStr); + PlayerUID xuid = _fromString(xuidStr); #endif - deleteMapFilesForPlayer(xuid); - m_saveFile->deleteFile( playerFiles->at(i) ); - } + deleteMapFilesForPlayer(xuid); + m_saveFile->deleteFile( playerFiles->at(i) ); + } } - delete playerFiles; + delete playerFiles; } } @@ -704,10 +701,10 @@ void DirectoryLevelStorage::saveMapIdLookup() ); #else m_saveFile->writeFile( fileEntry, - &m_saveableMapDataMappings, // data buffer - sizeof(MapDataMappings), // number of bytes to write - &NumberOfBytesWritten // number of bytes written - ); + &m_saveableMapDataMappings, // data buffer + sizeof(MapDataMappings), // number of bytes to write + &NumberOfBytesWritten // number of bytes written + ); assert( NumberOfBytesWritten == sizeof(MapDataMappings) ); #endif } diff --git a/Minecraft.World/DirectoryLevelStorage.h b/Minecraft.World/DirectoryLevelStorage.h index 820ef31f..3c811ef3 100644 --- a/Minecraft.World/DirectoryLevelStorage.h +++ b/Minecraft.World/DirectoryLevelStorage.h @@ -122,7 +122,7 @@ public: virtual void saveLevelData(LevelData *levelData, vector > *players); virtual void saveLevelData(LevelData *levelData); virtual void save(shared_ptr player); - virtual bool load(shared_ptr player); // 4J Changed return val to bool to check if new player or loaded player + virtual CompoundTag *load(shared_ptr player); // 4J Changed return val to bool to check if new player or loaded player virtual CompoundTag *loadPlayerDataTag(PlayerUID xuid); virtual void clearOldPlayerFiles(); // 4J Added PlayerIO *getPlayerIO(); diff --git a/Minecraft.World/DispenseItemBehavior.cpp b/Minecraft.World/DispenseItemBehavior.cpp new file mode 100644 index 00000000..19eb5d0b --- /dev/null +++ b/Minecraft.World/DispenseItemBehavior.cpp @@ -0,0 +1,10 @@ +#include "stdafx.h" + +#include "DispenseItemBehavior.h" + +DispenseItemBehavior *DispenseItemBehavior::NOOP = new NoOpDispenseItemBehavior(); + +shared_ptr NoOpDispenseItemBehavior::dispense(BlockSource *source, shared_ptr dispensed) +{ + return dispensed; +} \ No newline at end of file diff --git a/Minecraft.World/DispenseItemBehavior.h b/Minecraft.World/DispenseItemBehavior.h new file mode 100644 index 00000000..08e1460b --- /dev/null +++ b/Minecraft.World/DispenseItemBehavior.h @@ -0,0 +1,29 @@ +#pragma once + +#include "Behavior.h" + +class ItemInstance; +class BlockSource; + +class DispenseItemBehavior : public Behavior +{ +public: + /** + * The 'do nothing' behavior. + */ + static DispenseItemBehavior *NOOP; + + /** + * + * @param source The source of this call (the dispenser that calls it) + * @param dispensed The ItemInstance which is being dispensed + * @return The ItemInstance that should is 'left over' + */ + virtual shared_ptr dispense(BlockSource *source, shared_ptr dispensed) = 0; +}; + +class NoOpDispenseItemBehavior : public DispenseItemBehavior +{ +public: + shared_ptr dispense(BlockSource *source, shared_ptr dispensed); +}; \ No newline at end of file diff --git a/Minecraft.World/DispenserTile.cpp b/Minecraft.World/DispenserTile.cpp index 286737c9..8758b3c5 100644 --- a/Minecraft.World/DispenserTile.cpp +++ b/Minecraft.World/DispenserTile.cpp @@ -3,6 +3,7 @@ #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.inventory.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.tile.entity.h" @@ -11,7 +12,9 @@ #include "net.minecraft.h" #include "Mob.h" -DispenserTile::DispenserTile(int id) : EntityTile(id, Material::stone) +BehaviorRegistry DispenserTile::REGISTRY = BehaviorRegistry(new DefaultDispenseItemBehavior()); + +DispenserTile::DispenserTile(int id) : BaseEntityTile(id, Material::stone) { random = new Random(); @@ -20,19 +23,14 @@ DispenserTile::DispenserTile(int id) : EntityTile(id, Material::stone) iconFrontVertical = NULL; } -int DispenserTile::getTickDelay() +int DispenserTile::getTickDelay(Level *level) { return 4; } -int DispenserTile::getResource(int data, Random *random, int playerBonusLevel) -{ - return Tile::dispenser_Id; -} - void DispenserTile::onPlace(Level *level, int x, int y, int z) { - EntityTile::onPlace(level, x, y, z); + BaseEntityTile::onPlace(level, x, y, z); recalcLockDir(level, x, y, z); } @@ -53,7 +51,7 @@ void DispenserTile::recalcLockDir(Level *level, int x, int y, int z) if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; - level->setData(x, y, z, lockDir); + level->setData(x, y, z, lockDir, Tile::UPDATE_CLIENTS); } Icon *DispenserTile::getTexture(int face, int data) @@ -113,80 +111,58 @@ bool DispenserTile::use(Level *level, int x, int y, int z, shared_ptr pl return true; } -void DispenserTile::fireArrow(Level *level, int x, int y, int z, Random *random) +void DispenserTile::dispenseFrom(Level *level, int x, int y, int z) { - const int lockDir = level->getData(x, y, z); - //const float power = 1.1f; - const int accuracy = 6; - //bool bLaunched=true; + BlockSourceImpl source(level, x, y, z); + shared_ptr trap = dynamic_pointer_cast( source.getEntity() ); + if (trap == NULL) return; - int xd = 0, zd = 0; - if (lockDir == Facing::SOUTH) + int slot = trap->getRandomSlot(); + if (slot < 0) { - zd = 1; - } - else if (lockDir == Facing::NORTH) - { - zd = -1; - } - else if (lockDir == Facing::EAST) - { - xd = 1; + level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); } else { - xd = -1; - } - - shared_ptr trap = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); - if(trap != NULL) - { - int slot=trap->getRandomSlot(); + shared_ptr item = trap->getItem(slot); + DispenseItemBehavior *behavior = getDispenseMethod(item); - if (slot < 0) + if (behavior != DispenseItemBehavior::NOOP) { - level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); - } - else - { - double xp = x + xd * 0.6 + 0.5; - double yp = y + 0.5; - double zp = z + zd * 0.6 + 0.5; - shared_ptr item=trap->getItem(slot); - int result = dispenseItem(trap, level, item, random, x, y, z, xd, zd, xp, yp, zp); - if (result == REMOVE_ITEM) - { - trap->removeItem(slot, 1); - } - else if (result == DISPENSE_ITEM) - { - item = trap->removeItem(slot, 1); - throwItem(level, item, random, accuracy, xd, zd, xp, yp, zp); - level->levelEvent(LevelEvent::SOUND_CLICK, x, y, z, 0); - } + shared_ptr leftOver = behavior->dispense(&source, item); - level->levelEvent(LevelEvent::PARTICLES_SHOOT, x, y, z, (xd + 1) + (zd + 1) * 3); + trap->setItem(slot, leftOver->count == 0 ? nullptr : leftOver); } } } +DispenseItemBehavior *DispenserTile::getDispenseMethod(shared_ptr item) +{ + return REGISTRY.get(item->getItem()); +} + void DispenserTile::neighborChanged(Level *level, int x, int y, int z, int type) { - if (type > 0 && Tile::tiles[type]->isSignalSource()) + bool signal = level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z); + int data = level->getData(x, y, z); + bool isTriggered = (data & TRIGGER_BIT) != 0; + + if (signal && !isTriggered) { - bool signal = level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z); - if (signal) - { - level->addToTickNextTick(x, y, z, this->id, getTickDelay()); - } + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); + level->setData(x, y, z, data | TRIGGER_BIT, UPDATE_NONE); + } + else if (!signal && isTriggered) + { + level->setData(x, y, z, data & ~TRIGGER_BIT, UPDATE_NONE); } } void DispenserTile::tick(Level *level, int x, int y, int z, Random *random) { - if (!level->isClientSide && ( level->hasNeighborSignal(x, y, z) || level->hasNeighborSignal(x, y + 1, z))) + if (!level->isClientSide) // && (level.hasNeighborSignal(x, y, z) || level.hasNeighborSignal(x, y + 1, z))) { - fireArrow(level, x, y, z, random); + dispenseFrom(level, x, y, z); } } @@ -195,14 +171,16 @@ shared_ptr DispenserTile::newTileEntity(Level *level) return shared_ptr( new DispenserTileEntity() ); } -void DispenserTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void DispenserTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { - int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3; + int dir = PistonBaseTile::getNewFacing(level, x, y, z, by); - if (dir == 0) level->setData(x, y, z, Facing::NORTH); - if (dir == 1) level->setData(x, y, z, Facing::EAST); - if (dir == 2) level->setData(x, y, z, Facing::SOUTH); - if (dir == 3) level->setData(x, y, z, Facing::WEST); + level->setData(x, y, z, dir, Tile::UPDATE_CLIENTS); + + if (itemInstance->hasCustomHoverName()) + { + dynamic_pointer_cast( level->getTileEntity(x, y, z))->setCustomName(itemInstance->getHoverName()); + } } void DispenserTile::onRemove(Level *level, int x, int y, int z, int id, int data) @@ -243,331 +221,33 @@ void DispenserTile::onRemove(Level *level, int x, int y, int z, int id, int data container->setItem(i,nullptr); } } + level->updateNeighbourForOutputSignal(x, y, z, id); } - EntityTile::onRemove(level, x, y, z, id, data); + BaseEntityTile::onRemove(level, x, y, z, id, data); } -void DispenserTile::throwItem(Level *level, shared_ptr item, Random *random, int accuracy, int xd, int zd, double xp, double yp, double zp) +Position *DispenserTile::getDispensePosition(BlockSource *source) { - shared_ptr itemEntity = shared_ptr(new ItemEntity(level, xp, yp - 0.3, zp, item)); + FacingEnum *facing = getFacing(source->getData()); - double pow = random->nextDouble() * 0.1 + 0.2; - itemEntity->xd = xd * pow; - itemEntity->yd = .2f; - itemEntity->zd = zd * pow; + double originX = source->getX() + 0.7 * facing->getStepX(); + double originY = source->getY() + 0.7 * facing->getStepY(); + double originZ = source->getZ() + 0.7 * facing->getStepZ(); - itemEntity->xd += (random->nextGaussian()) * 0.0075f * accuracy; - itemEntity->yd += (random->nextGaussian()) * 0.0075f * accuracy; - itemEntity->zd += (random->nextGaussian()) * 0.0075f * accuracy; - - level->addEntity(itemEntity); + return new PositionImpl(originX, originY, originZ); } -int DispenserTile::dispenseItem(shared_ptr trap, Level *level, shared_ptr item, Random *random, int x, int y, int z, int xd, int zd, double xp, double yp, double zp) +FacingEnum *DispenserTile::getFacing(int data) { - float power = 1.1f; - int accuracy = 6; - - // 4J-PB - moved to a switch - switch(item->id) - { - case Item::arrow_Id: - { - int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false); - if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit - { - shared_ptr arrow = shared_ptr( new Arrow(level, xp, yp, zp) ); - arrow->shoot(xd, .1f, zd, power, (float) accuracy); - arrow->pickup = Arrow::PICKUP_ALLOWED; - level->addEntity(arrow); - level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0); - return REMOVE_ITEM; - } - else - { - // some negative sound effect? - level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); - - // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs - return LEAVE_ITEM; - } - } - break; - case Item::egg_Id: - { - int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false); - if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit - { - shared_ptr egg = shared_ptr( new ThrownEgg(level, xp, yp, zp) ); - egg->shoot(xd, .1f, zd, power, (float) accuracy); - level->addEntity(egg); - level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0); - return REMOVE_ITEM; - } - else - { - // some negative sound effect? - level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); - - // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs - return LEAVE_ITEM; - } - } - break; - case Item::snowBall_Id: - { - int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false); - if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit - { - shared_ptr snowball = shared_ptr( new Snowball(level, xp, yp, zp) ); - snowball->shoot(xd, .1f, zd, power, (float) accuracy); - level->addEntity(snowball); - level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0); - return REMOVE_ITEM; - } - else - { - // some negative sound effect? - level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); - - // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs - return LEAVE_ITEM; - } - } - break; - case Item::potion_Id: - { - int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false); - if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit - { - if(PotionItem::isThrowable(item->getAuxValue())) - { - shared_ptr potion = shared_ptr(new ThrownPotion(level, xp, yp, zp, item->getAuxValue())); - potion->shoot(xd, .1f, zd, power * 1.25f, accuracy * .5f); - level->addEntity(potion); - level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0); - } - else - { - shared_ptr itemEntity = shared_ptr( new ItemEntity(level, xp, yp - 0.3, zp, item) ); - - double pow = random->nextDouble() * 0.1 + 0.2; - itemEntity->xd = xd * pow; - itemEntity->yd = .2f; - itemEntity->zd = zd * pow; - - itemEntity->xd += (random->nextGaussian()) * 0.0075f * accuracy; - itemEntity->yd += (random->nextGaussian()) * 0.0075f * accuracy; - itemEntity->zd += (random->nextGaussian()) * 0.0075f * accuracy; - - level->addEntity(itemEntity); - level->levelEvent(LevelEvent::SOUND_CLICK, x, y, z, 0); - } - return REMOVE_ITEM; - } - else - { - // some negative sound effect? - level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); - - // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs - return LEAVE_ITEM; - } - } - break; - case Item::expBottle_Id: - { - int currentProjectiles = level->countInstanceOf(eTYPE_PROJECTILE,false); - if(currentProjectiles < Level::MAX_DISPENSABLE_PROJECTILES) // 4J - added limit - { - shared_ptr expBottle = shared_ptr( new ThrownExpBottle(level, xp, yp, zp) ); - expBottle->shoot(xd, .1f, zd, power * 1.25f, accuracy * .5f); - level->addEntity(expBottle); - level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0); - return REMOVE_ITEM; - } - else - { - // some negative sound effect? - level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); - - // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs - return LEAVE_ITEM; - } - } - break; - case Item::fireball_Id: // TU9 - { - int currentFireballs = level->countInstanceOf(eTYPE_SMALL_FIREBALL,true); - if(currentFireballs < Level::MAX_DISPENSABLE_FIREBALLS) // 4J - added limit - { - shared_ptr fireball = shared_ptr( new SmallFireball(level, xp + xd * .3, yp, zp + zd * .3, xd + random->nextGaussian() * .05, random->nextGaussian() * .05, zd + random->nextGaussian() * .05)); - level->addEntity(fireball); - level->levelEvent(LevelEvent::SOUND_BLAZE_FIREBALL, x, y, z, 0); - return REMOVE_ITEM; - } - else - { - // some negative sound effect? - level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); - - // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs - return LEAVE_ITEM; - } - } - break; - case Item::monsterPlacer_Id: - { - int iResult=0; - //MonsterPlacerItem *spawnEgg = (MonsterPlacerItem *)item->getItem(); - shared_ptr newEntity = MonsterPlacerItem::canSpawn(item->getAuxValue(), level,&iResult); - - shared_ptr mob = dynamic_pointer_cast(newEntity); - if (mob != NULL) - { - // 4J-PB - Changed the line below slightly since mobs were sticking to the dispenser rather than dropping down when fired - mob->moveTo(xp + xd * 0.4, yp - 0.3, zp + zd * 0.4, level->random->nextFloat() * 360, 0); - mob->finalizeMobSpawn(); - level->addEntity(mob); - level->levelEvent(LevelEvent::SOUND_LAUNCH, x, y, z, 0); - return REMOVE_ITEM; - } - else - { - // some negative sound effect? - level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); - - // not sending a message here, since we will probably get flooded with them when people have automatic dispensers for spawn eggs - return LEAVE_ITEM; - } - } - break; - case Item::bucket_lava_Id: - case Item::bucket_water_Id: - { - BucketItem *pBucket = (BucketItem *) item->getItem(); - - if (pBucket->emptyBucket(level, x, y, z, x + xd, y, z + zd)) - { - item->id = Item::bucket_empty_Id; - item->count = 1; - return LEAVE_ITEM; - } - return DISPENSE_ITEM; - } - break; - case Item::bucket_empty_Id: - { - int xt = x + xd; - int zt = z + zd; - Material *pMaterial=level->getMaterial(xt, y, zt); - int data = level->getData(xt, y, zt); - - if (pMaterial == Material::water && data == 0) - { - level->setTile(xt, y, zt, 0); - - if (--item->count == 0) - { - item->id = Item::bucket_water_Id; - item->count = 1; - } - else if (trap->addItem(shared_ptr(new ItemInstance(Item::bucket_water))) < 0) - { - throwItem(level, shared_ptr(new ItemInstance(Item::bucket_water)), random, 6, xd, zd, xp, yp, zp); - } - - return LEAVE_ITEM; - } - else if (pMaterial == Material::lava && data == 0) - { - level->setTile(xt, y, zt, 0); - - if (--item->count == 0) - { - item->id = Item::bucket_lava_Id; - item->count = 1; - } - else if (trap->addItem(shared_ptr(new ItemInstance(Item::bucket_lava))) < 0) - { - throwItem(level, shared_ptr(new ItemInstance(Item::bucket_lava)), random, 6, xd, zd, xp, yp, zp); - } - - return LEAVE_ITEM; - } - return DISPENSE_ITEM; - } - - break; - // TU12 - case Item::minecart_Id: - case Item::minecart_chest_Id: - case Item::minecart_furnace_Id: - { - xp = x + (xd < 0 ? xd * 0.8 : xd * 1.8f) + Mth::abs(zd) * 0.5f; - zp = z + (zd < 0 ? zd * 0.8 : zd * 1.8f) + Mth::abs(xd) * 0.5f; - - if (RailTile::isRail(level, x + xd, y, z + zd)) - { - yp = y + 0.5f; - } - else if (level->isEmptyTile(x + xd, y, z + zd) && RailTile::isRail(level, x + xd, y - 1, z + zd)) - { - yp = y - 0.5f; - } - else - { - return DISPENSE_ITEM; - } - - if( level->countInstanceOf(eTYPE_MINECART, true) < Level::MAX_CONSOLE_MINECARTS ) // 4J - added limit - { - shared_ptr minecart = shared_ptr(new Minecart(level, xp, yp, zp, ((MinecartItem *) item->getItem())->type)); - level->addEntity(minecart); - level->levelEvent(LevelEvent::SOUND_CLICK, x, y, z, 0); - - return REMOVE_ITEM; - } - else - { - return DISPENSE_ITEM; - } - } - break; - - case Item::boat_Id: - { - bool bLaunchBoat=false; - - xp = x + (xd < 0 ? xd * 0.8 : xd * 1.8f) + Mth::abs(zd) * 0.5f; - zp = z + (zd < 0 ? zd * 0.8 : zd * 1.8f) + Mth::abs(xd) * 0.5f; - - if (level->getMaterial(x + xd, y, z + zd) == Material::water) - { - bLaunchBoat=true; - yp = y + 1.0f; - } - else if (level->isEmptyTile(x + xd, y, z + zd) && level->getMaterial(x + xd, y - 1, z + zd) == Material::water) - { - bLaunchBoat=true; - yp = y; - } - - // check the limit on boats - if( bLaunchBoat && level->countInstanceOf(eTYPE_BOAT, true) < Level::MAX_XBOX_BOATS ) // 4J - added limit - { - shared_ptr boat = shared_ptr(new Boat(level, xp, yp, zp)); - level->addEntity(boat); - level->levelEvent(LevelEvent::SOUND_CLICK, x, y, z, 0); - return REMOVE_ITEM; - } - else - { - return DISPENSE_ITEM; - } - } - break; - } + return FacingEnum::fromData(data & FACING_MASK); +} - return DISPENSE_ITEM; +bool DispenserTile::hasAnalogOutputSignal() +{ + return true; } + +int DispenserTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + return AbstractContainerMenu::getRedstoneSignalFromContainer(dynamic_pointer_cast( level->getTileEntity(x, y, z)) ); +} \ No newline at end of file diff --git a/Minecraft.World/DispenserTile.h b/Minecraft.World/DispenserTile.h index 5bc892aa..1205be94 100644 --- a/Minecraft.World/DispenserTile.h +++ b/Minecraft.World/DispenserTile.h @@ -1,21 +1,20 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" +#include "net.minecraft.core.h" class Player; class Mob; class ChunkRebuildData; -class DispenserTile : public EntityTile + +class DispenserTile : public BaseEntityTile { friend class Tile; friend class ChunkRebuildData; -private: - static const int DISPENSE_ITEM = 0; - static const int REMOVE_ITEM = 1; - static const int LEAVE_ITEM = 2; - public: static const int FACING_MASK = 0x7; + static const int TRIGGER_BIT = 8; + static BehaviorRegistry REGISTRY; protected: Random *random; @@ -28,31 +27,31 @@ protected: DispenserTile(int id); public: - virtual int getTickDelay(); - virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual void onPlace(Level *level, int x, int y, int z); + virtual int getTickDelay(Level *level); + virtual void onPlace(Level *level, int x, int y, int z); private: void recalcLockDir(Level *level, int x, int y, int z); public: virtual Icon *getTexture(int face, int data); - //@Override - void registerIcons(IconRegister *iconRegister); + virtual void registerIcons(IconRegister *iconRegister); virtual bool TestUse(); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param -private: - void fireArrow(Level *level, int x, int y, int z, Random *random); +protected: + virtual void dispenseFrom(Level *level, int x, int y, int z); + virtual DispenseItemBehavior *getDispenseMethod(shared_ptr item); public: virtual void neighborChanged(Level *level, int x, int y, int z, int type); - virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual void tick(Level *level, int x, int y, int z, Random *random); virtual shared_ptr newTileEntity(Level *level); - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); -private: - static void throwItem(Level *level, shared_ptr item, Random *random, int accuracy, int xd, int zd, double xp, double yp, double zp); - static int dispenseItem(shared_ptr trap, Level *level, shared_ptr item, Random *random, int x, int y, int z, int xd, int zd, double xp, double yp, double zp); + static Position *getDispensePosition(BlockSource *source); + static FacingEnum *getFacing(int data); + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); }; \ No newline at end of file diff --git a/Minecraft.World/DispenserTileEntity.cpp b/Minecraft.World/DispenserTileEntity.cpp index 2c4705ea..b087e535 100644 --- a/Minecraft.World/DispenserTileEntity.cpp +++ b/Minecraft.World/DispenserTileEntity.cpp @@ -1,5 +1,3 @@ -using namespace std; - #include "stdafx.h" #include "com.mojang.nbt.h" #include "TileEntity.h" @@ -13,14 +11,14 @@ using namespace std; DispenserTileEntity::DispenserTileEntity() : TileEntity() { - items = new ItemInstanceArray(9); + items = ItemInstanceArray(9); random = new Random(); + name = L""; } DispenserTileEntity::~DispenserTileEntity() { - delete[] items->data; - delete items; + delete[] items.data; delete random; } @@ -32,27 +30,27 @@ unsigned int DispenserTileEntity::getContainerSize() shared_ptr DispenserTileEntity::getItem(unsigned int slot) { - return items->data[slot]; + return items[slot]; } shared_ptr DispenserTileEntity::removeItem(unsigned int slot, int count) { - if (items->data[slot] != NULL) + if (items[slot] != NULL) { - if (items->data[slot]->count <= count) + if (items[slot]->count <= count) { - shared_ptr item = items->data[slot]; - items->data[slot] = nullptr; - this->setChanged(); + shared_ptr item = items[slot]; + items[slot] = nullptr; + setChanged(); // 4J Stu - Fix for duplication glitch if(item->count <= 0) return nullptr; return item; } else { - shared_ptr i = items->data[slot]->remove(count); - if (items->data[slot]->count == 0) items->data[slot] = nullptr; - this->setChanged(); + shared_ptr i = items[slot]->remove(count); + if (items[slot]->count == 0) items[slot] = nullptr; + setChanged(); // 4J Stu - Fix for duplication glitch if(i->count <= 0) return nullptr; return i; @@ -63,10 +61,10 @@ shared_ptr DispenserTileEntity::removeItem(unsigned int slot, int shared_ptr DispenserTileEntity::removeItemNoUpdate(int slot) { - if (items->data[slot] != NULL) + if (items[slot] != NULL) { - shared_ptr item = items->data[slot]; - items->data[slot] = nullptr; + shared_ptr item = items[slot]; + items[slot] = nullptr; return item; } return nullptr; @@ -75,20 +73,20 @@ shared_ptr DispenserTileEntity::removeItemNoUpdate(int slot) // 4J-PB added for spawn eggs not being useable due to limits, so add them in again void DispenserTileEntity::AddItemBack(shared_ptritem, unsigned int slot) { - if (items->data[slot] != NULL) + if (items[slot] != NULL) { // just increment the count of the items - if(item->id==items->data[slot]->id) + if(item->id==items[slot]->id) { - items->data[slot]->count++; - this->setChanged(); + items[slot]->count++; + setChanged(); } } else { - items->data[slot] = item; + items[slot] = item; if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); - this->setChanged(); + setChanged(); } } /** @@ -99,9 +97,9 @@ void DispenserTileEntity::AddItemBack(shared_ptritem, unsigned int */ bool DispenserTileEntity::removeProjectile(int itemId) { - for (unsigned int i = 0; i < items->length; i++) + for (unsigned int i = 0; i < items.length; i++) { - if (items->data[i] != NULL && items->data[i]->id == itemId) + if (items[i] != NULL && items[i]->id == itemId) { shared_ptr removedItem = removeItem(i, 1); return removedItem != NULL; @@ -114,9 +112,9 @@ int DispenserTileEntity::getRandomSlot() { int replaceSlot = -1; int replaceOdds = 1; - for (unsigned int i = 0; i < items->length; i++) + for (unsigned int i = 0; i < items.length; i++) { - if (items->data[i] != NULL && random->nextInt(replaceOdds++) == 0) + if (items[i] != NULL && random->nextInt(replaceOdds++) == 0) { replaceSlot = i; } @@ -127,18 +125,18 @@ int DispenserTileEntity::getRandomSlot() void DispenserTileEntity::setItem(unsigned int slot, shared_ptr item) { - items->data[slot] = item; + items[slot] = item; if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); - this->setChanged(); + setChanged(); } int DispenserTileEntity::addItem(shared_ptr item) { - for (int i = 0; i < items->length; i++) + for (int i = 0; i < items.length; i++) { - if ((*items)[i] == NULL || (*items)[i]->id == 0) + if (items[i] == NULL || items[i]->id == 0) { - (*items)[i] = item; + setItem(i, item); return i; } } @@ -146,22 +144,39 @@ int DispenserTileEntity::addItem(shared_ptr item) return -1; } -int DispenserTileEntity::getName() +wstring DispenserTileEntity::getName() +{ + return hasCustomName() ? name : app.GetString(IDS_TILE_DISPENSER); +} + +wstring DispenserTileEntity::getCustomName() +{ + return hasCustomName() ? name : L""; +} + +void DispenserTileEntity::setCustomName(const wstring &name) { - return IDS_TILE_DISPENSER; + this->name = name; +} + +bool DispenserTileEntity::hasCustomName() +{ + return !name.empty(); } void DispenserTileEntity::load(CompoundTag *base) { TileEntity::load(base); ListTag *inventoryList = (ListTag *) base->getList(L"Items"); - items = new ItemInstanceArray(getContainerSize()); + delete [] items.data; + items = ItemInstanceArray(getContainerSize()); for (int i = 0; i < inventoryList->size(); i++) { CompoundTag *tag = inventoryList->get(i); unsigned int slot = tag->getByte(L"Slot") & 0xff; - if (slot >= 0 && slot < items->length) (*items)[slot] = ItemInstance::fromTag(tag); + if (slot >= 0 && slot < items.length) items[slot] = ItemInstance::fromTag(tag); } + if (base->contains(L"CustomName")) name = base->getString(L"CustomName"); } void DispenserTileEntity::save(CompoundTag *base) @@ -169,17 +184,18 @@ void DispenserTileEntity::save(CompoundTag *base) TileEntity::save(base); ListTag *listTag = new ListTag; - for (unsigned int i = 0; i < items->length; i++) + for (unsigned int i = 0; i < items.length; i++) { - if (items->data[i] != NULL) + if (items[i] != NULL) { CompoundTag *tag = new CompoundTag(); tag->putByte(L"Slot", (byte) i); - items->data[i]->save(tag); + items[i]->save(tag); listTag->add(tag); } } base->put(L"Items", listTag); + if (hasCustomName()) base->putString(L"CustomName", name); } int DispenserTileEntity::getMaxStackSize() @@ -207,17 +223,22 @@ void DispenserTileEntity::stopOpen() { } +bool DispenserTileEntity::canPlaceItem(int slot, shared_ptr item) +{ + return true; +} + // 4J Added shared_ptr DispenserTileEntity::clone() { shared_ptr result = shared_ptr( new DispenserTileEntity() ); TileEntity::clone(result); - for (unsigned int i = 0; i < items->length; i++) + for (unsigned int i = 0; i < items.length; i++) { - if (items->data[i] != NULL) + if (items[i] != NULL) { - result->items->data[i] = ItemInstance::clone(items->data[i]); + result->items[i] = ItemInstance::clone(items[i]); } } return result; diff --git a/Minecraft.World/DispenserTileEntity.h b/Minecraft.World/DispenserTileEntity.h index 8519ad54..fc0c1f39 100644 --- a/Minecraft.World/DispenserTileEntity.h +++ b/Minecraft.World/DispenserTileEntity.h @@ -18,12 +18,15 @@ public: static TileEntity *create() { return new DispenserTileEntity(); } -using TileEntity::setChanged; + using TileEntity::setChanged; private: - ItemInstanceArray *items; + ItemInstanceArray items; Random *random; +protected: + wstring name; + public: DispenserTileEntity(); virtual ~DispenserTileEntity(); @@ -31,20 +34,24 @@ public: virtual unsigned int getContainerSize(); virtual shared_ptr getItem(unsigned int slot); virtual shared_ptr removeItem(unsigned int slot, int count); - shared_ptr removeItemNoUpdate(int slot); - bool removeProjectile(int itemId); - int getRandomSlot(); + virtual shared_ptr removeItemNoUpdate(int slot); + virtual bool removeProjectile(int itemId); + virtual int getRandomSlot(); virtual void setItem(unsigned int slot, shared_ptr item); virtual int addItem(shared_ptr item); - virtual int getName(); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual void setCustomName(const wstring &name); + virtual bool hasCustomName(); virtual void load(CompoundTag *base); virtual void save(CompoundTag *base); virtual int getMaxStackSize(); virtual bool stillValid(shared_ptr player); virtual void setChanged(); - void startOpen(); - void stopOpen(); + virtual void startOpen(); + virtual void stopOpen(); + virtual bool canPlaceItem(int slot, shared_ptr item); // 4J Added virtual shared_ptr clone(); diff --git a/Minecraft.World/DoorItem.cpp b/Minecraft.World/DoorItem.cpp index d59ac8d9..97de0f65 100644 --- a/Minecraft.World/DoorItem.cpp +++ b/Minecraft.World/DoorItem.cpp @@ -28,7 +28,7 @@ bool DoorItem::useOn(shared_ptr instance, shared_ptr playe if (material == Material::wood) tile = Tile::door_wood; else tile = Tile::door_iron; - if (!player->mayBuild(x, y, z) || !player->mayBuild(x, y + 1, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, instance) || !player->mayUseItemAt(x, y + 1, z, face, instance)) return false; if (!tile->mayPlace(level, x, y, z)) return false; // 4J-PB - Adding a test only version to allow tooltips to be displayed @@ -65,10 +65,8 @@ void DoorItem::place(Level *level, int x, int y, int z, int dir, Tile *tile) if (doorLeft && !doorRight) flip = true; else if (solidRight > solidLeft) flip = true; - level->noNeighborUpdate = true; - level->setTileAndData(x, y, z, tile->id, dir); - level->setTileAndData(x, y + 1, z, tile->id, 8 | (flip ? 1 : 0)); - level->noNeighborUpdate = false; + level->setTileAndData(x, y, z, tile->id, dir, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y + 1, z, tile->id, 8 | (flip ? 1 : 0), Tile::UPDATE_CLIENTS); level->updateNeighborsAt(x, y, z, tile->id); level->updateNeighborsAt(x, y + 1, z, tile->id); } diff --git a/Minecraft.World/DoorTile.cpp b/Minecraft.World/DoorTile.cpp index be31be27..8b70e6d9 100644 --- a/Minecraft.World/DoorTile.cpp +++ b/Minecraft.World/DoorTile.cpp @@ -12,8 +12,6 @@ const wstring DoorTile::TEXTURES[] = { L"doorWood_lower", L"doorWood_upper", L"d DoorTile::DoorTile(int id, Material *material) : Tile(id, material,isSolidRender()) { - icons = NULL; - if (material == Material::metal) { texBase = 2; @@ -30,12 +28,12 @@ DoorTile::DoorTile(int id, Material *material) : Tile(id, material,isSolidRender Icon *DoorTile::getTexture(int face, int data) { - return icons[texBase]; + return iconBottom[TEXTURE_NORMAL]; } Icon *DoorTile::getTexture(LevelSource *level, int x, int y, int z, int face) { - if (face == Facing::UP || face == Facing::DOWN) return icons[texBase]; + if (face == Facing::UP || face == Facing::DOWN) return iconBottom[TEXTURE_NORMAL]; int compositeData = getCompositeData(level, x, y, z); int dir = compositeData & C_DIR_MASK; @@ -59,18 +57,22 @@ Icon *DoorTile::getTexture(LevelSource *level, int x, int y, int z, int face) if ((compositeData & C_RIGHT_HINGE_MASK) != 0) flip = !flip; } - return icons[texBase + (flip ? DOOR_TILE_TEXTURE_COUNT : 0) + (upper ? 1 : 0)]; + if (upper) + { + return iconTop[flip ? TEXTURE_FLIPPED : TEXTURE_NORMAL]; + } + else + { + return iconBottom[flip ? TEXTURE_FLIPPED : TEXTURE_NORMAL]; + } } void DoorTile::registerIcons(IconRegister *iconRegister) { - icons = new Icon*[DOOR_TILE_TEXTURE_COUNT * 2]; - - for (int i = 0; i < DOOR_TILE_TEXTURE_COUNT; i++) - { - icons[i] = iconRegister->registerIcon(TEXTURES[i]); - icons[i + DOOR_TILE_TEXTURE_COUNT] = new FlippedIcon(icons[i], true, false); - } + iconTop[TEXTURE_NORMAL] = iconRegister->registerIcon(getIconName() + L"_upper"); + iconBottom[TEXTURE_NORMAL] = iconRegister->registerIcon(getIconName() + L"_lower"); + iconTop[TEXTURE_FLIPPED] = new FlippedIcon(iconTop[TEXTURE_NORMAL], true, false); + iconBottom[TEXTURE_FLIPPED] = new FlippedIcon(iconBottom[TEXTURE_NORMAL], true, false); } bool DoorTile::blocksLight() @@ -177,12 +179,12 @@ void DoorTile::attack(Level *level, int x, int y, int z, shared_ptr play // 4J-PB - Adding a TestUse for tooltip display bool DoorTile::TestUse() { - return true; + return id == Tile::door_wood_Id; } bool DoorTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param { - if(soundOnly) + if (soundOnly) { // 4J - added - just do enough to play the sound if (material != Material::metal) @@ -199,12 +201,12 @@ bool DoorTile::use(Level *level, int x, int y, int z, shared_ptr player, lowerData ^= 4; if ((compositeData & C_IS_UPPER_MASK) == 0) { - level->setData(x, y, z, lowerData);//, Tile.UPDATE_CLIENTS); + level->setData(x, y, z, lowerData, Tile::UPDATE_CLIENTS); level->setTilesDirty(x, y, z, x, y, z); } else { - level->setData(x, y - 1, z, lowerData);//, Tile.UPDATE_CLIENTS); + level->setData(x, y - 1, z, lowerData, Tile::UPDATE_CLIENTS); level->setTilesDirty(x, y - 1, z, x, y, z); } @@ -222,12 +224,12 @@ void DoorTile::setOpen(Level *level, int x, int y, int z, bool shouldOpen) lowerData ^= 4; if ((compositeData & C_IS_UPPER_MASK) == 0) { - level->setData(x, y, z, lowerData);//, Tile.UPDATE_CLIENTS); + level->setData(x, y, z, lowerData, Tile::UPDATE_CLIENTS); level->setTilesDirty(x, y, z, x, y, z); } else { - level->setData(x, y - 1, z, lowerData);//, Tile.UPDATE_CLIENTS); + level->setData(x, y - 1, z, lowerData, Tile::UPDATE_CLIENTS); level->setTilesDirty(x, y - 1, z, x, y, z); } @@ -242,16 +244,16 @@ void DoorTile::neighborChanged(Level *level, int x, int y, int z, int type) bool spawn = false; if (level->getTile(x, y + 1, z) != id) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); spawn = true; } if (!level->isSolidBlockingTile(x, y - 1, z)) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); spawn = true; if (level->getTile(x, y + 1, z) == id) { - level->setTile(x, y + 1, z, 0); + level->removeTile(x, y + 1, z); } } if (spawn) @@ -274,7 +276,7 @@ void DoorTile::neighborChanged(Level *level, int x, int y, int z, int type) { if (level->getTile(x, y - 1, z) != id) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); } if (type > 0 && type != id) { @@ -339,3 +341,17 @@ int DoorTile::cloneTileId(Level *level, int x, int y, int z) { return material == Material::metal ? Item::door_iron_Id : Item::door_wood_Id; } + +void DoorTile::playerWillDestroy(Level *level, int x, int y, int z, int data, shared_ptr player) +{ + if (player->abilities.instabuild) + { + if ((data & UPPER_BIT) != 0) + { + if (level->getTile(x, y - 1, z) == id) + { + level->removeTile(x, y - 1, z); + } + } + } +} \ No newline at end of file diff --git a/Minecraft.World/DoorTile.h b/Minecraft.World/DoorTile.h index 59a8b414..a4e4f62f 100644 --- a/Minecraft.World/DoorTile.h +++ b/Minecraft.World/DoorTile.h @@ -10,6 +10,11 @@ class DoorTile : public Tile { friend class Tile; friend class ChunkRebuildData; + +private: + static const int TEXTURE_NORMAL = 0; + static const int TEXTURE_FLIPPED = 1; + public: static const int UPPER_BIT = 8; static const int C_DIR_MASK = 3; @@ -22,16 +27,15 @@ private: static const int DOOR_TILE_TEXTURE_COUNT = 4; static const wstring TEXTURES[]; int texBase; - Icon **icons; + Icon *iconTop[2]; + Icon *iconBottom[2]; protected: DoorTile(int id, Material *material); public: virtual Icon *getTexture(int face, int data); - //@Override - Icon *getTexture(LevelSource *level, int x, int y, int z, int face); - //@Override - void registerIcons(IconRegister *iconRegister); + virtual Icon *getTexture(LevelSource *level, int x, int y, int z, int face); + virtual void registerIcons(IconRegister *iconRegister); virtual bool blocksLight(); virtual bool isSolidRender(bool isServerLevel = false); virtual bool isCubeShaped(); @@ -57,4 +61,5 @@ public: virtual int getPistonPushReaction(); int getCompositeData(LevelSource *level, int x, int y, int z); virtual int cloneTileId(Level *level, int x, int y, int z); + virtual void playerWillDestroy(Level *level, int x, int y, int z, int data, shared_ptr player); }; diff --git a/Minecraft.World/DoubleTag.h b/Minecraft.World/DoubleTag.h index 130c3ebb..1f768d5b 100644 --- a/Minecraft.World/DoubleTag.h +++ b/Minecraft.World/DoubleTag.h @@ -10,7 +10,7 @@ public: DoubleTag(const wstring &name, double data) : Tag(name) {this->data = data; } void write(DataOutput *dos) { dos->writeDouble(data); } - void load(DataInput *dis) { data = dis->readDouble(); } + void load(DataInput *dis, int tagDepth) { data = dis->readDouble(); } byte getId() { return TAG_Double; } wstring toString() diff --git a/Minecraft.World/DragonFireball.cpp b/Minecraft.World/DragonFireball.cpp index e3b5d579..32524592 100644 --- a/Minecraft.World/DragonFireball.cpp +++ b/Minecraft.World/DragonFireball.cpp @@ -17,7 +17,7 @@ DragonFireball::DragonFireball(Level *level) : Fireball(level) setSize(5 / 16.0f, 5 / 16.0f); } -DragonFireball::DragonFireball(Level *level, shared_ptr mob, double xa, double ya, double za) : Fireball(level, mob, xa, ya, za) +DragonFireball::DragonFireball(Level *level, shared_ptr mob, double xa, double ya, double za) : Fireball(level, mob, xa, ya, za) { setSize(5 / 16.0f, 5 / 16.0f); } @@ -32,7 +32,7 @@ void DragonFireball::onHit(HitResult *res) if (!level->isClientSide) { AABB *aoe = bb->grow(SPLASH_RANGE, SPLASH_RANGE / 2, SPLASH_RANGE); - vector > *entitiesOfClass = level->getEntitiesOfClass(typeid(Mob), aoe); + vector > *entitiesOfClass = level->getEntitiesOfClass(typeid(LivingEntity), aoe); if (entitiesOfClass != NULL && !entitiesOfClass->empty()) { @@ -40,7 +40,7 @@ void DragonFireball::onHit(HitResult *res) for( AUTO_VAR(it, entitiesOfClass->begin()); it != entitiesOfClass->end(); ++it) { //shared_ptr e = *it; - shared_ptr e = dynamic_pointer_cast( *it ); + shared_ptr e = dynamic_pointer_cast( *it ); double dist = distanceToSqr(e); if (dist < SPLASH_RANGE_SQ) { @@ -65,22 +65,17 @@ bool DragonFireball::isPickable() return false; } -bool DragonFireball::hurt(DamageSource *source, int damage) +bool DragonFireball::hurt(DamageSource *source, float damage) { return false; } -bool DragonFireball::shouldBurn() -{ - return false; -} - -int DragonFireball::getIcon() +ePARTICLE_TYPE DragonFireball::getTrailParticleType() { - return 15 + 14 * 16; + return eParticleType_dragonbreath; } -ePARTICLE_TYPE DragonFireball::getTrailParticleType() +bool DragonFireball::shouldBurn() { - return eParticleType_dragonbreath; + return false; } \ No newline at end of file diff --git a/Minecraft.World/DragonFireball.h b/Minecraft.World/DragonFireball.h index 9ce199ed..a7fe1f1f 100644 --- a/Minecraft.World/DragonFireball.h +++ b/Minecraft.World/DragonFireball.h @@ -18,7 +18,7 @@ private: public: DragonFireball(Level *level); - DragonFireball(Level *level, shared_ptr mob, double xa, double ya, double za); + DragonFireball(Level *level, shared_ptr mob, double xa, double ya, double za); DragonFireball(Level *level, double x, double y, double z, double xa, double ya, double za); protected: @@ -26,12 +26,11 @@ protected: public: virtual bool isPickable(); - virtual bool hurt(DamageSource *source, int damage); - - virtual bool shouldBurn(); - virtual int getIcon(); + virtual bool hurt(DamageSource *source, float damage); protected: // 4J Added TU9 virtual ePARTICLE_TYPE getTrailParticleType(); + + virtual bool shouldBurn(); }; \ No newline at end of file diff --git a/Minecraft.World/DropperTile.cpp b/Minecraft.World/DropperTile.cpp new file mode 100644 index 00000000..a28228c9 --- /dev/null +++ b/Minecraft.World/DropperTile.cpp @@ -0,0 +1,74 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.h" +#include "net.minecraft.world.h" +#include "net.minecraft.core.h" +#include "DropperTile.h" + +DropperTile::DropperTile(int id) : DispenserTile(id) +{ + DISPENSE_BEHAVIOUR = new DefaultDispenseItemBehavior(); +} + +void DropperTile::registerIcons(IconRegister *iconRegister) +{ + icon = iconRegister->registerIcon(L"furnace_side"); + iconTop = iconRegister->registerIcon(L"furnace_top"); + iconFront = iconRegister->registerIcon(getIconName() + L"_front_horizontal"); + iconFrontVertical = iconRegister->registerIcon(getIconName() + L"_front_vertical"); +} + +DispenseItemBehavior *DropperTile::getDispenseMethod(shared_ptr item) +{ + return DISPENSE_BEHAVIOUR; +} + +shared_ptr DropperTile::newTileEntity(Level *level) +{ + return shared_ptr( new DropperTileEntity() ); +} + +void DropperTile::dispenseFrom(Level *level, int x, int y, int z) +{ + BlockSourceImpl source(level, x, y, z); + shared_ptr trap = dynamic_pointer_cast( source.getEntity() ); + if (trap == NULL) return; + + int slot = trap->getRandomSlot(); + if (slot < 0) + { + level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); + } + else + { + shared_ptr item = trap->getItem(slot); + int face = level->getData(x, y, z) & DispenserTile::FACING_MASK; + shared_ptr into = HopperTileEntity::getContainerAt(level, x + Facing::STEP_X[face], y + Facing::STEP_Y[face], z + Facing::STEP_Z[face]); + shared_ptr remaining = nullptr; + + if (into != NULL) + { + remaining = HopperTileEntity::addItem(into.get(), item->copy()->remove(1), Facing::OPPOSITE_FACING[face]); + + if (remaining == NULL) + { + remaining = item->copy(); + if (--remaining->count == 0) remaining = nullptr; + } + else + { + // placing one item failed, so restore original count + remaining = item->copy(); + } + } + else + { + remaining = DISPENSE_BEHAVIOUR->dispense(&source, item); + if (remaining != NULL && remaining->count == 0) remaining = nullptr; + } + + trap->setItem(slot, remaining); + } +} \ No newline at end of file diff --git a/Minecraft.World/DropperTile.h b/Minecraft.World/DropperTile.h new file mode 100644 index 00000000..7769abde --- /dev/null +++ b/Minecraft.World/DropperTile.h @@ -0,0 +1,23 @@ +#pragma once + +#include "DispenserTile.h" + +class DropperTile : public DispenserTile +{ +private: + DispenseItemBehavior *DISPENSE_BEHAVIOUR; + +public: + DropperTile(int id); + + virtual void registerIcons(IconRegister *iconRegister); + +protected: + virtual DispenseItemBehavior *getDispenseMethod(shared_ptr item); + +public: + virtual shared_ptr newTileEntity(Level *level); + +protected: + virtual void dispenseFrom(Level *level, int x, int y, int z); +}; \ No newline at end of file diff --git a/Minecraft.World/DropperTileEntity.cpp b/Minecraft.World/DropperTileEntity.cpp new file mode 100644 index 00000000..51bf6abf --- /dev/null +++ b/Minecraft.World/DropperTileEntity.cpp @@ -0,0 +1,19 @@ +#include "stdafx.h" + +#include "DropperTileEntity.h" + +wstring DropperTileEntity::getName() +{ + return hasCustomName() ? name : app.GetString(IDS_CONTAINER_DROPPER); +} + +// 4J Added +shared_ptr DropperTileEntity::clone() +{ + shared_ptr result = shared_ptr( new DropperTileEntity() ); + TileEntity::clone(result); + + result->name = name; + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/DropperTileEntity.h b/Minecraft.World/DropperTileEntity.h new file mode 100644 index 00000000..d04113c8 --- /dev/null +++ b/Minecraft.World/DropperTileEntity.h @@ -0,0 +1,15 @@ +#pragma once + +#include "DispenserTileEntity.h" + +class DropperTileEntity : public DispenserTileEntity +{ +public: + eINSTANCEOF GetType() { return eTYPE_DROPPERTILEENTITY; } + static TileEntity *create() { return new DropperTileEntity(); } + // 4J Added + virtual shared_ptr clone(); + +public: + wstring getName(); +}; \ No newline at end of file diff --git a/Minecraft.World/DummyCriteria.cpp b/Minecraft.World/DummyCriteria.cpp new file mode 100644 index 00000000..5ae7dad9 --- /dev/null +++ b/Minecraft.World/DummyCriteria.cpp @@ -0,0 +1,24 @@ +#include "stdafx.h" + +#include "DummyCriteria.h" + +DummyCriteria::DummyCriteria(const wstring &name) +{ + this->name = name; + ObjectiveCriteria::CRITERIA_BY_NAME[name] = this; +} + +wstring DummyCriteria::getName() +{ + return name; +} + +int DummyCriteria::getScoreModifier(vector > *players) +{ + return 0; +} + +bool DummyCriteria::isReadOnly() +{ + return false; +} \ No newline at end of file diff --git a/Minecraft.World/DummyCriteria.h b/Minecraft.World/DummyCriteria.h new file mode 100644 index 00000000..6d2fc12c --- /dev/null +++ b/Minecraft.World/DummyCriteria.h @@ -0,0 +1,16 @@ +#pragma once + +#include "ObjectiveCriteria.h" + +class DummyCriteria : public ObjectiveCriteria +{ +private: + wstring name; + +public: + DummyCriteria(const wstring &name); + + virtual wstring getName(); + virtual int getScoreModifier(vector > *players); + virtual bool isReadOnly(); +}; \ No newline at end of file diff --git a/Minecraft.World/DungeonFeature.cpp b/Minecraft.World/DungeonFeature.cpp index cefc49ca..6c7dc673 100644 --- a/Minecraft.World/DungeonFeature.cpp +++ b/Minecraft.World/DungeonFeature.cpp @@ -10,182 +10,182 @@ void DungeonFeature::addRoom(int xOffs, int zOffs, byteArray blocks, double xRoo void DungeonFeature::addTunnel(int xOffs, int zOffs, byteArray blocks, double xCave, double yCave, double zCave, float thickness, float yRot, float xRot, int step, int dist, double yScale) { - double xMid = xOffs * 16 + 8; - double zMid = zOffs * 16 + 8; + double xMid = xOffs * 16 + 8; + double zMid = zOffs * 16 + 8; - float yRota = 0; - float xRota = 0; - Random *random = new Random(this->random->nextLong()); + float yRota = 0; + float xRota = 0; + Random *random = new Random(this->random->nextLong()); - if (dist <= 0) + if (dist <= 0) { - int max = radius * 16 - 16; - dist = max - random->nextInt(max / 4); - } - bool singleStep = false; + int max = radius * 16 - 16; + dist = max - random->nextInt(max / 4); + } + bool singleStep = false; - if (step == -1) + if (step == -1) { - step = dist / 2; - singleStep = true; - } + step = dist / 2; + singleStep = true; + } - int splitPoint = random->nextInt(dist / 2) + dist / 4; - bool steep = random->nextInt(6) == 0; + int splitPoint = random->nextInt(dist / 2) + dist / 4; + bool steep = random->nextInt(6) == 0; - for (; step < dist; step++) + for (; step < dist; step++) { - double rad = 1.5 + (Mth::sin(step * PI / dist) * thickness) * 1; - double yRad = rad * yScale; + double rad = 1.5 + (Mth::sin(step * PI / dist) * thickness) * 1; + double yRad = rad * yScale; - float xc = Mth::cos(xRot); - float xs = Mth::sin(xRot); - xCave += Mth::cos(yRot) * xc; - yCave += xs; - zCave += Mth::sin(yRot) * xc; + float xc = Mth::cos(xRot); + float xs = Mth::sin(xRot); + xCave += Mth::cos(yRot) * xc; + yCave += xs; + zCave += Mth::sin(yRot) * xc; - if (steep) + if (steep) { - xRot *= 0.92f; - } + xRot *= 0.92f; + } else { - xRot *= 0.7f; - } - xRot += xRota * 0.1f; - yRot += yRota * 0.1f; + xRot *= 0.7f; + } + xRot += xRota * 0.1f; + yRot += yRota * 0.1f; - xRota *= 0.90f; - yRota *= 0.75f; - xRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 2; - yRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 4; + xRota *= 0.90f; + yRota *= 0.75f; + xRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 2; + yRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 4; - if (!singleStep && step == splitPoint && thickness > 1) + if (!singleStep && step == splitPoint && thickness > 1) { - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random->nextFloat() * 0.5f + 0.5f, yRot - PI / 2, xRot / 3, step, dist, 1.0); - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random->nextFloat() * 0.5f + 0.5f, yRot + PI / 2, xRot / 3, step, dist, 1.0); - return; - } - if (!singleStep && random->nextInt(4) == 0) continue; - - { - double xd = xCave - xMid; - double zd = zCave - zMid; - double remaining = dist - step; - double rr = (thickness + 2) + 16; - if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) + addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random->nextFloat() * 0.5f + 0.5f, yRot - PI / 2, xRot / 3, step, dist, 1.0); + addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random->nextFloat() * 0.5f + 0.5f, yRot + PI / 2, xRot / 3, step, dist, 1.0); + return; + } + if (!singleStep && random->nextInt(4) == 0) continue; + + { + double xd = xCave - xMid; + double zd = zCave - zMid; + double remaining = dist - step; + double rr = (thickness + 2) + 16; + if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) { - return; - } - } + return; + } + } - if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; + if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; - int x0 = Mth::floor(xCave - rad) - xOffs * 16 - 1; - int x1 = Mth::floor(xCave + rad) - xOffs * 16 + 1; + int x0 = Mth::floor(xCave - rad) - xOffs * 16 - 1; + int x1 = Mth::floor(xCave + rad) - xOffs * 16 + 1; - int y0 = Mth::floor(yCave - yRad) - 1; - int y1 = Mth::floor(yCave + yRad) + 1; + int y0 = Mth::floor(yCave - yRad) - 1; + int y1 = Mth::floor(yCave + yRad) + 1; - int z0 = Mth::floor(zCave - rad) - zOffs * 16 - 1; - int z1 = Mth::floor(zCave + rad) - zOffs * 16 + 1; + int z0 = Mth::floor(zCave - rad) - zOffs * 16 - 1; + int z1 = Mth::floor(zCave + rad) - zOffs * 16 + 1; - if (x0 < 0) x0 = 0; - if (x1 > 16) x1 = 16; + if (x0 < 0) x0 = 0; + if (x1 > 16) x1 = 16; - if (y0 < 1) y0 = 1; - if (y1 > Level::genDepth - 8) y1 = Level::genDepth - 8; + if (y0 < 1) y0 = 1; + if (y1 > Level::genDepth - 8) y1 = Level::genDepth - 8; - if (z0 < 0) z0 = 0; - if (z1 > 16) z1 = 16; + if (z0 < 0) z0 = 0; + if (z1 > 16) z1 = 16; - bool detectedWater = false; - for (int xx = x0; !detectedWater && xx < x1; xx++) + bool detectedWater = false; + for (int xx = x0; !detectedWater && xx < x1; xx++) { - for (int zz = z0; !detectedWater && zz < z1; zz++) + for (int zz = z0; !detectedWater && zz < z1; zz++) { - for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) + for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) { - int p = (xx * 16 + zz) * Level::genDepth + yy; + int p = (xx * 16 + zz) * Level::genDepth + yy; if (yy < 0 || yy >= Level::genDepth) continue; - if (blocks[p] == Tile::water_Id || blocks[p] == Tile::calmWater_Id) + if (blocks[p] == Tile::water_Id || blocks[p] == Tile::calmWater_Id) { - detectedWater = true; - } - if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) + detectedWater = true; + } + if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) { - yy = y0; - } - } - } - } - if (detectedWater) continue; - - for (int xx = x0; xx < x1; xx++) + yy = y0; + } + } + } + } + if (detectedWater) continue; + + for (int xx = x0; xx < x1; xx++) { - double xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; - for (int zz = z0; zz < z1; zz++) + double xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; + for (int zz = z0; zz < z1; zz++) { - double zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; - int p = (xx * 16 + zz) * Level::genDepth + y1; - bool hasGrass = false; - for (int yy = y1 - 1; yy >= y0; yy--) + double zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; + int p = (xx * 16 + zz) * Level::genDepth + y1; + bool hasGrass = false; + for (int yy = y1 - 1; yy >= y0; yy--) { - double yd = (yy + 0.5 - yCave) / yRad; - if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) + double yd = (yy + 0.5 - yCave) / yRad; + if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) { - int block = blocks[p]; - if (block == Tile::grass_Id) hasGrass = true; - if (block == Tile::rock_Id || block == Tile::dirt_Id || block == Tile::grass_Id) + int block = blocks[p]; + if (block == Tile::grass_Id) hasGrass = true; + if (block == Tile::stone_Id || block == Tile::dirt_Id || block == Tile::grass_Id) { - if (yy < 10) + if (yy < 10) { - blocks[p] = (byte) Tile::lava_Id; - } + blocks[p] = (byte) Tile::lava_Id; + } else { - blocks[p] = (byte) 0; - if (hasGrass && blocks[p - 1] == Tile::dirt_Id) blocks[p - 1] = (byte) Tile::grass_Id; - } - } - } - p--; - } - } - } - if (singleStep) break; - } + blocks[p] = (byte) 0; + if (hasGrass && blocks[p - 1] == Tile::dirt_Id) blocks[p - 1] = (byte) Tile::grass_Id; + } + } + } + p--; + } + } + } + if (singleStep) break; + } } void DungeonFeature::addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks) { - int caves = random->nextInt(random->nextInt(random->nextInt(40) + 1) + 1); - if (random->nextInt(15) != 0) caves = 0; + int caves = random->nextInt(random->nextInt(random->nextInt(40) + 1) + 1); + if (random->nextInt(15) != 0) caves = 0; - for (int cave = 0; cave < caves; cave++) + for (int cave = 0; cave < caves; cave++) { - double xCave = x * 16 + random->nextInt(16); - double yCave = random->nextInt(random->nextInt(Level::genDepth - 8) + 8); - double zCave = z * 16 + random->nextInt(16); + double xCave = x * 16 + random->nextInt(16); + double yCave = random->nextInt(random->nextInt(Level::genDepth - 8) + 8); + double zCave = z * 16 + random->nextInt(16); - int tunnels = 1; - if (random->nextInt(4) == 0) + int tunnels = 1; + if (random->nextInt(4) == 0) { - addRoom(xOffs, zOffs, blocks, xCave, yCave, zCave); - tunnels += random->nextInt(4); - } + addRoom(xOffs, zOffs, blocks, xCave, yCave, zCave); + tunnels += random->nextInt(4); + } - for (int i = 0; i < tunnels; i++) + for (int i = 0; i < tunnels; i++) { - float yRot = random->nextFloat() * PI * 2; - float xRot = ((random->nextFloat() - 0.5f) * 2) / 8; - float thickness = random->nextFloat() * 2 + random->nextFloat(); + float yRot = random->nextFloat() * PI * 2; + float xRot = ((random->nextFloat() - 0.5f) * 2) / 8; + float thickness = random->nextFloat() * 2 + random->nextFloat(); - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 1.0); - } - } + addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 1.0); + } + } } \ No newline at end of file diff --git a/Minecraft.World/DurangoStats.cpp b/Minecraft.World/DurangoStats.cpp index c9b51c84..6e50fd20 100644 --- a/Minecraft.World/DurangoStats.cpp +++ b/Minecraft.World/DurangoStats.cpp @@ -45,8 +45,8 @@ bool DsItemEvent::onLeaderboard(ELeaderboardId leaderboard, eAcquisitionMethod m switch (param->itemId) { case Item::egg_Id: - case Tile::mushroom1_Id: - case Tile::mushroom2_Id: + case Tile::mushroom_brown_Id: + case Tile::mushroom_red_Id: return leaderboard == eLeaderboardId_FARMING; } break; @@ -57,13 +57,13 @@ bool DsItemEvent::onLeaderboard(ELeaderboardId leaderboard, eAcquisitionMethod m case Tile::dirt_Id: case Tile::stoneBrick_Id: case Tile::sand_Id: - case Tile::rock_Id: + case Tile::stone_Id: case Tile::gravel_Id: case Tile::clay_Id: case Tile::obsidian_Id: return leaderboard == eLeaderboardId_MINING; - case Tile::crops_Id: + case Tile::wheat_Id: case Tile::pumpkin_Id: case Tile::reeds_Id: return leaderboard == eLeaderboardId_FARMING; @@ -83,9 +83,9 @@ int DsItemEvent::mergeIds(int itemId) default: return itemId; - case Tile::mushroom1_Id: - case Tile::mushroom2_Id: - return Tile::mushroom1_Id; + case Tile::mushroom_brown_Id: + case Tile::mushroom_red_Id: + return Tile::mushroom_brown_Id; case Tile::dirt_Id: case Tile::grass_Id: @@ -267,11 +267,11 @@ byteArray DsMobKilled::createParamBlob(shared_ptr player, shared_ptrGetType(); - if ( (mobEType == eTYPE_SPIDER) && (mob->rider.lock() != NULL) && (mob->rider.lock()->GetType() == eTYPE_SKELETON) ) + if ( (mobEType == eTYPE_SPIDER) && (mob->rider.lock() != NULL) && (mob->rider.lock()->GetType() == eTYPE_SKELETON) && mob->rider.lock()->isAlive() ) { mob_networking_id = SPIDER_JOCKEY_ID; // Spider jockey only a concept for leaderboards. } - else if ( (mobEType == eTYPE_SKELETON) && (mob->riding != NULL) && (mob->riding->GetType() == eTYPE_SPIDER) ) + else if ( (mobEType == eTYPE_SKELETON) && (mob->riding != NULL) && (mob->riding->GetType() == eTYPE_SPIDER) && mob->riding->isAlive() ) { mob_networking_id = SPIDER_JOCKEY_ID; // Spider jockey only a concept for leaderboards. } @@ -769,7 +769,7 @@ Stat* DurangoStats::get_pigOneM() Stat *DurangoStats::get_cowsMilked() { - return get_itemsCrafted(Item::milk_Id); + return get_itemsCrafted(Item::bucket_milk_Id); } Stat* DurangoStats::get_killMob() @@ -930,7 +930,7 @@ byteArray DurangoStats::getParam_pigOneM(int distance) byteArray DurangoStats::getParam_cowsMilked() { - return DsItemEvent::createParamBlob(DsItemEvent::eAcquisitionMethod_Crafted, Item::milk_Id, 0, 1); + return DsItemEvent::createParamBlob(DsItemEvent::eAcquisitionMethod_Crafted, Item::bucket_milk_Id, 0, 1); } byteArray DurangoStats::getParam_blocksPlaced(int blockId, int data, int count) diff --git a/Minecraft.World/DyePowderItem.cpp b/Minecraft.World/DyePowderItem.cpp index a05b8354..b4ab86fa 100644 --- a/Minecraft.World/DyePowderItem.cpp +++ b/Minecraft.World/DyePowderItem.cpp @@ -62,8 +62,8 @@ const unsigned int DyePowderItem::COLOR_USE_DESCS[] = }; const wstring DyePowderItem::COLOR_TEXTURES[] = -{ L"dyePowder_black", L"dyePowder_red", L"dyePowder_green", L"dyePowder_brown", L"dyePowder_blue", L"dyePowder_purple", L"dyePowder_cyan", L"dyePowder_silver", L"dyePowder_gray", L"dyePowder_pink", -L"dyePowder_lime", L"dyePowder_yellow", L"dyePowder_lightBlue", L"dyePowder_magenta", L"dyePowder_orange", L"dyePowder_white"}; +{ L"black", L"red", L"green", L"brown", L"blue", L"purple", L"cyan", L"silver", L"gray", L"pink", +L"lime", L"yellow", L"light_blue", L"magenta", L"orange", L"white"}; const int DyePowderItem::COLOR_RGB[] = { @@ -73,8 +73,8 @@ const int DyePowderItem::COLOR_RGB[] = 0x51301a, 0x253192, 0x7b2fbe, - 0xababab, 0x287697, + 0xababab, 0x434343, 0xd88198, 0x41cd34, @@ -121,33 +121,42 @@ unsigned int DyePowderItem::getUseDescriptionId(shared_ptr itemIns bool DyePowderItem::useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { - if (!player->mayBuild(x, y, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, itemInstance)) return false; // 4J-PB - Adding a test only version to allow tooltips to be displayed if (itemInstance->getAuxValue() == WHITE) { // bone meal is a fertilizer, so instantly grow trees and stuff - int tile = level->getTile(x, y, z); - if (tile == Tile::sapling_Id) + if (growCrop(itemInstance, level, x, y, z, bTestUseOnOnly)) { - if(!bTestUseOnOnly) - { - if (!level->isClientSide) - { - ((Sapling *) Tile::sapling)->growTree(level, x, y, z, level->random); - itemInstance->count--; - } - } + if (!level->isClientSide) level->levelEvent(LevelEvent::PARTICLES_PLANT_GROWTH, x, y, z, 0); return true; } - else if (tile == Tile::mushroom1_Id || tile == Tile::mushroom2_Id) + } + else if (itemInstance->getAuxValue() == BROWN) + { + // plant cocoa + + int tile = level->getTile(x, y, z); + int data = level->getData(x, y, z); + + if (tile == Tile::treeTrunk_Id && TreeTile::getWoodType(data) == TreeTile::JUNGLE_TRUNK) { + if (face == 0) return false; + if (face == 1) return false; + if (face == 2) z--; + if (face == 3) z++; + if (face == 4) x--; + if (face == 5) x++; + if(!bTestUseOnOnly) { - if (!level->isClientSide) + if (level->isEmptyTile(x, y, z)) { - if (((Mushroom *) Tile::tiles[tile])->growTree(level, x, y, z, level->random)) + int cocoaData = Tile::tiles[Tile::cocoa_Id]->getPlacedOnFaceDataValue(level, x, y, z, face, clickX, clickY, clickZ, 0); + level->setTileAndData(x, y, z, Tile::cocoa_Id, cocoaData, Tile::UPDATE_CLIENTS); + if (!player->abilities.instabuild) { itemInstance->count--; } @@ -155,147 +164,169 @@ bool DyePowderItem::useOn(shared_ptr itemInstance, shared_ptrgetData(x, y, z) == 7) return false; - if(!bTestUseOnOnly) + } + return false; +} + +bool DyePowderItem::growCrop(shared_ptr itemInstance, Level *level, int x, int y, int z, bool bTestUseOnOnly) +{ + int tile = level->getTile(x, y, z); + if (tile == Tile::sapling_Id) + { + if(!bTestUseOnOnly) + { + if (!level->isClientSide) { - if (!level->isClientSide) - { - ((StemTile *) Tile::tiles[tile])->growCropsToMax(level, x, y, z); - itemInstance->count--; - } + if (level->random->nextFloat() < 0.45) ((Sapling *) Tile::sapling)->advanceTree(level, x, y, z, level->random); + itemInstance->count--; } - return true; - } - else if (tile == Tile::carrots_Id || tile == Tile::potatoes_Id) + } + return true; + } + else if (tile == Tile::mushroom_brown_Id || tile == Tile::mushroom_red_Id) + { + if(!bTestUseOnOnly) { - if (level->getData(x, y, z) == 7) return false; - if(!bTestUseOnOnly) + if (!level->isClientSide) { - if (!level->isClientSide) - { - ((CropTile *) Tile::tiles[tile])->growCropsToMax(level, x, y, z); - itemInstance->count--; - } + if (level->random->nextFloat() < 0.4) ((Mushroom *) Tile::tiles[tile])->growTree(level, x, y, z, level->random); + itemInstance->count--; } - return true; } - else if (tile == Tile::crops_Id) + return true; + } + else if (tile == Tile::melonStem_Id || tile == Tile::pumpkinStem_Id) + { + if (level->getData(x, y, z) == 7) return false; + if(!bTestUseOnOnly) { - if (level->getData(x, y, z) == 7) return false; - if(!bTestUseOnOnly) - { - if (!level->isClientSide) - { - ((CropTile *) Tile::crops)->growCropsToMax(level, x, y, z); - itemInstance->count--; - } + if (!level->isClientSide) + { + ((StemTile *) Tile::tiles[tile])->growCrops(level, x, y, z); + itemInstance->count--; } - return true; } - else if (tile == Tile::cocoa_Id) + return true; + } + else if (tile == Tile::carrots_Id || tile == Tile::potatoes_Id) + { + if (level->getData(x, y, z) == 7) return false; + if(!bTestUseOnOnly) { - if(!bTestUseOnOnly) + if (!level->isClientSide) { - if (!level->isClientSide) - { - level->setData(x, y, z, (2 << 2) | DirectionalTile::getDirection(level->getData(x, y, z))); - itemInstance->count--; - } + ((CropTile *) Tile::tiles[tile])->growCrops(level, x, y, z); + itemInstance->count--; } - return true; - } - else if (tile == Tile::grass_Id) + } + return true; + } + else if (tile == Tile::wheat_Id) + { + if (level->getData(x, y, z) == 7) return false; + if(!bTestUseOnOnly) + { + if (!level->isClientSide) + { + ((CropTile *) Tile::tiles[tile])->growCrops(level, x, y, z); + itemInstance->count--; + } + } + return true; + } + else if (tile == Tile::cocoa_Id) + { + if(!bTestUseOnOnly) { - if(!bTestUseOnOnly) - { - if (!level->isClientSide) - { - itemInstance->count--; + int data = level->getData(x, y, z); + int direction = DirectionalTile::getDirection(data); + int age = CocoaTile::getAge(data); + if (age >= 2) return false; + if (!level->isClientSide) + { + age++; + level->setData(x, y, z, (age << 2) | direction, Tile::UPDATE_CLIENTS); + itemInstance->count--; + } + } + return true; + } + else if (tile == Tile::grass_Id) + { + if(!bTestUseOnOnly) + { + if (!level->isClientSide) + { + itemInstance->count--; - for (int j = 0; j < 128; j++) + for (int j = 0; j < 128; j++) + { + int xx = x; + int yy = y + 1; + int zz = z; + for (int i = 0; i < j / 16; i++) { - int xx = x; - int yy = y + 1; - int zz = z; - for (int i = 0; i < j / 16; i++) + xx += random->nextInt(3) - 1; + yy += (random->nextInt(3) - 1) * random->nextInt(3) / 2; + zz += random->nextInt(3) - 1; + if (level->getTile(xx, yy - 1, zz) != Tile::grass_Id || level->isSolidBlockingTile(xx, yy, zz)) { - xx += random->nextInt(3) - 1; - yy += (random->nextInt(3) - 1) * random->nextInt(3) / 2; - zz += random->nextInt(3) - 1; - if (level->getTile(xx, yy - 1, zz) != Tile::grass_Id || level->isSolidBlockingTile(xx, yy, zz)) - { - goto mainloop; - } + goto mainloop; } + } - if (level->getTile(xx, yy, zz) == 0) + if (level->getTile(xx, yy, zz) == 0) + { + if (random->nextInt(10) != 0) + { + if (Tile::tallgrass->canSurvive(level, xx, yy, zz)) level->setTileAndData(xx, yy, zz, Tile::tallgrass_Id, TallGrass::TALL_GRASS, Tile::UPDATE_ALL); + } + else if (random->nextInt(3) != 0) { - if (random->nextInt(10) != 0) - { - if (Tile::tallgrass->canSurvive(level, xx, yy, zz)) level->setTileAndData(xx, yy, zz, Tile::tallgrass_Id, TallGrass::TALL_GRASS); - } - else if (random->nextInt(3) != 0) - { - if (Tile::flower->canSurvive(level, xx, yy, zz)) level->setTile(xx, yy, zz, Tile::flower_Id); - } - else - { - if (Tile::rose->canSurvive(level, xx, yy, zz)) level->setTile(xx, yy, zz, Tile::rose_Id); - } + if (Tile::flower->canSurvive(level, xx, yy, zz)) level->setTileAndUpdate(xx, yy, zz, Tile::flower_Id); + } + else + { + if (Tile::rose->canSurvive(level, xx, yy, zz)) level->setTileAndUpdate(xx, yy, zz, Tile::rose_Id); } + } - // 4J - Stops infinite loops. + // 4J - Stops infinite loops. mainloop: continue; - } } } - - return true; } + + return true; } - else if (itemInstance->getAuxValue() == BROWN) - { - // plant cocoa + return false; +} - int tile = level->getTile(x, y, z); - int data = level->getData(x, y, z); +void DyePowderItem::addGrowthParticles(Level *level, int x, int y, int z, int count) +{ + int id = level->getTile(x, y, z); + if (count == 0) count = 15; + Tile *tile = id > 0 && id < Tile::TILE_NUM_COUNT ? Tile::tiles[id] : NULL; - if (tile == Tile::treeTrunk_Id && TreeTile::getWoodType(data) == TreeTile::JUNGLE_TRUNK) - { - if (face == 0) return false; - if (face == 1) return false; - if (face == 2) z--; - if (face == 3) z++; - if (face == 4) x--; - if (face == 5) x++; + if (tile == NULL) return; + tile->updateShape(level, x, y, z); - if(!bTestUseOnOnly) - { - if (level->isEmptyTile(x, y, z)) - { - int cocoaData = Tile::tiles[Tile::cocoa_Id]->getPlacedOnFaceDataValue(level, x, y, z, face, clickX, clickY, clickZ, 0); - level->setTileAndData(x, y, z, Tile::cocoa_Id, cocoaData); - if (!player->abilities.instabuild) - { - itemInstance->count--; - } - } - } - return true; - } - } - return false; + for (int i = 0; i < count; i++) + { + double xa = level->random->nextGaussian() * 0.02; + double ya = level->random->nextGaussian() * 0.02; + double za = level->random->nextGaussian() * 0.02; + level->addParticle(eParticleType_happyVillager, x + level->random->nextFloat(), y + level->random->nextFloat() * tile->getShapeY1(), z + level->random->nextFloat(), xa, ya, za); + } } -bool DyePowderItem::interactEnemy(shared_ptr itemInstance, shared_ptr mob) +bool DyePowderItem::interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr mob) { if (dynamic_pointer_cast( mob ) != NULL) { shared_ptr sheep = dynamic_pointer_cast(mob); // convert to tile-based color value (0 is white instead of black) - int newColor = ClothTile::getTileDataForItemAuxValue(itemInstance->getAuxValue()); + int newColor = ColoredTile::getTileDataForItemAuxValue(itemInstance->getAuxValue()); if (!sheep->isSheared() && sheep->getColor() != newColor) { sheep->setColor(newColor); @@ -312,6 +343,6 @@ void DyePowderItem::registerIcons(IconRegister *iconRegister) for (int i = 0; i < DYE_POWDER_ITEM_TEXTURE_COUNT; i++) { - icons[i] = iconRegister->registerIcon(COLOR_TEXTURES[i]); + icons[i] = iconRegister->registerIcon(getIconName() + L"_" + COLOR_TEXTURES[i]); } } \ No newline at end of file diff --git a/Minecraft.World/DyePowderItem.h b/Minecraft.World/DyePowderItem.h index b96b4087..270b5424 100644 --- a/Minecraft.World/DyePowderItem.h +++ b/Minecraft.World/DyePowderItem.h @@ -43,7 +43,9 @@ public: virtual unsigned int getDescriptionId(shared_ptr itemInstance); virtual unsigned int getUseDescriptionId(shared_ptr itemInstance); virtual bool useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); - virtual bool interactEnemy(shared_ptr itemInstance, shared_ptr mob); + static bool growCrop(shared_ptr itemInstance, Level *level, int x, int y, int z, bool bTestUseOnOnly); + static void addGrowthParticles(Level *level, int x, int y, int z, int count); + virtual bool interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr mob); //@Override void registerIcons(IconRegister *iconRegister); diff --git a/Minecraft.World/EatTileGoal.cpp b/Minecraft.World/EatTileGoal.cpp index 55bf2f35..c2cbd6bf 100644 --- a/Minecraft.World/EatTileGoal.cpp +++ b/Minecraft.World/EatTileGoal.cpp @@ -11,7 +11,7 @@ EatTileGoal::EatTileGoal(Mob *mob) eatAnimationTick = 0; this->mob = mob; - this->level = mob->level; + level = mob->level; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag | Control::JumpControlFlag); } @@ -60,14 +60,13 @@ void EatTileGoal::tick() if (level->getTile(xx, yy, zz) == Tile::tallgrass_Id) { - level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy, zz, Tile::tallgrass_Id + (TallGrass::TALL_GRASS << Tile::TILE_NUM_SHIFT)); - level->setTile(xx, yy, zz, 0); + level->destroyTile(xx, yy, zz, false); mob->ate(); } else if (level->getTile(xx, yy - 1, zz) == Tile::grass_Id) { level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, xx, yy - 1, zz, Tile::grass_Id); - level->setTile(xx, yy - 1, zz, Tile::dirt_Id); + level->setTileAndData(xx, yy - 1, zz, Tile::dirt_Id, 0, Tile::UPDATE_CLIENTS); mob->ate(); } } \ No newline at end of file diff --git a/Minecraft.World/EffectCommand.cpp b/Minecraft.World/EffectCommand.cpp new file mode 100644 index 00000000..5d708db8 --- /dev/null +++ b/Minecraft.World/EffectCommand.cpp @@ -0,0 +1,86 @@ +#include "stdafx.h" +#include "net.minecraft.commands.common.h" +#include "..\Minecraft.Client\MinecraftServer.h" + +EGameCommand EffectCommand::getId() +{ + return eGameCommand_Effect; +} + +int EffectCommand::getPermissionLevel() +{ + return LEVEL_GAMEMASTERS; +} + +wstring EffectCommand::getUsage(CommandSender *source) +{ + return L"commands.effect.usage"; +} + +void EffectCommand::execute(shared_ptr source, byteArray commandData) +{ + //if (args.length >= 2) + //{ + // Player player = convertToPlayer(source, args[0]); + + // if (args[1].equals("clear")) { + // if (player.getActiveEffects().isEmpty()) { + // throw new CommandException("commands.effect.failure.notActive.all", player.getAName()); + // } else { + // player.removeAllEffects(); + // logAdminAction(source, "commands.effect.success.removed.all", player.getAName()); + // } + // } else { + // int effectId = convertArgToInt(source, args[1], 1); + // int duration = SharedConstants.TICKS_PER_SECOND * 30; + // int seconds = 30; + // int amplifier = 0; + + // if (effectId < 0 || effectId >= MobEffect.effects.length || MobEffect.effects[effectId] == null) { + // throw new InvalidNumberException("commands.effect.notFound", effectId); + // } + + // if (args.length >= 3) { + // seconds = convertArgToInt(source, args[2], 0, 1000000); + // if (MobEffect.effects[effectId].isInstantenous()) { + // duration = seconds; + // } else { + // duration = seconds * SharedConstants.TICKS_PER_SECOND; + // } + // } else if (MobEffect.effects[effectId].isInstantenous()) { + // duration = 1; + // } + + // if (args.length >= 4) { + // amplifier = convertArgToInt(source, args[3], 0, 255); + // } + + // if (seconds == 0) { + // if (player.hasEffect(effectId)) { + // player.removeEffect(effectId); + // logAdminAction(source, "commands.effect.success.removed", ChatMessageComponent.forTranslation(MobEffect.effects[effectId].getDescriptionId()), player.getAName()); + // } else { + // throw new CommandException("commands.effect.failure.notActive", ChatMessageComponent.forTranslation(MobEffect.effects[effectId].getDescriptionId()), player.getAName()); + // } + // } else { + // MobEffectInstance instance = new MobEffectInstance(effectId, duration, amplifier); + // player.addEffect(instance); + // logAdminAction(source, "commands.effect.success", ChatMessageComponent.forTranslation(instance.getDescriptionId()), effectId, amplifier, player.getAName(), seconds); + // } + // } + + // return; + //} + + //throw new UsageException("commands.effect.usage"); +} + +wstring EffectCommand::getPlayerNames() +{ + return L""; //MinecraftServer::getInstance()->getPlayerNames(); +} + +bool EffectCommand::isValidWildcardPlayerArgument(wstring args, int argumentIndex) +{ + return argumentIndex == 0; +} \ No newline at end of file diff --git a/Minecraft.World/EffectCommand.h b/Minecraft.World/EffectCommand.h new file mode 100644 index 00000000..e198d0ac --- /dev/null +++ b/Minecraft.World/EffectCommand.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Command.h" + +class EffectCommand : public Command +{ +public: + EGameCommand getId(); + int getPermissionLevel(); + wstring getUsage(CommandSender *source); + void execute(shared_ptr source, byteArray commandData); + +protected: + wstring getPlayerNames(); + +public: + bool isValidWildcardPlayerArgument(wstring args, int argumentIndex); +}; \ No newline at end of file diff --git a/Minecraft.World/EggItem.cpp b/Minecraft.World/EggItem.cpp index b85dbcd6..0655a2fa 100644 --- a/Minecraft.World/EggItem.cpp +++ b/Minecraft.World/EggItem.cpp @@ -16,7 +16,7 @@ using namespace std; EggItem::EggItem(int id) : Item( id ) { - this->maxStackSize = 16; + maxStackSize = 16; } shared_ptr EggItem::use(shared_ptr instance, Level *level, shared_ptr player) @@ -25,7 +25,7 @@ shared_ptr EggItem::use(shared_ptr instance, Level * { instance->count--; } - level->playSound( dynamic_pointer_cast(player), eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); - if (!level->isClientSide) level->addEntity( shared_ptr( new ThrownEgg(level, dynamic_pointer_cast( player )) )); - return instance; + level->playEntitySound( player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); + if (!level->isClientSide) level->addEntity( shared_ptr(new ThrownEgg(level, player)) ); + return instance; } diff --git a/Minecraft.World/EggTile.cpp b/Minecraft.World/EggTile.cpp index e6711a3f..3a11c0d1 100644 --- a/Minecraft.World/EggTile.cpp +++ b/Minecraft.World/EggTile.cpp @@ -10,12 +10,12 @@ EggTile::EggTile(int id) : Tile(id, Material::egg, isSolidRender()) void EggTile::onPlace(Level *level, int x, int y, int z) { - level->addToTickNextTick(x, y, z, id, getTickDelay()); + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); } void EggTile::neighborChanged(Level *level, int x, int y, int z, int type) { - level->addToTickNextTick(x, y, z, id, getTickDelay()); + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); } void EggTile::tick(Level *level, int x, int y, int z, Random *random) @@ -30,12 +30,12 @@ void EggTile::checkSlide(Level *level, int x, int y, int z) int r = 32; if (HeavyTile::instaFall || !level->hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r)) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); while (HeavyTile::isFree(level, x, y - 1, z) && y > 0) y--; if (y > 0) { - level->setTile(x, y, z, id); + level->setTileAndData(x, y, z, id, 0, Tile::UPDATE_CLIENTS); } } else @@ -50,8 +50,8 @@ bool EggTile::use(Level *level, int x, int y, int z, shared_ptr player, { if(soundOnly) return false; - teleport(level, x, y, z); - return true; + teleport(level, x, y, z); + return true; } void EggTile::attack(Level *level, int x, int y, int z, shared_ptr player) @@ -74,8 +74,8 @@ void EggTile::teleport(Level *level, int x, int y, int z) // Don't set tiles on client, and don't create particles on the server (matches later change in Java) if(!level->isClientSide) { - level->setTileAndData(xt, yt, zt, id, level->getData(x, y, z)); - level->setTile(x, y, z, 0); + level->setTileAndData(xt, yt, zt, id, level->getData(x, y, z), Tile::UPDATE_CLIENTS); + level->removeTile(x, y, z); // 4J Stu - The PC version is wrong as the particles calculated on the client side will point towards a different // location to the one where the egg has actually moved. As the deltas are all small we can pack them into an int @@ -90,31 +90,31 @@ void EggTile::teleport(Level *level, int x, int y, int z) // 4J Stu - This code will not work correctly on the client as it will show the particles going in the wrong direction // and only for the player who attacks the egg - // else - // { - // int count = 128; - // for (int j = 0; j < count; j++) - // { - // double d = level->random->nextDouble(); // j < count / 2 ? 0 : - //// 1; - // float xa = (level->random->nextFloat() - 0.5f) * 0.2f; - // float ya = (level->random->nextFloat() - 0.5f) * 0.2f; - // float za = (level->random->nextFloat() - 0.5f) * 0.2f; - - // double _x = xt + (x - xt) * d + (level->random->nextDouble() - 0.5) * 1 + 0.5f; - // double _y = yt + (y - yt) * d + level->random->nextDouble() * 1 - 0.5f; - // double _z = zt + (z - zt) * d + (level->random->nextDouble() - 0.5) * 1 + 0.5f; - // level->addParticle(eParticleType_ender, _x, _y, _z, xa, ya, za); - // } - // } + // else + // { + // int count = 128; + // for (int j = 0; j < count; j++) + // { + // double d = level->random->nextDouble(); // j < count / 2 ? 0 : + //// 1; + // float xa = (level->random->nextFloat() - 0.5f) * 0.2f; + // float ya = (level->random->nextFloat() - 0.5f) * 0.2f; + // float za = (level->random->nextFloat() - 0.5f) * 0.2f; + + // double _x = xt + (x - xt) * d + (level->random->nextDouble() - 0.5) * 1 + 0.5f; + // double _y = yt + (y - yt) * d + level->random->nextDouble() * 1 - 0.5f; + // double _z = zt + (z - zt) * d + (level->random->nextDouble() - 0.5) * 1 + 0.5f; + // level->addParticle(eParticleType_ender, _x, _y, _z, xa, ya, za); + // } + // } return; } } } -int EggTile::getTickDelay() +int EggTile::getTickDelay(Level *level) { - return 3; + return 5; } bool EggTile::blocksLight() @@ -132,6 +132,11 @@ bool EggTile::isCubeShaped() return false; } +bool EggTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) +{ + return true; +} + int EggTile::getRenderShape() { return Tile::SHAPE_EGG; @@ -165,9 +170,4 @@ void EggTile::generateTeleportParticles(Level *level,int xt,int yt, int zt,int d double _z = zt + deltaZ * d + (level->random->nextDouble() - 0.5) * 1 + 0.5f; level->addParticle(eParticleType_ender, _x, _y, _z, xa, ya, za); } -} - -bool EggTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) -{ - return true; } \ No newline at end of file diff --git a/Minecraft.World/EggTile.h b/Minecraft.World/EggTile.h index c8929cbe..354a4436 100644 --- a/Minecraft.World/EggTile.h +++ b/Minecraft.World/EggTile.h @@ -5,23 +5,23 @@ class EggTile : public Tile { public: EggTile(int id); - virtual void onPlace(Level *level, int x, int y, int z); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); - virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual void onPlace(Level *level, int x, int y, int z); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual void tick(Level *level, int x, int y, int z, Random *random); private: void checkSlide(Level *level, int x, int y, int z); public: virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - virtual void attack(Level *level, int x, int y, int z, shared_ptr player); + virtual void attack(Level *level, int x, int y, int z, shared_ptr player); private: void teleport(Level *level, int x, int y, int z); public: - virtual int getTickDelay(); - virtual bool blocksLight(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); + virtual int getTickDelay(Level *level); + virtual bool blocksLight(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); - virtual int getRenderShape(); + virtual int getRenderShape(); virtual int cloneTileId(Level *level, int x, int y, int z); // 4J Added diff --git a/Minecraft.World/EmptyLevelChunk.cpp b/Minecraft.World/EmptyLevelChunk.cpp index 80460b10..1353ca4d 100644 --- a/Minecraft.World/EmptyLevelChunk.cpp +++ b/Minecraft.World/EmptyLevelChunk.cpp @@ -26,7 +26,7 @@ bool EmptyLevelChunk::isAt(int x, int z) int EmptyLevelChunk::getHeightmap(int x, int z) { - return 0; + return 0; } void EmptyLevelChunk::recalcBlockLights() @@ -140,15 +140,20 @@ void EmptyLevelChunk::unload(bool unloadTileEntities) // 4J - added parameter { } +bool EmptyLevelChunk::containsPlayer() +{ + return false; +} + void EmptyLevelChunk::markUnsaved() { } -void EmptyLevelChunk::getEntities(shared_ptr except, AABB bb, vector > &es) +void EmptyLevelChunk::getEntities(shared_ptr except, AABB bb, vector > &es, EntitySelector *selector) { } -void EmptyLevelChunk::getEntitiesOfClass(const type_info& ec, AABB bb, vector > &es) +void EmptyLevelChunk::getEntitiesOfClass(const type_info& ec, AABB bb, vector > &es, EntitySelector *selector) { } @@ -168,12 +173,12 @@ void EmptyLevelChunk::setBlocks(byteArray newBlocks, int sub) int EmptyLevelChunk::getBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, int y1, int z1, int p, bool includeLighting/* = true*/) { - int xs = x1 - x0; - int ys = y1 - y0; - int zs = z1 - z0; + int xs = x1 - x0; + int ys = y1 - y0; + int zs = z1 - z0; - int s = xs * ys * zs; - int len; + int s = xs * ys * zs; + int len; if( includeLighting ) { len = s + s / 2 * 3; @@ -184,20 +189,20 @@ int EmptyLevelChunk::getBlocksAndData(byteArray data, int x0, int y0, int z0, in } - Arrays::fill(data, p, p + len, (byte) 0); - return len; + Arrays::fill(data, p, p + len, (byte) 0); + return len; } int EmptyLevelChunk::setBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, int y1, int z1, int p, bool includeLighting/* = true*/) { - int xs = x1 - x0; - int ys = y1 - y0; - int zs = z1 - z0; + int xs = x1 - x0; + int ys = y1 - y0; + int zs = z1 - z0; - int s = xs * ys * zs; + int s = xs * ys * zs; if( includeLighting ) { - return s + s / 2 * 3; + return s + s / 2 * 3; } else { diff --git a/Minecraft.World/EmptyLevelChunk.h b/Minecraft.World/EmptyLevelChunk.h index 02ffc176..06bffea9 100644 --- a/Minecraft.World/EmptyLevelChunk.h +++ b/Minecraft.World/EmptyLevelChunk.h @@ -39,9 +39,10 @@ public: void removeTileEntity(int x, int y, int z); void load(); void unload(bool unloadTileEntities) ; // 4J - added parameter + bool containsPlayer(); // 4J added void markUnsaved(); - void getEntities(shared_ptr except, AABB bb, vector > &es); - void getEntitiesOfClass(const type_info& ec, AABB bb, vector > &es); + void getEntities(shared_ptr except, AABB bb, vector > &es, EntitySelector *selector); + void getEntitiesOfClass(const type_info& ec, AABB bb, vector > &es, EntitySelector *selector); int countEntities(); bool shouldSave(bool force); void setBlocks(byteArray newBlocks, int sub); diff --git a/Minecraft.World/EmptyMapItem.cpp b/Minecraft.World/EmptyMapItem.cpp new file mode 100644 index 00000000..42adc304 --- /dev/null +++ b/Minecraft.World/EmptyMapItem.cpp @@ -0,0 +1,43 @@ +#include "stdafx.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.entity.player.h" +#include "EmptyMapItem.h" + +EmptyMapItem::EmptyMapItem(int id) : ComplexItem(id) +{ +} + +shared_ptr EmptyMapItem::use(shared_ptr itemInstance, Level *level, shared_ptr player) +{ + //shared_ptr map = shared_ptr( new ItemInstance(Item::map, 1, level->getFreeAuxValueFor(L"map")) ); + + //String id = "map_" + map.getAuxValue(); + //MapItemSavedData data = new MapItemSavedData(id); + //level.setSavedData(id, data); + + //data.scale = 0; + //int scale = MapItemSavedData.MAP_SIZE * 2 * (1 << data.scale); + //data.x = (int) (Math.round(player.x / scale) * scale); + //data.z = (int) (Math.round(player.z / scale) * scale); + //data.dimension = (byte) level.dimension.id; + + //data.setDirty(); + + shared_ptr map = shared_ptr( new ItemInstance(Item::map, 1, -1) ); + Item::map->onCraftedBy(map, level, player); + + itemInstance->count--; + if (itemInstance->count <= 0) + { + return map; + } + else + { + if (!player->inventory->add(map->copy())) + { + player->drop(map); + } + } + + return itemInstance; +} \ No newline at end of file diff --git a/Minecraft.World/EmptyMapItem.h b/Minecraft.World/EmptyMapItem.h new file mode 100644 index 00000000..825111d0 --- /dev/null +++ b/Minecraft.World/EmptyMapItem.h @@ -0,0 +1,11 @@ +#pragma once + +#include "ComplexItem.h" + +class EmptyMapItem : public ComplexItem +{ +public: + EmptyMapItem(int id); + + shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); +}; \ No newline at end of file diff --git a/Minecraft.World/EnchantItemCommand.cpp b/Minecraft.World/EnchantItemCommand.cpp index aa02b533..7ec57563 100644 --- a/Minecraft.World/EnchantItemCommand.cpp +++ b/Minecraft.World/EnchantItemCommand.cpp @@ -12,7 +12,7 @@ EGameCommand EnchantItemCommand::getId() int EnchantItemCommand::getPermissionLevel() { - return 0; //aLEVEL_GAMEMASTERS; + return LEVEL_GAMEMASTERS; } void EnchantItemCommand::execute(shared_ptr source, byteArray commandData) diff --git a/Minecraft.World/EnchantedBookItem.cpp b/Minecraft.World/EnchantedBookItem.cpp index 59e7156b..88776c18 100644 --- a/Minecraft.World/EnchantedBookItem.cpp +++ b/Minecraft.World/EnchantedBookItem.cpp @@ -43,9 +43,9 @@ ListTag *EnchantedBookItem::getEnchantments(shared_ptr *) item->tag->get((wchar_t *)TAG_STORED_ENCHANTMENTS.c_str()); } -void EnchantedBookItem::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced, vector &unformattedStrings) +void EnchantedBookItem::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced) { - Item::appendHoverText(itemInstance, player, lines, advanced, unformattedStrings); + Item::appendHoverText(itemInstance, player, lines, advanced); ListTag *list = getEnchantments(itemInstance); @@ -59,8 +59,7 @@ void EnchantedBookItem::appendHoverText(shared_ptr itemInstance, s if (Enchantment::enchantments[type] != NULL) { - lines->push_back(Enchantment::enchantments[type]->getFullname(level, unformatted)); - unformattedStrings.push_back(unformatted); + lines->push_back(Enchantment::enchantments[type]->getFullname(level)); } } } diff --git a/Minecraft.World/EnchantedBookItem.h b/Minecraft.World/EnchantedBookItem.h index c67f208f..9296f3c3 100644 --- a/Minecraft.World/EnchantedBookItem.h +++ b/Minecraft.World/EnchantedBookItem.h @@ -15,7 +15,7 @@ public: bool isEnchantable(shared_ptr itemInstance); const Rarity *getRarity(shared_ptr itemInstance); ListTag *getEnchantments(shared_ptr item); - void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced, vector &unformattedStrings); + void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced); void addEnchantment(shared_ptr item, EnchantmentInstance *enchantment); shared_ptr createForEnchantment(EnchantmentInstance *enchant); void createForEnchantment(Enchantment *enchant, vector > *items); diff --git a/Minecraft.World/Enchantment.cpp b/Minecraft.World/Enchantment.cpp index 2ce1441a..ae638b27 100644 --- a/Minecraft.World/Enchantment.cpp +++ b/Minecraft.World/Enchantment.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "net.minecraft.world.item.enchantment.h" +#include "net.minecraft.world.item.h" #include "Enchantment.h" //Enchantment *Enchantment::enchantments[256]; @@ -129,9 +130,9 @@ int Enchantment::getDamageProtection(int level, DamageSource *source) return 0; } -int Enchantment::getDamageBonus(int level, shared_ptr target) +float Enchantment::getDamageBonus(int level, shared_ptr target) { - return 0; + return 0.0f; } bool Enchantment::isCompatibleWith(Enchantment *other) const @@ -150,13 +151,12 @@ int Enchantment::getDescriptionId() return descriptionId; } -wstring Enchantment::getFullname(int level,wstring &unformatted) +HtmlString Enchantment::getFullname(int level) { wchar_t formatted[256]; - swprintf(formatted,256,L"%ls %ls",app.GetString( getDescriptionId() ), getLevelString(level).c_str()); - unformatted = formatted; - swprintf(formatted,256,L"%ls",app.GetHTMLColour(eHTMLColor_f),unformatted.c_str()); - return formatted; + swprintf(formatted, 256, L"%ls %ls", app.GetString(getDescriptionId()), getLevelString(level).c_str()); + + return HtmlString(formatted, eHTMLColor_f); } bool Enchantment::canEnchant(shared_ptr item) diff --git a/Minecraft.World/Enchantment.h b/Minecraft.World/Enchantment.h index 794edf85..7daa1a37 100644 --- a/Minecraft.World/Enchantment.h +++ b/Minecraft.World/Enchantment.h @@ -74,11 +74,11 @@ public: virtual int getMinCost(int level); virtual int getMaxCost(int level); virtual int getDamageProtection(int level, DamageSource *source); - virtual int getDamageBonus(int level, shared_ptr target); + virtual float getDamageBonus(int level, shared_ptr target); virtual bool isCompatibleWith(Enchantment *other) const; virtual Enchantment *setDescriptionId(int id); virtual int getDescriptionId(); - virtual wstring getFullname(int level,wstring &unformatted); // 4J Stu added unformatted + virtual HtmlString getFullname(int level); virtual bool canEnchant(shared_ptr item); private: diff --git a/Minecraft.World/EnchantmentContainer.cpp b/Minecraft.World/EnchantmentContainer.cpp index 6e5541fb..166e8d5f 100644 --- a/Minecraft.World/EnchantmentContainer.cpp +++ b/Minecraft.World/EnchantmentContainer.cpp @@ -2,7 +2,7 @@ #include "net.minecraft.world.inventory.h" #include "EnchantmentContainer.h" -EnchantmentContainer::EnchantmentContainer(EnchantmentMenu *menu) : SimpleContainer(IDS_ENCHANT, 1), m_menu( menu ) +EnchantmentContainer::EnchantmentContainer(EnchantmentMenu *menu) : SimpleContainer(IDS_ENCHANT, L"", false, 1), m_menu( menu ) { } @@ -15,4 +15,9 @@ void EnchantmentContainer::setChanged() { SimpleContainer::setChanged(); m_menu->slotsChanged(); // Remove this param as it's not needed +} + +bool EnchantmentContainer::canPlaceItem(int slot, shared_ptr item) +{ + return true; } \ No newline at end of file diff --git a/Minecraft.World/EnchantmentContainer.h b/Minecraft.World/EnchantmentContainer.h index 48d8687f..8b337f48 100644 --- a/Minecraft.World/EnchantmentContainer.h +++ b/Minecraft.World/EnchantmentContainer.h @@ -15,4 +15,5 @@ public: EnchantmentContainer(EnchantmentMenu *menu); virtual int getMaxStackSize(); virtual void setChanged(); + virtual bool canPlaceItem(int slot, shared_ptr item); }; \ No newline at end of file diff --git a/Minecraft.World/EnchantmentHelper.cpp b/Minecraft.World/EnchantmentHelper.cpp index f43ced01..da784d5a 100644 --- a/Minecraft.World/EnchantmentHelper.cpp +++ b/Minecraft.World/EnchantmentHelper.cpp @@ -88,6 +88,7 @@ void EnchantmentHelper::setEnchantments(unordered_map *enchantments, s int EnchantmentHelper::getEnchantmentLevel(int enchantmentId, ItemInstanceArray inventory) { + if (inventory.data == NULL) return 0; int bestLevel = 0; //for (ItemInstance piece : inventory) for(unsigned int i = 0; i < inventory.length; ++i) @@ -147,12 +148,12 @@ EnchantmentHelper::GetDamageProtectionIteration EnchantmentHelper::getDamageProt * @param source * @return */ -int EnchantmentHelper::getDamageProtection(shared_ptr inventory, DamageSource *source) +int EnchantmentHelper::getDamageProtection(ItemInstanceArray armor, DamageSource *source) { getDamageProtectionIteration.sum = 0; getDamageProtectionIteration.source = source; - runIterationOnInventory(getDamageProtectionIteration, inventory->armor); + runIterationOnInventory(getDamageProtectionIteration, armor); if (getDamageProtectionIteration.sum > 25) { @@ -177,72 +178,68 @@ EnchantmentHelper::GetDamageBonusIteration EnchantmentHelper::getDamageBonusIter * @param target * @return */ -int EnchantmentHelper::getDamageBonus(shared_ptr inventory, shared_ptr target) +float EnchantmentHelper::getDamageBonus(shared_ptr source, shared_ptr target) { getDamageBonusIteration.sum = 0; getDamageBonusIteration.target = target; - runIterationOnItem(getDamageBonusIteration, inventory->getSelected()); + runIterationOnItem(getDamageBonusIteration, source->getCarriedItem() ); - if (getDamageBonusIteration.sum > 0) - { - return 1 + random.nextInt(getDamageBonusIteration.sum); - } - return 0; + return getDamageBonusIteration.sum; } -int EnchantmentHelper::getKnockbackBonus(shared_ptr inventory, shared_ptr target) +int EnchantmentHelper::getKnockbackBonus(shared_ptr source, shared_ptr target) { - return getEnchantmentLevel(Enchantment::knockback->id, inventory->getSelected()); + return getEnchantmentLevel(Enchantment::knockback->id, source->getCarriedItem() ); } -int EnchantmentHelper::getFireAspect(shared_ptr source) +int EnchantmentHelper::getFireAspect(shared_ptr source) { return getEnchantmentLevel(Enchantment::fireAspect->id, source->getCarriedItem()); } -int EnchantmentHelper::getOxygenBonus(shared_ptr inventory) +int EnchantmentHelper::getOxygenBonus(shared_ptr source) { - return getEnchantmentLevel(Enchantment::drownProtection->id, inventory->armor); + return getEnchantmentLevel(Enchantment::drownProtection->id, source->getEquipmentSlots() ); } -int EnchantmentHelper::getDiggingBonus(shared_ptr inventory) +int EnchantmentHelper::getDiggingBonus(shared_ptr source) { - return getEnchantmentLevel(Enchantment::diggingBonus->id, inventory->getSelected()); + return getEnchantmentLevel(Enchantment::diggingBonus->id, source->getCarriedItem() ); } -int EnchantmentHelper::getDigDurability(shared_ptr inventory) +int EnchantmentHelper::getDigDurability(shared_ptr source) { - return getEnchantmentLevel(Enchantment::digDurability->id, inventory->getSelected()); + return getEnchantmentLevel(Enchantment::digDurability->id, source->getCarriedItem() ); } -bool EnchantmentHelper::hasSilkTouch(shared_ptr inventory) +bool EnchantmentHelper::hasSilkTouch(shared_ptr source) { - return getEnchantmentLevel(Enchantment::untouching->id, inventory->getSelected()) > 0; + return getEnchantmentLevel(Enchantment::untouching->id, source->getCarriedItem() ) > 0; } -int EnchantmentHelper::getDiggingLootBonus(shared_ptr inventory) +int EnchantmentHelper::getDiggingLootBonus(shared_ptr source) { - return getEnchantmentLevel(Enchantment::resourceBonus->id, inventory->getSelected()); + return getEnchantmentLevel(Enchantment::resourceBonus->id, source->getCarriedItem() ); } -int EnchantmentHelper::getKillingLootBonus(shared_ptr inventory) +int EnchantmentHelper::getKillingLootBonus(shared_ptr source) { - return getEnchantmentLevel(Enchantment::lootBonus->id, inventory->getSelected()); + return getEnchantmentLevel(Enchantment::lootBonus->id, source->getCarriedItem() ); } -bool EnchantmentHelper::hasWaterWorkerBonus(shared_ptr inventory) +bool EnchantmentHelper::hasWaterWorkerBonus(shared_ptr source) { - return getEnchantmentLevel(Enchantment::waterWorker->id, inventory->armor) > 0; + return getEnchantmentLevel(Enchantment::waterWorker->id, source->getEquipmentSlots() ) > 0; } -int EnchantmentHelper::getArmorThorns(shared_ptr source) +int EnchantmentHelper::getArmorThorns(shared_ptr source) { return getEnchantmentLevel(Enchantment::thorns->id, source->getEquipmentSlots()); } -shared_ptr EnchantmentHelper::getRandomItemWith(Enchantment *enchantment, shared_ptr source) +shared_ptr EnchantmentHelper::getRandomItemWith(Enchantment *enchantment, shared_ptr source) { ItemInstanceArray items = source->getEquipmentSlots(); for(unsigned int i = 0; i < items.length; ++i) diff --git a/Minecraft.World/EnchantmentHelper.h b/Minecraft.World/EnchantmentHelper.h index 9f7de5c5..6ed2e398 100644 --- a/Minecraft.World/EnchantmentHelper.h +++ b/Minecraft.World/EnchantmentHelper.h @@ -49,14 +49,14 @@ private: * @return */ public: - static int getDamageProtection(shared_ptr inventory, DamageSource *source); + static int getDamageProtection(ItemInstanceArray armor, DamageSource *source); private: class GetDamageBonusIteration : public EnchantmentIterationMethod { public: - int sum; - shared_ptr target; + float sum; + shared_ptr target; virtual void doEnchantment(Enchantment *enchantment, int level); }; @@ -70,18 +70,18 @@ private: * @return */ public: - static int getDamageBonus(shared_ptr inventory, shared_ptr target); - static int getKnockbackBonus(shared_ptr inventory, shared_ptr target); - static int getFireAspect(shared_ptr source); - static int getOxygenBonus(shared_ptr inventory); - static int getDiggingBonus(shared_ptr inventory); - static int getDigDurability(shared_ptr inventory); - static bool hasSilkTouch(shared_ptr inventory); - static int getDiggingLootBonus(shared_ptr inventory); - static int getKillingLootBonus(shared_ptr inventory); - static bool hasWaterWorkerBonus(shared_ptr inventory); - static int getArmorThorns(shared_ptr source); - static shared_ptr getRandomItemWith(Enchantment *enchantment, shared_ptr source); + static float getDamageBonus(shared_ptr source, shared_ptr target); + static int getKnockbackBonus(shared_ptr source, shared_ptr target); + static int getFireAspect(shared_ptr source); + static int getOxygenBonus(shared_ptr source); + static int getDiggingBonus(shared_ptr source); + static int getDigDurability(shared_ptr source); + static bool hasSilkTouch(shared_ptr source); + static int getDiggingLootBonus(shared_ptr source); + static int getKillingLootBonus(shared_ptr source); + static bool hasWaterWorkerBonus(shared_ptr source); + static int getArmorThorns(shared_ptr source); + static shared_ptr getRandomItemWith(Enchantment *enchantment, shared_ptr source); /** * diff --git a/Minecraft.World/EnchantmentMenu.cpp b/Minecraft.World/EnchantmentMenu.cpp index 23b366ce..fa769bf9 100644 --- a/Minecraft.World/EnchantmentMenu.cpp +++ b/Minecraft.World/EnchantmentMenu.cpp @@ -17,9 +17,9 @@ EnchantmentMenu::EnchantmentMenu(shared_ptr inventory, Level *level, } this->level = level; - this->x = xt; - this->y = yt; - this->z = zt; + x = xt; + y = yt; + z = zt; addSlot(new EnchantmentSlot(enchantSlots, 0, 21 + 4, 43 + 4)); for (int y = 0; y < 3; y++) @@ -53,9 +53,9 @@ void EnchantmentMenu::broadcastChanges() // 4J Added m_costsChanged to stop continually sending update packets even when no changes have been made if(m_costsChanged) { - for (int i = 0; i < containerListeners->size(); i++) + for (int i = 0; i < containerListeners.size(); i++) { - ContainerListener *listener = containerListeners->at(i); + ContainerListener *listener = containerListeners.at(i); listener->setContainerData(this, 0, costs[0]); listener->setContainerData(this, 1, costs[1]); listener->setContainerData(this, 2, costs[2]); @@ -162,7 +162,7 @@ bool EnchantmentMenu::clickMenuButton(shared_ptr player, int i) vector *newEnchantment = EnchantmentHelper::selectEnchantment(&random, item, costs[i]); if (newEnchantment != NULL) { - player->withdrawExperienceLevels(costs[i]); + player->giveExperienceLevels(-costs[i]); if (isBook) item->id = Item::enchantedBook_Id; int randomIndex = isBook ? random.nextInt(newEnchantment->size()) : -1; //for (EnchantmentInstance e : newEnchantment) @@ -216,8 +216,8 @@ bool EnchantmentMenu::stillValid(shared_ptr player) shared_ptr EnchantmentMenu::quickMoveStack(shared_ptr player, int slotIndex) { shared_ptr clicked = nullptr; - Slot *slot = slots->at(slotIndex); - Slot *IngredientSlot = slots->at(INGREDIENT_SLOT); + Slot *slot = slots.at(slotIndex); + Slot *IngredientSlot = slots.at(INGREDIENT_SLOT); if (slot != NULL && slot->hasItem()) { diff --git a/Minecraft.World/EnchantmentTableEntity.cpp b/Minecraft.World/EnchantmentTableEntity.cpp index 31da3c49..15131aa2 100644 --- a/Minecraft.World/EnchantmentTableEntity.cpp +++ b/Minecraft.World/EnchantmentTableEntity.cpp @@ -10,15 +10,16 @@ EnchantmentTableEntity::EnchantmentTableEntity() random = new Random(); time = 0; - flip = 0.0f; + flip = 0.0f; oFlip = 0.0f; flipT = 0.0f; flipA = 0.0f; - open = 0.0f; + open = 0.0f; oOpen = 0.0f; - rot = 0.0f; + rot = 0.0f; oRot = 0.0f; tRot = 0.0f; + name = L""; } EnchantmentTableEntity::~EnchantmentTableEntity() @@ -26,6 +27,18 @@ EnchantmentTableEntity::~EnchantmentTableEntity() delete random; } +void EnchantmentTableEntity::save(CompoundTag *base) +{ + TileEntity::save(base); + if (hasCustomName()) base->putString(L"CustomName", name); +} + +void EnchantmentTableEntity::load(CompoundTag *base) +{ + TileEntity::load(base); + if (base->contains(L"CustomName")) name = base->getString(L"CustomName"); +} + void EnchantmentTableEntity::tick() { TileEntity::tick(); @@ -89,6 +102,26 @@ void EnchantmentTableEntity::tick() flip = flip + flipA; } +wstring EnchantmentTableEntity::getName() +{ + return hasCustomName() ? name : app.GetString(IDS_ENCHANT); +} + +wstring EnchantmentTableEntity::getCustomName() +{ + return hasCustomName() ? name : L""; +} + +bool EnchantmentTableEntity::hasCustomName() +{ + return !name.empty(); +} + +void EnchantmentTableEntity::setCustomName(const wstring &name) +{ + this->name = name; +} + shared_ptr EnchantmentTableEntity::clone() { shared_ptr result = shared_ptr( new EnchantmentTableEntity() ); diff --git a/Minecraft.World/EnchantmentTableEntity.h b/Minecraft.World/EnchantmentTableEntity.h index aa54c812..18ae5b75 100644 --- a/Minecraft.World/EnchantmentTableEntity.h +++ b/Minecraft.World/EnchantmentTableEntity.h @@ -10,15 +10,24 @@ public: public: int time; - float flip, oFlip, flipT, flipA; - float open, oOpen; - float rot, oRot, tRot; + float flip, oFlip, flipT, flipA; + float open, oOpen; + float rot, oRot, tRot; private: Random *random; + wstring name; + public: EnchantmentTableEntity(); ~EnchantmentTableEntity(); - virtual void tick(); + + virtual void save(CompoundTag *base); + virtual void load(CompoundTag *base); + virtual void tick(); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual bool hasCustomName(); + virtual void setCustomName(const wstring &name); // 4J Added virtual shared_ptr clone(); diff --git a/Minecraft.World/EnchantmentTableTile.cpp b/Minecraft.World/EnchantmentTableTile.cpp index 70c127ba..d50fe5f5 100644 --- a/Minecraft.World/EnchantmentTableTile.cpp +++ b/Minecraft.World/EnchantmentTableTile.cpp @@ -9,10 +9,10 @@ const wstring EnchantmentTableTile::TEXTURE_SIDE = L"enchantment_side"; const wstring EnchantmentTableTile::TEXTURE_TOP = L"enchantment_top"; const wstring EnchantmentTableTile::TEXTURE_BOTTOM = L"enchantment_bottom"; -EnchantmentTableTile::EnchantmentTableTile(int id) : EntityTile(id, Material::stone, isSolidRender()) +EnchantmentTableTile::EnchantmentTableTile(int id) : BaseEntityTile(id, Material::stone, isSolidRender()) { updateDefaultShape(); - setLightBlock(0); + setLightBlock(0); iconTop = NULL; iconBottom = NULL; @@ -21,7 +21,7 @@ EnchantmentTableTile::EnchantmentTableTile(int id) : EntityTile(id, Material::st // 4J Added override void EnchantmentTableTile::updateDefaultShape() { - setShape(0, 0, 0, 1, 12 / 16.0f, 1); + setShape(0, 0, 0, 1, 12 / 16.0f, 1); } bool EnchantmentTableTile::isCubeShaped() @@ -31,28 +31,28 @@ bool EnchantmentTableTile::isCubeShaped() void EnchantmentTableTile::animateTick(Level *level, int x, int y, int z, Random *random) { - EntityTile::animateTick(level, x, y, z, random); + BaseEntityTile::animateTick(level, x, y, z, random); - for (int xx = x - 2; xx <= x + 2; xx++) + for (int xx = x - 2; xx <= x + 2; xx++) { - for (int zz = z - 2; zz <= z + 2; zz++) + for (int zz = z - 2; zz <= z + 2; zz++) { - if (xx > x - 2 && xx < x + 2 && zz == z - 1) + if (xx > x - 2 && xx < x + 2 && zz == z - 1) { - zz = z + 2; - } - if (random->nextInt(16) != 0) continue; - for (int yy = y; yy <= y + 1; yy++) + zz = z + 2; + } + if (random->nextInt(16) != 0) continue; + for (int yy = y; yy <= y + 1; yy++) { - if (level->getTile(xx, yy, zz) == Tile::bookshelf_Id) + if (level->getTile(xx, yy, zz) == Tile::bookshelf_Id) { - if (!level->isEmptyTile((xx - x) / 2 + x, yy, (zz - z) / 2 + z)) break; + if (!level->isEmptyTile((xx - x) / 2 + x, yy, (zz - z) / 2 + z)) break; - level->addParticle(eParticleType_enchantmenttable, x + 0.5, y + 2.0, z + 0.5, xx - x + random->nextFloat() - 0.5, yy - y - random->nextFloat() - 1, zz - z + random->nextFloat() - 0.5); - } - } - } - } + level->addParticle(eParticleType_enchantmenttable, x + 0.5, y + 2.0, z + 0.5, xx - x + random->nextFloat() - 0.5, yy - y - random->nextFloat() - 1, zz - z + random->nextFloat() - 0.5); + } + } + } + } } bool EnchantmentTableTile::isSolidRender(bool isServerLevel) @@ -76,12 +76,22 @@ bool EnchantmentTableTile::use(Level *level, int x, int y, int z, shared_ptrisClientSide) + if (level->isClientSide) { - return true; - } - player->startEnchanting(x, y, z); - return true; + return true; + } + shared_ptr table = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + player->startEnchanting(x, y, z, table->hasCustomName() ? table->getName() : L""); + return true; +} + +void EnchantmentTableTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) +{ + BaseEntityTile::setPlacedBy(level, x, y, z, by, itemInstance); + if (itemInstance->hasCustomHoverName()) + { + dynamic_pointer_cast( level->getTileEntity(x, y, z))->setCustomName(itemInstance->getHoverName()); + } } void EnchantmentTableTile::registerIcons(IconRegister *iconRegister) diff --git a/Minecraft.World/EnchantmentTableTile.h b/Minecraft.World/EnchantmentTableTile.h index 43816cec..ec5c70bf 100644 --- a/Minecraft.World/EnchantmentTableTile.h +++ b/Minecraft.World/EnchantmentTableTile.h @@ -1,8 +1,8 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" class ChunkRebuildData; -class EnchantmentTableTile : public EntityTile +class EnchantmentTableTile : public BaseEntityTile { friend class ChunkRebuildData; public: @@ -16,14 +16,14 @@ private: public: EnchantmentTableTile(int id); - - virtual void updateDefaultShape(); // 4J Added override - bool isCubeShaped(); - void animateTick(Level *level, int x, int y, int z, Random *random); - bool isSolidRender(bool isServerLevel = false); - Icon *getTexture(int face, int data); - shared_ptr newTileEntity(Level *level); - bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - //@Override - void registerIcons(IconRegister *iconRegister); + + virtual void updateDefaultShape(); // 4J Added override + virtual bool isCubeShaped(); + virtual void animateTick(Level *level, int x, int y, int z, Random *random); + virtual bool isSolidRender(bool isServerLevel = false); + virtual Icon *getTexture(int face, int data); + virtual shared_ptr newTileEntity(Level *level); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual void registerIcons(IconRegister *iconRegister); }; diff --git a/Minecraft.World/EndPodiumFeature.cpp b/Minecraft.World/EndPodiumFeature.cpp index 261b6446..7cf742fa 100644 --- a/Minecraft.World/EndPodiumFeature.cpp +++ b/Minecraft.World/EndPodiumFeature.cpp @@ -74,7 +74,7 @@ bool EndPodiumFeature::place(Level *level, Random *random, int x, int y, int z) { if(level->isEmptyTile(xx,yy,zz)) { - placeBlock(level, xx, yy, zz, Tile::whiteStone_Id, 0); + placeBlock(level, xx, yy, zz, Tile::endStone_Id, 0); } } } diff --git a/Minecraft.World/EndTag.h b/Minecraft.World/EndTag.h index 684ee6ce..2815a577 100644 --- a/Minecraft.World/EndTag.h +++ b/Minecraft.World/EndTag.h @@ -7,7 +7,7 @@ public: EndTag() : Tag(L"") {} EndTag(const wstring &name) : Tag(name) {} - void load(DataInput *dis) {}; + void load(DataInput *dis, int tagDepth) {}; void write(DataOutput *dos) {}; byte getId() { return TAG_End; } diff --git a/Minecraft.World/EnderChestTile.cpp b/Minecraft.World/EnderChestTile.cpp index 7e50a933..ef3c2046 100644 --- a/Minecraft.World/EnderChestTile.cpp +++ b/Minecraft.World/EnderChestTile.cpp @@ -7,7 +7,7 @@ #include "net.minecraft.h" #include "EnderChestTile.h" -EnderChestTile::EnderChestTile(int id) : EntityTile(id, Material::stone, isSolidRender()) +EnderChestTile::EnderChestTile(int id) : BaseEntityTile(id, Material::stone, isSolidRender()) { updateDefaultShape(); } @@ -48,7 +48,7 @@ bool EnderChestTile::isSilkTouchable() return true; } -void EnderChestTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void EnderChestTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { int facing = 0; int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5f)) & 3; @@ -58,7 +58,7 @@ void EnderChestTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptrsetData(x, y, z, facing); + level->setData(x, y, z, facing, Tile::UPDATE_CLIENTS); } bool EnderChestTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly) diff --git a/Minecraft.World/EnderChestTile.h b/Minecraft.World/EnderChestTile.h index 96173f63..4c2bbcbf 100644 --- a/Minecraft.World/EnderChestTile.h +++ b/Minecraft.World/EnderChestTile.h @@ -1,15 +1,15 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" #include "ChestTile.h" -class EnderChestTile : public EntityTile +class EnderChestTile : public BaseEntityTile { public: static const int EVENT_SET_OPEN_COUNT = ChestTile::EVENT_SET_OPEN_COUNT; EnderChestTile(int id); - virtual void updateDefaultShape(); // 4J Added override + virtual void updateDefaultShape(); // 4J Added override bool isSolidRender(bool isServerLevel = false); bool isCubeShaped(); @@ -21,7 +21,7 @@ protected: bool isSilkTouchable(); public: - void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); + void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); shared_ptr newTileEntity(Level *level); void animateTick(Level *level, int xt, int yt, int zt, Random *random); diff --git a/Minecraft.World/EnderChestTileEntity.cpp b/Minecraft.World/EnderChestTileEntity.cpp index dffa2bd5..8169c029 100644 --- a/Minecraft.World/EnderChestTileEntity.cpp +++ b/Minecraft.World/EnderChestTileEntity.cpp @@ -55,12 +55,14 @@ void EnderChestTileEntity::tick() } } -void EnderChestTileEntity::triggerEvent(int b0, int b1) +bool EnderChestTileEntity::triggerEvent(int b0, int b1) { if (b0 == ChestTile::EVENT_SET_OPEN_COUNT) { openCount = b1; + return true; } + return TileEntity::triggerEvent(b0, b1); } void EnderChestTileEntity::setRemoved() diff --git a/Minecraft.World/EnderChestTileEntity.h b/Minecraft.World/EnderChestTileEntity.h index f6882980..1231bbd3 100644 --- a/Minecraft.World/EnderChestTileEntity.h +++ b/Minecraft.World/EnderChestTileEntity.h @@ -19,7 +19,7 @@ public: EnderChestTileEntity(); void tick(); - void triggerEvent(int b0, int b1); + bool triggerEvent(int b0, int b1); void setRemoved(); void startOpen(); void stopOpen(); diff --git a/Minecraft.World/EnderCrystal.cpp b/Minecraft.World/EnderCrystal.cpp index 719e9d96..78e00419 100644 --- a/Minecraft.World/EnderCrystal.cpp +++ b/Minecraft.World/EnderCrystal.cpp @@ -63,7 +63,7 @@ void EnderCrystal::tick() int zt = Mth::floor(z); if (level->getTile(xt, yt, zt) != Tile::fire_Id) { - level->setTile(xt, yt, zt, Tile::fire_Id); + level->setTileAndUpdate(xt, yt, zt, Tile::fire_Id); } } } @@ -88,12 +88,12 @@ bool EnderCrystal::isPickable() return true; } -bool EnderCrystal::hurt(DamageSource *source, int damage) +bool EnderCrystal::hurt(DamageSource *source, float damage) { - // 4J-PB - if the owner of the source is the enderdragon, then ignore it (where the dragon's fireball hits an endercrystal) - shared_ptr sourceIsDragon = dynamic_pointer_cast(source->getEntity()); + if (isInvulnerable()) return false; - if(sourceIsDragon!=NULL) + // 4J-PB - if the owner of the source is the enderdragon, then ignore it (where the dragon's fireball hits an endercrystal) + if ( source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_ENDERDRAGON) ) { return false; } diff --git a/Minecraft.World/EnderCrystal.h b/Minecraft.World/EnderCrystal.h index 26606e26..15940452 100644 --- a/Minecraft.World/EnderCrystal.h +++ b/Minecraft.World/EnderCrystal.h @@ -38,5 +38,5 @@ protected: public: virtual float getShadowHeightOffs(); virtual bool isPickable(); - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); }; \ No newline at end of file diff --git a/Minecraft.World/EnderDragon.cpp b/Minecraft.World/EnderDragon.cpp index 2ccd453c..2dc0c434 100644 --- a/Minecraft.World/EnderDragon.cpp +++ b/Minecraft.World/EnderDragon.cpp @@ -2,7 +2,9 @@ #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.boss.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.damagesource.h" @@ -42,9 +44,8 @@ void EnderDragon::_init() // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); + setHealth(getMaxHealth()); xTarget = yTarget = zTarget = 0.0; posPointer = -1; @@ -80,32 +81,10 @@ void EnderDragon::_init() m_currentPath = NULL; } -EnderDragon::EnderDragon(Level *level) : BossMob(level) +EnderDragon::EnderDragon(Level *level) : Mob(level) { _init(); - head = shared_ptr( new BossMobPart(this, L"head", 6, 6) ); - neck = shared_ptr( new BossMobPart(this, L"neck", 6, 6) ); // 4J Added - body = shared_ptr( new BossMobPart(this, L"body", 8, 8) ); - tail1 = shared_ptr( new BossMobPart(this, L"tail", 4, 4) ); - tail2 = shared_ptr( new BossMobPart(this, L"tail", 4, 4) ); - tail3 = shared_ptr( new BossMobPart(this, L"tail", 4, 4) ); - wing1 = shared_ptr( new BossMobPart(this, L"wing", 4, 4) ); - wing2 = shared_ptr( new BossMobPart(this, L"wing", 4, 4) ); - - subEntities.push_back(head); - subEntities.push_back(neck); // 4J Added - subEntities.push_back(body); - subEntities.push_back(tail1); - subEntities.push_back(tail2); - subEntities.push_back(tail3); - subEntities.push_back(wing1); - subEntities.push_back(wing2); - - maxHealth = 200; - setHealth(maxHealth); - - this->textureIdx = TN_MOB_ENDERDRAGON; // 4J was "/mob/enderdragon/ender.png"; setSize(16, 8); noPhysics = true; @@ -118,6 +97,28 @@ EnderDragon::EnderDragon(Level *level) : BossMob(level) noCulling = true; } +// 4J - split off from ctor so we can use shared_from_this() +void EnderDragon::AddParts() +{ + head = shared_ptr( new MultiEntityMobPart(dynamic_pointer_cast(shared_from_this()), L"head", 6, 6) ); + neck = shared_ptr( new MultiEntityMobPart(dynamic_pointer_cast(shared_from_this()), L"neck", 6, 6) ); // 4J Added + body = shared_ptr( new MultiEntityMobPart(dynamic_pointer_cast(shared_from_this()), L"body", 8, 8) ); + tail1 = shared_ptr( new MultiEntityMobPart(dynamic_pointer_cast(shared_from_this()), L"tail", 4, 4) ); + tail2 = shared_ptr( new MultiEntityMobPart(dynamic_pointer_cast(shared_from_this()), L"tail", 4, 4) ); + tail3 = shared_ptr( new MultiEntityMobPart(dynamic_pointer_cast(shared_from_this()), L"tail", 4, 4) ); + wing1 = shared_ptr( new MultiEntityMobPart(dynamic_pointer_cast(shared_from_this()), L"wing", 4, 4) ); + wing2 = shared_ptr( new MultiEntityMobPart(dynamic_pointer_cast(shared_from_this()), L"wing", 4, 4) ); + + subEntities.push_back(head); + subEntities.push_back(neck); // 4J Added + subEntities.push_back(body); + subEntities.push_back(tail1); + subEntities.push_back(tail2); + subEntities.push_back(tail3); + subEntities.push_back(wing1); + subEntities.push_back(wing2); +} + EnderDragon::~EnderDragon() { if(m_nodes->data != NULL) @@ -132,11 +133,16 @@ EnderDragon::~EnderDragon() if( m_currentPath != NULL ) delete m_currentPath; } -void EnderDragon::defineSynchedData() +void EnderDragon::registerAttributes() { - BossMob::defineSynchedData(); + Mob::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(200); +} - entityData->define(DATA_ID_SYNCHED_HEALTH, maxHealth); +void EnderDragon::defineSynchedData() +{ + Mob::defineSynchedData(); // 4J Added for new dragon behaviour entityData->define(DATA_ID_SYNCHED_ACTION, e_EnderdragonAction_HoldingPattern); @@ -144,7 +150,7 @@ void EnderDragon::defineSynchedData() void EnderDragon::getLatencyPos(doubleArray result, int step, float a) { - if (health <= 0) + if (getHealth() <= 0) { a = 0; } @@ -172,32 +178,28 @@ void EnderDragon::getLatencyPos(doubleArray result, int step, float a) void EnderDragon::aiStep() { - if (!level->isClientSide) - { - entityData->set(DATA_ID_SYNCHED_HEALTH, health); - } - else + if (level->isClientSide) { // 4J Stu - If saved when dead we need to make sure that the actual health is updated correctly on the client // Fix for TU9: Content: Gameplay: Enderdragon respawns after loading game which was previously saved at point of hes death - health = getSynchedHealth(); + setHealth(getHealth()); float flap = Mth::cos(flapTime * PI * 2); float oldFlap = Mth::cos(oFlapTime * PI * 2); if (oldFlap <= -0.3f && flap >= -0.3f) { - level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_MOVE, 1, 0.8f + random->nextFloat() * .3f, 100.0f); + level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_MOVE, 1, 0.8f + random->nextFloat() * .3f, false, 100.0f); } // play a growl every now and then if(! (getSynchedAction() == e_EnderdragonAction_Sitting_Flaming || - getSynchedAction() == e_EnderdragonAction_Sitting_Scanning || - getSynchedAction() == e_EnderdragonAction_Sitting_Attacking)) + getSynchedAction() == e_EnderdragonAction_Sitting_Scanning || + getSynchedAction() == e_EnderdragonAction_Sitting_Attacking)) { m_iGrowlTimer--; if(m_iGrowlTimer<0) { - level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_GROWL, 0.5f, 0.8f + random->nextFloat() * .3f, 100.0f); + level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_GROWL, 0.5f, 0.8f + random->nextFloat() * .3f, false, 100.0f); m_iGrowlTimer=200+(random->nextInt(200)); } } @@ -205,7 +207,7 @@ void EnderDragon::aiStep() oFlapTime = flapTime; - if (health <= 0) + if (getHealth() <= 0) { // level.addParticle("explode", x + random.nextFloat() * bbWidth * 2 - bbWidth, y + random.nextFloat() * bbHeight, z + random.nextFloat() * bbWidth * 2 - bbWidth, 0, 0, 0); float xo = (random->nextFloat() - 0.5f) * 8; @@ -342,7 +344,7 @@ void EnderDragon::aiStep() else if( getSynchedAction() == e_EnderdragonAction_Sitting_Attacking ) { // AP - changed this to use playLocalSound because no sound could be heard with playSound (cos it's a stub function) - level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_GROWL, 0.5f, 0.8f + random->nextFloat() * .3f, 100.0f); + level->playLocalSound(x, y, z, eSoundType_MOB_ENDERDRAGON_GROWL, 0.5f, 0.8f + random->nextFloat() * .3f, false, 100.0f); } } else @@ -352,7 +354,7 @@ void EnderDragon::aiStep() double zdd = zTarget - z; double dist = xdd * xdd + ydd * ydd + zdd * zdd; - + if( getSynchedAction() == e_EnderdragonAction_Sitting_Flaming ) { --m_actionTicks; @@ -379,7 +381,7 @@ void EnderDragon::aiStep() else if( getSynchedAction() == e_EnderdragonAction_Sitting_Scanning ) { attackTarget = level->getNearestPlayer( shared_from_this(), SITTING_ATTACK_VIEW_RANGE, SITTING_ATTACK_Y_VIEW_RANGE ); - + ++m_actionTicks; if( attackTarget != NULL ) { @@ -444,10 +446,10 @@ void EnderDragon::aiStep() for( AUTO_VAR(it, targets->begin() ); it != targets->end(); ++it) { - shared_ptr e = dynamic_pointer_cast( *it ); - if (e != NULL) + if ( (*it)->instanceof(eTYPE_LIVINGENTITY) ) { //app.DebugPrintf("Attacking entity with acid\n"); + shared_ptr e = dynamic_pointer_cast( *it ); e->hurt(DamageSource::dragonbreath, 2); } } @@ -511,9 +513,9 @@ void EnderDragon::aiStep() } else { -// double xTargetO = xTarget; -// double yTargetO = yTarget; -// double zTargetO = zTarget; + // double xTargetO = xTarget; + // double yTargetO = yTarget; + // double zTargetO = zTarget; if (getSynchedAction() == e_EnderdragonAction_StrafePlayer && attackTarget != NULL && m_currentPath != NULL && m_currentPath->isDone()) { xTarget = attackTarget->x; @@ -685,7 +687,7 @@ void EnderDragon::aiStep() // Curls/straightens the tail for (int i = 0; i < 3; i++) { - shared_ptr part = nullptr; + shared_ptr part = nullptr; if (i == 0) part = tail1; if (i == 1) part = tail2; @@ -706,7 +708,7 @@ void EnderDragon::aiStep() } -// 4J Stu - Fireball attack taken from Ghast + // 4J Stu - Fireball attack taken from Ghast if (!level->isClientSide) { double maxDist = 64.0f; @@ -763,7 +765,7 @@ void EnderDragon::aiStep() if (m_fireballCharge > 0) m_fireballCharge--; } } -// End fireball attack + // End fireball attack if (!level->isClientSide) { @@ -779,14 +781,14 @@ void EnderDragon::checkCrystals() { if (!level->isClientSide) { - hurt(head, DamageSource::explosion, 10); + hurt(head, DamageSource::explosion(NULL), 10); } nearestCrystal = nullptr; } else if (tickCount % 10 == 0) { - if (health < maxHealth) health++; + if (getHealth() < getMaxHealth()) setHealth(getHealth() + 1); } } @@ -798,7 +800,7 @@ void EnderDragon::checkCrystals() shared_ptr crystal = nullptr; double nearest = Double::MAX_VALUE; //for (Entity ec : crystals) - for(AUTO_VAR(it, crystals->begin()); it != crystals->end(); ++it) + for(AUTO_VAR(it, crystals->begin()); it != crystals->end(); ++it) { shared_ptr ec = dynamic_pointer_cast( *it ); double dist = ec->distanceToSqr(shared_from_this() ); @@ -809,7 +811,7 @@ void EnderDragon::checkCrystals() } } delete crystals; - + nearestCrystal = crystal; } @@ -819,10 +821,10 @@ void EnderDragon::checkAttack() { //if (tickCount % 20 == 0) { -// Vec3 *v = getViewVector(1); -// double xdd = 0; -// double ydd = -1; -// double zdd = 0; + // Vec3 *v = getViewVector(1); + // double xdd = 0; + // double ydd = -1; + // double zdd = 0; // double x = (body.bb.x0 + body.bb.x1) / 2; // double y = (body.bb.y0 + body.bb.y1) / 2 - 2; @@ -840,9 +842,10 @@ void EnderDragon::knockBack(vector > *entities) //for (Entity e : entities) for(AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) { - shared_ptr e = dynamic_pointer_cast( *it ); - if (e != NULL)//(e instanceof Mob) + + if ( (*it)->instanceof(eTYPE_LIVINGENTITY) )//(e instanceof Mob) { + shared_ptr e = dynamic_pointer_cast( *it ); double xd = e->x - xm; double zd = e->z - zm; double dd = xd * xd + zd * zd; @@ -856,10 +859,11 @@ void EnderDragon::hurt(vector > *entities) //for (int i = 0; i < entities->size(); i++) for(AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) { - shared_ptr e = dynamic_pointer_cast( *it );//entities.get(i); - if (e != NULL) //(e instanceof Mob) + + if ( (*it)->instanceof(eTYPE_LIVINGENTITY) ) //(e instanceof Mob) { - DamageSource *damageSource = DamageSource::mobAttack( dynamic_pointer_cast( shared_from_this() )); + shared_ptr e = dynamic_pointer_cast( *it );//entities.get(i); + DamageSource *damageSource = DamageSource::mobAttack( dynamic_pointer_cast( shared_from_this() )); e->hurt(damageSource, 10); delete damageSource; } @@ -918,12 +922,12 @@ void EnderDragon::findNewTarget() } break; case e_EnderdragonAction_Landing: -// setSynchedAction(e_EnderdragonAction_Sitting_Flaming); -//#if PRINT_DRAGON_STATE_CHANGE_MESSAGES -// app.DebugPrintf("Dragon action is now: SittingFlaming\n"); -//#endif -// m_actionTicks = FLAME_TICKS; - + // setSynchedAction(e_EnderdragonAction_Sitting_Flaming); + //#if PRINT_DRAGON_STATE_CHANGE_MESSAGES + // app.DebugPrintf("Dragon action is now: SittingFlaming\n"); + //#endif + // m_actionTicks = FLAME_TICKS; + m_flameAttacks = 0; setSynchedAction(e_EnderdragonAction_Sitting_Scanning); attackTarget = level->getNearestPlayer( shared_from_this(), SITTING_ATTACK_VIEW_RANGE, SITTING_ATTACK_Y_VIEW_RANGE ); @@ -948,7 +952,7 @@ void EnderDragon::findNewTarget() if( m_currentPath == NULL || m_currentPath->isDone() ) { int currentNodeIndex = findClosestNode(); - + // To get the angle to the player correct when landing, head to a node diametrically opposite the player, then swoop in to 4,4 int eggHeight = max( level->seaLevel + 5, level->getTopSolidBlock(PODIUM_X_POS,PODIUM_Z_POS) ); //level->getHeightmap(4,4); playerNearestToEgg = level->getNearestPlayer(PODIUM_X_POS, eggHeight, PODIUM_Z_POS, 128.0); @@ -986,8 +990,8 @@ void EnderDragon::findNewTarget() } } else if(getSynchedAction() == e_EnderdragonAction_Sitting_Flaming || - getSynchedAction() == e_EnderdragonAction_Sitting_Attacking || - getSynchedAction() == e_EnderdragonAction_Sitting_Scanning) + getSynchedAction() == e_EnderdragonAction_Sitting_Attacking || + getSynchedAction() == e_EnderdragonAction_Sitting_Scanning) { // Does no movement } @@ -1076,14 +1080,13 @@ bool EnderDragon::checkWalls(AABB *bb) { } - else if (t == Tile::obsidian_Id || t == Tile::whiteStone_Id || t == Tile::unbreakable_Id) + else if (t == Tile::obsidian_Id || t == Tile::endStone_Id || t == Tile::unbreakable_Id || !level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) { hitWall = true; } else { - destroyedTile = true; - level->setTile(x, y, z, 0); + destroyedTile = level->removeTile(x, y, z) || destroyedTile; } } } @@ -1100,9 +1103,9 @@ bool EnderDragon::checkWalls(AABB *bb) return hitWall; } -bool EnderDragon::hurt(shared_ptr bossMobPart, DamageSource *source, int damage) +bool EnderDragon::hurt(shared_ptr MultiEntityMobPart, DamageSource *source, float damage) { - if (bossMobPart != head) + if (MultiEntityMobPart != head) { damage = damage / 4 + 1; } @@ -1116,18 +1119,18 @@ bool EnderDragon::hurt(shared_ptr bossMobPart, DamageSource *source //zTarget = z - cc1 * 5 + (random->nextFloat() - 0.5f) * 2; //attackTarget = NULL; - if (source == DamageSource::explosion || (dynamic_pointer_cast(source->getEntity()) != NULL)) + if ( source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_PLAYER) || source->isExplosion() ) { - int healthBefore = health; + int healthBefore = getHealth(); reallyHurt(source, damage); //if(!level->isClientSide) app.DebugPrintf("Health is now %d\n", health); - if( health <= 0 && + if( getHealth() <= 0 && !( getSynchedAction() == e_EnderdragonAction_Sitting_Flaming || - getSynchedAction() == e_EnderdragonAction_Sitting_Scanning || - getSynchedAction() == e_EnderdragonAction_Sitting_Attacking) ) + getSynchedAction() == e_EnderdragonAction_Sitting_Scanning || + getSynchedAction() == e_EnderdragonAction_Sitting_Attacking) ) { - health = 1; + setHealth(1); if( setSynchedAction(e_EnderdragonAction_LandingApproach) ) { @@ -1150,7 +1153,7 @@ bool EnderDragon::hurt(shared_ptr bossMobPart, DamageSource *source getSynchedAction() == e_EnderdragonAction_Sitting_Scanning || getSynchedAction() == e_EnderdragonAction_Sitting_Attacking) { - m_sittingDamageReceived += healthBefore - health; + m_sittingDamageReceived += healthBefore - getHealth(); if(m_sittingDamageReceived > (SITTING_ALLOWED_DAMAGE_PERCENTAGE*getMaxHealth() ) ) { @@ -1166,13 +1169,23 @@ bool EnderDragon::hurt(shared_ptr bossMobPart, DamageSource *source return true; } +bool EnderDragon::hurt(DamageSource *source, float damage) +{ + return false; +} + +bool EnderDragon::reallyHurt(DamageSource *source, float damage) +{ + return Mob::hurt(source, damage); +} + void EnderDragon::tickDeath() { if( getSynchedAction() != e_EnderdragonAction_Sitting_Flaming && getSynchedAction() != e_EnderdragonAction_Sitting_Scanning && getSynchedAction() != e_EnderdragonAction_Sitting_Attacking) { - if(!level->isClientSide) health = 1; + if(!level->isClientSide) setHealth(1); return; } @@ -1198,8 +1211,7 @@ void EnderDragon::tickDeath() } if (dragonDeathTime == 1) { - //level->globalLevelEvent(LevelEvent::SOUND_DRAGON_DEATH, (int) x, (int) y, (int) z, 0); - level->levelEvent(LevelEvent::SOUND_DRAGON_DEATH, (int) x, (int) y, (int) z, 0); + level->globalLevelEvent(LevelEvent::SOUND_DRAGON_DEATH, (int) x, (int) y, (int) z, 0); } } move(0, 0.1f, 0); @@ -1257,22 +1269,22 @@ void EnderDragon::spawnExitPortal(int x, int z) } else { - level->setTile(xx, yy, zz, Tile::unbreakable_Id); + level->setTileAndUpdate(xx, yy, zz, Tile::unbreakable_Id); } } else if (yy > y) { - level->setTile(xx, yy, zz, 0); + level->setTileAndUpdate(xx, yy, zz, 0); } else { if (d > r - 1 - 0.5) { - level->setTile(xx, yy, zz, Tile::unbreakable_Id); + level->setTileAndUpdate(xx, yy, zz, Tile::unbreakable_Id); } else { - level->setTile(xx, yy, zz, Tile::endPortalTile_Id); + level->setTileAndUpdate(xx, yy, zz, Tile::endPortalTile_Id); } } } @@ -1280,15 +1292,15 @@ void EnderDragon::spawnExitPortal(int x, int z) } } - level->setTile(x, y + 0, z, Tile::unbreakable_Id); - level->setTile(x, y + 1, z, Tile::unbreakable_Id); - level->setTile(x, y + 2, z, Tile::unbreakable_Id); - level->setTile(x - 1, y + 2, z, Tile::torch_Id); - level->setTile(x + 1, y + 2, z, Tile::torch_Id); - level->setTile(x, y + 2, z - 1, Tile::torch_Id); - level->setTile(x, y + 2, z + 1, Tile::torch_Id); - level->setTile(x, y + 3, z, Tile::unbreakable_Id); - level->setTile(x, y + 4, z, Tile::dragonEgg_Id); + level->setTileAndUpdate(x, y + 0, z, Tile::unbreakable_Id); + level->setTileAndUpdate(x, y + 1, z, Tile::unbreakable_Id); + level->setTileAndUpdate(x, y + 2, z, Tile::unbreakable_Id); + level->setTileAndUpdate(x - 1, y + 2, z, Tile::torch_Id); + level->setTileAndUpdate(x + 1, y + 2, z, Tile::torch_Id); + level->setTileAndUpdate(x, y + 2, z - 1, Tile::torch_Id); + level->setTileAndUpdate(x, y + 2, z + 1, Tile::torch_Id); + level->setTileAndUpdate(x, y + 3, z, Tile::unbreakable_Id); + level->setTileAndUpdate(x, y + 4, z, Tile::dragonEgg_Id); // 4J-PB - The podium can be floating with nothing under it, so put some whiteStone under it if this is the case for (int yy = y - 5; yy < y - 1; yy++) @@ -1299,7 +1311,7 @@ void EnderDragon::spawnExitPortal(int x, int z) { if(level->isEmptyTile(xx,yy,zz)) { - level->setTile(xx, yy, zz, Tile::whiteStone_Id); + level->setTileAndUpdate(xx, yy, zz, Tile::endStone_Id); } } } @@ -1322,15 +1334,24 @@ bool EnderDragon::isPickable() return false; } -// Fix for TU9 Enderdragon sound hits being the player sound hits - moved this forward from later version -int EnderDragon::getHurtSound() +Level *EnderDragon::getLevel() { - return eSoundType_MOB_ENDERDRAGON_HIT; + return level; } -int EnderDragon::getSynchedHealth() +int EnderDragon::getAmbientSound() { - return entityData->getInteger(DATA_ID_SYNCHED_HEALTH); + return eSoundType_MOB_ENDERDRAGON_GROWL; //"mob.enderdragon.growl"; +} + +int EnderDragon::getHurtSound() +{ + return eSoundType_MOB_ENDERDRAGON_HIT; //"mob.enderdragon.hit"; +} + +float EnderDragon::getSoundVolume() +{ + return 5; } // 4J Added for new dragon behaviour @@ -1343,74 +1364,74 @@ bool EnderDragon::setSynchedAction(EEnderdragonAction action, bool force /*= fal case e_EnderdragonAction_HoldingPattern: switch(action) { - case e_EnderdragonAction_StrafePlayer: - case e_EnderdragonAction_LandingApproach: - validTransition = true; - break; + case e_EnderdragonAction_StrafePlayer: + case e_EnderdragonAction_LandingApproach: + validTransition = true; + break; }; break; case e_EnderdragonAction_StrafePlayer: switch(action) { - case e_EnderdragonAction_HoldingPattern: - case e_EnderdragonAction_LandingApproach: - validTransition = true; - break; + case e_EnderdragonAction_HoldingPattern: + case e_EnderdragonAction_LandingApproach: + validTransition = true; + break; }; break; case e_EnderdragonAction_LandingApproach: switch(action) { - case e_EnderdragonAction_Landing: - validTransition = true; - break; + case e_EnderdragonAction_Landing: + validTransition = true; + break; }; break; case e_EnderdragonAction_Landing: switch(action) { - case e_EnderdragonAction_Sitting_Flaming: - case e_EnderdragonAction_Sitting_Scanning: - validTransition = true; - break; + case e_EnderdragonAction_Sitting_Flaming: + case e_EnderdragonAction_Sitting_Scanning: + validTransition = true; + break; }; break; case e_EnderdragonAction_Takeoff: switch(action) { - case e_EnderdragonAction_HoldingPattern: - validTransition = true; - break; + case e_EnderdragonAction_HoldingPattern: + validTransition = true; + break; }; break; case e_EnderdragonAction_Sitting_Flaming: switch(action) { - case e_EnderdragonAction_Sitting_Scanning: - case e_EnderdragonAction_Sitting_Attacking: - case e_EnderdragonAction_Takeoff: - validTransition = true; - break; + case e_EnderdragonAction_Sitting_Scanning: + case e_EnderdragonAction_Sitting_Attacking: + case e_EnderdragonAction_Takeoff: + validTransition = true; + break; }; break; case e_EnderdragonAction_Sitting_Scanning: switch(action) { - case e_EnderdragonAction_Sitting_Flaming: - case e_EnderdragonAction_Sitting_Attacking: - case e_EnderdragonAction_Takeoff: - validTransition = true; - break; + case e_EnderdragonAction_Sitting_Flaming: + case e_EnderdragonAction_Sitting_Attacking: + case e_EnderdragonAction_Takeoff: + validTransition = true; + break; }; break; case e_EnderdragonAction_Sitting_Attacking: switch(action) { - case e_EnderdragonAction_Sitting_Flaming: - case e_EnderdragonAction_Sitting_Scanning: - case e_EnderdragonAction_Takeoff: - validTransition = true; - break; + case e_EnderdragonAction_Sitting_Flaming: + case e_EnderdragonAction_Sitting_Scanning: + case e_EnderdragonAction_Takeoff: + validTransition = true; + break; }; break; }; @@ -1461,7 +1482,7 @@ void EnderDragon::handleCrystalDestroyed(DamageSource *source) #endif } } - else if(dynamic_pointer_cast(source->getEntity()) != NULL) + else if(source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_PLAYER)) { if(setSynchedAction(e_EnderdragonAction_StrafePlayer)) { @@ -1652,14 +1673,14 @@ Path *EnderDragon::findPath(int startIndex, int endIndex, Node *finalNode /* = N Node *from = m_nodes->data[startIndex]; Node *to = m_nodes->data[endIndex]; - from->g = 0; - from->h = from->distanceTo(to); - from->f = from->h; + from->g = 0; + from->h = from->distanceTo(to); + from->f = from->h; - openSet->clear(); - openSet->insert(from); + openSet->clear(); + openSet->insert(from); - Node *closest = from; + Node *closest = from; int minimumNodeIndex = 0; if(m_remainingCrystalsCount <= 0) @@ -1668,9 +1689,9 @@ Path *EnderDragon::findPath(int startIndex, int endIndex, Node *finalNode /* = N minimumNodeIndex = 12; } - while (!openSet->isEmpty()) + while (!openSet->isEmpty()) { - Node *x = openSet->pop(); + Node *x = openSet->pop(); if (x->equals(to)) { @@ -1680,14 +1701,14 @@ Path *EnderDragon::findPath(int startIndex, int endIndex, Node *finalNode /* = N finalNode->cameFrom = to; to = finalNode; } - return reconstruct_path(from, to); - } + return reconstruct_path(from, to); + } - if (x->distanceTo(to) < closest->distanceTo(to)) + if (x->distanceTo(to) < closest->distanceTo(to)) { - closest = x; - } - x->closed = true; + closest = x; + } + x->closed = true; unsigned int xIndex = 0; for(unsigned int i = 0; i < 24; ++i) @@ -1699,7 +1720,7 @@ Path *EnderDragon::findPath(int startIndex, int endIndex, Node *finalNode /* = N } } - for (int i = minimumNodeIndex; i < 24; i++) + for (int i = minimumNodeIndex; i < 24; i++) { if(m_nodeAdjacency[xIndex] & (1<cameFrom = closest; closest = finalNode; } - return reconstruct_path(from, closest); + return reconstruct_path(from, closest); } // function reconstruct_path(came_from,current_node) Path *EnderDragon::reconstruct_path(Node *from, Node *to) { - int count = 1; - Node *n = to; - while (n->cameFrom != NULL) + int count = 1; + Node *n = to; + while (n->cameFrom != NULL) { - count++; - n = n->cameFrom; - } - - NodeArray nodes = NodeArray(count); - n = to; - nodes.data[--count] = n; - while (n->cameFrom != NULL) + count++; + n = n->cameFrom; + } + + NodeArray nodes = NodeArray(count); + n = to; + nodes.data[--count] = n; + while (n->cameFrom != NULL) { - n = n->cameFrom; - nodes.data[--count] = n; - } + n = n->cameFrom; + nodes.data[--count] = n; + } Path *ret = new Path(nodes); delete [] nodes.data; - return ret; + return ret; } void EnderDragon::addAdditonalSaveData(CompoundTag *entityTag) @@ -1767,7 +1788,7 @@ void EnderDragon::addAdditonalSaveData(CompoundTag *entityTag) entityTag->putShort(L"RemainingCrystals", m_remainingCrystalsCount); entityTag->putInt(L"DragonState", (int)getSynchedAction() ); - BossMob::addAdditonalSaveData(entityTag); + Mob::addAdditonalSaveData(entityTag); } void EnderDragon::readAdditionalSaveData(CompoundTag *tag) @@ -1778,7 +1799,7 @@ void EnderDragon::readAdditionalSaveData(CompoundTag *tag) if(tag->contains(L"DragonState")) setSynchedAction( (EEnderdragonAction)tag->getInt(L"DragonState"), true); - BossMob::readAdditionalSaveData(tag); + Mob::readAdditionalSaveData(tag); } float EnderDragon::getTilt(float a) @@ -1895,7 +1916,7 @@ double EnderDragon::getHeadPartYRotDiff(int partIndex, doubleArray bodyPos, doub Vec3 *EnderDragon::getHeadLookVector(float a) { Vec3 *result = NULL; - + if( getSynchedAction() == e_EnderdragonAction_Landing || getSynchedAction() == e_EnderdragonAction_Takeoff ) { int eggHeight = level->getTopSolidBlock(PODIUM_X_POS,PODIUM_Z_POS); //level->getHeightmap(4,4); @@ -1903,7 +1924,7 @@ Vec3 *EnderDragon::getHeadLookVector(float a) if( dist < 1.0f ) dist = 1.0f; // The 6.0f is dragon->getHeadPartYOffset(6, start, p) float yOffset = 6.0f / dist; - + double xRotTemp = xRot; double rotScale = 1.5f; xRot = -yOffset * rotScale * 5.0f; diff --git a/Minecraft.World/EnderDragon.h b/Minecraft.World/EnderDragon.h index 8a12c08c..a13ecaa2 100644 --- a/Minecraft.World/EnderDragon.h +++ b/Minecraft.World/EnderDragon.h @@ -1,22 +1,22 @@ #pragma once using namespace std; #include "BossMob.h" +#include "MultiEntityMob.h" +#include "Enemy.h" -class BossMobPart; +class MultiEntityMobPart; class EnderCrystal; class Node; class BinaryHeap; class Path; -class EnderDragon : public BossMob +class EnderDragon : public Mob, public BossMob, public MultiEntityMob, public Enemy { public: eINSTANCEOF GetType() { return eTYPE_ENDERDRAGON; }; static Entity *create(Level *level) { return new EnderDragon(level); } -private: - static const int DATA_ID_SYNCHED_HEALTH = 16; - +private: // 4J Added for new behaviours static const int DATA_ID_SYNCHED_ACTION = 17; @@ -27,16 +27,16 @@ public: double positions[positionsLength][3]; int posPointer; - //BossMobPart[] subEntities; + //MultiEntityMobPart[] subEntities; vector > subEntities; - shared_ptr head; - shared_ptr neck; // 4J Added - shared_ptr body; - shared_ptr tail1; - shared_ptr tail2; - shared_ptr tail3; - shared_ptr wing1; - shared_ptr wing2; + shared_ptr head; + shared_ptr neck; // 4J Added + shared_ptr body; + shared_ptr tail1; + shared_ptr tail2; + shared_ptr tail3; + shared_ptr wing1; + shared_ptr wing2; float oFlapTime; float flapTime; @@ -112,9 +112,11 @@ private: public: EnderDragon(Level *level); + void AddParts(); virtual ~EnderDragon(); protected: + virtual void registerAttributes(); virtual void defineSynchedData(); public: @@ -122,7 +124,7 @@ public: virtual void aiStep(); private: - using BossMob::hurt; + using MultiEntityMob::hurt; void checkCrystals(); void checkAttack(); @@ -133,9 +135,11 @@ private: bool checkWalls(AABB *bb); public: - virtual bool hurt(shared_ptr bossMobPart, DamageSource *source, int damage); + virtual bool hurt(shared_ptr MultiEntityMobPart, DamageSource *source, float damage); + virtual bool hurt(DamageSource *source, float damage); protected: + virtual bool reallyHurt(DamageSource *source, float damage); virtual void tickDeath(); private: @@ -143,11 +147,15 @@ private: protected: virtual void checkDespawn(); - virtual int getHurtSound(); public: virtual vector > *getSubEntities(); virtual bool isPickable(); - virtual int getSynchedHealth(); + Level *getLevel(); + +protected: + int getAmbientSound(); + int getHurtSound(); + float getSoundVolume(); private: // 4J added for new dragon behaviour @@ -174,4 +182,8 @@ public: double getHeadPartYOffset(int partIndex, doubleArray bodyPos, doubleArray partPos); double getHeadPartYRotDiff(int partIndex, doubleArray bodyPos, doubleArray partPos); Vec3 *getHeadLookVector(float a); + + virtual wstring getAName() { return app.GetString(IDS_ENDERDRAGON); }; + virtual float getHealth() { return LivingEntity::getHealth(); }; + virtual float getMaxHealth() { return LivingEntity::getMaxHealth(); }; }; diff --git a/Minecraft.World/EnderEyeItem.cpp b/Minecraft.World/EnderEyeItem.cpp index a08c1f62..063e1408 100644 --- a/Minecraft.World/EnderEyeItem.cpp +++ b/Minecraft.World/EnderEyeItem.cpp @@ -18,11 +18,12 @@ bool EnderEyeItem::useOn(shared_ptr instance, shared_ptr p int targetType = level->getTile(x, y, z); int targetData = level->getData(x, y, z); - if (player->mayBuild(x, y, z) && targetType == Tile::endPortalFrameTile_Id && !TheEndPortalFrameTile::hasEye(targetData)) + if (player->mayUseItemAt(x, y, z, face, instance) && targetType == Tile::endPortalFrameTile_Id && !TheEndPortalFrameTile::hasEye(targetData)) { if(bTestUseOnOnly) return true; if (level->isClientSide) return true; - level->setData(x, y, z, targetData + TheEndPortalFrameTile::EYE_BIT); + level->setData(x, y, z, targetData + TheEndPortalFrameTile::EYE_BIT, Tile::UPDATE_CLIENTS); + level->updateNeighbourForOutputSignal(x, y, z, Tile::endPortalFrameTile_Id); instance->count--; for (int i = 0; i < 16; i++) @@ -121,7 +122,7 @@ bool EnderEyeItem::useOn(shared_ptr instance, shared_ptr p targetX += Direction::STEP_X[direction] * pz; targetZ += Direction::STEP_Z[direction] * pz; - level->setTile(targetX, y, targetZ, Tile::endPortalTile_Id); + level->setTileAndData(targetX, y, targetZ, Tile::endPortalTile_Id, 0, Tile::UPDATE_CLIENTS); } } } @@ -132,7 +133,7 @@ bool EnderEyeItem::useOn(shared_ptr instance, shared_ptr p return false; } -bool EnderEyeItem::TestUse(Level *level, shared_ptr player) +bool EnderEyeItem::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { HitResult *hr = getPlayerPOVHitResult(level, player, false); if (hr != NULL && hr->type == HitResult::TILE) @@ -210,29 +211,13 @@ shared_ptr EnderEyeItem::use(shared_ptr instance, Le eyeOfEnderSignal->signalTo(level->getLevelData()->getXStronghold()<<4, player->y + 1.62 - player->heightOffset, level->getLevelData()->getZStronghold()<<4); level->addEntity(eyeOfEnderSignal); - level->playSound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); + level->playEntitySound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); level->levelEvent(nullptr, LevelEvent::SOUND_LAUNCH, (int) player->x, (int) player->y, (int) player->z, 0); if (!player->abilities.instabuild) { instance->count--; } } - - /*TilePos *nearestMapFeature = level->findNearestMapFeature(LargeFeature::STRONGHOLD, (int) player->x, (int) player->y, (int) player->z); - if (nearestMapFeature != NULL) - { - shared_ptr eyeOfEnderSignal = shared_ptr( new EyeOfEnderSignal(level, player->x, player->y + 1.62 - player->heightOffset, player->z) ); - eyeOfEnderSignal->signalTo(nearestMapFeature->x, nearestMapFeature->y, nearestMapFeature->z); - delete nearestMapFeature; - level->addEntity(eyeOfEnderSignal); - - level->playSound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); - level->levelEvent(NULL, LevelEvent::SOUND_LAUNCH, (int) player->x, (int) player->y, (int) player->z, 0); - if (!player->abilities.instabuild) - { - instance->count--; - } - }*/ } return instance; } \ No newline at end of file diff --git a/Minecraft.World/EnderEyeItem.h b/Minecraft.World/EnderEyeItem.h index 72036aa5..cbe880d2 100644 --- a/Minecraft.World/EnderEyeItem.h +++ b/Minecraft.World/EnderEyeItem.h @@ -8,6 +8,6 @@ public: EnderEyeItem(int id); virtual bool useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); - virtual bool TestUse(Level *level, shared_ptr player); + virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); }; \ No newline at end of file diff --git a/Minecraft.World/EnderMan.cpp b/Minecraft.World/EnderMan.cpp index abfc5cb5..d099911c 100644 --- a/Minecraft.World/EnderMan.cpp +++ b/Minecraft.World/EnderMan.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" @@ -10,7 +12,7 @@ #include "..\Minecraft.Client\Textures.h" #include "EnderMan.h" - +AttributeModifier *EnderMan::SPEED_MODIFIER_ATTACKING = (new AttributeModifier(eModifierId_MOB_ENDERMAN_ATTACKSPEED, 6.2f, AttributeModifier::OPERATION_ADDITION))->setSerialize(false); bool EnderMan::MAY_TAKE[256]; @@ -23,8 +25,8 @@ void EnderMan::staticCtor() MAY_TAKE[Tile::gravel_Id] = true; MAY_TAKE[Tile::flower_Id] = true; MAY_TAKE[Tile::rose_Id] = true; - MAY_TAKE[Tile::mushroom1_Id] = true; - MAY_TAKE[Tile::mushroom2_Id] = true; + MAY_TAKE[Tile::mushroom_brown_Id] = true; + MAY_TAKE[Tile::mushroom_red_Id] = true; MAY_TAKE[Tile::tnt_Id] = true; MAY_TAKE[Tile::cactus_Id] = true; MAY_TAKE[Tile::clay_Id] = true; @@ -39,27 +41,28 @@ EnderMan::EnderMan(Level *level) : Monster( level ) // the derived version of the function is called // Brought forward from 1.2.3 this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); + setHealth(getMaxHealth()); // 4J initialisors teleportTime = 0; aggroTime = 0; + lastAttackTarget = nullptr; + aggroedByPlayer = false; - this->textureIdx = TN_MOB_ENDERMAN; // 4J was "/mob/enderman.png"; - runSpeed = 0.2f; - attackDamage = 7; setSize(0.6f, 2.9f); footSize = 1; } -int EnderMan::getMaxHealth() +void EnderMan::registerAttributes() { - return 40; + Monster::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(40); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.3f); + getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(7); } -// Brought forward from 1.2.3 void EnderMan::defineSynchedData() { Monster::defineSynchedData(); @@ -97,6 +100,8 @@ shared_ptr EnderMan::findAttackTarget() { if (isLookingAtMe(player)) { + aggroedByPlayer = true; + if (aggroTime == 0) level->playEntitySound(player, eSoundType_MOB_ENDERMAN_STARE, 1, 1); if (aggroTime++ == 5) { aggroTime = 0; @@ -131,48 +136,61 @@ bool EnderMan::isLookingAtMe(shared_ptr player) void EnderMan::aiStep() { - if (this->isInWaterOrRain()) hurt(DamageSource::drown, 1); + if (isInWaterOrRain()) hurt(DamageSource::drown, 1); + + if (lastAttackTarget != attackTarget) + { + AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + speed->removeModifier(SPEED_MODIFIER_ATTACKING); + + if (attackTarget != NULL) + { + speed->addModifier(new AttributeModifier(*SPEED_MODIFIER_ATTACKING)); + } + } - runSpeed = attackTarget != NULL ? 6.5f : 0.3f; + lastAttackTarget = attackTarget; if (!level->isClientSide) { - if (getCarryingTile() == 0) + if (level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) { - if (random->nextInt(20) == 0) + if (getCarryingTile() == 0) { - int xt = Mth::floor(x - 2 + random->nextDouble() * 4); - int yt = Mth::floor(y + random->nextDouble() * 3); - int zt = Mth::floor(z - 2 + random->nextDouble() * 4); - int t = level->getTile(xt, yt, zt); - //if (t > 0 && Tile::tiles[t]->isCubeShaped()) - if(EnderMan::MAY_TAKE[t]) // 4J - Brought forward from 1.2.3 + if (random->nextInt(20) == 0) { - setCarryingTile(level->getTile(xt, yt, zt)); - setCarryingData(level->getData(xt, yt, zt)); - level->setTile(xt, yt, zt, 0); + int xt = Mth::floor(x - 2 + random->nextDouble() * 4); + int yt = Mth::floor(y + random->nextDouble() * 3); + int zt = Mth::floor(z - 2 + random->nextDouble() * 4); + int t = level->getTile(xt, yt, zt); + if(MAY_TAKE[t]) + { + setCarryingTile(level->getTile(xt, yt, zt)); + setCarryingData(level->getData(xt, yt, zt)); + level->setTileAndUpdate(xt, yt, zt, 0); + } } } - } - else - { - if (random->nextInt(2000) == 0) + else { - int xt = Mth::floor(x - 1 + random->nextDouble() * 2); - int yt = Mth::floor(y + random->nextDouble() * 2); - int zt = Mth::floor(z - 1 + random->nextDouble() * 2); - int t = level->getTile(xt, yt, zt); - int bt = level->getTile(xt, yt - 1, zt); - if (t == 0 && bt > 0 && Tile::tiles[bt]->isCubeShaped()) + if (random->nextInt(2000) == 0) { - level->setTileAndData(xt, yt, zt, getCarryingTile(), getCarryingData()); - setCarryingTile(0); + int xt = Mth::floor(x - 1 + random->nextDouble() * 2); + int yt = Mth::floor(y + random->nextDouble() * 2); + int zt = Mth::floor(z - 1 + random->nextDouble() * 2); + int t = level->getTile(xt, yt, zt); + int bt = level->getTile(xt, yt - 1, zt); + if (t == 0 && bt > 0 && Tile::tiles[bt]->isCubeShaped()) + { + level->setTileAndData(xt, yt, zt, getCarryingTile(), getCarryingData(), Tile::UPDATE_ALL); + setCarryingTile(0); + } } } } } - // 4J - Brought forward particles from 1.2.3 + for (int i = 0; i < 2; i++) { level->addParticle(eParticleType_ender, x + (random->nextDouble() - 0.5) * bbWidth, y + random->nextDouble() * bbHeight - 0.25f, z + (random->nextDouble() - 0.5) * bbWidth, @@ -184,37 +202,41 @@ void EnderMan::aiStep() float br = getBrightness(1); if (br > 0.5f) { - if (level->canSeeSky(Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random->nextFloat() * 30 < (br - 0.4f) * 2) + if (level->canSeeSky(Mth::floor(x), (int)floor( y + 0.5 ), Mth::floor(z)) && random->nextFloat() * 30 < (br - 0.4f) * 2) { - // 4J - Brought forward behaviour change from 1.2.3 - //onFire = 20 * 15; attackTarget = nullptr; setCreepy(false); + aggroedByPlayer = false; teleport(); } } } - // 4J Brought forward behaviour change from 1.2.3 + if (isInWaterOrRain() || isOnFire()) { attackTarget = nullptr; setCreepy(false); + aggroedByPlayer = false; teleport(); } + + if (isCreepy() && !aggroedByPlayer && random->nextInt(100) == 0) + { + setCreepy(false); + } + jumping = false; if (attackTarget != NULL) { - this->lookAt(attackTarget, 100, 100); + lookAt(attackTarget, 100, 100); } if (!level->isClientSide && isAlive()) { if (attackTarget != NULL) { - if ( dynamic_pointer_cast(attackTarget) != NULL && isLookingAtMe(dynamic_pointer_cast(attackTarget))) + if ( attackTarget->instanceof(eTYPE_PLAYER) && isLookingAtMe(dynamic_pointer_cast(attackTarget))) { - xxa = yya = 0; - runSpeed = 0; if (attackTarget->distanceToSqr(shared_from_this()) < 4 * 4) { teleport(); @@ -316,13 +338,10 @@ bool EnderMan::teleport(double xx, double yy, double zz) double _y = yo + (y - yo) * d + random->nextDouble() * bbHeight; double _z = zo + (z - zo) * d + (random->nextDouble() - 0.5) * bbWidth * 2; - // 4J - Brought forward particle change from 1.2.3 - //level->addParticle(eParticleType_largesmoke, _x, _y, _z, xa, ya, za); level->addParticle(eParticleType_ender, _x, _y, _z, xa, ya, za); } - // 4J - moved sounds forward from 1.2.3 level->playSound(xo, yo, zo, eSoundType_MOB_ENDERMEN_PORTAL, 1, 1); - level->playSound(shared_from_this(), eSoundType_MOB_ENDERMEN_PORTAL, 1, 1); + playSound(eSoundType_MOB_ENDERMEN_PORTAL, 1, 1); return true; } else @@ -334,19 +353,16 @@ bool EnderMan::teleport(double xx, double yy, double zz) int EnderMan::getAmbientSound() { - // 4J - brought sound change forward from 1.2.3 - return eSoundType_MOB_ENDERMEN_IDLE; + return isCreepy()? eSoundType_MOB_ENDERMAN_SCREAM : eSoundType_MOB_ENDERMEN_IDLE; } int EnderMan::getHurtSound() { - // 4J - brought sound change forward from 1.2.3 return eSoundType_MOB_ENDERMEN_HIT; } int EnderMan::getDeathSound() { - // 4J - brought sound change forward from 1.2.3 return eSoundType_MOB_ENDERMEN_DEATH; } @@ -387,13 +403,25 @@ int EnderMan::getCarryingData() return entityData->getByte(DATA_CARRY_ITEM_DATA); } -bool EnderMan::hurt(DamageSource *source, int damage) +bool EnderMan::hurt(DamageSource *source, float damage) { + if (isInvulnerable()) return false; + setCreepy(true); + + if ( dynamic_cast(source) != NULL && source->getEntity()->instanceof(eTYPE_PLAYER)) + { + aggroedByPlayer = true; + } + if (dynamic_cast(source) != NULL) { + aggroedByPlayer = false; for (int i = 0; i < 64; i++) { - if (teleport()) return true; + if (teleport()) + { + return true; + } } return false; } diff --git a/Minecraft.World/EnderMan.h b/Minecraft.World/EnderMan.h index f5084532..10fb2b37 100644 --- a/Minecraft.World/EnderMan.h +++ b/Minecraft.World/EnderMan.h @@ -10,6 +10,8 @@ public: public: static void staticCtor(); private: + static AttributeModifier *SPEED_MODIFIER_ATTACKING; + static bool MAY_TAKE[256]; static const int DATA_CARRY_ITEM_ID = 16; @@ -19,13 +21,14 @@ private: private: int teleportTime; int aggroTime; + shared_ptr lastAttackTarget; + bool aggroedByPlayer; public: EnderMan(Level *level); - virtual int getMaxHealth(); - protected: + virtual void registerAttributes(); virtual void defineSynchedData(); public: @@ -53,12 +56,11 @@ protected: virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); public: - // 4J Brought forward from 1.2.3 to help fix Enderman behaviour void setCarryingTile(int carryingTile); int getCarryingTile(); void setCarryingData(int carryingData); int getCarryingData(); - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); bool isCreepy(); void setCreepy(bool creepy); }; \ No newline at end of file diff --git a/Minecraft.World/EnderpearlItem.cpp b/Minecraft.World/EnderpearlItem.cpp index 7a9b6e52..e1ed693b 100644 --- a/Minecraft.World/EnderpearlItem.cpp +++ b/Minecraft.World/EnderpearlItem.cpp @@ -7,10 +7,10 @@ EnderpearlItem::EnderpearlItem(int id) : Item(id) { - this->maxStackSize = 16; + maxStackSize = 16; } -bool EnderpearlItem::TestUse(Level *level, shared_ptr player) +bool EnderpearlItem::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { return true; } @@ -25,7 +25,7 @@ shared_ptr EnderpearlItem::use(shared_ptr instance, instance->count--; } - level->playSound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); + level->playEntitySound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); if (!level->isClientSide) { level->addEntity( shared_ptr( new ThrownEnderpearl(level, player) ) ); diff --git a/Minecraft.World/EnderpearlItem.h b/Minecraft.World/EnderpearlItem.h index 84913b9e..973f5284 100644 --- a/Minecraft.World/EnderpearlItem.h +++ b/Minecraft.World/EnderpearlItem.h @@ -9,5 +9,5 @@ public: virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); // 4J added - virtual bool TestUse(Level *level, shared_ptr player); + virtual bool TestUse(shared_ptr instance, Level *level, shared_ptr player); }; \ No newline at end of file diff --git a/Minecraft.World/Enemy.cpp b/Minecraft.World/Enemy.cpp index 25d1ad47..b9aa3e20 100644 --- a/Minecraft.World/Enemy.cpp +++ b/Minecraft.World/Enemy.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" #include "Enemy.h" +EntitySelector *Enemy::ENEMY_SELECTOR = new Enemy::EnemyEntitySelector(); - -const int Enemy::XP_REWARD_NONE = 0; -const int Enemy::XP_REWARD_SMALL = 3; -const int Enemy::XP_REWARD_MEDIUM = 5; -const int Enemy::XP_REWARD_LARGE = 10; -const int Enemy::XP_REWARD_HUGE = 20; \ No newline at end of file +bool Enemy::EnemyEntitySelector::matches(shared_ptr entity) const +{ + return (entity != NULL) && entity->instanceof(eTYPE_ENEMY); +} \ No newline at end of file diff --git a/Minecraft.World/Enemy.h b/Minecraft.World/Enemy.h index cb7d3a3e..9d5f4603 100644 --- a/Minecraft.World/Enemy.h +++ b/Minecraft.World/Enemy.h @@ -1,14 +1,21 @@ #pragma once #include "Creature.h" - -class Level; +#include "EntitySelector.h" class Enemy : public Creature { public: - static const int XP_REWARD_NONE; - static const int XP_REWARD_SMALL; - static const int XP_REWARD_MEDIUM; - static const int XP_REWARD_LARGE; - static const int XP_REWARD_HUGE; + class EnemyEntitySelector : public EntitySelector + { + bool matches(shared_ptr entity) const; + }; + + static const int XP_REWARD_NONE = 0; + static const int XP_REWARD_SMALL = 3; + static const int XP_REWARD_MEDIUM = 5; + static const int XP_REWARD_LARGE = 10; + static const int XP_REWARD_HUGE = 20; + static const int XP_REWARD_BOSS = 50; + + static EntitySelector *ENEMY_SELECTOR; }; diff --git a/Minecraft.World/Entity.cpp b/Minecraft.World/Entity.cpp index 4c9d5cf6..f1c2259c 100644 --- a/Minecraft.World/Entity.cpp +++ b/Minecraft.World/Entity.cpp @@ -3,6 +3,7 @@ #include "net.minecraft.world.item.h" #include "net.minecraft.world.item.enchantment.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.dimension.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.entity.item.h" @@ -21,7 +22,10 @@ #include "..\Minecraft.Client\MinecraftServer.h" #include "..\Minecraft.Client\MultiPlayerLevel.h" #include "..\Minecraft.Client\MultiplayerLocalPlayer.h" +#include "..\Minecraft.Client\ServerLevel.h" +#include "..\Minecraft.Client\PlayerList.h" +const wstring Entity::RIDING_TAG = L"Riding"; int Entity::entityCounter = 2048; // 4J - changed initialiser to 2048, as we are using range 0 - 2047 as special unique smaller ids for things that need network tracked DWORD Entity::tlsIdx = TlsAlloc(); @@ -55,7 +59,7 @@ int Entity::getSmallId() if( removedFound ) { // Has set up the entityIdRemovingFlags vector in this case, so we should check against this when allocating new ids -// app.DebugPrintf("getSmallId: Removed entities found\n"); + // app.DebugPrintf("getSmallId: Removed entities found\n"); puiRemovedFlags = entityIdRemovingFlags; } } @@ -75,7 +79,7 @@ int Entity::getSmallId() { if( puiRemovedFlags[i] & uiMask ) { -// app.DebugPrintf("Avoiding using ID %d (0x%x)\n", i * 32 + j,puiRemovedFlags[i]); + // app.DebugPrintf("Avoiding using ID %d (0x%x)\n", i * 32 + j,puiRemovedFlags[i]); uiMask >>= 1; continue; } @@ -234,7 +238,7 @@ void Entity::tickExtraWandering() // 4J - added for common ctor code // Do all the default initialisations done in the java class -void Entity::_init(bool useSmallId) +void Entity::_init(bool useSmallId, Level *level) { // 4J - changed to assign two different types of ids. A range from 0-2047 is used for things that we'll be wanting to identify over the network, // so we should only need 11 bits rather than 32 to uniquely identify them. The rest of the range is used for anything we don't need to track like this, @@ -254,6 +258,7 @@ void Entity::_init(bool useSmallId) blocksBuilding = false; rider = weak_ptr(); riding = nullptr; + forcedLoading = false; //level = NULL; // Level is assigned to in the original c_tor code xo = yo = zo = 0.0; @@ -277,6 +282,7 @@ void Entity::_init(bool useSmallId) walkDistO = 0; walkDist = 0; + moveDist = 0.0f; fallDistance = 0; @@ -301,15 +307,17 @@ void Entity::_init(bool useSmallId) firstTick = true; - - customTextureUrl = L""; - customTextureUrl2 = L""; - - fireImmune = false; // values that need to be sent to clients in SMP - entityData = shared_ptr(new SynchedEntityData()); + if( useSmallId ) + { + entityData = shared_ptr(new SynchedEntityData()); + } + else + { + entityData = nullptr; + } xRideRotA = yRideRotA = 0.0; inChunk = false; @@ -320,23 +328,43 @@ void Entity::_init(bool useSmallId) hasImpulse = false; + changingDimensionDelay = 0; + isInsidePortal = false; + portalTime = 0; + dimension = 0; + portalEntranceDir = 0; + invulnerable = false; + if( useSmallId ) + { + uuid = L"ent" + Mth::createInsecureUUID(random); + } + // 4J Added m_ignoreVerticalCollisions = false; m_uiAnimOverrideBitmask = 0L; + m_ignorePortal = false; } Entity::Entity(Level *level, bool useSmallId) // 4J - added useSmallId parameter { MemSect(16); - _init(useSmallId); + _init(useSmallId, level); MemSect(0); this->level = level; // resetPos(); setPos(0, 0, 0); - entityData->define(DATA_SHARED_FLAGS_ID, (byte) 0); - entityData->define(DATA_AIR_SUPPLY_ID, TOTAL_AIR_SUPPLY); // 4J Stu - Brought forward from 1.2.3 to fix 38654 - Gameplay: Player will take damage when air bubbles are present if resuming game from load/autosave underwater. + if (level != NULL) + { + dimension = level->dimension->id; + } + + if( entityData ) + { + entityData->define(DATA_SHARED_FLAGS_ID, (byte) 0); + entityData->define(DATA_AIR_SUPPLY_ID, TOTAL_AIR_SUPPLY); // 4J Stu - Brought forward from 1.2.3 to fix 38654 - Gameplay: Player will take damage when air bubbles are present if resuming game from load/autosave underwater. + } // 4J Stu - We cannot call virtual functions in ctors, as at this point the object // is of type Entity and not a derived class @@ -482,9 +510,11 @@ void Entity::baseTick() // 4J Stu - Not needed //util.Timer.push("entityBaseTick"); - if (riding != NULL && riding->removed) riding = nullptr; + if (riding != NULL && riding->removed) + { + riding = nullptr; + } - tickCount++; walkDistO = walkDist; xo = x; yo = y; @@ -492,10 +522,54 @@ void Entity::baseTick() xRotO = xRot; yRotO = yRot; + if (!level->isClientSide) // 4J Stu - Don't need this && level instanceof ServerLevel) + { + if(!m_ignorePortal) // 4J Added + { + MinecraftServer *server = dynamic_cast(level)->getServer(); + int waitTime = getPortalWaitTime(); + + if (isInsidePortal) + { + if (server->isNetherEnabled()) + { + if (riding == NULL) + { + if (portalTime++ >= waitTime) + { + portalTime = waitTime; + changingDimensionDelay = getDimensionChangingDelay(); + + int targetDimension; + + if (level->dimension->id == -1) + { + targetDimension = 0; + } + else + { + targetDimension = -1; + } + + changeDimension(targetDimension); + } + } + isInsidePortal = false; + } + } + else + { + if (portalTime > 0) portalTime -= 4; + if (portalTime < 0) portalTime = 0; + } + if (changingDimensionDelay > 0) changingDimensionDelay--; + } + } + if (isSprinting() && !isInWater() && canCreateParticles()) { int xt = Mth::floor(x); - int yt = Mth::floor(y - 0.2f - this->heightOffset); + int yt = Mth::floor(y - 0.2f - heightOffset); int zt = Mth::floor(z); int t = level->getTile(xt, yt, zt); int d = level->getData(xt, yt, zt); @@ -505,37 +579,7 @@ void Entity::baseTick() } } - if (updateInWaterState()) - { - if (!wasInWater && !firstTick && canCreateParticles()) - { - float speed = Mth::sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.2f; - if (speed > 1) speed = 1; - MemSect(31); - level->playSound(shared_from_this(), eSoundType_RANDOM_SPLASH, speed, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f); - MemSect(0); - float yt = (float) Mth::floor(bb->y0); - for (int i = 0; i < 1 + bbWidth * 20; i++) - { - float xo = (random->nextFloat() * 2 - 1) * bbWidth; - float zo = (random->nextFloat() * 2 - 1) * bbWidth; - level->addParticle(eParticleType_bubble, x + xo, yt + 1, z + zo, xd, yd - random->nextFloat() * 0.2f, zd); - } - for (int i = 0; i < 1 + bbWidth * 20; i++) - { - float xo = (random->nextFloat() * 2 - 1) * bbWidth; - float zo = (random->nextFloat() * 2 - 1) * bbWidth; - level->addParticle(eParticleType_splash, x + xo, yt + 1, z + zo, xd, yd, zd); - } - } - fallDistance = 0; - wasInWater = true; - onFire = 0; - } - else - { - wasInWater = false; - } + updateInWaterState(); if (level->isClientSide) { @@ -575,7 +619,6 @@ void Entity::baseTick() if (!level->isClientSide) { setSharedFlag(FLAG_ONFIRE, onFire > 0); - setSharedFlag(FLAG_RIDING, riding != NULL); } firstTick = false; @@ -584,6 +627,10 @@ void Entity::baseTick() //util.Timer.pop(); } +int Entity::getPortalWaitTime() +{ + return 0; +} void Entity::lavaHurt() { @@ -650,6 +697,7 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - ySlideOffset *= 0.4f; double xo = x; + double yo = y; double zo = z; if (isStuckInWeb) @@ -670,7 +718,7 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - AABB *bbOrg = bb->copy(); - bool isPlayerSneaking = onGround && isSneaking() && dynamic_pointer_cast(shared_from_this()) != NULL; + bool isPlayerSneaking = onGround && isSneaking() && instanceof(eTYPE_PLAYER); if (isPlayerSneaking) { @@ -709,8 +757,8 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - AUTO_VAR(itEndAABB, aABBs->end()); // 4J Stu - Particles (and possibly other entities) don't have xChunk and zChunk set, so calculate the chunk instead - int xc = Mth::floor(x / 16); - int zc = Mth::floor(z / 16); + int xc = Mth::floor(x / 16); + int zc = Mth::floor(z / 16); if(!level->isClientSide || level->reallyHasChunk(xc, zc)) { // 4J Stu - It's horrible that the client is doing any movement at all! But if we don't have the chunk @@ -824,13 +872,6 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - za = zaN; bb->set(normal); } - else - { - double ss = bb->y0 - (int) bb->y0; - if (ss > 0) { - ySlideOffset += (float) (ss + 0.01); - } - } } @@ -849,14 +890,14 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - if (zaOrg != za) zd = 0; double xm = x - xo; + double ym = y - yo; double zm = z - zo; if (makeStepSound() && !isPlayerSneaking && riding == NULL) { - walkDist += (float) ( sqrt(xm * xm + zm * zm) * 0.6 ); int xt = Mth::floor(x); - int yt = Mth::floor(y - 0.2f - this->heightOffset); + int yt = Mth::floor(y - 0.2f - heightOffset); int zt = Mth::floor(z); int t = level->getTile(xt, yt, zt); if (t == 0) @@ -867,10 +908,23 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - t = level->getTile(xt, yt - 1, zt); } } + if (t != Tile::ladder_Id) + { + ym = 0; + } + + walkDist += Mth::sqrt(xm * xm + zm * zm) * 0.6; + moveDist += Mth::sqrt(xm * xm + ym * ym + zm * zm) * 0.6; - if (walkDist > nextStep && t > 0) + if (moveDist > nextStep && t > 0) { - nextStep = (int) walkDist + 1; + nextStep = (int) moveDist + 1; + if (isInWater()) + { + float speed = Mth::sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.35f; + if (speed > 1) speed = 1; + playSound(eSoundType_LIQUID_SWIM, speed, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f); + } playStepSound(xt, yt, zt, t); Tile::tiles[t]->stepOn(level, xt, yt, zt, shared_from_this()); } @@ -879,7 +933,7 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - checkInsideTiles(); - bool water = this->isInWaterOrRain(); + bool water = isInWaterOrRain(); if (level->containsFireTile(bb->shrink(0.001, 0.001, 0.001))) { burn(1); @@ -899,7 +953,7 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - if (water && onFire > 0) { - level->playSound(shared_from_this(), eSoundType_RANDOM_FIZZ, 0.7f, 1.6f + (random->nextFloat() - random->nextFloat()) * 0.4f); + playSound(eSoundType_RANDOM_FIZZ, 0.7f, 1.6f + (random->nextFloat() - random->nextFloat()) * 0.4f); onFire = -flameTime; } } @@ -933,7 +987,8 @@ void Entity::playStepSound(int xt, int yt, int zt, int t) { const Tile::SoundType *soundType = Tile::tiles[t]->soundType; MemSect(31); - if(GetType() == eTYPE_PLAYER) + + if (GetType() == eTYPE_PLAYER) { // should we turn off step sounds? unsigned int uiAnimOverrideBitmask=getAnimOverrideBitmask(); // this is masked for custom anim off, and force anim @@ -943,51 +998,23 @@ void Entity::playStepSound(int xt, int yt, int zt, int t) return; } - MultiPlayerLevel *mplevel= (MultiPlayerLevel *)level; - - if(mplevel) - { - if (level->getTile(xt, yt + 1, zt) == Tile::topSnow_Id) - { - soundType = Tile::topSnow->soundType; - mplevel->playLocalSound((double)xt+0.5,(double)yt,(double)zt+0.5,soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); - } - else if (!Tile::tiles[t]->material->isLiquid()) - { - mplevel->playLocalSound((double)xt+0.5,(double)yt,(double)zt+0.5,soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); - } - } - else - { - if (level->getTile(xt, yt + 1, zt) == Tile::topSnow_Id) - { - soundType = Tile::topSnow->soundType; - level->playLocalSound((double)xt+0.5,(double)yt,(double)zt+0.5,soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); - } - else if (!Tile::tiles[t]->material->isLiquid()) - { - level->playLocalSound((double)xt+0.5,(double)yt,(double)zt+0.5,soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); - } - } } - else + if (level->getTile(xt, yt + 1, zt) == Tile::topSnow_Id) { - if (level->getTile(xt, yt + 1, zt) == Tile::topSnow_Id) - { - soundType = Tile::topSnow->soundType; - level->playSound(shared_from_this(), soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); - } - else if (!Tile::tiles[t]->material->isLiquid()) - { - level->playSound(shared_from_this(), soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); - } + soundType = Tile::topSnow->soundType; + playSound(soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); + } + else if (!Tile::tiles[t]->material->isLiquid()) + { + playSound(soundType->getStepSound(), soundType->getVolume() * 0.15f, soundType->getPitch()); } + MemSect(0); } void Entity::playSound(int iSound, float volume, float pitch) { - level->playSound(shared_from_this(), iSound, volume, pitch); + level->playEntitySound(shared_from_this(), iSound, volume, pitch); } bool Entity::makeStepSound() @@ -1001,22 +1028,6 @@ void Entity::checkFallDamage(double ya, bool onGround) { if (fallDistance > 0) { - if (dynamic_pointer_cast(shared_from_this()) != NULL) - { - int xt = Mth::floor(x); - int yt = Mth::floor(y - 0.2f - this->heightOffset); - int zt = Mth::floor(z); - int t = level->getTile(xt, yt, zt); - if (t == 0 && level->getTile(xt, yt - 1, zt) == Tile::fence_Id) - { - t = level->getTile(xt, yt - 1, zt); - } - - if (t > 0) - { - Tile::tiles[t]->fallOn(level, xt, yt, zt, shared_from_this(), fallDistance); - } - } causeFallDamage(fallDistance); fallDistance = 0; } @@ -1053,7 +1064,7 @@ void Entity::causeFallDamage(float distance) bool Entity::isInWaterOrRain() { - return wasInWater || (level->isRainingAt( Mth::floor(x), Mth::floor(y), Mth::floor(z))); + return wasInWater || (level->isRainingAt( Mth::floor(x), Mth::floor(y), Mth::floor(z)) || level->isRainingAt(Mth::floor(x), Mth::floor(y + bbHeight), Mth::floor(z))); } bool Entity::isInWater() @@ -1063,7 +1074,38 @@ bool Entity::isInWater() bool Entity::updateInWaterState() { - return level->checkAndHandleWater(bb->grow(0, -0.4f, 0)->shrink(0.001, 0.001, 0.001), Material::water, shared_from_this()); + if(level->checkAndHandleWater(bb->grow(0, -0.4f, 0)->shrink(0.001, 0.001, 0.001), Material::water, shared_from_this())) + { + if (!wasInWater && !firstTick && canCreateParticles()) + { + float speed = Mth::sqrt(xd * xd * 0.2f + yd * yd + zd * zd * 0.2f) * 0.2f; + if (speed > 1) speed = 1; + MemSect(31); + playSound(eSoundType_RANDOM_SPLASH, speed, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f); + MemSect(0); + float yt = (float) Mth::floor(bb->y0); + for (int i = 0; i < 1 + bbWidth * 20; i++) + { + float xo = (random->nextFloat() * 2 - 1) * bbWidth; + float zo = (random->nextFloat() * 2 - 1) * bbWidth; + level->addParticle(eParticleType_bubble, x + xo, yt + 1, z + zo, xd, yd - random->nextFloat() * 0.2f, zd); + } + for (int i = 0; i < 1 + bbWidth * 20; i++) + { + float xo = (random->nextFloat() * 2 - 1) * bbWidth; + float zo = (random->nextFloat() * 2 - 1) * bbWidth; + level->addParticle(eParticleType_splash, x + xo, yt + 1, z + zo, xd, yd, zd); + } + } + fallDistance = 0; + wasInWater = true; + onFire = 0; + } + else + { + wasInWater = false; + } + return wasInWater; } bool Entity::isUnderLiquid(Material *material) @@ -1118,7 +1160,7 @@ int Entity::getLightColor(float a) if (level->hasChunkAt(xTile, 0, zTile)) { double hh = (bb->y1 - bb->y0) * 0.66; - int yTile = Mth::floor(y - this->heightOffset + hh); + int yTile = Mth::floor(y - heightOffset + hh); return level->getLightColor(xTile, yTile, zTile, 0); } return 0; @@ -1132,7 +1174,7 @@ float Entity::getBrightness(float a) if (level->hasChunkAt(xTile, 0, zTile)) { double hh = (bb->y1 - bb->y0) * 0.66; - int yTile = Mth::floor(y - this->heightOffset + hh); + int yTile = Mth::floor(y - heightOffset + hh); return level->getBrightness(xTile, yTile, zTile); } return 0; @@ -1145,28 +1187,28 @@ void Entity::setLevel(Level *level) void Entity::absMoveTo(double x, double y, double z, float yRot, float xRot) { - this->xo = this->x = x; - this->yo = this->y = y; - this->zo = this->z = z; - this->yRotO = this->yRot = yRot; - this->xRotO = this->xRot = xRot; + xo = this->x = x; + yo = this->y = y; + zo = this->z = z; + yRotO = this->yRot = yRot; + xRotO = this->xRot = xRot; ySlideOffset = 0; double yRotDiff = yRotO - yRot; if (yRotDiff < -180) yRotO += 360; if (yRotDiff >= 180) yRotO -= 360; - this->setPos(this->x, this->y, this->z); - this->setRot(yRot, xRot); + setPos(this->x, this->y, this->z); + setRot(yRot, xRot); } void Entity::moveTo(double x, double y, double z, float yRot, float xRot) { - this->xOld = this->xo = this->x = x; - this->yOld = this->yo = this->y = y + heightOffset; - this->zOld = this->zo = this->z = z; + xOld = xo = this->x = x; + yOld = yo = this->y = y + heightOffset; + zOld = zo = this->z = z; this->yRot = yRot; this->xRot = xRot; - this->setPos(this->x, this->y, this->z); + setPos(this->x, this->y, this->z); } float Entity::distanceTo(shared_ptr e) @@ -1231,7 +1273,7 @@ void Entity::push(shared_ptr e) xa *= 1 - pushthrough; za *= 1 - pushthrough; - this->push(-xa, 0, -za); + push(-xa, 0, -za); e->push(xa, 0, za); } } @@ -1241,18 +1283,17 @@ void Entity::push(double xa, double ya, double za) xd += xa; yd += ya; zd += za; - this->hasImpulse = true; + hasImpulse = true; } - void Entity::markHurt() { - this->hurtMarked = true; + hurtMarked = true; } - -bool Entity::hurt(DamageSource *source, int damage) +bool Entity::hurt(DamageSource *source, float damage) { + if(isInvulnerable()) return false; markHurt(); return false; } @@ -1297,21 +1338,28 @@ bool Entity::shouldRenderAtSqrDistance(double distance) return distance < size * size; } -// 4J - used to be wstring return type, returning L"" -int Entity::getTexture() +bool Entity::isCreativeModeAllowed() { - return -1; + return false; } -bool Entity::isCreativeModeAllowed() +bool Entity::saveAsMount(CompoundTag *entityTag) { - return false; + wstring id = getEncodeId(); + if (removed || id.empty() ) + { + return false; + } + // TODO Is this fine to be casting to a non-const char pointer? + entityTag->putString(L"id", id ); + saveWithoutId(entityTag); + return true; } bool Entity::save(CompoundTag *entityTag) { wstring id = getEncodeId(); - if (removed || id.empty() ) + if (removed || id.empty() || (rider.lock() != NULL) ) { return false; } @@ -1331,8 +1379,22 @@ void Entity::saveWithoutId(CompoundTag *entityTag) entityTag->putShort(L"Fire", (short) onFire); entityTag->putShort(L"Air", (short) getAirSupply()); entityTag->putBoolean(L"OnGround", onGround); + entityTag->putInt(L"Dimension", dimension); + entityTag->putBoolean(L"Invulnerable", invulnerable); + entityTag->putInt(L"PortalCooldown", changingDimensionDelay); + + entityTag->putString(L"UUID", uuid); addAdditonalSaveData(entityTag); + + if (riding != NULL) + { + CompoundTag *ridingTag = new CompoundTag(RIDING_TAG); + if (riding->saveAsMount(ridingTag)) + { + entityTag->put(L"Riding", ridingTag); + } + } } void Entity::load(CompoundTag *tag) @@ -1369,19 +1431,43 @@ void Entity::load(CompoundTag *tag) onFire = tag->getShort(L"Fire"); setAirSupply(tag->getShort(L"Air")); onGround = tag->getBoolean(L"OnGround"); + dimension = tag->getInt(L"Dimension"); + invulnerable = tag->getBoolean(L"Invulnerable"); + changingDimensionDelay = tag->getInt(L"PortalCooldown"); + + if (tag->contains(L"UUID")) + { + uuid = tag->getString(L"UUID"); + } setPos(x, y, z); setRot(yRot, xRot); readAdditionalSaveData(tag); + + // set position again because bb size may have changed + if (repositionEntityAfterLoad()) setPos(x, y, z); } +bool Entity::repositionEntityAfterLoad() +{ + return true; +} const wstring Entity::getEncodeId() { return EntityIO::getEncodeId( shared_from_this() ); } +/** +* Called after load() has finished and the entity has been added to the +* world +*/ +void Entity::onLoadedFromSave() +{ + +} + ListTag *Entity::newDoubleList(unsigned int number, double firstValue, ...) { ListTag *res = new ListTag(); @@ -1449,6 +1535,10 @@ shared_ptr Entity::spawnAtLocation(int resource, int count, float yO shared_ptr Entity::spawnAtLocation(shared_ptr itemInstance, float yOffs) { + if (itemInstance->count == 0) + { + return nullptr; + } shared_ptr ie = shared_ptr( new ItemEntity(level, x, y + yOffs, z, itemInstance) ); ie->throwTime = 10; level->addEntity(ie); @@ -1468,7 +1558,7 @@ bool Entity::isInWall() float yo = ((i >> 1) % 2 - 0.5f) * 0.1f; float zo = ((i >> 2) % 2 - 0.5f) * bbWidth * 0.8f; int xt = Mth::floor(x + xo); - int yt = Mth::floor(y + this->getHeadHeight() + yo); + int yt = Mth::floor(y + getHeadHeight() + yo); int zt = Mth::floor(z + zo); if (level->isSolidBlockingTile(xt, yt, zt)) { @@ -1525,24 +1615,20 @@ void Entity::rideTick() yRideRotA -= yra; xRideRotA -= xra; - yRot += (float) yra; - xRot += (float) xra; + // jeb: This caused the crosshair to "drift" while riding horses. For now I've just disabled it, + // because I can't figure out what it's needed for. Riding boats and minecarts seem unaffected... + // yRot += yra; + // xRot += xra; } void Entity::positionRider() { shared_ptr lockedRider = rider.lock(); - if( lockedRider ) + if( lockedRider == NULL) { - shared_ptr player = dynamic_pointer_cast(lockedRider); - if (!(player && player->isLocalPlayer())) - { - lockedRider->xOld = xOld; - lockedRider->yOld = yOld + getRideHeight() + lockedRider->getRidingHeight(); - lockedRider->zOld = zOld; - } - lockedRider->setPos(x, y + getRideHeight() + lockedRider->getRidingHeight(), z); + return; } + lockedRider->setPos(x, y + getRideHeight() + lockedRider->getRidingHeight(), z); } double Entity::getRidingHeight() @@ -1564,7 +1650,7 @@ void Entity::ride(shared_ptr e) { if (riding != NULL) { - // 4J Stu - Position should already be updated before the SetRidingPacket comes in + // 4J Stu - Position should already be updated before the SetEntityLinkPacket comes in if(!level->isClientSide) moveTo(riding->x, riding->bb->y0 + riding->bbHeight, riding->z, yRot, xRot); riding->rider = weak_ptr(); } @@ -1579,52 +1665,6 @@ void Entity::ride(shared_ptr e) e->rider = shared_from_this(); } -// 4J Stu - Brought forward from 12w36 to fix #46282 - TU5: Gameplay: Exiting the minecart in a tight corridor damages the player -void Entity::findStandUpPosition(shared_ptr vehicle) -{ - AABB *boundingBox; - double fallbackX = vehicle->x; - double fallbackY = vehicle->bb->y0 + vehicle->bbHeight; - double fallbackZ = vehicle->z; - - for (double xDiff = -1.5; xDiff < 2; xDiff += 1.5) - { - for (double zDiff = -1.5; zDiff < 2; zDiff += 1.5) - { - if (xDiff == 0 && zDiff == 0) - { - continue; - } - - int xToInt = (int) (this->x + xDiff); - int zToInt = (int) (this->z + zDiff); - - // 4J Stu - Added loop over y to restaring the bb into 2 block high spaces if required (eg the track block plus 1 air block above it for minecarts) - for(double yDiff = 1.0; yDiff >= 0; yDiff -= 0.5) - { - boundingBox = this->bb->cloneMove(xDiff, yDiff, zDiff); - - if (level->getTileCubes(boundingBox,true)->size() == 0) - { - if (level->isTopSolidBlocking(xToInt, (int) (y - (1-yDiff)), zToInt)) - { - this->moveTo(this->x + xDiff, this->y + yDiff, this->z + zDiff, yRot, xRot); - return; - } - else if (level->isTopSolidBlocking(xToInt, (int) (y - (1-yDiff)) - 1, zToInt) || level->getMaterial(xToInt, (int) (y - (1-yDiff)) - 1, zToInt) == Material::water) - { - fallbackX = x + xDiff; - fallbackY = y + yDiff; - fallbackZ = z + zDiff; - } - } - } - } - } - - this->moveTo(fallbackX, fallbackY, fallbackZ, yRot, xRot); -} - void Entity::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) { setPos(x, y, z); @@ -1663,6 +1703,26 @@ Vec3 *Entity::getLookAngle() void Entity::handleInsidePortal() { + if (changingDimensionDelay > 0) + { + changingDimensionDelay = getDimensionChangingDelay(); + return; + } + + double xd = xo - x; + double zd = zo - z; + + if (!level->isClientSide && !isInsidePortal) + { + portalEntranceDir = Direction::getDirection(xd, zd); + } + + isInsidePortal = true; +} + +int Entity::getDimensionChangingDelay() +{ + return SharedConstants::TICKS_PER_SECOND * 45; } void Entity::lerpMotion(double xd, double yd, double zd) @@ -1680,10 +1740,6 @@ void Entity::animateHurt() { } -void Entity::prepareCustomTextures() -{ -} - ItemInstanceArray Entity::getEquipmentSlots() // ItemInstance[] { return ItemInstanceArray(); // Default ctor creates NULL internal array @@ -1696,12 +1752,12 @@ void Entity::setEquippedSlot(int slot, shared_ptr item) bool Entity::isOnFire() { - return onFire > 0 || getSharedFlag(FLAG_ONFIRE); + return !fireImmune && (onFire > 0 || getSharedFlag(FLAG_ONFIRE)); } bool Entity::isRiding() { - return riding != NULL || getSharedFlag(FLAG_RIDING); + return riding != NULL; } bool Entity::isSneaking() @@ -1771,19 +1827,29 @@ void Entity::setUsingItemFlag(bool value) bool Entity::getSharedFlag(int flag) { - return (entityData->getByte(DATA_SHARED_FLAGS_ID) & (1 << flag)) != 0; + if( entityData ) + { + return (entityData->getByte(DATA_SHARED_FLAGS_ID) & (1 << flag)) != 0; + } + else + { + return false; + } } void Entity::setSharedFlag(int flag, bool value) { - byte currentValue = entityData->getByte(DATA_SHARED_FLAGS_ID); - if (value) - { - entityData->set(DATA_SHARED_FLAGS_ID, (byte) (currentValue | (1 << flag))); - } - else + if( entityData ) { - entityData->set(DATA_SHARED_FLAGS_ID, (byte) (currentValue & ~(1 << flag))); + byte currentValue = entityData->getByte(DATA_SHARED_FLAGS_ID); + if (value) + { + entityData->set(DATA_SHARED_FLAGS_ID, (byte) (currentValue | (1 << flag))); + } + else + { + entityData->set(DATA_SHARED_FLAGS_ID, (byte) (currentValue & ~(1 << flag))); + } } } @@ -1806,11 +1872,10 @@ void Entity::thunderHit(const LightningBolt *lightningBolt) if (onFire == 0) setOnFire(8); } -void Entity::killed(shared_ptr mob) +void Entity::killed(shared_ptr mob) { } - bool Entity::checkInTile(double x, double y, double z) { int xTile = Mth::floor(x); @@ -1821,16 +1886,17 @@ bool Entity::checkInTile(double x, double y, double z) double yd = y - (yTile); double zd = z - (zTile); - if (level->isSolidBlockingTile(xTile, yTile, zTile)) + vector *cubes = level->getTileCubes(bb); + if ( (cubes && !cubes->empty()) || level->isFullAABBTile(xTile, yTile, zTile)) { - bool west = !level->isSolidBlockingTile(xTile - 1, yTile, zTile); - bool east = !level->isSolidBlockingTile(xTile + 1, yTile, zTile); - bool up = !level->isSolidBlockingTile(xTile, yTile - 1, zTile); - bool down = !level->isSolidBlockingTile(xTile, yTile + 1, zTile); - bool north = !level->isSolidBlockingTile(xTile, yTile, zTile - 1); - bool south = !level->isSolidBlockingTile(xTile, yTile, zTile + 1); - - int dir = -1; + bool west = !level->isFullAABBTile(xTile - 1, yTile, zTile); + bool east = !level->isFullAABBTile(xTile + 1, yTile, zTile); + bool down = !level->isFullAABBTile(xTile, yTile - 1, zTile); + bool up = !level->isFullAABBTile(xTile, yTile + 1, zTile); + bool north = !level->isFullAABBTile(xTile, yTile, zTile - 1); + bool south = !level->isFullAABBTile(xTile, yTile, zTile + 1); + + int dir = 3; double closest = 9999; if (west && xd < closest) { @@ -1842,12 +1908,7 @@ bool Entity::checkInTile(double x, double y, double z) closest = 1 - xd; dir = 1; } - if (up && yd < closest) - { - closest = yd; - dir = 2; - } - if (down && 1 - yd < closest) + if (up && 1 - yd < closest) { closest = 1 - yd; dir = 3; @@ -1872,9 +1933,9 @@ bool Entity::checkInTile(double x, double y, double z) if (dir == 4) this->zd = -speed; if (dir == 5) this->zd = +speed; + return true; } - return false; } @@ -1886,10 +1947,13 @@ void Entity::makeStuckInWeb() wstring Entity::getAName() { +#ifdef _DEBUG wstring id = EntityIO::getEncodeId(shared_from_this()); if (id.empty()) id = L"generic"; return L"entity." + id + _toString(entityId); - //return I18n.get("entity." + id + ".name"); +#else + return L""; +#endif } vector > *Entity::getSubEntities() @@ -1916,16 +1980,147 @@ bool Entity::isAttackable() return true; } -bool Entity::isInvulnerable() +bool Entity::skipAttackInteraction(shared_ptr source) { return false; } +bool Entity::isInvulnerable() +{ + return invulnerable; +} + void Entity::copyPosition(shared_ptr target) { moveTo(target->x, target->y, target->z, target->yRot, target->xRot); } +void Entity::restoreFrom(shared_ptr oldEntity, bool teleporting) +{ + CompoundTag *tag = new CompoundTag(); + oldEntity->saveWithoutId(tag); + load(tag); + delete tag; + changingDimensionDelay = oldEntity->changingDimensionDelay; + portalEntranceDir = oldEntity->portalEntranceDir; +} + +void Entity::changeDimension(int i) +{ + if (level->isClientSide || removed) return; + + MinecraftServer *server = MinecraftServer::getInstance(); + int lastDimension = dimension; + ServerLevel *oldLevel = server->getLevel(lastDimension); + ServerLevel *newLevel = server->getLevel(i); + + if (lastDimension == 1 && i == 1) + { + newLevel = server->getLevel(0); + } + + // 4J: Restrictions on what can go through + { + // 4J: Some things should just be destroyed when they hit a portal + if (instanceof(eTYPE_FALLINGTILE)) + { + removed = true; + return; + } + + // 4J: Check server level entity limit (arrows, item entities, experience orbs, etc) + if (newLevel->atEntityLimit(shared_from_this())) return; + + // 4J: Check level limit on living entities, minecarts and boats + if (!instanceof(eTYPE_PLAYER) && !newLevel->canCreateMore(GetType(), Level::eSpawnType_Portal)) return; + } + + // 4J: Definitely sending, set dimension now + dimension = newLevel->dimension->id; + + level->removeEntity(shared_from_this()); + removed = false; + + server->getPlayers()->repositionAcrossDimension(shared_from_this(), lastDimension, oldLevel, newLevel); + shared_ptr newEntity = EntityIO::newEntity(EntityIO::getEncodeId(shared_from_this()), newLevel); + + if (newEntity != NULL) + { + newEntity->restoreFrom(shared_from_this(), true); + + if (lastDimension == 1 && i == 1) + { + Pos *spawnPos = newLevel->getSharedSpawnPos(); + spawnPos->y = level->getTopSolidBlock(spawnPos->x, spawnPos->z); + newEntity->moveTo(spawnPos->x, spawnPos->y, spawnPos->z, newEntity->yRot, newEntity->xRot); + delete spawnPos; + } + + newLevel->addEntity(newEntity); + } + + removed = true; + + oldLevel->resetEmptyTime(); + newLevel->resetEmptyTime(); +} + +float Entity::getTileExplosionResistance(Explosion *explosion, Level *level, int x, int y, int z, Tile *tile) +{ + return tile->getExplosionResistance(shared_from_this()); +} + +bool Entity::shouldTileExplode(Explosion *explosion, Level *level, int x, int y, int z, int id, float power) +{ + return true; +} + +int Entity::getMaxFallDistance() +{ + return 3; +} + +int Entity::getPortalEntranceDir() +{ + return portalEntranceDir; +} + +bool Entity::isIgnoringTileTriggers() +{ + return false; +} + +bool Entity::displayFireAnimation() +{ + return isOnFire(); +} + +void Entity::setUUID(const wstring &UUID) +{ + uuid = UUID; +} + +wstring Entity::getUUID() +{ + return uuid; +} + +bool Entity::isPushedByWater() +{ + return true; +} + +wstring Entity::getDisplayName() +{ + return getAName(); +} + +// 4J: Added to retrieve name that should be sent in ChatPackets (important on Xbox One for players) +wstring Entity::getNetworkName() +{ + return getDisplayName(); +} + void Entity::setAnimOverrideBitmask(unsigned int uiBitmask) { m_uiAnimOverrideBitmask=uiBitmask; @@ -1953,4 +2148,4 @@ unsigned int Entity::getAnimOverrideBitmask() } return m_uiAnimOverrideBitmask; -} +} \ No newline at end of file diff --git a/Minecraft.World/Entity.h b/Minecraft.World/Entity.h index bde83e30..e2a26290 100644 --- a/Minecraft.World/Entity.h +++ b/Minecraft.World/Entity.h @@ -6,7 +6,7 @@ using namespace std; #include "Vec3.h" #include "Definitions.h" -class Mob; +class LivingEntity; class LightningBolt; class ItemEntity; class EntityPos; @@ -17,6 +17,7 @@ class Random; class Level; class CompoundTag; class DamageSource; +class Explosion; // 4J Stu Added this mainly to allow is to record telemetry for player deaths enum EEntityDamageType @@ -33,13 +34,16 @@ enum EEntityDamageType class Entity : public enable_shared_from_this { -friend class Gui; // 4J Stu - Added to be able to access the shared flag functions and constants, without making them publicly available to everything + friend class Gui; // 4J Stu - Added to be able to access the shared flag functions and constants, without making them publicly available to everything public: // 4J-PB - added to replace (e instanceof Type), avoiding dynamic casts virtual eINSTANCEOF GetType() = 0; -public: + inline bool instanceof(eINSTANCEOF super) { return eTYPE_DERIVED_FROM(super, GetType()); } + inline static bool instanceof(eINSTANCEOF type, eINSTANCEOF super) { return eTYPE_DERIVED_FROM(super, type); } +public: + static const wstring RIDING_TAG; static const short TOTAL_AIR_SUPPLY = 20 * 15; private: @@ -53,6 +57,7 @@ public: bool blocksBuilding; weak_ptr rider; // Changed to weak to avoid circular dependency between rider/riding entity shared_ptr riding; + bool forcedLoading; Level *level; double xo, yo, zo; @@ -79,6 +84,7 @@ public: float walkDistO; float walkDist; + float moveDist; float fallDistance; private: @@ -110,10 +116,6 @@ public: private: bool firstTick; -public: - wstring customTextureUrl; - wstring customTextureUrl2; - protected: bool fireImmune; @@ -125,7 +127,7 @@ private: static const int DATA_SHARED_FLAGS_ID = 0; static const int FLAG_ONFIRE = 0; static const int FLAG_SNEAKING = 1; - static const int FLAG_RIDING = 2; + //static const int FLAG_ = 2; static const int FLAG_SPRINTING = 3; static const int FLAG_USING_ITEM = 4; static const int FLAG_INVISIBLE = 5; @@ -138,22 +140,39 @@ private: public: bool inChunk; - int xChunk, yChunk, zChunk; - int xp, yp, zp, xRotp, yRotp; - bool noCulling; - bool hasImpulse; + int xChunk, yChunk, zChunk; + int xp, yp, zp, xRotp, yRotp; + bool noCulling; + bool hasImpulse; + int changingDimensionDelay; + +protected: + bool isInsidePortal; + int portalTime; + +public: + int dimension; + +protected: + int portalEntranceDir; + +private: + bool invulnerable; + wstring uuid; protected: // 4J Added so that client side simulations on the host are not affected by zero-lag bool m_ignoreVerticalCollisions; + bool m_ignorePortal; + public: Entity(Level *level, bool useSmallId = true); // 4J - added useSmallId parameter virtual ~Entity(); protected: // 4J - added for common ctor code - void _init(bool useSmallId); + void _init(bool useSmallId, Level *level); protected: virtual void defineSynchedData() = 0; @@ -191,6 +210,7 @@ public: void interpolateTurn(float xo, float yo); virtual void tick(); virtual void baseTick(); + virtual int getPortalWaitTime(); protected: void lavaHurt(); @@ -256,7 +276,7 @@ protected: public: // 4J Added damageSource param to enable telemetry on player deaths - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); bool intersects(double x0, double y0, double z0, double x1, double y1, double z1); virtual bool isPickable(); virtual bool isPushable(); @@ -264,18 +284,24 @@ public: virtual void awardKillScore(shared_ptr victim, int score); virtual bool shouldRender(Vec3 *c); virtual bool shouldRenderAtSqrDistance(double distance); - virtual int getTexture(); // 4J - changed from wstring to int virtual bool isCreativeModeAllowed(); + bool saveAsMount(CompoundTag *entityTag); bool save(CompoundTag *entityTag); void saveWithoutId(CompoundTag *entityTag); virtual void load(CompoundTag *tag); protected: + virtual bool repositionEntityAfterLoad(); const wstring getEncodeId(); public: virtual void readAdditionalSaveData(CompoundTag *tag) = 0; virtual void addAdditonalSaveData(CompoundTag *tag) = 0; + /** + * Called after load() has finished and the entity has been added to the + * world + */ + virtual void onLoadedFromSave(); protected: ListTag *newDoubleList(unsigned int number, double firstValue, ...); @@ -296,15 +322,14 @@ public: virtual double getRidingHeight(); virtual double getRideHeight(); virtual void ride(shared_ptr e); - virtual void findStandUpPosition(shared_ptr vehicle); // 4J Stu - Brought forward from 12w36 to fix #46282 - TU5: Gameplay: Exiting the minecart in a tight corridor damages the player virtual void lerpTo(double x, double y, double z, float yRot, float xRot, int steps); virtual float getPickRadius(); virtual Vec3 *getLookAngle(); virtual void handleInsidePortal(); + virtual int getDimensionChangingDelay(); virtual void lerpMotion(double xd, double yd, double zd); virtual void handleEntityEvent(byte eventId); virtual void animateHurt(); - virtual void prepareCustomTextures(); virtual ItemInstanceArray getEquipmentSlots(); // ItemInstance[] virtual void setEquippedSlot(int slot, shared_ptr item); // 4J Stu - Brought forward change from 1.3 to fix #64688 - Customer Encountered: TU7: Content: Art: Aura of enchanted item is not displayed for other players in online game virtual bool isOnFire(); @@ -336,7 +361,7 @@ public: void setAirSupply(int supply); virtual void thunderHit(const LightningBolt *lightningBolt); - virtual void killed(shared_ptr mob); + virtual void killed(shared_ptr mob); protected: bool checkInTile(double x, double y, double z); @@ -346,9 +371,6 @@ public: virtual wstring getAName(); - // TU9 - bool skipAttackInteraction(shared_ptr source) {return false;} - // 4J - added to manage allocation of small ids private: // Things also added here to be able to manage the concept of a number of extra "wandering" entities - normally path finding entities aren't allowed to @@ -374,14 +396,28 @@ public: void considerForExtraWandering(bool enable); bool isExtraWanderingEnabled(); int getWanderingQuadrant(); - + virtual vector > *getSubEntities(); virtual bool is(shared_ptr other); virtual float getYHeadRot(); virtual void setYHeadRot(float yHeadRot); virtual bool isAttackable(); + virtual bool skipAttackInteraction(shared_ptr source); virtual bool isInvulnerable(); virtual void copyPosition(shared_ptr target); + virtual void restoreFrom(shared_ptr oldEntity, bool teleporting); + virtual void changeDimension(int i); + virtual float getTileExplosionResistance(Explosion *explosion, Level *level, int x, int y, int z, Tile *tile); + virtual bool shouldTileExplode(Explosion *explosion, Level *level, int x, int y, int z, int id, float power); + virtual int getMaxFallDistance(); + virtual int getPortalEntranceDir(); + virtual bool isIgnoringTileTriggers(); + virtual bool displayFireAnimation(); + virtual void setUUID(const wstring &UUID); + virtual wstring getUUID(); + virtual bool isPushedByWater(); + virtual wstring getDisplayName(); + virtual wstring getNetworkName(); // 4J: Added private: unsigned int m_uiAnimOverrideBitmask; diff --git a/Minecraft.World/EntityActionAtPositionPacket.cpp b/Minecraft.World/EntityActionAtPositionPacket.cpp index 7353f932..64f36d1f 100644 --- a/Minecraft.World/EntityActionAtPositionPacket.cpp +++ b/Minecraft.World/EntityActionAtPositionPacket.cpp @@ -24,7 +24,7 @@ EntityActionAtPositionPacket::EntityActionAtPositionPacket(shared_ptr e, this->x = x; this->y = y; this->z = z; - this->id = e->entityId; + id = e->entityId; } void EntityActionAtPositionPacket::read(DataInputStream *dis) //throws IOException diff --git a/Minecraft.World/EntityDamageSource.cpp b/Minecraft.World/EntityDamageSource.cpp index 8c7a5ee1..22237bf1 100644 --- a/Minecraft.World/EntityDamageSource.cpp +++ b/Minecraft.World/EntityDamageSource.cpp @@ -5,7 +5,7 @@ #include "net.minecraft.network.packet.h" //EntityDamageSource::EntityDamageSource(const wstring &msgId, shared_ptr entity) : DamageSource(msgId) -EntityDamageSource::EntityDamageSource(ChatPacket::EChatPacketMessage msgId, shared_ptr entity) : DamageSource(msgId) +EntityDamageSource::EntityDamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId, shared_ptr entity) : DamageSource(msgId, msgWithItemId) { this->entity = entity; } @@ -21,18 +21,41 @@ shared_ptr EntityDamageSource::getEntity() // //return I18n.get("death." + msgId, player.name, entity.getAName()); //} -shared_ptr EntityDamageSource::getDeathMessagePacket(shared_ptr player) +shared_ptr EntityDamageSource::getDeathMessagePacket(shared_ptr player) { + shared_ptr held = (entity != NULL) && entity->instanceof(eTYPE_LIVINGENTITY) ? dynamic_pointer_cast(entity)->getCarriedItem() : nullptr; wstring additional = L""; - if(entity->GetType() == eTYPE_SERVERPLAYER) + + if (entity->instanceof(eTYPE_SERVERPLAYER)) + { + additional = dynamic_pointer_cast(entity)->name; + } + else if (entity->instanceof(eTYPE_MOB)) + { + shared_ptr mob = dynamic_pointer_cast(entity); + if (mob->hasCustomName()) + { + additional = mob->getCustomName(); + } + } + + if ( (held != NULL) && held->hasCustomHoverName()) { - shared_ptr sourcePlayer = dynamic_pointer_cast(entity); - if(sourcePlayer != NULL) additional = sourcePlayer->name; + return shared_ptr( new ChatPacket(player->getNetworkName(), m_msgWithItemId, entity->GetType(), additional, held->getHoverName() ) ); + } + else + { + return shared_ptr( new ChatPacket(player->getNetworkName(), m_msgId, entity->GetType(), additional ) ); } - return shared_ptr( new ChatPacket(player->name, m_msgId, entity->GetType(), additional ) ); } bool EntityDamageSource::scalesWithDifficulty() { - return entity != NULL && dynamic_pointer_cast(entity) && !(dynamic_pointer_cast(entity)); + return (entity != NULL) && entity->instanceof(eTYPE_LIVINGENTITY) && !entity->instanceof(eTYPE_PLAYER); +} + +// 4J: Copy function +DamageSource *EntityDamageSource::copy() +{ + return new EntityDamageSource(*this); } \ No newline at end of file diff --git a/Minecraft.World/EntityDamageSource.h b/Minecraft.World/EntityDamageSource.h index bdbe36e7..3df654fd 100644 --- a/Minecraft.World/EntityDamageSource.h +++ b/Minecraft.World/EntityDamageSource.h @@ -13,14 +13,16 @@ protected: public: //EntityDamageSource(const wstring &msgId, shared_ptr entity); - EntityDamageSource(ChatPacket::EChatPacketMessage msgId, shared_ptr entity); + EntityDamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId, shared_ptr entity); virtual ~EntityDamageSource() { } - shared_ptr getEntity(); + shared_ptr getEntity(); // 4J Stu - Made return a packet //virtual wstring getLocalizedDeathMessage(shared_ptr player); - virtual shared_ptr getDeathMessagePacket(shared_ptr player); + virtual shared_ptr getDeathMessagePacket(shared_ptr player); virtual bool scalesWithDifficulty(); + + virtual DamageSource *copy(); }; \ No newline at end of file diff --git a/Minecraft.World/EntityDiagram.cd b/Minecraft.World/EntityDiagram.cd new file mode 100644 index 00000000..2cfded11 --- /dev/null +++ b/Minecraft.World/EntityDiagram.cd @@ -0,0 +1,805 @@ + + + + + + + + + + lk9By8fuVr+s9Vq2ZZrRsbv3c3+a+rkZfp7902m71mE= + Entity.h + + + + + + + + + + + + + + IkXwEshzVK9k0lP3eIozMydyc56b0ZNv9VTruo1/COQ= + livingentity.h + + + + + + + + + + + + + + UAlyxmP2UGIgHDSYIll6BnYGw1UcADEHoAPyGCoBCMA= + mob.h + + + + + + EBBIAgACgAIAkgAQQAgQAAQAAwAAAAECgADAAgIgAIA= + PigZombie.h + + + + + + kABEAiYAlAIA2gQQAABSoAwgQiAIAAEA0BDAgAEgAsA= + Zombie.h + + + + + + + + + + + + + + EAJAAAAAAAAAAAAAAAAQAEAgAAAIAAECAgDAAAAgAAA= + monster.h + + + + + + + + + + + + + + + + ECKEBAAAAAAEAgCGAAASOQAgBBAAAAACEAIBQAEgAUQ= + PathfinderMob.h + + + + + + AAIAAAAAAAAAAAAAEAAQAAAAAAAAAAEAAABAAAAAAAA= + Giant.h + + + + + + wABwAgAQQUYBkAQUAlQQACAoQyCJIEEDwgPCEYglAMA= + Wolf.h + + + + + + AAAQgAAAEAoAAAAQAABAAAQAUACBAQBAABIACCABAEA= + TamableAnimal.h + + + + + + EAICgQAAIBIgAAQwgiAAAIAAThgJAAADIACCAIAhAEA= + Animal.h + + + + + + + + + + + + + + AIgAAEAAAQIAAAgQQAACAAAAQgAICEEGAAAAAAAEAAA= + AgableMob.h + + + + + + AAAAAAAAAAAAkAABAYoYAAAEASAJAAEAgABAAABlAIA= + Chicken.h + + + + + + AAAAAAAAAAAAkAAAAAAQAAAAAyGAAAEAgABAAAAkAIA= + Cow.h + + + + + + + + + + + + + + AAAAgAAAAAAAkAQAAAAAAAAAAAAAAAAAAAAAAAAlAAA= + Golem.h + + + + + + EAAAAQAAAAAAAAAAAAAAAAAAAgAAAAEAAABAAAAEAAA= + mushroomcow.h + + + + + + EAAECgAACAIQkIQwAAAQABAgSwCBAAFBoADCAIA1AYA= + ocelot.h + + + + + + QAAAQEACAAIEkAAQAAASABAAQyABAAECgABAQAAlAIA= + Pig.h + + + + + + BAAAQhAiAAIQkAAQAEAQAIAQQyAoAAGAgABAgAQsAsA= + Sheep.h + + + + + + AAAAAAAAAAAAAAAAAAAQAAAgAQAIAAEAgCBAAAAAAIA= + SnowMan.h + + + + + + FEAAAABEAgBAkQAgCAgQAAABAYCIAwEAgBBAAAAgAkA= + Squid.h + + + + + + + + + + + + + + EAAAgAAAAAEAAAQAAAIAAAAAABAAAAAAAAAAAAABAAA= + WaterAnimal.h + + + + + + QEIACCAAECIAkAAwEAAQAAAiQSAIgAEAFADCBAAgAMA= + VillagerGolem.h + + + + + + AAAAAAAAAAQAAAAAAAAAAAAAAkAAAAAAAAAAAAAAAAA= + AmbientCreature.h + + + + + + EABAEAACAAoAkAAwAAAQIAEAUQCAgAkAAADAAAIxAIA= + Bat.h + + + + + + QABiQAADwAMA0gCQJAARAQAgQwAoAgEAEBDRCBCxBZA= + WitherBoss.h + + + + + + AAAAAAAAAAIAAAAQAAEAAAAAQAAAAAEAAAAAAAAAAAA= + nethersphere.h + + + + + + AUQkhQAAyxJqEAAeUAkdPDLp8bCIIAURQADhQQg6A0g= + EnderDragon.h + + + + + + gAFBQABAAAIAEQAwAAgAAAABQAAAAAEAAADAAAAAAAA= + EnderCrystal.h + + + + + + AAAAAAAAAAIAEEAQAAAAAAAAQAAQAAEAQACAAAAAAgA= + MultiEntityMobPart.h + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAA= + GlobalEntity.h + + + + + + AAFAAMAAAAIAQgAQAAAAAAAAQAAgAAEAAAAAAAAAAAE= + lightningbolt.h + + + + + + AoRASBACFAIAEUAwIAgRgAMAUASAACVAEADUAAAECCQ= + Boat.h + + + + + + AABBQAAACAIgEQAwAAlAAAIAQAAAAAEAIABRAAAhQAA= + FallingTile.h + + + + + + AABAAIBExAIAQEAwAUgABAAAQAAAQAEAKAXAAEAEAAg= + ItemEntity.h + + + + + + + + + + + + + + AoBgSAICEEKAcUQ0YCgDgGMAUQaMAIFAOCCaQGBAKCw= + minecart.h + + + + + + AACAAAAAAAAAAAAAAAAAAEAAAQAIAAEAgCBAAAAAAAA= + minecartchest.h + + + + + + AAAIAAAkQAIAABAUAAgAAEACAQAAACAACAAUAAAAAAA= + minecartcontainer.h + + + + + + AADAAgAAAAIAASAQAgmAAUAAAQAIAKEAACBAgAAABgA= + minecarthopper.h + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAQAAACEAAABAAAAAACA= + minecartrideable.h + + + + + + EABABAAAAAIABAAQAAAAAAAAAQAIAAEAgABAAAAAAEA= + minecartspawner.h + + + + + + CARAAAAAAAIAAAAQSAgAAEAAAUEIBIUAAABAEAABAEA= + MinecartTNT.h + + + + + + AAFAwAAAAAIAkQAwCAgAAAAAQAEAAAEAAABAAAAAAAA= + PrimedTnt.h + + + + + + gAAAAAAAEAAAkAAAAAARAMIAQQAICAEAgABEABAhACA= + Blaze.h + + + + + + + + + + + + AAIAAgAAAAAAAAAAAAAQAAAgAAAAAAEAAABAAAAAAAA= + CaveSpider.h + + + + + + AABAIgQAEAAAsAAAAAAQAAAAQSASAAEGgBBQAAAgAAA= + Spider.h + + + + + + AoBAQAAQAjIAgAAQICgQgAAgQAAAAAEAgEpAAAAhAIA= + Creeper.h + + + + + + IIgoAIAAgAIAkIAUQAAUADoAQQAIAAEGgADAgAEgCIA= + EnderMan.h + + + + + + EAgABAAAgAYAkAQSMAgQAAAAQQCAAAEAgIDEAQggAEA= + Ghast.h + + + + + + AAAAAAAAAAAAAAAAAAAAIAAAAIACAAIAAAAAAAABAAA= + FlyingMob.h + + + + + + EAAAAAgAACAAgAgAAAARAIAAJQgACAEAkABQEBAhAAA= + lavaslime.h + + + + + + EABAAAgABIIAgAgUBBgAAAAAZACAAAMApEBQABAiAFA= + Slime.h + + + + + + EAJAAAAAAAAAkAAgAAAQAEAAACAAQAECgBDAAAAggEA= + Silverfish.h + + + + + + AEACAgCAACIgkAAYAKAQAAQhQSgIBAEAgBBBAQAgAYA= + Skeleton.h + + + + + + AAAABAACAAAAkAEAEAAQCAAgQQAIAAEAAEBAAQAiAOA= + Witch.h + + + + + + AJEAGgEYQWMAkASxMBgYgGBQUkAgBhEJUSDCCEAmEcA= + Villager.h + + + + + + tnzh7119+X+pYpq2sMm9VykjcZ9d6HXvO5y/lb7N/3c= + Player.h + + + + + + ABFAQAhOBIIggQIwoAoABABAQgACIAEAAChAIAAABCg= + Arrow.h + + + + + + + + + + + + + + AAAAAAAAAAAgEAAAAAAAAgAAAAEAAAEAAADAQBAAAAA= + DragonFireball.h + + + + + + ABFAQEgMAAIAkAAQAAoBBQAAQAEACAEEAACQSAAAAAE= + Fireball.h + + + + + + BAFAQABGAAIAAAAQCAgDAAAAQAAACAEAADBAAAAAAAA= + EyeOfEnderSignal.h + + + + + + AAFAwABGAAIAAAAQAAABAAAAQAAACAEAAABAAABAIEA= + FireworksRocketEntity.h + + + + + + ABHAQAgOAAIAgECUAAoABAAAUAAAAAEAECAAAACAACQ= + FishingHook.h + + + + + + + + + + + + + + CAAAAAAAAAIAAAAQAAAAAAAAAAAAAAEAAABAQAAAAAA= + largefireball.h + + + + + + AAAAAAAAAAAAEAEAAAAAAAAAAAAAAAEAAADAQAAAAAA= + SmallFireball.h + + + + + + AAAAAAAAAAAAAAAAAAgAAEAAAAAAAAEAAABAQAAAAAA= + Snowball.h + + + + + + ABFAwAgOAAIAgFAQAAIABAAEQAAAAAMAACAAQgAAAAA= + Throwable.h + + + + + + AAAAAAAAAAAAAAAAAAgAAAAQAAAAAAEAAAAAQAAAAAA= + ThrownEgg.h + + + + + + AAAAAAAAAAQAAAAAAAAAAAAAAAAAAAEAAABAQAAAAAA= + ThrownEnderpearl.h + + + + + + AEAAAAAAAAAAgBAAAAAAAAAAAAAAAAEAAABAQgAAAAA= + ThrownExpBottle.h + + + + + + AAAAAAAAAAIggBAQAAgAAgAAAAAAIgEAAABQQgEAAAA= + ThrownPotion.h + + + + + + + + + + + + + + AAAAAEAIAAAAEAAAAAAAAIAAQgEAAAEAAADARAAAIAA= + WitherSkull.h + + + + + + BABAAAAAAAIAAAAwAEAAAAgAQAAAAAEAAACAAAAAAAA= + DelayedRelease.h + + + + + + AABAgMBABAIAQCAwABgJAAAAQAIAACEAAATCAAAUAAg= + ExperienceOrb.h + + + + + + QBBAAAAIACIAEgCQAAoAACIAwBEAQAEAAACIAAAoAAA= + HangingEntity.h + + + + + + QAAIAIAEQAIAAEAQAAgAAAAASAAAQCFAAABAAAQggAA= + ItemFrame.h + + + + + + QAAIAAAEAAqAAAAQAAgAAAIAwAAAQCEAAABACAAgAAA= + leashfenceknotentity.h + + + + + + QAAAAAAAAAIAAEAQAAgAAQAgAAAAQAEAAABAAAAgAAA= + Painting.h + + + + + + Mh4VJEJMQKcF4KAXixAFjgAkYcMfAR3KuAoZDsCBDmI= + c:\users\james\documents\work2\storiespark\minecraft\minecraftconsoles-dev-branch-1.6.4\minecraft.client\localplayer.h + + + + + + IjjhQugN4T4hcAiyCQEFsChhAgJRAAECaZ6AVIotPjI= + c:\users\james\documents\work2\storiespark\minecraft\minecraftconsoles-dev-branch-1.6.4\minecraft.client\serverplayer.h + + + + + + WZjVmhMVAOcMt1dRYs4aD5EBV/2vlC9CtyDQNqwvnNA= + EntityHorse.h + + + + + + ANFRCAAAwIKBIBgEASEAAAggAAEAAWEAAgBxEQEABAg= + TileEntity.h + + + + + + AADIAAAGQICIiBQEBUEAIDAiCVEMAAEAAEheEAAAAAA= + BeaconTileEntity.h + + + + + + AADoIAAEQIGkIJDMAAgCAAACAwAEAgEAAABWGQAAQAA= + BrewingStandTileEntity.h + + + + + + AADIAAAERYCCABAkCQgAAAAGASAFAQECEIhXEAAABAg= + ChestTileEntity.h + + + + + + AAAAAAAAAICAAAAABAgAAAAgARQEAANAIEBEAAAEBCA= + CommandBlockEntity.h + + + + + + AAAAAAAAAICAAAAAAAAAABAACAEAAAEAAABAAAAAAAA= + ComparatorTileEntity.h + + + + + + + + + + + + + + AABAAAAAAAABAAAAAAAAAAAAAAAAAAEAAABAAAAAAAA= + DaylightDetectorTileEntity.h + + + + + + AACIAAAEQICAABAEAAiAKAACAwAECAEAAAVWEAAAAAA= + dispensertileentity.h + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAABEEAAAAAA= + DropperTileEntity.h + + + + + + AIFBAAAAAIGIAAAAISAQAAQCAAAEAAEAAARWEBAAAAA= + EnchantmentTableEntity.h + + + + + + AABIAAAAAAACABIgAAAAAAACACAAAQEAAABQEAAABAA= + EnderChestTileEntity.h + + + + + + AgDsAIEEQoCAABWMABgCoMASAQCEBAMAIARWEAABAAA= + furnacetileentity.h + + + + + + AADJAgAkRICAADAEAgmAAQACAQAEAAEAQBBWEAyFJgA= + HopperTileEntity.h + + + + + + AABABAAAAICABAAAAAAAAAAgAQAAAQEAAQBAEAAAAAA= + mobspawnertileentity.h + + + + + + AQAAgAwAAICAAAAQAAAAAAAAAAAAAAEAAABAEAAAAAA= + musictileentity.h + + + + + + ACABYAAAQICAEgCgAAAAgAIwEGABEAEACBhQEQCAAAA= + SignTileEntity.h + + + + + + AAAAAIiAgICAAAAAgACAAAAiCCCAAAEAAABAFAAABCg= + SkullTileEntity.h + + + + + + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAABAEAAAAAA= + TheEndPortalTileEntity.h + + + + \ No newline at end of file diff --git a/Minecraft.World/EntityHorse.cpp b/Minecraft.World/EntityHorse.cpp new file mode 100644 index 00000000..2d67d21b --- /dev/null +++ b/Minecraft.World/EntityHorse.cpp @@ -0,0 +1,1841 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.ai.goal.h" +#include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.effect.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.inventory.h" +#include "net.minecraft.world.phys.h" +#include "..\Minecraft.Client\Textures.h" +#include "..\Minecraft.Client\Minecraft.h" +#include "BasicTypeContainers.h" +#include "EntityHorse.h" + +const wstring EntityHorse::TEX_FOLDER = L"mob/horse/"; + +const EntitySelector *EntityHorse::PARENT_HORSE_SELECTOR = new HorseEntitySelector(); + +Attribute *EntityHorse::JUMP_STRENGTH = (new RangedAttribute(eAttributeId_HORSE_JUMPSTRENGTH, .7, 0, 2.0))->setSyncable(true); + +wstring EntityHorse::ARMOR_TEXTURES[EntityHorse::ARMORS] = {L"", L"armor/horse_armor_iron.png", L"armor/horse_armor_gold.png", L"armor/horse_armor_diamond.png"}; +int EntityHorse::ARMOR_TEXTURES_ID[EntityHorse::ARMORS] = {-1, TN_MOB_HORSE_ARMOR_IRON, TN_MOB_HORSE_ARMOR_GOLD, TN_MOB_HORSE_ARMOR_DIAMOND }; +wstring EntityHorse::ARMOR_HASHES[EntityHorse::ARMORS] = {L"", L"meo", L"goo", L"dio"}; +int EntityHorse::ARMOR_PROTECTION[EntityHorse::ARMORS] = {0, 5, 7, 11}; + +wstring EntityHorse::VARIANT_TEXTURES[EntityHorse::VARIANTS] = {L"horse_white.png", L"horse_creamy.png", L"horse_chestnut.png", L"horse_brown.png", L"horse_black.png", L"horse_gray.png", L"horse_darkbrown.png"}; +int EntityHorse::VARIANT_TEXTURES_ID[EntityHorse::VARIANTS] = {TN_MOB_HORSE_WHITE, TN_MOB_HORSE_CREAMY, TN_MOB_HORSE_CHESTNUT, TN_MOB_HORSE_BROWN, TN_MOB_HORSE_BLACK, TN_MOB_HORSE_GRAY, TN_MOB_HORSE_DARKBROWN}; + +wstring EntityHorse::VARIANT_HASHES[EntityHorse::VARIANTS] = {L"hwh", L"hcr", L"hch", L"hbr", L"hbl", L"hgr", L"hdb"}; + +wstring EntityHorse::MARKING_TEXTURES[EntityHorse::MARKINGS] = {L"", L"horse_markings_white.png", L"horse_markings_whitefield.png", L"horse_markings_whitedots.png", L"horse_markings_blackdots.png"}; +int EntityHorse::MARKING_TEXTURES_ID[EntityHorse::MARKINGS] = {-1, TN_MOB_HORSE_MARKINGS_WHITE, TN_MOB_HORSE_MARKINGS_WHITEFIELD, TN_MOB_HORSE_MARKINGS_WHITEDOTS, TN_MOB_HORSE_MARKINGS_BLACKDOTS}; +wstring EntityHorse::MARKING_HASHES[EntityHorse::MARKINGS] = {L"", L"wo_", L"wmo", L"wdo", L"bdo"}; + +bool HorseEntitySelector::matches(shared_ptr entity) const +{ + return entity->instanceof(eTYPE_HORSE) && dynamic_pointer_cast(entity)->isBred(); +} + +EntityHorse::EntityHorse(Level *level) : Animal(level) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called + this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); + + countEating = 0; + mouthCounter = 0; + standCounter = 0; + tailCounter = 0; + sprintCounter = 0; + isEntityJumping = false; + inventory = nullptr; + hasReproduced = false; + temper = 0; + playerJumpPendingScale = 0.0f; + allowStandSliding = false; + eatAnim = eatAnimO = 0.0f; + standAnim = standAnimO = 0.0f; + mouthAnim = mouthAnimO = 0.0f; + gallopSoundCounter = 0; + + layerTextureHashName = L""; + + layerTextureLayers = intArray(3); + for(unsigned int i = 0; i < 3; ++i) + { + layerTextureLayers[i] = -1; + } + + setSize(1.4f, 1.6f); + fireImmune = false; + setChestedHorse(false); + + getNavigation()->setAvoidWater(true); + goalSelector.addGoal(0, new FloatGoal(this)); + goalSelector.addGoal(1, new PanicGoal(this, 1.2)); + goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2)); + goalSelector.addGoal(2, new BreedGoal(this, 1.0)); + goalSelector.addGoal(4, new FollowParentGoal(this, 1.0)); + goalSelector.addGoal(6, new RandomStrollGoal(this, .7)); + goalSelector.addGoal(7, new LookAtPlayerGoal(this, typeid(Player), 6)); + goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + + createInventory(); +} + +EntityHorse::~EntityHorse() +{ + delete [] layerTextureLayers.data; +} + +void EntityHorse::defineSynchedData() +{ + Animal::defineSynchedData(); + entityData->define(DATA_ID_HORSE_FLAGS, 0); + entityData->define(DATA_ID_TYPE, (byte) 0); + entityData->define(DATA_ID_TYPE_VARIANT, 0); + entityData->define(DATA_ID_OWNER_NAME, L""); + entityData->define(DATA_ID_ARMOR, 0); +} + +void EntityHorse::setType(int i) +{ + entityData->set(DATA_ID_TYPE, (byte) i); + clearLayeredTextureInfo(); +} + +int EntityHorse::getType() +{ + return entityData->getByte(DATA_ID_TYPE); +} + +void EntityHorse::setVariant(int i) +{ + entityData->set(DATA_ID_TYPE_VARIANT, i); + clearLayeredTextureInfo(); +} + +int EntityHorse::getVariant() +{ + return entityData->getInteger(DATA_ID_TYPE_VARIANT); +} + +wstring EntityHorse::getAName() +{ + if (hasCustomName()) return getCustomName(); +#ifdef _DEBUG + int type = getType(); + switch (type) + { + default: + case TYPE_HORSE: + return L"entity.horse.name"; + case TYPE_DONKEY: + return L"entity.donkey.name"; + case TYPE_MULE: + return L"entity.mule.name"; + case TYPE_SKELETON: + return L"entity.skeletonhorse.name"; + case TYPE_UNDEAD: + return L"entity.zombiehorse.name"; + } +#else + return L""; +#endif +} + +bool EntityHorse::getHorseFlag(int flag) +{ + return (entityData->getInteger(DATA_ID_HORSE_FLAGS) & flag) != 0; +} + +void EntityHorse::setHorseFlag(int flag, bool value) +{ + int current = entityData->getInteger(DATA_ID_HORSE_FLAGS); + if (value) + { + entityData->set(DATA_ID_HORSE_FLAGS, current | flag); + } + else + { + entityData->set(DATA_ID_HORSE_FLAGS, current & ~flag); + } +} + +bool EntityHorse::isAdult() +{ + return !isBaby(); +} + +bool EntityHorse::isTamed() +{ + return getHorseFlag(FLAG_TAME); +} + +bool EntityHorse::isRidable() +{ + return isAdult(); +} + +wstring EntityHorse::getOwnerName() +{ + return entityData->getString(DATA_ID_OWNER_NAME); +} + +void EntityHorse::setOwner(const wstring &par1Str) +{ + entityData->set(DATA_ID_OWNER_NAME, par1Str); +} + +float EntityHorse::getFoalScale() +{ + int age = getAge(); + if (age >= 0) + { + return 1.0f; + } + return .5f + (float) (BABY_START_AGE - age) / (float) BABY_START_AGE * .5f; +} + + +void EntityHorse::updateSize(bool isBaby) +{ + if (isBaby) + { + internalSetSize(getFoalScale()); + } + else + { + internalSetSize(1.0f); + } +} + +bool EntityHorse::getIsJumping() +{ + return isEntityJumping; +} + +void EntityHorse::setTamed(bool flag) +{ + setHorseFlag(FLAG_TAME, flag); +} + +void EntityHorse::setIsJumping(bool flag) +{ + isEntityJumping = flag; +} + + +bool EntityHorse::canBeLeashed() +{ + return !isUndead() && Animal::canBeLeashed(); +} + +void EntityHorse::onLeashDistance(float distanceToLeashHolder) +{ + if (distanceToLeashHolder > 6 && isEating()) + { + setEating(false); + } +} + +bool EntityHorse::isChestedHorse() +{ + return getHorseFlag(FLAG_CHESTED); +} + +int EntityHorse::getArmorType() +{ + return entityData->getInteger(DATA_ID_ARMOR); +} + +int EntityHorse::getArmorTypeForItem(shared_ptr armorItem) +{ + if (armorItem == NULL) + { + return ARMOR_NONE; + } + if (armorItem->id == Item::horseArmorMetal_Id) + { + return ARMOR_IRON; + } + else if (armorItem->id == Item::horseArmorGold_Id) + { + return ARMOR_GOLD; + } + else if (armorItem->id == Item::horseArmorDiamond_Id) + { + return ARMOR_DIAMOND; + } + return ARMOR_NONE; +} + +bool EntityHorse::isEating() +{ + return getHorseFlag(FLAG_EATING); +} + +bool EntityHorse::isStanding() +{ + return getHorseFlag(FLAG_STANDING); +} + +bool EntityHorse::isBred() +{ + return getHorseFlag(FLAG_BRED); +} + +bool EntityHorse::getHasReproduced() +{ + return hasReproduced; +} + +void EntityHorse::setArmorType(int i) +{ + entityData->set(DATA_ID_ARMOR, i); + clearLayeredTextureInfo(); +} + +void EntityHorse::setBred(bool flag) +{ + setHorseFlag(FLAG_BRED, flag); + +} + +void EntityHorse::setChestedHorse(bool flag) +{ + setHorseFlag(FLAG_CHESTED, flag); +} + +void EntityHorse::setReproduced(bool flag) +{ + hasReproduced = flag; +} + +void EntityHorse::setSaddled(bool flag) +{ + setHorseFlag(FLAG_SADDLE, flag); +} + +int EntityHorse::getTemper() +{ + return temper; +} + +void EntityHorse::setTemper(int temper) +{ + this->temper = temper; +} + +int EntityHorse::modifyTemper(int amount) +{ + int temper = Mth::clamp(getTemper() + amount, 0, getMaxTemper()); + + setTemper(temper); + return temper; +} + + +bool EntityHorse::hurt(DamageSource *damagesource, float dmg) +{ + // 4J: Protect owned horses from untrusted players + if (isTamed()) + { + shared_ptr entity = damagesource->getDirectEntity(); + if (entity != NULL && entity->instanceof(eTYPE_PLAYER)) + { + shared_ptr attacker = dynamic_pointer_cast(entity); + attacker->canHarmPlayer(getOwnerName()); + } + } + + shared_ptr attacker = damagesource->getEntity(); + if (rider.lock() != NULL && (rider.lock() == (attacker) )) + { + return false; + } + + return Animal::hurt(damagesource, dmg); +} + + +int EntityHorse::getArmorValue() +{ + return ARMOR_PROTECTION[getArmorType()]; +} + + +bool EntityHorse::isPushable() +{ + return rider.lock() == NULL; +} + +// TODO: [EB]: Explain why this is being done - what side effect does getBiome have? +bool EntityHorse::checkSpawningBiome() +{ + int x = Mth::floor(this->x); + int z = Mth::floor(this->z); + + level->getBiome(x, z); + return true; +} + +/** +* Drops a chest block if the horse is bagged +*/ +void EntityHorse::dropBags() +{ + if (level->isClientSide || !isChestedHorse()) + { + return; + } + + spawnAtLocation(Tile::chest_Id, 1); + setChestedHorse(false); +} + +void EntityHorse::eatingHorse() +{ + openMouth(); + level->playEntitySound(shared_from_this(), eSoundType_EATING, 1.0f, 1.0f + (random->nextFloat() - random->nextFloat()) * 0.2f); +} + +/** +* Changed to adjust fall damage for riders +*/ +void EntityHorse::causeFallDamage(float fallDistance) +{ + + if (fallDistance > 1) + { + playSound(eSoundType_MOB_HORSE_LAND, .4f, 1); + } + + int dmg = Mth::ceil(fallDistance * .5f - 3.0f); + if (dmg <= 0) return; + + hurt(DamageSource::fall, dmg); + + if (rider.lock() != NULL) + { + rider.lock()->hurt(DamageSource::fall, dmg); + } + + int id = level->getTile(Mth::floor(x), Mth::floor(y - 0.2 - yRotO), Mth::floor(z)); + if (id > 0) + { + const Tile::SoundType *stepsound = Tile::tiles[id]->soundType; + level->playEntitySound(shared_from_this(), stepsound->getStepSound(), stepsound->getVolume() * 0.5f, stepsound->getPitch() * 0.75f); + } +} + + +/** +* Different inventory sizes depending on the kind of horse +* +* @return +*/ +int EntityHorse::getInventorySize() +{ + int type = getType(); + if (isChestedHorse() && (type == TYPE_DONKEY || type == TYPE_MULE)) + { + return INV_BASE_COUNT + INV_DONKEY_CHEST_COUNT; + } + return INV_BASE_COUNT; +} + +void EntityHorse::createInventory() +{ + shared_ptr old = inventory; + inventory = shared_ptr( new AnimalChest(L"HorseChest", getInventorySize()) ); + inventory->setCustomName(getAName()); + if (old != NULL) + { + old->removeListener(this); + + int max = min(old->getContainerSize(), inventory->getContainerSize()); + for (int slot = 0; slot < max; slot++) + { + shared_ptr item = old->getItem(slot); + if (item != NULL) + { + inventory->setItem(slot, item->copy()); + } + } + old = nullptr; + } + inventory->addListener(this); + updateEquipment(); +} + +void EntityHorse::updateEquipment() +{ + if (!level->isClientSide) + { + setSaddled(inventory->getItem(INV_SLOT_SADDLE) != NULL); + if (canWearArmor()) + { + setArmorType(getArmorTypeForItem(inventory->getItem(INV_SLOT_ARMOR))); + } + } +} + +void EntityHorse::containerChanged() +{ + int armorType = getArmorType(); + bool saddled = isSaddled(); + updateEquipment(); + if (tickCount > 20) + { + if (armorType == ARMOR_NONE && armorType != getArmorType()) + { + playSound(eSoundType_MOB_HORSE_ARMOR, .5f, 1); + } + if (!saddled && isSaddled()) + { + playSound(eSoundType_MOB_HORSE_LEATHER, .5f, 1); + } + } + +} + + +bool EntityHorse::canSpawn() +{ + checkSpawningBiome(); + return Animal::canSpawn(); +} + + +shared_ptr EntityHorse::getClosestMommy(shared_ptr baby, double searchRadius) +{ + double closestDistance = Double::MAX_VALUE; + + shared_ptr mommy = nullptr; + vector > *list = level->getEntities(baby, baby->bb->expand(searchRadius, searchRadius, searchRadius), PARENT_HORSE_SELECTOR); + + for(AUTO_VAR(it,list->begin()); it != list->end(); ++it) + { + shared_ptr horse = *it; + double distanceSquared = horse->distanceToSqr(baby->x, baby->y, baby->z); + + if (distanceSquared < closestDistance) + { + mommy = horse; + closestDistance = distanceSquared; + } + } + delete list; + + return dynamic_pointer_cast(mommy); +} + +double EntityHorse::getCustomJump() +{ + return getAttribute(JUMP_STRENGTH)->getValue(); +} + +int EntityHorse::getDeathSound() +{ + openMouth(); + int type = getType(); + if (type == TYPE_UNDEAD) + { + return eSoundType_MOB_HORSE_ZOMBIE_DEATH; //"mob.horse.zombie.death"; + } + if (type == TYPE_SKELETON) + { + return eSoundType_MOB_HORSE_SKELETON_DEATH; //"mob.horse.skeleton.death"; + } + if (type == TYPE_DONKEY || type == TYPE_MULE) + { + return eSoundType_MOB_HORSE_DONKEY_DEATH; //"mob.horse.donkey.death"; + } + return eSoundType_MOB_HORSE_DEATH; //"mob.horse.death"; +} + +int EntityHorse::getDeathLoot() +{ + bool flag = random->nextInt(4) == 0; + + int type = getType(); + if (type == TYPE_SKELETON) + { + return Item::bone_Id; + } + if (type == TYPE_UNDEAD) + { + if (flag) + { + return 0; + } + return Item::rotten_flesh_Id; + } + + return Item::leather_Id; +} + +int EntityHorse::getHurtSound() +{ + openMouth(); + { + if (random->nextInt(3) == 0) + { + stand(); + } + } + int type = getType(); + if (type == TYPE_UNDEAD) + { + return eSoundType_MOB_HORSE_ZOMBIE_HIT; //"mob.horse.zombie.hit"; + } + if (type == TYPE_SKELETON) + { + return eSoundType_MOB_HORSE_SKELETON_HIT; //"mob.horse.skeleton.hit"; + } + if (type == TYPE_DONKEY || type == TYPE_MULE) + { + return eSoundType_MOB_HORSE_DONKEY_HIT; //"mob.horse.donkey.hit"; + } + return eSoundType_MOB_HORSE_HIT; //"mob.horse.hit"; +} + +bool EntityHorse::isSaddled() +{ + return getHorseFlag(FLAG_SADDLE); +} + + +int EntityHorse::getAmbientSound() +{ + openMouth(); + if (random->nextInt(10) == 0 && !isImmobile()) + { + stand(); + } + int type = getType(); + if (type == TYPE_UNDEAD) + { + return eSoundType_MOB_HORSE_ZOMBIE_IDLE; //"mob.horse.zombie.idle"; + } + if (type == TYPE_SKELETON) + { + return eSoundType_MOB_HORSE_SKELETON_IDLE; //"mob.horse.skeleton.idle"; + } + if (type == TYPE_DONKEY || type == TYPE_MULE) + { + return eSoundType_MOB_HORSE_DONKEY_IDLE; //"mob.horse.donkey.idle"; + } + return eSoundType_MOB_HORSE_IDLE; //"mob.horse.idle"; +} + +/** +* sound played when an untamed mount buckles rider +*/ +int EntityHorse::getMadSound() +{ + openMouth(); + stand(); + int type = getType(); + if (type == TYPE_UNDEAD || type == TYPE_SKELETON) + { + return -1; + } + if (type == TYPE_DONKEY || type == TYPE_MULE) + { + return eSoundType_MOB_HORSE_DONKEY_ANGRY; //"mob.horse.donkey.angry"; + } + return eSoundType_MOB_HORSE_ANGRY; //"mob.horse.angry"; +} + +void EntityHorse::playStepSound(int xt, int yt, int zt, int t) +{ + const Tile::SoundType *soundType = Tile::tiles[t]->soundType; + if (level->getTile(xt, yt + 1, zt) == Tile::topSnow_Id) + { + soundType = Tile::topSnow->soundType; + } + if (!Tile::tiles[t]->material->isLiquid()) + { + int type = getType(); + if (rider.lock() != NULL && type != TYPE_DONKEY && type != TYPE_MULE) + { + gallopSoundCounter++; + if (gallopSoundCounter > 5 && gallopSoundCounter % 3 == 0) + { + playSound(eSoundType_MOB_HORSE_GALLOP, soundType->getVolume() * 0.15f, soundType->getPitch()); + if (type == TYPE_HORSE && random->nextInt(10) == 0) + { + playSound(eSoundType_MOB_HORSE_BREATHE, soundType->getVolume() * 0.6f, soundType->getPitch()); + } + } + else if (gallopSoundCounter <= 5) + { + playSound(eSoundType_MOB_HORSE_WOOD, soundType->getVolume() * 0.15f, soundType->getPitch()); + } + } + else if (soundType == Tile::SOUND_WOOD) + { + playSound(eSoundType_MOB_HORSE_SOFT, soundType->getVolume() * 0.15f, soundType->getPitch()); + } + else + { + playSound(eSoundType_MOB_HORSE_WOOD, soundType->getVolume() * 0.15f, soundType->getPitch()); + } + } +} + +void EntityHorse::registerAttributes() +{ + Animal::registerAttributes(); + + getAttributes()->registerAttribute(JUMP_STRENGTH); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(53); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.225f); +} + +int EntityHorse::getMaxSpawnClusterSize() +{ + return 6; +} + +/** +* How difficult is the creature to be tamed? the Higher the number, the +* more difficult +*/ +int EntityHorse::getMaxTemper() +{ + return 100; +} + +float EntityHorse::getSoundVolume() +{ + return 0.8f; +} + + +int EntityHorse::getAmbientSoundInterval() +{ + return 400; +} + +bool EntityHorse::hasLayeredTextures() +{ + return getType() == TYPE_HORSE || getArmorType() > 0; +} + +void EntityHorse::clearLayeredTextureInfo() +{ + layerTextureHashName = L""; +} + +void EntityHorse::rebuildLayeredTextureInfo() +{ + layerTextureHashName = L"horse/"; + layerTextureLayers[0] = -1; + layerTextureLayers[1] = -1; + layerTextureLayers[2] = -1; + + int type = getType(); + int variant = getVariant(); + int armorIndex = 2; + if (type == TYPE_HORSE) + { + int skin = variant & 0xFF; + int markings = (variant & 0xFF00) >> 8; + layerTextureLayers[0] = VARIANT_TEXTURES_ID[skin]; + layerTextureHashName += VARIANT_HASHES[skin]; + + layerTextureLayers[1] = MARKING_TEXTURES_ID[markings]; + layerTextureHashName += MARKING_HASHES[markings]; + + if(layerTextureLayers[1] == -1) + { + armorIndex = 1; + } + } + else + { + layerTextureLayers[0] = -1; + layerTextureHashName += L"_" + _toString(type) + L"_"; + armorIndex = 1; + } + + int armor = getArmorType(); + layerTextureLayers[armorIndex] = ARMOR_TEXTURES_ID[armor]; + layerTextureHashName += ARMOR_HASHES[armor]; +} + +wstring EntityHorse::getLayeredTextureHashName() +{ + if (layerTextureHashName.empty()) + { + rebuildLayeredTextureInfo(); + } + return layerTextureHashName; +} + +intArray EntityHorse::getLayeredTextureLayers() +{ + if (layerTextureHashName.empty()) + { + rebuildLayeredTextureInfo(); + } + return layerTextureLayers; +} + +void EntityHorse::openInventory(shared_ptr player) +{ + if (!level->isClientSide && (rider.lock() == NULL || rider.lock() == player) && isTamed()) + { + inventory->setCustomName(getAName()); + player->openHorseInventory(dynamic_pointer_cast(shared_from_this()), inventory); + } +} + +bool EntityHorse::mobInteract(shared_ptr player) +{ + shared_ptr itemstack = player->inventory->getSelected(); + + if (itemstack != NULL && itemstack->id == Item::spawnEgg_Id) + { + return Animal::mobInteract(player); + } + + if (!isTamed()) + { + if (isUndead()) + { + return false; + } + } + + if (isTamed() && isAdult() && player->isSneaking()) + { + openInventory(player); + return true; + } + + if (isRidable() && rider.lock() != NULL) + { + return Animal::mobInteract(player); + } + + // consumables + if (itemstack != NULL) + { + bool itemUsed = false; + + if (canWearArmor()) + { + int armorType = -1; + + if (itemstack->id == Item::horseArmorMetal_Id) + { + armorType = ARMOR_IRON; + } + else if (itemstack->id == Item::horseArmorGold_Id) + { + armorType = ARMOR_GOLD; + } + else if (itemstack->id == Item::horseArmorDiamond_Id) + { + armorType = ARMOR_DIAMOND; + } + + if (armorType >= 0) + { + if (!isTamed()) + { + makeMad(); + return true; + } + openInventory(player); + return true; + } + } + + if (!itemUsed && !isUndead()) + { + float _heal = 0; + int _ageUp = 0; + int temper = 0; + + if (itemstack->id == Item::wheat_Id) + { + _heal = 2; + _ageUp = 60; + temper = 3; + } + else if (itemstack->id == Item::sugar_Id) + { + _heal = 1; + _ageUp = 30; + temper = 3; + } + else if (itemstack->id == Item::bread_Id) + { + _heal = 7; + _ageUp = 180; + temper = 3; + } + else if (itemstack->id == Tile::hayBlock_Id) + { + _heal = 20; + _ageUp = 180; + } + else if (itemstack->id == Item::apple_Id) + { + _heal = 3; + _ageUp = 60; + temper = 3; + } + else if (itemstack->id == Item::carrotGolden_Id) + { + _heal = 4; + _ageUp = 60; + temper = 5; + if (isTamed() && getAge() == 0) + { + itemUsed = true; + setInLove(); + } + } + else if (itemstack->id == Item::apple_gold_Id) + { + _heal = 10; + _ageUp = 240; + temper = 10; + if (isTamed() && getAge() == 0) + { + itemUsed = true; + setInLove(); + } + } + if (getHealth() < getMaxHealth() && _heal > 0) + { + heal(_heal); + itemUsed = true; + } + if (!isAdult() && _ageUp > 0) + { + ageUp(_ageUp); + itemUsed = true; + } + if (temper > 0 && (itemUsed || !isTamed()) && temper < getMaxTemper()) + { + itemUsed = true; + modifyTemper(temper); + } + if (itemUsed) + { + eatingHorse(); + } + } + + if (!isTamed() && !itemUsed) + { + if (itemstack != NULL && itemstack->interactEnemy(player, dynamic_pointer_cast(shared_from_this()))) + { + return true; + } + makeMad(); + return true; + } + + if (!itemUsed && canWearBags() && !isChestedHorse()) + { + if (itemstack->id == Tile::chest_Id) + { + setChestedHorse(true); + playSound(eSoundType_MOB_CHICKENPLOP, 1.0f, (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); + itemUsed = true; + createInventory(); + } + } + + if (!itemUsed && isRidable() && !isSaddled()) + { + if (itemstack->id == Item::saddle_Id) + { + openInventory(player); + return true; + } + } + + if (itemUsed) + { + if (!player->abilities.instabuild) + { + if (--itemstack->count == 0) + { + player->inventory->setItem(player->inventory->selected, nullptr); + } + } + return true; + } + } + + if (isRidable() && rider.lock() == NULL) + { + // for name tag items and such, we must call the item's interaction + // method before riding + if (itemstack != NULL && itemstack->interactEnemy(player, dynamic_pointer_cast(shared_from_this()))) + { + return true; + } + doPlayerRide(player); + + app.DebugPrintf(" Horse speed: %f\n", (float) (getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue())); + + return true; + } + else + { + return Animal::mobInteract(player); + } +} + +void EntityHorse::doPlayerRide(shared_ptr player) +{ + player->yRot = yRot; + player->xRot = xRot; + setEating(false); + setStanding(false); + if (!level->isClientSide) + { + player->ride(shared_from_this()); + } +} + +/** +* Can this horse be trapped in an amulet? +*/ +bool EntityHorse::isAmuletHorse() +{ + return getType() == TYPE_SKELETON; +} + +/** +* Can wear regular armor +*/ +bool EntityHorse::canWearArmor() +{ + return getType() == TYPE_HORSE; +} + +/** +* able to carry bags +* +* @return +*/ +bool EntityHorse::canWearBags() +{ + int type = getType(); + return type == TYPE_MULE || type == TYPE_DONKEY; +} + +bool EntityHorse::isImmobile() +{ + if (rider.lock() != NULL && isSaddled()) + { + return true; + } + return isEating() || isStanding(); +} + +/** +* Rare horse that can be transformed into Nightmares or Bathorses or give +* ghost horses on dead +*/ +bool EntityHorse::isPureBreed() +{ + return getType() > 10 && getType() < 21; +} + +/** +* Is this an Undead Horse? +* +* @return +*/ +bool EntityHorse::isUndead() +{ + int type = getType(); + return type == TYPE_UNDEAD || type == TYPE_SKELETON; +} + +bool EntityHorse::isSterile() +{ + return isUndead() || getType() == TYPE_MULE; +} + + +bool EntityHorse::isFood(shared_ptr itemInstance) +{ + // horses have their own food behaviors in mobInterract + return false; +} + +void EntityHorse::moveTail() +{ + tailCounter = 1; +} + +int EntityHorse::nameYOffset() +{ + if (isAdult()) + { + return -80; + } + else + { + return (int) (-5 - getFoalScale() * 80.0f); + } +} + +void EntityHorse::die(DamageSource *damagesource) +{ + Animal::die(damagesource); + if (!level->isClientSide) + { + dropMyStuff(); + } +} + +void EntityHorse::aiStep() +{ + if (random->nextInt(200) == 0) + { + moveTail(); + } + + Animal::aiStep(); + + if (!level->isClientSide) + { + if (random->nextInt(900) == 0 && deathTime == 0) + { + heal(1); + } + + if (!isEating() && rider.lock() == NULL && random->nextInt(300) == 0) + { + if (level->getTile(Mth::floor(x), Mth::floor(y) - 1, Mth::floor(z)) == Tile::grass_Id) + { + setEating(true); + } + } + + if (isEating() && ++countEating > 50) + { + countEating = 0; + setEating(false); + } + + if (isBred() && !isAdult() && !isEating()) + { + shared_ptr mommy = getClosestMommy(shared_from_this(), 16); + if (mommy != NULL && distanceToSqr(mommy) > 4.0) + { + Path *pathentity = level->findPath(shared_from_this(), mommy, 16.0f, true, false, false, true); + setPath(pathentity); + } + + } + } +} + +void EntityHorse::tick() +{ + Animal::tick(); + + // if client-side data values have changed, rebuild texture info + if (level->isClientSide && entityData->isDirty()) + { + entityData->clearDirty(); + clearLayeredTextureInfo(); + } + + if (mouthCounter > 0 && ++mouthCounter > 30) + { + mouthCounter = 0; + setHorseFlag(FLAG_OPEN_MOUTH, false); + } + + if (!level->isClientSide) + { + if (standCounter > 0 && ++standCounter > 20) + { + standCounter = 0; + setStanding(false); + } + } + + if (tailCounter > 0 && ++tailCounter > 8) + { + tailCounter = 0; + } + + if (sprintCounter > 0) + { + ++sprintCounter; + + if (sprintCounter > 300) + { + sprintCounter = 0; + } + } + + eatAnimO = eatAnim; + if (isEating()) + { + eatAnim += (1.0f - eatAnim) * .4f + .05f; + if (eatAnim > 1) + { + eatAnim = 1; + } + } + else + { + eatAnim += (.0f - eatAnim) * .4f - .05f; + if (eatAnim < 0) + { + eatAnim = 0; + } + } + standAnimO = standAnim; + if (isStanding()) + { + // standing is incompatible with eating, so lock eat anim + eatAnimO = eatAnim = 0; + standAnim += (1.0f - standAnim) * .4f + .05f; + if (standAnim > 1) + { + standAnim = 1; + } + } + else + { + allowStandSliding = false; + // the animation falling back to ground is slower in the beginning + standAnim += (.8f * standAnim * standAnim * standAnim - standAnim) * .6f - .05f; + if (standAnim < 0) + { + standAnim = 0; + } + } + mouthAnimO = mouthAnim; + if (getHorseFlag(FLAG_OPEN_MOUTH)) + { + mouthAnim += (1.0f - mouthAnim) * .7f + .05f; + if (mouthAnim > 1) + { + mouthAnim = 1; + } + } + else + { + mouthAnim += (.0f - mouthAnim) * .7f - .05f; + if (mouthAnim < 0) + { + mouthAnim = 0; + } + } +} + +void EntityHorse::openMouth() +{ + if (!level->isClientSide) + { + mouthCounter = 1; + setHorseFlag(FLAG_OPEN_MOUTH, true); + } +} + +bool EntityHorse::isReadyForParenting() +{ + return rider.lock() == NULL && riding == NULL && isTamed() && isAdult() && !isSterile() && getHealth() >= getMaxHealth(); +} + +bool EntityHorse::renderName() +{ + return hasCustomName() && rider.lock() == NULL; +} + +bool EntityHorse::rideableEntity() +{ + return true; +} + + +void EntityHorse::setUsingItemFlag(bool flag) +{ + setHorseFlag(FLAG_EATING, flag); +} + +void EntityHorse::setEating(bool state) +{ + setUsingItemFlag(state); +} + +void EntityHorse::setStanding(bool state) +{ + if (state) + { + setEating(false); + } + setHorseFlag(FLAG_STANDING, state); +} + +void EntityHorse::stand() +{ + if (!level->isClientSide) + { + standCounter = 1; + setStanding(true); + } +} + +void EntityHorse::makeMad() +{ + stand(); + int ambient = getMadSound(); + playSound(ambient, getSoundVolume(), getVoicePitch()); +} + +void EntityHorse::dropMyStuff() +{ + dropInventory(shared_from_this(), inventory); + dropBags(); +} + +void EntityHorse::dropInventory(shared_ptr entity, shared_ptr animalchest) +{ + if (animalchest == NULL || level->isClientSide) return; + + for (int i = 0; i < animalchest->getContainerSize(); i++) + { + shared_ptr itemstack = animalchest->getItem(i); + if (itemstack == NULL) + { + continue; + } + spawnAtLocation(itemstack, 0); + } + +} + +bool EntityHorse::tameWithName(shared_ptr player) +{ + setOwner(player->getName()); + setTamed(true); + return true; +} + +/** +* Overridden method to add control to mounts, should be moved to +* EntityLiving +*/ +void EntityHorse::travel(float xa, float ya) +{ + // If the entity is not ridden by Player, then execute the normal + // Entityliving code + if (rider.lock() == NULL || !isSaddled()) + { + footSize = .5f; + flyingSpeed = .02f; + Animal::travel(xa, ya); + return; + } + + yRotO = yRot = rider.lock()->yRot; + xRot = rider.lock()->xRot * 0.5f; + setRot(yRot, xRot); + yHeadRot = yBodyRot = yRot; + + shared_ptr livingRider = dynamic_pointer_cast(rider.lock()); + xa = livingRider->xxa * .5f; + ya = livingRider->yya; + + // move much slower backwards + if (ya <= 0) + { + ya *= .25f; + gallopSoundCounter = 0; + } + + if (onGround && playerJumpPendingScale == 0 && isStanding() && !allowStandSliding) + { + xa = 0; + ya = 0; + } + + if (playerJumpPendingScale > 0 && !getIsJumping() && onGround) + { + yd = getCustomJump() * playerJumpPendingScale; + if (hasEffect(MobEffect::jump)) + { + yd += (getEffect(MobEffect::jump)->getAmplifier() + 1) * .1f; + } + + setIsJumping(true); + hasImpulse = true; + + if (ya > 0) + { + float sin = Mth::sin(yRot * PI / 180); + float cos = Mth::cos(yRot * PI / 180); + + xd += -0.4f * sin * playerJumpPendingScale; + zd += 0.4f * cos * playerJumpPendingScale; + + playSound(eSoundType_MOB_HORSE_JUMP, .4f, 1); + } + playerJumpPendingScale = 0; + } + + footSize = 1; + flyingSpeed = getSpeed() * .1f; + if (!level->isClientSide) + { + setSpeed((float) (getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue())); + Animal::travel(xa, ya); + } + + + if (onGround) + { + // blood - fixes jump bug + playerJumpPendingScale = 0; + setIsJumping(false); + } + walkAnimSpeedO = walkAnimSpeed; + double dx = x - xo; + double dz = z - zo; + float wst = Mth::sqrt(dx * dx + dz * dz) * 4.0f; + if (wst > 1.0f) + { + wst = 1.0f; + } + + walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f; + walkAnimPos += walkAnimSpeed; + +} + + +void EntityHorse::addAdditonalSaveData(CompoundTag *tag) +{ + Animal::addAdditonalSaveData(tag); + + tag->putBoolean(L"EatingHaystack", isEating()); + tag->putBoolean(L"ChestedHorse", isChestedHorse()); + tag->putBoolean(L"HasReproduced", getHasReproduced()); + tag->putBoolean(L"Bred", isBred()); + tag->putInt(L"Type", getType()); + tag->putInt(L"Variant", getVariant()); + tag->putInt(L"Temper", getTemper()); + tag->putBoolean(L"Tame", isTamed()); + tag->putString(L"OwnerName", getOwnerName()); + + if (isChestedHorse()) + { + ListTag *listTag = new ListTag(); + + for (int i = INV_BASE_COUNT; i < inventory->getContainerSize(); i++) + { + shared_ptr stack = inventory->getItem(i); + + if (stack != NULL) + { + CompoundTag *compoundTag = new CompoundTag(); + + compoundTag->putByte(L"Slot", (byte) i); + + stack->save(compoundTag); + listTag->add(compoundTag); + } + } + tag->put(L"Items", listTag); + } + + if (inventory->getItem(INV_SLOT_ARMOR) != NULL) + { + tag->put(L"ArmorItem", inventory->getItem(INV_SLOT_ARMOR)->save(new CompoundTag(L"ArmorItem"))); + } + if (inventory->getItem(INV_SLOT_SADDLE) != NULL) + { + tag->put(L"SaddleItem", inventory->getItem(INV_SLOT_SADDLE)->save(new CompoundTag(L"SaddleItem"))); + } +} + + +void EntityHorse::readAdditionalSaveData(CompoundTag *tag) +{ + Animal::readAdditionalSaveData(tag); + setEating(tag->getBoolean(L"EatingHaystack")); + setBred(tag->getBoolean(L"Bred")); + setChestedHorse(tag->getBoolean(L"ChestedHorse")); + setReproduced(tag->getBoolean(L"HasReproduced")); + setType(tag->getInt(L"Type")); + setVariant(tag->getInt(L"Variant")); + setTemper(tag->getInt(L"Temper")); + setTamed(tag->getBoolean(L"Tame")); + if (tag->contains(L"OwnerName")) + { + setOwner(tag->getString(L"OwnerName")); + } + + // 4J: This is for handling old save data, not needed on console + /*AttributeInstance *oldSpeedAttribute = getAttributes()->getInstance(SharedMonsterAttributes::MOVEMENT_SPEED); + + if (oldSpeedAttribute != NULL) + { + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(oldSpeedAttribute->getBaseValue() * 0.25f); + }*/ + + if (isChestedHorse()) + { + ListTag *nbttaglist = (ListTag *) tag->getList(L"Items"); + createInventory(); + + for (int i = 0; i < nbttaglist->size(); i++) + { + CompoundTag *compoundTag = nbttaglist->get(i); + int slot = compoundTag->getByte(L"Slot") & 0xFF; + + if (slot >= INV_BASE_COUNT && slot < inventory->getContainerSize()) + { + inventory->setItem(slot, ItemInstance::fromTag(compoundTag)); + } + } + } + + if (tag->contains(L"ArmorItem")) + { + shared_ptr armor = ItemInstance::fromTag(tag->getCompound(L"ArmorItem")); + if (armor != NULL && isHorseArmor(armor->id)) + { + inventory->setItem(INV_SLOT_ARMOR, armor); + } + } + + if (tag->contains(L"SaddleItem")) + { + shared_ptr saddleItem = ItemInstance::fromTag(tag->getCompound(L"SaddleItem")); + if (saddleItem != NULL && saddleItem->id == Item::saddle_Id) + { + inventory->setItem(INV_SLOT_SADDLE, saddleItem); + } + } + else if (tag->getBoolean(L"Saddle")) + { + inventory->setItem(INV_SLOT_SADDLE, shared_ptr( new ItemInstance(Item::saddle))); + } + updateEquipment(); +} + + +bool EntityHorse::canMate(shared_ptr partner) +{ + if (partner == shared_from_this()) return false; + if (partner->GetType() != GetType()) return false; + + shared_ptr horsePartner = dynamic_pointer_cast(partner); + + if (!isReadyForParenting() || !horsePartner->isReadyForParenting()) + { + return false; + } + int type = getType(); + int pType = horsePartner->getType(); + + return type == pType || (type == TYPE_HORSE && pType == TYPE_DONKEY) || (type == TYPE_DONKEY && pType == TYPE_HORSE); +} + + +shared_ptr EntityHorse::getBreedOffspring(shared_ptr partner) +{ + shared_ptr horsePartner = dynamic_pointer_cast(partner); + shared_ptr baby = shared_ptr( new EntityHorse(level) ); + + int type = getType(); + int partnerType = horsePartner->getType(); + int babyType = TYPE_HORSE; + + if (type == partnerType) + { + babyType = type; + } + else if (type == TYPE_HORSE && partnerType == TYPE_DONKEY || type == TYPE_DONKEY && partnerType == TYPE_HORSE) + { + babyType = TYPE_MULE; + } + + // select skin and marking colors + if (babyType == TYPE_HORSE) + { + int skinResult; + int selectSkin = random->nextInt(9); + if (selectSkin < 4) + { + skinResult = getVariant() & 0xff; + } + else if (selectSkin < 8) + { + skinResult = horsePartner->getVariant() & 0xff; + } + else + { + skinResult = random->nextInt(VARIANTS); + } + + int selectMarking = random->nextInt(5); + if (selectMarking < 4) + { + skinResult |= getVariant() & 0xff00; + } + else if (selectMarking < 8) + { + skinResult |= horsePartner->getVariant() & 0xff00; + } + else + { + skinResult |= (random->nextInt(MARKINGS) << 8) & 0xff00; + } + baby->setVariant(skinResult); + } + + baby->setType(babyType); + + // generate stats from parents + double maxHealth = getAttribute(SharedMonsterAttributes::MAX_HEALTH)->getBaseValue() + partner->getAttribute(SharedMonsterAttributes::MAX_HEALTH)->getBaseValue() + generateRandomMaxHealth(); + baby->getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(maxHealth / 3.0f); + + double jumpStrength = getAttribute(JUMP_STRENGTH)->getBaseValue() + partner->getAttribute(JUMP_STRENGTH)->getBaseValue() + generateRandomJumpStrength(); + baby->getAttribute(JUMP_STRENGTH)->setBaseValue(jumpStrength / 3.0f); + + double speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getBaseValue() + partner->getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getBaseValue() + generateRandomSpeed(); + baby->getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(speed / 3.0f); + + return baby; +} + +MobGroupData *EntityHorse::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param +{ + groupData = Animal::finalizeMobSpawn(groupData); + + int type = 0; + int variant = 0; + + if ( dynamic_cast(groupData) != NULL ) + { + type = ((HorseGroupData *) groupData)->horseType; + variant = ((HorseGroupData *) groupData)->horseVariant & 0xff | (random->nextInt(MARKINGS) << 8); + } + else + { + if(extraData != 0) + { + type = extraData - 1; + } + else if (random->nextInt(10) == 0) + { + type = TYPE_DONKEY; + } + else + { + type = TYPE_HORSE; + } + + if(type == TYPE_HORSE) + { + int skin = random->nextInt(VARIANTS); + int mark = random->nextInt(MARKINGS); + variant = skin | (mark << 8); + } + groupData = new HorseGroupData(type, variant); + } + + setType(type); + setVariant(variant); + + if (random->nextInt(5) == 0) + { + setAge(AgableMob::BABY_START_AGE); + } + + if (type == TYPE_SKELETON || type == TYPE_UNDEAD) + { + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(15); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.2f); + } + else + { + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(generateRandomMaxHealth()); + if (type == TYPE_HORSE) + { + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(generateRandomSpeed()); + } + else + { + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.175f); + } + } + if (type == TYPE_MULE || type == TYPE_DONKEY) + { + getAttribute(JUMP_STRENGTH)->setBaseValue(.5f); + } + else + { + getAttribute(JUMP_STRENGTH)->setBaseValue(generateRandomJumpStrength()); + } + setHealth(getMaxHealth()); + + return groupData; +} + +float EntityHorse::getEatAnim(float a) +{ + return eatAnimO + (eatAnim - eatAnimO) * a; +} + +float EntityHorse::getStandAnim(float a) +{ + return standAnimO + (standAnim - standAnimO) * a; +} + +float EntityHorse::getMouthAnim(float a) +{ + return mouthAnimO + (mouthAnim - mouthAnimO) * a; +} + +bool EntityHorse::useNewAi() +{ + return true; +} + +void EntityHorse::onPlayerJump(int jumpAmount) +{ + if (isSaddled()) + { + if (jumpAmount < 0) + { + jumpAmount = 0; + } + else + { + allowStandSliding = true; + stand(); + } + + if (jumpAmount >= 90) + { + playerJumpPendingScale = 1.0f; + } + else + { + playerJumpPendingScale = .4f + .4f * (float) jumpAmount / 90.0f; + } + } +} + +void EntityHorse::spawnTamingParticles(bool success) +{ + ePARTICLE_TYPE particle = success ? eParticleType_heart : eParticleType_smoke; + + for (int i = 0; i < 7; i++) + { + double xa = random->nextGaussian() * 0.02; + double ya = random->nextGaussian() * 0.02; + double za = random->nextGaussian() * 0.02; + level->addParticle(particle, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + .5f + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); + } +} + +void EntityHorse::handleEntityEvent(byte id) +{ + if (id == EntityEvent::TAMING_SUCCEEDED) + { + spawnTamingParticles(true); + } + else if (id == EntityEvent::TAMING_FAILED) + { + spawnTamingParticles(false); + } + else + { + Animal::handleEntityEvent(id); + } +} + +void EntityHorse::positionRider() +{ + Animal::positionRider(); + + if (standAnimO > 0) + { + float sin = Mth::sin(yBodyRot * PI / 180); + float cos = Mth::cos(yBodyRot * PI / 180); + float dist = .7f * standAnimO; + float height = .15f * standAnimO; + + rider.lock()->setPos(x + dist * sin, y + getRideHeight() + rider.lock()->getRidingHeight() + height, z - dist * cos); + + if ( rider.lock()->instanceof(eTYPE_LIVINGENTITY) ) + { + shared_ptr livingRider = dynamic_pointer_cast(rider.lock()); + livingRider->yBodyRot = yBodyRot; + } + } +} + +// Health is between 15 and 30 +float EntityHorse::generateRandomMaxHealth() +{ + return 15.0f + random->nextInt(8) + random->nextInt(9); +} + +double EntityHorse::generateRandomJumpStrength() +{ + return .4f + random->nextDouble() * .2 + random->nextDouble() * .2 + random->nextDouble() * .2; +} + +double EntityHorse::generateRandomSpeed() +{ + double speed = (0.45f + random->nextDouble() * .3 + random->nextDouble() * .3 + random->nextDouble() * .3) * 0.25f; + app.DebugPrintf(" Speed: %f\n", speed); + return speed; +} + +EntityHorse::HorseGroupData::HorseGroupData(int type, int variant) +{ + horseType = type; + horseVariant = variant; +} + +bool EntityHorse::isHorseArmor(int itemId) +{ + return itemId == Item::horseArmorMetal_Id || itemId == Item::horseArmorGold_Id || itemId == Item::horseArmorDiamond_Id; +} + +bool EntityHorse::onLadder() +{ + // prevent horses from climbing ladders + return false; +} + +shared_ptr EntityHorse::getOwner() +{ + return level->getPlayerByUUID(getOwnerName()); +} \ No newline at end of file diff --git a/Minecraft.World/EntityHorse.h b/Minecraft.World/EntityHorse.h new file mode 100644 index 00000000..c2784491 --- /dev/null +++ b/Minecraft.World/EntityHorse.h @@ -0,0 +1,342 @@ +#pragma once + +#include "Animal.h" +#include "net.minecraft.world.ContainerListener.h" +#include "MobGroupData.h" +#include "EntitySelector.h" + +class Attribute; +class AnimalChest; + +class HorseEntitySelector : public EntitySelector +{ +public: + bool matches(shared_ptr entity) const; +}; + +class EntityHorse : public Animal, public net_minecraft_world::ContainerListener +{ +public: + eINSTANCEOF GetType() { return eTYPE_HORSE; } + static Entity *create(Level *level) { return new EntityHorse(level); } + +private: + static const wstring TEX_FOLDER; + + static const EntitySelector *PARENT_HORSE_SELECTOR; + + static Attribute *JUMP_STRENGTH; + + static const int DATA_ID_HORSE_FLAGS = 16; + static const int DATA_ID_TYPE = 19; + static const int DATA_ID_TYPE_VARIANT = 20; + static const int DATA_ID_OWNER_NAME = 21; + static const int DATA_ID_ARMOR = 22; + + static const int FLAG_TAME = 1 << 1; + static const int FLAG_SADDLE = 1 << 2; + static const int FLAG_CHESTED = 1 << 3; + static const int FLAG_BRED = 1 << 4; + static const int FLAG_EATING = 1 << 5; + static const int FLAG_STANDING = 1 << 6; + static const int FLAG_OPEN_MOUTH = 1 << 7; + +public: + static const int INV_SLOT_SADDLE = 0; + static const int INV_SLOT_ARMOR = 1; + static const int INV_BASE_COUNT = 2; + static const int INV_DONKEY_CHEST_COUNT = 15; + + // TODO: USE ENUMS! // Original comment + static const int ARMOR_NONE = 0; + static const int ARMOR_IRON = 1; + static const int ARMOR_GOLD = 2; + static const int ARMOR_DIAMOND = 3; + +private: + static const int ARMORS = 4; + static wstring ARMOR_TEXTURES[ARMORS]; + static int ARMOR_TEXTURES_ID[ARMORS]; + static wstring ARMOR_HASHES[ARMORS]; + static int ARMOR_PROTECTION[ARMORS]; + +public: + static const int TYPE_HORSE = 0; + static const int TYPE_DONKEY = 1; + static const int TYPE_MULE = 2; + static const int TYPE_UNDEAD = 3; + static const int TYPE_SKELETON = 4; + + static const int VARIANT_WHITE = 0; + static const int VARIANT_CREAMY = 1; + static const int VARIANT_CHESTNUT = 2; + static const int VARIANT_BROWN = 3; + static const int VARIANT_BLACK = 4; + static const int VARIANT_GRAY = 5; + static const int VARIANT_DARKBROWN = 6; + +private: + static const int VARIANTS = 7; + static wstring VARIANT_TEXTURES[VARIANTS]; + static int VARIANT_TEXTURES_ID[VARIANTS]; + static wstring VARIANT_HASHES[VARIANTS]; + +public: + static const int MARKING_NONE = 0; + static const int MARKING_WHITE_DETAILS = 1; + static const int MARKING_WHITE_FIELDS = 2; + static const int MARKING_WHITE_DOTS = 3; + static const int MARKING_BLACK_DOTS = 4; + +private: + static const int MARKINGS = 5; + static wstring MARKING_TEXTURES[MARKINGS]; + static int MARKING_TEXTURES_ID[MARKINGS]; + static wstring MARKING_HASHES[MARKINGS]; + +private: + int countEating; // eating timer + int mouthCounter; + int standCounter; + +public: + int tailCounter; + int sprintCounter; + +protected: + bool isEntityJumping; + +private: + shared_ptr inventory; + bool hasReproduced; + +protected: + int temper; + float playerJumpPendingScale; + +private: + bool allowStandSliding; + + // animation data + float eatAnim, eatAnimO; + float standAnim, standAnimO; + float mouthAnim, mouthAnimO; + +public: + EntityHorse(Level *world); + ~EntityHorse(); + +protected: + virtual void defineSynchedData(); + +public: + virtual void setType(int i); + virtual int getType(); + virtual void setVariant(int i); + virtual int getVariant(); + virtual wstring getAName(); + +private: + virtual bool getHorseFlag(int flag); + virtual void setHorseFlag(int flag, bool value); + +public: + virtual bool isAdult(); + virtual bool isTamed(); + virtual bool isRidable(); + virtual wstring getOwnerName(); + virtual void setOwner(const wstring &par1Str); + virtual float getFoalScale(); + virtual void updateSize(bool isBaby); + virtual bool getIsJumping(); + virtual void setTamed(bool flag); + virtual void setIsJumping(bool flag); + virtual bool canBeLeashed(); + +protected: + virtual void onLeashDistance(float distanceToLeashHolder); + +public: + virtual bool isChestedHorse(); + virtual int getArmorType(); + virtual int getArmorTypeForItem(shared_ptr armorItem); + virtual bool isEating(); + virtual bool isStanding(); + virtual bool isBred(); + virtual bool getHasReproduced(); + virtual void setArmorType(int i); + virtual void setBred(bool flag); + virtual void setChestedHorse(bool flag); + virtual void setReproduced(bool flag); + virtual void setSaddled(bool flag); + virtual int getTemper(); + virtual void setTemper(int temper); + virtual int modifyTemper(int amount); + virtual bool hurt(DamageSource *damagesource, float dmg); + virtual int getArmorValue(); + virtual bool isPushable(); + virtual bool checkSpawningBiome(); + virtual void dropBags(); + +private: + virtual void eatingHorse(); + +protected: + virtual void causeFallDamage(float fallDistance); + +private: + virtual int getInventorySize(); + virtual void createInventory(); + virtual void updateEquipment(); + +public: + virtual void containerChanged(); + virtual bool canSpawn(); + +protected: + virtual shared_ptr getClosestMommy(shared_ptr baby, double searchRadius); + +public: + virtual double getCustomJump(); + +protected: + virtual int getDeathSound(); + virtual int getDeathLoot(); + virtual int getHurtSound(); + +public: + virtual bool isSaddled(); + +protected: + virtual int getAmbientSound(); + virtual int getMadSound(); + +private: + int gallopSoundCounter; + + +protected: + virtual void playStepSound(int xt, int yt, int zt, int t); + virtual void registerAttributes(); + +public: + virtual int getMaxSpawnClusterSize(); + virtual int getMaxTemper(); + +protected: + virtual float getSoundVolume(); + +public: + virtual int getAmbientSoundInterval(); + virtual bool hasLayeredTextures(); + +private: + wstring layerTextureHashName; + intArray layerTextureLayers; + +private: + virtual void clearLayeredTextureInfo(); + virtual void rebuildLayeredTextureInfo(); + +public: + virtual wstring getLayeredTextureHashName(); + virtual intArray getLayeredTextureLayers(); + virtual void openInventory(shared_ptr player); + virtual bool mobInteract(shared_ptr player); + +private: + virtual void doPlayerRide(shared_ptr player); + +public: + virtual bool isAmuletHorse(); + virtual bool canWearArmor(); + virtual bool canWearBags(); + +protected: + virtual bool isImmobile(); + +public: + virtual bool isPureBreed(); + virtual bool isUndead(); + virtual bool isSterile(); + virtual bool isFood(shared_ptr itemInstance); + +private: + virtual void moveTail(); + +public: + virtual int nameYOffset(); + virtual void die(DamageSource *damagesource); + virtual void aiStep(); + virtual void tick(); + +private: + virtual void openMouth(); + +public: + // 4J-JEV: Made public for tooltip code, doesn't change state anyway. + virtual bool isReadyForParenting(); + +public: + virtual bool renderName(); + virtual bool rideableEntity(); + virtual void setUsingItemFlag(bool flag); + virtual void setEating(bool state); + virtual void setStanding(bool state); + +private: + virtual void stand(); + +public: + virtual void makeMad(); + virtual void dropMyStuff(); + +private: + virtual void dropInventory(shared_ptr entity, shared_ptr animalchest); + +public: + virtual bool tameWithName(shared_ptr player); + virtual void travel(float xa, float ya); + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual bool canMate(shared_ptr partner); + virtual shared_ptr getBreedOffspring(shared_ptr partner); + virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param + virtual float getEatAnim(float a); + virtual float getStandAnim(float a); + virtual float getMouthAnim(float a); + +protected: + virtual bool useNewAi(); + +public: + virtual void onPlayerJump(int jumpAmount); + +protected: + virtual void spawnTamingParticles(bool success); + +public: + virtual void handleEntityEvent(byte id); + virtual void positionRider(); + +private: + virtual float generateRandomMaxHealth(); + virtual double generateRandomJumpStrength(); + virtual double generateRandomSpeed(); + + shared_ptr getOwner(); + +public: + class HorseGroupData : public MobGroupData + { + + public: + int horseType; + int horseVariant; + + HorseGroupData(int type, int variant); + }; + + static bool isHorseArmor(int itemId); + virtual bool onLadder(); +}; \ No newline at end of file diff --git a/Minecraft.World/EntityIO.cpp b/Minecraft.World/EntityIO.cpp index d0677d38..4532e8dd 100644 --- a/Minecraft.World/EntityIO.cpp +++ b/Minecraft.World/EntityIO.cpp @@ -3,6 +3,8 @@ #include "Painting.h" #include "System.h" #include "Entity.h" +#include "WitherBoss.h" +#include "net.minecraft.world.entity.ambient.h" #include "net.minecraft.world.entity.animal.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.entity.monster.h" @@ -24,7 +26,7 @@ unordered_map EntityIO::idsSpawnableInCreativ void EntityIO::setId(entityCreateFn createFn, eINSTANCEOF clas, const wstring &id, int idNum) { - idCreateMap->insert( unordered_map::value_type(id, createFn) ); + idCreateMap->insert( unordered_map::value_type(id, createFn) ); classIdMap->insert( unordered_map::value_type(clas,id ) ); numCreateMap->insert( unordered_map::value_type(idNum, createFn) ); numClassMap->insert( unordered_map::value_type(idNum, clas) ); @@ -43,52 +45,65 @@ void EntityIO::staticCtor() { setId(ItemEntity::create, eTYPE_ITEMENTITY, L"Item", 1); setId(ExperienceOrb::create, eTYPE_EXPERIENCEORB, L"XPOrb", 2); - - setId(Painting::create, eTYPE_PAINTING, L"Painting", 9); - setId(Arrow::create, eTYPE_ARROW, L"Arrow", 10); - setId(Snowball::create, eTYPE_SNOWBALL, L"Snowball", 11); - setId(Fireball::create, eTYPE_FIREBALL, L"Fireball", 12); + + setId(LeashFenceKnotEntity::create, eTYPE_LEASHFENCEKNOT, L"LeashKnot", 8); + setId(Painting::create, eTYPE_PAINTING, L"Painting", 9); + setId(Arrow::create, eTYPE_ARROW, L"Arrow", 10); + setId(Snowball::create, eTYPE_SNOWBALL, L"Snowball", 11); + setId(LargeFireball::create, eTYPE_FIREBALL, L"Fireball", 12); setId(SmallFireball::create, eTYPE_SMALL_FIREBALL, L"SmallFireball", 13); setId(ThrownEnderpearl::create, eTYPE_THROWNENDERPEARL, L"ThrownEnderpearl", 14); setId(EyeOfEnderSignal::create, eTYPE_EYEOFENDERSIGNAL, L"EyeOfEnderSignal", 15); setId(ThrownPotion::create, eTYPE_THROWNPOTION, L"ThrownPotion", 16); setId(ThrownExpBottle::create, eTYPE_THROWNEXPBOTTLE, L"ThrownExpBottle", 17); setId(ItemFrame::create, eTYPE_ITEM_FRAME, L"ItemFrame", 18); - - setId(PrimedTnt::create, eTYPE_PRIMEDTNT, L"PrimedTnt", 20); - setId(FallingTile::create, eTYPE_FALLINGTILE, L"FallingSand", 21); - - setId(Minecart::create, eTYPE_MINECART, L"Minecart", 40); - setId(Boat::create, eTYPE_BOAT, L"Boat", 41); - - setId(Mob::create, eTYPE_MOB, L"Mob", 48); - setId(Monster::create, eTYPE_MONSTER, L"Monster", 49); - - setId(Creeper::create, eTYPE_CREEPER, L"Creeper", 50, eMinecraftColour_Mob_Creeper_Colour1, eMinecraftColour_Mob_Creeper_Colour2, IDS_CREEPER); - setId(Skeleton::create, eTYPE_SKELETON, L"Skeleton", 51, eMinecraftColour_Mob_Skeleton_Colour1, eMinecraftColour_Mob_Skeleton_Colour2, IDS_SKELETON); - setId(Spider::create, eTYPE_SPIDER, L"Spider", 52, eMinecraftColour_Mob_Spider_Colour1, eMinecraftColour_Mob_Spider_Colour2, IDS_SPIDER); - setId(Giant::create, eTYPE_GIANT, L"Giant", 53); - setId(Zombie::create, eTYPE_ZOMBIE, L"Zombie", 54, eMinecraftColour_Mob_Zombie_Colour1, eMinecraftColour_Mob_Zombie_Colour2, IDS_ZOMBIE); - setId(Slime::create, eTYPE_SLIME, L"Slime", 55, eMinecraftColour_Mob_Slime_Colour1, eMinecraftColour_Mob_Slime_Colour2, IDS_SLIME); - setId(Ghast::create, eTYPE_GHAST, L"Ghast", 56, eMinecraftColour_Mob_Ghast_Colour1, eMinecraftColour_Mob_Ghast_Colour2, IDS_GHAST); - setId(PigZombie::create, eTYPE_PIGZOMBIE, L"PigZombie", 57, eMinecraftColour_Mob_PigZombie_Colour1, eMinecraftColour_Mob_PigZombie_Colour2, IDS_PIGZOMBIE); + setId(WitherSkull::create, eTYPE_WITHER_SKULL, L"WitherSkull", 19); + + setId(PrimedTnt::create, eTYPE_PRIMEDTNT, L"PrimedTnt", 20); + setId(FallingTile::create, eTYPE_FALLINGTILE, L"FallingSand", 21); + + setId(FireworksRocketEntity::create, eTYPE_FIREWORKS_ROCKET, L"FireworksRocketEntity", 22); + + setId(Boat::create, eTYPE_BOAT, L"Boat", 41); + setId(MinecartRideable::create, eTYPE_MINECART_RIDEABLE, L"MinecartRideable", 42); + setId(MinecartChest::create, eTYPE_MINECART_CHEST, L"MinecartChest", 43); + setId(MinecartFurnace::create, eTYPE_MINECART_FURNACE, L"MinecartFurnace", 44); + setId(MinecartTNT::create, eTYPE_MINECART_TNT, L"MinecartTNT", 45); + setId(MinecartHopper::create, eTYPE_MINECART_HOPPER, L"MinecartHopper", 46); + setId(MinecartSpawner::create, eTYPE_MINECART_SPAWNER, L"MinecartSpawner", 47); + + setId(Mob::create, eTYPE_MOB, L"Mob", 48); + setId(Monster::create, eTYPE_MONSTER, L"Monster", 49); + + setId(Creeper::create, eTYPE_CREEPER, L"Creeper", 50, eMinecraftColour_Mob_Creeper_Colour1, eMinecraftColour_Mob_Creeper_Colour2, IDS_CREEPER); + setId(Skeleton::create, eTYPE_SKELETON, L"Skeleton", 51, eMinecraftColour_Mob_Skeleton_Colour1, eMinecraftColour_Mob_Skeleton_Colour2, IDS_SKELETON); + setId(Spider::create, eTYPE_SPIDER, L"Spider", 52, eMinecraftColour_Mob_Spider_Colour1, eMinecraftColour_Mob_Spider_Colour2, IDS_SPIDER); + setId(Giant::create, eTYPE_GIANT, L"Giant", 53); + setId(Zombie::create, eTYPE_ZOMBIE, L"Zombie", 54, eMinecraftColour_Mob_Zombie_Colour1, eMinecraftColour_Mob_Zombie_Colour2, IDS_ZOMBIE); + setId(Slime::create, eTYPE_SLIME, L"Slime", 55, eMinecraftColour_Mob_Slime_Colour1, eMinecraftColour_Mob_Slime_Colour2, IDS_SLIME); + setId(Ghast::create, eTYPE_GHAST, L"Ghast", 56, eMinecraftColour_Mob_Ghast_Colour1, eMinecraftColour_Mob_Ghast_Colour2, IDS_GHAST); + setId(PigZombie::create, eTYPE_PIGZOMBIE, L"PigZombie", 57, eMinecraftColour_Mob_PigZombie_Colour1, eMinecraftColour_Mob_PigZombie_Colour2, IDS_PIGZOMBIE); setId(EnderMan::create, eTYPE_ENDERMAN, L"Enderman", 58, eMinecraftColour_Mob_Enderman_Colour1, eMinecraftColour_Mob_Enderman_Colour2, IDS_ENDERMAN); setId(CaveSpider::create, eTYPE_CAVESPIDER, L"CaveSpider", 59, eMinecraftColour_Mob_CaveSpider_Colour1, eMinecraftColour_Mob_CaveSpider_Colour2, IDS_CAVE_SPIDER); setId(Silverfish::create, eTYPE_SILVERFISH, L"Silverfish", 60, eMinecraftColour_Mob_Silverfish_Colour1, eMinecraftColour_Mob_Silverfish_Colour2, IDS_SILVERFISH); setId(Blaze::create, eTYPE_BLAZE, L"Blaze", 61, eMinecraftColour_Mob_Blaze_Colour1, eMinecraftColour_Mob_Blaze_Colour2, IDS_BLAZE); setId(LavaSlime::create, eTYPE_LAVASLIME, L"LavaSlime", 62, eMinecraftColour_Mob_LavaSlime_Colour1, eMinecraftColour_Mob_LavaSlime_Colour2, IDS_LAVA_SLIME); - setId(EnderDragon::create, eTYPE_ENDERDRAGON, L"EnderDragon", 63); - - setId(Pig::create, eTYPE_PIG, L"Pig", 90, eMinecraftColour_Mob_Pig_Colour1, eMinecraftColour_Mob_Pig_Colour2, IDS_PIG); - setId(Sheep::create, eTYPE_SHEEP, L"Sheep", 91, eMinecraftColour_Mob_Sheep_Colour1, eMinecraftColour_Mob_Sheep_Colour2, IDS_SHEEP); - setId(Cow::create, eTYPE_COW, L"Cow", 92, eMinecraftColour_Mob_Cow_Colour1, eMinecraftColour_Mob_Cow_Colour2, IDS_COW); - setId(Chicken::create, eTYPE_CHICKEN, L"Chicken", 93, eMinecraftColour_Mob_Chicken_Colour1, eMinecraftColour_Mob_Chicken_Colour2, IDS_CHICKEN); - setId(Squid::create, eTYPE_SQUID, L"Squid", 94, eMinecraftColour_Mob_Squid_Colour1, eMinecraftColour_Mob_Squid_Colour2, IDS_SQUID); - setId(Wolf::create, eTYPE_WOLF, L"Wolf", 95, eMinecraftColour_Mob_Wolf_Colour1, eMinecraftColour_Mob_Wolf_Colour2, IDS_WOLF); + setId(EnderDragon::create, eTYPE_ENDERDRAGON, L"EnderDragon", 63, eMinecraftColour_Mob_Enderman_Colour1, eMinecraftColour_Mob_Enderman_Colour1, IDS_ENDERDRAGON); + setId(WitherBoss::create, eTYPE_WITHERBOSS, L"WitherBoss", 64); + setId(Bat::create, eTYPE_BAT, L"Bat", 65, eMinecraftColour_Mob_Bat_Colour1, eMinecraftColour_Mob_Bat_Colour2, IDS_BAT); + setId(Witch::create, eTYPE_WITCH, L"Witch", 66, eMinecraftColour_Mob_Witch_Colour1, eMinecraftColour_Mob_Witch_Colour2, IDS_WITCH); + + setId(Pig::create, eTYPE_PIG, L"Pig", 90, eMinecraftColour_Mob_Pig_Colour1, eMinecraftColour_Mob_Pig_Colour2, IDS_PIG); + setId(Sheep::create, eTYPE_SHEEP, L"Sheep", 91, eMinecraftColour_Mob_Sheep_Colour1, eMinecraftColour_Mob_Sheep_Colour2, IDS_SHEEP); + setId(Cow::create, eTYPE_COW, L"Cow", 92, eMinecraftColour_Mob_Cow_Colour1, eMinecraftColour_Mob_Cow_Colour2, IDS_COW); + setId(Chicken::create, eTYPE_CHICKEN, L"Chicken", 93, eMinecraftColour_Mob_Chicken_Colour1, eMinecraftColour_Mob_Chicken_Colour2, IDS_CHICKEN); + setId(Squid::create, eTYPE_SQUID, L"Squid", 94, eMinecraftColour_Mob_Squid_Colour1, eMinecraftColour_Mob_Squid_Colour2, IDS_SQUID); + setId(Wolf::create, eTYPE_WOLF, L"Wolf", 95, eMinecraftColour_Mob_Wolf_Colour1, eMinecraftColour_Mob_Wolf_Colour2, IDS_WOLF); setId(MushroomCow::create, eTYPE_MUSHROOMCOW, L"MushroomCow", 96, eMinecraftColour_Mob_MushroomCow_Colour1, eMinecraftColour_Mob_MushroomCow_Colour2, IDS_MUSHROOM_COW); setId(SnowMan::create, eTYPE_SNOWMAN, L"SnowMan", 97); - setId(Ozelot::create, eTYPE_OZELOT, L"Ozelot", 98, eMinecraftColour_Mob_Ocelot_Colour1, eMinecraftColour_Mob_Ocelot_Colour2, IDS_OZELOT); + setId(Ocelot::create, eTYPE_OCELOT, L"Ozelot", 98, eMinecraftColour_Mob_Ocelot_Colour1, eMinecraftColour_Mob_Ocelot_Colour2, IDS_OZELOT); setId(VillagerGolem::create, eTYPE_VILLAGERGOLEM, L"VillagerGolem", 99); + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", 100, eMinecraftColour_Mob_Horse_Colour1, eMinecraftColour_Mob_Horse_Colour2, IDS_HORSE); setId(Villager::create, eTYPE_VILLAGER, L"Villager", 120, eMinecraftColour_Mob_Villager_Colour1, eMinecraftColour_Mob_Villager_Colour2, IDS_VILLAGER); @@ -96,70 +111,116 @@ void EntityIO::staticCtor() // 4J Added setId(DragonFireball::create, eTYPE_DRAGON_FIREBALL, L"DragonFireball", 1000); + + // 4J-PB - moved to allow the eggs to be named and coloured in the Creative Mode menu + // 4J Added for custom spawn eggs + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", 100 | ((EntityHorse::TYPE_DONKEY + 1) << 12), eMinecraftColour_Mob_Horse_Colour1, eMinecraftColour_Mob_Horse_Colour2, IDS_DONKEY); + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", 100 | ((EntityHorse::TYPE_MULE + 1) << 12), eMinecraftColour_Mob_Horse_Colour1, eMinecraftColour_Mob_Horse_Colour2, IDS_MULE); + +#ifndef _CONTENT_PACKAGE + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", 100 | ((EntityHorse::TYPE_SKELETON + 1) << 12), eMinecraftColour_Mob_Horse_Colour1, eMinecraftColour_Mob_Horse_Colour2, IDS_SKELETON_HORSE); + setId(EntityHorse::create, eTYPE_HORSE, L"EntityHorse", 100 | ((EntityHorse::TYPE_UNDEAD + 1) << 12), eMinecraftColour_Mob_Horse_Colour1, eMinecraftColour_Mob_Horse_Colour2, IDS_ZOMBIE_HORSE); + setId(Ocelot::create, eTYPE_OCELOT, L"Ozelot", 98 | ((Ocelot::TYPE_BLACK + 1) << 12), eMinecraftColour_Mob_Ocelot_Colour1, eMinecraftColour_Mob_Ocelot_Colour2, IDS_OZELOT ); + setId(Ocelot::create, eTYPE_OCELOT, L"Ozelot", 98 | ((Ocelot::TYPE_RED + 1) << 12), eMinecraftColour_Mob_Ocelot_Colour1, eMinecraftColour_Mob_Ocelot_Colour2, IDS_OZELOT ); + setId(Ocelot::create, eTYPE_OCELOT, L"Ozelot", 98 | ((Ocelot::TYPE_SIAMESE + 1) << 12), eMinecraftColour_Mob_Ocelot_Colour1, eMinecraftColour_Mob_Ocelot_Colour2, IDS_OZELOT ); + setId(Spider::create, eTYPE_SPIDER, L"Spider", 52 | (2 << 12), eMinecraftColour_Mob_Spider_Colour1, eMinecraftColour_Mob_Spider_Colour2, IDS_SKELETON ); +#endif } shared_ptr EntityIO::newEntity(const wstring& id, Level *level) { - shared_ptr entity; + shared_ptr entity; AUTO_VAR(it, idCreateMap->find(id)); if(it != idCreateMap->end() ) { entityCreateFn create = it->second; if (create != NULL) entity = shared_ptr(create(level)); + if( ( entity != NULL ) && entity->GetType() == eTYPE_ENDERDRAGON ) + { + dynamic_pointer_cast(entity)->AddParts(); // 4J added to finalise creation + } } - return entity; + return entity; } shared_ptr EntityIO::loadStatic(CompoundTag *tag, Level *level) { - shared_ptr entity; + shared_ptr entity; + + if (tag->getString(L"id").compare(L"Minecart") == 0) + { + // I don't like this any more than you do. Sadly, compatibility... + + switch (tag->getInt(L"Type")) + { + case Minecart::TYPE_CHEST: + tag->putString(L"id", L"MinecartChest"); + break; + case Minecart::TYPE_FURNACE: + tag->putString(L"id", L"MinecartFurnace"); + break; + case Minecart::TYPE_RIDEABLE: + tag->putString(L"id", L"MinecartRideable"); + break; + } + + tag->remove(L"Type"); + } AUTO_VAR(it, idCreateMap->find(tag->getString(L"id"))); if(it != idCreateMap->end() ) { entityCreateFn create = it->second; if (create != NULL) entity = shared_ptr(create(level)); + if( ( entity != NULL ) && entity->GetType() == eTYPE_ENDERDRAGON ) + { + dynamic_pointer_cast(entity)->AddParts(); // 4J added to finalise creation + } } - if (entity != NULL) + if (entity != NULL) { - entity->load(tag); - } + entity->load(tag); + } else { #ifdef _DEBUG app.DebugPrintf("Skipping Entity with id %ls\n", tag->getString(L"id").c_str() ); #endif - } - return entity; + } + return entity; } shared_ptr EntityIO::newById(int id, Level *level) { - shared_ptr entity; + shared_ptr entity; AUTO_VAR(it, numCreateMap->find(id)); if(it != numCreateMap->end() ) { entityCreateFn create = it->second; if (create != NULL) entity = shared_ptr(create(level)); + if( ( entity != NULL ) && entity->GetType() == eTYPE_ENDERDRAGON ) + { + dynamic_pointer_cast(entity)->AddParts(); // 4J added to finalise creation + } } - if (entity != NULL) + if (entity != NULL) { - } + } else { - //printf("Skipping Entity with id %d\n", id ) ; - } - return entity; + //printf("Skipping Entity with id %d\n", id ) ; + } + return entity; } shared_ptr EntityIO::newByEnumType(eINSTANCEOF eType, Level *level) { - shared_ptr entity; + shared_ptr entity; unordered_map::iterator it = classNumMap->find( eType ); if( it != classNumMap->end() ) @@ -169,10 +230,14 @@ shared_ptr EntityIO::newByEnumType(eINSTANCEOF eType, Level *level) { entityCreateFn create = it2->second; if (create != NULL) entity = shared_ptr(create(level)); + if( ( entity != NULL ) && entity->GetType() == eTYPE_ENDERDRAGON ) + { + dynamic_pointer_cast(entity)->AddParts(); // 4J added to finalise creation + } } } - return entity; + return entity; } int EntityIO::getId(shared_ptr entity) @@ -208,7 +273,7 @@ wstring EntityIO::getEncodeId(int entityIoValue) //{ //return classIdMap.get(class1); //} - + AUTO_VAR(it, numClassMap->find(entityIoValue)); if(it != numClassMap->end() ) { diff --git a/Minecraft.World/EntitySelector.cpp b/Minecraft.World/EntitySelector.cpp new file mode 100644 index 00000000..36c7bf88 --- /dev/null +++ b/Minecraft.World/EntitySelector.cpp @@ -0,0 +1,42 @@ +#include "stdafx.h" +#include "Container.h" +#include "EntitySelector.h" + +const EntitySelector *EntitySelector::ENTITY_STILL_ALIVE = new AliveEntitySelector(); +const EntitySelector *EntitySelector::CONTAINER_ENTITY_SELECTOR = new ContainerEntitySelector(); + +bool AliveEntitySelector::matches(shared_ptr entity) const +{ + return entity->isAlive(); +} + +bool ContainerEntitySelector::matches(shared_ptr entity) const +{ + return (dynamic_pointer_cast(entity) != NULL) && entity->isAlive(); +} + +MobCanWearArmourEntitySelector::MobCanWearArmourEntitySelector(shared_ptr item) +{ + this->item = item; +} + +bool MobCanWearArmourEntitySelector::matches(shared_ptr entity) const +{ + if ( !entity->isAlive() ) return false; + if ( !entity->instanceof(eTYPE_LIVINGENTITY) ) return false; + + shared_ptr mob = dynamic_pointer_cast(entity); + + if (mob->getCarried(Mob::getEquipmentSlotForItem(item)) != NULL) return false; + + if ( mob->instanceof(eTYPE_MOB) ) + { + return dynamic_pointer_cast(mob)->canPickUpLoot(); + } + else if (mob->instanceof(eTYPE_PLAYER)) + { + return true; + } + + return false; +} \ No newline at end of file diff --git a/Minecraft.World/EntitySelector.h b/Minecraft.World/EntitySelector.h new file mode 100644 index 00000000..5cba9e84 --- /dev/null +++ b/Minecraft.World/EntitySelector.h @@ -0,0 +1,32 @@ +#pragma once + +class EntitySelector +{ +public: + static const EntitySelector *ENTITY_STILL_ALIVE; + static const EntitySelector *CONTAINER_ENTITY_SELECTOR; + + virtual bool matches(shared_ptr entity) const = 0; +}; + +class AliveEntitySelector : public EntitySelector +{ +public: + bool matches(shared_ptr entity) const; +}; + +class ContainerEntitySelector : public EntitySelector +{ +public: + bool matches(shared_ptr entity) const; +}; + +class MobCanWearArmourEntitySelector : public EntitySelector +{ +private: + shared_ptr item; + +public: + MobCanWearArmourEntitySelector(shared_ptr item); + bool matches(shared_ptr entity) const; +}; \ No newline at end of file diff --git a/Minecraft.World/EntityTile.h b/Minecraft.World/EntityTile.h index 7f781c19..50e62397 100644 --- a/Minecraft.World/EntityTile.h +++ b/Minecraft.World/EntityTile.h @@ -1,15 +1,7 @@ #pragma once -#include "Tile.h" -class TileEntity; - -class EntityTile : public Tile +class EntityTile { -protected: - EntityTile(int id, Material *material, bool isSolidRender = true); public: - virtual void onPlace(Level *level, int x, int y, int z); - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); virtual shared_ptr newTileEntity(Level *level) = 0; - virtual void triggerEvent(Level *level, int x, int y, int z, int b0, int b1); }; \ No newline at end of file diff --git a/Minecraft.World/ExperienceCommand.cpp b/Minecraft.World/ExperienceCommand.cpp index b8ac2efc..9a59d71a 100644 --- a/Minecraft.World/ExperienceCommand.cpp +++ b/Minecraft.World/ExperienceCommand.cpp @@ -2,6 +2,7 @@ #include "net.minecraft.commands.h" #include "..\Minecraft.Client\MinecraftServer.h" #include "..\Minecraft.Client\PlayerList.h" +#include "net.minecraft.world.level.h" #include "ExperienceCommand.h" EGameCommand ExperienceCommand::getId() @@ -9,33 +10,50 @@ EGameCommand ExperienceCommand::getId() return eGameCommand_Experience; } -void ExperienceCommand::execute(shared_ptr source, byteArray commandData) +int ExperienceCommand::getPermissionLevel() { - //if (args.length > 0) - //{ - // Player player; - // int amount = convertArgToInt(source, args[0], 0, 5000); - - // if (args.length > 1) { - // player = getPlayer(args[1]); - // } else { - // player = convertSourceToPlayer(source); - // } - - // player.increaseXp(amount); - // logAdminAction(source, "commands.xp.success", amount, player.getAName()); - //} + return LEVEL_GAMEMASTERS; } -shared_ptr ExperienceCommand::getPlayer(PlayerUID playerId) +void ExperienceCommand::execute(shared_ptr source, byteArray commandData) { - return nullptr; - //shared_ptr player = MinecraftServer::getInstance()->getPlayers()->getPlayer(playerId); - - //if (player == null) - //{ - // throw new PlayerNotFoundException(); - //} else { - // return player; - //} +// if (args.length > 0) { +// Player player; +// String inputAmount = args[0]; +// +// boolean levels = inputAmount.endsWith("l") || inputAmount.endsWith("L"); +// if (levels && inputAmount.length() > 1) inputAmount = inputAmount.substring(0, inputAmount.length() - 1); +// +// int amount = convertArgToInt(source, inputAmount); +// boolean take = amount < 0; +// +// if (take) amount *= -1; +// +// if (args.length > 1) { +// player = convertToPlayer(source, args[1]); +// } else { +// player = convertSourceToPlayer(source); +// } +// +// if (levels) { +// if (take) { +// player.giveExperienceLevels(-amount); +// logAdminAction(source, "commands.xp.success.negative.levels", amount, player.getAName()); +// } else { +// player.giveExperienceLevels(amount); +// logAdminAction(source, "commands.xp.success.levels", amount, player.getAName()); +// } +// } else { +// if (take) { +// throw new UsageException("commands.xp.failure.widthdrawXp"); +// } else { +// player.increaseXp(amount); +// logAdminAction(source, "commands.xp.success", amount, player.getAName()); +// } +// } +// +// return; +// } +// +// throw new UsageException("commands.xp.usage"); } \ No newline at end of file diff --git a/Minecraft.World/ExperienceCommand.h b/Minecraft.World/ExperienceCommand.h index b1dd2cbe..2ca86aff 100644 --- a/Minecraft.World/ExperienceCommand.h +++ b/Minecraft.World/ExperienceCommand.h @@ -8,8 +8,6 @@ class ExperienceCommand : public Command { public: virtual EGameCommand getId(); + virtual int getPermissionLevel(); virtual void execute(shared_ptr source, byteArray commandData); - -protected: - shared_ptr getPlayer(PlayerUID playerId); }; \ No newline at end of file diff --git a/Minecraft.World/ExperienceItem.cpp b/Minecraft.World/ExperienceItem.cpp index 497c2385..433c1207 100644 --- a/Minecraft.World/ExperienceItem.cpp +++ b/Minecraft.World/ExperienceItem.cpp @@ -15,7 +15,7 @@ bool ExperienceItem::isFoil(shared_ptr itemInstance) return true; } -bool ExperienceItem::TestUse(Level *level, shared_ptr player) +bool ExperienceItem::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { return true; } @@ -26,7 +26,7 @@ shared_ptr ExperienceItem::use(shared_ptr itemInstan { itemInstance->count--; } - level->playSound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); + level->playEntitySound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); if (!level->isClientSide) level->addEntity( shared_ptr( new ThrownExpBottle(level, player) )); return itemInstance; } \ No newline at end of file diff --git a/Minecraft.World/ExperienceItem.h b/Minecraft.World/ExperienceItem.h index c8e95925..89dac191 100644 --- a/Minecraft.World/ExperienceItem.h +++ b/Minecraft.World/ExperienceItem.h @@ -11,5 +11,5 @@ public: virtual bool isFoil(shared_ptr itemInstance); virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); - virtual bool TestUse(Level *level, shared_ptr player); + virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); }; \ No newline at end of file diff --git a/Minecraft.World/ExperienceOrb.cpp b/Minecraft.World/ExperienceOrb.cpp index 76f2a9ae..9fed6d71 100644 --- a/Minecraft.World/ExperienceOrb.cpp +++ b/Minecraft.World/ExperienceOrb.cpp @@ -90,7 +90,7 @@ void ExperienceOrb::tick() yd = 0.2f; xd = (random->nextFloat() - random->nextFloat()) * 0.2f; zd = (random->nextFloat() - random->nextFloat()) * 0.2f; - level->playSound(shared_from_this(), eSoundType_RANDOM_FIZZ, 0.4f, 2.0f + random->nextFloat() * 0.4f); + playSound(eSoundType_RANDOM_FIZZ, 0.4f, 2.0f + random->nextFloat() * 0.4f); } checkInTile(x, (bb->y0 + bb->y1) / 2, z); @@ -162,8 +162,9 @@ void ExperienceOrb::burn(int dmg) hurt(DamageSource::inFire, dmg); } -bool ExperienceOrb::hurt(DamageSource *source, int damage) +bool ExperienceOrb::hurt(DamageSource *source, float damage) { + if (isInvulnerable()) return false; markHurt(); health -= damage; if (health <= 0) @@ -195,7 +196,7 @@ void ExperienceOrb::playerTouch(shared_ptr player) { player->takeXpDelay = 2; // 4J - sound change brought forward from 1.2.3 - level->playSound(shared_from_this(), eSoundType_RANDOM_ORB, 0.1f, 0.5f * ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.8f)); + playSound(eSoundType_RANDOM_ORB, 0.1f, 0.5f * ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.8f)); player->take(shared_from_this(), 1); player->increaseXp(value); remove(); diff --git a/Minecraft.World/ExperienceOrb.h b/Minecraft.World/ExperienceOrb.h index 524ae52a..37d11a6c 100644 --- a/Minecraft.World/ExperienceOrb.h +++ b/Minecraft.World/ExperienceOrb.h @@ -46,7 +46,7 @@ protected: virtual void burn(int dmg); public: - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); virtual void addAdditonalSaveData(CompoundTag *entityTag); virtual void readAdditionalSaveData(CompoundTag *tag); virtual void playerTouch(shared_ptr player); diff --git a/Minecraft.World/Explosion.cpp b/Minecraft.World/Explosion.cpp index 604813b7..028ad673 100644 --- a/Minecraft.World/Explosion.cpp +++ b/Minecraft.World/Explosion.cpp @@ -1,5 +1,7 @@ #include "stdafx.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.item.enchantment.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" @@ -69,9 +71,11 @@ void Explosion::explode() int t = level->getTile(xt, yt, zt); if (t > 0) { - remainingPower -= (Tile::tiles[t]->getExplosionResistance(source) + 0.3f) * stepSize; + Tile *tile = Tile::tiles[t]; + float resistance = source != NULL ? source->getTileExplosionResistance(this, level, xt, yt, zt, tile) : tile->getExplosionResistance(source); + remainingPower -= (resistance + 0.3f) * stepSize; } - if (remainingPower > 0) + if (remainingPower > 0&& (source == NULL || source->shouldTileExplode(this, level, xt, yt, zt, t, remainingPower))) { toBlow.insert(TilePos(xt, yt, zt)); } @@ -142,16 +146,17 @@ void Explosion::explode() double sp = level->getSeenPercent(center, e->bb); double pow = (1 - dist) * sp; - if(canDamage) e->hurt(DamageSource::explosion, (int) ((pow * pow + pow) / 2 * 8 * r + 1)); + if(canDamage) e->hurt(DamageSource::explosion(this), (int) ((pow * pow + pow) / 2 * 8 * r + 1)); - double push = pow; - e->xd += xa * push; - e->yd += ya * push; - e->zd += za * push; + double kbPower = ProtectionEnchantment::getExplosionKnockbackAfterDampener(e, pow); + e->xd += xa *kbPower; + e->yd += ya *kbPower; + e->zd += za *kbPower; - shared_ptr player = dynamic_pointer_cast(e); - if (player != NULL) + + if (e->instanceof(eTYPE_PLAYER)) { + shared_ptr player = dynamic_pointer_cast(e); //app.DebugPrintf("Adding player knockback (%f,%f,%f)\n", xa * pow, ya * pow, za * pow); hitPlayers.insert( playerVec3Map::value_type( player, Vec3::newPermanent(xa * pow, ya * pow, za * pow))); } @@ -164,68 +169,82 @@ void Explosion::explode() void Explosion::finalizeExplosion(bool generateParticles, vector *toBlowDirect/*=NULL*/) // 4J - added toBlowDirect parameter { level->playSound(x, y, z, eSoundType_RANDOM_EXPLODE, 4, (1 + (level->random->nextFloat() - level->random->nextFloat()) * 0.2f) * 0.7f); - level->addParticle(eParticleType_hugeexplosion, x, y, z, 0, 0, 0); - + if (r < 2 || !destroyBlocks) + { + level->addParticle(eParticleType_largeexplode, x, y, z, 1.0f, 0, 0); + } + else + { + level->addParticle(eParticleType_hugeexplosion, x, y, z, 1.0f, 0, 0); + } + // 4J - use pointer to vector directly passed in if this is available - used to speed up calling this from an incoming packet vector *toBlowArray = toBlowDirect ? toBlowDirect : new vector( toBlow.begin(), toBlow.end() ); - //toBlowArray.addAll(toBlow); - // TODO 4J Stu - Reverse iterator - PIXBeginNamedEvent(0,"Finalizing explosion size %d",toBlow.size()); - app.DebugPrintf("Finalizing explosion size %d\n",toBlow.size()); - static const int MAX_EXPLODE_PARTICLES = 50; - // 4J - try and make at most MAX_EXPLODE_PARTICLES pairs of particles - int fraction = (int)toBlowArray->size() / MAX_EXPLODE_PARTICLES; - if( fraction == 0 ) fraction = 1; - size_t j = toBlowArray->size() - 1; - //for (size_t j = toBlowArray->size() - 1; j >= 0; j--) - for(AUTO_VAR(it,toBlowArray->rbegin()); it != toBlowArray->rend(); ++it) + if (destroyBlocks) { - TilePos *tp = &(*it); //&toBlowArray->at(j); - int xt = tp->x; - int yt = tp->y; - int zt = tp->z; - // if (xt >= 0 && yt >= 0 && zt >= 0 && xt < width && yt < depth && - // zt < height) { - int t = level->getTile(xt, yt, zt); - - if (generateParticles) + //toBlowArray.addAll(toBlow); + // TODO 4J Stu - Reverse iterator + PIXBeginNamedEvent(0,"Finalizing explosion size %d",toBlow.size()); + app.DebugPrintf("Finalizing explosion size %d\n",toBlow.size()); + static const int MAX_EXPLODE_PARTICLES = 50; + // 4J - try and make at most MAX_EXPLODE_PARTICLES pairs of particles + int fraction = (int)toBlowArray->size() / MAX_EXPLODE_PARTICLES; + if( fraction == 0 ) fraction = 1; + size_t j = toBlowArray->size() - 1; + //for (size_t j = toBlowArray->size() - 1; j >= 0; j--) + for(AUTO_VAR(it,toBlowArray->rbegin()); it != toBlowArray->rend(); ++it) { - if( ( j % fraction ) == 0 ) + TilePos *tp = &(*it); //&toBlowArray->at(j); + int xt = tp->x; + int yt = tp->y; + int zt = tp->z; + // if (xt >= 0 && yt >= 0 && zt >= 0 && xt < width && yt < depth && + // zt < height) { + int t = level->getTile(xt, yt, zt); + + if (generateParticles) { - double xa = xt + level->random->nextFloat(); - double ya = yt + level->random->nextFloat(); - double za = zt + level->random->nextFloat(); + if( ( j % fraction ) == 0 ) + { + double xa = xt + level->random->nextFloat(); + double ya = yt + level->random->nextFloat(); + double za = zt + level->random->nextFloat(); - double xd = xa - x; - double yd = ya - y; - double zd = za - z; + double xd = xa - x; + double yd = ya - y; + double zd = za - z; - double dd = sqrt(xd * xd + yd * yd + zd * zd); + double dd = sqrt(xd * xd + yd * yd + zd * zd); - xd /= dd; - yd /= dd; - zd /= dd; + xd /= dd; + yd /= dd; + zd /= dd; - double speed = 0.5 / (dd / r + 0.1); - speed *= (level->random->nextFloat() * level->random->nextFloat() + 0.3f); - xd *= speed; - yd *= speed; - zd *= speed; + double speed = 0.5 / (dd / r + 0.1); + speed *= (level->random->nextFloat() * level->random->nextFloat() + 0.3f); + xd *= speed; + yd *= speed; + zd *= speed; - level->addParticle(eParticleType_explode, (xa + x * 1) / 2, (ya + y * 1) / 2, (za + z * 1) / 2, xd, yd, zd); - level->addParticle(eParticleType_smoke, xa, ya, za, xd, yd, zd); + level->addParticle(eParticleType_explode, (xa + x * 1) / 2, (ya + y * 1) / 2, (za + z * 1) / 2, xd, yd, zd); + level->addParticle(eParticleType_smoke, xa, ya, za, xd, yd, zd); + } } - } - if (t > 0) - { - Tile::tiles[t]->spawnResources(level, xt, yt, zt, level->getData(xt, yt, zt), 0.3f, 0); - level->setTile(xt, yt, zt, 0); - Tile::tiles[t]->wasExploded(level, xt, yt, zt); - } - // } + if (t > 0) + { + Tile *tile = Tile::tiles[t]; - --j; + if (tile->dropFromExplosion(this)) + { + tile->spawnResources(level, xt, yt, zt, level->getData(xt, yt, zt), 1.0f / r, 0); + } + level->setTileAndData(xt, yt, zt, 0, 0, Tile::UPDATE_ALL); + tile->wasExploded(level, xt, yt, zt, this); + } + + --j; + } } if (fire) @@ -241,7 +260,7 @@ void Explosion::finalizeExplosion(bool generateParticles, vector *toBlo int b = level->getTile(xt, yt - 1, zt); if (t == 0 && Tile::solid[b] && random->nextInt(3) == 0) { - level->setTile(xt, yt, zt, Tile::fire_Id); + level->setTileAndUpdate(xt, yt, zt, Tile::fire_Id); } } } @@ -262,4 +281,12 @@ Vec3 *Explosion::getHitPlayerKnockback( shared_ptr player ) if(it == hitPlayers.end() ) return Vec3::newTemp(0.0,0.0,0.0); return it->second; +} + +shared_ptr Explosion::getSourceMob() +{ + if (source == NULL) return nullptr; + if (source->instanceof(eTYPE_PRIMEDTNT)) return dynamic_pointer_cast(source)->getOwner(); + if (source->instanceof(eTYPE_LIVINGENTITY)) return dynamic_pointer_cast(source); + return nullptr; } \ No newline at end of file diff --git a/Minecraft.World/Explosion.h b/Minecraft.World/Explosion.h index c06960d2..1fe1e57b 100644 --- a/Minecraft.World/Explosion.h +++ b/Minecraft.World/Explosion.h @@ -39,4 +39,5 @@ public: void finalizeExplosion(bool generateParticles, vector *toBlowDirect = NULL); // 4J - added toBlow parameter playerVec3Map *getHitPlayers(); Vec3 *getHitPlayerKnockback( shared_ptr player ); + shared_ptr getSourceMob(); }; \ No newline at end of file diff --git a/Minecraft.World/ExtremeHillsBiome.cpp b/Minecraft.World/ExtremeHillsBiome.cpp index 7e62c7d3..26d97dd4 100644 --- a/Minecraft.World/ExtremeHillsBiome.cpp +++ b/Minecraft.World/ExtremeHillsBiome.cpp @@ -1,13 +1,20 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.levelgen.feature.h" #include "ExtremeHillsBiome.h" ExtremeHillsBiome::ExtremeHillsBiome(int id) : Biome(id) { + silverfishFeature = new OreFeature(Tile::monsterStoneEgg_Id, 8); friendlies.clear(); } +ExtremeHillsBiome::~ExtremeHillsBiome() +{ + delete silverfishFeature; +} + void ExtremeHillsBiome::decorate(Level *level, Random *random, int xo, int zo) { Biome::decorate(level, random, xo, zo); @@ -20,11 +27,18 @@ void ExtremeHillsBiome::decorate(Level *level, Random *random, int xo, int zo) { int y = random->nextInt((Level::genDepth / 4) - 4) + 4; int z = zo + random->nextInt(16); int tile = level->getTile(x, y, z); - if (tile == Tile::rock_Id) + if (tile == Tile::stone_Id) { - level->setTileNoUpdate(x, y, z, Tile::emeraldOre_Id); + level->setTileAndData(x, y, z, Tile::emeraldOre_Id, 0, Tile::UPDATE_CLIENTS); } } } + for (int i = 0; i < 7; i++) + { + int x = xo + random->nextInt(16); + int y = random->nextInt(Level::genDepth / 2); + int z = zo + random->nextInt(16); + silverfishFeature->place(level, random, x, y, z); + } } diff --git a/Minecraft.World/ExtremeHillsBiome.h b/Minecraft.World/ExtremeHillsBiome.h index faafa66e..cf9edabc 100644 --- a/Minecraft.World/ExtremeHillsBiome.h +++ b/Minecraft.World/ExtremeHillsBiome.h @@ -7,9 +7,11 @@ class ExtremeHillsBiome : public Biome friend class Biome; private: static const bool GENERATE_EMERALD_ORE = true; + Feature *silverfishFeature; protected: ExtremeHillsBiome(int id); + ~ExtremeHillsBiome(); public: void decorate(Level *level, Random *random, int xo, int zo); diff --git a/Minecraft.World/EyeOfEnderSignal.cpp b/Minecraft.World/EyeOfEnderSignal.cpp index 39d9f82e..95747a89 100644 --- a/Minecraft.World/EyeOfEnderSignal.cpp +++ b/Minecraft.World/EyeOfEnderSignal.cpp @@ -8,8 +8,6 @@ #include "JavaMath.h" #include "EyeOfEnderSignal.h" - - void EyeOfEnderSignal::_init() { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that @@ -23,7 +21,6 @@ void EyeOfEnderSignal::_init() surviveAfterDeath = false; } - EyeOfEnderSignal::EyeOfEnderSignal(Level *level) : Entity(level) { _init(); @@ -34,7 +31,6 @@ void EyeOfEnderSignal::defineSynchedData() { } - bool EyeOfEnderSignal::shouldRenderAtSqrDistance(double distance) { double size = bb->getSize() * 4; @@ -49,8 +45,8 @@ EyeOfEnderSignal::EyeOfEnderSignal(Level *level, double x, double y, double z) : setSize(0.25f, 0.25f); - this->setPos(x, y, z); - this->heightOffset = 0; + setPos(x, y, z); + heightOffset = 0; } void EyeOfEnderSignal::signalTo(double tx, int ty, double tz) @@ -85,8 +81,8 @@ void EyeOfEnderSignal::lerpMotion(double xd, double yd, double zd) if (xRotO == 0 && yRotO == 0) { float sd = (float) sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (atan2(xd, zd) * 180 / PI); - xRotO = this->xRot = (float) (atan2(yd, (double)sd) * 180 / PI); + yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI); + xRotO = xRot = (float) (atan2(yd, (double)sd) * 180 / PI); } } diff --git a/Minecraft.World/Facing.cpp b/Minecraft.World/Facing.cpp index 9df4187d..33742e92 100644 --- a/Minecraft.World/Facing.cpp +++ b/Minecraft.World/Facing.cpp @@ -20,3 +20,5 @@ const int Facing::STEP_Z[6] = { 0, 0, -1, 1, 0, 0 }; + +const wstring Facing::NAMES[] = {L"DOWN", L"UP", L"NORTH", L"SOUTH", L"WEST", L"EAST"}; \ No newline at end of file diff --git a/Minecraft.World/Facing.h b/Minecraft.World/Facing.h index 1c4cfdf3..b257e4bf 100644 --- a/Minecraft.World/Facing.h +++ b/Minecraft.World/Facing.h @@ -3,15 +3,17 @@ class Facing { public: - static const int DOWN = 0; - static const int UP = 1; - static const int NORTH = 2; - static const int SOUTH = 3; - static const int WEST = 4; - static const int EAST = 5; + static const int DOWN = 0; + static const int UP = 1; + static const int NORTH = 2; + static const int SOUTH = 3; + static const int WEST = 4; + static const int EAST = 5; static const int OPPOSITE_FACING[6]; static const int STEP_X[6]; static const int STEP_Y[6]; static const int STEP_Z[6]; + + static const wstring NAMES[]; }; \ No newline at end of file diff --git a/Minecraft.World/FacingEnum.cpp b/Minecraft.World/FacingEnum.cpp new file mode 100644 index 00000000..cfcb61e0 --- /dev/null +++ b/Minecraft.World/FacingEnum.cpp @@ -0,0 +1,47 @@ +#include "stdafx.h" + +#include "FacingEnum.h" + +FacingEnum *FacingEnum::DOWN = new FacingEnum(0, 1, 0, -1, 0); +FacingEnum *FacingEnum::UP = new FacingEnum(1, 0, 0, 1, 0); +FacingEnum *FacingEnum::NORTH = new FacingEnum(2, 3, 0, 0, -1); +FacingEnum *FacingEnum::SOUTH = new FacingEnum(3, 2, 0, 0, 1); +FacingEnum *FacingEnum::EAST = new FacingEnum(4, 5, -1, 0, 0); +FacingEnum *FacingEnum::WEST = new FacingEnum(5, 4, 1, 0, 0); + +FacingEnum *FacingEnum::BY_DATA[6] = {FacingEnum::DOWN,FacingEnum::UP,FacingEnum::NORTH,FacingEnum::SOUTH,FacingEnum::EAST,FacingEnum::WEST}; + +FacingEnum::FacingEnum(int dataValue, int oppositeIndex, int stepX, int stepY, int stepZ) + : dataValue(dataValue), oppositeIndex(oppositeIndex), stepX(stepX), stepY(stepY), stepZ(stepZ) +{ +} + +int FacingEnum::getDataValue() +{ + return dataValue; +} + +FacingEnum *FacingEnum::getOpposite() +{ + return BY_DATA[oppositeIndex]; +} + +int FacingEnum::getStepX() +{ + return stepX; +} + +int FacingEnum::getStepY() +{ + return stepY; +} + +int FacingEnum::getStepZ() +{ + return stepZ; +} + +FacingEnum *FacingEnum::fromData(int data) +{ + return BY_DATA[data % 6]; +} \ No newline at end of file diff --git a/Minecraft.World/FacingEnum.h b/Minecraft.World/FacingEnum.h new file mode 100644 index 00000000..5857956f --- /dev/null +++ b/Minecraft.World/FacingEnum.h @@ -0,0 +1,31 @@ +#pragma once + +class FacingEnum +{ +public: + static FacingEnum *DOWN; + static FacingEnum *UP; + static FacingEnum *NORTH; + static FacingEnum *SOUTH; + static FacingEnum *EAST; + static FacingEnum *WEST; + +private: + const int dataValue; + const int oppositeIndex; + const int stepX; + const int stepY; + const int stepZ; + + static FacingEnum *BY_DATA[6]; + + FacingEnum(int dataValue, int oppositeIndex, int stepX, int stepY, int stepZ); + +public: + int getDataValue(); + FacingEnum *getOpposite(); + int getStepX(); + int getStepY(); + int getStepZ(); + static FacingEnum *fromData(int data); +}; \ No newline at end of file diff --git a/Minecraft.World/FallingTile.cpp b/Minecraft.World/FallingTile.cpp index 254631ff..28248014 100644 --- a/Minecraft.World/FallingTile.cpp +++ b/Minecraft.World/FallingTile.cpp @@ -24,6 +24,7 @@ void FallingTile::_init() hurtEntities = false; fallDamageMax = 40; fallDamageAmount = 2; + tileData = NULL; // 4J Added so that client-side falling tiles can fall through blocks // This fixes a bug on the host where the tile update from the server comes in before the client-side falling tile @@ -62,6 +63,11 @@ FallingTile::FallingTile(Level *level, double x, double y, double z, int tile, i zOld = z; } +FallingTile::~FallingTile() +{ + delete tileData; +} + bool FallingTile::makeStepSound() { return false; @@ -105,7 +111,7 @@ void FallingTile::tick() { if (level->getTile(xt, yt, zt) == tile) { - level->setTile(xt, yt, zt, 0); + level->removeTile(xt, yt, zt); } else { @@ -120,17 +126,36 @@ void FallingTile::tick() zd *= 0.7f; yd *= -0.5f; - // if (HeavyTile.isFree(level, xt, yt, zt)) { if (level->getTile(xt, yt, zt) != Tile::pistonMovingPiece_Id) { remove(); - if (!cancelDrop && level->mayPlace(tile, xt, yt, zt, true, 1, nullptr) && !HeavyTile::isFree(level, xt, yt - 1, zt) && level->setTileAndData(xt, yt, zt, tile, data)) + if (!cancelDrop && level->mayPlace(tile, xt, yt, zt, true, 1, nullptr, nullptr) && !HeavyTile::isFree(level, xt, yt - 1, zt) && level->setTileAndData(xt, yt, zt, tile, data, Tile::UPDATE_ALL)) { HeavyTile *hv = dynamic_cast(Tile::tiles[tile]); if (hv) { hv->onLand(level, xt, yt, zt, data); } + if (tileData != NULL && Tile::tiles[tile]->isEntityTile()) + { + shared_ptr tileEntity = level->getTileEntity(xt, yt, zt); + + if (tileEntity != NULL) + { + CompoundTag *swap = new CompoundTag(); + tileEntity->save(swap); + vector *allTags = tileData->getAllTags(); + for(AUTO_VAR(it, allTags->begin()); it != allTags->end(); ++it) + { + Tag *tag = *it; + if (tag->getName().compare(L"x") == 0 || tag->getName().compare(L"y") == 0 || tag->getName().compare(L"z") == 0) continue; + swap->put(tag->getName(), tag->copy()); + } + delete allTags; + tileEntity->load(swap); + tileEntity->setChanged(); + } + } } else { @@ -140,7 +165,7 @@ void FallingTile::tick() } else if ( (time > 20 * 5 && !level->isClientSide && (yt < 1 || yt > Level::maxBuildHeight)) || (time > 20 * 30)) { - if(dropItem) spawnAtLocation(tile, 1); + if(dropItem) spawnAtLocation( shared_ptr( new ItemInstance(tile, 1, Tile::tiles[tile]->getSpawnResourcesAuxValue(data) )), 0); remove(); } } @@ -153,14 +178,16 @@ void FallingTile::causeFallDamage(float distance) int dmg = Mth::ceil(distance - 1); if (dmg > 0) { - vector > *entities = level->getEntities(shared_from_this(), bb); + // 4J: Copy vector since it might be modified when we hurt the entities (invalidating our iterator) + vector > *entities = new vector >(*level->getEntities(shared_from_this(), bb)); DamageSource *source = tile == Tile::anvil_Id ? DamageSource::anvil : DamageSource::fallingBlock; - //for (Entity entity : entities) - for(AUTO_VAR(it,entities->begin()); it != entities->end(); ++it) + for(AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) { (*it)->hurt(source, min(Mth::floor(dmg * fallDamageAmount), fallDamageMax)); } + delete entities; + if (tile == Tile::anvil_Id && random->nextFloat() < 0.05f + (dmg * 0.05)) { int damage = data >> 2; @@ -182,17 +209,26 @@ void FallingTile::causeFallDamage(float distance) void FallingTile::addAdditonalSaveData(CompoundTag *tag) { tag->putByte(L"Tile", (byte) tile); + tag->putInt(L"TileID", tile); tag->putByte(L"Data", (byte) data); tag->putByte(L"Time", (byte) time); tag->putBoolean(L"DropItem", dropItem); tag->putBoolean(L"HurtEntities", hurtEntities); tag->putFloat(L"FallHurtAmount", fallDamageAmount); tag->putInt(L"FallHurtMax", fallDamageMax); + if (tileData != NULL) tag->putCompound(L"TileEntityData", tileData); } void FallingTile::readAdditionalSaveData(CompoundTag *tag) { - tile = tag->getByte(L"Tile") & 0xff; + if (tag->contains(L"TileID")) + { + tile = tag->getInt(L"TileID"); + } + else + { + tile = tag->getByte(L"Tile") & 0xff; + } data = tag->getByte(L"Data") & 0xff; time = tag->getByte(L"Time") & 0xff; @@ -212,6 +248,11 @@ void FallingTile::readAdditionalSaveData(CompoundTag *tag) dropItem = tag->getBoolean(L"DropItem"); } + if (tag->contains(L"TileEntityData")) + { + tileData = tag->getCompound(L"TileEntityData"); + } + if (tile == 0) { tile = Tile::sand_Id; diff --git a/Minecraft.World/FallingTile.h b/Minecraft.World/FallingTile.h index eefc9e3b..7ca97416 100644 --- a/Minecraft.World/FallingTile.h +++ b/Minecraft.World/FallingTile.h @@ -25,8 +25,12 @@ private: void _init(); public: + CompoundTag *tileData; + + FallingTile(Level *level); FallingTile(Level *level, double x, double y, double z, int tile, int data = 0); + ~FallingTile(); protected: virtual bool makeStepSound(); diff --git a/Minecraft.World/FarmTile.cpp b/Minecraft.World/FarmTile.cpp index ecfaf44b..6cbe40ac 100644 --- a/Minecraft.World/FarmTile.cpp +++ b/Minecraft.World/FarmTile.cpp @@ -8,18 +8,18 @@ FarmTile::FarmTile(int id) : Tile(id, Material::dirt,isSolidRender()) { - iconWet = NULL; + iconWet = NULL; iconDry = NULL; - setTicking(true); - updateDefaultShape(); - setLightBlock(255); + setTicking(true); + updateDefaultShape(); + setLightBlock(255); } // 4J Added override void FarmTile::updateDefaultShape() { - setShape(0, 0, 0, 1, 15 / 16.0f, 1); + setShape(0, 0, 0, 1, 15 / 16.0f, 1); } AABB *FarmTile::getAABB(Level *level, int x, int y, int z) @@ -39,7 +39,7 @@ bool FarmTile::isCubeShaped() Icon *FarmTile::getTexture(int face, int data) { - if (face == Facing::UP) + if (face == Facing::UP) { if(data > 0) { @@ -50,28 +50,30 @@ Icon *FarmTile::getTexture(int face, int data) return iconDry; } } - return Tile::dirt->getTexture(face); + return Tile::dirt->getTexture(face); } void FarmTile::tick(Level *level, int x, int y, int z, Random *random) { - if (isNearWater(level, x, y, z) || level->isRainingAt(x, y + 1, z)) + if (isNearWater(level, x, y, z) || level->isRainingAt(x, y + 1, z)) { - level->setData(x, y, z, 7); - } else + level->setData(x, y, z, 7, Tile::UPDATE_CLIENTS); + } + else { - int moisture = level->getData(x, y, z); - if (moisture > 0) + int moisture = level->getData(x, y, z); + if (moisture > 0) { - level->setData(x, y, z, moisture - 1); - } else + level->setData(x, y, z, moisture - 1, Tile::UPDATE_CLIENTS); + } + else { - if (!isUnderCrops(level, x, y, z)) + if (!isUnderCrops(level, x, y, z)) { - level->setTile(x, y, z, Tile::dirt_Id); - } - } - } + level->setTileAndUpdate(x, y, z, Tile::dirt_Id); + } + } + } } void FarmTile::fallOn(Level *level, int x, int y, int z, shared_ptr entity, float fallDistance) @@ -80,49 +82,59 @@ void FarmTile::fallOn(Level *level, int x, int y, int z, shared_ptr enti // We should not be setting tiles on the client based on random values! if (!level->isClientSide && level->random->nextFloat() < (fallDistance - .5f)) { - // Fix for #60547 - TU7: Content: Gameplay: Players joining a game can destroy crops even with Trust Players option disabled. - shared_ptr player = dynamic_pointer_cast(entity); - if(player == NULL || player->isAllowedToMine()) level->setTile(x, y, z, Tile::dirt_Id); - } + if(entity->instanceof(eTYPE_PLAYER)) + { + shared_ptr player = dynamic_pointer_cast(entity); + if(!player->isAllowedToMine()) + { + return; + } + } + else if (!level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) + { + return; + } + level->setTileAndUpdate(x, y, z, Tile::dirt_Id); + } } bool FarmTile::isUnderCrops(Level *level, int x, int y, int z) { - int r = 0; - for (int xx = x - r; xx <= x + r; xx++) - for (int zz = z - r; zz <= z + r; zz++) + int r = 0; + for (int xx = x - r; xx <= x + r; xx++) + for (int zz = z - r; zz <= z + r; zz++) { - int tile = level->getTile(xx, y + 1, zz); - if (tile == Tile::crops_Id || tile == Tile::melonStem_Id || tile == Tile::pumpkinStem_Id || tile == Tile::potatoes_Id || tile == Tile::carrots_Id) + int tile = level->getTile(xx, y + 1, zz); + if (tile == Tile::wheat_Id || tile == Tile::melonStem_Id || tile == Tile::pumpkinStem_Id || tile == Tile::potatoes_Id || tile == Tile::carrots_Id) { - return true; - } - } - return false; + return true; + } + } + return false; } bool FarmTile::isNearWater(Level *level, int x, int y, int z) { - for (int xx = x - 4; xx <= x + 4; xx++) - for (int yy = y; yy <= y + 1; yy++) - for (int zz = z - 4; zz <= z + 4; zz++) + for (int xx = x - 4; xx <= x + 4; xx++) + for (int yy = y; yy <= y + 1; yy++) + for (int zz = z - 4; zz <= z + 4; zz++) { - if (level->getMaterial(xx, yy, zz) == Material::water) + if (level->getMaterial(xx, yy, zz) == Material::water) { - return true; - } - } - return false; + return true; + } + } + return false; } void FarmTile::neighborChanged(Level *level, int x, int y, int z, int type) { - Tile::neighborChanged(level, x, y, z, type); - Material *above = level->getMaterial(x, y + 1, z); - if (above->isSolid()) + Tile::neighborChanged(level, x, y, z, type); + Material *above = level->getMaterial(x, y + 1, z); + if (above->isSolid()) { - level->setTile(x, y, z, Tile::dirt_Id); - } + level->setTileAndUpdate(x, y, z, Tile::dirt_Id); + } } bool FarmTile::blocksLight() diff --git a/Minecraft.World/Feature.cpp b/Minecraft.World/Feature.cpp index 301bd26c..b4d9a6ee 100644 --- a/Minecraft.World/Feature.cpp +++ b/Minecraft.World/Feature.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" #include "Feature.h" @@ -13,6 +14,10 @@ Feature::Feature(bool doUpdate) this->doUpdate = doUpdate; } +void Feature::applyFeature(Level *level, Random *random, int xChunk, int zChunk) +{ +} + void Feature::placeBlock(Level *level, int x, int y, int z, int tile) { placeBlock(level, x, y, z, tile, 0); @@ -22,10 +27,10 @@ void Feature::placeBlock(Level *level, int x, int y, int z, int tile, int data) { if (doUpdate) { - level->setTileAndData(x, y, z, tile, data); + level->setTileAndData(x, y, z, tile, data, Tile::UPDATE_ALL); } else { - level->setTileAndDataNoUpdate(x, y, z, tile, data); + level->setTileAndData(x, y, z, tile, data, Tile::UPDATE_CLIENTS); } -} +} \ No newline at end of file diff --git a/Minecraft.World/Feature.h b/Minecraft.World/Feature.h index 9b89c0a6..84ea5abd 100644 --- a/Minecraft.World/Feature.h +++ b/Minecraft.World/Feature.h @@ -14,6 +14,8 @@ public: virtual bool place(Level *level, Random *random, int x, int y, int z) = 0; virtual bool placeWithIndex(Level *level, Random *random, int x, int y, int z,int iIndex, int iRadius) { return false;} virtual void init(double V1, double V2, double V3) {}; + virtual void applyFeature(Level *level, Random *random, int xChunk, int zChunk); + protected: virtual void placeBlock(Level *level, int x, int y, int z, int tile); virtual void placeBlock(Level *level, int x, int y, int z, int tile, int data); diff --git a/Minecraft.World/FenceGateTile.cpp b/Minecraft.World/FenceGateTile.cpp index 6b0243ed..a8de450e 100644 --- a/Minecraft.World/FenceGateTile.cpp +++ b/Minecraft.World/FenceGateTile.cpp @@ -16,17 +16,17 @@ Icon *FenceGateTile::getTexture(int face, int data) bool FenceGateTile::mayPlace(Level *level, int x, int y, int z) { - if (!level->getMaterial(x, y - 1, z)->isSolid()) return false; - return Tile::mayPlace(level, x, y, z); + if (!level->getMaterial(x, y - 1, z)->isSolid()) return false; + return Tile::mayPlace(level, x, y, z); } AABB *FenceGateTile::getAABB(Level *level, int x, int y, int z) { - int data = level->getData(x, y, z); - if (isOpen(data)) + int data = level->getData(x, y, z); + if (isOpen(data)) { - return NULL; - } + return NULL; + } // 4J Brought forward change from 1.2.3 to fix hit box rotation if (data == Direction::NORTH || data == Direction::SOUTH) { @@ -75,38 +75,39 @@ int FenceGateTile::getRenderShape() return Tile::SHAPE_FENCE_GATE; } -void FenceGateTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void FenceGateTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { - int dir = (((Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3)) % 4; - level->setData(x, y, z, dir); + int dir = (((Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3)) % 4; + level->setData(x, y, z, dir, Tile::UPDATE_CLIENTS); } bool FenceGateTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param { - if( soundOnly ) + if (soundOnly) { // 4J - added - just do enough to play the sound level->levelEvent(player, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); // 4J - changed event to pass player rather than NULL as the source of the event so we can filter the broadcast properly return false; } - int data = level->getData(x, y, z); - if (isOpen(data)) + int data = level->getData(x, y, z); + if (isOpen(data)) { - level->setData(x, y, z, data & ~OPEN_BIT); - } + level->setData(x, y, z, data & ~OPEN_BIT, Tile::UPDATE_CLIENTS); + } else { - // open the door from the player - int dir = (((Mth::floor(player->yRot * 4 / (360) + 0.5)) & 3)) % 4; - int current = getDirection(data); - if (current == ((dir + 2) % 4)) { - data = dir; - } - level->setData(x, y, z, data | OPEN_BIT); - } - level->levelEvent(player, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); - return true; + // open the door from the player + int dir = (((Mth::floor(player->yRot * 4 / (360) + 0.5)) & 3)) % 4; + int current = getDirection(data); + if (current == ((dir + 2) % 4)) + { + data = dir; + } + level->setData(x, y, z, data | OPEN_BIT, Tile::UPDATE_CLIENTS); + } + level->levelEvent(player, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); + return true; } void FenceGateTile::neighborChanged(Level *level, int x, int y, int z, int type) @@ -120,12 +121,12 @@ void FenceGateTile::neighborChanged(Level *level, int x, int y, int z, int type) { if (signal && !isOpen(data)) { - level->setData(x, y, z, data | OPEN_BIT); + level->setData(x, y, z, data | OPEN_BIT, Tile::UPDATE_CLIENTS); level->levelEvent(nullptr, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); } else if (!signal && isOpen(data)) { - level->setData(x, y, z, data & ~OPEN_BIT); + level->setData(x, y, z, data & ~OPEN_BIT, Tile::UPDATE_CLIENTS); level->levelEvent(nullptr, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); } } diff --git a/Minecraft.World/FenceGateTile.h b/Minecraft.World/FenceGateTile.h index 277fcd4d..125a776d 100644 --- a/Minecraft.World/FenceGateTile.h +++ b/Minecraft.World/FenceGateTile.h @@ -4,23 +4,23 @@ class FenceGateTile : public DirectionalTile { private: - static const int OPEN_BIT = 4; + static const int OPEN_BIT = 4; public: FenceGateTile(int id); - Icon *getTexture(int face, int data); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual AABB *getAABB(Level *level, int x, int y, int z); + Icon *getTexture(int face, int data); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual AABB *getAABB(Level *level, int x, int y, int z); virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param // Brought forward from 1.2.3 - virtual bool blocksLight(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); + virtual bool blocksLight(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); virtual bool isPathfindable(LevelSource *level, int x, int y, int z); virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); - virtual int getRenderShape(); - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual int getRenderShape(); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param virtual void neighborChanged(Level *level, int x, int y, int z, int type); - static bool isOpen(int data); + static bool isOpen(int data); void registerIcons(IconRegister *iconRegister); }; diff --git a/Minecraft.World/FenceTile.cpp b/Minecraft.World/FenceTile.cpp index 0d1f9bc4..39f4aac1 100644 --- a/Minecraft.World/FenceTile.cpp +++ b/Minecraft.World/FenceTile.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" +#include "net.minecraft.world.item.h" #include "net.minecraft.world.level.h" -#include "net.minecraft.world.phys.h" #include "net.minecraft.world.h" #include "FenceTile.h" @@ -9,73 +9,89 @@ FenceTile::FenceTile(int id, const wstring &texture, Material *material) : Tile( this->texture = texture; } -AABB *FenceTile::getAABB(Level *level, int x, int y, int z) +void FenceTile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source) { - bool n = connectsTo(level, x, y, z - 1); - bool s = connectsTo(level, x, y, z + 1); - bool w = connectsTo(level, x - 1, y, z); - bool e = connectsTo(level, x + 1, y, z); + bool n = connectsTo(level, x, y, z - 1); + bool s = connectsTo(level, x, y, z + 1); + bool w = connectsTo(level, x - 1, y, z); + bool e = connectsTo(level, x + 1, y, z); - float west = 6.0f / 16.0f; - float east = 10.0f / 16.0f; - float north = 6.0f / 16.0f; - float south = 10.0f / 16.0f; + float west = 6.0f / 16.0f; + float east = 10.0f / 16.0f; + float north = 6.0f / 16.0f; + float south = 10.0f / 16.0f; - if (n) + if (n) { - north = 0; - } - if (s) + north = 0; + } + if (s) { - south = 1; - } - if (w) + south = 1; + } + if (n || s) { - west = 0; - } - if (e) + setShape(west, 0, north, east, 1.5f, south); + Tile::addAABBs(level, x, y, z, box, boxes, source); + } + north = 6.0f / 16.0f; + south = 10.0f / 16.0f; + if (w) { - east = 1; - } + west = 0; + } + if (e) + { + east = 1; + } + if (w || e || (!n && !s)) + { + setShape(west, 0, north, east, 1.5f, south); + Tile::addAABBs(level, x, y, z, box, boxes, source); + } + + if (n) + { + north = 0; + } + if (s) + { + south = 1; + } - return AABB::newTemp(x + west, y, z + north, x + east, y + 1.5f, z + south); + setShape(west, 0, north, east, 1.0f, south); } void FenceTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { - bool n = connectsTo(level, x, y, z - 1); - bool s = connectsTo(level, x, y, z + 1); - bool w = connectsTo(level, x - 1, y, z); - bool e = connectsTo(level, x + 1, y, z); + bool n = connectsTo(level, x, y, z - 1); + bool s = connectsTo(level, x, y, z + 1); + bool w = connectsTo(level, x - 1, y, z); + bool e = connectsTo(level, x + 1, y, z); - float west = 6.0f / 16.0f; - float east = 10.0f / 16.0f; - float north = 6.0f / 16.0f; - float south = 10.0f / 16.0f; + float west = 6.0f / 16.0f; + float east = 10.0f / 16.0f; + float north = 6.0f / 16.0f; + float south = 10.0f / 16.0f; - if (n) + if (n) { - north = 0; - } - if (s) + north = 0; + } + if (s) { - south = 1; - } - if (w) + south = 1; + } + if (w) { - west = 0; - } - if (e) + west = 0; + } + if (e) { - east = 1; - } + east = 1; + } - setShape(west, 0, north, east, 1.0f, south); -} - -bool FenceTile::blocksLight() -{ - return false; + setShape(west, 0, north, east, 1.0f, south); } bool FenceTile::isSolidRender(bool isServerLevel) @@ -100,20 +116,20 @@ int FenceTile::getRenderShape() bool FenceTile::connectsTo(LevelSource *level, int x, int y, int z) { - int tile = level->getTile(x, y, z); - if (tile == id || tile == Tile::fenceGate_Id) + int tile = level->getTile(x, y, z); + if (tile == id || tile == Tile::fenceGate_Id) { - return true; - } - Tile *tileInstance = Tile::tiles[tile]; - if (tileInstance != NULL) + return true; + } + Tile *tileInstance = Tile::tiles[tile]; + if (tileInstance != NULL) { - if (tileInstance->material->isSolidBlocking() && tileInstance->isCubeShaped()) + if (tileInstance->material->isSolidBlocking() && tileInstance->isCubeShaped()) { - return tileInstance->material != Material::vegetable; - } - } - return false; + return tileInstance->material != Material::vegetable; + } + } + return false; } bool FenceTile::isFence(int tile) @@ -129,4 +145,14 @@ void FenceTile::registerIcons(IconRegister *iconRegister) bool FenceTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { return true; +} + +bool FenceTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly) +{ + if (level->isClientSide) return true; + if (LeashItem::bindPlayerMobs(player, level, x, y, z)) + { + return true; + } + return false; } \ No newline at end of file diff --git a/Minecraft.World/FenceTile.h b/Minecraft.World/FenceTile.h index 5b61fca4..ca22163a 100644 --- a/Minecraft.World/FenceTile.h +++ b/Minecraft.World/FenceTile.h @@ -9,15 +9,15 @@ private: public: FenceTile(int id, const wstring &texture, Material *material); - virtual AABB *getAABB(Level *level, int x, int y, int z); + virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param - virtual bool blocksLight(); virtual bool isSolidRender(bool isServerLevel = false); virtual bool isCubeShaped(); virtual bool isPathfindable(LevelSource *level, int x, int y, int z); virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); virtual int getRenderShape(); - bool connectsTo(LevelSource *level, int x, int y, int z); + virtual bool connectsTo(LevelSource *level, int x, int y, int z); static bool isFence(int tile); - void registerIcons(IconRegister *iconRegister); + virtual void registerIcons(IconRegister *iconRegister); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); }; \ No newline at end of file diff --git a/Minecraft.World/File.cpp b/Minecraft.World/File.cpp index 1d66bfeb..21bc3021 100644 --- a/Minecraft.World/File.cpp +++ b/Minecraft.World/File.cpp @@ -37,7 +37,7 @@ File::File( const wstring& pathname ) //: parent( NULL ) m_abstractPathName = pathname; #ifdef _WINDOWS64 - string path = wstringtofilename(m_abstractPathName); + string path = wstringtochararray(m_abstractPathName); string finalPath = StorageManager.GetMountedPath(path.c_str()); if(finalPath.size() == 0) finalPath = path; m_abstractPathName = convStringToWstring(finalPath); diff --git a/Minecraft.World/FileHeader.cpp b/Minecraft.World/FileHeader.cpp index 59e97d9b..35f7b02d 100644 --- a/Minecraft.World/FileHeader.cpp +++ b/Minecraft.World/FileHeader.cpp @@ -217,6 +217,7 @@ void FileHeader::ReadHeader( LPVOID saveMem, ESavePlatform plat /*= SAVE_FILE_PL // : Bumped it to 6 for PS3 v1 to update map data mappings to use larger PlayerUID // : Bumped it to 7 for Durango v1 to update map data mappings to use string based PlayerUID // : Bumped it to 8 for Durango v1 when to save the chunks in a different compressed format + case SAVE_FILE_VERSION_CHUNK_INHABITED_TIME: case SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE: case SAVE_FILE_VERSION_DURANGO_CHANGE_MAP_DATA_MAPPING_SIZE: case SAVE_FILE_VERSION_CHANGE_MAP_DATA_MAPPING_SIZE: diff --git a/Minecraft.World/FileHeader.h b/Minecraft.World/FileHeader.h index 203ec322..4444409f 100644 --- a/Minecraft.World/FileHeader.h +++ b/Minecraft.World/FileHeader.h @@ -36,6 +36,12 @@ enum ESaveVersions // This is the version at which we changed the chunk format to directly save the compressed storage formats SAVE_FILE_VERSION_COMPRESSED_CHUNK_STORAGE, + // This is the version at which we added inhabited time to chunk (1.6.4) + SAVE_FILE_VERSION_CHUNK_INHABITED_TIME, + + + // 4J Stu - If you add a new version here, the save conversion tool will also need updated to be able to read this new format + SAVE_FILE_VERSION_NEXT, }; diff --git a/Minecraft.World/FireChargeItem.cpp b/Minecraft.World/FireChargeItem.cpp index c4e47b0c..7a865ff5 100644 --- a/Minecraft.World/FireChargeItem.cpp +++ b/Minecraft.World/FireChargeItem.cpp @@ -13,7 +13,7 @@ FireChargeItem::FireChargeItem(int id) : Item(id) m_dragonFireballIcon = NULL; } -bool FireChargeItem::useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) +bool FireChargeItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { if (level->isClientSide) { @@ -27,7 +27,7 @@ bool FireChargeItem::useOn(shared_ptr itemInstance, shared_ptrmayBuild(x, y, z)) + if (!player->mayUseItemAt(x, y, z, face, instance)) { return false; } @@ -42,13 +42,13 @@ bool FireChargeItem::useOn(shared_ptr itemInstance, shared_ptrplaySound( x + 0.5, y + 0.5, z + 0.5,eSoundType_FIRE_IGNITE, 1, random->nextFloat() * 0.4f + 0.8f); - level->setTile(x, y, z, Tile::fire_Id); + level->playSound( x + 0.5, y + 0.5, z + 0.5,eSoundType_FIRE_NEWIGNITE, 1, random->nextFloat() * 0.4f + 0.8f); + level->setTileAndUpdate(x, y, z, Tile::fire_Id); } if (!player->abilities.instabuild) { - itemInstance->count--; + instance->count--; } return true; } diff --git a/Minecraft.World/FireTile.cpp b/Minecraft.World/FireTile.cpp index 60f062db..dfb4b961 100644 --- a/Minecraft.World/FireTile.cpp +++ b/Minecraft.World/FireTile.cpp @@ -50,8 +50,10 @@ void FireTile::init() setFlammable(Tile::bookshelf_Id, FLAME_EASY, BURN_MEDIUM); setFlammable(Tile::tnt_Id, FLAME_MEDIUM, BURN_INSTANT); setFlammable(Tile::tallgrass_Id, FLAME_INSTANT, BURN_INSTANT); - setFlammable(Tile::cloth_Id, FLAME_EASY, BURN_EASY); + setFlammable(Tile::wool_Id, FLAME_EASY, BURN_EASY); setFlammable(Tile::vine_Id, FLAME_MEDIUM, BURN_INSTANT); + setFlammable(Tile::coalBlock_Id, FLAME_HARD, BURN_HARD); + setFlammable(Tile::hayBlock_Id, FLAME_INSTANT, BURN_MEDIUM); } void FireTile::setFlammable(int id, int flame, int burn) @@ -90,13 +92,18 @@ int FireTile::getResourceCount(Random *random) return 0; } -int FireTile::getTickDelay() +int FireTile::getTickDelay(Level *level) { return 30; } void FireTile::tick(Level *level, int x, int y, int z, Random *random) { + if (!level->getGameRules()->getBoolean(GameRules::RULE_DOFIRETICK)) + { + return; + } + // 4J added - we don't want fire to do anything that might create new fire, or destroy this fire, if we aren't actually tracking (for network) the chunk this is in in the player // chunk map. If we did change something in that case, then the change wouldn't get sent to any player that had already received that full chunk, and so we'd just become desynchronised. // Seems safest just to do an addToTickNextTick here instead with a decent delay, to make sure that we will get ticked again in the future, when we might again be in a chunk @@ -105,13 +112,13 @@ void FireTile::tick(Level *level, int x, int y, int z, Random *random) { if( !MinecraftServer::getInstance()->getPlayers()->isTrackingTile(x, y, z, level->dimension->id) ) { - level->addToTickNextTick(x, y, z, id, getTickDelay() * 5); + level->addToTickNextTick(x, y, z, id, getTickDelay(level) * 5); return; } } - bool infiniBurn = level->getTile(x, y - 1, z) == Tile::hellRock_Id; + bool infiniBurn = level->getTile(x, y - 1, z) == Tile::netherRack_Id; if (level->dimension->id == 1) // 4J - was == instanceof TheEndDimension { if (level->getTile(x, y - 1, z) == Tile::unbreakable_Id) infiniBurn = true; @@ -119,14 +126,14 @@ void FireTile::tick(Level *level, int x, int y, int z, Random *random) if (!mayPlace(level, x, y, z)) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); } if (!infiniBurn && level->isRaining()) { if (level->isRainingAt(x, y, z) || level->isRainingAt(x - 1, y, z) || level->isRainingAt(x + 1, y, z) || level->isRainingAt(x, y, z - 1) || level->isRainingAt(x, y, z + 1)) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); return; } } @@ -134,13 +141,13 @@ void FireTile::tick(Level *level, int x, int y, int z, Random *random) int age = level->getData(x, y, z); if (age < 15) { - level->setDataNoUpdate(x, y, z, age + random->nextInt(3) / 2); + level->setData(x, y, z, age + random->nextInt(3) / 2, Tile::UPDATE_NONE); } - level->addToTickNextTick(x, y, z, id, getTickDelay() + random->nextInt(10)); + level->addToTickNextTick(x, y, z, id, getTickDelay(level) + random->nextInt(10)); if (!infiniBurn && !isValidFireLocation(level, x, y, z)) { - if (!level->isTopSolidBlocking(x, y - 1, z) || age > 3) level->setTile(x, y, z, 0); + if (!level->isTopSolidBlocking(x, y - 1, z) || age > 3) level->removeTile(x, y, z); return; } @@ -148,7 +155,7 @@ void FireTile::tick(Level *level, int x, int y, int z, Random *random) { if (age == 15 && random->nextInt(4) == 0) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); return; } } @@ -183,23 +190,18 @@ void FireTile::tick(Level *level, int x, int y, int z, Random *random) int fodds = getFireOdds(level, xx, yy, zz); if (fodds > 0) { - int odds = (fodds + 40) / (age + 30); + int odds = (fodds + 40 + (level->difficulty * 7)) / (age + 30); if (isHumid) { odds /= 2; } if (odds > 0 && random->nextInt(rate) <= odds) { - if ((level->isRaining() && level->isRainingAt(xx, yy, zz)) || level->isRainingAt(xx - 1, yy, z) || level->isRainingAt(xx + 1, yy, zz) || level->isRainingAt(xx, yy, zz - 1) - || level->isRainingAt(xx, yy, zz + 1)) + if (!(level->isRaining() && level->isRainingAt(xx, yy, zz) || level->isRainingAt(xx - 1, yy, z) || level->isRainingAt(xx + 1, yy, zz) || level->isRainingAt(xx, yy, zz - 1) || level->isRainingAt(xx, yy, zz + 1))) { - // DO NOTHING, rain! - - } else { int tAge = age + random->nextInt(5) / 4; if (tAge > 15) tAge = 15; - level->setTileAndData(xx, yy, zz, this->id, tAge); - + level->setTileAndData(xx, yy, zz, id, tAge, Tile::UPDATE_ALL); } } } @@ -209,6 +211,11 @@ void FireTile::tick(Level *level, int x, int y, int z, Random *random) } } +bool FireTile::canInstantlyTick() +{ + return false; +} + void FireTile::checkBurnOut(Level *level, int x, int y, int z, int chance, Random *random, int age) { int odds = burnOdds[level->getTile(x, y, z)]; @@ -219,10 +226,10 @@ void FireTile::checkBurnOut(Level *level, int x, int y, int z, int chance, Rando { int tAge = age + random->nextInt(5) / 4; if (tAge > 15) tAge = 15; - level->setTileAndData(x, y, z, this->id, tAge); + level->setTileAndData(x, y, z, id, tAge, Tile::UPDATE_ALL); } else { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); } if (wasTnt) { @@ -284,7 +291,7 @@ void FireTile::neighborChanged(Level *level, int x, int y, int z, int type) { if (!level->isTopSolidBlocking(x, y - 1, z) && !isValidFireLocation(level, x, y, z)) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); return; } } @@ -300,10 +307,10 @@ void FireTile::onPlace(Level *level, int x, int y, int z) } if (!level->isTopSolidBlocking(x, y - 1, z) && !isValidFireLocation(level, x, y, z)) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); return; } - level->addToTickNextTick(x, y, z, id, getTickDelay() + level->random->nextInt(10)); + level->addToTickNextTick(x, y, z, id, getTickDelay(level) + level->random->nextInt(10)); } bool FireTile::isFlammable(int tile) @@ -315,7 +322,7 @@ void FireTile::animateTick(Level *level, int x, int y, int z, Random *random) { if (random->nextInt(24) == 0) { - level->playLocalSound(x + 0.5f, y + 0.5f, z + 0.5f,eSoundType_FIRE_FIRE, 1 + random->nextFloat(), random->nextFloat() * 0.7f + 0.3f); + level->playLocalSound(x + 0.5f, y + 0.5f, z + 0.5f,eSoundType_FIRE_FIRE, 1 + random->nextFloat(), random->nextFloat() * 0.7f + 0.3f, false); } if (level->isTopSolidBlocking(x, y - 1, z) || Tile::fire->canBurn(level, x, y - 1, z)) diff --git a/Minecraft.World/FireTile.h b/Minecraft.World/FireTile.h index af079a6a..1d823752 100644 --- a/Minecraft.World/FireTile.h +++ b/Minecraft.World/FireTile.h @@ -13,19 +13,19 @@ public: static const wstring TEXTURE_SECOND; static const int FLAME_INSTANT = 60; - static const int FLAME_EASY = 30; - static const int FLAME_MEDIUM = 15; - static const int FLAME_HARD = 5; - - static const int BURN_INSTANT = 100; - static const int BURN_EASY = 60; - static const int BURN_MEDIUM = 20; - static const int BURN_HARD = 5; - static const int BURN_NEVER = 0; + static const int FLAME_EASY = 30; + static const int FLAME_MEDIUM = 15; + static const int FLAME_HARD = 5; + + static const int BURN_INSTANT = 100; + static const int BURN_EASY = 60; + static const int BURN_MEDIUM = 20; + static const int BURN_HARD = 5; + static const int BURN_NEVER = 0; private: - int *flameOdds; - int *burnOdds; + int *flameOdds; + int *burnOdds; Icon **icons; protected: FireTile(int id); @@ -36,17 +36,19 @@ private: void setFlammable(int id, int flame, int burn); public: virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual bool blocksLight(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); - virtual int getRenderShape(); - virtual int getResourceCount(Random *random); - virtual int getTickDelay(); - virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual bool blocksLight(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); + virtual int getRenderShape(); + virtual int getResourceCount(Random *random); + virtual int getTickDelay(Level *level); + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual bool canInstantlyTick(); + private: void checkBurnOut(Level *level, int x, int y, int z, int chance, Random *random, int age); - bool isValidFireLocation(Level *level, int x, int y, int z); - int getFireOdds(Level *level, int x, int y, int z); + bool isValidFireLocation(Level *level, int x, int y, int z); + int getFireOdds(Level *level, int x, int y, int z); public: virtual bool mayPick(); bool canBurn(LevelSource *level, int x, int y, int z); diff --git a/Minecraft.World/Fireball.cpp b/Minecraft.World/Fireball.cpp index 46be68f7..1d9fbdda 100644 --- a/Minecraft.World/Fireball.cpp +++ b/Minecraft.World/Fireball.cpp @@ -63,8 +63,8 @@ Fireball::Fireball(Level *level, double x, double y, double z, double xa, double setSize(16 / 16.0f, 16 / 16.0f); - this->moveTo(x, y, z, yRot, xRot); - this->setPos(x, y, z); + moveTo(x, y, z, yRot, xRot); + setPos(x, y, z); double dd = sqrt(xa * xa + ya * ya + za * za); @@ -84,7 +84,7 @@ Fireball::Fireball(Level *level, double x, double y, double z, double xa, double } } -Fireball::Fireball(Level *level, shared_ptr mob, double xa, double ya, double za) : Entity ( level ) +Fireball::Fireball(Level *level, shared_ptr mob, double xa, double ya, double za) : Entity ( level ) { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called @@ -92,13 +92,13 @@ Fireball::Fireball(Level *level, shared_ptr mob, double xa, double ya, doub _init(); - this->owner = mob; + owner = mob; setSize(16 / 16.0f, 16 / 16.0f); - this->moveTo(mob->x, mob->y, mob->z, mob->yRot, mob->xRot); - this->setPos(x, y, z); - this->heightOffset = 0; + moveTo(mob->x, mob->y, mob->z, mob->yRot, mob->xRot); + setPos(x, y, z); + heightOffset = 0; xd = yd = zd = 0.0; @@ -198,7 +198,7 @@ void Fireball::tick() to = Vec3::newTemp(res->pos->x, res->pos->y, res->pos->z); } shared_ptr hitEntity = nullptr; - vector > *objects = level->getEntities(shared_from_this(), this->bb->expand(xd, yd, zd)->grow(1, 1, 1)); + vector > *objects = level->getEntities(shared_from_this(), bb->expand(xd, yd, zd)->grow(1, 1, 1)); double nearest = 0; AUTO_VAR(itEnd, objects->end()); for (AUTO_VAR(it, objects->begin()); it != itEnd; it++) @@ -239,8 +239,8 @@ void Fireball::tick() z += zd; double sd = sqrt(xd * xd + zd * zd); - yRot = (float) (atan2(xd, zd) * 180 / PI); - xRot = (float) (atan2(yd, sd) * 180 / PI); + yRot = (float) (atan2(zd, xd) * 180 / PI) + 90; + xRot = (float) (atan2(sd, yd) * 180 / PI) - 90; while (xRot - xRotO < -180) xRotO -= 360; @@ -256,7 +256,7 @@ void Fireball::tick() yRot = yRotO + (yRot - yRotO) * 0.2f; - float inertia = 0.95f; + float inertia = getInertia(); if (isInWater()) { for (int i = 0; i < 4; i++) @@ -292,37 +292,19 @@ void Fireball::tick() setPos(x, y, z); } -void Fireball::onHit(HitResult *res) +float Fireball::getInertia() { - if (!level->isClientSide) - { - if (res->entity != NULL) - { - DamageSource *damageSource = DamageSource::fireball(dynamic_pointer_cast( shared_from_this() ), owner); - if (res->entity->hurt(damageSource, 6)) - { - } - else - { - } - delete damageSource; - } - - bool destroyBlocks = true;//level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); - level->explode(nullptr, x, y, z, 1, true, destroyBlocks); - - remove(); - } + return 0.95f; } void Fireball::addAdditonalSaveData(CompoundTag *tag) { - tag->putShort(L"xTile", (short) xTile); + tag->putShort(L"xTile", (short) xTile); tag->putShort(L"yTile", (short) yTile); tag->putShort(L"zTile", (short) zTile); tag->putByte(L"inTile", (byte) lastTile); tag->putByte(L"inGround", (byte) (inGround ? 1 : 0)); - tag->put(L"direction", this->newDoubleList(3, this->xd, this->yd, this->zd)); + tag->put(L"direction", newDoubleList(3, xd, yd, zd)); } void Fireball::readAdditionalSaveData(CompoundTag *tag) @@ -338,13 +320,13 @@ void Fireball::readAdditionalSaveData(CompoundTag *tag) if (tag->contains(L"direction")) { ListTag *listTag = (ListTag *)tag->getList(L"direction"); - this->xd = ((DoubleTag *) listTag->get(0))->data; - this->yd = ((DoubleTag *) listTag->get(1))->data; - this->zd = ((DoubleTag *) listTag->get(2))->data; + xd = ((DoubleTag *) listTag->get(0))->data; + yd = ((DoubleTag *) listTag->get(1))->data; + zd = ((DoubleTag *) listTag->get(2))->data; } else { - this->remove(); + remove(); } } @@ -358,8 +340,9 @@ float Fireball::getPickRadius() return 1; } -bool Fireball::hurt(DamageSource *source, int damage) +bool Fireball::hurt(DamageSource *source, float damage) { + if (isInvulnerable()) return false; markHurt(); if (source->getEntity() != NULL) @@ -374,10 +357,9 @@ bool Fireball::hurt(DamageSource *source, int damage) yPower = yd * 0.1; zPower = zd * 0.1; } - shared_ptr mob = dynamic_pointer_cast( source->getEntity() ); - if (mob != NULL) + if ( source->getEntity()->instanceof(eTYPE_LIVINGENTITY) ) { - owner = mob; + owner = dynamic_pointer_cast( source->getEntity() ); } return true; } @@ -399,17 +381,12 @@ int Fireball::getLightColor(float a) return 15 << 20 | 15 << 4; } -bool Fireball::shouldBurn() -{ - return true; -} - -int Fireball::getIcon() +ePARTICLE_TYPE Fireball::getTrailParticleType() { - return 14 + 2 * 16; + return eParticleType_smoke; } -ePARTICLE_TYPE Fireball::getTrailParticleType() +bool Fireball::shouldBurn() { - return eParticleType_smoke; + return true; } \ No newline at end of file diff --git a/Minecraft.World/Fireball.h b/Minecraft.World/Fireball.h index c9471625..0f902099 100644 --- a/Minecraft.World/Fireball.h +++ b/Minecraft.World/Fireball.h @@ -10,7 +10,6 @@ class Fireball : public Entity { public: eINSTANCEOF GetType() { return eTYPE_FIREBALL; } - static Entity *create(Level *level) { return new Fireball(level); } private: int xTile; @@ -22,7 +21,7 @@ private: bool inGround; public: - shared_ptr owner; + shared_ptr owner; private: int life; @@ -43,31 +42,30 @@ public: virtual bool shouldRenderAtSqrDistance(double distance); Fireball(Level *level, double x, double y, double z, double xa, double ya, double za); - Fireball(Level *level, shared_ptr mob, double xa, double ya, double za); + Fireball(Level *level, shared_ptr mob, double xa, double ya, double za); public: virtual void tick(); protected: - virtual void onHit(HitResult *res); + virtual float getInertia(); + virtual void onHit(HitResult *res) = 0; public: virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); virtual bool isPickable(); virtual float getPickRadius(); - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); virtual float getShadowHeightOffs(); virtual float getBrightness(float a); virtual int getLightColor(float a); - // 4J Added TU9 - virtual bool shouldBurn(); - virtual int getIcon(); - protected: // 4J Added TU9 virtual ePARTICLE_TYPE getTrailParticleType(); + + virtual bool shouldBurn(); }; diff --git a/Minecraft.World/FireworksChargeItem.cpp b/Minecraft.World/FireworksChargeItem.cpp new file mode 100644 index 00000000..2de2be04 --- /dev/null +++ b/Minecraft.World/FireworksChargeItem.cpp @@ -0,0 +1,211 @@ +#include "stdafx.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.h" +#include "FireworksChargeItem.h" + +FireworksChargeItem::FireworksChargeItem(int id) : Item(id) +{ +} + +Icon *FireworksChargeItem::getLayerIcon(int auxValue, int spriteLayer) +{ + if (spriteLayer > 0) + { + return overlay; + } + return Item::getLayerIcon(auxValue, spriteLayer); +} + +int FireworksChargeItem::getColor(shared_ptr item, int spriteLayer) +{ + if (spriteLayer == 1) + { + Tag *colorTag = getExplosionTagField(item, FireworksItem::TAG_E_COLORS); + if (colorTag != NULL) + { + IntArrayTag *colors = (IntArrayTag *) colorTag; + if (colors->data.length == 1) + { + return colors->data[0]; + } + int totalRed = 0; + int totalGreen = 0; + int totalBlue = 0; + for (unsigned int i = 0; i < colors->data.length; ++i) + { + int c = colors->data[i]; + totalRed += (c & 0xff0000) >> 16; + totalGreen += (c & 0x00ff00) >> 8; + totalBlue += (c & 0x0000ff) >> 0; + } + totalRed /= colors->data.length; + totalGreen /= colors->data.length; + totalBlue /= colors->data.length; + return (totalRed << 16) | (totalGreen << 8) | totalBlue; + } + return 0x8a8a8a; + } + return Item::getColor(item, spriteLayer); +} + +bool FireworksChargeItem::hasMultipleSpriteLayers() +{ + return true; +} + +Tag *FireworksChargeItem::getExplosionTagField(shared_ptr instance, const wstring &field) +{ + if (instance->hasTag()) + { + CompoundTag *explosion = instance->getTag()->getCompound(FireworksItem::TAG_EXPLOSION); + if (explosion != NULL) + { + return explosion->get(field); + } + } + return NULL; +} + +void FireworksChargeItem::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced) +{ + if (itemInstance->hasTag()) + { + CompoundTag *explosion = itemInstance->getTag()->getCompound(FireworksItem::TAG_EXPLOSION); + if (explosion != NULL) + { + appendHoverText(explosion, lines); + } + } +} + +const unsigned int FIREWORKS_CHARGE_TYPE_NAME[] = +{ + IDS_FIREWORKS_CHARGE_TYPE_0, + IDS_FIREWORKS_CHARGE_TYPE_1, + IDS_FIREWORKS_CHARGE_TYPE_2, + IDS_FIREWORKS_CHARGE_TYPE_3, + IDS_FIREWORKS_CHARGE_TYPE_4 +}; + +const unsigned int FIREWORKS_CHARGE_COLOUR_NAME[] = +{ + IDS_FIREWORKS_CHARGE_BLACK, + IDS_FIREWORKS_CHARGE_RED, + IDS_FIREWORKS_CHARGE_GREEN, + IDS_FIREWORKS_CHARGE_BROWN, + IDS_FIREWORKS_CHARGE_BLUE, + IDS_FIREWORKS_CHARGE_PURPLE, + IDS_FIREWORKS_CHARGE_CYAN, + IDS_FIREWORKS_CHARGE_SILVER, + IDS_FIREWORKS_CHARGE_GRAY, + IDS_FIREWORKS_CHARGE_PINK, + IDS_FIREWORKS_CHARGE_LIME, + IDS_FIREWORKS_CHARGE_YELLOW, + IDS_FIREWORKS_CHARGE_LIGHT_BLUE, + IDS_FIREWORKS_CHARGE_MAGENTA, + IDS_FIREWORKS_CHARGE_ORANGE, + IDS_FIREWORKS_CHARGE_WHITE +}; + +void FireworksChargeItem::appendHoverText(CompoundTag *expTag, vector *lines) +{ + // shape + byte type = expTag->getByte(FireworksItem::TAG_E_TYPE); + if (type >= FireworksItem::TYPE_MIN && type <= FireworksItem::TYPE_MAX) + { + lines->push_back(HtmlString(app.GetString(FIREWORKS_CHARGE_TYPE_NAME[type]))); + } + else + { + lines->push_back(HtmlString(app.GetString(IDS_FIREWORKS_CHARGE_TYPE))); + } + + // colors + intArray colorList = expTag->getIntArray(FireworksItem::TAG_E_COLORS); + if (colorList.length > 0) + { + + bool first = true; + wstring output = L""; + for (unsigned int i = 0; i < colorList.length; ++i) + { + int c = colorList[i]; + if (!first) + { + output += L",\n"; // 4J-PB - without the newline, they tend to go offscreen in split-screen or localised languages + } + first = false; + + // find color name by lookup + bool found = false; + for (int dc = 0; dc < 16; dc++) + { + if (c == DyePowderItem::COLOR_RGB[dc]) + { + found = true; + output += app.GetString(FIREWORKS_CHARGE_COLOUR_NAME[dc]); + break; + } + } + if (!found) + { + output += app.GetString(IDS_FIREWORKS_CHARGE_CUSTOM); + } + } + lines->push_back(output); + } + + // has fade? + intArray fadeList = expTag->getIntArray(FireworksItem::TAG_E_FADECOLORS); + if (fadeList.length > 0) + { + bool first = true; + wstring output = wstring(app.GetString(IDS_FIREWORKS_CHARGE_FADE_TO)) + L" "; + for (unsigned int i = 0; i < fadeList.length; ++i) + { + int c = fadeList[i]; + if (!first) + { + output += L",\n";// 4J-PB - without the newline, they tend to go offscreen in split-screen or localised languages + } + first = false; + + // find color name by lookup + bool found = false; + for (int dc = 0; dc < 16; dc++) + { + if (c == DyePowderItem::COLOR_RGB[dc]) + { + found = true; + output += app.GetString(FIREWORKS_CHARGE_COLOUR_NAME[dc]); + break; + } + } + if (!found) + { + output += app.GetString(IDS_FIREWORKS_CHARGE_CUSTOM); + } + } + lines->push_back(output); + } + + // has trail + bool trail = expTag->getBoolean(FireworksItem::TAG_E_TRAIL); + if (trail) + { + lines->push_back(HtmlString(app.GetString(IDS_FIREWORKS_CHARGE_TRAIL))); + } + + // has flicker + bool flicker = expTag->getBoolean(FireworksItem::TAG_E_FLICKER); + if (flicker) + { + lines->push_back(HtmlString(app.GetString(IDS_FIREWORKS_CHARGE_FLICKER))); + } +} + +void FireworksChargeItem::registerIcons(IconRegister *iconRegister) +{ + Item::registerIcons(iconRegister); + overlay = iconRegister->registerIcon(getIconName() + L"_overlay"); +} \ No newline at end of file diff --git a/Minecraft.World/FireworksChargeItem.h b/Minecraft.World/FireworksChargeItem.h new file mode 100644 index 00000000..bfdca8ac --- /dev/null +++ b/Minecraft.World/FireworksChargeItem.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Item.h" + +class FireworksChargeItem : public Item +{ +private: + Icon *overlay; + +public: + FireworksChargeItem(int id); + + virtual Icon *getLayerIcon(int auxValue, int spriteLayer); + virtual int getColor(shared_ptr item, int spriteLayer); + virtual bool hasMultipleSpriteLayers(); + + static Tag *getExplosionTagField(shared_ptr instance, const wstring &field); + + virtual void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced); + + static void appendHoverText(CompoundTag *expTag, vector *lines); + + virtual void registerIcons(IconRegister *iconRegister); +}; \ No newline at end of file diff --git a/Minecraft.World/FireworksItem.cpp b/Minecraft.World/FireworksItem.cpp new file mode 100644 index 00000000..045ea130 --- /dev/null +++ b/Minecraft.World/FireworksItem.cpp @@ -0,0 +1,81 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.projectile.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "FireworksItem.h" + +const wstring FireworksItem::TAG_FIREWORKS = L"Fireworks"; +const wstring FireworksItem::TAG_EXPLOSION = L"Explosion"; +const wstring FireworksItem::TAG_EXPLOSIONS = L"Explosions"; +const wstring FireworksItem::TAG_FLIGHT = L"Flight"; +const wstring FireworksItem::TAG_E_TYPE = L"Type"; +const wstring FireworksItem::TAG_E_TRAIL = L"Trail"; +const wstring FireworksItem::TAG_E_FLICKER = L"Flicker"; +const wstring FireworksItem::TAG_E_COLORS = L"Colors"; +const wstring FireworksItem::TAG_E_FADECOLORS = L"FadeColors"; + +FireworksItem::FireworksItem(int id) : Item(id) +{ +} + +bool FireworksItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) +{ + // 4J-JEV: Fix for xb1 #173493 - CU7: Content: UI: Missing tooltip for Firework Rocket. + if (bTestUseOnOnly) return true; + + if (!level->isClientSide) + { + shared_ptr f = shared_ptr( new FireworksRocketEntity(level, x + clickX, y + clickY, z + clickZ, instance) ); + level->addEntity(f); + + if (!player->abilities.instabuild) + { + instance->count--; + } + return true; + } + + return false; +} + +void FireworksItem::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced) +{ + if (!itemInstance->hasTag()) + { + return; + } + CompoundTag *fireTag = itemInstance->getTag()->getCompound(TAG_FIREWORKS); + if (fireTag == NULL) + { + return; + } + if (fireTag->contains(TAG_FLIGHT)) + { + lines->push_back(wstring(app.GetString(IDS_ITEM_FIREWORKS_FLIGHT)) + L" " + _toString((fireTag->getByte(TAG_FLIGHT)))); + } + + ListTag *explosions = (ListTag *) fireTag->getList(TAG_EXPLOSIONS); + if (explosions != NULL && explosions->size() > 0) + { + + for (int i = 0; i < explosions->size(); i++) + { + CompoundTag *expTag = explosions->get(i); + + vector eLines; + FireworksChargeItem::appendHoverText(expTag, &eLines); + + if (eLines.size() > 0) + { + // Indent lines after first line + for (int i = 1; i < eLines.size(); i++) + { + eLines[i].indent = true; + } + + lines->insert(lines->end(), eLines.begin(), eLines.end()); + } + } + } +} \ No newline at end of file diff --git a/Minecraft.World/FireworksItem.h b/Minecraft.World/FireworksItem.h new file mode 100644 index 00000000..afc6cb59 --- /dev/null +++ b/Minecraft.World/FireworksItem.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Item.h" + +class FireworksItem : public Item +{ +public: + static const wstring TAG_FIREWORKS; + static const wstring TAG_EXPLOSION; + static const wstring TAG_EXPLOSIONS; + static const wstring TAG_FLIGHT; + static const wstring TAG_E_TYPE; + static const wstring TAG_E_TRAIL; + static const wstring TAG_E_FLICKER; + static const wstring TAG_E_COLORS; + static const wstring TAG_E_FADECOLORS; + + static const byte TYPE_SMALL = 0; + static const byte TYPE_BIG = 1; + static const byte TYPE_STAR = 2; + static const byte TYPE_CREEPER = 3; + static const byte TYPE_BURST = 4; + + static const byte TYPE_MIN = TYPE_SMALL; + static const byte TYPE_MAX = TYPE_BURST; + + FireworksItem(int id); + + bool useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); + void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced); +}; \ No newline at end of file diff --git a/Minecraft.World/FireworksMenu.cpp b/Minecraft.World/FireworksMenu.cpp new file mode 100644 index 00000000..68c9e0f2 --- /dev/null +++ b/Minecraft.World/FireworksMenu.cpp @@ -0,0 +1,150 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.item.crafting.h" +#include "CraftingContainer.h" +#include "ResultContainer.h" +#include "ResultSlot.h" +#include "FireworksMenu.h" + +FireworksMenu::FireworksMenu(shared_ptr inventory, Level *level, int xt, int yt, int zt) : AbstractContainerMenu() +{ + m_canMakeFireworks = false; + m_canMakeCharge = false; + m_canMakeFade = false; + + craftSlots = shared_ptr( new CraftingContainer(this, 3, 3) ); + resultSlots = shared_ptr( new ResultContainer() ); + + this->level = level; + x = xt; + y = yt; + z = zt; + addSlot(new ResultSlot( inventory->player, craftSlots, resultSlots, 0, 120 + 4, 31 + 4)); + + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 3; x++) + { + addSlot(new Slot(craftSlots, x + y * 3, 30 + x * 18, 17 + y * 18)); + } + } + + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(inventory, x + y * 9 + 9, 8 + x * 18, 84 + y * 18)); + } + } + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(inventory, x, 8 + x * 18, 142)); + } + + slotsChanged(); // 4J - removed craftSlots parameter, see comment below +} + +void FireworksMenu::slotsChanged() // 4J used to take a shared_ptr but wasn't using it, so removed to simplify things +{ + FireworksRecipe::updatePossibleRecipes(craftSlots, &m_canMakeFireworks, &m_canMakeCharge, &m_canMakeFade); + resultSlots->setItem(0, Recipes::getInstance()->getItemFor(craftSlots, level, Recipes::pFireworksRecipes)); +} + +void FireworksMenu::removed(shared_ptr player) +{ + AbstractContainerMenu::removed(player); + if (level->isClientSide) return; + + for (int i = 0; i < 9; i++) + { + shared_ptr item = craftSlots->removeItemNoUpdate(i); + if (item != NULL) + { + player->drop(item); + } + } +} + +bool FireworksMenu::stillValid(shared_ptr player) +{ + return true; +} + +shared_ptr FireworksMenu::quickMoveStack(shared_ptr player, int slotIndex) +{ + shared_ptr clicked = nullptr; + Slot *slot = slots.at(slotIndex); + if (slot != NULL && slot->hasItem()) + { + shared_ptr stack = slot->getItem(); + clicked = stack->copy(); + + if (slotIndex == RESULT_SLOT) + { + if(!moveItemStackTo(stack, INV_SLOT_START, USE_ROW_SLOT_END, true)) + { + return nullptr; + } + slot->onQuickCraft(stack, clicked); + } + else if (slotIndex >= INV_SLOT_START && slotIndex < INV_SLOT_END) + { + if(isValidIngredient(stack, -1) && moveItemStackTo(stack, CRAFT_SLOT_START, CRAFT_SLOT_END, false)) + { + } + else if(!moveItemStackTo(stack, USE_ROW_SLOT_START, USE_ROW_SLOT_END, false)) + { + return nullptr; + } + } + else if (slotIndex >= USE_ROW_SLOT_START && slotIndex < USE_ROW_SLOT_END) + { + if(isValidIngredient(stack, -1) && moveItemStackTo(stack, CRAFT_SLOT_START, CRAFT_SLOT_END, false)) + { + } + else if(!moveItemStackTo(stack, INV_SLOT_START, INV_SLOT_END, false)) + { + return nullptr; + } + } + else + { + if(!moveItemStackTo(stack, INV_SLOT_START, USE_ROW_SLOT_END, false)) + { + return nullptr; + } + } + if (stack->count == 0) + { + slot->set(nullptr); + } + else + { + slot->setChanged(); + } + if (stack->count == clicked->count) + { + // nothing moved + return nullptr; + } + else + { + slot->onTake(player, stack); + } + } + return clicked; +} + +bool FireworksMenu::canTakeItemForPickAll(shared_ptr carried, Slot *target) +{ + return target->container != resultSlots && AbstractContainerMenu::canTakeItemForPickAll(carried, target); +} + +bool FireworksMenu::isValidIngredient(shared_ptr item, int slotId) +{ + if(item == NULL || slotId == RESULT_SLOT) return true; + return FireworksRecipe::isValidIngredient(item, m_canMakeFireworks, m_canMakeCharge, m_canMakeFade); +} \ No newline at end of file diff --git a/Minecraft.World/FireworksMenu.h b/Minecraft.World/FireworksMenu.h new file mode 100644 index 00000000..97621261 --- /dev/null +++ b/Minecraft.World/FireworksMenu.h @@ -0,0 +1,43 @@ +#pragma once + +#include "AbstractContainerMenu.h" + +class CraftingContainer; +class Container; + +class FireworksMenu : public AbstractContainerMenu +{ + // 4J Stu Made these public for UI menus, perhaps should make friend class? +public: + static const int RESULT_SLOT = 0; + static const int CRAFT_SLOT_START = 1; + static const int CRAFT_SLOT_END = CRAFT_SLOT_START + 9; + static const int INV_SLOT_START = CRAFT_SLOT_END; + static const int INV_SLOT_END = INV_SLOT_START + (9*3); + static const int USE_ROW_SLOT_START = INV_SLOT_END; + static const int USE_ROW_SLOT_END = USE_ROW_SLOT_START + 9; + +public: + shared_ptr craftSlots; + shared_ptr resultSlots; + +private: + Level *level; + int x, y, z; + + bool m_canMakeFireworks; + bool m_canMakeCharge; + bool m_canMakeFade; + +public: + FireworksMenu(shared_ptr inventory, Level *level, int xt, int yt, int zt); + + virtual void slotsChanged();// 4J used to take a shared_ptr but wasn't using it, so removed to simplify things + virtual void removed(shared_ptr player); + virtual bool stillValid(shared_ptr player); + virtual shared_ptr quickMoveStack(shared_ptr player, int slotIndex); + virtual bool canTakeItemForPickAll(shared_ptr carried, Slot *target); + + // 4J Added + virtual bool isValidIngredient(shared_ptr item, int slotId); +}; \ No newline at end of file diff --git a/Minecraft.World/FireworksRecipe.cpp b/Minecraft.World/FireworksRecipe.cpp new file mode 100644 index 00000000..a357c9cb --- /dev/null +++ b/Minecraft.World/FireworksRecipe.cpp @@ -0,0 +1,418 @@ +#include "stdafx.h" +#include "net.minecraft.world.item.h" +#include "FireworksRecipe.h" + +DWORD FireworksRecipe::tlsIdx = 0; +FireworksRecipe::ThreadStorage *FireworksRecipe::tlsDefault = NULL; + +FireworksRecipe::ThreadStorage::ThreadStorage() +{ + resultItem = nullptr; +} + +void FireworksRecipe::CreateNewThreadStorage() +{ + ThreadStorage *tls = new ThreadStorage(); + if(tlsDefault == NULL ) + { + tlsIdx = TlsAlloc(); + tlsDefault = tls; + } + TlsSetValue(tlsIdx, tls); +} + +void FireworksRecipe::UseDefaultThreadStorage() +{ + TlsSetValue(tlsIdx, tlsDefault); +} + +void FireworksRecipe::ReleaseThreadStorage() +{ + ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx); + if( tls == tlsDefault ) return; + + delete tls; +} + +void FireworksRecipe::setResultItem(shared_ptr item) +{ + ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx); + tls->resultItem = item; +} + +FireworksRecipe::FireworksRecipe() +{ + //resultItem = nullptr; +} + +bool FireworksRecipe::matches(shared_ptr craftSlots, Level *level) +{ + shared_ptr resultItem = nullptr; + + int paperCount = 0; + int sulphurCount = 0; + int colorCount = 0; + int chargeCount = 0; + int chargeComponents = 0; + int typeComponents = 0; + + for (int slot = 0; slot < craftSlots->getContainerSize(); slot++) + { + shared_ptr item = craftSlots->getItem(slot); + if (item == NULL) continue; + + if (item->id == Item::gunpowder_Id) + { + sulphurCount++; + } + else if (item->id == Item::fireworksCharge_Id) + { + chargeCount++; + } + else if (item->id == Item::dye_powder_Id) + { + colorCount++; + } + else if (item->id == Item::paper_Id) + { + paperCount++; + } + else if (item->id == Item::yellowDust_Id) + { + // glowstone dust gives flickering + chargeComponents++; + } + else if (item->id == Item::diamond_Id) + { + // diamonds give trails + chargeComponents++; + } + else if (item->id == Item::fireball_Id) + { + // fireball gives larger explosion + typeComponents++; + } + else if (item->id == Item::feather_Id) + { + // burst + typeComponents++; + } + else if (item->id == Item::goldNugget_Id) + { + // star + typeComponents++; + } + else if (item->id == Item::skull_Id) + { + // creeper + typeComponents++; + } + else + { + setResultItem(resultItem); + return false; + } + } + chargeComponents += colorCount + typeComponents; + + if (sulphurCount > 3 || paperCount > 1) + { + setResultItem(resultItem); + return false; + } + + // create fireworks + if (sulphurCount >= 1 && paperCount == 1 && chargeComponents == 0) + { + resultItem = shared_ptr( new ItemInstance(Item::fireworks) ); + if (chargeCount > 0) + { + CompoundTag *itemTag = new CompoundTag(); + CompoundTag *fireTag = new CompoundTag(FireworksItem::TAG_FIREWORKS); + ListTag *expTags = new ListTag(FireworksItem::TAG_EXPLOSIONS); + + for (int slot = 0; slot < craftSlots->getContainerSize(); slot++) + { + shared_ptr item = craftSlots->getItem(slot); + if (item == NULL || item->id != Item::fireworksCharge_Id) continue; + + if (item->hasTag() && item->getTag()->contains(FireworksItem::TAG_EXPLOSION)) + { + expTags->add((CompoundTag *)item->getTag()->getCompound(FireworksItem::TAG_EXPLOSION)->copy()); + } + } + + fireTag->put(FireworksItem::TAG_EXPLOSIONS, expTags); + fireTag->putByte(FireworksItem::TAG_FLIGHT, (byte) sulphurCount); + itemTag->put(FireworksItem::TAG_FIREWORKS, fireTag); + + resultItem->setTag(itemTag); + } + setResultItem(resultItem); + return true; + } + // create firecharge + if (sulphurCount == 1 && paperCount == 0 && chargeCount == 0 && colorCount > 0 && typeComponents <= 1) + { + + resultItem = shared_ptr( new ItemInstance(Item::fireworksCharge) ); + CompoundTag *itemTag = new CompoundTag(); + CompoundTag *expTag = new CompoundTag(FireworksItem::TAG_EXPLOSION); + + byte type = 0; + + vector colors; + for (int slot = 0; slot < craftSlots->getContainerSize(); slot++) + { + shared_ptr item = craftSlots->getItem(slot); + if (item == NULL) continue; + + if (item->id == Item::dye_powder_Id) + { + colors.push_back(DyePowderItem::COLOR_RGB[item->getAuxValue()]); + } + else if (item->id == Item::yellowDust_Id) + { + // glowstone dust gives flickering + expTag->putBoolean(FireworksItem::TAG_E_FLICKER, true); + } + else if (item->id == Item::diamond_Id) + { + // diamonds give trails + expTag->putBoolean(FireworksItem::TAG_E_TRAIL, true); + } + else if (item->id == Item::fireball_Id) + { + type = FireworksItem::TYPE_BIG; + } + else if (item->id == Item::feather_Id) + { + type = FireworksItem::TYPE_BURST; + } + else if (item->id == Item::goldNugget_Id) + { + type = FireworksItem::TYPE_STAR; + } + else if (item->id == Item::skull_Id) + { + type = FireworksItem::TYPE_CREEPER; + } + } + intArray colorArray(colors.size()); + for (int i = 0; i < colorArray.length; i++) + { + colorArray[i] = colors.at(i); + } + expTag->putIntArray(FireworksItem::TAG_E_COLORS, colorArray); + + expTag->putByte(FireworksItem::TAG_E_TYPE, type); + + itemTag->put(FireworksItem::TAG_EXPLOSION, expTag); + resultItem->setTag(itemTag); + + setResultItem(resultItem); + return true; + } + // apply fade colors to firecharge + if (sulphurCount == 0 && paperCount == 0 && chargeCount == 1 && colorCount > 0 && colorCount == chargeComponents) + { + + vector colors; + for (int slot = 0; slot < craftSlots->getContainerSize(); slot++) + { + shared_ptr item = craftSlots->getItem(slot); + if (item == NULL) continue; + + if (item->id == Item::dye_powder_Id) + { + colors.push_back(DyePowderItem::COLOR_RGB[item->getAuxValue()]); + } + else if (item->id == Item::fireworksCharge_Id) + { + resultItem = item->copy(); + resultItem->count = 1; + } + } + intArray colorArray(colors.size()); + for (int i = 0; i < colorArray.length; i++) + { + colorArray[i] = colors.at(i); + } + if (resultItem != NULL && resultItem->hasTag()) + { + CompoundTag *compound = resultItem->getTag()->getCompound(FireworksItem::TAG_EXPLOSION); + if (compound == NULL) + { + delete colorArray.data; + + setResultItem(resultItem); + return false; + } + compound->putIntArray(FireworksItem::TAG_E_FADECOLORS, colorArray); + } + else + { + delete colorArray.data; + + setResultItem(resultItem); + return false; + } + + setResultItem(resultItem); + return true; + } + + setResultItem(resultItem); + return false; +} + +shared_ptr FireworksRecipe::assemble(shared_ptr craftSlots) +{ + ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx); + return tls->resultItem->copy(); + //return resultItem->copy(); +} + +int FireworksRecipe::size() +{ + return 10; +} + +const ItemInstance *FireworksRecipe::getResultItem() +{ + ThreadStorage *tls = (ThreadStorage *)TlsGetValue(tlsIdx); + return tls->resultItem.get(); + //return resultItem.get(); +} + +void FireworksRecipe::updatePossibleRecipes(shared_ptr craftSlots, bool *firework, bool *charge, bool *fade) +{ + *firework = false; + *charge = false; + *fade = false; + + int paperCount = 0; + int sulphurCount = 0; + int colorCount = 0; + int chargeCount = 0; + int chargeComponents = 0; + int typeComponents = 0; + + for (int slot = 0; slot < craftSlots->getContainerSize(); slot++) + { + shared_ptr item = craftSlots->getItem(slot); + if (item == NULL) continue; + + if (item->id == Item::gunpowder_Id) + { + sulphurCount++; + } + else if (item->id == Item::fireworksCharge_Id) + { + chargeCount++; + } + else if (item->id == Item::dye_powder_Id) + { + colorCount++; + } + else if (item->id == Item::paper_Id) + { + paperCount++; + } + else if (item->id == Item::yellowDust_Id) + { + // glowstone dust gives flickering + chargeComponents++; + } + else if (item->id == Item::diamond_Id) + { + // diamonds give trails + chargeComponents++; + } + else if (item->id == Item::fireball_Id) + { + // fireball gives larger explosion + typeComponents++; + } + else if (item->id == Item::feather_Id) + { + // burst + typeComponents++; + } + else if (item->id == Item::goldNugget_Id) + { + // star + typeComponents++; + } + else if (item->id == Item::skull_Id) + { + // creeper + typeComponents++; + } + else + { + return; + } + } + chargeComponents += colorCount + typeComponents; + + if (sulphurCount > 3 || paperCount > 1) + { + return; + } + + // create fireworks + if ( paperCount <= 1 && chargeComponents == 0 ) + { + *firework = true; + } + // create firecharge + if ( sulphurCount <= 1 && colorCount >= 0 && paperCount == 0 && chargeCount == 0 && typeComponents <= 1 ) + { + *charge = true; + } + // apply fade colors to firecharge + if ( sulphurCount == 0 && paperCount == 0 && chargeCount <= 1 && colorCount >= 0 ) + { + *fade = true; + } +} + +bool FireworksRecipe::isValidIngredient(shared_ptr item, bool firework, bool charge, bool fade) +{ + bool valid = false; + switch(item->id) + { + case Item::gunpowder_Id: + valid = firework || charge; + break; + case Item::fireworksCharge_Id: + valid = firework || fade; + break; + case Item::dye_powder_Id: + valid = charge || fade; + break; + case Item::paper_Id: + valid = firework; + break; + case Item::yellowDust_Id: + valid = charge; + break; + case Item::diamond_Id: + valid = charge; + break; + case Item::fireball_Id: + valid = charge; + break; + case Item::feather_Id: + valid = charge; + break; + case Item::goldNugget_Id: + valid = charge; + break; + case Item::skull_Id: + valid = charge; + break; + } + return valid; +} \ No newline at end of file diff --git a/Minecraft.World/FireworksRecipe.h b/Minecraft.World/FireworksRecipe.h new file mode 100644 index 00000000..ef2815ea --- /dev/null +++ b/Minecraft.World/FireworksRecipe.h @@ -0,0 +1,46 @@ +#pragma once + +#include "Recipy.h" + +class FireworksRecipe : public Recipy +{ +private: + //shared_ptr resultItem; + + // 4J added so we can have separate contexts and rleBuf for different threads + class ThreadStorage + { + public: + shared_ptr resultItem; + ThreadStorage(); + }; + static DWORD tlsIdx; + static ThreadStorage *tlsDefault; + + void setResultItem(shared_ptr item); +public: + // Each new thread that needs to use Compression will need to call one of the following 2 functions, to either create its own + // local storage, or share the default storage already allocated by the main thread + static void CreateNewThreadStorage(); + static void UseDefaultThreadStorage(); + static void ReleaseThreadStorage(); + +public: + FireworksRecipe(); + + bool matches(shared_ptr craftSlots, Level *level); + shared_ptr assemble(shared_ptr craftSlots); + int size(); + const ItemInstance *getResultItem(); + + + virtual const int getGroup() { return 0; } + + // 4J-PB + virtual bool requires(int iRecipe) { return false; }; + virtual void requires(INGREDIENTS_REQUIRED *pIngReq) {}; + + // 4J Added + static void updatePossibleRecipes(shared_ptr craftSlots, bool *firework, bool *charge, bool *fade); + static bool isValidIngredient(shared_ptr item, bool firework, bool charge, bool fade); +}; \ No newline at end of file diff --git a/Minecraft.World/FireworksRocketEntity.cpp b/Minecraft.World/FireworksRocketEntity.cpp new file mode 100644 index 00000000..e84844f1 --- /dev/null +++ b/Minecraft.World/FireworksRocketEntity.cpp @@ -0,0 +1,181 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "FireworksRocketEntity.h" + +FireworksRocketEntity::FireworksRocketEntity(Level *level) : Entity(level) +{ + defineSynchedData(); + + life = 0; + lifetime = 0; + setSize(0.25f, 0.25f); +} + +void FireworksRocketEntity::defineSynchedData() +{ + entityData->defineNULL(DATA_ID_FIREWORKS_ITEM, NULL); +} + +bool FireworksRocketEntity::shouldRenderAtSqrDistance(double distance) +{ + return distance < 64 * 64; +} + +FireworksRocketEntity::FireworksRocketEntity(Level *level, double x, double y, double z, shared_ptr sourceItem) : Entity(level) +{ + defineSynchedData(); + + life = 0; + + setSize(0.25f, 0.25f); + + setPos(x, y, z); + heightOffset = 0; + + int flightCount = 1; + if (sourceItem != NULL && sourceItem->hasTag()) + { + entityData->set(DATA_ID_FIREWORKS_ITEM, sourceItem); + + CompoundTag *tag = sourceItem->getTag(); + CompoundTag *compound = tag->getCompound(FireworksItem::TAG_FIREWORKS); + if (compound != NULL) + { + flightCount += compound->getByte(FireworksItem::TAG_FLIGHT); + } + } + xd = random->nextGaussian() * .001; + zd = random->nextGaussian() * .001; + yd = 0.05; + + lifetime = (SharedConstants::TICKS_PER_SECOND / 2) * flightCount + random->nextInt(6) + random->nextInt(7); +} + +void FireworksRocketEntity::lerpMotion(double xd, double yd, double zd) +{ + xd = xd; + yd = yd; + zd = zd; + if (xRotO == 0 && yRotO == 0) + { + double sd = Mth::sqrt(xd * xd + zd * zd); + yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI); + xRotO = xRot = (float) (atan2(yd, sd) * 180 / PI); + } +} + +void FireworksRocketEntity::tick() +{ + xOld = x; + yOld = y; + zOld = z; + Entity::tick(); + + xd *= 1.15; + zd *= 1.15; + yd += .04; + move(xd, yd, zd); + + double sd = Mth::sqrt(xd * xd + zd * zd); + yRot = (float) (atan2(xd, zd) * 180 / PI); + xRot = (float) (atan2(yd, sd) * 180 / PI); + + while (xRot - xRotO < -180) + xRotO -= 360; + while (xRot - xRotO >= 180) + xRotO += 360; + + while (yRot - yRotO < -180) + yRotO -= 360; + while (yRot - yRotO >= 180) + yRotO += 360; + + xRot = xRotO + (xRot - xRotO) * 0.2f; + yRot = yRotO + (yRot - yRotO) * 0.2f; + + if (!level->isClientSide ) + { + if (life == 0) + { + level->playEntitySound(shared_from_this(), eSoundType_FIREWORKS_LAUNCH, 3, 1); + } + } + + life++; + if (level->isClientSide && (life % 2) < 2) + { + level->addParticle(eParticleType_fireworksspark, x, y - .3, z, random->nextGaussian() * .05, -yd * .5, random->nextGaussian() * .05); + } + if (!level->isClientSide && life > lifetime) + { + level->broadcastEntityEvent(shared_from_this(), EntityEvent::FIREWORKS_EXPLODE); + remove(); + } +} + +void FireworksRocketEntity::handleEntityEvent(byte eventId) +{ + if (eventId == EntityEvent::FIREWORKS_EXPLODE && level->isClientSide) + { + shared_ptr sourceItem = entityData->getItemInstance(DATA_ID_FIREWORKS_ITEM); + CompoundTag *tag = NULL; + if (sourceItem != NULL && sourceItem->hasTag()) + { + tag = sourceItem->getTag()->getCompound(FireworksItem::TAG_FIREWORKS); + } + level->createFireworks(x, y, z, xd, yd, zd, tag); + } + Entity::handleEntityEvent(eventId); +} + +void FireworksRocketEntity::addAdditonalSaveData(CompoundTag *tag) +{ + tag->putInt(L"Life", life); + tag->putInt(L"LifeTime", lifetime); + shared_ptr itemInstance = entityData->getItemInstance(DATA_ID_FIREWORKS_ITEM); + if (itemInstance != NULL) + { + CompoundTag *itemTag = new CompoundTag(); + itemInstance->save(itemTag); + tag->putCompound(L"FireworksItem", itemTag); + } + +} + +void FireworksRocketEntity::readAdditionalSaveData(CompoundTag *tag) +{ + life = tag->getInt(L"Life"); + lifetime = tag->getInt(L"LifeTime"); + + CompoundTag *itemTag = tag->getCompound(L"FireworksItem"); + if (itemTag != NULL) + { + shared_ptr fromTag = ItemInstance::fromTag(itemTag); + if (fromTag != NULL) + { + entityData->set(DATA_ID_FIREWORKS_ITEM, fromTag); + } + } +} + +float FireworksRocketEntity::getShadowHeightOffs() +{ + return 0; +} + +float FireworksRocketEntity::getBrightness(float a) +{ + return Entity::getBrightness(a); +} + +int FireworksRocketEntity::getLightColor(float a) +{ + return Entity::getLightColor(a); +} + +bool FireworksRocketEntity::isAttackable() +{ + return false; +} \ No newline at end of file diff --git a/Minecraft.World/FireworksRocketEntity.h b/Minecraft.World/FireworksRocketEntity.h new file mode 100644 index 00000000..025a2778 --- /dev/null +++ b/Minecraft.World/FireworksRocketEntity.h @@ -0,0 +1,38 @@ +#pragma once + +#include "Entity.h" + +class FireworksRocketEntity : public Entity +{ +public: + eINSTANCEOF GetType() { return eTYPE_FIREWORKS_ROCKET; } + static Entity *create(Level *level) { return new FireworksRocketEntity(level); } + +private: + static const int DATA_ID_FIREWORKS_ITEM = 8; + + int life; + int lifetime; + + // constructor needed for level loader +public: + FireworksRocketEntity(Level *level); + +protected: + virtual void defineSynchedData(); + +public: + virtual bool shouldRenderAtSqrDistance(double distance); + + FireworksRocketEntity(Level *level, double x, double y, double z, shared_ptr sourceItem); + + virtual void lerpMotion(double xd, double yd, double zd); + virtual void tick(); + virtual void handleEntityEvent(byte eventId); + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual float getShadowHeightOffs(); + virtual float getBrightness(float a); + virtual int getLightColor(float a); + virtual bool isAttackable(); +}; \ No newline at end of file diff --git a/Minecraft.World/FishingHook.cpp b/Minecraft.World/FishingHook.cpp index efa2dbc6..3e627af2 100644 --- a/Minecraft.World/FishingHook.cpp +++ b/Minecraft.World/FishingHook.cpp @@ -67,18 +67,18 @@ FishingHook::FishingHook(Level *level, shared_ptr mob) : Entity( level ) { _init(); - this->owner = mob; + owner = mob; // 4J Stu - Moved this outside the ctor //owner->fishing = dynamic_pointer_cast( shared_from_this() ); - this->moveTo(mob->x, mob->y + 1.62 - mob->heightOffset, mob->z, mob->yRot, mob->xRot); + moveTo(mob->x, mob->y + 1.62 - mob->heightOffset, mob->z, mob->yRot, mob->xRot); x -= Mth::cos(yRot / 180 * PI) * 0.16f; y -= 0.1f; z -= Mth::sin(yRot / 180 * PI) * 0.16f; - this->setPos(x, y, z); - this->heightOffset = 0; + setPos(x, y, z); + heightOffset = 0; float speed = 0.4f; @@ -122,8 +122,8 @@ void FishingHook::shoot(double xd, double yd, double zd, float pow, float uncert double sd = sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (atan2(xd, zd) * 180 / PI); - xRotO = this->xRot = (float) (atan2(yd, sd) * 180 / PI); + yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI); + xRotO = xRot = (float) (atan2(yd, sd) * 180 / PI); life = 0; } @@ -137,9 +137,9 @@ void FishingHook::lerpTo(double x, double y, double z, float yRot, float xRot, i lSteps = steps; - this->xd = lxd; - this->yd = lyd; - this->zd = lzd; + xd = lxd; + yd = lyd; + zd = lzd; } void FishingHook::lerpMotion(double xd, double yd, double zd) @@ -165,15 +165,15 @@ void FishingHook::tick() xRot += (float) ( (lxr - xRot) / lSteps ); lSteps--; - this->setPos(xt, yt, zt); - this->setRot(yRot, xRot); + setPos(xt, yt, zt); + setRot(yRot, xRot); return; } if (!level->isClientSide) { shared_ptr selectedItem = owner->getSelectedItem(); - if (owner->removed || !owner->isAlive() || selectedItem == NULL || selectedItem->getItem() != Item::fishingRod || this->distanceToSqr(owner) > 32 * 32) + if (owner->removed || !owner->isAlive() || selectedItem == NULL || selectedItem->getItem() != Item::fishingRod || distanceToSqr(owner) > 32 * 32) { remove(); owner->fishing = nullptr; @@ -231,7 +231,7 @@ void FishingHook::tick() to = Vec3::newTemp(res->pos->x, res->pos->y, res->pos->z); } shared_ptr hitEntity = nullptr; - vector > *objects = level->getEntities(shared_from_this(), this->bb->expand(xd, yd, zd)->grow(1, 1, 1)); + vector > *objects = level->getEntities(shared_from_this(), bb->expand(xd, yd, zd)->grow(1, 1, 1)); double nearest = 0; AUTO_VAR(itEnd, objects->end()); for (AUTO_VAR(it, objects->begin()); it != itEnd; it++) @@ -337,7 +337,7 @@ void FishingHook::tick() { nibble = random->nextInt(30) + 10; yd -= 0.2f; - level->playSound(shared_from_this(), eSoundType_RANDOM_SPLASH, 0.25f, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f); + playSound(eSoundType_RANDOM_SPLASH, 0.25f, 1 + (random->nextFloat() - random->nextFloat()) * 0.4f); float yt = (float) Mth::floor(bb->y0); for (int i = 0; i < 1 + bbWidth * 20; i++) { @@ -432,7 +432,7 @@ int FishingHook::retrieve() ie->Entity::yd = ya * speed + sqrt(dist) * 0.08; ie->Entity::zd = za * speed; level->addEntity(ie); - owner->level->addEntity( shared_ptr( new ExperienceOrb(owner->level, owner->x, owner->y + 0.5f, owner->z + 0.5f, random->nextInt(3) + 1) ) ); // 4J Stu brought forward from 1.4 + owner->level->addEntity( shared_ptr( new ExperienceOrb(owner->level, owner->x, owner->y + 0.5f, owner->z + 0.5f, random->nextInt(6) + 1) ) ); // 4J Stu brought forward from 1.4 dmg = 1; } if (inGround) dmg = 2; diff --git a/Minecraft.World/FishingRodItem.cpp b/Minecraft.World/FishingRodItem.cpp index 858005e0..883eb2de 100644 --- a/Minecraft.World/FishingRodItem.cpp +++ b/Minecraft.World/FishingRodItem.cpp @@ -13,8 +13,6 @@ #include "FishingRodItem.h" #include "SoundTypes.h" -const wstring FishingRodItem::TEXTURE_EMPTY = L"fishingRod_empty"; - FishingRodItem::FishingRodItem(int id) : Item(id) { setMaxDamage(64); @@ -37,12 +35,12 @@ shared_ptr FishingRodItem::use(shared_ptr instance, if (player->fishing != NULL) { int dmg = player->fishing->retrieve(); - instance->hurt(dmg, player); + instance->hurtAndBreak(dmg, player); player->swing(); } else { - level->playSound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); + level->playEntitySound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); if (!level->isClientSide) { // 4J Stu - Move the player->fishing out of the ctor as we cannot reference 'this' @@ -57,8 +55,8 @@ shared_ptr FishingRodItem::use(shared_ptr instance, void FishingRodItem::registerIcons(IconRegister *iconRegister) { - Item::registerIcons(iconRegister); - emptyIcon = iconRegister->registerIcon(TEXTURE_EMPTY); + icon = iconRegister->registerIcon(getIconName() + L"_uncast"); + emptyIcon = iconRegister->registerIcon(getIconName() + L"_cast"); } Icon *FishingRodItem::getEmptyIcon() diff --git a/Minecraft.World/FishingRodItem.h b/Minecraft.World/FishingRodItem.h index a6df606d..5d95177a 100644 --- a/Minecraft.World/FishingRodItem.h +++ b/Minecraft.World/FishingRodItem.h @@ -8,9 +8,6 @@ class Level; class FishingRodItem : public Item { -public: - static const wstring TEXTURE_EMPTY; - private: Icon *emptyIcon; @@ -21,7 +18,6 @@ public: virtual bool isMirroredArt(); virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); - //@Override void registerIcons(IconRegister *iconRegister); Icon *getEmptyIcon(); }; diff --git a/Minecraft.World/FixedBiomeSource.cpp b/Minecraft.World/FixedBiomeSource.cpp index 35708cb2..257ec3db 100644 --- a/Minecraft.World/FixedBiomeSource.cpp +++ b/Minecraft.World/FixedBiomeSource.cpp @@ -4,7 +4,7 @@ FixedBiomeSource::FixedBiomeSource(Biome *fixed, float temperature, float downfall) { - this->biome = fixed; + biome = fixed; this->temperature = temperature; this->downfall = downfall; } @@ -45,9 +45,9 @@ floatArray FixedBiomeSource::getTemperatureBlock(int x, int z, int w, int h) con // 4J - note that caller is responsible for deleting returned array. temperatures array is for output only. void FixedBiomeSource::getTemperatureBlock(doubleArray& temperatures, int x, int z, int w, int h) const { - temperatures = doubleArray(w * h); + temperatures = doubleArray(w * h); - Arrays::fill(temperatures, 0, w * h, (double)temperature); + Arrays::fill(temperatures, 0, w * h, (double)temperature); } void FixedBiomeSource::getDownfallBlock(floatArray &downfalls, int x, int z, int w, int h) const diff --git a/Minecraft.World/FlatGeneratorInfo.cpp b/Minecraft.World/FlatGeneratorInfo.cpp new file mode 100644 index 00000000..9df19693 --- /dev/null +++ b/Minecraft.World/FlatGeneratorInfo.cpp @@ -0,0 +1,250 @@ +#include "stdafx.h" +#include "StringHelpers.h" +#include "net.minecraft.world.level.levelgen.flat.h" +#include "net.minecraft.world.level.tile.h" +#include "FlatGeneratorInfo.h" + +const wstring FlatGeneratorInfo::STRUCTURE_VILLAGE = L"village"; +const wstring FlatGeneratorInfo::STRUCTURE_BIOME_SPECIFIC = L"biome_1"; +const wstring FlatGeneratorInfo::STRUCTURE_STRONGHOLD = L"stronghold"; +const wstring FlatGeneratorInfo::STRUCTURE_MINESHAFT = L"mineshaft"; +const wstring FlatGeneratorInfo::STRUCTURE_BIOME_DECORATION = L"decoration"; +const wstring FlatGeneratorInfo::STRUCTURE_LAKE = L"lake"; +const wstring FlatGeneratorInfo::STRUCTURE_LAVA_LAKE = L"lava_lake"; +const wstring FlatGeneratorInfo::STRUCTURE_DUNGEON = L"dungeon"; + +FlatGeneratorInfo::FlatGeneratorInfo() +{ + biome = 0; +} + +FlatGeneratorInfo::~FlatGeneratorInfo() +{ + for(AUTO_VAR(it, layers.begin()); it != layers.end(); ++it) + { + delete *it; + } +} + +int FlatGeneratorInfo::getBiome() +{ + return biome; +} + +void FlatGeneratorInfo::setBiome(int biome) +{ + this->biome = biome; +} + +unordered_map > *FlatGeneratorInfo::getStructures() +{ + return &structures; +} + +vector *FlatGeneratorInfo::getLayers() +{ + return &layers; +} + +void FlatGeneratorInfo::updateLayers() +{ + int y = 0; + + for(AUTO_VAR(it, layers.begin()); it != layers.end(); ++it) + { + FlatLayerInfo *layer = *it; + layer->setStart(y); + y += layer->getHeight(); + } +} + +wstring FlatGeneratorInfo::toString() +{ + return L""; +#if 0 + StringBuilder builder = new StringBuilder(); + + builder.append(SERIALIZATION_VERSION); + builder.append(";"); + + for (int i = 0; i < layers.size(); i++) + { + if (i > 0) builder.append(","); + builder.append(layers.get(i).toString()); + } + + builder.append(";"); + builder.append(biome); + + if (!structures.isEmpty()) + { + builder.append(";"); + int structCount = 0; + + for (Map.Entry> structure : structures.entrySet()) + { + if (structCount++ > 0) builder.append(","); + builder.append(structure.getKey().toLowerCase()); + + Map options = structure.getValue(); + if (!options.isEmpty()) + { + builder.append("("); + int optionCount = 0; + + for (Map.Entry option : options.entrySet()) + { + if (optionCount++ > 0) builder.append(" "); + builder.append(option.getKey()); + builder.append("="); + builder.append(option.getValue()); + } + + builder.append(")"); + } + } + } + else + { + builder.append(";"); + } + + return builder.toString(); +#endif +} + +FlatLayerInfo *FlatGeneratorInfo::getLayerFromString(const wstring &input, int yOffset) +{ + return NULL; +#if 0 + std::vector parts = stringSplit(input, L'x'); + + int height = 1; + int id; + int data = 0; + + if (parts.size() == 2) + { + height = _fromString(parts[0]); + if (yOffset + height >= Level::maxBuildHeight) height = Level::maxBuildHeight - yOffset; + if (height < 0) height = 0; + } + + wstring identity = parts[parts.size() - 1]; + parts = stringSplit(identity, L':'); + + id = _fromString(parts[0]); + if (parts.size() > 1) data = _from_String(parts[1]); + + if (Tile::tiles[id] == NULL) + { + id = 0; + data = 0; + } + + if (data < 0 || data > 15) data = 0; + + FlatLayerInfo *result = new FlatLayerInfo(height, id, data); + result->setStart(yOffset); + return result; +#endif +} + +vector *FlatGeneratorInfo::getLayersFromString(const wstring &input) +{ + if (input.empty()) return NULL; + + vector *result = new vector(); + std::vector depths = stringSplit(input, L','); + + int yOffset = 0; + + for(AUTO_VAR(it, depths.begin()); it != depths.end(); ++it) + { + FlatLayerInfo *layer = getLayerFromString(*it, yOffset); + if (layer == NULL) return NULL; + result->push_back(layer); + yOffset += layer->getHeight(); + } + + return result; +} + +FlatGeneratorInfo *FlatGeneratorInfo::fromValue(const wstring &input) +{ + return getDefault(); + +#if 0 + if (input.empty()) return getDefault(); + std::vector parts = stringSplit(input, L';'); + + int version = parts.size() == 1 ? 0 : Mth::getInt(parts[0], 0); + if (version < 0 || version > SERIALIZATION_VERSION) return getDefault(); + + FlatGeneratorInfo *result = new FlatGeneratorInfo(); + int index = parts.size() == 1 ? 0 : 1; + vector *layers = getLayersFromString(parts[index++]); + + if (layers == NULL || layers->isEmpty()) + { + delete layers; + return getDefault(); + } + + result->getLayers()->addAll(layers); + delete layers; + result->updateLayers(); + + int biome = Biome::plains_Id; + if (version > 0 && parts.size() > index) biome = Mth::getInt(parts[index++], biome); + result->setBiome(biome); + + if (version > 0 && parts.size() > index) + { + std::vector structures = stringSplit(parts[index++], L','); + + for(AUTO_VAR(it, structures.begin()); it != structures.end(); ++it) + { + std::vector separated = stringSplit(parts[index++], L"\\("); + + unordered_map structureOptions; + + if (separated[0].length() > 0) + { + (*result->getStructures())[separated[0]] = structureOptions; + + if (separated.size() > 1 && separated[1].endsWith(L")") && separated[1].length() > 1) + { + String[] options = separated[1].substring(0, separated[1].length() - 1).split(" "); + + for (int option = 0; option < options.length; option++) + { + String[] split = options[option].split("=", 2); + if (split.length == 2) structureOptions[split[0]] = split[1]; + } + } + } + } + } + else + { + (* (result->getStructures()) )[STRUCTURE_VILLAGE] = unordered_map(); + } + + return result; +#endif +} + +FlatGeneratorInfo *FlatGeneratorInfo::getDefault() +{ + FlatGeneratorInfo *result = new FlatGeneratorInfo(); + + result->setBiome(Biome::plains->id); + result->getLayers()->push_back(new FlatLayerInfo(1, Tile::unbreakable_Id)); + result->getLayers()->push_back(new FlatLayerInfo(2, Tile::dirt_Id)); + result->getLayers()->push_back(new FlatLayerInfo(1, Tile::grass_Id)); + result->updateLayers(); + (* (result->getStructures()) )[STRUCTURE_VILLAGE] = unordered_map(); + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/FlatGeneratorInfo.h b/Minecraft.World/FlatGeneratorInfo.h new file mode 100644 index 00000000..4fda8e43 --- /dev/null +++ b/Minecraft.World/FlatGeneratorInfo.h @@ -0,0 +1,41 @@ +#pragma once + +class FlatLayerInfo; + +class FlatGeneratorInfo +{ +public: + static const int SERIALIZATION_VERSION = 2; + static const wstring STRUCTURE_VILLAGE; + static const wstring STRUCTURE_BIOME_SPECIFIC; + static const wstring STRUCTURE_STRONGHOLD; + static const wstring STRUCTURE_MINESHAFT; + static const wstring STRUCTURE_BIOME_DECORATION; + static const wstring STRUCTURE_LAKE; + static const wstring STRUCTURE_LAVA_LAKE; + static const wstring STRUCTURE_DUNGEON; + +private: + vector layers; + unordered_map > structures; + int biome; + +public: + FlatGeneratorInfo(); + ~FlatGeneratorInfo(); + + int getBiome(); + void setBiome(int biome); + unordered_map > *getStructures(); + vector *getLayers(); + void updateLayers(); + wstring toString(); + +private: + static FlatLayerInfo *getLayerFromString(const wstring &input, int yOffset); + static vector *getLayersFromString(const wstring &input); + +public: + static FlatGeneratorInfo *fromValue(const wstring &input); + static FlatGeneratorInfo *getDefault(); +}; \ No newline at end of file diff --git a/Minecraft.World/FlatLayerInfo.cpp b/Minecraft.World/FlatLayerInfo.cpp new file mode 100644 index 00000000..4a4d79dd --- /dev/null +++ b/Minecraft.World/FlatLayerInfo.cpp @@ -0,0 +1,78 @@ +#include "stdafx.h" + +#include "FlatLayerInfo.h" + +void FlatLayerInfo::_init(int height, int id) +{ + this->height = height; + this->id = id; + data = 0; + start = 0; +} + +FlatLayerInfo::FlatLayerInfo(int height, int id) +{ + _init(height, id); +} + +FlatLayerInfo::FlatLayerInfo(int height, int id, int data) +{ + _init(height, id); + this->data = data; +} + +int FlatLayerInfo::getHeight() +{ + return height; +} + +void FlatLayerInfo::setHeight(int height) +{ + this->height = height; +} + +int FlatLayerInfo::getId() +{ + return id; +} + +void FlatLayerInfo::setId(int id) +{ + this->id = id; +} + +int FlatLayerInfo::getData() +{ + return data; +} + +void FlatLayerInfo::setData(int data) +{ + this->data = data; +} + +int FlatLayerInfo::getStart() +{ + return start; +} + +void FlatLayerInfo::setStart(int start) +{ + this->start = start; +} + +wstring FlatLayerInfo::toString() +{ + wstring result = _toString(id); + + if (height > 1) + { + result = _toString(height) + L"x" + result; + } + if (data > 0) + { + result += L":" + _toString(data); + } + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/FlatLayerInfo.h b/Minecraft.World/FlatLayerInfo.h new file mode 100644 index 00000000..68096720 --- /dev/null +++ b/Minecraft.World/FlatLayerInfo.h @@ -0,0 +1,26 @@ +#pragma once + +class FlatLayerInfo +{ +private: + int height; + int id; + int data; + int start; + + void _init(int height, int id); + +public: + FlatLayerInfo(int height, int id); + FlatLayerInfo(int height, int id, int data); + + int getHeight(); + void setHeight(int height); + int getId(); + void setId(int id); + int getData(); + void setData(int data); + int getStart(); + void setStart(int start); + wstring toString(); +}; \ No newline at end of file diff --git a/Minecraft.World/FlatLevelSource.cpp b/Minecraft.World/FlatLevelSource.cpp index 6435bfb4..7a31374e 100644 --- a/Minecraft.World/FlatLevelSource.cpp +++ b/Minecraft.World/FlatLevelSource.cpp @@ -20,7 +20,7 @@ FlatLevelSource::FlatLevelSource(Level *level, __int64 seed, bool generateStruct this->random = new Random(seed); this->pprandom = new Random(seed); // 4J - added, so that we can have a separate random for doing post-processing in parallel with creation - villageFeature = new VillageFeature(0,m_XZSize); + villageFeature = new VillageFeature(m_XZSize); } @@ -151,3 +151,8 @@ TilePos *FlatLevelSource::findNearestMapFeature(Level *level, const wstring& fea { return NULL; } + +void FlatLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ) +{ + // TODO +} \ No newline at end of file diff --git a/Minecraft.World/FlatLevelSource.h b/Minecraft.World/FlatLevelSource.h index 804a7b5a..8f8a506d 100644 --- a/Minecraft.World/FlatLevelSource.h +++ b/Minecraft.World/FlatLevelSource.h @@ -41,4 +41,5 @@ public: virtual wstring gatherStats(); virtual vector *getMobsAt(MobCategory *mobCategory, int x, int y, int z); virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ); }; diff --git a/Minecraft.World/FleeSunGoal.cpp b/Minecraft.World/FleeSunGoal.cpp index a9799038..d58ad709 100644 --- a/Minecraft.World/FleeSunGoal.cpp +++ b/Minecraft.World/FleeSunGoal.cpp @@ -6,10 +6,10 @@ #include "net.minecraft.world.phys.h" #include "FleeSunGoal.h" -FleeSunGoal::FleeSunGoal(PathfinderMob *mob, float speed) +FleeSunGoal::FleeSunGoal(PathfinderMob *mob, double speedModifier) { this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; this->level = mob->level; setRequiredControlFlags(Control::MoveControlFlag); } @@ -35,7 +35,7 @@ bool FleeSunGoal::canContinueToUse() void FleeSunGoal::start() { - mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speed); + mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speedModifier); } Vec3 *FleeSunGoal::getHidePos() diff --git a/Minecraft.World/FleeSunGoal.h b/Minecraft.World/FleeSunGoal.h index 9d26c9f6..18f384c4 100644 --- a/Minecraft.World/FleeSunGoal.h +++ b/Minecraft.World/FleeSunGoal.h @@ -7,11 +7,11 @@ class FleeSunGoal : public Goal private: PathfinderMob *mob; // Owner of this goal double wantedX, wantedY, wantedZ; - float speed; + double speedModifier; Level *level; public: - FleeSunGoal(PathfinderMob *mob, float speed); + FleeSunGoal(PathfinderMob *mob, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/FlintAndSteelItem.cpp b/Minecraft.World/FlintAndSteelItem.cpp index 5ebdad2b..18f6bb18 100644 --- a/Minecraft.World/FlintAndSteelItem.cpp +++ b/Minecraft.World/FlintAndSteelItem.cpp @@ -25,7 +25,7 @@ bool FlintAndSteelItem::useOn(shared_ptr instance, shared_ptrmayBuild(x, y, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, instance)) return false; int targetType = level->getTile(x, y, z); @@ -47,11 +47,11 @@ bool FlintAndSteelItem::useOn(shared_ptr instance, shared_ptrplaySound(x + 0.5, y + 0.5, z + 0.5, eSoundType_FIRE_IGNITE, 1, random->nextFloat() * 0.4f + 0.8f); - level->setTile(x, y, z, Tile::fire_Id); + level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_FIRE_NEWIGNITE, 1, random->nextFloat() * 0.4f + 0.8f); + level->setTileAndUpdate(x, y, z, Tile::fire_Id); } - instance->hurt(1, player); + instance->hurtAndBreak(1, player); } else { diff --git a/Minecraft.World/FloatTag.h b/Minecraft.World/FloatTag.h index 266db4d3..80301649 100644 --- a/Minecraft.World/FloatTag.h +++ b/Minecraft.World/FloatTag.h @@ -10,7 +10,7 @@ public: FloatTag(const wstring &name, float data) : Tag(name) {this->data = data; } void write(DataOutput *dos) { dos->writeFloat(data); } - void load(DataInput *dis) { data = dis->readFloat(); } + void load(DataInput *dis, int tagDepth) { data = dis->readFloat(); } byte getId() { return TAG_Float; } wstring toString() diff --git a/Minecraft.World/FlowerFeature.cpp b/Minecraft.World/FlowerFeature.cpp index 3fd8bac4..f24d61bf 100644 --- a/Minecraft.World/FlowerFeature.cpp +++ b/Minecraft.World/FlowerFeature.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.dimension.h" #include "FlowerFeature.h" #include "net.minecraft.world.level.tile.h" @@ -22,19 +23,19 @@ bool FlowerFeature::place(Level *level, Random *random, int x, int y, int z) } } - for (int i = 0; i < 64; i++) + for (int i = 0; i < 64; i++) { - int x2 = x + random->nextInt(8) - random->nextInt(8); - int y2 = y + random->nextInt(4) - random->nextInt(4); - int z2 = z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(x2, y2, z2)) + int x2 = x + random->nextInt(8) - random->nextInt(8); + int y2 = y + random->nextInt(4) - random->nextInt(4); + int z2 = z + random->nextInt(8) - random->nextInt(8); + if (level->isEmptyTile(x2, y2, z2) && (!level->dimension->hasCeiling || y2 < Level::genDepthMinusOne)) { - if (Tile::tiles[tile]->canSurvive(level, x2, y2, z2)) + if (Tile::tiles[tile]->canSurvive(level, x2, y2, z2)) { - level->setTileNoUpdate(x2, y2, z2, tile); - } - } - } + level->setTileAndData(x2, y2, z2, tile, 0, Tile::UPDATE_CLIENTS); + } + } + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/FlowerPotTile.cpp b/Minecraft.World/FlowerPotTile.cpp index b245e56d..4cdd529c 100644 --- a/Minecraft.World/FlowerPotTile.cpp +++ b/Minecraft.World/FlowerPotTile.cpp @@ -42,7 +42,7 @@ bool FlowerPotTile::use(Level *level, int x, int y, int z, shared_ptr pl if (type > 0) { - level->setData(x, y, z, type); + level->setData(x, y, z, type, Tile::UPDATE_CLIENTS); if (!player->abilities.instabuild) { @@ -102,7 +102,7 @@ void FlowerPotTile::neighborChanged(Level *level, int x, int y, int z, int type) { spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); } } @@ -133,9 +133,9 @@ shared_ptr FlowerPotTile::getItemFromType(int type) case TYPE_CACTUS: return shared_ptr( new ItemInstance(Tile::cactus) ); case TYPE_MUSHROOM_BROWN: - return shared_ptr( new ItemInstance(Tile::mushroom1) ); + return shared_ptr( new ItemInstance(Tile::mushroom_brown) ); case TYPE_MUSHROOM_RED: - return shared_ptr( new ItemInstance(Tile::mushroom2) ); + return shared_ptr( new ItemInstance(Tile::mushroom_red) ); case TYPE_DEAD_BUSH: return shared_ptr( new ItemInstance(Tile::deadBush) ); case TYPE_SAPLING_DEFAULT: @@ -160,8 +160,8 @@ int FlowerPotTile::getTypeFromItem(shared_ptr item) if (id == Tile::rose_Id) return TYPE_FLOWER_RED; if (id == Tile::flower_Id) return TYPE_FLOWER_YELLOW; if (id == Tile::cactus_Id) return TYPE_CACTUS; - if (id == Tile::mushroom1_Id) return TYPE_MUSHROOM_BROWN; - if (id == Tile::mushroom2_Id) return TYPE_MUSHROOM_RED; + if (id == Tile::mushroom_brown_Id) return TYPE_MUSHROOM_BROWN; + if (id == Tile::mushroom_red_Id) return TYPE_MUSHROOM_RED; if (id == Tile::deadBush_Id) return TYPE_DEAD_BUSH; if (id == Tile::sapling_Id) diff --git a/Minecraft.World/FlyingMob.cpp b/Minecraft.World/FlyingMob.cpp index b7a01678..1757ae58 100644 --- a/Minecraft.World/FlyingMob.cpp +++ b/Minecraft.World/FlyingMob.cpp @@ -14,6 +14,12 @@ void FlyingMob::causeFallDamage(float distance) // not trigger the "fallOn" tile calls (such as trampling crops) } +void FlyingMob::checkFallDamage(double ya, bool onGround) +{ + // this method is empty because flying creatures should + // not trigger the "fallOn" tile calls (such as trampling crops) +} + void FlyingMob::travel(float xa, float ya) { if (isInWater()) diff --git a/Minecraft.World/FlyingMob.h b/Minecraft.World/FlyingMob.h index f3bb2a03..ac45e97f 100644 --- a/Minecraft.World/FlyingMob.h +++ b/Minecraft.World/FlyingMob.h @@ -11,6 +11,7 @@ public: protected: virtual void causeFallDamage(float distance); + virtual void checkFallDamage(double ya, bool onGround); public: virtual void travel(float xa, float ya); diff --git a/Minecraft.World/FollowOwnerGoal.cpp b/Minecraft.World/FollowOwnerGoal.cpp index faba2226..8565d782 100644 --- a/Minecraft.World/FollowOwnerGoal.cpp +++ b/Minecraft.World/FollowOwnerGoal.cpp @@ -7,16 +7,16 @@ #include "net.minecraft.world.phys.h" #include "FollowOwnerGoal.h" -FollowOwnerGoal::FollowOwnerGoal(TamableAnimal *tamable, float speed, float startDistance, float stopDistance) +FollowOwnerGoal::FollowOwnerGoal(TamableAnimal *tamable, double speedModifier, float startDistance, float stopDistance) { owner = weak_ptr(); timeToRecalcPath = 0; oldAvoidWater = false; this->tamable = tamable; - this->level = tamable->level; - this->speed = speed; - this->navigation = tamable->getNavigation(); + level = tamable->level; + this->speedModifier = speedModifier; + navigation = tamable->getNavigation(); this->startDistance = startDistance; this->stopDistance = stopDistance; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); @@ -24,11 +24,11 @@ FollowOwnerGoal::FollowOwnerGoal(TamableAnimal *tamable, float speed, float star bool FollowOwnerGoal::canUse() { - shared_ptr owner = tamable->getOwner(); + shared_ptr owner = dynamic_pointer_cast( tamable->getOwner() ); if (owner == NULL) return false; if (tamable->isSitting()) return false; if (tamable->distanceToSqr(owner) < startDistance * startDistance) return false; - this->owner = weak_ptr(owner); + this->owner = weak_ptr(owner); return true; } @@ -59,7 +59,8 @@ void FollowOwnerGoal::tick() if (--timeToRecalcPath > 0) return; timeToRecalcPath = 10; - if (navigation->moveTo(owner.lock(), speed)) return; + if (navigation->moveTo(owner.lock(), speedModifier)) return; + if (tamable->isLeashed()) return; if (tamable->distanceToSqr(owner.lock()) < TeleportDistance * TeleportDistance) return; // find a good spawn position nearby the owner diff --git a/Minecraft.World/FollowOwnerGoal.h b/Minecraft.World/FollowOwnerGoal.h index e7b598fa..09cb0edc 100644 --- a/Minecraft.World/FollowOwnerGoal.h +++ b/Minecraft.World/FollowOwnerGoal.h @@ -12,16 +12,16 @@ public: private: TamableAnimal *tamable; // Owner of this goal - weak_ptr owner; + weak_ptr owner; Level *level; - float speed; + double speedModifier; PathNavigation *navigation; int timeToRecalcPath; float stopDistance, startDistance; bool oldAvoidWater; public: - FollowOwnerGoal(TamableAnimal *tamable, float speed, float startDistance, float stopDistance); + FollowOwnerGoal(TamableAnimal *tamable, double speedModifier, float startDistance, float stopDistance); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/FollowParentGoal.cpp b/Minecraft.World/FollowParentGoal.cpp index 3e347d62..61c5614a 100644 --- a/Minecraft.World/FollowParentGoal.cpp +++ b/Minecraft.World/FollowParentGoal.cpp @@ -6,12 +6,12 @@ #include "BasicTypeContainers.h" #include "FollowParentGoal.h" -FollowParentGoal::FollowParentGoal(Animal *animal, float speed) +FollowParentGoal::FollowParentGoal(Animal *animal, double speedModifier) { timeToRecalcPath = 0; this->animal = animal; - this->speed = speed; + this->speedModifier = speedModifier; } bool FollowParentGoal::canUse() @@ -61,5 +61,5 @@ void FollowParentGoal::tick() { if (--timeToRecalcPath > 0) return; timeToRecalcPath = 10; - animal->getNavigation()->moveTo(parent.lock(), speed); + animal->getNavigation()->moveTo(parent.lock(), speedModifier); } \ No newline at end of file diff --git a/Minecraft.World/FollowParentGoal.h b/Minecraft.World/FollowParentGoal.h index 0aa64bbf..40b828dc 100644 --- a/Minecraft.World/FollowParentGoal.h +++ b/Minecraft.World/FollowParentGoal.h @@ -9,11 +9,11 @@ class FollowParentGoal : public Goal private: Animal *animal; // Owner of this goal weak_ptr parent; - float speed; + double speedModifier; int timeToRecalcPath; public: - FollowParentGoal(Animal *animal, float speed); + FollowParentGoal(Animal *animal, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/FoodConstants.cpp b/Minecraft.World/FoodConstants.cpp index a05b21c8..6ced45d5 100644 --- a/Minecraft.World/FoodConstants.cpp +++ b/Minecraft.World/FoodConstants.cpp @@ -25,6 +25,7 @@ const float FoodConstants::FOOD_SATURATION_MAX = 1.0f; const float FoodConstants::FOOD_SATURATION_SUPERNATURAL = 1.2f; // some exhaustion guidelines +const float FoodConstants::EXHAUSTION_HEAL = 3.0f; const float FoodConstants::EXHAUSTION_JUMP = .2f; const float FoodConstants::EXHAUSTION_SPRINT_JUMP = FoodConstants::EXHAUSTION_JUMP * 4; const float FoodConstants::EXHAUSTION_MINE = .025f; diff --git a/Minecraft.World/FoodConstants.h b/Minecraft.World/FoodConstants.h index 6f80b041..cc4620cb 100644 --- a/Minecraft.World/FoodConstants.h +++ b/Minecraft.World/FoodConstants.h @@ -3,35 +3,36 @@ class FoodConstants { public: - static const int MAX_FOOD; - static const float MAX_SATURATION; - static const float START_SATURATION; - static const float SATURATION_FLOOR; + static const int MAX_FOOD; + static const float MAX_SATURATION; + static const float START_SATURATION; + static const float SATURATION_FLOOR; - // this value modifies how quickly food is dropped - static const float EXHAUSTION_DROP; + // this value modifies how quickly food is dropped + static const float EXHAUSTION_DROP; - // number of game ticks to change health because of food - static const int HEALTH_TICK_COUNT; + // number of game ticks to change health because of food + static const int HEALTH_TICK_COUNT; - static const int HEAL_LEVEL; - static const int STARVE_LEVEL; + static const int HEAL_LEVEL; + static const int STARVE_LEVEL; - // some saturation guidelines - static const float FOOD_SATURATION_POOR; - static const float FOOD_SATURATION_LOW; - static const float FOOD_SATURATION_NORMAL; - static const float FOOD_SATURATION_GOOD; - static const float FOOD_SATURATION_MAX; - static const float FOOD_SATURATION_SUPERNATURAL; + // some saturation guidelines + static const float FOOD_SATURATION_POOR; + static const float FOOD_SATURATION_LOW; + static const float FOOD_SATURATION_NORMAL; + static const float FOOD_SATURATION_GOOD; + static const float FOOD_SATURATION_MAX; + static const float FOOD_SATURATION_SUPERNATURAL; - // some exhaustion guidelines - static const float EXHAUSTION_JUMP; - static const float EXHAUSTION_SPRINT_JUMP; - static const float EXHAUSTION_MINE; - static const float EXHAUSTION_ATTACK; - static const float EXHAUSTION_DAMAGE; - static const float EXHAUSTION_WALK; - static const float EXHAUSTION_SPRINT; - static const float EXHAUSTION_SWIM; + // some exhaustion guidelines + static const float EXHAUSTION_HEAL; + static const float EXHAUSTION_JUMP; + static const float EXHAUSTION_SPRINT_JUMP; + static const float EXHAUSTION_MINE; + static const float EXHAUSTION_ATTACK; + static const float EXHAUSTION_DAMAGE; + static const float EXHAUSTION_WALK; + static const float EXHAUSTION_SPRINT; + static const float EXHAUSTION_SWIM; }; \ No newline at end of file diff --git a/Minecraft.World/FoodData.cpp b/Minecraft.World/FoodData.cpp index 79ef0fc1..ab0ced84 100644 --- a/Minecraft.World/FoodData.cpp +++ b/Minecraft.World/FoodData.cpp @@ -13,9 +13,9 @@ FoodData::FoodData() exhaustionLevel = 0; tickTimer = 0; - this->foodLevel = FoodConstants::MAX_FOOD; - this->lastFoodLevel = FoodConstants::MAX_FOOD; - this->saturationLevel = FoodConstants::START_SATURATION; + foodLevel = FoodConstants::MAX_FOOD; + lastFoodLevel = FoodConstants::MAX_FOOD; + saturationLevel = FoodConstants::START_SATURATION; } void FoodData::eat(int food, float saturationModifier) @@ -50,9 +50,9 @@ void FoodData::tick(shared_ptr player) } } - // 4J Added - Allow host to disable using hunger. We don't deplete the hunger bar due to exhaustion - // but I think we should deplete it to heal - if(player->isAllowedToIgnoreExhaustion()) + // 4J: Added - Allow host to disable using hunger. We don't deplete the hunger bar due to exhaustion + // but I think we should deplete it to heal. Don't heal if natural regen is disabled + if(player->isAllowedToIgnoreExhaustion() && player->level->getGameRules()->getBoolean(GameRules::RULE_NATURAL_REGENERATION)) { if(foodLevel > 0 && player->isHurt()) { @@ -65,12 +65,13 @@ void FoodData::tick(shared_ptr player) } } } - else if (foodLevel >= FoodConstants::HEAL_LEVEL && player->isHurt()) + else if (player->level->getGameRules()->getBoolean(GameRules::RULE_NATURAL_REGENERATION) && foodLevel >= FoodConstants::HEAL_LEVEL && player->isHurt()) { tickTimer++; if (tickTimer >= FoodConstants::HEALTH_TICK_COUNT) { player->heal(1); + addExhaustion(FoodConstants::EXHAUSTION_HEAL); tickTimer = 0; } } @@ -145,15 +146,15 @@ float FoodData::getSaturationLevel() void FoodData::setFoodLevel(int food) { - this->foodLevel = food; + foodLevel = food; } void FoodData::setSaturation(float saturation) { - this->saturationLevel = saturation; + saturationLevel = saturation; } void FoodData::setExhaustion(float exhaustion) { - this->exhaustionLevel = exhaustion; + exhaustionLevel = exhaustion; } \ No newline at end of file diff --git a/Minecraft.World/FoodItem.cpp b/Minecraft.World/FoodItem.cpp index f5304cb9..557404cb 100644 --- a/Minecraft.World/FoodItem.cpp +++ b/Minecraft.World/FoodItem.cpp @@ -38,7 +38,7 @@ shared_ptr FoodItem::useTimeDepleted(shared_ptr inst instance->count--; player->getFoodData()->eat(this); // 4J - new sound brought forward from 1.2.3 - level->playSound(player, eSoundType_RANDOM_BURP, 0.5f, level->random->nextFloat() * 0.1f + 0.9f); + level->playEntitySound(player, eSoundType_RANDOM_BURP, 0.5f, level->random->nextFloat() * 0.1f + 0.9f); addEatEffect(instance, level, player); diff --git a/Minecraft.World/FoodRecipies.cpp b/Minecraft.World/FoodRecipies.cpp index 1497cd41..e78700f4 100644 --- a/Minecraft.World/FoodRecipies.cpp +++ b/Minecraft.World/FoodRecipies.cpp @@ -14,38 +14,31 @@ void FoodRecipies::addRecipes(Recipes *r) L"###", // L"#X#", // L"###", // - L'#', Item::goldNugget, L'X', Item::apple, + L'#', Item::goldIngot, L'X', Item::apple, + L'F'); + + r->addShapedRecipy(new ItemInstance(Item::apple_gold, 1, 1), // + L"sssctcig", + L"###", // + L"#X#", // + L"###", // + L'#', Tile::goldBlock, L'X', Item::apple, + L'F'); + + r->addShapedRecipy(new ItemInstance(Item::speckledMelon, 1), // + L"ssscicig", + L"###", // + L"#X#", // + L"###", // + + L'#', Item::goldNugget, L'X', Item::melon, L'F'); - // 4J-PB - Moving the mushroom stew shaped->shapeless forward from 1.9, so it will not need the crafting table r->addShapelessRecipy(new ItemInstance(Item::mushroomStew), L"ttig", - Tile::mushroom1, Tile::mushroom2, Item::bowl, + Tile::mushroom_brown, Tile::mushroom_red, Item::bowl, L'F'); - - /*r->addShapedRecipy(new ItemInstance(Item::mushroomStew), // - L"sssctctcig", - L"Y", // - L"X", // - L"#", // - - L'X', Tile::mushroom1, - L'Y', Tile::mushroom2, - L'#', Item::bowl, - L'F');*/ - - // 4J-PB - removing for the xbox game - we already have it above -// r->addShapedRecipy(new ItemInstance(Item::mushroomStew), // -// L"sssctctcig", -// L"Y", // -// L"X", // -// L"#", // -// -// L'X', Tile::mushroom2, -// L'Y', Tile::mushroom1, -// L'#', Item::bowl, -// L'F'); -// + r->addShapedRecipy(new ItemInstance(Item::cookie, 8), // L"sczcig", L"#X#", // @@ -82,14 +75,6 @@ void FoodRecipies::addRecipes(Recipes *r) Tile::pumpkin, Item::sugar, Item::egg, L'F'); - r->addShapedRecipy(new ItemInstance(Item::apple_gold, 1, 1), // - L"sssctcig", - L"###", // - L"#X#", // - L"###", // - L'#', Tile::goldBlock, L'X', Item::apple, - L'F'); - r->addShapedRecipy(new ItemInstance(Item::carrotGolden, 1, 0), // L"ssscicig", L"###", // @@ -101,12 +86,7 @@ void FoodRecipies::addRecipes(Recipes *r) r->addShapelessRecipy(new ItemInstance(Item::fermentedSpiderEye), // L"itig", - Item::spiderEye, Tile::mushroom1, Item::sugar, - L'F'); - - r->addShapelessRecipy(new ItemInstance(Item::speckledMelon), // - L"iig", - Item::melon, Item::goldNugget, + Item::spiderEye, Tile::mushroom_brown, Item::sugar, L'F'); r->addShapelessRecipy(new ItemInstance(Item::blazePowder, 2), // diff --git a/Minecraft.World/FurnaceMenu.cpp b/Minecraft.World/FurnaceMenu.cpp index dca02231..2a6ebc63 100644 --- a/Minecraft.World/FurnaceMenu.cpp +++ b/Minecraft.World/FurnaceMenu.cpp @@ -45,8 +45,8 @@ void FurnaceMenu::broadcastChanges() { AbstractContainerMenu::broadcastChanges(); - AUTO_VAR(itEnd, containerListeners->end()); - for (AUTO_VAR(it, containerListeners->begin()); it != itEnd; it++) + AUTO_VAR(itEnd, containerListeners.end()); + for (AUTO_VAR(it, containerListeners.begin()); it != itEnd; it++) { ContainerListener *listener = *it; //containerListeners->at(i); if (tc != furnace->tickCount) @@ -83,7 +83,7 @@ bool FurnaceMenu::stillValid(shared_ptr player) shared_ptr FurnaceMenu::quickMoveStack(shared_ptr player, int slotIndex) { shared_ptr clicked = nullptr; - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); //Slot *IngredientSlot = slots->at(INGREDIENT_SLOT); bool charcoalUsed = furnace->wasCharcoalUsed(); @@ -160,11 +160,11 @@ shared_ptr FurnaceMenu::quickMoveStack(shared_ptr player, return clicked; } -shared_ptr FurnaceMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player) +shared_ptr FurnaceMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player, bool looped) // 4J Added looped param { bool charcoalUsed = furnace->wasCharcoalUsed(); - shared_ptr out = AbstractContainerMenu::clicked(slotIndex, buttonNum, clickType, player); + shared_ptr out = AbstractContainerMenu::clicked(slotIndex, buttonNum, clickType, player, looped); #ifdef _EXTENDED_ACHIEVEMENTS if ( charcoalUsed && (out!=nullptr) && (buttonNum==0 || buttonNum==1) && clickType==CLICK_PICKUP diff --git a/Minecraft.World/FurnaceMenu.h b/Minecraft.World/FurnaceMenu.h index 72b264d3..6eaf98e6 100644 --- a/Minecraft.World/FurnaceMenu.h +++ b/Minecraft.World/FurnaceMenu.h @@ -34,5 +34,6 @@ public: virtual bool stillValid(shared_ptr player); virtual shared_ptr quickMoveStack(shared_ptr player, int slotIndex); - virtual shared_ptr clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player); + // 4J Added looped param + virtual shared_ptr clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player, bool looped = false); }; diff --git a/Minecraft.World/FurnaceRecipes.cpp b/Minecraft.World/FurnaceRecipes.cpp index 49ded1f5..af59884c 100644 --- a/Minecraft.World/FurnaceRecipes.cpp +++ b/Minecraft.World/FurnaceRecipes.cpp @@ -25,14 +25,14 @@ FurnaceRecipes::FurnaceRecipes() addFurnaceRecipy(Item::beef_raw_Id, new ItemInstance(Item::beef_cooked), .35f); addFurnaceRecipy(Item::chicken_raw_Id, new ItemInstance(Item::chicken_cooked), .35f); addFurnaceRecipy(Item::fish_raw_Id, new ItemInstance(Item::fish_cooked), .35f); - addFurnaceRecipy(Tile::stoneBrick_Id, new ItemInstance(Tile::rock), .1f); + addFurnaceRecipy(Tile::cobblestone_Id, new ItemInstance(Tile::stone), .1f); addFurnaceRecipy(Item::clay_Id, new ItemInstance(Item::brick), .3f); + addFurnaceRecipy(Tile::clay_Id, new ItemInstance(Tile::clayHardened), .35f); addFurnaceRecipy(Tile::cactus_Id, new ItemInstance(Item::dye_powder, 1, DyePowderItem::GREEN), .2f); addFurnaceRecipy(Tile::treeTrunk_Id, new ItemInstance(Item::coal, 1, CoalItem::CHAR_COAL), .15f); addFurnaceRecipy(Tile::emeraldOre_Id, new ItemInstance(Item::emerald), 1); addFurnaceRecipy(Item::potato_Id, new ItemInstance(Item::potatoBaked), .35f); - // 4J - TU9 - add in smelting netherrack - addFurnaceRecipy(Tile::hellRock_Id, new ItemInstance(Item::netherbrick), .1f); + addFurnaceRecipy(Tile::netherRack_Id, new ItemInstance(Item::netherbrick), .1f); // special silk touch related recipes: addFurnaceRecipy(Tile::coalOre_Id, new ItemInstance(Item::coal), .1f); diff --git a/Minecraft.World/FurnaceTile.cpp b/Minecraft.World/FurnaceTile.cpp index ea0f84e8..d22d6ca7 100644 --- a/Minecraft.World/FurnaceTile.cpp +++ b/Minecraft.World/FurnaceTile.cpp @@ -3,6 +3,7 @@ #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.inventory.h" #include "net.minecraft.world.level.tile.entity.h" #include "net.minecraft.world.h" #include "FurnaceTile.h" @@ -11,7 +12,7 @@ bool FurnaceTile::noDrop = false; -FurnaceTile::FurnaceTile(int id, bool lit) : EntityTile(id, Material::stone) +FurnaceTile::FurnaceTile(int id, bool lit) : BaseEntityTile(id, Material::stone) { random = new Random(); this->lit = lit; @@ -27,7 +28,7 @@ int FurnaceTile::getResource(int data, Random *random, int playerBonusLevel) void FurnaceTile::onPlace(Level *level, int x, int y, int z) { - EntityTile::onPlace(level, x, y, z); + BaseEntityTile::onPlace(level, x, y, z); recalcLockDir(level, x, y, z); } @@ -48,7 +49,7 @@ void FurnaceTile::recalcLockDir(Level *level, int x, int y, int z) if (Tile::solid[s] && !Tile::solid[n]) lockDir = 2; if (Tile::solid[w] && !Tile::solid[e]) lockDir = 5; if (Tile::solid[e] && !Tile::solid[w]) lockDir = 4; - level->setData(x, y, z, lockDir); + level->setData(x, y, z, lockDir, Tile::UPDATE_CLIENTS); } Icon *FurnaceTile::getTexture(int face, int data) @@ -83,15 +84,18 @@ void FurnaceTile::animateTick(Level *level, int xt, int yt, int zt, Random *rand { level->addParticle(eParticleType_smoke, x - r, y, z + ss, 0, 0, 0); level->addParticle(eParticleType_flame, x - r, y, z + ss, 0, 0, 0); - } else if (dir == 5) + } + else if (dir == 5) { level->addParticle(eParticleType_smoke, x + r, y, z + ss, 0, 0, 0); level->addParticle(eParticleType_flame, x + r, y, z + ss, 0, 0, 0); - } else if (dir == 2) + } + else if (dir == 2) { level->addParticle(eParticleType_smoke, x + ss, y, z - r, 0, 0, 0); level->addParticle(eParticleType_flame, x + ss, y, z - r, 0, 0, 0); - } else if (dir == 3) + } + else if (dir == 3) { level->addParticle(eParticleType_smoke, x + ss, y, z + r, 0, 0, 0); level->addParticle(eParticleType_flame, x + ss, y, z + r, 0, 0, 0); @@ -123,11 +127,11 @@ void FurnaceTile::setLit(bool lit, Level *level, int x, int y, int z) shared_ptr te = level->getTileEntity(x, y, z); noDrop = true; - if (lit) level->setTile(x, y, z, Tile::furnace_lit_Id); - else level->setTile(x, y, z, Tile::furnace_Id); + if (lit) level->setTileAndUpdate(x, y, z, Tile::furnace_lit_Id); + else level->setTileAndUpdate(x, y, z, Tile::furnace_Id); noDrop = false; - level->setData(x, y, z, data); + level->setData(x, y, z, data, Tile::UPDATE_CLIENTS); if( te != NULL ) { te->clearRemoved(); @@ -140,14 +144,19 @@ shared_ptr FurnaceTile::newTileEntity(Level *level) return shared_ptr( new FurnaceTileEntity() ); } -void FurnaceTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void FurnaceTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { int dir = (Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3; - if (dir == 0) level->setData(x, y, z, Facing::NORTH); - if (dir == 1) level->setData(x, y, z, Facing::EAST); - if (dir == 2) level->setData(x, y, z, Facing::SOUTH); - if (dir == 3) level->setData(x, y, z, Facing::WEST); + if (dir == 0) level->setData(x, y, z, Facing::NORTH, Tile::UPDATE_CLIENTS); + if (dir == 1) level->setData(x, y, z, Facing::EAST, Tile::UPDATE_CLIENTS); + if (dir == 2) level->setData(x, y, z, Facing::SOUTH, Tile::UPDATE_CLIENTS); + if (dir == 3) level->setData(x, y, z, Facing::WEST, Tile::UPDATE_CLIENTS); + + if (itemInstance->hasCustomHoverName()) + { + dynamic_pointer_cast( level->getTileEntity(x, y, z))->setCustomName(itemInstance->getHoverName()); + } } void FurnaceTile::onRemove(Level *level, int x, int y, int z, int id, int data) @@ -201,8 +210,24 @@ void FurnaceTile::onRemove(Level *level, int x, int y, int z, int id, int data) container->setItem(i,nullptr); } } + level->updateNeighbourForOutputSignal(x, y, z, id); } } - EntityTile::onRemove(level, x, y, z, id, data); + BaseEntityTile::onRemove(level, x, y, z, id, data); + +} +bool FurnaceTile::hasAnalogOutputSignal() +{ + return true; +} + +int FurnaceTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + return AbstractContainerMenu::getRedstoneSignalFromContainer(dynamic_pointer_cast( level->getTileEntity(x, y, z)) ); } + +int FurnaceTile::cloneTileId(Level *level, int x, int y, int z) +{ + return Tile::furnace_Id; +} \ No newline at end of file diff --git a/Minecraft.World/FurnaceTile.h b/Minecraft.World/FurnaceTile.h index c192f94d..a868863f 100644 --- a/Minecraft.World/FurnaceTile.h +++ b/Minecraft.World/FurnaceTile.h @@ -1,19 +1,19 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" class Mob; class Player; class Random; class ChunkRebuildData; -class FurnaceTile : public EntityTile +class FurnaceTile : public BaseEntityTile { friend class Tile; friend class ChunkRebuildData; private: Random *random; - bool lit; - static bool noDrop; + bool lit; + static bool noDrop; Icon *iconTop; Icon *iconFront; @@ -21,19 +21,23 @@ protected: FurnaceTile(int id, bool lit); public: virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual void onPlace(Level *level, int x, int y, int z); + virtual void onPlace(Level *level, int x, int y, int z); private: void recalcLockDir(Level *level, int x, int y, int z); public: Icon *getTexture(int face, int data); - void registerIcons(IconRegister *iconRegister); - virtual void animateTick(Level *level, int xt, int yt, int zt, Random *random); + void registerIcons(IconRegister *iconRegister); + virtual void animateTick(Level *level, int xt, int yt, int zt, Random *random); virtual bool TestUse(); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - static void setLit(bool lit, Level *level, int x, int y, int z); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + static void setLit(bool lit, Level *level, int x, int y, int z); protected: virtual shared_ptr newTileEntity(Level *level); public: - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); + virtual int cloneTileId(Level *level, int x, int y, int z); }; \ No newline at end of file diff --git a/Minecraft.World/FurnaceTileEntity.cpp b/Minecraft.World/FurnaceTileEntity.cpp index 0f18528c..a11e8527 100644 --- a/Minecraft.World/FurnaceTileEntity.cpp +++ b/Minecraft.World/FurnaceTileEntity.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "com.mojang.nbt.h" +#include "net.minecraft.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.item.crafting.h" @@ -8,40 +9,43 @@ #include "Material.h" #include "FurnaceTileEntity.h" +int furnaceSlotsForUp [] = { FurnaceTileEntity::SLOT_INPUT }; +int furnaceSlotsForDown [] = { FurnaceTileEntity::SLOT_RESULT, FurnaceTileEntity::SLOT_FUEL }; +int furnaceSlotsForSides [] = { FurnaceTileEntity::SLOT_FUEL }; +const intArray FurnaceTileEntity::SLOTS_FOR_UP = intArray(furnaceSlotsForUp, 1); +const intArray FurnaceTileEntity::SLOTS_FOR_DOWN = intArray(furnaceSlotsForDown, 2); +const intArray FurnaceTileEntity::SLOTS_FOR_SIDES = intArray(furnaceSlotsForSides, 1); const int FurnaceTileEntity::BURN_INTERVAL = 10 * 20; // 4J Stu - Need a ctor to initialise member variables FurnaceTileEntity::FurnaceTileEntity() : TileEntity() { - items = new ItemInstanceArray(3); + items = ItemInstanceArray(3); litTime = 0; - litDuration = 0; - tickCount = 0; - m_charcoalUsed = false; + name = L""; } FurnaceTileEntity::~FurnaceTileEntity() { - delete[] items->data; - delete items; + delete[] items.data; } unsigned int FurnaceTileEntity::getContainerSize() { - return items->length; + return items.length; } shared_ptr FurnaceTileEntity::getItem(unsigned int slot) { - return (*items)[slot]; + return items[slot]; } @@ -49,20 +53,20 @@ shared_ptr FurnaceTileEntity::removeItem(unsigned int slot, int co { m_charcoalUsed = false; - if ((*items)[slot] != NULL) + if (items[slot] != NULL) { - if ((*items)[slot]->count <= count) + if (items[slot]->count <= count) { - shared_ptr item = (*items)[slot]; - (*items)[slot] = nullptr; + shared_ptr item = items[slot]; + items[slot] = nullptr; // 4J Stu - Fix for duplication glitch if(item->count <= 0) return nullptr; return item; } else { - shared_ptr i = (*items)[slot]->remove(count); - if ((*items)[slot]->count == 0) (*items)[slot] = nullptr; + shared_ptr i = items[slot]->remove(count); + if (items[slot]->count == 0) items[slot] = nullptr; // 4J Stu - Fix for duplication glitch if(i->count <= 0) return nullptr; return i; @@ -75,10 +79,10 @@ shared_ptr FurnaceTileEntity::removeItemNoUpdate(int slot) { m_charcoalUsed = false; - if (items->data[slot] != NULL) + if (items[slot] != NULL) { - shared_ptr item = items->data[slot]; - items->data[slot] = nullptr; + shared_ptr item = items[slot]; + items[slot] = nullptr; return item; } return nullptr; @@ -87,32 +91,48 @@ shared_ptr FurnaceTileEntity::removeItemNoUpdate(int slot) void FurnaceTileEntity::setItem(unsigned int slot, shared_ptr item) { - (*items)[slot] = item; + items[slot] = item; if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); } -int FurnaceTileEntity::getName() +wstring FurnaceTileEntity::getName() +{ + return hasCustomName() ? name : app.GetString(IDS_TILE_FURNACE); +} + +wstring FurnaceTileEntity::getCustomName() { - return IDS_TILE_FURNACE; + return hasCustomName() ? name : L""; +} + +bool FurnaceTileEntity::hasCustomName() +{ + return !name.empty(); +} + +void FurnaceTileEntity::setCustomName(const wstring &name) +{ + this->name = name; } void FurnaceTileEntity::load(CompoundTag *base) { TileEntity::load(base); ListTag *inventoryList = (ListTag *) base->getList(L"Items"); - items = new ItemInstanceArray(getContainerSize()); + delete[] items.data; + items = ItemInstanceArray(getContainerSize()); for (int i = 0; i < inventoryList->size(); i++) { CompoundTag *tag = inventoryList->get(i); unsigned int slot = tag->getByte(L"Slot"); - if (slot >= 0 && slot < items->length) (*items)[slot] = ItemInstance::fromTag(tag); + if (slot >= 0 && slot < items.length) items[slot] = ItemInstance::fromTag(tag); } litTime = base->getShort(L"BurnTime"); tickCount = base->getShort(L"CookTime"); - litDuration = getBurnDuration((*items)[FUEL_SLOT]); - + litDuration = getBurnDuration(items[SLOT_FUEL]); + if (base->contains(L"CustomName")) name = base->getString(L"CustomName"); m_charcoalUsed = base->getBoolean(L"CharcoalUsed"); } @@ -124,18 +144,18 @@ void FurnaceTileEntity::save(CompoundTag *base) base->putShort(L"CookTime", (short) (tickCount)); ListTag *listTag = new ListTag(); - for (unsigned int i = 0; i < items->length; i++) + for (unsigned int i = 0; i < items.length; i++) { - if ((*items)[i] != NULL) + if (items[i] != NULL) { CompoundTag *tag = new CompoundTag(); tag->putByte(L"Slot", (byte) i); - (*items)[i]->save(tag); + items[i]->save(tag); listTag->add(tag); } } base->put(L"Items", listTag); - + if (hasCustomName()) base->putString(L"CustomName", name); base->putBoolean(L"CharcoalUsed", m_charcoalUsed); } @@ -178,24 +198,24 @@ void FurnaceTileEntity::tick() { if (litTime == 0 && canBurn()) { - litDuration = litTime = getBurnDuration((*items)[FUEL_SLOT]); + litDuration = litTime = getBurnDuration(items[SLOT_FUEL]); if (litTime > 0) { changed = true; - if ((*items)[FUEL_SLOT] != NULL) + if (items[SLOT_FUEL] != NULL) { // 4J Added: Keep track of whether charcoal was used in production of current stack. - if ( (*items)[FUEL_SLOT]->getItem()->id == Item::coal_Id - && (*items)[FUEL_SLOT]->getAuxValue() == CoalItem::CHAR_COAL) + if ( items[SLOT_FUEL]->getItem()->id == Item::coal_Id + && items[SLOT_FUEL]->getAuxValue() == CoalItem::CHAR_COAL) { m_charcoalUsed = true; } - (*items)[FUEL_SLOT]->count--; - if ((*items)[FUEL_SLOT]->count == 0) + items[SLOT_FUEL]->count--; + if (items[SLOT_FUEL]->count == 0) { - Item *remaining = (*items)[FUEL_SLOT]->getItem()->getCraftingRemainingItem(); - (*items)[FUEL_SLOT] = remaining != NULL ? shared_ptr(new ItemInstance(remaining)) : nullptr; + Item *remaining = items[SLOT_FUEL]->getItem()->getCraftingRemainingItem(); + items[SLOT_FUEL] = remaining != NULL ? shared_ptr(new ItemInstance(remaining)) : nullptr; } } } @@ -229,13 +249,13 @@ void FurnaceTileEntity::tick() bool FurnaceTileEntity::canBurn() { - if ((*items)[INPUT_SLOT] == NULL) return false; - ItemInstance *burnResult = FurnaceRecipes::getInstance()->getResult((*items)[0]->getItem()->id); + if (items[SLOT_INPUT] == NULL) return false; + ItemInstance *burnResult = FurnaceRecipes::getInstance()->getResult(items[SLOT_INPUT]->getItem()->id); if (burnResult == NULL) return false; - if ((*items)[RESULT_SLOT] == NULL) return true; - if (!(*items)[RESULT_SLOT]->sameItem_not_shared(burnResult)) return false; - if ((*items)[RESULT_SLOT]->count < getMaxStackSize() && (*items)[RESULT_SLOT]->count < (*items)[RESULT_SLOT]->getMaxStackSize()) return true; - if ((*items)[RESULT_SLOT]->count < burnResult->getMaxStackSize()) return true; + if (items[SLOT_RESULT] == NULL) return true; + if (!items[SLOT_RESULT]->sameItem_not_shared(burnResult)) return false; + if (items[SLOT_RESULT]->count < getMaxStackSize() && items[SLOT_RESULT]->count < items[SLOT_RESULT]->getMaxStackSize()) return true; + if (items[SLOT_RESULT]->count < burnResult->getMaxStackSize()) return true; return false; } @@ -244,12 +264,12 @@ void FurnaceTileEntity::burn() { if (!canBurn()) return; - ItemInstance *result = FurnaceRecipes::getInstance()->getResult((*items)[0]->getItem()->id); - if ((*items)[RESULT_SLOT] == NULL) (*items)[RESULT_SLOT] = result->copy(); - else if ((*items)[RESULT_SLOT]->id == result->id) (*items)[RESULT_SLOT]->count++; + ItemInstance *result = FurnaceRecipes::getInstance()->getResult(items[SLOT_INPUT]->getItem()->id); + if (items[SLOT_RESULT] == NULL) items[SLOT_RESULT] = result->copy(); + else if (items[SLOT_RESULT]->id == result->id) items[SLOT_RESULT]->count++; - (*items)[INPUT_SLOT]->count--; - if ((*items)[INPUT_SLOT]->count <= 0) (*items)[INPUT_SLOT] = nullptr; + items[SLOT_INPUT]->count--; + if (items[SLOT_INPUT]->count <= 0) items[SLOT_INPUT] = nullptr; } @@ -273,6 +293,11 @@ int FurnaceTileEntity::getBurnDuration(shared_ptr itemInstance) { return BURN_INTERVAL * 3 / 2; } + + if (tile == Tile::coalBlock) + { + return BURN_INTERVAL * 8 * 10; + } } if (dynamic_cast(item) && ((DiggerItem *) item)->getTier() == Item::Tier::WOOD) @@ -329,6 +354,45 @@ void FurnaceTileEntity::stopOpen() { } +bool FurnaceTileEntity::canPlaceItem(int slot, shared_ptr item) +{ + if (slot == SLOT_RESULT) return false; + if (slot == SLOT_FUEL) return isFuel(item); + return true; +} + +intArray FurnaceTileEntity::getSlotsForFace(int face) +{ + if (face == Facing::DOWN) + { + return SLOTS_FOR_DOWN; + } + else if (face == Facing::UP) + { + return SLOTS_FOR_UP; + } + else + { + return SLOTS_FOR_SIDES; + } +} + +bool FurnaceTileEntity::canPlaceItemThroughFace(int slot, shared_ptr item, int face) +{ + return canPlaceItem(slot, item); + +} + +bool FurnaceTileEntity::canTakeItemThroughFace(int slot, shared_ptr item, int face) +{ + if (face == Facing::DOWN && slot == SLOT_FUEL) + { + if (item->id != Item::bucket_empty_Id) return false; + } + + return true; +} + // 4J Added shared_ptr FurnaceTileEntity::clone() { @@ -339,11 +403,11 @@ shared_ptr FurnaceTileEntity::clone() result->tickCount = tickCount; result->litDuration = litDuration; - for (unsigned int i = 0; i < items->length; i++) + for (unsigned int i = 0; i < items.length; i++) { - if ((*items)[i] != NULL) + if (items[i] != NULL) { - (*result->items)[i] = ItemInstance::clone((*items)[i]); + result->items[i] = ItemInstance::clone(items[i]); } } return result; diff --git a/Minecraft.World/FurnaceTileEntity.h b/Minecraft.World/FurnaceTileEntity.h index db39452e..2907a4ca 100644 --- a/Minecraft.World/FurnaceTileEntity.h +++ b/Minecraft.World/FurnaceTileEntity.h @@ -3,28 +3,30 @@ using namespace std; #include "FurnaceTile.h" #include "TileEntity.h" -#include "Container.h" +#include "WorldlyContainer.h" class Player; class Level; -class FurnaceTileEntity : public TileEntity, public Container +class FurnaceTileEntity : public TileEntity, public WorldlyContainer { public: eINSTANCEOF GetType() { return eTYPE_FURNACETILEENTITY; } static TileEntity *create() { return new FurnaceTileEntity(); } -using TileEntity::setChanged; + using TileEntity::setChanged; + + static const int SLOT_INPUT = 0; + static const int SLOT_FUEL = 1; + static const int SLOT_RESULT = 2; private: - static const int BURN_INTERVAL; - ItemInstanceArray *items; + static const intArray SLOTS_FOR_UP; + static const intArray SLOTS_FOR_DOWN; + static const intArray SLOTS_FOR_SIDES; - enum { - INPUT_SLOT = 0, - FUEL_SLOT, - RESULT_SLOT, - }; + static const int BURN_INTERVAL; + ItemInstanceArray items; // 4J-JEV: Added for 'Renewable Energy' achievement. // Should be true iff characoal was consumed whilst cooking the current stack. @@ -35,6 +37,10 @@ public: int litDuration; int tickCount; +private: + + wstring name; + public: // 4J Stu - Need a ctor to initialise member variables FurnaceTileEntity(); @@ -45,7 +51,10 @@ public: virtual shared_ptr removeItem(unsigned int slot, int count); virtual shared_ptr removeItemNoUpdate(int slot); virtual void setItem(unsigned int slot, shared_ptr item); - virtual int getName(); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual bool hasCustomName(); + virtual void setCustomName(const wstring &name); virtual void load(CompoundTag *base); virtual void save(CompoundTag *base); virtual int getMaxStackSize(); @@ -67,8 +76,13 @@ public: virtual bool stillValid(shared_ptr player); virtual void setChanged(); - void startOpen(); - void stopOpen(); + void startOpen(); + void stopOpen(); + + virtual bool canPlaceItem(int slot, shared_ptr item); + virtual intArray getSlotsForFace(int face); + virtual bool canPlaceItemThroughFace(int slot, shared_ptr item, int face); + virtual bool canTakeItemThroughFace(int slot, shared_ptr item, int face); // 4J Added virtual shared_ptr clone(); diff --git a/Minecraft.World/GameDifficultyCommand.h b/Minecraft.World/GameDifficultyCommand.h new file mode 100644 index 00000000..ffa0cc2d --- /dev/null +++ b/Minecraft.World/GameDifficultyCommand.h @@ -0,0 +1,75 @@ +/* +package net.minecraft.commands.common; + +import java.util.List; + +import net.minecraft.commands.*; +import net.minecraft.commands.exceptions.UsageException; +import net.minecraft.locale.I18n; +import net.minecraft.network.chat.ChatMessageComponent; +import net.minecraft.server.MinecraftServer; + +public class GameDifficultyCommand extends BaseCommand { + + // note: copied from Options.java, move to shared location? + private static final String[] DIFFICULTY_NAMES = { + "options.difficulty.peaceful", "options.difficulty.easy", "options.difficulty.normal", "options.difficulty.hard" + }; + + @Override + public String getName() { + return "difficulty"; + } + + @Override + public int getPermissionLevel() { + return LEVEL_GAMEMASTERS; + } + + + @Override + public String getUsage(CommandSender source) { + return "commands.difficulty.usage"; + } + + @Override + public void execute(CommandSender source, String[] args) { + if (args.length > 0) { + int newDiff = getDifficultyForString(source, args[0]); + + MinecraftServer.getInstance().setDifficulty(newDiff); + + logAdminAction(source, "commands.difficulty.success", ChatMessageComponent.forTranslation(DIFFICULTY_NAMES[newDiff])); + + return; + } + + throw new UsageException("commands.difficulty.usage"); + } + + protected int getDifficultyForString(CommandSender source, String name) { + if (name.equalsIgnoreCase("peaceful") || name.equalsIgnoreCase("p")) { + return 0; + } else if (name.equalsIgnoreCase("easy") || name.equalsIgnoreCase("e")) { + return 1; + } else if (name.equalsIgnoreCase("normal") || name.equalsIgnoreCase("n")) { + return 2; + } else if (name.equalsIgnoreCase("hard") || name.equalsIgnoreCase("h")) { + return 3; + } else { + return convertArgToInt(source, name, 0, 3); + } + } + + @Override + public List matchArguments(CommandSender source, String[] args) { + if (args.length == 1) { + return matchArguments(args, "peaceful", "easy", "normal", "hard"); + } + + return null; + } + +} + +*/ \ No newline at end of file diff --git a/Minecraft.World/GameModeCommand.cpp b/Minecraft.World/GameModeCommand.cpp index 86d4c5a5..f8c1ffb6 100644 --- a/Minecraft.World/GameModeCommand.cpp +++ b/Minecraft.World/GameModeCommand.cpp @@ -7,23 +7,32 @@ EGameCommand GameModeCommand::getId() return eGameCommand_GameMode; } +int GameModeCommand::getPermissionLevel() +{ + return LEVEL_GAMEMASTERS; +} + void GameModeCommand::execute(shared_ptr source, byteArray commandData) { - //if (args.length > 0) - //{ + //if (args.length > 0) { // GameType newMode = getModeForString(source, args[0]); - // Player player = args.length >= 2 ? getPlayer(args[1]) : convertSourceToPlayer(source); + // Player player = args.length >= 2 ? convertToPlayer(source, args[1]) : convertSourceToPlayer(source); // player.setGameMode(newMode); + // player.fallDistance = 0; // reset falldistance so flying people do not die :P - // String mode = I18n.get("gameMode." + newMode.getName()); + // ChatMessageComponent mode = ChatMessageComponent.forTranslation("gameMode." + newMode.getName()); // if (player != source) { // logAdminAction(source, AdminLogCommand.LOGTYPE_DONT_SHOW_TO_SELF, "commands.gamemode.success.other", player.getAName(), mode); // } else { // logAdminAction(source, AdminLogCommand.LOGTYPE_DONT_SHOW_TO_SELF, "commands.gamemode.success.self", mode); // } + + // return; //} + + //throw new UsageException("commands.gamemode.usage"); } GameType *GameModeCommand::getModeForString(shared_ptr source, const wstring &name) @@ -38,16 +47,4 @@ GameType *GameModeCommand::getModeForString(shared_ptr source, co //} else { // return LevelSettings.validateGameType(convertArgToInt(source, name, 0, GameType.values().length - 2)); //} -} - -shared_ptr GameModeCommand::getPlayer(PlayerUID playerId) -{ - return nullptr; - //Player player = MinecraftServer.getInstance().getPlayers().getPlayer(name); - - //if (player == null) { - // throw new PlayerNotFoundException(); - //} else { - // return player; - //} } \ No newline at end of file diff --git a/Minecraft.World/GameModeCommand.h b/Minecraft.World/GameModeCommand.h index 66401587..302be9f5 100644 --- a/Minecraft.World/GameModeCommand.h +++ b/Minecraft.World/GameModeCommand.h @@ -8,9 +8,9 @@ class GameModeCommand : public Command { public: virtual EGameCommand getId(); + int getPermissionLevel(); virtual void execute(shared_ptr source, byteArray commandData); protected: GameType *getModeForString(shared_ptr source, const wstring &name); - shared_ptr getPlayer(PlayerUID playerId); }; \ No newline at end of file diff --git a/Minecraft.World/GameRuleCommand.h b/Minecraft.World/GameRuleCommand.h new file mode 100644 index 00000000..25cf12ce --- /dev/null +++ b/Minecraft.World/GameRuleCommand.h @@ -0,0 +1,83 @@ +/* +package net.minecraft.commands.common; + +import net.minecraft.commands.BaseCommand; +import net.minecraft.commands.CommandSender; +import net.minecraft.commands.exceptions.UsageException; +import net.minecraft.network.chat.ChatMessageComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.GameRules; + +import java.util.List; + +public class GameRuleCommand extends BaseCommand { + @Override + public String getName() { + return "gamerule"; + } + + @Override + public int getPermissionLevel() { + return LEVEL_GAMEMASTERS; + } + + + @Override + public String getUsage(CommandSender source) { + return "commands.gamerule.usage"; + } + + @Override + public void execute(CommandSender source, String[] args) { + if (args.length == 2) { + String rule = args[0]; + String value = args[1]; + + GameRules rules = getRules(); + + if (rules.contains(rule)) { + rules.set(rule, value); + logAdminAction(source, "commands.gamerule.success"); + } else { + logAdminAction(source, "commands.gamerule.norule", rule); + } + + return; + } else if (args.length == 1) { + String rule = args[0]; + GameRules rules = getRules(); + + if (rules.contains(rule)) { + String value = rules.get(rule); + source.sendMessage(ChatMessageComponent.forPlainText(rule).addPlainText(" = ").addPlainText(value)); + } else { + logAdminAction(source, "commands.gamerule.norule", rule); + } + + return; + } else if (args.length == 0) { + GameRules rules = getRules(); + source.sendMessage(ChatMessageComponent.forPlainText(joinStrings(rules.getRuleNames()))); + return; + } + + throw new UsageException("commands.gamerule.usage"); + } + + @Override + public List matchArguments(CommandSender source, String[] args) { + if (args.length == 1) { + return matchArguments(args, getRules().getRuleNames()); + } else if (args.length == 2) { + return matchArguments(args, "true", "false"); + } + + return null; + } + + private GameRules getRules() { + return MinecraftServer.getInstance().getLevel(0).getGameRules(); + } +} + +*/ \ No newline at end of file diff --git a/Minecraft.World/GameRules.cpp b/Minecraft.World/GameRules.cpp new file mode 100644 index 00000000..0e594520 --- /dev/null +++ b/Minecraft.World/GameRules.cpp @@ -0,0 +1,193 @@ +#include "stdafx.h" + +#include "GameRules.h" + +// 4J: GameRules isn't in use anymore, just routes any requests to app game host options, kept things commented out for context + +const int GameRules::RULE_DOFIRETICK = 0; +const int GameRules::RULE_MOBGRIEFING = 1; +const int GameRules::RULE_KEEPINVENTORY = 2; +const int GameRules::RULE_DOMOBSPAWNING = 3; +const int GameRules::RULE_DOMOBLOOT = 4; +const int GameRules::RULE_DOTILEDROPS = 5; +//const int GameRules::RULE_COMMANDBLOCKOUTPUT = 6; +const int GameRules::RULE_NATURAL_REGENERATION = 7; +const int GameRules::RULE_DAYLIGHT = 8; + +GameRules::GameRules() +{ + /*registerRule(RULE_DOFIRETICK, L"1"); + registerRule(RULE_MOBGRIEFING, L"1"); + registerRule(RULE_KEEPINVENTORY, L"0"); + registerRule(RULE_DOMOBSPAWNING, L"1"); + registerRule(RULE_DOMOBLOOT, L"1"); + registerRule(RULE_DOTILEDROPS, L"1"); + registerRule(RULE_COMMANDBLOCKOUTPUT, L"1"); + registerRule(RULE_NATURAL_REGENERATION, L"1"); + registerRule(RULE_DAYLIGHT, L"1");*/ +} + +GameRules::~GameRules() +{ + /*for(AUTO_VAR(it,rules.begin()); it != rules.end(); ++it) + { + delete it->second; + }*/ +} + +bool GameRules::getBoolean(const int rule) +{ + switch(rule) + { + case GameRules::RULE_DOFIRETICK: + return app.GetGameHostOption(eGameHostOption_FireSpreads); + case GameRules::RULE_MOBGRIEFING: + return app.GetGameHostOption(eGameHostOption_MobGriefing); + case GameRules::RULE_KEEPINVENTORY: + return app.GetGameHostOption(eGameHostOption_KeepInventory); + case GameRules::RULE_DOMOBSPAWNING: + return app.GetGameHostOption(eGameHostOption_DoMobSpawning); + case GameRules::RULE_DOMOBLOOT: + return app.GetGameHostOption(eGameHostOption_DoMobLoot); + case GameRules::RULE_DOTILEDROPS: + return app.GetGameHostOption(eGameHostOption_DoTileDrops); + case GameRules::RULE_NATURAL_REGENERATION: + return app.GetGameHostOption(eGameHostOption_NaturalRegeneration); + case GameRules::RULE_DAYLIGHT: + return app.GetGameHostOption(eGameHostOption_DoDaylightCycle); + default: + assert(0); + return false; + } +} + +/* +void GameRules::registerRule(const wstring &name, const wstring &startValue) +{ + rules[name] = new GameRule(startValue); +} + +void GameRules::set(const wstring &ruleName, const wstring &newValue) +{ + AUTO_VAR(it, rules.find(ruleName)); + if(it != rules.end() ) + { + GameRule *gameRule = it->second; + gameRule->set(newValue); + } + else + { + registerRule(ruleName, newValue); + } +} + +wstring GameRules::get(const wstring &ruleName) +{ + AUTO_VAR(it, rules.find(ruleName)); + if(it != rules.end() ) + { + GameRule *gameRule = it->second; + return gameRule->get(); + } + return L""; +} + +int GameRules::getInt(const wstring &ruleName) +{ + AUTO_VAR(it, rules.find(ruleName)); + if(it != rules.end() ) + { + GameRule *gameRule = it->second; + return gameRule->getInt(); + } + return 0; +} + +double GameRules::getDouble(const wstring &ruleName) +{ + AUTO_VAR(it, rules.find(ruleName)); + if(it != rules.end() ) + { + GameRule *gameRule = it->second; + return gameRule->getDouble(); + } + return 0; +} + +CompoundTag *GameRules::createTag() +{ + CompoundTag *result = new CompoundTag(L"GameRules"); + + for(AUTO_VAR(it,rules.begin()); it != rules.end(); ++it) + { + GameRule *gameRule = it->second; + result->putString(it->first, gameRule->get()); + } + + return result; +} + +void GameRules::loadFromTag(CompoundTag *tag) +{ + vector *allTags = tag->getAllTags(); + for (AUTO_VAR(it, allTags->begin()); it != allTags->end(); ++it) + { + Tag *ruleTag = *it; + wstring ruleName = ruleTag->getName(); + wstring value = tag->getString(ruleTag->getName()); + + set(ruleName, value); + } + delete allTags; +} + +// Need to delete returned vector. +vector *GameRules::getRuleNames() +{ + vector *out = new vector(); + for (AUTO_VAR(it, rules.begin()); it != rules.end(); it++) out->push_back(it->first); + return out; +} + +bool GameRules::contains(const wstring &rule) +{ + AUTO_VAR(it, rules.find(rule)); + return it != rules.end(); +} + +GameRules::GameRule::GameRule(const wstring &startValue) +{ + value = L""; + booleanValue = false; + intValue = 0; + doubleValue = 0.0; + set(startValue); +} + +void GameRules::GameRule::set(const wstring &newValue) +{ + value = newValue; + booleanValue = _fromString(newValue); + intValue = _fromString(newValue); + doubleValue = _fromString(newValue); +} + +wstring GameRules::GameRule::get() +{ + return value; +} + +bool GameRules::GameRule::getBoolean() +{ + return booleanValue; +} + +int GameRules::GameRule::getInt() +{ + return intValue; +} + +double GameRules::GameRule::getDouble() +{ + return doubleValue; +}*/ \ No newline at end of file diff --git a/Minecraft.World/GameRules.h b/Minecraft.World/GameRules.h new file mode 100644 index 00000000..35eddc6c --- /dev/null +++ b/Minecraft.World/GameRules.h @@ -0,0 +1,56 @@ +#pragma once + +class GameRules +{ +private: + class GameRule + { + private: + wstring value; + bool booleanValue; + int intValue; + double doubleValue; + + public: + GameRule(const wstring &startValue); + + void set(const wstring &newValue); + wstring get(); + bool getBoolean(); + int getInt(); + double getDouble(); + }; + +public: + // 4J: Originally strings + // default rules + static const int RULE_DOFIRETICK; + static const int RULE_MOBGRIEFING; + static const int RULE_KEEPINVENTORY; + static const int RULE_DOMOBSPAWNING; + static const int RULE_DOMOBLOOT; + static const int RULE_DOTILEDROPS; + static const int RULE_COMMANDBLOCKOUTPUT; + static const int RULE_NATURAL_REGENERATION; + static const int RULE_DAYLIGHT; + +private: + unordered_map rules; + +public: + GameRules(); + ~GameRules(); + + bool getBoolean(const int rule); + + // 4J: Removed unused functions + /*void set(const wstring &ruleName, const wstring &newValue); + void registerRule(const wstring &name, const wstring &startValue); + wstring get(const wstring &ruleName); + int getInt(const wstring &ruleName); + double getDouble(const wstring &ruleName); + CompoundTag *createTag(); + void loadFromTag(CompoundTag *tag); + vector *getRuleNames(); + bool contains(const wstring &rule);*/ +}; \ No newline at end of file diff --git a/Minecraft.World/Ghast.cpp b/Minecraft.World/Ghast.cpp index fcf0b705..f0817791 100644 --- a/Minecraft.World/Ghast.cpp +++ b/Minecraft.World/Ghast.cpp @@ -3,8 +3,10 @@ #include "net.minecraft.world.phys.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.damagesource.h" #include "net.minecraft.stats.h" @@ -17,6 +19,7 @@ void Ghast::_init() { + explosionPower = 1; floatDuration = 0; target = nullptr; retargetTime = 0; @@ -33,28 +36,31 @@ Ghast::Ghast(Level *level) : FlyingMob( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + _init(); - _init(); - - this->textureIdx = TN_MOB_GHAST; // 4J was L"/mob/ghast.png"; - this->setSize(4, 4); - this->fireImmune = true; + setSize(4, 4); + fireImmune = true; xpReward = Enemy::XP_REWARD_MEDIUM; } -bool Ghast::hurt(DamageSource *source, int dmg) +bool Ghast::isCharging() +{ + return entityData->getByte(DATA_IS_CHARGING) != 0; +} + +bool Ghast::hurt(DamageSource *source, float dmg) { + if (isInvulnerable()) return false; if (source->getMsgId() == ChatPacket::e_ChatDeathFireball) { - shared_ptr player = dynamic_pointer_cast( source->getEntity() ); - if (player != NULL) + if ( (source->getEntity() != NULL) && source->getEntity()->instanceof(eTYPE_PLAYER) ) { // reflected fireball, kill the ghast FlyingMob::hurt(source, 1000); - player->awardStat(GenericStats::ghast(),GenericStats::param_ghast()); + dynamic_pointer_cast(source->getEntity())->awardStat(GenericStats::ghast(), GenericStats::param_ghast()); return true; } } @@ -64,123 +70,118 @@ bool Ghast::hurt(DamageSource *source, int dmg) void Ghast::defineSynchedData() { - FlyingMob::defineSynchedData(); + FlyingMob::defineSynchedData(); - entityData->define(DATA_IS_CHARGING, (byte) 0); + entityData->define(DATA_IS_CHARGING, (byte) 0); } -int Ghast::getMaxHealth() +void Ghast::registerAttributes() { - return 10; -} + FlyingMob::registerAttributes(); -void Ghast::tick() -{ - FlyingMob::tick(); - byte current = entityData->getByte(DATA_IS_CHARGING); -// this->textureName = current == 1 ? L"/mob/ghast_fire.png" : L"/mob/ghast.png"; // 4J replaced with following line - this->textureIdx = current == 1 ? TN_MOB_GHAST_FIRE : TN_MOB_GHAST; + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(10); } void Ghast::serverAiStep() { - if (!level->isClientSide && level->difficulty == Difficulty::PEACEFUL) remove(); - checkDespawn(); + if (!level->isClientSide && level->difficulty == Difficulty::PEACEFUL) remove(); + checkDespawn(); - oCharge = charge; - double xd = xTarget - x; - double yd = yTarget - y; - double zd = zTarget - z; + oCharge = charge; + double xd = xTarget - x; + double yd = yTarget - y; + double zd = zTarget - z; - double dd = xd * xd + yd * yd + zd * zd; + double dd = xd * xd + yd * yd + zd * zd; - if (dd < 1 * 1 || dd > 60 * 60) + if (dd < 1 * 1 || dd > 60 * 60) { - xTarget = x + (random->nextFloat() * 2 - 1) * 16; - yTarget = y + (random->nextFloat() * 2 - 1) * 16; - zTarget = z + (random->nextFloat() * 2 - 1) * 16; - } + xTarget = x + (random->nextFloat() * 2 - 1) * 16; + yTarget = y + (random->nextFloat() * 2 - 1) * 16; + zTarget = z + (random->nextFloat() * 2 - 1) * 16; + } - if (floatDuration-- <= 0) + if (floatDuration-- <= 0) { - floatDuration += random->nextInt(5) + 2; + floatDuration += random->nextInt(5) + 2; dd = sqrt(dd); - if (canReach(xTarget, yTarget, zTarget, dd)) + if (canReach(xTarget, yTarget, zTarget, dd)) { - this->xd += xd / dd * 0.1; - this->yd += yd / dd * 0.1; - this->zd += zd / dd * 0.1; - } + this->xd += xd / dd * 0.1; + this->yd += yd / dd * 0.1; + this->zd += zd / dd * 0.1; + } else { - xTarget = x; - yTarget = y; - zTarget = z; - } - } - - if (target != NULL && target->removed) target = nullptr; - if (target == NULL || retargetTime-- <= 0) + xTarget = x; + yTarget = y; + zTarget = z; + } + } + + if (target != NULL && target->removed) target = nullptr; + if (target == NULL || retargetTime-- <= 0) { - target = level->getNearestAttackablePlayer(shared_from_this(), 100); - if (target != NULL) + target = level->getNearestAttackablePlayer(shared_from_this(), 100); + if (target != NULL) { - retargetTime = 20; - } - } + retargetTime = 20; + } + } - double maxDist = 64.0f; - if (target != NULL && target->distanceToSqr(shared_from_this()) < maxDist * maxDist) + double maxDist = 64.0f; + if (target != NULL && target->distanceToSqr(shared_from_this()) < maxDist * maxDist) { - double xdd = target->x - x; - double ydd = (target->bb->y0 + target->bbHeight / 2) - (y + bbHeight / 2); - double zdd = target->z - z; - yBodyRot = yRot = -(float) atan2(xdd, zdd) * 180 / PI; + double xdd = target->x - x; + double ydd = (target->bb->y0 + target->bbHeight / 2) - (y + bbHeight / 2); + double zdd = target->z - z; + yBodyRot = yRot = -(float) atan2(xdd, zdd) * 180 / PI; - if (this->canSee(target)) + if (canSee(target)) { - if (charge == 10) + if (charge == 10) { // 4J - change brought forward from 1.2.3 level->levelEvent(nullptr, LevelEvent::SOUND_GHAST_WARNING, (int) x, (int) y, (int) z, 0); - } - charge++; - if (charge == 20) + } + charge++; + if (charge == 20) { // 4J - change brought forward from 1.2.3 level->levelEvent(nullptr, LevelEvent::SOUND_GHAST_FIREBALL, (int) x, (int) y, (int) z, 0); - shared_ptr ie = shared_ptr( new Fireball(level, dynamic_pointer_cast( shared_from_this() ), xdd, ydd, zdd) ); - double d = 4; - Vec3 *v = getViewVector(1); - ie->x = x + v->x * d; - ie->y = y + bbHeight / 2 + 0.5f; - ie->z = z + v->z * d; - level->addEntity(ie); - charge = -40; - } - } + shared_ptr ie = shared_ptr( new LargeFireball(level, dynamic_pointer_cast( shared_from_this() ), xdd, ydd, zdd) ); + ie->explosionPower = explosionPower; + double d = 4; + Vec3 *v = getViewVector(1); + ie->x = x + v->x * d; + ie->y = y + bbHeight / 2 + 0.5f; + ie->z = z + v->z * d; + level->addEntity(ie); + charge = -40; + } + } else { - if (charge > 0) charge--; - } - } + if (charge > 0) charge--; + } + } else { - yBodyRot = yRot = -(float) atan2(this->xd, this->zd) * 180 / PI; - if (charge > 0) charge--; - } + yBodyRot = yRot = -(float) atan2(this->xd, this->zd) * 180 / PI; + if (charge > 0) charge--; + } - if (!level->isClientSide) + if (!level->isClientSide) { - byte old = entityData->getByte(DATA_IS_CHARGING); - byte current = (byte) (charge > 10 ? 1 : 0); - if (old != current) + byte old = entityData->getByte(DATA_IS_CHARGING); + byte current = (byte) (charge > 10 ? 1 : 0); + if (old != current) { - entityData->set(DATA_IS_CHARGING, current); - } - } + entityData->set(DATA_IS_CHARGING, current); + } + } } bool Ghast::canReach(double xt, double yt, double zt, double dist) @@ -192,31 +193,31 @@ bool Ghast::canReach(double xt, double yt, double zt, double dist) AABB *bb = this->bb->copy(); for (int d = 1; d < dist; d++) { - bb->move(xd, yd, zd); - if (!level->getCubes( shared_from_this(), bb)->empty()) return false; + bb->move(xd, yd, zd); + if (!level->getCubes( shared_from_this(), bb)->empty()) return false; } - return true; + return true; } int Ghast::getAmbientSound() { - return eSoundType_MOB_GHAST_MOAN; + return eSoundType_MOB_GHAST_MOAN; } int Ghast::getHurtSound() { - return eSoundType_MOB_GHAST_SCREAM; + return eSoundType_MOB_GHAST_SCREAM; } int Ghast::getDeathSound() { - return eSoundType_MOB_GHAST_DEATH; + return eSoundType_MOB_GHAST_DEATH; } int Ghast::getDeathLoot() { - return Item::sulphur->id; + return Item::gunpowder_Id; } void Ghast::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) @@ -229,21 +230,32 @@ void Ghast::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) count = random->nextInt(3) + random->nextInt(1 + playerBonusLevel); for (int i = 0; i < count; i++) { - spawnAtLocation(Item::sulphur_Id, 1); + spawnAtLocation(Item::gunpowder_Id, 1); } } float Ghast::getSoundVolume() { - return 0.4f;//10; 4J-PB - changing due to customer demands + return 0.4f;//10; 4J-PB - changing due to customer demands } bool Ghast::canSpawn() { - return (random->nextInt(20) == 0 && FlyingMob::canSpawn() && level->difficulty > Difficulty::PEACEFUL); + return (random->nextInt(20) == 0 && FlyingMob::canSpawn() && level->difficulty > Difficulty::PEACEFUL); } int Ghast::getMaxSpawnClusterSize() { - return 1; + return 1; +} +void Ghast::addAdditonalSaveData(CompoundTag *tag) +{ + FlyingMob::addAdditonalSaveData(tag); + tag->putInt(L"ExplosionPower", explosionPower); } + +void Ghast::readAdditionalSaveData(CompoundTag *tag) +{ + FlyingMob::readAdditionalSaveData(tag); + if (tag->contains(L"ExplosionPower")) explosionPower = tag->getInt(L"ExplosionPower"); +} \ No newline at end of file diff --git a/Minecraft.World/Ghast.h b/Minecraft.World/Ghast.h index cdb44b61..f19f737c 100644 --- a/Minecraft.World/Ghast.h +++ b/Minecraft.World/Ghast.h @@ -29,21 +29,20 @@ public: int charge; private: + int explosionPower; + + void _init(); public: Ghast(Level *level); - virtual bool hurt(DamageSource *source, int dmg); + virtual bool isCharging(); + virtual bool hurt(DamageSource *source, float dmg); protected: virtual void defineSynchedData(); - -public: - int getMaxHealth(); - -public: - virtual void tick(); + virtual void registerAttributes(); protected: virtual void serverAiStep(); @@ -61,5 +60,7 @@ protected: public: virtual bool canSpawn(); - virtual int getMaxSpawnClusterSize(); + virtual int getMaxSpawnClusterSize(); + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditionalSaveData(CompoundTag *tag); }; diff --git a/Minecraft.World/Giant.cpp b/Minecraft.World/Giant.cpp index 054394da..dbb790bf 100644 --- a/Minecraft.World/Giant.cpp +++ b/Minecraft.World/Giant.cpp @@ -1,5 +1,7 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" #include "Giant.h" #include "..\Minecraft.Client\Textures.h" @@ -10,20 +12,19 @@ Giant::Giant(Level *level) : Monster( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + registerAttributes(); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_ZOMBIE; // 4J was L"/mob/zombie.png"; - runSpeed = 0.5f; - attackDamage = 50; - this->heightOffset*=6; - this->setSize(bbWidth * 6, bbHeight * 6); + heightOffset*=6; + setSize(bbWidth * 6, bbHeight * 6); } -int Giant::getMaxHealth() +void Giant::registerAttributes() { - return 100; + Monster::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(100); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.5f); + getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(50); } float Giant::getWalkTargetValue(int x, int y, int z) diff --git a/Minecraft.World/Giant.h b/Minecraft.World/Giant.h index 21798854..478de94c 100644 --- a/Minecraft.World/Giant.h +++ b/Minecraft.World/Giant.h @@ -12,7 +12,10 @@ public: static Entity *create(Level *level) { return new Giant(level); } Giant(Level *level); - - int getMaxHealth(); + +protected: + virtual void registerAttributes(); + +public: virtual float getWalkTargetValue(int x, int y, int z); }; diff --git a/Minecraft.World/GiveItemCommand.cpp b/Minecraft.World/GiveItemCommand.cpp index 1d13592f..b3cbff4f 100644 --- a/Minecraft.World/GiveItemCommand.cpp +++ b/Minecraft.World/GiveItemCommand.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "net.minecraft.commands.h" +#include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.item.h" #include "net.minecraft.network.packet.h" #include "..\Minecraft.Client\ServerPlayer.h" @@ -10,6 +11,11 @@ EGameCommand GiveItemCommand::getId() return eGameCommand_Give; } +int GiveItemCommand::getPermissionLevel() +{ + return LEVEL_GAMEMASTERS; +} + void GiveItemCommand::execute(shared_ptr source, byteArray commandData) { ByteArrayInputStream bais(commandData); @@ -20,14 +26,15 @@ void GiveItemCommand::execute(shared_ptr source, byteArray comman int amount = dis.readInt(); int aux = dis.readInt(); wstring tag = dis.readUTF(); - + bais.reset(); shared_ptr player = getPlayer(uid); if(player != NULL && item > 0 && Item::items[item] != NULL) { shared_ptr itemInstance = shared_ptr(new ItemInstance(item, amount, aux)); - player->drop(itemInstance); + shared_ptr drop = player->drop(itemInstance); + drop->throwTime = 0; //logAdminAction(source, L"commands.give.success", ChatPacket::e_ChatCustom, Item::items[item]->getName(itemInstance), item, amount, player->getAName()); logAdminAction(source, ChatPacket::e_ChatCustom, L"commands.give.success", item, player->getAName()); } diff --git a/Minecraft.World/GiveItemCommand.h b/Minecraft.World/GiveItemCommand.h index 532070a6..fbe99c4f 100644 --- a/Minecraft.World/GiveItemCommand.h +++ b/Minecraft.World/GiveItemCommand.h @@ -8,6 +8,7 @@ class GiveItemCommand : public Command { public: virtual EGameCommand getId(); + virtual int getPermissionLevel(); virtual void execute(shared_ptr source, byteArray commandData); public: diff --git a/Minecraft.World/GlowstoneTile.cpp b/Minecraft.World/GlowstoneTile.cpp new file mode 100644 index 00000000..dba4ce91 --- /dev/null +++ b/Minecraft.World/GlowstoneTile.cpp @@ -0,0 +1,22 @@ +#include "stdafx.h" +#include "Glowstonetile.h" +#include "net.minecraft.world.item.h" + +Glowstonetile::Glowstonetile(int id, Material *material) : Tile(id, material) +{ +} + +int Glowstonetile::getResourceCountForLootBonus(int bonusLevel, Random *random) +{ + return Mth::clamp(getResourceCount(random) + random->nextInt(bonusLevel + 1), 1, 4); +} + +int Glowstonetile::getResourceCount(Random *random) +{ + return 2 + random->nextInt(3); +} + +int Glowstonetile::getResource(int data, Random *random, int playerBonusLevel) +{ + return Item::yellowDust->id; +} \ No newline at end of file diff --git a/Minecraft.World/GlowstoneTile.h b/Minecraft.World/GlowstoneTile.h new file mode 100644 index 00000000..f09491bd --- /dev/null +++ b/Minecraft.World/GlowstoneTile.h @@ -0,0 +1,13 @@ +#pragma once +#include "Tile.h" + +class Random; + +class Glowstonetile : public Tile +{ +public: + Glowstonetile(int id, Material *material); + virtual int getResourceCountForLootBonus(int bonusLevel, Random *random); + virtual int getResourceCount(Random *random); + virtual int getResource(int data, Random *random, int playerBonusLevel); +}; \ No newline at end of file diff --git a/Minecraft.World/GoalSelector.cpp b/Minecraft.World/GoalSelector.cpp index 85a37dda..3e3d99b5 100644 --- a/Minecraft.World/GoalSelector.cpp +++ b/Minecraft.World/GoalSelector.cpp @@ -30,6 +30,33 @@ void GoalSelector::addGoal(int prio, Goal *goal, bool canDeletePointer /*= true* goals.push_back(new InternalGoal(prio, goal, canDeletePointer)); } +void GoalSelector::removeGoal(Goal *toRemove) +{ + for(AUTO_VAR(it, goals.begin()); it != goals.end(); ) + { + InternalGoal *ig = *it; + Goal *goal = ig->goal; + + if (goal == toRemove) + { + AUTO_VAR(it2, find(usingGoals.begin(), usingGoals.end(), ig) ); + if (it2 != usingGoals.end()) + { + goal->stop(); + usingGoals.erase(it2); + } + + if(ig->canDeletePointer) delete ig->goal; + delete ig; + it = goals.erase(it); + } + else + { + ++it; + } + } +} + void GoalSelector::tick() { vector toStart; diff --git a/Minecraft.World/GoalSelector.h b/Minecraft.World/GoalSelector.h index c2bf0b87..3841b93a 100644 --- a/Minecraft.World/GoalSelector.h +++ b/Minecraft.World/GoalSelector.h @@ -29,6 +29,7 @@ public: // 4J Added canDelete param void addGoal(int prio, Goal *goal, bool canDeletePointer = true); + void removeGoal(Goal *toRemove); void tick(); vector *getRunningGoals(); diff --git a/Minecraft.World/GoldenAppleItem.cpp b/Minecraft.World/GoldenAppleItem.cpp index 6c99d201..47e2c21c 100644 --- a/Minecraft.World/GoldenAppleItem.cpp +++ b/Minecraft.World/GoldenAppleItem.cpp @@ -26,11 +26,13 @@ const Rarity *GoldenAppleItem::getRarity(shared_ptr itemInstance) void GoldenAppleItem::addEatEffect(shared_ptr instance, Level *level, shared_ptr player) { + if (!level->isClientSide) player->addEffect(new MobEffectInstance(MobEffect::absorption->id, 2 * 60 * SharedConstants::TICKS_PER_SECOND, 0)); + if (instance->getAuxValue() > 0) { if (!level->isClientSide) { - player->addEffect(new MobEffectInstance(MobEffect::regeneration->id, 30 * SharedConstants::TICKS_PER_SECOND, 3)); + player->addEffect(new MobEffectInstance(MobEffect::regeneration->id, 30 * SharedConstants::TICKS_PER_SECOND, 4)); player->addEffect(new MobEffectInstance(MobEffect::damageResistance->id, 300 * SharedConstants::TICKS_PER_SECOND, 0)); player->addEffect(new MobEffectInstance(MobEffect::fireResistance->id, 300 * SharedConstants::TICKS_PER_SECOND, 0)); } diff --git a/Minecraft.World/GrassTile.cpp b/Minecraft.World/GrassTile.cpp index 0e955025..68e7c233 100644 --- a/Minecraft.World/GrassTile.cpp +++ b/Minecraft.World/GrassTile.cpp @@ -16,23 +16,23 @@ GrassTile::GrassTile(int id) : Tile(id, Material::grass) iconSnowSide = NULL; iconSideOverlay = NULL; - setTicking(true); + setTicking(true); } Icon *GrassTile::getTexture(int face, int data) { - if (face == Facing::UP) return iconTop; - if (face == Facing::DOWN) return Tile::dirt->getTexture(face); - return icon; + if (face == Facing::UP) return iconTop; + if (face == Facing::DOWN) return Tile::dirt->getTexture(face); + return icon; } Icon *GrassTile::getTexture(LevelSource *level, int x, int y, int z, int face) { - if (face == Facing::UP) return iconTop; - if (face == Facing::DOWN) return Tile::dirt->getTexture(face); - Material *above = level->getMaterial(x, y + 1, z); - if (above == Material::topSnow || above == Material::snow) return iconSnowSide; - else return icon; + if (face == Facing::UP) return iconTop; + if (face == Facing::DOWN) return Tile::dirt->getTexture(face); + Material *above = level->getMaterial(x, y + 1, z); + if (above == Material::topSnow || above == Material::snow) return iconSnowSide; + else return icon; } void GrassTile::registerIcons(IconRegister *iconRegister) @@ -46,10 +46,10 @@ void GrassTile::registerIcons(IconRegister *iconRegister) int GrassTile::getColor() const { // 4J Replaced - //double temp = 0.5; - //double rain = 1.0; + //double temp = 0.5; + //double rain = 1.0; - //return GrassColor::get(temp, rain); + //return GrassColor::get(temp, rain); return Minecraft::GetInstance()->getColourTable()->getColor( eMinecraftColour_Grass_Common ); } @@ -90,15 +90,15 @@ int GrassTile::getColor(LevelSource *level, int x, int y, int z, int data) void GrassTile::tick(Level *level, int x, int y, int z, Random *random) { - if (level->isClientSide) return; + if (level->isClientSide) return; - if (level->getRawBrightness(x, y + 1, z) < MIN_BRIGHTNESS && Tile::lightBlock[level->getTile(x, y + 1, z)] > 2) + if (level->getRawBrightness(x, y + 1, z) < MIN_BRIGHTNESS && Tile::lightBlock[level->getTile(x, y + 1, z)] > 2) { - level->setTile(x, y, z, Tile::dirt_Id); - } + level->setTileAndUpdate(x, y, z, Tile::dirt_Id); + } else { - if (level->getRawBrightness(x, y + 1, z) >= Level::MAX_BRIGHTNESS - 6) + if (level->getRawBrightness(x, y + 1, z) >= Level::MAX_BRIGHTNESS - 6) { for (int i = 0; i < 4; i++) { @@ -108,11 +108,11 @@ void GrassTile::tick(Level *level, int x, int y, int z, Random *random) int above = level->getTile(xt, yt + 1, zt); if (level->getTile(xt, yt, zt) == Tile::dirt_Id && level->getRawBrightness(xt, yt + 1, zt) >= MIN_BRIGHTNESS && Tile::lightBlock[above] <= 2) { - level->setTile(xt, yt, zt, Tile::grass_Id); + level->setTileAndUpdate(xt, yt, zt, Tile::grass_Id); } } - } - } + } + } } int GrassTile::getResource(int data, Random *random, int playerBonusLevel) diff --git a/Minecraft.World/GravelTile.cpp b/Minecraft.World/GravelTile.cpp index 1ee866a9..86c34962 100644 --- a/Minecraft.World/GravelTile.cpp +++ b/Minecraft.World/GravelTile.cpp @@ -8,6 +8,7 @@ GravelTile::GravelTile(int type) : HeavyTile(type) int GravelTile::getResource(int data, Random *random, int playerBonusLevel) { - if (random->nextInt(10 - playerBonusLevel * 3) == 0) return Item::flint->id; - return id; + if (playerBonusLevel > 3) playerBonusLevel = 3; + if (random->nextInt(10 - playerBonusLevel * 3) == 0) return Item::flint->id; + return id; } \ No newline at end of file diff --git a/Minecraft.World/GroundBushFeature.cpp b/Minecraft.World/GroundBushFeature.cpp index df7561f3..88b7f733 100644 --- a/Minecraft.World/GroundBushFeature.cpp +++ b/Minecraft.World/GroundBushFeature.cpp @@ -5,8 +5,8 @@ GroundBushFeature::GroundBushFeature(int trunkType, int leafType) { - this->trunkTileType = trunkType; - this->leafTileType = leafType; + trunkTileType = trunkType; + leafTileType = leafType; } bool GroundBushFeature::place(Level *level, Random *random, int x, int y, int z) diff --git a/Minecraft.World/HalfSlabTile.cpp b/Minecraft.World/HalfSlabTile.cpp index ed3969c1..13308b9a 100644 --- a/Minecraft.World/HalfSlabTile.cpp +++ b/Minecraft.World/HalfSlabTile.cpp @@ -6,17 +6,6 @@ #include "net.minecraft.stats.h" #include "Facing.h" -/*package net.minecraft.world.level.tile; - -import java.util.*; - -import net.minecraft.Facing; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.*; -import net.minecraft.world.level.material.Material; -import net.minecraft.world.phys.AABB;*/ - - HalfSlabTile::HalfSlabTile(int id, bool fullSize, Material *material) : Tile(id, material, fullSize) { @@ -98,41 +87,41 @@ int HalfSlabTile::getResourceCount(Random *random) int HalfSlabTile::getSpawnResourcesAuxValue(int data) { - return data & TYPE_MASK; + return data & TYPE_MASK; } bool HalfSlabTile::isCubeShaped() { - return fullSize; + return fullSize; } bool HalfSlabTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { - if (fullSize) return Tile::shouldRenderFace(level, x, y, z, face); + if (fullSize) return Tile::shouldRenderFace(level, x, y, z, face); - if (face != Facing::UP && face != Facing::DOWN && !Tile::shouldRenderFace(level, x, y, z, face)) - { - return false; - } + if (face != Facing::UP && face != Facing::DOWN && !Tile::shouldRenderFace(level, x, y, z, face)) + { + return false; + } - int ox = x, oy = y, oz = z; - ox += Facing::STEP_X[Facing::OPPOSITE_FACING[face]]; - oy += Facing::STEP_Y[Facing::OPPOSITE_FACING[face]]; - oz += Facing::STEP_Z[Facing::OPPOSITE_FACING[face]]; + int ox = x, oy = y, oz = z; + ox += Facing::STEP_X[Facing::OPPOSITE_FACING[face]]; + oy += Facing::STEP_Y[Facing::OPPOSITE_FACING[face]]; + oz += Facing::STEP_Z[Facing::OPPOSITE_FACING[face]]; - boolean isUpper = (level->getData(ox, oy, oz) & TOP_SLOT_BIT) != 0; - if (isUpper) - { - if (face == Facing::DOWN) return true; - if (face == Facing::UP && Tile::shouldRenderFace(level, x, y, z, face)) return true; - return !(isHalfSlab(level->getTile(x, y, z)) && (level->getData(x, y, z) & TOP_SLOT_BIT) != 0); - } - else - { - if (face == Facing::UP) return true; - if (face == Facing::DOWN && Tile::shouldRenderFace(level, x, y, z, face)) return true; - return !(isHalfSlab(level->getTile(x, y, z)) && (level->getData(x, y, z) & TOP_SLOT_BIT) == 0); - } + boolean isUpper = (level->getData(ox, oy, oz) & TOP_SLOT_BIT) != 0; + if (isUpper) + { + if (face == Facing::DOWN) return true; + if (face == Facing::UP && Tile::shouldRenderFace(level, x, y, z, face)) return true; + return !(isHalfSlab(level->getTile(x, y, z)) && (level->getData(x, y, z) & TOP_SLOT_BIT) != 0); + } + else + { + if (face == Facing::UP) return true; + if (face == Facing::DOWN && Tile::shouldRenderFace(level, x, y, z, face)) return true; + return !(isHalfSlab(level->getTile(x, y, z)) && (level->getData(x, y, z) & TOP_SLOT_BIT) == 0); + } } bool HalfSlabTile::isHalfSlab(int tileId) @@ -140,4 +129,24 @@ bool HalfSlabTile::isHalfSlab(int tileId) return tileId == Tile::stoneSlabHalf_Id || tileId == Tile::woodSlabHalf_Id; } +int HalfSlabTile::cloneTileData(Level *level, int x, int y, int z) +{ + return Tile::cloneTileData(level, x, y, z) & TYPE_MASK; +} +int HalfSlabTile::cloneTileId(Level *level, int x, int y, int z) +{ + if (isHalfSlab(id)) + { + return id; + } + if (id == Tile::stoneSlab_Id) + { + return Tile::stoneSlabHalf_Id; + } + if (id == Tile::woodSlab_Id) + { + return Tile::woodSlabHalf_Id; + } + return Tile::stoneSlabHalf_Id; +} \ No newline at end of file diff --git a/Minecraft.World/HalfSlabTile.h b/Minecraft.World/HalfSlabTile.h index 183a4add..6399d827 100644 --- a/Minecraft.World/HalfSlabTile.h +++ b/Minecraft.World/HalfSlabTile.h @@ -5,11 +5,9 @@ class HalfSlabTile : public Tile { - - public: - static const int TYPE_MASK = 7; - static const int TOP_SLOT_BIT = 8; + static const int TYPE_MASK = 7; + static const int TOP_SLOT_BIT = 8; protected: bool fullSize; @@ -30,4 +28,6 @@ private: public: virtual int getAuxName(int auxValue) = 0; + virtual int cloneTileData(Level *level, int x, int y, int z); + virtual int cloneTileId(Level *level, int x, int y, int z); }; \ No newline at end of file diff --git a/Minecraft.World/HalfTransparentTile.h b/Minecraft.World/HalfTransparentTile.h index e3d34c3f..41908ef2 100644 --- a/Minecraft.World/HalfTransparentTile.h +++ b/Minecraft.World/HalfTransparentTile.h @@ -15,5 +15,5 @@ public: virtual bool isSolidRender(bool isServerLevel = false); virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); virtual bool blocksLight(); - void registerIcons(IconRegister *iconRegister); + virtual void registerIcons(IconRegister *iconRegister); }; diff --git a/Minecraft.World/HangingEntity.cpp b/Minecraft.World/HangingEntity.cpp index 6256a381..8ba3e1fc 100644 --- a/Minecraft.World/HangingEntity.cpp +++ b/Minecraft.World/HangingEntity.cpp @@ -14,22 +14,19 @@ void HangingEntity::_init(Level *level) checkInterval = 0; dir = 0; xTile = yTile = zTile = 0; + this->heightOffset = 0; + this->setSize(0.5f, 0.5f); } HangingEntity::HangingEntity(Level *level) : Entity( level ) { _init(level); - this->heightOffset = 0; - this->setSize(0.5f, 0.5f); } HangingEntity::HangingEntity(Level *level, int xTile, int yTile, int zTile, int dir) : Entity( level ) { _init(level); - //motive = NULL; - this->heightOffset = 0; - this->setSize(0.5f, 0.5f); this->xTile = xTile; this->yTile = yTile; this->zTile = zTile; @@ -38,7 +35,7 @@ HangingEntity::HangingEntity(Level *level, int xTile, int yTile, int zTile, int void HangingEntity::setDir(int dir) { this->dir = dir; - this->yRotO = this->yRot = (float)(dir * 90); + yRotO = yRot = (float)(dir * 90); float w = (float)getWidth(); float h = (float)getHeight(); @@ -75,7 +72,7 @@ void HangingEntity::setDir(int dir) if (dir == Direction::EAST) z -= offs(getWidth()); y += offs(getHeight()); - this->setPos(x, y, z); + setPos(x, y, z); float ss = -(0.5f / 16.0f); @@ -98,13 +95,16 @@ float HangingEntity::offs(int w) void HangingEntity::tick() { - if (checkInterval++ == 20 * 5 && !level->isClientSide)//isClientSide) + xo = x; + yo = y; + zo = z; + if (checkInterval++ == 20 * 5 && !level->isClientSide) { checkInterval = 0; if (!removed && !survives()) { remove(); - dropItem(); + dropItem(nullptr); } } } @@ -156,7 +156,7 @@ bool HangingEntity::survives() for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) { shared_ptr e = (*it); - if(dynamic_pointer_cast(e) != NULL) + if( e->instanceof(eTYPE_HANGING_ENTITY) ) { return false; } @@ -181,15 +181,16 @@ bool HangingEntity::skipAttackInteraction(shared_ptr source) return false; } -bool HangingEntity::hurt(DamageSource *source, int damage) +bool HangingEntity::hurt(DamageSource *source, float damage) { + if (isInvulnerable()) return false; if (!removed && !level->isClientSide) { if (dynamic_cast(source) != NULL) { shared_ptr sourceEntity = source->getDirectEntity(); - if (dynamic_pointer_cast(sourceEntity) != NULL && !dynamic_pointer_cast(sourceEntity)->isAllowedToHurtEntity(shared_from_this()) ) + if ( (sourceEntity != NULL) && sourceEntity->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast(sourceEntity)->isAllowedToHurtEntity(shared_from_this()) ) { return false; } @@ -200,7 +201,7 @@ bool HangingEntity::hurt(DamageSource *source, int damage) shared_ptr player = nullptr; shared_ptr e = source->getEntity(); - if (e!=NULL && ((e->GetType() & eTYPE_PLAYER)!=0) ) // check if it's serverplayer or player + if ( (e!=NULL) && e->instanceof(eTYPE_PLAYER) ) // check if it's serverplayer or player { player = dynamic_pointer_cast( e ); } @@ -210,7 +211,7 @@ bool HangingEntity::hurt(DamageSource *source, int damage) return true; } - dropItem(); + dropItem(nullptr); } return true; } @@ -221,7 +222,7 @@ void HangingEntity::move(double xa, double ya, double za, bool noEntityCubes) if (!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) { remove(); - dropItem(); + dropItem(nullptr); } } @@ -230,7 +231,7 @@ void HangingEntity::push(double xa, double ya, double za) if (!level->isClientSide && !removed && (xa * xa + ya * ya + za * za) > 0) { remove(); - dropItem(); + dropItem(nullptr); } } @@ -289,4 +290,7 @@ void HangingEntity::readAdditionalSaveData(CompoundTag *tag) setDir(dir); } - +bool HangingEntity::repositionEntityAfterLoad() +{ + return false; +} \ No newline at end of file diff --git a/Minecraft.World/HangingEntity.h b/Minecraft.World/HangingEntity.h index b87915e4..30d0a1bd 100644 --- a/Minecraft.World/HangingEntity.h +++ b/Minecraft.World/HangingEntity.h @@ -10,7 +10,6 @@ public: private: void _init(Level *level); - float offs(int w); int checkInterval; //eINSTANCEOF eType; @@ -25,12 +24,16 @@ public: HangingEntity(Level *level); HangingEntity(Level *level, int xTile, int yTile, int zTile, int dir); void setDir(int dir); - bool survives(); + virtual bool survives(); + +private: + float offs(int w); +public: virtual void tick(); virtual bool isPickable(); virtual bool skipAttackInteraction(shared_ptr source); - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); virtual void move(double xa, double ya, double za, bool noEntityCubes=false); // 4J - added noEntityCubes parameter virtual void push(double xa, double ya, double za); virtual void addAdditonalSaveData(CompoundTag *tag); @@ -38,5 +41,8 @@ public: virtual int getWidth()=0; virtual int getHeight()=0; - virtual void dropItem()=0; + virtual void dropItem(shared_ptr causedBy)=0; + +protected: + virtual bool repositionEntityAfterLoad(); }; diff --git a/Minecraft.World/HangingEntityItem.cpp b/Minecraft.World/HangingEntityItem.cpp index 505dce4d..9e4e9d5b 100644 --- a/Minecraft.World/HangingEntityItem.cpp +++ b/Minecraft.World/HangingEntityItem.cpp @@ -3,6 +3,7 @@ #include "net.minecraft.world.phys.h" #include "net.minecraft.world.damagesource.h" #include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.item.h" #include "net.minecraft.world.level.h" #include "HangingEntityItem.h" #include "HangingEntity.h" @@ -13,10 +14,7 @@ HangingEntityItem::HangingEntityItem(int id, eINSTANCEOF eClassType) : Item(id) { - //super(id); - //this.clazz = clazz; this->eType=eClassType; - // setItemCategory(CreativeModeTab.TAB_DECORATIONS); } bool HangingEntityItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int xt, int yt, int zt, int face, float clickX, float clickY, float clickZ, bool bTestOnly) @@ -26,17 +24,16 @@ bool HangingEntityItem::useOn(shared_ptr instance, shared_ptrmayBuild(xt, yt, zt)) return false; + if (!player->mayUseItemAt(xt, yt, zt, face, instance)) return false; return true; } int dir = Direction::FACING_DIRECTION[face]; - shared_ptr entity = createEntity(level, xt, yt, zt, dir); + shared_ptr entity = createEntity(level, xt, yt, zt, dir, instance->getAuxValue() ); - //if (!player->mayUseItemAt(xt, yt, zt, face, instance)) return false; - if (!player->mayBuild(xt, yt, zt)) return false; + if (!player->mayUseItemAt(xt, yt, zt, face, instance)) return false; if (entity != NULL && entity->survives()) { @@ -65,12 +62,22 @@ bool HangingEntityItem::useOn(shared_ptr instance, shared_ptr HangingEntityItem::createEntity(Level *level, int x, int y, int z, int dir) +shared_ptr HangingEntityItem::createEntity(Level *level, int x, int y, int z, int dir, int auxValue) // 4J added auxValue { if (eType == eTYPE_PAINTING) { shared_ptr painting = shared_ptr(new Painting(level, x, y, z, dir)); - painting->PaintingPostConstructor(dir); + +#ifndef _CONTENT_PACKAGE + if (app.DebugArtToolsOn() && auxValue > 0) + { + painting->PaintingPostConstructor(dir, auxValue - 1); + } + else +#endif + { + painting->PaintingPostConstructor(dir); + } return dynamic_pointer_cast (painting); } @@ -86,3 +93,25 @@ shared_ptr HangingEntityItem::createEntity(Level *level, int x, i } } +// 4J Adding overrides for art tools +void HangingEntityItem::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced) +{ +#ifndef _CONTENT_PACKAGE + if (eType == eTYPE_PAINTING && app.DebugArtToolsOn() && itemInstance->getAuxValue() > 0 ) + { + int motive = itemInstance->getAuxValue() - 1; + + wchar_t formatted[256]; + ZeroMemory(formatted, 256 * sizeof(wchar_t)); + swprintf(formatted, 256, L"** %ls %dx%d",Painting::Motive::values[motive]->name.c_str(),Painting::Motive::values[motive]->w/16,Painting::Motive::values[motive]->h/16); + + wstring motiveName = formatted; + + lines->push_back(HtmlString(motiveName.c_str(), eHTMLColor_c)); + } + else +#endif + { + return Item::appendHoverText(itemInstance, player, lines, advanced); + } +} \ No newline at end of file diff --git a/Minecraft.World/HangingEntityItem.h b/Minecraft.World/HangingEntityItem.h index 51bd8b23..d0e82897 100644 --- a/Minecraft.World/HangingEntityItem.h +++ b/Minecraft.World/HangingEntityItem.h @@ -16,6 +16,8 @@ public: virtual bool useOn(shared_ptr instance, shared_ptr player, Level *level, int xt, int yt, int zt, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly);//, float clickX, float clickY, float clickZ); private: - shared_ptr createEntity(Level *level, int x, int y, int z, int dir) ; + shared_ptr createEntity(Level *level, int x, int y, int z, int dir, int auxValue); // 4J Stu added auxValue param +public: + virtual void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced); }; diff --git a/Minecraft.World/Hasher.cpp b/Minecraft.World/Hasher.cpp index 7c3d0564..954ff1e4 100644 --- a/Minecraft.World/Hasher.cpp +++ b/Minecraft.World/Hasher.cpp @@ -1,5 +1,5 @@ #include "stdafx.h" -#include +#include #include "Hasher.h" @@ -19,7 +19,7 @@ wstring Hasher::getHash(wstring &name) //return new BigInteger(1, m.digest()).toString(16); // TODO 4J Stu - Will this hash us with the same distribution as the MD5? - return _toString( std::hash{}( s ) ); + return _toString(std::hash{}( s ) ); //} //catch (NoSuchAlgorithmException e) //{ diff --git a/Minecraft.World/HatchetItem.cpp b/Minecraft.World/HatchetItem.cpp index 16bf89bf..7fa204ca 100644 --- a/Minecraft.World/HatchetItem.cpp +++ b/Minecraft.World/HatchetItem.cpp @@ -25,7 +25,7 @@ HatchetItem::HatchetItem(int id, const Tier *tier) : DiggerItem (id, 3, tier, di // 4J - brought forward from 1.2.3 float HatchetItem::getDestroySpeed(shared_ptr itemInstance, Tile *tile) { - if (tile != NULL && tile->material == Material::wood) + if (tile != NULL && (tile->material == Material::wood || tile->material == Material::plant || tile->material == Material::replaceable_plant)) { return speed; } diff --git a/Minecraft.World/HayBlockTile.cpp b/Minecraft.World/HayBlockTile.cpp new file mode 100644 index 00000000..c782835c --- /dev/null +++ b/Minecraft.World/HayBlockTile.cpp @@ -0,0 +1,23 @@ +#include "stdafx.h" +#include "net.minecraft.world.h" +#include "HayBlockTile.h" + +HayBlockTile::HayBlockTile(int id) : RotatedPillarTile(id, Material::grass) +{ +} + +int HayBlockTile::getRenderShape() +{ + return SHAPE_TREE; +} + +Icon *HayBlockTile::getTypeTexture(int type) +{ + return icon; +} + +void HayBlockTile::registerIcons(IconRegister *iconRegister) +{ + iconTop = iconRegister->registerIcon(getIconName() + L"_top"); + icon = iconRegister->registerIcon(getIconName() + L"_side"); +} \ No newline at end of file diff --git a/Minecraft.World/HayBlockTile.h b/Minecraft.World/HayBlockTile.h new file mode 100644 index 00000000..fca2e449 --- /dev/null +++ b/Minecraft.World/HayBlockTile.h @@ -0,0 +1,18 @@ +#pragma once + +#include "RotatedPillarTile.h" + +class HayBlockTile : public RotatedPillarTile +{ + friend class ChunkRebuildData; +public: + HayBlockTile(int id); + + int getRenderShape(); + +protected: + Icon *getTypeTexture(int type); + +public: + void registerIcons(IconRegister *iconRegister); +}; \ No newline at end of file diff --git a/Minecraft.World/HealthBoostMobEffect.cpp b/Minecraft.World/HealthBoostMobEffect.cpp new file mode 100644 index 00000000..9066a041 --- /dev/null +++ b/Minecraft.World/HealthBoostMobEffect.cpp @@ -0,0 +1,16 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "HealthBoostMobEffect.h" + +HealthBoostMobEffect::HealthBoostMobEffect(int id, bool isHarmful, eMinecraftColour color) : MobEffect(id, isHarmful, color) +{ +} + +void HealthBoostMobEffect::removeAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier) +{ + MobEffect::removeAttributeModifiers(entity, attributes, amplifier); + if (entity->getHealth() > entity->getMaxHealth()) + { + entity->setHealth(entity->getMaxHealth()); + } +} diff --git a/Minecraft.World/HealthBoostMobEffect.h b/Minecraft.World/HealthBoostMobEffect.h new file mode 100644 index 00000000..e5746ba0 --- /dev/null +++ b/Minecraft.World/HealthBoostMobEffect.h @@ -0,0 +1,14 @@ +#pragma once + +#include "MobEffect.h" + +class LivingEntity; +class BaseAttributeMap; + +class HealthBoostMobEffect : public MobEffect +{ +public: + HealthBoostMobEffect(int id, bool isHarmful, eMinecraftColour color); + + void removeAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier); +}; \ No newline at end of file diff --git a/Minecraft.World/HealthCriteria.cpp b/Minecraft.World/HealthCriteria.cpp new file mode 100644 index 00000000..52db9f11 --- /dev/null +++ b/Minecraft.World/HealthCriteria.cpp @@ -0,0 +1,27 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.player.h" +#include "HealthCriteria.h" + +HealthCriteria::HealthCriteria(const wstring &id) : DummyCriteria(id) +{ +} + +int HealthCriteria::getScoreModifier(vector > *players) +{ + float health = 0; + + for (AUTO_VAR(it,players->begin()); it != players->end(); ++it) + { + shared_ptr player = *it; + health += player->getHealth() + player->getAbsorptionAmount(); + } + + if (players->size() > 0) health /= players->size(); + + return Mth::ceil(health); +} + +bool HealthCriteria::isReadOnly() +{ + return true; +} \ No newline at end of file diff --git a/Minecraft.World/HealthCriteria.h b/Minecraft.World/HealthCriteria.h new file mode 100644 index 00000000..8cd57046 --- /dev/null +++ b/Minecraft.World/HealthCriteria.h @@ -0,0 +1,12 @@ +#pragma once + +#include "DummyCriteria.h" + +class HealthCriteria : public DummyCriteria +{ +public: + HealthCriteria(const wstring &id); + + int getScoreModifier(vector > *players); + bool isReadOnly(); +}; \ No newline at end of file diff --git a/Minecraft.World/HeavyTile.cpp b/Minecraft.World/HeavyTile.cpp index 18460f2f..6c2b96e6 100644 --- a/Minecraft.World/HeavyTile.cpp +++ b/Minecraft.World/HeavyTile.cpp @@ -16,12 +16,12 @@ HeavyTile::HeavyTile(int type, Material *material, bool isSolidRender) : Tile(ty void HeavyTile::onPlace(Level *level, int x, int y, int z) { - level->addToTickNextTick(x, y, z, id, getTickDelay()); + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); } void HeavyTile::neighborChanged(Level *level, int x, int y, int z, int type) { - level->addToTickNextTick(x, y, z, id, getTickDelay()); + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); } void HeavyTile::tick(Level *level, int x, int y, int z, Random *random) @@ -34,56 +34,57 @@ void HeavyTile::tick(Level *level, int x, int y, int z, Random *random) void HeavyTile::checkSlide(Level *level, int x, int y, int z) { - int x2 = x; - int y2 = y; - int z2 = z; - if (isFree(level, x2, y2 - 1, z2) && y2 >= 0) + int x2 = x; + int y2 = y; + int z2 = z; + if (isFree(level, x2, y2 - 1, z2) && y2 >= 0) { - int r = 32; + int r = 32; if (instaFall || !level->hasChunksAt(x - r, y - r, z - r, x + r, y + r, z + r) ) { - level->setTile(x, y, z, 0); - while (isFree(level, x, y - 1, z) && y > 0) - y--; - if (y > 0) { - level->setTile(x, y, z, id); - } - } + level->removeTile(x, y, z); + while (isFree(level, x, y - 1, z) && y > 0) + y--; + if (y > 0) + { + level->setTileAndUpdate(x, y, z, id); + } + } else if (!level->isClientSide) { // 4J added - don't do anything just now if we can't create any new falling tiles if( !level->newFallingTileAllowed() ) { - level->addToTickNextTick(x, y, z, id, getTickDelay()); + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); return; } - shared_ptr e = shared_ptr( new FallingTile(level, x + 0.5f, y + 0.5f, z + 0.5f, id, level->getData(x, y, z)) ); + shared_ptr e = shared_ptr( new FallingTile(level, x + 0.5f, y + 0.5f, z + 0.5f, id, level->getData(x, y, z)) ); falling(e); - level->addEntity(e); - } - } + level->addEntity(e); + } + } } void HeavyTile::falling(shared_ptr entity) { } -int HeavyTile::getTickDelay() +int HeavyTile::getTickDelay(Level *level) { - return 5; + return 2; } bool HeavyTile::isFree(Level *level, int x, int y, int z) { - int t = level->getTile(x, y, z); - if (t == 0) return true; - if (t == Tile::fire_Id) return true; - Material *material = Tile::tiles[t]->material; - if (material == Material::water) return true; - if (material == Material::lava) return true; - return false; + int t = level->getTile(x, y, z); + if (t == 0) return true; + if (t == Tile::fire_Id) return true; + Material *material = Tile::tiles[t]->material; + if (material == Material::water) return true; + if (material == Material::lava) return true; + return false; } void HeavyTile::onLand(Level *level, int xt, int yt, int zt, int data) diff --git a/Minecraft.World/HeavyTile.h b/Minecraft.World/HeavyTile.h index a9186eae..f68ed162 100644 --- a/Minecraft.World/HeavyTile.h +++ b/Minecraft.World/HeavyTile.h @@ -10,17 +10,17 @@ class HeavyTile : public Tile public: static bool instaFall; - HeavyTile(int type, bool isSolidRender = true); - HeavyTile(int type, Material *material, bool isSolidRender = true); - virtual void onPlace(Level *level, int x, int y, int z); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); - virtual void tick(Level *level, int x, int y, int z, Random *random); + HeavyTile(int type, bool isSolidRender = true); + HeavyTile(int type, Material *material, bool isSolidRender = true); + virtual void onPlace(Level *level, int x, int y, int z); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual void tick(Level *level, int x, int y, int z, Random *random); private: void checkSlide(Level *level, int x, int y, int z); protected: virtual void falling(shared_ptr entity); public: - virtual int getTickDelay(); - static bool isFree(Level *level, int x, int y, int z); + virtual int getTickDelay(Level *level); + static bool isFree(Level *level, int x, int y, int z); virtual void onLand(Level *level, int xt, int yt, int zt, int data); }; diff --git a/Minecraft.World/HellBiome.cpp b/Minecraft.World/HellBiome.cpp index df0b4ed7..d023c01d 100644 --- a/Minecraft.World/HellBiome.cpp +++ b/Minecraft.World/HellBiome.cpp @@ -4,13 +4,14 @@ HellBiome::HellBiome(int id) : Biome(id) { - enemies.clear(); - friendlies.clear(); + enemies.clear(); + friendlies.clear(); friendlies_chicken.clear(); // 4J added friendlies_wolf.clear(); // 4J added - waterFriendlies.clear(); + waterFriendlies.clear(); + ambientFriendlies.clear(); - enemies.push_back(new MobSpawnerData(eTYPE_GHAST, 50, 4, 4)); - enemies.push_back(new MobSpawnerData(eTYPE_PIGZOMBIE, 100, 4, 4)); + enemies.push_back(new MobSpawnerData(eTYPE_GHAST, 50, 4, 4)); + enemies.push_back(new MobSpawnerData(eTYPE_PIGZOMBIE, 100, 4, 4)); enemies.push_back(new MobSpawnerData(eTYPE_LAVASLIME, 1, 4, 4)); } \ No newline at end of file diff --git a/Minecraft.World/HellFireFeature.cpp b/Minecraft.World/HellFireFeature.cpp index f795d997..4b32134c 100644 --- a/Minecraft.World/HellFireFeature.cpp +++ b/Minecraft.World/HellFireFeature.cpp @@ -5,15 +5,15 @@ bool HellFireFeature::place(Level *level, Random *random, int x, int y, int z) { - for (int i = 0; i < 64; i++) + for (int i = 0; i < 64; i++) { - int x2 = x + random->nextInt(8) - random->nextInt(8); - int y2 = y + random->nextInt(4) - random->nextInt(4); - int z2 = z + random->nextInt(8) - random->nextInt(8); - if (!level->isEmptyTile(x2, y2, z2)) continue; - if (level->getTile(x2, y2 - 1, z2) != Tile::hellRock_Id) continue; - level->setTile(x2, y2, z2, Tile::fire_Id); - } + int x2 = x + random->nextInt(8) - random->nextInt(8); + int y2 = y + random->nextInt(4) - random->nextInt(4); + int z2 = z + random->nextInt(8) - random->nextInt(8); + if (!level->isEmptyTile(x2, y2, z2)) continue; + if (level->getTile(x2, y2 - 1, z2) != Tile::netherRack_Id) continue; + level->setTileAndData(x2, y2, z2, Tile::fire_Id, 0, Tile::UPDATE_CLIENTS); + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/HellFlatLevelSource.cpp b/Minecraft.World/HellFlatLevelSource.cpp index 0b1c4359..4957f617 100644 --- a/Minecraft.World/HellFlatLevelSource.cpp +++ b/Minecraft.World/HellFlatLevelSource.cpp @@ -10,15 +10,15 @@ HellFlatLevelSource::HellFlatLevelSource(Level *level, __int64 seed) int hellScale = level->getLevelData()->getHellScale(); m_XZSize = ceil((float)xzSize / hellScale); - this->level = level; + this->level = level; - random = new Random(seed); + random = new Random(seed); pprandom = new Random(seed); } HellFlatLevelSource::~HellFlatLevelSource() { - delete random; + delete random; delete pprandom; } @@ -35,7 +35,7 @@ void HellFlatLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) int block = 0; if ( (yc <= 6) || ( yc >= 121 ) ) { - block = Tile::hellRock_Id; + block = Tile::netherRack_Id; } blocks[xc << 11 | zc << 7 | yc] = (byte) block; @@ -46,13 +46,13 @@ void HellFlatLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) void HellFlatLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks) { - for (int x = 0; x < 16; x++) + for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) + for (int z = 0; z < 16; z++) { - for (int y = Level::genDepthMinusOne; y >= 0; y--) + for (int y = Level::genDepthMinusOne; y >= 0; y--) { - int offs = (z * 16 + x) * Level::genDepth + y; + int offs = (z * 16 + x) * Level::genDepth + y; // 4J Build walls around the level bool blockSet = false; @@ -93,15 +93,15 @@ void HellFlatLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks) if (y >= Level::genDepthMinusOne - random->nextInt(5)) { - blocks[offs] = (byte) Tile::unbreakable_Id; - } + blocks[offs] = (byte) Tile::unbreakable_Id; + } else if (y <= 0 + random->nextInt(5)) { - blocks[offs] = (byte) Tile::unbreakable_Id; -} - } - } - } + blocks[offs] = (byte) Tile::unbreakable_Id; + } + } + } + } } LevelChunk *HellFlatLevelSource::create(int x, int z) @@ -111,28 +111,28 @@ LevelChunk *HellFlatLevelSource::create(int x, int z) LevelChunk *HellFlatLevelSource::getChunk(int xOffs, int zOffs) { - random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); + random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); // 4J - now allocating this with a physical alloc & bypassing general memory management so that it will get cleanly freed int chunksSize = Level::genDepth * 16 * 16; byte *tileData = (byte *)XPhysicalAlloc(chunksSize, MAXULONG_PTR, 4096, PAGE_READWRITE); XMemSet128(tileData,0,chunksSize); byteArray blocks = byteArray(tileData,chunksSize); -// byteArray blocks = byteArray(16 * level->depth * 16); + // byteArray blocks = byteArray(16 * level->depth * 16); - prepareHeights(xOffs, zOffs, blocks); - buildSurfaces(xOffs, zOffs, blocks); + prepareHeights(xOffs, zOffs, blocks); + buildSurfaces(xOffs, zOffs, blocks); -// caveFeature->apply(this, level, xOffs, zOffs, blocks); - // townFeature.apply(this, level, xOffs, zOffs, blocks); - // addCaves(xOffs, zOffs, blocks); - // addTowns(xOffs, zOffs, blocks); + // caveFeature->apply(this, level, xOffs, zOffs, blocks); + // townFeature.apply(this, level, xOffs, zOffs, blocks); + // addCaves(xOffs, zOffs, blocks); + // addTowns(xOffs, zOffs, blocks); // 4J - this now creates compressed block data from the blocks array passed in, so needs to be after data is finalised. // Also now need to free the passed in blocks as the LevelChunk doesn't use the passed in allocation anymore. - LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); + LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); XPhysicalFree(tileData); - return levelChunk; + return levelChunk; } // 4J - removed & moved into its own method from getChunk, so we can call recalcHeightmap after the chunk is added into the cache. Without @@ -151,9 +151,9 @@ bool HellFlatLevelSource::hasChunk(int x, int y) void HellFlatLevelSource::postProcess(ChunkSource *parent, int xt, int zt) { - HeavyTile::instaFall = true; - int xo = xt * 16; - int zo = zt * 16; + HeavyTile::instaFall = true; + int xo = xt * 16; + int zo = zt * 16; // 4J - added. The original java didn't do any setting of the random seed here. We'll be running our postProcess in parallel with getChunk etc. so // we need to use a separate random - have used the same initialisation code as used in RandomLevelSource::postProcess to make sure this random value @@ -163,26 +163,26 @@ void HellFlatLevelSource::postProcess(ChunkSource *parent, int xt, int zt) __int64 zScale = pprandom->nextLong() / 2 * 2 + 1; pprandom->setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed()); - int count = pprandom->nextInt(pprandom->nextInt(10) + 1) + 1; + int count = pprandom->nextInt(pprandom->nextInt(10) + 1) + 1; - for (int i = 0; i < count; i++) + for (int i = 0; i < count; i++) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth - 8) + 4; - int z = zo + pprandom->nextInt(16) + 8; - HellFireFeature().place(level, pprandom, x, y, z); - } - - count = pprandom->nextInt(pprandom->nextInt(10) + 1); - for (int i = 0; i < count; i++) + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth - 8) + 4; + int z = zo + pprandom->nextInt(16) + 8; + HellFireFeature().place(level, pprandom, x, y, z); + } + + count = pprandom->nextInt(pprandom->nextInt(10) + 1); + for (int i = 0; i < count; i++) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth - 8) + 4; - int z = zo + pprandom->nextInt(16) + 8; - LightGemFeature().place(level, pprandom, x, y, z); - } + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth - 8) + 4; + int z = zo + pprandom->nextInt(16) + 8; + LightGemFeature().place(level, pprandom, x, y, z); + } - HeavyTile::instaFall = false; + HeavyTile::instaFall = false; app.processSchematics(parent->getChunk(xt,zt)); @@ -210,15 +210,19 @@ wstring HellFlatLevelSource::gatherStats() vector *HellFlatLevelSource::getMobsAt(MobCategory *mobCategory, int x, int y, int z) { - Biome *biome = level->getBiome(x, z); - if (biome == NULL) - { - return NULL; - } - return biome->getMobs(mobCategory); + Biome *biome = level->getBiome(x, z); + if (biome == NULL) + { + return NULL; + } + return biome->getMobs(mobCategory); } TilePos *HellFlatLevelSource::findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z) { return NULL; } + +void HellFlatLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ) +{ +} \ No newline at end of file diff --git a/Minecraft.World/HellFlatLevelSource.h b/Minecraft.World/HellFlatLevelSource.h index b756d9a6..2e58f160 100644 --- a/Minecraft.World/HellFlatLevelSource.h +++ b/Minecraft.World/HellFlatLevelSource.h @@ -16,7 +16,7 @@ class HellFlatLevelSource : public ChunkSource { public: static const int CHUNK_HEIGHT = 8; - static const int CHUNK_WIDTH = 4; + static const int CHUNK_WIDTH = 4; private: Random *random; @@ -26,14 +26,14 @@ private: Level *level; public: - HellFlatLevelSource(Level *level, __int64 seed); + HellFlatLevelSource(Level *level, __int64 seed); ~HellFlatLevelSource(); private: - void prepareHeights(int xOffs, int zOffs, byteArray blocks); + void prepareHeights(int xOffs, int zOffs, byteArray blocks); public: - void buildSurfaces(int xOffs, int zOffs, byteArray blocks); + void buildSurfaces(int xOffs, int zOffs, byteArray blocks); LevelChunk *create(int x, int z); LevelChunk *getChunk(int xOffs, int zOffs); @@ -41,11 +41,12 @@ public: public: virtual bool hasChunk(int x, int y); - void postProcess(ChunkSource *parent, int xt, int zt); - bool save(bool force, ProgressListener *progressListener); - bool tick(); - bool shouldSave(); - wstring gatherStats(); + void postProcess(ChunkSource *parent, int xt, int zt); + bool save(bool force, ProgressListener *progressListener); + bool tick(); + bool shouldSave(); + wstring gatherStats(); virtual vector *getMobsAt(MobCategory *mobCategory, int x, int y, int z); - virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ); }; diff --git a/Minecraft.World/HellPortalFeature.cpp b/Minecraft.World/HellPortalFeature.cpp index 7a918e2c..66485578 100644 --- a/Minecraft.World/HellPortalFeature.cpp +++ b/Minecraft.World/HellPortalFeature.cpp @@ -5,33 +5,33 @@ bool HellPortalFeature::place(Level *level, Random *random, int x, int y, int z) { - if (!level->isEmptyTile(x, y, z)) return false; - if (level->getTile(x, y + 1, z) != Tile::hellRock_Id) return false; - level->setTile(x, y, z, Tile::lightGem_Id); + if (!level->isEmptyTile(x, y, z)) return false; + if (level->getTile(x, y + 1, z) != Tile::netherRack_Id) return false; + level->setTileAndData(x, y, z, Tile::glowstone_Id, 0, Tile::UPDATE_CLIENTS); - for (int i = 0; i < 1500; i++) + for (int i = 0; i < 1500; i++) { - int x2 = x + random->nextInt(8) - random->nextInt(8); - int y2 = y - random->nextInt(12); - int z2 = z + random->nextInt(8) - random->nextInt(8); - if (level->getTile(x2, y2, z2) != 0) continue; + int x2 = x + random->nextInt(8) - random->nextInt(8); + int y2 = y - random->nextInt(12); + int z2 = z + random->nextInt(8) - random->nextInt(8); + if (level->getTile(x2, y2, z2) != 0) continue; - int count = 0; - for (int t = 0; t < 6; t++) + int count = 0; + for (int t = 0; t < 6; t++) { - int tile = 0; - if (t == 0) tile = level->getTile(x2 - 1, y2, z2); - if (t == 1) tile = level->getTile(x2 + 1, y2, z2); - if (t == 2) tile = level->getTile(x2, y2 - 1, z2); - if (t == 3) tile = level->getTile(x2, y2 + 1, z2); - if (t == 4) tile = level->getTile(x2, y2, z2 - 1); - if (t == 5) tile = level->getTile(x2, y2, z2 + 1); + int tile = 0; + if (t == 0) tile = level->getTile(x2 - 1, y2, z2); + if (t == 1) tile = level->getTile(x2 + 1, y2, z2); + if (t == 2) tile = level->getTile(x2, y2 - 1, z2); + if (t == 3) tile = level->getTile(x2, y2 + 1, z2); + if (t == 4) tile = level->getTile(x2, y2, z2 - 1); + if (t == 5) tile = level->getTile(x2, y2, z2 + 1); - if (tile == Tile::lightGem_Id) count++; - } + if (tile == Tile::glowstone_Id) count++; + } - if (count == 1) level->setTile(x2, y2, z2, Tile::lightGem_Id); - } + if (count == 1) level->setTileAndData(x2, y2, z2, Tile::glowstone_Id, 0, Tile::UPDATE_CLIENTS); + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/HellRandomLevelSource.cpp b/Minecraft.World/HellRandomLevelSource.cpp index 10194f7d..31bb3d69 100644 --- a/Minecraft.World/HellRandomLevelSource.cpp +++ b/Minecraft.World/HellRandomLevelSource.cpp @@ -16,18 +16,18 @@ HellRandomLevelSource::HellRandomLevelSource(Level *level, __int64 seed) netherBridgeFeature = new NetherBridgeFeature(); caveFeature = new LargeHellCaveFeature(); - this->level = level; + this->level = level; - random = new Random(seed); + random = new Random(seed); pprandom = new Random(seed); // 4J - added, so that we can have a separate random for doing post-processing in parallel with creation - lperlinNoise1 = new PerlinNoise(random, 16); - lperlinNoise2 = new PerlinNoise(random, 16); - perlinNoise1 = new PerlinNoise(random, 8); - perlinNoise2 = new PerlinNoise(random, 4); - perlinNoise3 = new PerlinNoise(random, 4); - - scaleNoise = new PerlinNoise(random, 10); - depthNoise = new PerlinNoise(random, 16); + lperlinNoise1 = new PerlinNoise(random, 16); + lperlinNoise2 = new PerlinNoise(random, 16); + perlinNoise1 = new PerlinNoise(random, 8); + perlinNoise2 = new PerlinNoise(random, 4); + perlinNoise3 = new PerlinNoise(random, 4); + + scaleNoise = new PerlinNoise(random, 10); + depthNoise = new PerlinNoise(random, 16); } HellRandomLevelSource::~HellRandomLevelSource() @@ -35,124 +35,124 @@ HellRandomLevelSource::~HellRandomLevelSource() delete netherBridgeFeature; delete caveFeature; - delete random; + delete random; delete pprandom; // 4J added - delete lperlinNoise1; - delete lperlinNoise2; - delete perlinNoise1; - delete perlinNoise2; - delete perlinNoise3; - - delete scaleNoise; - delete depthNoise; + delete lperlinNoise1; + delete lperlinNoise2; + delete perlinNoise1; + delete perlinNoise2; + delete perlinNoise3; + + delete scaleNoise; + delete depthNoise; } void HellRandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) { - int xChunks = 16 / CHUNK_WIDTH; - int waterHeight = 32; + int xChunks = 16 / CHUNK_WIDTH; + int waterHeight = 32; - int xSize = xChunks + 1; - int ySize = Level::genDepth / CHUNK_HEIGHT + 1; - int zSize = xChunks + 1; + int xSize = xChunks + 1; + int ySize = Level::genDepth / CHUNK_HEIGHT + 1; + int zSize = xChunks + 1; doubleArray buffer; // 4J - used to be declared with class level scope but tidying up for thread safety reasons - buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize); + buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize); - for (int xc = 0; xc < xChunks; xc++) + for (int xc = 0; xc < xChunks; xc++) { - for (int zc = 0; zc < xChunks; zc++) + for (int zc = 0; zc < xChunks; zc++) { - for (int yc = 0; yc < Level::genDepth / CHUNK_HEIGHT; yc++) + for (int yc = 0; yc < Level::genDepth / CHUNK_HEIGHT; yc++) { - double yStep = 1 / (double) CHUNK_HEIGHT; - double s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; - double s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; - double s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; - double s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; - - double s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; - double s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; - double s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; - double s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; - - for (int y = 0; y < CHUNK_HEIGHT; y++) + double yStep = 1 / (double) CHUNK_HEIGHT; + double s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; + double s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; + double s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; + double s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; + + double s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; + double s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; + double s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; + double s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; + + for (int y = 0; y < CHUNK_HEIGHT; y++) { - double xStep = 1 / (double) CHUNK_WIDTH; + double xStep = 1 / (double) CHUNK_WIDTH; - double _s0 = s0; - double _s1 = s1; - double _s0a = (s2 - s0) * xStep; - double _s1a = (s3 - s1) * xStep; + double _s0 = s0; + double _s1 = s1; + double _s0a = (s2 - s0) * xStep; + double _s1a = (s3 - s1) * xStep; - for (int x = 0; x < CHUNK_WIDTH; x++) + for (int x = 0; x < CHUNK_WIDTH; x++) { - int offs = (x + xc * CHUNK_WIDTH) << Level::genDepthBitsPlusFour | (0 + zc * CHUNK_WIDTH) << Level::genDepthBits | (yc * CHUNK_HEIGHT + y); - int step = 1 << Level::genDepthBits; - double zStep = 1 / (double) CHUNK_WIDTH; + int offs = (x + xc * CHUNK_WIDTH) << Level::genDepthBitsPlusFour | (0 + zc * CHUNK_WIDTH) << Level::genDepthBits | (yc * CHUNK_HEIGHT + y); + int step = 1 << Level::genDepthBits; + double zStep = 1 / (double) CHUNK_WIDTH; - double val = _s0; - double vala = (_s1 - _s0) * zStep; - for (int z = 0; z < CHUNK_WIDTH; z++) + double val = _s0; + double vala = (_s1 - _s0) * zStep; + for (int z = 0; z < CHUNK_WIDTH; z++) { - int tileId = 0; - if (yc * CHUNK_HEIGHT + y < waterHeight) + int tileId = 0; + if (yc * CHUNK_HEIGHT + y < waterHeight) { - tileId = Tile::calmLava_Id; - } - if (val > 0) + tileId = Tile::calmLava_Id; + } + if (val > 0) { - tileId = Tile::hellRock_Id; - } - - blocks[offs] = (byte) tileId; - offs += step; - val += vala; - } - _s0 += _s0a; - _s1 += _s1a; - } - - s0 += s0a; - s1 += s1a; - s2 += s2a; - s3 += s3a; - } - } - } - } + tileId = Tile::netherRack_Id; + } + + blocks[offs] = (byte) tileId; + offs += step; + val += vala; + } + _s0 += _s0a; + _s1 += _s1a; + } + + s0 += s0a; + s1 += s1a; + s2 += s2a; + s3 += s3a; + } + } + } + } delete [] buffer.data; } void HellRandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks) { - int waterHeight = Level::genDepth - 64; + int waterHeight = Level::genDepth - 64; - double s = 1 / 32.0; + double s = 1 / 32.0; - doubleArray sandBuffer(16*16); // 4J - used to be declared with class level scope but moved here for thread safety + doubleArray sandBuffer(16*16); // 4J - used to be declared with class level scope but moved here for thread safety doubleArray gravelBuffer(16*16); doubleArray depthBuffer(16*16); - sandBuffer = perlinNoise2->getRegion(sandBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s, s, 1); - gravelBuffer = perlinNoise2->getRegion(gravelBuffer, xOffs * 16, 109, zOffs * 16, 16, 1, 16, s, 1, s); - depthBuffer = perlinNoise3->getRegion(depthBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s * 2, s * 2, s * 2); + sandBuffer = perlinNoise2->getRegion(sandBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s, s, 1); + gravelBuffer = perlinNoise2->getRegion(gravelBuffer, xOffs * 16, 109, zOffs * 16, 16, 1, 16, s, 1, s); + depthBuffer = perlinNoise3->getRegion(depthBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s * 2, s * 2, s * 2); - for (int x = 0; x < 16; x++) + for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) + for (int z = 0; z < 16; z++) { - bool sand = (sandBuffer[x + z * 16] + random->nextDouble() * 0.2) > 0; - bool gravel = (gravelBuffer[x + z * 16] + random->nextDouble() * 0.2) > 0; - int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random->nextDouble() * 0.25); + bool sand = (sandBuffer[x + z * 16] + random->nextDouble() * 0.2) > 0; + bool gravel = (gravelBuffer[x + z * 16] + random->nextDouble() * 0.2) > 0; + int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random->nextDouble() * 0.25); - int run = -1; + int run = -1; - byte top = (byte) Tile::hellRock_Id; - byte material = (byte) Tile::hellRock_Id; + byte top = (byte) Tile::netherRack_Id; + byte material = (byte) Tile::netherRack_Id; - for (int y = Level::genDepthMinusOne; y >= 0; y--) + for (int y = Level::genDepthMinusOne; y >= 0; y--) { - int offs = (z * 16 + x) * Level::genDepth + y; + int offs = (z * 16 + x) * Level::genDepth + y; // 4J Build walls around the level bool blockSet = false; @@ -193,38 +193,38 @@ void HellRandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks if (y >= Level::genDepthMinusOne - random->nextInt(5) || y <= 0 + random->nextInt(5)) { - blocks[offs] = (byte) Tile::unbreakable_Id; - } + blocks[offs] = (byte) Tile::unbreakable_Id; + } else { - int old = blocks[offs]; + int old = blocks[offs]; - if (old == 0) + if (old == 0) { - run = -1; - } - else if (old == Tile::hellRock_Id) + run = -1; + } + else if (old == Tile::netherRack_Id) { - if (run == -1) + if (run == -1) { - if (runDepth <= 0) + if (runDepth <= 0) { - top = 0; - material = (byte) Tile::hellRock_Id; - } + top = 0; + material = (byte) Tile::netherRack_Id; + } else if (y >= waterHeight - 4 && y <= waterHeight + 1) { - top = (byte) Tile::hellRock_Id; - material = (byte) Tile::hellRock_Id; - if (gravel) top = (byte) Tile::gravel_Id; - if (gravel) material = (byte) Tile::hellRock_Id; + top = (byte) Tile::netherRack_Id; + material = (byte) Tile::netherRack_Id; + if (gravel) top = (byte) Tile::gravel_Id; + if (gravel) material = (byte) Tile::netherRack_Id; if (sand) { // 4J Stu - Make some nether wart spawn outside of the nether fortresses if(random->nextInt(16) == 0) { top = (byte) Tile::netherStalk_Id; - + // Place the nether wart on top of the soul sand y += 1; int genDepthMinusOne = Level::genDepthMinusOne; // Take into local int for PS4 as min takes a reference to the const int there and then needs the value to exist for the linker @@ -234,30 +234,30 @@ void HellRandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks } else { - top = (byte) Tile::hellSand_Id; + top = (byte) Tile::soulsand_Id; } } - if (sand) material = (byte) Tile::hellSand_Id; - } + if (sand) material = (byte) Tile::soulsand_Id; + } - if (y < waterHeight && top == 0) top = (byte) Tile::calmLava_Id; + if (y < waterHeight && top == 0) top = (byte) Tile::calmLava_Id; - run = runDepth; + run = runDepth; // 4J Stu - If sand, then allow adding nether wart at heights below the water level - if (y >= waterHeight - 1 || sand) blocks[offs] = top; - else blocks[offs] = material; - } + if (y >= waterHeight - 1 || sand) blocks[offs] = top; + else blocks[offs] = material; + } else if (run > 0) { - run--; - blocks[offs] = material; - } - } - } - } - } - } - delete [] sandBuffer.data; + run--; + blocks[offs] = material; + } + } + } + } + } + } + delete [] sandBuffer.data; delete [] gravelBuffer.data; delete [] depthBuffer.data; } @@ -269,27 +269,27 @@ LevelChunk *HellRandomLevelSource::create(int x, int z) LevelChunk *HellRandomLevelSource::getChunk(int xOffs, int zOffs) { - random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); + random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); // 4J - now allocating this with a physical alloc & bypassing general memory management so that it will get cleanly freed int blocksSize = Level::genDepth * 16 * 16; byte *tileData = (byte *)XPhysicalAlloc(blocksSize, MAXULONG_PTR, 4096, PAGE_READWRITE); XMemSet128(tileData,0,blocksSize); byteArray blocks = byteArray(tileData,blocksSize); -// byteArray blocks = byteArray(16 * level->depth * 16); + // byteArray blocks = byteArray(16 * level->depth * 16); - prepareHeights(xOffs, zOffs, blocks); - buildSurfaces(xOffs, zOffs, blocks); + prepareHeights(xOffs, zOffs, blocks); + buildSurfaces(xOffs, zOffs, blocks); - caveFeature->apply(this, level, xOffs, zOffs, blocks); + caveFeature->apply(this, level, xOffs, zOffs, blocks); netherBridgeFeature->apply(this, level, xOffs, zOffs, blocks); // 4J - this now creates compressed block data from the blocks array passed in, so needs to be after data is finalised. // Also now need to free the passed in blocks as the LevelChunk doesn't use the passed in allocation anymore. - LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); + LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); levelChunk->setCheckAllLight(); XPhysicalFree(tileData); - return levelChunk; + return levelChunk; } // 4J - removed & moved into its own method from getChunk, so we can call recalcHeightmap after the chunk is added into the cache. Without @@ -303,105 +303,105 @@ void HellRandomLevelSource::lightChunk(LevelChunk *lc) doubleArray HellRandomLevelSource::getHeights(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize) { - if (buffer.data == NULL) + if (buffer.data == NULL) { - buffer = doubleArray(xSize * ySize * zSize); - } + buffer = doubleArray(xSize * ySize * zSize); + } - double s = 1 * 684.412; - double hs = 1 * 684.412 * 3; + double s = 1 * 684.412; + double hs = 1 * 684.412 * 3; doubleArray pnr, ar, br, sr, dr, fi, fis; // 4J - used to be declared with class level scope but moved here for thread safety - sr = scaleNoise->getRegion(sr, x, y, z, xSize, 1, zSize, 1.0, 0, 1.0); - dr = depthNoise->getRegion(dr, x, y, z, xSize, 1, zSize, 100.0, 0, 100.0); + sr = scaleNoise->getRegion(sr, x, y, z, xSize, 1, zSize, 1.0, 0, 1.0); + dr = depthNoise->getRegion(dr, x, y, z, xSize, 1, zSize, 100.0, 0, 100.0); - pnr = perlinNoise1->getRegion(pnr, x, y, z, xSize, ySize, zSize, s / 80.0, hs / 60.0, s / 80.0); - ar = lperlinNoise1->getRegion(ar, x, y, z, xSize, ySize, zSize, s, hs, s); - br = lperlinNoise2->getRegion(br, x, y, z, xSize, ySize, zSize, s, hs, s); + pnr = perlinNoise1->getRegion(pnr, x, y, z, xSize, ySize, zSize, s / 80.0, hs / 60.0, s / 80.0); + ar = lperlinNoise1->getRegion(ar, x, y, z, xSize, ySize, zSize, s, hs, s); + br = lperlinNoise2->getRegion(br, x, y, z, xSize, ySize, zSize, s, hs, s); - int p = 0; - int pp = 0; - doubleArray yoffs = doubleArray(ySize); - for (int yy = 0; yy < ySize; yy++) + int p = 0; + int pp = 0; + doubleArray yoffs = doubleArray(ySize); + for (int yy = 0; yy < ySize; yy++) { - yoffs[yy] = cos(yy * PI * 6 / (double) ySize) * 2; + yoffs[yy] = cos(yy * PI * 6 / (double) ySize) * 2; - double dd = yy; - if (yy > ySize / 2) + double dd = yy; + if (yy > ySize / 2) { - dd = (ySize - 1) - yy; - } - if (dd < 4) { - dd = 4 - dd; - yoffs[yy] -= dd * dd * dd * 10; - } - } - - for (int xx = 0; xx < xSize; xx++) + dd = (ySize - 1) - yy; + } + if (dd < 4) { + dd = 4 - dd; + yoffs[yy] -= dd * dd * dd * 10; + } + } + + for (int xx = 0; xx < xSize; xx++) { - for (int zz = 0; zz < zSize; zz++) + for (int zz = 0; zz < zSize; zz++) { - double scale = ((sr[pp] + 256.0) / 512); - if (scale > 1) scale = 1; + double scale = ((sr[pp] + 256.0) / 512); + if (scale > 1) scale = 1; - double floating = 0; + double floating = 0; - double depth = (dr[pp] / 8000.0); - if (depth < 0) depth = -depth; - depth = depth * 3.0 - 3.0; + double depth = (dr[pp] / 8000.0); + if (depth < 0) depth = -depth; + depth = depth * 3.0 - 3.0; - if (depth < 0) + if (depth < 0) { - depth = depth / 2; - if (depth < -1) depth = -1; - depth = depth / 1.4; - depth /= 2; - scale = 0; - } + depth = depth / 2; + if (depth < -1) depth = -1; + depth = depth / 1.4; + depth /= 2; + scale = 0; + } else { - if (depth > 1) depth = 1; - depth = depth / 6; - } - scale = (scale) + 0.5; - depth = depth * ySize / 16; - pp++; - - for (int yy = 0; yy < ySize; yy++) + if (depth > 1) depth = 1; + depth = depth / 6; + } + scale = (scale) + 0.5; + depth = depth * ySize / 16; + pp++; + + for (int yy = 0; yy < ySize; yy++) { - double val = 0; + double val = 0; - double yOffs = yoffs[yy]; + double yOffs = yoffs[yy]; - double bb = ar[p] / 512; - double cc = br[p] / 512; + double bb = ar[p] / 512; + double cc = br[p] / 512; - double v = (pnr[p] / 10 + 1) / 2; - if (v < 0) val = bb; - else if (v > 1) val = cc; - else val = bb + (cc - bb) * v; - val -= yOffs; + double v = (pnr[p] / 10 + 1) / 2; + if (v < 0) val = bb; + else if (v > 1) val = cc; + else val = bb + (cc - bb) * v; + val -= yOffs; - if (yy > ySize - 4) + if (yy > ySize - 4) { - double slide = (yy - (ySize - 4)) / (4 - 1.0f); - val = val * (1 - slide) + -10 * slide; - } + double slide = (yy - (ySize - 4)) / (4 - 1.0f); + val = val * (1 - slide) + -10 * slide; + } - if (yy < floating) + if (yy < floating) { - double slide = (floating - yy) / (4); - if (slide < 0) slide = 0; - if (slide > 1) slide = 1; - val = val * (1 - slide) + -10 * slide; - } - - buffer[p] = val; - p++; - } - } - } + double slide = (floating - yy) / (4); + if (slide < 0) slide = 0; + if (slide > 1) slide = 1; + val = val * (1 - slide) + -10 * slide; + } + + buffer[p] = val; + p++; + } + } + } delete [] pnr.data; delete [] ar.data; @@ -412,7 +412,7 @@ doubleArray HellRandomLevelSource::getHeights(doubleArray buffer, int x, int y, delete [] fis.data; delete [] yoffs.data; - return buffer; + return buffer; } bool HellRandomLevelSource::hasChunk(int x, int y) @@ -422,9 +422,9 @@ bool HellRandomLevelSource::hasChunk(int x, int y) void HellRandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) { - HeavyTile::instaFall = true; - int xo = xt * 16; - int zo = zt * 16; + HeavyTile::instaFall = true; + int xo = xt * 16; + int zo = zt * 16; // 4J - added. The original java didn't do any setting of the random seed here. We'll be running our postProcess in parallel with getChunk etc. so // we need to use a separate random - have used the same initialisation code as used in RandomLevelSource::postProcess to make sure this random value @@ -436,58 +436,58 @@ void HellRandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) netherBridgeFeature->postProcess(level, pprandom, xt, zt); - for (int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth - 8) + 4; - int z = zo + pprandom->nextInt(16) + 8; - HellSpringFeature(Tile::lava_Id).place(level, pprandom, x, y, z); - } + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth - 8) + 4; + int z = zo + pprandom->nextInt(16) + 8; + HellSpringFeature(Tile::lava_Id, false).place(level, pprandom, x, y, z); + } - int count = pprandom->nextInt(pprandom->nextInt(10) + 1) + 1; + int count = pprandom->nextInt(pprandom->nextInt(10) + 1) + 1; - for (int i = 0; i < count; i++) + for (int i = 0; i < count; i++) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth - 8) + 4; - int z = zo + pprandom->nextInt(16) + 8; - HellFireFeature().place(level, pprandom, x, y, z); - } - - count = pprandom->nextInt(pprandom->nextInt(10) + 1); - for (int i = 0; i < count; i++) + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth - 8) + 4; + int z = zo + pprandom->nextInt(16) + 8; + HellFireFeature().place(level, pprandom, x, y, z); + } + + count = pprandom->nextInt(pprandom->nextInt(10) + 1); + for (int i = 0; i < count; i++) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth - 8) + 4; - int z = zo + pprandom->nextInt(16) + 8; - LightGemFeature().place(level, pprandom, x, y, z); - } + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth - 8) + 4; + int z = zo + pprandom->nextInt(16) + 8; + LightGemFeature().place(level, pprandom, x, y, z); + } - for (int i = 0; i < 10; i++) + for (int i = 0; i < 10; i++) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth); - int z = zo + pprandom->nextInt(16) + 8; - HellPortalFeature().place(level, pprandom, x, y, z); - } + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth); + int z = zo + pprandom->nextInt(16) + 8; + HellPortalFeature().place(level, pprandom, x, y, z); + } - if (pprandom->nextInt(1) == 0) + if (pprandom->nextInt(1) == 0) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth); - int z = zo + pprandom->nextInt(16) + 8; - FlowerFeature(Tile::mushroom1_Id).place(level, pprandom, x, y, z); - } + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth); + int z = zo + pprandom->nextInt(16) + 8; + FlowerFeature(Tile::mushroom_brown_Id).place(level, pprandom, x, y, z); + } - if (pprandom->nextInt(1) == 0) + if (pprandom->nextInt(1) == 0) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth); - int z = zo + pprandom->nextInt(16) + 8; - FlowerFeature(Tile::mushroom2_Id).place(level, pprandom, x, y, z); - } + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth); + int z = zo + pprandom->nextInt(16) + 8; + FlowerFeature(Tile::mushroom_red_Id).place(level, pprandom, x, y, z); + } - OreFeature quartzFeature(Tile::netherQuartz_Id, 13, Tile::hellRock_Id); + OreFeature quartzFeature(Tile::netherQuartz_Id, 13, Tile::netherRack_Id); for (int i = 0; i < 16; i++) { int x = xo + pprandom->nextInt(16); @@ -496,8 +496,17 @@ void HellRandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) quartzFeature.place(level, pprandom, x, y, z); } - HeavyTile::instaFall = false; - + for (int i = 0; i < 16; i++) + { + int x = xo + random->nextInt(16); + int y = random->nextInt(Level::genDepth - 20) + 10; + int z = zo + random->nextInt(16); + HellSpringFeature hellSpringFeature(Tile::lava_Id, true); + hellSpringFeature.place(level, random, x, y, z); + } + + HeavyTile::instaFall = false; + app.processSchematics(parent->getChunk(xt,zt)); } @@ -524,21 +533,33 @@ wstring HellRandomLevelSource::gatherStats() vector *HellRandomLevelSource::getMobsAt(MobCategory *mobCategory, int x, int y, int z) { - // check if the coordinates is within a netherbridge - if (mobCategory == MobCategory::monster && netherBridgeFeature->isInsideFeature(x, y, z)) + // check if the coordinates is within a netherbridge + if (mobCategory == MobCategory::monster) { - return netherBridgeFeature->getBridgeEnemies(); - } + if(netherBridgeFeature->isInsideFeature(x, y, z)) + { + return netherBridgeFeature->getBridgeEnemies(); + } + if ((netherBridgeFeature->isInsideBoundingFeature(x, y, z) && level->getTile(x, y - 1, z) == Tile::netherBrick_Id)) + { + return netherBridgeFeature->getBridgeEnemies(); + } + } - Biome *biome = level->getBiome(x, z); - if (biome == NULL) + Biome *biome = level->getBiome(x, z); + if (biome == NULL) { - return NULL; - } - return biome->getMobs(mobCategory); + return NULL; + } + return biome->getMobs(mobCategory); } TilePos *HellRandomLevelSource::findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z) { return NULL; } + +void HellRandomLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ) +{ + netherBridgeFeature->apply(this, level, chunkX, chunkZ, NULL); +} \ No newline at end of file diff --git a/Minecraft.World/HellRandomLevelSource.h b/Minecraft.World/HellRandomLevelSource.h index 0587e86a..2a0c3c86 100644 --- a/Minecraft.World/HellRandomLevelSource.h +++ b/Minecraft.World/HellRandomLevelSource.h @@ -17,36 +17,36 @@ class HellRandomLevelSource : public ChunkSource { public: static const int CHUNK_HEIGHT = 8; - static const int CHUNK_WIDTH = 4; + static const int CHUNK_WIDTH = 4; private: Random *random; Random *pprandom; // 4J added PerlinNoise *lperlinNoise1; - PerlinNoise *lperlinNoise2; - PerlinNoise *perlinNoise1; - PerlinNoise *perlinNoise2; - PerlinNoise *perlinNoise3; + PerlinNoise *lperlinNoise2; + PerlinNoise *perlinNoise1; + PerlinNoise *perlinNoise2; + PerlinNoise *perlinNoise3; public: PerlinNoise *scaleNoise; - PerlinNoise *depthNoise; + PerlinNoise *depthNoise; private: Level *level; public: - HellRandomLevelSource(Level *level, __int64 seed); + HellRandomLevelSource(Level *level, __int64 seed); ~HellRandomLevelSource(); NetherBridgeFeature *netherBridgeFeature; private: - void prepareHeights(int xOffs, int zOffs, byteArray blocks); + void prepareHeights(int xOffs, int zOffs, byteArray blocks); public: - void buildSurfaces(int xOffs, int zOffs, byteArray blocks); + void buildSurfaces(int xOffs, int zOffs, byteArray blocks); private: LargeFeature *caveFeature; @@ -57,16 +57,17 @@ public: virtual void lightChunk(LevelChunk *lc); // 4J added private: - doubleArray getHeights(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize); + doubleArray getHeights(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize); public: bool hasChunk(int x, int y); - void postProcess(ChunkSource *parent, int xt, int zt); - bool save(bool force, ProgressListener *progressListener); - bool tick(); - bool shouldSave(); - wstring gatherStats(); + void postProcess(ChunkSource *parent, int xt, int zt); + bool save(bool force, ProgressListener *progressListener); + bool tick(); + bool shouldSave(); + wstring gatherStats(); virtual vector *getMobsAt(MobCategory *mobCategory, int x, int y, int z); - virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ); }; diff --git a/Minecraft.World/HellSpringFeature.cpp b/Minecraft.World/HellSpringFeature.cpp index cfd2d74f..1b62b9b2 100644 --- a/Minecraft.World/HellSpringFeature.cpp +++ b/Minecraft.World/HellSpringFeature.cpp @@ -3,40 +3,41 @@ #include "HellSpringFeature.h" #include "net.minecraft.world.level.tile.h" -HellSpringFeature::HellSpringFeature(int tile) +HellSpringFeature::HellSpringFeature(int tile, bool insideRock) { this->tile = tile; + this->insideRock = insideRock; } bool HellSpringFeature::place(Level *level, Random *random, int x, int y, int z) { - if (level->getTile(x, y + 1, z) != Tile::hellRock_Id) return false; - if (level->getTile(x, y - 1, z) != Tile::hellRock_Id) return false; - - if (level->getTile(x, y, z) != 0 && level->getTile(x, y, z) != Tile::hellRock_Id) return false; - - int rockCount = 0; - if (level->getTile(x - 1, y, z) == Tile::hellRock_Id) rockCount++; - if (level->getTile(x + 1, y, z) == Tile::hellRock_Id) rockCount++; - if (level->getTile(x, y, z - 1) == Tile::hellRock_Id) rockCount++; - if (level->getTile(x, y, z + 1) == Tile::hellRock_Id) rockCount++; - if (level->getTile(x, y - 1, z) == Tile::hellRock_Id) rockCount++; - - int holeCount = 0; - if (level->isEmptyTile(x - 1, y, z)) holeCount++; - if (level->isEmptyTile(x + 1, y, z)) holeCount++; - if (level->isEmptyTile(x, y, z - 1)) holeCount++; - if (level->isEmptyTile(x, y, z + 1)) holeCount++; + if (level->getTile(x, y + 1, z) != Tile::netherRack_Id) return false; + if (level->getTile(x, y - 1, z) != Tile::netherRack_Id) return false; + + if (level->getTile(x, y, z) != 0 && level->getTile(x, y, z) != Tile::netherRack_Id) return false; + + int rockCount = 0; + if (level->getTile(x - 1, y, z) == Tile::netherRack_Id) rockCount++; + if (level->getTile(x + 1, y, z) == Tile::netherRack_Id) rockCount++; + if (level->getTile(x, y, z - 1) == Tile::netherRack_Id) rockCount++; + if (level->getTile(x, y, z + 1) == Tile::netherRack_Id) rockCount++; + if (level->getTile(x, y - 1, z) == Tile::netherRack_Id) rockCount++; + + int holeCount = 0; + if (level->isEmptyTile(x - 1, y, z)) holeCount++; + if (level->isEmptyTile(x + 1, y, z)) holeCount++; + if (level->isEmptyTile(x, y, z - 1)) holeCount++; + if (level->isEmptyTile(x, y, z + 1)) holeCount++; if (level->isEmptyTile(x, y - 1, z)) holeCount++; - if (rockCount == 4 && holeCount == 1) + if ((!insideRock && rockCount == 4 && holeCount == 1) || rockCount == 5) { - level->setTile(x, y, z, tile); - level->setInstaTick(true); - Tile::tiles[tile]->tick(level, x, y, z, random); - level->setInstaTick(false); - } + level->setTileAndData(x, y, z, tile, 0, Tile::UPDATE_CLIENTS); + level->setInstaTick(true); + Tile::tiles[tile]->tick(level, x, y, z, random); + level->setInstaTick(false); + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/HellSpringFeature.h b/Minecraft.World/HellSpringFeature.h index a8ffbc00..a0ab4c93 100644 --- a/Minecraft.World/HellSpringFeature.h +++ b/Minecraft.World/HellSpringFeature.h @@ -6,9 +6,10 @@ class HellSpringFeature : public Feature { private: int tile; + bool insideRock; public: - HellSpringFeature(int tile); + HellSpringFeature(int tile, bool insideRock); - virtual bool place(Level *level, Random *random, int x, int y, int z); + virtual bool place(Level *level, Random *random, int x, int y, int z); }; \ No newline at end of file diff --git a/Minecraft.World/HitResult.cpp b/Minecraft.World/HitResult.cpp index ffa93541..8599e034 100644 --- a/Minecraft.World/HitResult.cpp +++ b/Minecraft.World/HitResult.cpp @@ -5,7 +5,7 @@ HitResult::HitResult(int x, int y, int z, int f, Vec3 *pos) { - this->type = TILE; + type = TILE; this->x = x; this->y = y; this->z = z; @@ -17,7 +17,7 @@ HitResult::HitResult(int x, int y, int z, int f, Vec3 *pos) HitResult::HitResult(shared_ptr entity) { - this->type = ENTITY; + type = ENTITY; this->entity = entity; pos = Vec3::newTemp(entity->x, entity->y, entity->z); diff --git a/Minecraft.World/HoeItem.cpp b/Minecraft.World/HoeItem.cpp index 50dde305..9714e5fc 100644 --- a/Minecraft.World/HoeItem.cpp +++ b/Minecraft.World/HoeItem.cpp @@ -14,15 +14,13 @@ HoeItem::HoeItem(int id, const Tier *tier) : Item(id) bool HoeItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { - if (!player->mayBuild(x, y, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, instance)) return false; // 4J-PB - Adding a test only version to allow tooltips to be displayed int targetType = level->getTile(x, y, z); - // Material above = level.getMaterial(x, y + 1, z); int above = level->getTile(x, y + 1, z); - // 4J-PB - missing parentheses if (face != 0 && above == 0 && (targetType == Tile::grass_Id || targetType == Tile::dirt_Id)) { if(!bTestUseOnOnly) @@ -31,8 +29,8 @@ bool HoeItem::useOn(shared_ptr instance, shared_ptr player level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, tile->soundType->getStepSound(), (tile->soundType->getVolume() + 1) / 2, tile->soundType->getPitch() * 0.8f); if (level->isClientSide) return true; - level->setTile(x, y, z, tile->id); - instance->hurt(1, player); + level->setTileAndUpdate(x, y, z, tile->id); + instance->hurtAndBreak(1, player); } return true; } diff --git a/Minecraft.World/Hopper.h b/Minecraft.World/Hopper.h new file mode 100644 index 00000000..08555dcf --- /dev/null +++ b/Minecraft.World/Hopper.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Container.h" + +class Level; + +class Hopper : public virtual Container +{ +public: + virtual Level *getLevel() = 0; + virtual double getLevelX() = 0; + virtual double getLevelY() = 0; + virtual double getLevelZ() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/HopperMenu.cpp b/Minecraft.World/HopperMenu.cpp new file mode 100644 index 00000000..afc700c3 --- /dev/null +++ b/Minecraft.World/HopperMenu.cpp @@ -0,0 +1,76 @@ +#include "stdafx.h" +#include "net.minecraft.world.inventory.h" +#include "HopperMenu.h" + +HopperMenu::HopperMenu(shared_ptr inventory, shared_ptr hopper) +{ + this->hopper = hopper; + hopper->startOpen(); + int yo = 51; + + for (int x = 0; x < hopper->getContainerSize(); x++) + { + addSlot(new Slot(hopper, x, 44 + x * 18, 20)); + } + + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(inventory, x + y * 9 + 9, 8 + x * 18, y * 18 + yo)); + } + } + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(inventory, x, 8 + x * 18, 58 + yo)); + } +} + +bool HopperMenu::stillValid(shared_ptr player) +{ + return hopper->stillValid(player); +} + +shared_ptr HopperMenu::quickMoveStack(shared_ptr player, int slotIndex) +{ + shared_ptr clicked = nullptr; + Slot *slot = slots.at(slotIndex); + if (slot != NULL && slot->hasItem()) + { + shared_ptr stack = slot->getItem(); + clicked = stack->copy(); + + if (slotIndex < hopper->getContainerSize()) + { + if (!moveItemStackTo(stack, hopper->getContainerSize(), slots.size(), true)) + { + return nullptr; + } + } else { + if (!moveItemStackTo(stack, 0, hopper->getContainerSize(), false)) + { + return nullptr; + } + } + if (stack->count == 0) + { + slot->set(nullptr); + } + else + { + slot->setChanged(); + } + } + return clicked; +} + +void HopperMenu::removed(shared_ptr player) +{ + AbstractContainerMenu::removed(player); + hopper->stopOpen(); +} + +shared_ptr HopperMenu::getContainer() +{ + return hopper; +} \ No newline at end of file diff --git a/Minecraft.World/HopperMenu.h b/Minecraft.World/HopperMenu.h new file mode 100644 index 00000000..ee0c4b93 --- /dev/null +++ b/Minecraft.World/HopperMenu.h @@ -0,0 +1,24 @@ +#pragma once + +#include "AbstractContainerMenu.h" + +class HopperMenu : public AbstractContainerMenu +{ +private: + shared_ptr hopper; + +public: + static const int CONTENTS_SLOT_START = 0; + static const int INV_SLOT_START = CONTENTS_SLOT_START + 5; + static const int INV_SLOT_END = INV_SLOT_START + 9 * 3; + static const int USE_ROW_SLOT_START = INV_SLOT_END; + static const int USE_ROW_SLOT_END = USE_ROW_SLOT_START + 9; + +public: + HopperMenu(shared_ptr inventory, shared_ptr hopper); + + bool stillValid(shared_ptr player); + shared_ptr quickMoveStack(shared_ptr player, int slotIndex); + void removed(shared_ptr player); + shared_ptr getContainer(); +}; \ No newline at end of file diff --git a/Minecraft.World/HopperTile.cpp b/Minecraft.World/HopperTile.cpp new file mode 100644 index 00000000..c111105e --- /dev/null +++ b/Minecraft.World/HopperTile.cpp @@ -0,0 +1,211 @@ +#include "stdafx.h" +#include "net.minecraft.h" +#include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.inventory.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.world.h" +#include "HopperTile.h" + +const wstring HopperTile::TEXTURE_OUTSIDE = L"hopper_outside"; +const wstring HopperTile::TEXTURE_INSIDE = L"hopper_inside"; + +HopperTile::HopperTile(int id) : BaseEntityTile(id, Material::metal, isSolidRender() ) +{ + setShape(0, 0, 0, 1, 1, 1); +} + +void HopperTile::updateShape(LevelSource *level, int x, int y, int z, int forceData , shared_ptr forceEntity) +{ + setShape(0, 0, 0, 1, 1, 1); +} + +void HopperTile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source) +{ + setShape(0, 0, 0, 1, 10.0f / 16.0f, 1); + BaseEntityTile::addAABBs(level, x, y, z, box, boxes, source); + float thickness = 2.0f / 16.0f; + setShape(0, 0, 0, thickness, 1, 1); + BaseEntityTile::addAABBs(level, x, y, z, box, boxes, source); + setShape(0, 0, 0, 1, 1, thickness); + BaseEntityTile::addAABBs(level, x, y, z, box, boxes, source); + setShape(1 - thickness, 0, 0, 1, 1, 1); + BaseEntityTile::addAABBs(level, x, y, z, box, boxes, source); + setShape(0, 0, 1 - thickness, 1, 1, 1); + BaseEntityTile::addAABBs(level, x, y, z, box, boxes, source); + + setShape(0, 0, 0, 1, 1, 1); +} + +int HopperTile::getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) +{ + int attached = Facing::OPPOSITE_FACING[face]; + if (attached == Facing::UP) attached = Facing::DOWN; + return attached; +} + +shared_ptr HopperTile::newTileEntity(Level *level) +{ + return shared_ptr( new HopperTileEntity() ); +} + +void HopperTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) +{ + BaseEntityTile::setPlacedBy(level, x, y, z, by, itemInstance); + + if (itemInstance->hasCustomHoverName()) + { + shared_ptr hopper = getHopper(level, x, y, z); + hopper->setCustomName(itemInstance->getHoverName()); + } +} + +void HopperTile::onPlace(Level *level, int x, int y, int z) +{ + BaseEntityTile::onPlace(level, x, y, z); + checkPoweredState(level, x, y, z); +} + +bool HopperTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly) +{ + if (level->isClientSide) + { + return true; + } + shared_ptr hopper = getHopper(level, x, y, z); + if (hopper != NULL) player->openHopper(hopper); + return true; +} + +void HopperTile::neighborChanged(Level *level, int x, int y, int z, int type) +{ + checkPoweredState(level, x, y, z); +} + +void HopperTile::checkPoweredState(Level *level, int x, int y, int z) +{ + int data = level->getData(x, y, z); + int attachedFace = getAttachedFace(data); + bool shouldBeOn = !level->hasNeighborSignal(x, y, z); + bool isOn = isTurnedOn(data); + + if (shouldBeOn != isOn) + { + level->setData(x, y, z, attachedFace | (shouldBeOn ? 0 : MASK_TOGGLE), UPDATE_NONE); + } +} + +void HopperTile::onRemove(Level *level, int x, int y, int z, int id, int data) +{ + shared_ptr container = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + if (container != NULL) + { + for (int i = 0; i < container->getContainerSize(); i++) + { + shared_ptr item = container->getItem(i); + if (item != NULL) + { + float xo = random.nextFloat() * 0.8f + 0.1f; + float yo = random.nextFloat() * 0.8f + 0.1f; + float zo = random.nextFloat() * 0.8f + 0.1f; + + while (item->count > 0) + { + int count = random.nextInt(21) + 10; + if (count > item->count) count = item->count; + item->count -= count; + + shared_ptr itemEntity = shared_ptr( new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr( new ItemInstance(item->id, count, item->getAuxValue())))); + + if (item->hasTag()) + { + itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); + } + + float pow = 0.05f; + itemEntity->xd = (float) random.nextGaussian() * pow; + itemEntity->yd = (float) random.nextGaussian() * pow + 0.2f; + itemEntity->zd = (float) random.nextGaussian() * pow; + level->addEntity(itemEntity); + } + } + } + level->updateNeighbourForOutputSignal(x, y, z, id); + } + + BaseEntityTile::onRemove(level, x, y, z, id, data); +} + +int HopperTile::getRenderShape() +{ + return SHAPE_HOPPER; +} + +bool HopperTile::isCubeShaped() +{ + return false; +} + +bool HopperTile::isSolidRender(bool isServerLevel /*= false*/) +{ + return false; +} + +bool HopperTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) +{ + return true; +} + +Icon *HopperTile::getTexture(int face, int data) +{ + if (face == Facing::UP) + { + return hopperTopIcon; + } + return hopperIcon; +} + +int HopperTile::getAttachedFace(int data) +{ + return data & MASK_ATTACHED; +} + +bool HopperTile::isTurnedOn(int data) +{ + return (data & MASK_TOGGLE) != MASK_TOGGLE; +} + +bool HopperTile::hasAnalogOutputSignal() +{ + return true; +} + +int HopperTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + return AbstractContainerMenu::getRedstoneSignalFromContainer(getHopper(level, x, y, z)); +} + +void HopperTile::registerIcons(IconRegister *iconRegister) +{ + hopperIcon = iconRegister->registerIcon(TEXTURE_OUTSIDE); + hopperTopIcon = iconRegister->registerIcon(L"hopper_top"); + hopperInnerIcon = iconRegister->registerIcon(TEXTURE_INSIDE); +} + +Icon *HopperTile::getTexture(const wstring &name) +{ + if (name.compare(TEXTURE_OUTSIDE) == 0) return Tile::hopper->hopperIcon; + if (name.compare(TEXTURE_INSIDE) == 0) return Tile::hopper->hopperInnerIcon; + return NULL; +} + +wstring HopperTile::getTileItemIconName() +{ + return L"hopper"; +} + +shared_ptr HopperTile::getHopper(LevelSource *level, int x, int y, int z) +{ + return dynamic_pointer_cast( level->getTileEntity(x, y, z) ); +} \ No newline at end of file diff --git a/Minecraft.World/HopperTile.h b/Minecraft.World/HopperTile.h new file mode 100644 index 00000000..12631587 --- /dev/null +++ b/Minecraft.World/HopperTile.h @@ -0,0 +1,56 @@ +#pragma once + +#include "BaseEntityTile.h" + +class HopperTileEntity; + +class HopperTile : public BaseEntityTile +{ + friend class ChunkRebuildData; +private: + static const int MASK_TOGGLE = 0x8; + static const int MASK_ATTACHED = 0x7; + +public : + static const wstring TEXTURE_OUTSIDE; + static const wstring TEXTURE_INSIDE; + +private: + Random random; + +private: + Icon *hopperIcon; + Icon *hopperTopIcon; + Icon *hopperInnerIcon; + +public: + HopperTile(int id); + + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); + virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); + virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); + virtual shared_ptr newTileEntity(Level *level); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual void onPlace(Level *level, int x, int y, int z); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + +private: + virtual void checkPoweredState(Level *level, int x, int y, int z); + +public: + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual int getRenderShape(); + virtual bool isCubeShaped(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); + virtual Icon *getTexture(int face, int data); + static int getAttachedFace(int data); + static bool isTurnedOn(int data); + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); + virtual void registerIcons(IconRegister *iconRegister); + static Icon *getTexture(const wstring &name); + virtual wstring getTileItemIconName(); + static shared_ptr getHopper(LevelSource *level, int x, int y, int z); +}; \ No newline at end of file diff --git a/Minecraft.World/HopperTileEntity.cpp b/Minecraft.World/HopperTileEntity.cpp new file mode 100644 index 00000000..77cb8152 --- /dev/null +++ b/Minecraft.World/HopperTileEntity.cpp @@ -0,0 +1,505 @@ +#include "stdafx.h" +#include "net.minecraft.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.world.phys.h" +#include "net.minecraft.world.h" +#include "HopperTileEntity.h" + +HopperTileEntity::HopperTileEntity() +{ + items = ItemInstanceArray(5); + name = L""; + cooldownTime = -1; +} + +HopperTileEntity::~HopperTileEntity() +{ + delete [] items.data; +} + +void HopperTileEntity::load(CompoundTag *base) +{ + TileEntity::load(base); + + ListTag *inventoryList = (ListTag *) base->getList(L"Items"); + delete[] items.data; + items = ItemInstanceArray(getContainerSize()); + if (base->contains(L"CustomName")) name = base->getString(L"CustomName"); + cooldownTime = base->getInt(L"TransferCooldown"); + for (int i = 0; i < inventoryList->size(); i++) + { + CompoundTag *tag = inventoryList->get(i); + int slot = tag->getByte(L"Slot"); + if (slot >= 0 && slot < items.length) items[slot] = ItemInstance::fromTag(tag); + } +} + +void HopperTileEntity::save(CompoundTag *base) +{ + TileEntity::save(base); + ListTag *listTag = new ListTag(); + + for (int i = 0; i < items.length; i++) + { + if (items[i] != NULL) + { + CompoundTag *tag = new CompoundTag(); + tag->putByte(L"Slot", (byte) i); + items[i]->save(tag); + listTag->add(tag); + } + } + base->put(L"Items", listTag); + base->putInt(L"TransferCooldown", cooldownTime); + if (hasCustomName()) base->putString(L"CustomName", name); +} + +void HopperTileEntity::setChanged() +{ + TileEntity::setChanged(); +} + +unsigned int HopperTileEntity::getContainerSize() +{ + return items.length; +} + +shared_ptr HopperTileEntity::getItem(unsigned int slot) +{ + return items[slot]; +} + +shared_ptr HopperTileEntity::removeItem(unsigned int slot, int count) +{ + if (items[slot] != NULL) + { + if (items[slot]->count <= count) + { + shared_ptr item = items[slot]; + items[slot] = nullptr; + return item; + } + else + { + shared_ptr i = items[slot]->remove(count); + if (items[slot]->count == 0) items[slot] = nullptr; + return i; + } + } + return nullptr; +} + +shared_ptr HopperTileEntity::removeItemNoUpdate(int slot) +{ + if (items[slot] != NULL) + { + shared_ptr item = items[slot]; + items[slot] = nullptr; + return item; + } + return nullptr; +} + +void HopperTileEntity::setItem(unsigned int slot, shared_ptr item) +{ + items[slot] = item; + if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); +} + +wstring HopperTileEntity::getName() +{ + return hasCustomName() ? name : app.GetString(IDS_CONTAINER_HOPPER); +} + +wstring HopperTileEntity::getCustomName() +{ + return hasCustomName() ? name : L""; +} + +bool HopperTileEntity::hasCustomName() +{ + return !name.empty(); +} + +void HopperTileEntity::setCustomName(const wstring &name) +{ + this->name = name; +} + +int HopperTileEntity::getMaxStackSize() +{ + return Container::LARGE_MAX_STACK_SIZE; +} + +bool HopperTileEntity::stillValid(shared_ptr player) +{ + if (level->getTileEntity(x, y, z) != shared_from_this()) return false; + if (player->distanceToSqr(x + 0.5, y + 0.5, z + 0.5) > 8 * 8) return false; + return true; +} + +void HopperTileEntity::startOpen() +{ +} + +void HopperTileEntity::stopOpen() +{ +} + +bool HopperTileEntity::canPlaceItem(int slot, shared_ptr item) +{ + return true; +} + +void HopperTileEntity::tick() +{ + if (level == NULL || level->isClientSide) return; + + cooldownTime--; + + if (!isOnCooldown()) + { + setCooldown(0); + tryMoveItems(); + } +} + +bool HopperTileEntity::tryMoveItems() +{ + if (level == NULL || level->isClientSide) return false; + + if (!isOnCooldown() && HopperTile::isTurnedOn(getData())) + { + bool changed = ejectItems(); + changed = suckInItems(this) || changed; + + if (changed) + { + setCooldown(MOVE_ITEM_SPEED); + setChanged(); + return true; + } + } + + return false; +} + +bool HopperTileEntity::ejectItems() +{ + shared_ptr container = getAttachedContainer(); + if (container == NULL) + { + return false; + } + + for (int slot = 0; slot < getContainerSize(); slot++) + { + if (getItem(slot) == NULL) continue; + + shared_ptr original = getItem(slot)->copy(); + shared_ptr result = addItem(container.get(), removeItem(slot, 1), Facing::OPPOSITE_FACING[HopperTile::getAttachedFace(getData())]); + + if (result == NULL || result->count == 0) + { + container->setChanged(); + return true; + } + else + { + setItem(slot, original); + } + } + + return false; +} + +bool HopperTileEntity::suckInItems(Hopper *hopper) +{ + shared_ptr container = getSourceContainer(hopper); + + if (container != NULL) + { + int face = Facing::DOWN; + + shared_ptr worldly = dynamic_pointer_cast(container); + if ( (worldly != NULL) && (face > -1) ) + { + intArray slots = worldly->getSlotsForFace(face); + + for (int i = 0; i < slots.length; i++) + { + if (tryTakeInItemFromSlot(hopper, container.get(), slots[i], face)) return true; + } + } + else + { + int size = container->getContainerSize(); + for (int i = 0; i < size; i++) + { + if (tryTakeInItemFromSlot(hopper, container.get(), i, face)) return true; + } + } + } + else + { + shared_ptr above = getItemAt(hopper->getLevel(), hopper->getLevelX(), hopper->getLevelY() + 1, hopper->getLevelZ()); + + if (above != NULL) + { + return addItem(hopper, above); + } + } + + return false; +} + +bool HopperTileEntity::tryTakeInItemFromSlot(Hopper *hopper, Container *container, int slot, int face) +{ + shared_ptr item = container->getItem(slot); + + if (item != NULL && canTakeItemFromContainer(container, item, slot, face)) + { + shared_ptr original = item->copy(); + shared_ptr result = addItem(hopper, container->removeItem(slot, 1), -1); + + if (result == NULL || result->count == 0) + { + container->setChanged(); + return true; + } + else + { + container->setItem(slot, original); + } + } + + return false; +} + +bool HopperTileEntity::addItem(Container *container, shared_ptr item) +{ + bool changed = false; + if (item == NULL) return false; + + shared_ptr copy = item->getItem()->copy(); + shared_ptr result = addItem(container, copy, -1); + + if (result == NULL || result->count == 0) + { + changed = true; + + item->remove(); + } + else + { + item->setItem(result); + } + + return changed; +} + +shared_ptr HopperTileEntity::addItem(Container *container, shared_ptr item, int face) +{ + if (dynamic_cast( container ) != NULL && face > -1) + { + WorldlyContainer *worldly = (WorldlyContainer *) container; + intArray slots = worldly->getSlotsForFace(face); + + for (int i = 0; i < slots.length && item != NULL && item->count > 0; i++) + { + item = tryMoveInItem(container, item, slots[i], face); + } + } + else + { + int size = container->getContainerSize(); + for (int i = 0; i < size && item != NULL && item->count > 0; i++) + { + item = tryMoveInItem(container, item, i, face); + } + } + + if (item != NULL && item->count == 0) + { + item = nullptr; + } + + return item; +} + +bool HopperTileEntity::canPlaceItemInContainer(Container *container, shared_ptr item, int slot, int face) +{ + if (!container->canPlaceItem(slot, item)) return false; + if ( dynamic_cast( container ) != NULL && !dynamic_cast( container )->canPlaceItemThroughFace(slot, item, face)) return false; + return true; +} + +bool HopperTileEntity::canTakeItemFromContainer(Container *container, shared_ptr item, int slot, int face) +{ + if (dynamic_cast( container ) != NULL && !dynamic_cast( container )->canTakeItemThroughFace(slot, item, face)) return false; + return true; +} + +shared_ptr HopperTileEntity::tryMoveInItem(Container *container, shared_ptr item, int slot, int face) +{ + shared_ptr current = container->getItem(slot); + + if (canPlaceItemInContainer(container, item, slot, face)) + { + bool success = false; + if (current == NULL) + { + container->setItem(slot, item); + item = nullptr; + success = true; + } + else if (canMergeItems(current, item)) + { + int space = item->getMaxStackSize() - current->count; + int count = min(item->count, space); + + item->count -= count; + current->count += count; + success = count > 0; + } + if (success) + { + HopperTileEntity *hopper = dynamic_cast(container); + if (hopper != NULL) + { + hopper->setCooldown(MOVE_ITEM_SPEED); + container->setChanged(); + } + container->setChanged(); + } + } + return item; +} + +shared_ptr HopperTileEntity::getAttachedContainer() +{ + int face = HopperTile::getAttachedFace(getData()); + return getContainerAt(getLevel(), x + Facing::STEP_X[face], y + Facing::STEP_Y[face], z + Facing::STEP_Z[face]); +} + +shared_ptr HopperTileEntity::getSourceContainer(Hopper *hopper) +{ + return getContainerAt(hopper->getLevel(), hopper->getLevelX(), hopper->getLevelY() + 1, hopper->getLevelZ()); +} + +shared_ptr HopperTileEntity::getItemAt(Level *level, double xt, double yt, double zt) +{ + vector > *entities = level->getEntitiesOfClass(typeid(ItemEntity), AABB::newTemp(xt, yt, zt, xt + 1, yt + 1, zt + 1), EntitySelector::ENTITY_STILL_ALIVE); + + if (entities->size() > 0) + { + shared_ptr out = dynamic_pointer_cast( entities->at(0) ); + delete entities; + return out; + } + else + { + delete entities; + return nullptr; + } +} + +shared_ptr HopperTileEntity::getContainerAt(Level *level, double x, double y, double z) +{ + shared_ptr result = nullptr; + + int xt = Mth::floor(x); + int yt = Mth::floor(y); + int zt = Mth::floor(z); + + shared_ptr entity = level->getTileEntity(xt, yt, zt); + + result = dynamic_pointer_cast(entity); + if (result != NULL) + { + if ( dynamic_pointer_cast(result) != NULL ) + { + int id = level->getTile(xt, yt, zt); + Tile *tile = Tile::tiles[id]; + + if ( dynamic_cast( tile ) != NULL ) + { + result = ((ChestTile *) tile)->getContainer(level, xt, yt, zt); + } + } + } + + if (result == NULL) + { + vector > *entities = level->getEntities(nullptr, AABB::newTemp(x, y, z, x + 1, y + 1, z + 1), EntitySelector::CONTAINER_ENTITY_SELECTOR); + + if ( (entities != NULL) && (entities->size() > 0) ) + { + result = dynamic_pointer_cast( entities->at( level->random->nextInt(entities->size()) ) ); + } + } + + return result; +} + +bool HopperTileEntity::canMergeItems(shared_ptr a, shared_ptr b) +{ + if (a->id != b->id) return false; + if (a->getAuxValue() != b->getAuxValue()) return false; + if (a->count > a->getMaxStackSize()) return false; + if (!ItemInstance::tagMatches(a, b)) return false; + return true; +} + +Level *HopperTileEntity::getLevel() +{ + return TileEntity::getLevel(); +} + +double HopperTileEntity::getLevelX() +{ + return x; +} + +double HopperTileEntity::getLevelY() +{ + return y; +} + +double HopperTileEntity::getLevelZ() +{ + return z; +} + +void HopperTileEntity::setCooldown(int time) +{ + cooldownTime = time; +} + +bool HopperTileEntity::isOnCooldown() +{ + return cooldownTime > 0; +} + +// 4J Added +shared_ptr HopperTileEntity::clone() +{ + shared_ptr result = shared_ptr( new HopperTileEntity() ); + TileEntity::clone(result); + + result->name = name; + result->cooldownTime = cooldownTime; + for (unsigned int i = 0; i < items.length; i++) + { + if (items[i] != NULL) + { + result->items[i] = ItemInstance::clone(items[i]); + } + } + return result; +} \ No newline at end of file diff --git a/Minecraft.World/HopperTileEntity.h b/Minecraft.World/HopperTileEntity.h new file mode 100644 index 00000000..2e84ffdb --- /dev/null +++ b/Minecraft.World/HopperTileEntity.h @@ -0,0 +1,80 @@ +#pragma once + +#include "TileEntity.h" +#include "Hopper.h" + +class HopperTileEntity : public TileEntity, public Hopper +{ +public: + eINSTANCEOF GetType() { return eTYPE_HOPPERTILEENTITY; } + static TileEntity *create() { return new HopperTileEntity(); } + // 4J Added + virtual shared_ptr clone(); + +public: + static const int MOVE_ITEM_SPEED = 8; + +private: + ItemInstanceArray items; + wstring name; + int cooldownTime ; + +public: + HopperTileEntity(); + ~HopperTileEntity(); + + virtual void load(CompoundTag *base); + virtual void save(CompoundTag *base); + virtual void setChanged(); + virtual unsigned int getContainerSize(); + virtual shared_ptr getItem(unsigned int slot); + virtual shared_ptr removeItem(unsigned int slot, int count); + virtual shared_ptr removeItemNoUpdate(int slot); + virtual void setItem(unsigned int slot, shared_ptr item); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual bool hasCustomName(); + virtual void setCustomName(const wstring &name); + virtual int getMaxStackSize(); + virtual bool stillValid(shared_ptr player); + virtual void startOpen(); + virtual void stopOpen(); + virtual bool canPlaceItem(int slot, shared_ptr item); + virtual void tick(); + virtual bool tryMoveItems(); + +private: + virtual bool ejectItems(); + +public: + static bool suckInItems(Hopper *hopper); + +private: + static bool tryTakeInItemFromSlot(Hopper *hopper, Container *container, int slot, int face); + +public: + static bool addItem(Container *container, shared_ptr item); + static shared_ptr addItem(Container *container, shared_ptr item, int face); + +private: + static bool canPlaceItemInContainer(Container *container, shared_ptr item, int slot, int face); + static bool canTakeItemFromContainer(Container *container, shared_ptr item, int slot, int face); + static shared_ptr tryMoveInItem(Container *container, shared_ptr item, int slot, int face); + virtual shared_ptr getAttachedContainer(); + +public: + static shared_ptr getSourceContainer(Hopper *hopper); + static shared_ptr getItemAt(Level *level, double xt, double yt, double zt); + static shared_ptr getContainerAt(Level *level, double x, double y, double z); + +private: + static bool canMergeItems(shared_ptr a, shared_ptr b); + +public: + virtual Level *getLevel(); + virtual double getLevelX(); + virtual double getLevelY(); + virtual double getLevelZ(); + virtual void setCooldown(int time); + virtual bool isOnCooldown(); +}; \ No newline at end of file diff --git a/Minecraft.World/HorseInventoryMenu.cpp b/Minecraft.World/HorseInventoryMenu.cpp new file mode 100644 index 00000000..7dba791f --- /dev/null +++ b/Minecraft.World/HorseInventoryMenu.cpp @@ -0,0 +1,132 @@ +#include "stdafx.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.entity.animal.h" +#include "HorseInventoryMenu.h" + +HorseSaddleSlot::HorseSaddleSlot( shared_ptr horseInventory ) : Slot(horseInventory, EntityHorse::INV_SLOT_SADDLE, 8, 18) +{ +} + +bool HorseSaddleSlot::mayPlace(shared_ptr item) +{ + return Slot::mayPlace(item) && item->id == Item::saddle_Id && !hasItem(); +} + + +HorseArmorSlot::HorseArmorSlot( HorseInventoryMenu *parent, shared_ptr horseInventory ) : Slot(horseInventory, EntityHorse::INV_SLOT_ARMOR, 8, 18 * 2) +{ + m_parent = parent; +} + +bool HorseArmorSlot::mayPlace(shared_ptr item) +{ + return Slot::mayPlace(item) && m_parent->horse->canWearArmor() && EntityHorse::isHorseArmor(item->id); +} + +bool HorseArmorSlot::isActive() +{ + return m_parent->horse->canWearArmor(); +} + + +HorseInventoryMenu::HorseInventoryMenu(shared_ptr playerInventory, shared_ptr horseInventory, shared_ptr horse) +{ + horseContainer = horseInventory; + this->horse = horse; + int containerRows = 3; + horseInventory->startOpen(); + + int yo = (containerRows - 4) * 18; + + // equipment slots + addSlot(new HorseSaddleSlot(horseInventory) ); + addSlot(new HorseArmorSlot(this, horseInventory) ); + + if (horse->isChestedHorse()) + { + for (int y = 0; y < containerRows; y++) + { + for (int x = 0; x < 5; x++) + { + addSlot(new Slot(horseInventory, EntityHorse::INV_BASE_COUNT + x + y * 5, 80 + x * 18, 18 + y * 18)); + } + } + } + + for (int y = 0; y < 3; y++) + { + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(playerInventory, x + y * 9 + 9, 8 + x * 18, 102 + y * 18 + yo)); + } + } + for (int x = 0; x < 9; x++) + { + addSlot(new Slot(playerInventory, x, 8 + x * 18, 160 + yo)); + } +} + +bool HorseInventoryMenu::stillValid(shared_ptr player) +{ + return horseContainer->stillValid(player) && horse->isAlive() && horse->distanceTo(player) < 8; +} + +shared_ptr HorseInventoryMenu::quickMoveStack(shared_ptr player, int slotIndex) +{ + shared_ptr clicked = nullptr; + Slot *slot = slots.at(slotIndex); + if (slot != NULL && slot->hasItem()) + { + shared_ptr stack = slot->getItem(); + clicked = stack->copy(); + + if (slotIndex < horseContainer->getContainerSize()) + { + if (!moveItemStackTo(stack, horseContainer->getContainerSize(), slots.size(), true)) + { + return nullptr; + } + } + else + { + if (getSlot(EntityHorse::INV_SLOT_ARMOR)->mayPlace(stack) && !getSlot(EntityHorse::INV_SLOT_ARMOR)->hasItem()) + { + if (!moveItemStackTo(stack, EntityHorse::INV_SLOT_ARMOR, EntityHorse::INV_SLOT_ARMOR + 1, false)) + { + return nullptr; + } + } + else if (getSlot(EntityHorse::INV_SLOT_SADDLE)->mayPlace(stack)) + { + if (!moveItemStackTo(stack, EntityHorse::INV_SLOT_SADDLE, EntityHorse::INV_SLOT_SADDLE + 1, false)) + { + return nullptr; + } + } + else if (horseContainer->getContainerSize() <= EntityHorse::INV_BASE_COUNT || !moveItemStackTo(stack, EntityHorse::INV_BASE_COUNT, horseContainer->getContainerSize(), false)) + { + return nullptr; + } + } + if (stack->count == 0) + { + slot->set(nullptr); + } + else + { + slot->setChanged(); + } + } + return clicked; +} + +void HorseInventoryMenu::removed(shared_ptr player) +{ + AbstractContainerMenu::removed(player); + horseContainer->stopOpen(); +} + +shared_ptr HorseInventoryMenu::getContainer() +{ + return horseContainer; +} \ No newline at end of file diff --git a/Minecraft.World/HorseInventoryMenu.h b/Minecraft.World/HorseInventoryMenu.h new file mode 100644 index 00000000..613c55f9 --- /dev/null +++ b/Minecraft.World/HorseInventoryMenu.h @@ -0,0 +1,41 @@ +#pragma once + +#include "AbstractContainerMenu.h" +#include "Slot.h" + +class HorseInventoryMenu; + +class HorseSaddleSlot : public Slot +{ +public: + HorseSaddleSlot( shared_ptr horseInventory ); + + bool mayPlace(shared_ptr item); +}; + +class HorseArmorSlot : public Slot +{ +private: + HorseInventoryMenu *m_parent; +public: + HorseArmorSlot( HorseInventoryMenu *parent, shared_ptr horseInventory ); + + bool mayPlace(shared_ptr item); + bool isActive(); +}; + +class HorseInventoryMenu : public AbstractContainerMenu +{ + friend class HorseArmorSlot; +private: + shared_ptr horseContainer; + shared_ptr horse; + +public: + HorseInventoryMenu(shared_ptr playerInventory, shared_ptr horseInventory, shared_ptr horse); + + bool stillValid(shared_ptr player); + shared_ptr quickMoveStack(shared_ptr player, int slotIndex); + void removed(shared_ptr player); + shared_ptr getContainer(); +}; \ No newline at end of file diff --git a/Minecraft.World/HouseFeature.cpp b/Minecraft.World/HouseFeature.cpp index f8c5d173..40b4e770 100644 --- a/Minecraft.World/HouseFeature.cpp +++ b/Minecraft.World/HouseFeature.cpp @@ -7,187 +7,188 @@ bool HouseFeature::place(Level *level, Random *random, int x, int y, int z) { - while (y > 0 && !level->getMaterial(x, y - 1, z)->blocksMotion()) - y--; + while (y > 0 && !level->getMaterial(x, y - 1, z)->blocksMotion()) + y--; int w = random->nextInt(7) + 7; int h = 4 + random->nextInt(3) / 2; int d = random->nextInt(7) + 7; - int x0 = x - w / 2; - int y0 = y; - int z0 = z - d / 2; + int x0 = x - w / 2; + int y0 = y; + int z0 = z - d / 2; - int doorSide = random->nextInt(4); - if (doorSide < 2) d += 2; - else w += 2; + int doorSide = random->nextInt(4); + if (doorSide < 2) d += 2; + else w += 2; - for (int xx = x0; xx < x0 + w; xx++) + for (int xx = x0; xx < x0 + w; xx++) { - for (int zz = z0; zz < z0 + d; zz++) + for (int zz = z0; zz < z0 + d; zz++) { - Material *m = level->getMaterial(xx, y - 1, zz); - if (!m->blocksMotion() || m == Material::ice) return false; - - bool ok = false; - if (doorSide == 0 && xx < x0 + 2) ok = true; - if (doorSide == 1 && xx > x0 + w - 1 - 2) ok = true; - if (doorSide == 2 && zz < z0 + 2) ok = true; - if (doorSide == 3 && zz > z0 + d - 1 - 2) ok = true; - int t = level->getTile(xx, y, zz); - if (ok) + Material *m = level->getMaterial(xx, y - 1, zz); + if (!m->blocksMotion() || m == Material::ice) return false; + + bool ok = false; + if (doorSide == 0 && xx < x0 + 2) ok = true; + if (doorSide == 1 && xx > x0 + w - 1 - 2) ok = true; + if (doorSide == 2 && zz < z0 + 2) ok = true; + if (doorSide == 3 && zz > z0 + d - 1 - 2) ok = true; + int t = level->getTile(xx, y, zz); + if (ok) { - if (t != 0) return false; - } + if (t != 0) return false; + } else { - if (t == Tile::stoneBrick_Id || t == Tile::mossStone_Id) return false; + if (t == Tile::cobblestone_Id || t == Tile::mossyCobblestone_Id) return false; } - } - } + } + } - if (doorSide == 0) + if (doorSide == 0) { - x0++; - w--; - } + x0++; + w--; + } else if (doorSide == 1) { - w--; - } + w--; + } else if (doorSide == 2) { - z0++; - d--; - } + z0++; + d--; + } else if (doorSide == 3) { - d--; - } - - int xx0 = x0; - int xx1 = x0 + w - 1; - int zz0 = z0; - int zz1 = z0 + d - 1; - if (doorSide >= 2) + d--; + } + + int xx0 = x0; + int xx1 = x0 + w - 1; + int zz0 = z0; + int zz1 = z0 + d - 1; + if (doorSide >= 2) { xx0++; xx1--; - } + } else { zz0++; zz1--; - } - for (int xx = x0; xx < x0 + w; xx++) + } + for (int xx = x0; xx < x0 + w; xx++) { - for (int zz = z0; zz < z0 + d; zz++) + for (int zz = z0; zz < z0 + d; zz++) { - int ho = h; + int ho = h; - int d1 = zz - z0; - int d2 = (z0 + d - 1) - zz; - if (doorSide < 2) + int d1 = zz - z0; + int d2 = (z0 + d - 1) - zz; + if (doorSide < 2) { - d1 = xx - x0; - d2 = (x0 + w - 1) - xx; - } + d1 = xx - x0; + d2 = (x0 + w - 1) - xx; + } - if (d2 < d1) d1 = d2; - h += d1; - for (int yy = y0 - 1; yy < y0 + h; yy++) + if (d2 < d1) d1 = d2; + h += d1; + for (int yy = y0 - 1; yy < y0 + h; yy++) { - int material = -1; - if (yy == y0 + h - 1) + int material = -1; + if (yy == y0 + h - 1) { - material = Tile::wood_Id; - } + material = Tile::wood_Id; + } else if (xx >= xx0 && xx <= xx1 && zz >= zz0 && zz <= zz1) { - material = 0; - if (yy == y0 - 1 || yy == y0 + h - 1 || xx == xx0 || zz == zz0 || xx == xx1 || zz == zz1) + material = 0; + if (yy == y0 - 1 || yy == y0 + h - 1 || xx == xx0 || zz == zz0 || xx == xx1 || zz == zz1) { - if (yy <= y0 + random->nextInt(3)) material = Tile::mossStone_Id; - else material = Tile::stoneBrick_Id; - } - } + if (yy <= y0 + random->nextInt(3)) material = Tile::mossyCobblestone_Id; + else material = Tile::cobblestone_Id; + } + } - if (material >= 0) + if (material >= 0) { - level->setTileNoUpdate(xx, yy, zz, material); - } - } - h = ho; - } - } - { - int xx = x0 + random->nextInt(w - 4) + 2; - int zz = z0 + random->nextInt(d - 4) + 2; - if (doorSide == 0) xx = x0; - if (doorSide == 1) xx = x0 + w - 1; - if (doorSide == 2) zz = z0; - if (doorSide == 3) zz = z0 + d - 1; - level->setTileNoUpdate(xx, y0, zz, 0); - level->setTileNoUpdate(xx, y0 + 1, zz, 0); - - int dir = 0; - if (doorSide == 0) dir = 0; - if (doorSide == 2) dir = 1; - if (doorSide == 1) dir = 2; - if (doorSide == 3) dir = 3; - - DoorItem::place(level, xx, y0, zz, dir, Tile::door_wood); - } - - for (int i = 0; i < (w * 2 + d * 2) * 3; i++) + level->setTileAndData(xx, yy, zz, material, 0, Tile::UPDATE_CLIENTS); + } + } + h = ho; + } + } + { + int xx = x0 + random->nextInt(w - 4) + 2; + int zz = z0 + random->nextInt(d - 4) + 2; + if (doorSide == 0) xx = x0; + if (doorSide == 1) xx = x0 + w - 1; + if (doorSide == 2) zz = z0; + if (doorSide == 3) zz = z0 + d - 1; + level->setTileAndData(xx, y0, zz, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(xx, y0 + 1, zz, 0, 0, Tile::UPDATE_CLIENTS); + + int dir = 0; + if (doorSide == 0) dir = 0; + if (doorSide == 2) dir = 1; + if (doorSide == 1) dir = 2; + if (doorSide == 3) dir = 3; + + DoorItem::place(level, xx, y0, zz, dir, Tile::door_wood); + } + + for (int i = 0; i < (w * 2 + d * 2) * 3; i++) { - int xx = x0 + random->nextInt(w - 4) + 2; - int zz = z0 + random->nextInt(d - 4) + 2; - int side = random->nextInt(4); + int xx = x0 + random->nextInt(w - 4) + 2; + int zz = z0 + random->nextInt(d - 4) + 2; + int side = random->nextInt(4); - if (side == 0) xx = xx0; - if (side == 1) xx = xx1; - if (side == 2) zz = zz0; - if (side == 3) zz = zz1; + if (side == 0) xx = xx0; + if (side == 1) xx = xx1; + if (side == 2) zz = zz0; + if (side == 3) zz = zz1; - if (level->isSolidBlockingTile(xx, y0 + 1, zz)) + if (level->isSolidBlockingTile(xx, y0 + 1, zz)) { - int count = 0; - if (level->isSolidBlockingTile(xx - 1, y0 + 1, zz) && level->isSolidBlockingTile(xx + 1, y0 + 1, zz)) count++; - if (level->isSolidBlockingTile(xx, y0 + 1, zz - 1) && level->isSolidBlockingTile(xx, y0 + 1, zz + 1)) count++; - if (count == 1) { - level->setTileNoUpdate(xx, y0 + 1, zz, Tile::glass_Id); - } - } - } - - int ww = xx1 - xx0; - int dd = zz1 - zz0; - for (int i = 0; i < (ww * 2 + dd * 2); i++) + int count = 0; + if (level->isSolidBlockingTile(xx - 1, y0 + 1, zz) && level->isSolidBlockingTile(xx + 1, y0 + 1, zz)) count++; + if (level->isSolidBlockingTile(xx, y0 + 1, zz - 1) && level->isSolidBlockingTile(xx, y0 + 1, zz + 1)) count++; + if (count == 1) + { + level->setTileAndData(xx, y0 + 1, zz, Tile::glass_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } + + int ww = xx1 - xx0; + int dd = zz1 - zz0; + for (int i = 0; i < (ww * 2 + dd * 2); i++) { - int xx = xx0 + random->nextInt(ww - 1) + 1; - int zz = zz0 + random->nextInt(dd - 1) + 1; - int yy = y0; + int xx = xx0 + random->nextInt(ww - 1) + 1; + int zz = zz0 + random->nextInt(dd - 1) + 1; + int yy = y0; - if (level->getTile(xx, yy + 2, zz) == 0) + if (level->getTile(xx, yy + 2, zz) == 0) { - int count = 0; - if (level->isSolidBlockingTile(xx - 1, yy + 2, zz)) count++; - if (level->isSolidBlockingTile(xx + 1, yy + 2, zz)) count++; - if (level->isSolidBlockingTile(xx, yy + 2, zz - 1)) count++; - if (level->isSolidBlockingTile(xx, yy + 2, zz + 1)) count++; - if (count == 1) + int count = 0; + if (level->isSolidBlockingTile(xx - 1, yy + 2, zz)) count++; + if (level->isSolidBlockingTile(xx + 1, yy + 2, zz)) count++; + if (level->isSolidBlockingTile(xx, yy + 2, zz - 1)) count++; + if (level->isSolidBlockingTile(xx, yy + 2, zz + 1)) count++; + if (count == 1) { - level->setTileNoUpdate(xx, y0 + 2, zz, Tile::torch_Id); - } - } - } + level->setTileAndData(xx, y0 + 2, zz, Tile::torch_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } - shared_ptr(pz) = shared_ptr(new PigZombie(level)); - pz->moveTo(x0 + w / 2.0 + 0.5, y0 + 0.5, z0 + d / 2.0 + 0.5, 0, 0); - level->addEntity(pz); + shared_ptr(pz) = shared_ptr(new PigZombie(level)); + pz->moveTo(x0 + w / 2.0 + 0.5, y0 + 0.5, z0 + d / 2.0 + 0.5, 0, 0); + level->addEntity(pz); - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/HtmlString.cpp b/Minecraft.World/HtmlString.cpp new file mode 100644 index 00000000..ce25740e --- /dev/null +++ b/Minecraft.World/HtmlString.cpp @@ -0,0 +1,57 @@ +#include "stdafx.h" +#include "HtmlString.h" +#include + +HtmlString::HtmlString(wstring text, eMinecraftColour hexColor, bool italics, bool indent) +{ + this->text = escapeXML(text); + this->color = hexColor; + this->italics = italics; + this->indent = indent; +} + +wstring HtmlString::ToString() +{ + std::wstringstream ss; + + if (indent) + { + ss << L"  "; + } + + if (italics) + { + ss << ""; + } + + eMinecraftColour color = this->color == eMinecraftColour_NOT_SET ? eHTMLColor_7 : this->color; + + ss << L"" << text << ""; + + if (italics) + { + ss << ""; + } + + return ss.str(); +} + +wstring HtmlString::Compose(vector *strings) +{ + if (strings == NULL) return L""; + + std::wstringstream ss; + + for(int i = 0; i < strings->size(); i++) + { + ss << strings->at(i).ToString(); + + // Add a break if there's another line + if (i + 1 < strings->size()) + { + ss << L"
"; + } + } + + return ss.str(); +} \ No newline at end of file diff --git a/Minecraft.World/HtmlString.h b/Minecraft.World/HtmlString.h new file mode 100644 index 00000000..16108073 --- /dev/null +++ b/Minecraft.World/HtmlString.h @@ -0,0 +1,16 @@ +#pragma once + +// 4J: Simple string wrapper that includes basic formatting information +class HtmlString +{ +public: + wstring text; // Text content of string + eMinecraftColour color; // Hex color + bool italics; // Show text in italics + bool indent; // Indent text + + HtmlString(wstring text, eMinecraftColour color = eMinecraftColour_NOT_SET, bool italics = false, bool indent = false); + wstring ToString(); + + static wstring Compose(vector *strings); +}; \ No newline at end of file diff --git a/Minecraft.World/HugeMushroomFeature.cpp b/Minecraft.World/HugeMushroomFeature.cpp index f67cf971..cc8696ae 100644 --- a/Minecraft.World/HugeMushroomFeature.cpp +++ b/Minecraft.World/HugeMushroomFeature.cpp @@ -15,97 +15,93 @@ HugeMushroomFeature::HugeMushroomFeature() : Feature(false) bool HugeMushroomFeature::place(Level *level, Random *random, int x, int y, int z) { - int type = random->nextInt(2); - if (forcedType >= 0) type = forcedType; - - int treeHeight = random->nextInt(3) + 4; + int type = random->nextInt(2); + if (forcedType >= 0) type = forcedType; - bool free = true; + int treeHeight = random->nextInt(3) + 4; + + bool free = true; if (y < 1 || y + treeHeight + 1 >= Level::maxBuildHeight) return false; - for (int yy = y; yy <= y + 1 + treeHeight; yy++) + for (int yy = y; yy <= y + 1 + treeHeight; yy++) { - int r = 3; - if (yy <= (y + 3) ) r = 0; - for (int xx = x - r; xx <= x + r && free; xx++) + int r = 3; + if (yy <= (y + 3) ) r = 0; + for (int xx = x - r; xx <= x + r && free; xx++) { - for (int zz = z - r; zz <= z + r && free; zz++) + for (int zz = z - r; zz <= z + r && free; zz++) { - if (yy >= 0 && yy < Level::maxBuildHeight) + if (yy >= 0 && yy < Level::maxBuildHeight) { - int tt = level->getTile(xx, yy, zz); - if (tt != 0 && tt != Tile::leaves_Id) + int tt = level->getTile(xx, yy, zz); + if (tt != 0 && tt != Tile::leaves_Id) { free = false; } - } + } else { - free = false; - } - } - } - } + free = false; + } + } + } + } - int belowTile = level->getTile(x, y - 1, z); - if (belowTile != Tile::dirt_Id && belowTile != Tile::grass_Id && belowTile != Tile::mycel_Id) + int belowTile = level->getTile(x, y - 1, z); + if (belowTile != Tile::dirt_Id && belowTile != Tile::grass_Id && belowTile != Tile::mycel_Id) { - return false; - } - - if (!free) return false; - - //if (!Tile::mushroom1->mayPlace(level, x, y, z)) return false; + return false; + } - //placeBlock(level, x, y - 1, z, Tile::dirt_Id, 0); + if (!free) return false; - int low = y + treeHeight; - if (type == 1) { - low = y + treeHeight - 3; - } - for (int yy = low; yy <= y + treeHeight; yy++) + int low = y + treeHeight; + if (type == 1) { + low = y + treeHeight - 3; + } + for (int yy = low; yy <= y + treeHeight; yy++) { - int offs = 1; - if (yy < y + treeHeight) offs += 1; - if (type == 0) offs = 3; - for (int xx = x - offs; xx <= x + offs; xx++) + int offs = 1; + if (yy < y + treeHeight) offs += 1; + if (type == 0) offs = 3; + for (int xx = x - offs; xx <= x + offs; xx++) { - for (int zz = z - offs; zz <= z + offs; zz++) + for (int zz = z - offs; zz <= z + offs; zz++) { - int data = 5; - if (xx == x - offs) data--; - if (xx == x + offs) data++; - if (zz == z - offs) data -= 3; - if (zz == z + offs) data += 3; + int data = 5; + if (xx == x - offs) data--; + if (xx == x + offs) data++; + if (zz == z - offs) data -= 3; + if (zz == z + offs) data += 3; - if (type == 0 || yy < y + treeHeight) + if (type == 0 || yy < y + treeHeight) { - if ((xx == x - offs || xx == x + offs) && (zz == z - offs || zz == z + offs)) continue; - if (xx == x - (offs - 1) && zz == z - offs) data = 1; - if (xx == x - offs && zz == z - (offs - 1)) data = 1; + if ((xx == x - offs || xx == x + offs) && (zz == z - offs || zz == z + offs)) continue; + if (xx == x - (offs - 1) && zz == z - offs) data = 1; + if (xx == x - offs && zz == z - (offs - 1)) data = 1; - if (xx == x + (offs - 1) && zz == z - offs) data = 3; - if (xx == x + offs && zz == z - (offs - 1)) data = 3; + if (xx == x + (offs - 1) && zz == z - offs) data = 3; + if (xx == x + offs && zz == z - (offs - 1)) data = 3; - if (xx == x - (offs - 1) && zz == z + offs) data = 7; - if (xx == x - offs && zz == z + (offs - 1)) data = 7; + if (xx == x - (offs - 1) && zz == z + offs) data = 7; + if (xx == x - offs && zz == z + (offs - 1)) data = 7; - if (xx == x + (offs - 1) && zz == z + offs) data = 9; - if (xx == x + offs && zz == z + (offs - 1)) data = 9; - } + if (xx == x + (offs - 1) && zz == z + offs) data = 9; + if (xx == x + offs && zz == z + (offs - 1)) data = 9; + } - if (data == 5 && yy < y + treeHeight) data = 0; - if (data != 0 || y >= y + treeHeight - 1) + if (data == 5 && yy < y + treeHeight) data = 0; + if (data != 0 || y >= y + treeHeight - 1) { - if (!Tile::solid[level->getTile(xx, yy, zz)]) placeBlock(level, xx, yy, zz, Tile::hugeMushroom1_Id + type, data); - } - } - } - } - for (int hh = 0; hh < treeHeight; hh++) + if (!Tile::solid[level->getTile(xx, yy, zz)]) placeBlock(level, xx, yy, zz, Tile::hugeMushroom_brown_Id + type, data); + } + } + } + } + for (int hh = 0; hh < treeHeight; hh++) { - int t = level->getTile(x, y + hh, z); - if (!Tile::solid[t]) placeBlock(level, x, y + hh, z, Tile::hugeMushroom1_Id + type, 10); - } - return true; + int t = level->getTile(x, y + hh, z); + if (!Tile::solid[t]) placeBlock(level, x, y + hh, z, Tile::hugeMushroom_brown_Id + type, 10); + } + return true; } diff --git a/Minecraft.World/HugeMushroomTile.cpp b/Minecraft.World/HugeMushroomTile.cpp index 9b8344c0..e96cfd1f 100644 --- a/Minecraft.World/HugeMushroomTile.cpp +++ b/Minecraft.World/HugeMushroomTile.cpp @@ -2,13 +2,13 @@ #include "net.minecraft.world.h" #include "HugeMushroomTile.h" -const wstring HugeMushroomTile::TEXTURE_STEM = L"mushroom_skin_stem"; -const wstring HugeMushroomTile::TEXTURE_INSIDE = L"mushroom_inside"; -const wstring HugeMushroomTile::TEXTURE_TYPE[] = {L"mushroom_skin_brown", L"mushroom_skin_red"}; +const wstring HugeMushroomTile::TEXTURE_STEM = L"skin_stem"; +const wstring HugeMushroomTile::TEXTURE_INSIDE = L"inside"; +const wstring HugeMushroomTile::TEXTURE_TYPE[] = {L"skin_brown", L"skin_red"}; HugeMushroomTile::HugeMushroomTile(int id, Material *material, int type) : Tile(id, material) { - this->type = type; + this->type = type; icons = NULL; iconStem = NULL; iconInside = NULL; @@ -16,45 +16,45 @@ HugeMushroomTile::HugeMushroomTile(int id, Material *material, int type) : Tile( Icon *HugeMushroomTile::getTexture(int face, int data) { - // 123 - // 456 10 - // 789 - if (data == 10 && face > 1) return iconStem; - if (data >= 1 && data <= 9 && face == 1) return icons[type]; - if (data >= 1 && data <= 3 && face == 2) return icons[type]; - if (data >= 7 && data <= 9 && face == 3) return icons[type]; + // 123 + // 456 10 + // 789 + if (data == 10 && face > 1) return iconStem; + if (data >= 1 && data <= 9 && face == 1) return icons[type]; + if (data >= 1 && data <= 3 && face == 2) return icons[type]; + if (data >= 7 && data <= 9 && face == 3) return icons[type]; - if ((data == 1 || data == 4 || data == 7) && face == 4) return icons[type]; - if ((data == 3 || data == 6 || data == 9) && face == 5) return icons[type]; + if ((data == 1 || data == 4 || data == 7) && face == 4) return icons[type]; + if ((data == 3 || data == 6 || data == 9) && face == 5) return icons[type]; - // two special cases requested by rhodox (painterly pack) - if (data == 14) + // two special cases requested by rhodox (painterly pack) + if (data == 14) { - return icons[type]; - } - if (data == 15) + return icons[type]; + } + if (data == 15) { - return iconStem; - } + return iconStem; + } - return iconInside; + return iconInside; } int HugeMushroomTile::getResourceCount(Random *random) { - int count = random->nextInt(10) - 7; - if (count < 0) count = 0; - return count; + int count = random->nextInt(10) - 7; + if (count < 0) count = 0; + return count; } int HugeMushroomTile::getResource(int data, Random *random, int playerBonusLevel) { - return Tile::mushroom1_Id + type; + return Tile::mushroom_brown_Id + type; } int HugeMushroomTile::cloneTileId(Level *level, int x, int y, int z) { - return Tile::mushroom1_Id + type; + return Tile::mushroom_brown_Id + type; } void HugeMushroomTile::registerIcons(IconRegister *iconRegister) @@ -63,9 +63,9 @@ void HugeMushroomTile::registerIcons(IconRegister *iconRegister) for (int i = 0; i < HUGE_MUSHROOM_TEXTURE_COUNT; i++) { - icons[i] = iconRegister->registerIcon(TEXTURE_TYPE[i]); + icons[i] = iconRegister->registerIcon(getIconName() + L"_" + TEXTURE_TYPE[i]); } - iconInside = iconRegister->registerIcon(TEXTURE_INSIDE); - iconStem = iconRegister->registerIcon(TEXTURE_STEM); + iconInside = iconRegister->registerIcon(getIconName() + L"_" + TEXTURE_INSIDE); + iconStem = iconRegister->registerIcon(getIconName() + L"_" + TEXTURE_STEM); } \ No newline at end of file diff --git a/Minecraft.World/HugeMushroomTile.h b/Minecraft.World/HugeMushroomTile.h index 2aa22fbb..0b45cf63 100644 --- a/Minecraft.World/HugeMushroomTile.h +++ b/Minecraft.World/HugeMushroomTile.h @@ -6,6 +6,9 @@ class HugeMushroomTile : public Tile { friend class ChunkRebuildData; public: + static const int MUSHROOM_TYPE_BROWN = 0; + static const int MUSHROOM_TYPE_RED = 1; + static const wstring TEXTURE_STEM; static const wstring TEXTURE_INSIDE; @@ -18,9 +21,9 @@ private: Icon *iconInside; public: HugeMushroomTile(int id, Material *material, int type); - Icon *getTexture(int face, int data); - int getResourceCount(Random *random); - int getResource(int data, Random *random, int playerBonusLevel); + Icon *getTexture(int face, int data); + int getResourceCount(Random *random); + int getResource(int data, Random *random, int playerBonusLevel); int cloneTileId(Level *level, int x, int y, int z); void registerIcons(IconRegister *iconRegister); }; diff --git a/Minecraft.World/HurtByTargetGoal.cpp b/Minecraft.World/HurtByTargetGoal.cpp index a146c47d..32bcd3c7 100644 --- a/Minecraft.World/HurtByTargetGoal.cpp +++ b/Minecraft.World/HurtByTargetGoal.cpp @@ -4,42 +4,38 @@ #include "net.minecraft.world.level.h" #include "HurtByTargetGoal.h" -HurtByTargetGoal::HurtByTargetGoal(Mob *mob, bool alertSameType) : TargetGoal(mob, 16, false) +HurtByTargetGoal::HurtByTargetGoal(PathfinderMob *mob, bool alertSameType) : TargetGoal(mob, false) { this->alertSameType = alertSameType; setRequiredControlFlags(TargetGoal::TargetFlag); + timestamp = 0; } bool HurtByTargetGoal::canUse() { - return canAttack(mob->getLastHurtByMob(), false); + int ts = mob->getLastHurtByMobTimestamp(); + return ts != timestamp && canAttack(mob->getLastHurtByMob(), false); } void HurtByTargetGoal::start() { mob->setTarget(mob->getLastHurtByMob()); - oldHurtByMob = mob->getLastHurtByMob(); + timestamp = mob->getLastHurtByMobTimestamp(); if (alertSameType) { + double within = getFollowDistance(); vector > *nearby = mob->level->getEntitiesOfClass(typeid(*mob), AABB::newTemp(mob->x, mob->y, mob->z, mob->x + 1, mob->y + 1, mob->z + 1)->grow(within, 4, within)); for(AUTO_VAR(it, nearby->begin()); it != nearby->end(); ++it) { - shared_ptr other = dynamic_pointer_cast(*it); + shared_ptr other = dynamic_pointer_cast(*it); if (this->mob->shared_from_this() == other) continue; if (other->getTarget() != NULL) continue; + if (other->isAlliedTo(mob->getLastHurtByMob())) continue; // don't target allies other->setTarget(mob->getLastHurtByMob()); } delete nearby; } TargetGoal::start(); -} - -void HurtByTargetGoal::tick() -{ - if (mob->getLastHurtByMob() != NULL && mob->getLastHurtByMob() != oldHurtByMob) - { - this->start(); - } -} +} \ No newline at end of file diff --git a/Minecraft.World/HurtByTargetGoal.h b/Minecraft.World/HurtByTargetGoal.h index 4c6ee5fe..4f7235e9 100644 --- a/Minecraft.World/HurtByTargetGoal.h +++ b/Minecraft.World/HurtByTargetGoal.h @@ -6,12 +6,11 @@ class HurtByTargetGoal : public TargetGoal { private: bool alertSameType; - shared_ptr oldHurtByMob; + int timestamp; public: - HurtByTargetGoal(Mob *mob, bool alertSameType); + HurtByTargetGoal(PathfinderMob *mob, bool alertSameType); bool canUse(); void start(); - void tick(); }; diff --git a/Minecraft.World/IceTile.cpp b/Minecraft.World/IceTile.cpp index 6ca9cc80..938c098f 100644 --- a/Minecraft.World/IceTile.cpp +++ b/Minecraft.World/IceTile.cpp @@ -27,7 +27,7 @@ void IceTile::playerDestroy(Level *level, shared_ptr player, int x, int player->awardStat(GenericStats::blocksMined(id), GenericStats::param_blocksMined(id,data,1) ); player->causeFoodExhaustion(FoodConstants::EXHAUSTION_MINE); - if (isSilkTouchable() && EnchantmentHelper::hasSilkTouch(player->inventory)) + if (isSilkTouchable() && EnchantmentHelper::hasSilkTouch(player)) { shared_ptr item = getSilkTouchItemInstance(data); if (item != NULL) @@ -39,16 +39,16 @@ void IceTile::playerDestroy(Level *level, shared_ptr player, int x, int { if (level->dimension->ultraWarm) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); return; } - int playerBonusLevel = EnchantmentHelper::getDiggingLootBonus(player->inventory); + int playerBonusLevel = EnchantmentHelper::getDiggingLootBonus(player); spawnResources(level, x, y, z, data, playerBonusLevel); Material *below = level->getMaterial(x, y - 1, z); if (below->blocksMotion() || below->isLiquid()) { - level->setTile(x, y, z, Tile::water_Id); + level->setTileAndUpdate(x, y, z, Tile::water_Id); } } } @@ -64,11 +64,11 @@ void IceTile::tick(Level *level, int x, int y, int z, Random *random) { if (level->dimension->ultraWarm) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); return; } this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, Tile::calmWater_Id); + level->setTileAndUpdate(x, y, z, Tile::calmWater_Id); } } diff --git a/Minecraft.World/IndirectEntityDamageSource.cpp b/Minecraft.World/IndirectEntityDamageSource.cpp index 01c54ed6..c2a67af5 100644 --- a/Minecraft.World/IndirectEntityDamageSource.cpp +++ b/Minecraft.World/IndirectEntityDamageSource.cpp @@ -5,7 +5,7 @@ #include "net.minecraft.network.packet.h" //IndirectEntityDamageSource::IndirectEntityDamageSource(const wstring &msgId, shared_ptr entity, shared_ptr owner) : EntityDamageSource(msgId, entity) -IndirectEntityDamageSource::IndirectEntityDamageSource(ChatPacket::EChatPacketMessage msgId, shared_ptr entity, shared_ptr owner) : EntityDamageSource(msgId, entity) +IndirectEntityDamageSource::IndirectEntityDamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId, shared_ptr entity, shared_ptr owner) : EntityDamageSource(msgId, msgWithItemId, entity) { this->owner = owner; } @@ -27,8 +27,9 @@ shared_ptr IndirectEntityDamageSource::getEntity() // //return I18n.get("death." + msgId, player.name, owner.getAName()); //} -shared_ptr IndirectEntityDamageSource::getDeathMessagePacket(shared_ptr player) +shared_ptr IndirectEntityDamageSource::getDeathMessagePacket(shared_ptr player) { + shared_ptr held = entity->instanceof(eTYPE_LIVINGENTITY) ? dynamic_pointer_cast(entity)->getCarriedItem() : nullptr; wstring additional = L""; int type; if(owner != NULL) @@ -44,5 +45,18 @@ shared_ptr IndirectEntityDamageSource::getDeathMessagePacket(shared_ { type = entity->GetType(); } - return shared_ptr( new ChatPacket(player->name, m_msgId, type, additional ) ); + if(held != NULL && held->hasCustomHoverName() ) + { + return shared_ptr( new ChatPacket(player->getNetworkName(), m_msgWithItemId, type, additional, held->getHoverName() ) ); + } + else + { + return shared_ptr( new ChatPacket(player->getNetworkName(), m_msgId, type, additional ) ); + } +} + +// 4J: Copy function +DamageSource *IndirectEntityDamageSource::copy() +{ + return new IndirectEntityDamageSource(*this); } \ No newline at end of file diff --git a/Minecraft.World/IndirectEntityDamageSource.h b/Minecraft.World/IndirectEntityDamageSource.h index b7aec18c..5ec397c3 100644 --- a/Minecraft.World/IndirectEntityDamageSource.h +++ b/Minecraft.World/IndirectEntityDamageSource.h @@ -13,7 +13,7 @@ private: public: //IndirectEntityDamageSource(const wstring &msgId, shared_ptr entity, shared_ptr owner); - IndirectEntityDamageSource(ChatPacket::EChatPacketMessage msgId, shared_ptr entity, shared_ptr owner); + IndirectEntityDamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::EChatPacketMessage msgWithItemId, shared_ptr entity, shared_ptr owner); virtual ~IndirectEntityDamageSource() { } virtual shared_ptr getDirectEntity(); // 4J Stu - Brought forward from 1.2.3 to fix #46422 @@ -21,5 +21,7 @@ public: // 4J Stu - Made return a packet //virtual wstring getLocalizedDeathMessage(shared_ptr player); - virtual shared_ptr getDeathMessagePacket(shared_ptr player); + virtual shared_ptr getDeathMessagePacket(shared_ptr player); + + virtual DamageSource *copy(); }; \ No newline at end of file diff --git a/Minecraft.World/InputStream.cpp b/Minecraft.World/InputStream.cpp index dbec82cc..e325db8a 100644 --- a/Minecraft.World/InputStream.cpp +++ b/Minecraft.World/InputStream.cpp @@ -5,5 +5,7 @@ InputStream *InputStream::getResourceAsStream(const wstring &fileName) { - return new FileInputStream( File( fileName ) ); + File file( fileName ); + + return file.exists() ? new FileInputStream( file ) : NULL; } \ No newline at end of file diff --git a/Minecraft.World/IntArrayTag.h b/Minecraft.World/IntArrayTag.h index 58339bf6..48f4ce74 100644 --- a/Minecraft.World/IntArrayTag.h +++ b/Minecraft.World/IntArrayTag.h @@ -10,6 +10,7 @@ public: IntArrayTag(const wstring &name) : Tag(name) { + data = intArray(); } IntArrayTag(const wstring &name, intArray data) : Tag(name) @@ -17,6 +18,11 @@ public: this->data = data; } + ~IntArrayTag() + { + delete [] data.data; + } + void write(DataOutput *dos) { dos->writeInt(data.length); @@ -26,7 +32,7 @@ public: } } - void load(DataInput *dis) + void load(DataInput *dis, int tagDepth) { int length = dis->readInt(); @@ -52,7 +58,7 @@ public: if (Tag::equals(obj)) { IntArrayTag *o = (IntArrayTag *) obj; - return ((data.data == NULL && o->data.data == NULL) || (data.data != NULL && data.length == o->data.length && memcmp(data.data, o->data.data, data.length) == 0) ); + return ((data.data == NULL && o->data.data == NULL) || (data.data != NULL && data.length == o->data.length && memcmp(data.data, o->data.data, data.length * sizeof(int)) == 0) ); } return false; } diff --git a/Minecraft.World/IntTag.h b/Minecraft.World/IntTag.h index f4d30818..cce87da3 100644 --- a/Minecraft.World/IntTag.h +++ b/Minecraft.World/IntTag.h @@ -9,7 +9,7 @@ public: IntTag(const wstring &name, int data) : Tag(name) {this->data = data; } void write(DataOutput *dos) { dos->writeInt(data); } - void load(DataInput *dis) { data = dis->readInt(); } + void load(DataInput *dis, int tagDepth) { data = dis->readInt(); } byte getId() { return TAG_Int; } wstring toString() diff --git a/Minecraft.World/Inventory.cpp b/Minecraft.World/Inventory.cpp index 8ef3f085..f6a136c9 100644 --- a/Minecraft.World/Inventory.cpp +++ b/Minecraft.World/Inventory.cpp @@ -154,35 +154,63 @@ void Inventory::swapPaint(int wheel) selected -= 9; } -void Inventory::clearInventory() +int Inventory::clearInventory(int id, int data) { - for (unsigned int i = 0; i < items.length; i++) + int count = 0; + for (int i = 0; i < items.length; i++) { + shared_ptr item = items[i]; + if (item == NULL) continue; + if (id > -1 && item->id != id) continue; + if (data > -1 && item->getAuxValue() != data) continue; + + count += item->count; items[i] = nullptr; } - for (unsigned int i = 0; i < armor.length; i++) + for (int i = 0; i < armor.length; i++) { + shared_ptr item = armor[i]; + if (item == NULL) continue; + if (id > -1 && item->id != id) continue; + if (data > -1 && item->getAuxValue() != data) continue; + + count += item->count; armor[i] = nullptr; } + + if (carried != NULL) + { + if (id > -1 && carried->id != id) return count; + if (data > -1 && carried->getAuxValue() != data) return count; + + count += carried->count; + setCarried(nullptr); + } + + return count; } void Inventory::replaceSlot(Item *item, int data) { if (item != NULL) { + // It's too easy to accidentally pick block and lose enchanted items. + if (heldItem != NULL && heldItem->isEnchantable() && getSlot(heldItem->id, heldItem->getDamageValue()) == selected) + { + return; + } + int oldSlot = getSlot(item->id, data); if (oldSlot >= 0) { + int oldSlotCount = items[oldSlot]->count; items[oldSlot] = items[selected]; + items[selected] = shared_ptr( new ItemInstance(Item::items[item->id], oldSlotCount, data) ); } - - // It's too easy to accidentally pick block and lose enchanted - // items. - if (heldItem != NULL && heldItem->isEnchantable() && getSlot(heldItem->id, heldItem->getDamageValue()) == selected) + else { - return; + items[selected] = shared_ptr(new ItemInstance(Item::items[item->id], 1, data)); } - items[selected] = shared_ptr(new ItemInstance(Item::items[item->id], 1, data)); } } @@ -324,8 +352,8 @@ void Inventory::swapSlots(int from, int to) bool Inventory::add(shared_ptr item) { - // 4J Stu - Fix for duplication glitch - if(item->count <= 0) return true; + if (item == NULL) return false; + if (item->count == 0) return false; if (!item->isDamaged()) { @@ -364,7 +392,7 @@ bool Inventory::add(shared_ptr item) GenericStats::param_itemsCollected(item->id, item->getAuxValue(), item->GetCount())); items[slot] = ItemInstance::clone(item); - items[slot]->popTime = Inventory::POP_TIME_DURATION; + items[slot]->popTime = POP_TIME_DURATION; item->count = 0; return true; } @@ -549,21 +577,24 @@ shared_ptr Inventory::getItem(unsigned int slot) */ } -int Inventory::getName() +wstring Inventory::getName() { - return IDS_INVENTORY; + return app.GetString(IDS_INVENTORY); } -int Inventory::getMaxStackSize() +wstring Inventory::getCustomName() { - return MAX_INVENTORY_STACK_SIZE; + return L""; } -int Inventory::getAttackDamage(shared_ptr entity) +bool Inventory::hasCustomName() { - shared_ptr item = getItem(selected); - if (item != NULL) return item->getAttackDamage(entity); - return 1; + return false; +} + +int Inventory::getMaxStackSize() +{ + return MAX_INVENTORY_STACK_SIZE; } bool Inventory::canDestroy(Tile *tile) @@ -595,7 +626,7 @@ int Inventory::getArmorValue() return val; } -void Inventory::hurtArmor(int dmg) +void Inventory::hurtArmor(float dmg) { dmg = dmg / 4; if (dmg < 1) @@ -606,7 +637,7 @@ void Inventory::hurtArmor(int dmg) { if (armor[i] != NULL && dynamic_cast( armor[i]->getItem() ) != NULL ) { - armor[i]->hurt(dmg, dynamic_pointer_cast( player->shared_from_this() ) ); + armor[i]->hurtAndBreak( (int) dmg, dynamic_pointer_cast( player->shared_from_this() ) ); if (armor[i]->count == 0) { armor[i] = nullptr; @@ -699,11 +730,11 @@ bool Inventory::contains(shared_ptr itemInstance) { for (unsigned int i = 0; i < armor.length; i++) { - if (armor[i] != NULL && armor[i]->equals(itemInstance)) return true; + if (armor[i] != NULL && armor[i]->sameItem(itemInstance)) return true; } for (unsigned int i = 0; i < items.length; i++) { - if (items[i] != NULL && items[i]->equals(itemInstance)) return true; + if (items[i] != NULL && items[i]->sameItem(itemInstance)) return true; } return false; } @@ -718,6 +749,11 @@ void Inventory::stopOpen() // TODO Auto-generated method stub } +bool Inventory::canPlaceItem(int slot, shared_ptr item) +{ + return true; +} + void Inventory::replaceWith(shared_ptr other) { for (int i = 0; i < items.length; i++) @@ -728,6 +764,8 @@ void Inventory::replaceWith(shared_ptr other) { armor[i] = ItemInstance::clone(other->armor[i]); } + + selected = other->selected; } int Inventory::countMatches(shared_ptr itemInstance) diff --git a/Minecraft.World/Inventory.h b/Minecraft.World/Inventory.h index 9d1aa7e0..5c49e904 100644 --- a/Minecraft.World/Inventory.h +++ b/Minecraft.World/Inventory.h @@ -37,7 +37,6 @@ public: shared_ptr getSelected(); // 4J-PB - Added for the in-game tooltips bool IsHeldItem(); - static int getSelectionSize(); private: @@ -45,16 +44,12 @@ private: int getSlot(int tileId, int data); int getSlotWithRemainingSpace(shared_ptr item); - + public: int getFreeSlot(); - void grabTexture(int id, int data, bool checkData, bool mayReplace); - void swapPaint(int wheel); - - void clearInventory(); - + int clearInventory(int id, int data); void replaceSlot(Item *item, int data); private: @@ -62,56 +57,37 @@ private: public: void tick(); - bool removeResource(int type); // 4J-PB added to get the right resource from the inventory for removal bool removeResource(int type,int iAuxVal); void removeResources(shared_ptr item); // 4J Added for trading - + // 4J-Stu added to the get the item that would be affected by the removeResource functions shared_ptr getResourceItem(int type); shared_ptr getResourceItem(int type,int iAuxVal); bool hasResource(int type); - void swapSlots(int from, int to); - bool add(shared_ptr item); - shared_ptr removeItem(unsigned int slot, int count); virtual shared_ptr removeItemNoUpdate(int slot); - void setItem(unsigned int slot, shared_ptr item); - float getDestroySpeed(Tile *tile); - ListTag *save(ListTag *listTag); - void load(ListTag *inventoryList); - unsigned int getContainerSize(); - shared_ptr getItem(unsigned int slot); - - int getName(); - + wstring getName(); + wstring getCustomName(); + bool hasCustomName(); int getMaxStackSize(); - - int getAttackDamage(shared_ptr entity); - bool canDestroy(Tile *tile); - shared_ptr getArmor(int layer); - int getArmorValue(); - - void hurtArmor(int dmg); - + void hurtArmor(float dmg); void dropAll(); - void setChanged(); - bool isSame(shared_ptr copy); private: @@ -119,17 +95,13 @@ private: public: shared_ptr copy(); - void setCarried(shared_ptr carried); - shared_ptr getCarried(); - bool stillValid(shared_ptr player); - bool contains(shared_ptr itemInstance); - virtual void startOpen(); virtual void stopOpen(); + bool canPlaceItem(int slot, shared_ptr item); void replaceWith(shared_ptr other); int countMatches(shared_ptr itemInstance); // 4J Added diff --git a/Minecraft.World/InventoryMenu.cpp b/Minecraft.World/InventoryMenu.cpp index 979243c1..ae5d9269 100644 --- a/Minecraft.World/InventoryMenu.cpp +++ b/Minecraft.World/InventoryMenu.cpp @@ -94,12 +94,12 @@ bool InventoryMenu::stillValid(shared_ptr player) shared_ptr InventoryMenu::quickMoveStack(shared_ptr player, int slotIndex) { shared_ptr clicked = nullptr; - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); - Slot *HelmetSlot = slots->at(ARMOR_SLOT_START); - Slot *ChestplateSlot = slots->at(ARMOR_SLOT_START+1); - Slot *LeggingsSlot = slots->at(ARMOR_SLOT_START+2); - Slot *BootsSlot = slots->at(ARMOR_SLOT_START+3); + Slot *HelmetSlot = slots.at(ARMOR_SLOT_START); + Slot *ChestplateSlot = slots.at(ARMOR_SLOT_START+1); + Slot *LeggingsSlot = slots.at(ARMOR_SLOT_START+2); + Slot *BootsSlot = slots.at(ARMOR_SLOT_START+3); if (slot != NULL && slot->hasItem()) @@ -225,16 +225,21 @@ bool InventoryMenu::mayCombine(Slot *slot, shared_ptr item) return slot->mayCombine(item); } +bool InventoryMenu::canTakeItemForPickAll(shared_ptr carried, Slot *target) +{ + return target->container != resultSlots && AbstractContainerMenu::canTakeItemForPickAll(carried, target); +} + // 4J-JEV: Added for achievement 'Iron Man'. -shared_ptr InventoryMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player) +shared_ptr InventoryMenu::clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player, bool looped) // 4J Added looped param { - shared_ptr out = AbstractContainerMenu::clicked(slotIndex, buttonNum, clickType, player); + shared_ptr out = AbstractContainerMenu::clicked(slotIndex, buttonNum, clickType, player, looped); #ifdef _EXTENDED_ACHIEVEMENTS static int ironItems[4] = {Item::helmet_iron_Id,Item::chestplate_iron_Id,Item::leggings_iron_Id,Item::boots_iron_Id}; for (int i = ARMOR_SLOT_START; i < ARMOR_SLOT_END; i++) { - Slot *slot = slots->at(i); + Slot *slot = slots.at(i); if ( (slot==NULL) || (!slot->hasItem()) || (slot->getItem()->getItem()->id != ironItems[i-ARMOR_SLOT_START]) ) { return out; diff --git a/Minecraft.World/InventoryMenu.h b/Minecraft.World/InventoryMenu.h index b37a4be9..1795eaef 100644 --- a/Minecraft.World/InventoryMenu.h +++ b/Minecraft.World/InventoryMenu.h @@ -38,7 +38,8 @@ public: virtual bool stillValid(shared_ptr player); virtual shared_ptr quickMoveStack(shared_ptr player, int slotIndex); virtual bool mayCombine(Slot *slot, shared_ptr item); + virtual bool canTakeItemForPickAll(shared_ptr carried, Slot *target); // 4J ADDED, - virtual shared_ptr clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player); + virtual shared_ptr clicked(int slotIndex, int buttonNum, int clickType, shared_ptr player, bool looped = false); }; diff --git a/Minecraft.World/Item.cpp b/Minecraft.World/Item.cpp index 5d723ec5..35768ac1 100644 --- a/Minecraft.World/Item.cpp +++ b/Minecraft.World/Item.cpp @@ -14,9 +14,12 @@ #include "MapItem.h" #include "Item.h" #include "HangingEntityItem.h" +#include "HtmlString.h" typedef Item::Tier _Tier; +//const UUID Item::BASE_ATTACK_DAMAGE_UUID = UUID::fromString(L"CB3F55D3-645C-4F38-A497-9C13A33DB5CF"); + wstring Item::ICON_DESCRIPTION_PREFIX = L"item."; const _Tier *_Tier::WOOD = new _Tier(0, 59, 2, 0, 15); // @@ -68,7 +71,7 @@ Item *Item::hatchet_gold = NULL; Item *Item::string = NULL; Item *Item::feather = NULL; -Item *Item::sulphur = NULL; +Item *Item::gunpowder = NULL; Item *Item::hoe_wood = NULL; Item *Item::hoe_stone = NULL; @@ -80,10 +83,10 @@ Item *Item::seeds_wheat = NULL; Item *Item::wheat = NULL; Item *Item::bread = NULL; -ArmorItem *Item::helmet_cloth = NULL; -ArmorItem *Item::chestplate_cloth = NULL; -ArmorItem *Item::leggings_cloth = NULL; -ArmorItem *Item::boots_cloth = NULL; +ArmorItem *Item::helmet_leather = NULL; +ArmorItem *Item::chestplate_leather = NULL; +ArmorItem *Item::leggings_leather = NULL; +ArmorItem *Item::boots_leather = NULL; ArmorItem *Item::helmet_chain = NULL; ArmorItem *Item::chestplate_chain = NULL; @@ -128,7 +131,7 @@ Item *Item::snowBall = NULL; Item *Item::boat = NULL; Item *Item::leather = NULL; -Item *Item::milk = NULL; +Item *Item::bucket_milk = NULL; Item *Item::brick = NULL; Item *Item::clay = NULL; Item *Item::reeds = NULL; @@ -152,7 +155,7 @@ Item *Item::cake = NULL; Item *Item::bed = NULL; -Item *Item::diode = NULL; +Item *Item::repeater = NULL; Item *Item::cookie = NULL; MapItem *Item::map = NULL; @@ -188,7 +191,7 @@ Item *Item::enderPearl = NULL; Item *Item::blazeRod = NULL; Item *Item::ghastTear = NULL; Item *Item::goldNugget = NULL; -Item *Item::netherStalkSeeds = NULL; +Item *Item::netherwart_seeds = NULL; PotionItem *Item::potion = NULL; Item *Item::glassBottle = NULL; Item *Item::spiderEye = NULL; @@ -200,14 +203,13 @@ Item *Item::cauldron = NULL; Item *Item::eyeOfEnder = NULL; Item *Item::speckledMelon = NULL; -Item *Item::monsterPlacer = NULL; +Item *Item::spawnEgg = NULL; Item *Item::expBottle = NULL; // TU9 Item *Item::fireball = NULL; Item *Item::frame = NULL; -Item *Item::netherbrick = NULL; Item *Item::skull = NULL; @@ -225,247 +227,273 @@ Item *Item::potato = NULL; Item *Item::potatoBaked = NULL; Item *Item::potatoPoisonous = NULL; +EmptyMapItem *Item::emptyMap = NULL; + Item *Item::carrotGolden = NULL; Item *Item::carrotOnAStick = NULL; +Item *Item::netherStar = NULL; Item *Item::pumpkinPie = NULL; +Item *Item::fireworks = NULL; +Item *Item::fireworksCharge = NULL; EnchantedBookItem *Item::enchantedBook = NULL; + +Item *Item::comparator = NULL; +Item *Item::netherbrick = NULL; Item *Item::netherQuartz = NULL; +Item *Item::minecart_tnt = NULL; +Item *Item::minecart_hopper = NULL; + +Item *Item::horseArmorMetal = NULL; +Item *Item::horseArmorGold = NULL; +Item *Item::horseArmorDiamond = NULL; +Item *Item::lead = NULL; +Item *Item::nameTag = NULL; void Item::staticCtor() { - - - Item::sword_wood = ( new WeaponItem(12, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_wood) ->setTextureName(L"swordWood")->setDescriptionId(IDS_ITEM_SWORD_WOOD)->setUseDescriptionId(IDS_DESC_SWORD); - Item::sword_stone = ( new WeaponItem(16, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_stone) ->setTextureName(L"swordStone")->setDescriptionId(IDS_ITEM_SWORD_STONE)->setUseDescriptionId(IDS_DESC_SWORD); - Item::sword_iron = ( new WeaponItem(11, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_iron) ->setTextureName(L"swordIron")->setDescriptionId(IDS_ITEM_SWORD_IRON)->setUseDescriptionId(IDS_DESC_SWORD); - Item::sword_diamond = ( new WeaponItem(20, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_diamond) ->setTextureName(L"swordDiamond")->setDescriptionId(IDS_ITEM_SWORD_DIAMOND)->setUseDescriptionId(IDS_DESC_SWORD); - Item::sword_gold = ( new WeaponItem(27, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_gold) ->setTextureName(L"swordGold")->setDescriptionId(IDS_ITEM_SWORD_GOLD)->setUseDescriptionId(IDS_DESC_SWORD); - - Item::shovel_wood = ( new ShovelItem(13, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_wood) ->setTextureName(L"shovelWood")->setDescriptionId(IDS_ITEM_SHOVEL_WOOD)->setUseDescriptionId(IDS_DESC_SHOVEL); - Item::shovel_stone = ( new ShovelItem(17, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_stone) ->setTextureName(L"shovelStone")->setDescriptionId(IDS_ITEM_SHOVEL_STONE)->setUseDescriptionId(IDS_DESC_SHOVEL); - Item::shovel_iron = ( new ShovelItem(0, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_iron) ->setTextureName(L"shovelIron")->setDescriptionId(IDS_ITEM_SHOVEL_IRON)->setUseDescriptionId(IDS_DESC_SHOVEL); - Item::shovel_diamond = ( new ShovelItem(21, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_diamond) ->setTextureName(L"shovelDiamond")->setDescriptionId(IDS_ITEM_SHOVEL_DIAMOND)->setUseDescriptionId(IDS_DESC_SHOVEL); - Item::shovel_gold = ( new ShovelItem(28, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_gold) ->setTextureName(L"shovelGold")->setDescriptionId(IDS_ITEM_SHOVEL_GOLD)->setUseDescriptionId(IDS_DESC_SHOVEL); - - Item::pickAxe_wood = ( new PickaxeItem(14, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_wood) ->setTextureName(L"pickaxeWood")->setDescriptionId(IDS_ITEM_PICKAXE_WOOD)->setUseDescriptionId(IDS_DESC_PICKAXE); - Item::pickAxe_stone = ( new PickaxeItem(18, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_stone) ->setTextureName(L"pickaxeStone")->setDescriptionId(IDS_ITEM_PICKAXE_STONE)->setUseDescriptionId(IDS_DESC_PICKAXE); - Item::pickAxe_iron = ( new PickaxeItem(1, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_iron) ->setTextureName(L"pickaxeIron")->setDescriptionId(IDS_ITEM_PICKAXE_IRON)->setUseDescriptionId(IDS_DESC_PICKAXE); - Item::pickAxe_diamond = ( new PickaxeItem(22, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_diamond) ->setTextureName(L"pickaxeDiamond")->setDescriptionId(IDS_ITEM_PICKAXE_DIAMOND)->setUseDescriptionId(IDS_DESC_PICKAXE); - Item::pickAxe_gold = ( new PickaxeItem(29, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_gold) ->setTextureName(L"pickaxeGold")->setDescriptionId(IDS_ITEM_PICKAXE_GOLD)->setUseDescriptionId(IDS_DESC_PICKAXE); - - Item::hatchet_wood = ( new HatchetItem(15, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_wood) ->setTextureName(L"hatchetWood")->setDescriptionId(IDS_ITEM_HATCHET_WOOD)->setUseDescriptionId(IDS_DESC_HATCHET); - Item::hatchet_stone = ( new HatchetItem(19, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_stone) ->setTextureName(L"hatchetStone")->setDescriptionId(IDS_ITEM_HATCHET_STONE)->setUseDescriptionId(IDS_DESC_HATCHET); - Item::hatchet_iron = ( new HatchetItem(2, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_iron) ->setTextureName(L"hatchetIron")->setDescriptionId(IDS_ITEM_HATCHET_IRON)->setUseDescriptionId(IDS_DESC_HATCHET); - Item::hatchet_diamond = ( new HatchetItem(23, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_diamond) ->setTextureName(L"hatchetDiamond")->setDescriptionId(IDS_ITEM_HATCHET_DIAMOND)->setUseDescriptionId(IDS_DESC_HATCHET); - Item::hatchet_gold = ( new HatchetItem(30, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_gold) ->setTextureName(L"hatchetGold")->setDescriptionId(IDS_ITEM_HATCHET_GOLD)->setUseDescriptionId(IDS_DESC_HATCHET); - - Item::hoe_wood = ( new HoeItem(34, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_wood) ->setTextureName(L"hoeWood")->setDescriptionId(IDS_ITEM_HOE_WOOD)->setUseDescriptionId(IDS_DESC_HOE); - Item::hoe_stone = ( new HoeItem(35, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_stone) ->setTextureName(L"hoeStone")->setDescriptionId(IDS_ITEM_HOE_STONE)->setUseDescriptionId(IDS_DESC_HOE); - Item::hoe_iron = ( new HoeItem(36, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_iron) ->setTextureName(L"hoeIron")->setDescriptionId(IDS_ITEM_HOE_IRON)->setUseDescriptionId(IDS_DESC_HOE); - Item::hoe_diamond = ( new HoeItem(37, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_diamond) ->setTextureName(L"hoeDiamond")->setDescriptionId(IDS_ITEM_HOE_DIAMOND)->setUseDescriptionId(IDS_DESC_HOE); - Item::hoe_gold = ( new HoeItem(38, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_gold) ->setTextureName(L"hoeGold")->setDescriptionId(IDS_ITEM_HOE_GOLD)->setUseDescriptionId(IDS_DESC_HOE); - - Item::door_wood = ( new DoorItem(68, Material::wood) ) ->setBaseItemTypeAndMaterial(eBaseItemType_door, eMaterial_wood)->setTextureName(L"doorWood")->setDescriptionId(IDS_ITEM_DOOR_WOOD)->setUseDescriptionId(IDS_DESC_DOOR_WOOD); - Item::door_iron = ( new DoorItem(74, Material::metal) ) ->setBaseItemTypeAndMaterial(eBaseItemType_door, eMaterial_iron)->setTextureName(L"doorIron")->setDescriptionId(IDS_ITEM_DOOR_IRON)->setUseDescriptionId(IDS_DESC_DOOR_IRON); - - Item::helmet_cloth = (ArmorItem *) ( ( new ArmorItem(42, ArmorItem::ArmorMaterial::CLOTH, 0, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_cloth) ->setTextureName(L"helmetCloth")->setDescriptionId(IDS_ITEM_HELMET_CLOTH)->setUseDescriptionId(IDS_DESC_HELMET_LEATHER) ); - Item::helmet_iron = (ArmorItem *) ( ( new ArmorItem(50, ArmorItem::ArmorMaterial::IRON, 2, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_iron) ->setTextureName(L"helmetIron")->setDescriptionId(IDS_ITEM_HELMET_IRON)->setUseDescriptionId(IDS_DESC_HELMET_IRON) ); - Item::helmet_diamond = (ArmorItem *) ( ( new ArmorItem(54, ArmorItem::ArmorMaterial::DIAMOND, 3, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_diamond) ->setTextureName(L"helmetDiamond")->setDescriptionId(IDS_ITEM_HELMET_DIAMOND)->setUseDescriptionId(IDS_DESC_HELMET_DIAMOND) ); - Item::helmet_gold = (ArmorItem *) ( ( new ArmorItem(58, ArmorItem::ArmorMaterial::GOLD, 4, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_gold) ->setTextureName(L"helmetGold")->setDescriptionId(IDS_ITEM_HELMET_GOLD)->setUseDescriptionId(IDS_DESC_HELMET_GOLD) ); + Item::sword_wood = ( new WeaponItem(12, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_wood) ->setIconName(L"swordWood")->setDescriptionId(IDS_ITEM_SWORD_WOOD)->setUseDescriptionId(IDS_DESC_SWORD); + Item::sword_stone = ( new WeaponItem(16, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_stone) ->setIconName(L"swordStone")->setDescriptionId(IDS_ITEM_SWORD_STONE)->setUseDescriptionId(IDS_DESC_SWORD); + Item::sword_iron = ( new WeaponItem(11, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_iron) ->setIconName(L"swordIron")->setDescriptionId(IDS_ITEM_SWORD_IRON)->setUseDescriptionId(IDS_DESC_SWORD); + Item::sword_diamond = ( new WeaponItem(20, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_diamond) ->setIconName(L"swordDiamond")->setDescriptionId(IDS_ITEM_SWORD_DIAMOND)->setUseDescriptionId(IDS_DESC_SWORD); + Item::sword_gold = ( new WeaponItem(27, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_sword, eMaterial_gold) ->setIconName(L"swordGold")->setDescriptionId(IDS_ITEM_SWORD_GOLD)->setUseDescriptionId(IDS_DESC_SWORD); + + Item::shovel_wood = ( new ShovelItem(13, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_wood) ->setIconName(L"shovelWood")->setDescriptionId(IDS_ITEM_SHOVEL_WOOD)->setUseDescriptionId(IDS_DESC_SHOVEL); + Item::shovel_stone = ( new ShovelItem(17, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_stone) ->setIconName(L"shovelStone")->setDescriptionId(IDS_ITEM_SHOVEL_STONE)->setUseDescriptionId(IDS_DESC_SHOVEL); + Item::shovel_iron = ( new ShovelItem(0, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_iron) ->setIconName(L"shovelIron")->setDescriptionId(IDS_ITEM_SHOVEL_IRON)->setUseDescriptionId(IDS_DESC_SHOVEL); + Item::shovel_diamond = ( new ShovelItem(21, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_diamond) ->setIconName(L"shovelDiamond")->setDescriptionId(IDS_ITEM_SHOVEL_DIAMOND)->setUseDescriptionId(IDS_DESC_SHOVEL); + Item::shovel_gold = ( new ShovelItem(28, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_shovel, eMaterial_gold) ->setIconName(L"shovelGold")->setDescriptionId(IDS_ITEM_SHOVEL_GOLD)->setUseDescriptionId(IDS_DESC_SHOVEL); + + Item::pickAxe_wood = ( new PickaxeItem(14, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_wood) ->setIconName(L"pickaxeWood")->setDescriptionId(IDS_ITEM_PICKAXE_WOOD)->setUseDescriptionId(IDS_DESC_PICKAXE); + Item::pickAxe_stone = ( new PickaxeItem(18, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_stone) ->setIconName(L"pickaxeStone")->setDescriptionId(IDS_ITEM_PICKAXE_STONE)->setUseDescriptionId(IDS_DESC_PICKAXE); + Item::pickAxe_iron = ( new PickaxeItem(1, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_iron) ->setIconName(L"pickaxeIron")->setDescriptionId(IDS_ITEM_PICKAXE_IRON)->setUseDescriptionId(IDS_DESC_PICKAXE); + Item::pickAxe_diamond = ( new PickaxeItem(22, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_diamond) ->setIconName(L"pickaxeDiamond")->setDescriptionId(IDS_ITEM_PICKAXE_DIAMOND)->setUseDescriptionId(IDS_DESC_PICKAXE); + Item::pickAxe_gold = ( new PickaxeItem(29, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pickaxe, eMaterial_gold) ->setIconName(L"pickaxeGold")->setDescriptionId(IDS_ITEM_PICKAXE_GOLD)->setUseDescriptionId(IDS_DESC_PICKAXE); + + Item::hatchet_wood = ( new HatchetItem(15, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_wood) ->setIconName(L"hatchetWood")->setDescriptionId(IDS_ITEM_HATCHET_WOOD)->setUseDescriptionId(IDS_DESC_HATCHET); + Item::hatchet_stone = ( new HatchetItem(19, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_stone) ->setIconName(L"hatchetStone")->setDescriptionId(IDS_ITEM_HATCHET_STONE)->setUseDescriptionId(IDS_DESC_HATCHET); + Item::hatchet_iron = ( new HatchetItem(2, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_iron) ->setIconName(L"hatchetIron")->setDescriptionId(IDS_ITEM_HATCHET_IRON)->setUseDescriptionId(IDS_DESC_HATCHET); + Item::hatchet_diamond = ( new HatchetItem(23, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_diamond) ->setIconName(L"hatchetDiamond")->setDescriptionId(IDS_ITEM_HATCHET_DIAMOND)->setUseDescriptionId(IDS_DESC_HATCHET); + Item::hatchet_gold = ( new HatchetItem(30, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hatchet, eMaterial_gold) ->setIconName(L"hatchetGold")->setDescriptionId(IDS_ITEM_HATCHET_GOLD)->setUseDescriptionId(IDS_DESC_HATCHET); + + Item::hoe_wood = ( new HoeItem(34, _Tier::WOOD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_wood) ->setIconName(L"hoeWood")->setDescriptionId(IDS_ITEM_HOE_WOOD)->setUseDescriptionId(IDS_DESC_HOE); + Item::hoe_stone = ( new HoeItem(35, _Tier::STONE) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_stone) ->setIconName(L"hoeStone")->setDescriptionId(IDS_ITEM_HOE_STONE)->setUseDescriptionId(IDS_DESC_HOE); + Item::hoe_iron = ( new HoeItem(36, _Tier::IRON) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_iron) ->setIconName(L"hoeIron")->setDescriptionId(IDS_ITEM_HOE_IRON)->setUseDescriptionId(IDS_DESC_HOE); + Item::hoe_diamond = ( new HoeItem(37, _Tier::DIAMOND) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_diamond) ->setIconName(L"hoeDiamond")->setDescriptionId(IDS_ITEM_HOE_DIAMOND)->setUseDescriptionId(IDS_DESC_HOE); + Item::hoe_gold = ( new HoeItem(38, _Tier::GOLD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_hoe, eMaterial_gold) ->setIconName(L"hoeGold")->setDescriptionId(IDS_ITEM_HOE_GOLD)->setUseDescriptionId(IDS_DESC_HOE); + + Item::door_wood = ( new DoorItem(68, Material::wood) ) ->setBaseItemTypeAndMaterial(eBaseItemType_door, eMaterial_wood)->setIconName(L"doorWood")->setDescriptionId(IDS_ITEM_DOOR_WOOD)->setUseDescriptionId(IDS_DESC_DOOR_WOOD); + Item::door_iron = ( new DoorItem(74, Material::metal) ) ->setBaseItemTypeAndMaterial(eBaseItemType_door, eMaterial_iron)->setIconName(L"doorIron")->setDescriptionId(IDS_ITEM_DOOR_IRON)->setUseDescriptionId(IDS_DESC_DOOR_IRON); + + Item::helmet_leather = (ArmorItem *) ( ( new ArmorItem(42, ArmorItem::ArmorMaterial::CLOTH, 0, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_cloth) ->setIconName(L"helmetCloth")->setDescriptionId(IDS_ITEM_HELMET_CLOTH)->setUseDescriptionId(IDS_DESC_HELMET_LEATHER) ); + Item::helmet_iron = (ArmorItem *) ( ( new ArmorItem(50, ArmorItem::ArmorMaterial::IRON, 2, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_iron) ->setIconName(L"helmetIron")->setDescriptionId(IDS_ITEM_HELMET_IRON)->setUseDescriptionId(IDS_DESC_HELMET_IRON) ); + Item::helmet_diamond = (ArmorItem *) ( ( new ArmorItem(54, ArmorItem::ArmorMaterial::DIAMOND, 3, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_diamond) ->setIconName(L"helmetDiamond")->setDescriptionId(IDS_ITEM_HELMET_DIAMOND)->setUseDescriptionId(IDS_DESC_HELMET_DIAMOND) ); + Item::helmet_gold = (ArmorItem *) ( ( new ArmorItem(58, ArmorItem::ArmorMaterial::GOLD, 4, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_gold) ->setIconName(L"helmetGold")->setDescriptionId(IDS_ITEM_HELMET_GOLD)->setUseDescriptionId(IDS_DESC_HELMET_GOLD) ); - Item::chestplate_cloth = (ArmorItem *) ( ( new ArmorItem(43, ArmorItem::ArmorMaterial::CLOTH, 0, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_cloth) ->setTextureName(L"chestplateCloth")->setDescriptionId(IDS_ITEM_CHESTPLATE_CLOTH)->setUseDescriptionId(IDS_DESC_CHESTPLATE_LEATHER) ); - Item::chestplate_iron = (ArmorItem *) ( ( new ArmorItem(51, ArmorItem::ArmorMaterial::IRON, 2, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_iron) ->setTextureName(L"chestplateIron")->setDescriptionId(IDS_ITEM_CHESTPLATE_IRON)->setUseDescriptionId(IDS_DESC_CHESTPLATE_IRON) ); - Item::chestplate_diamond = (ArmorItem *) ( ( new ArmorItem(55, ArmorItem::ArmorMaterial::DIAMOND, 3, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_diamond) ->setTextureName(L"chestplateDiamond")->setDescriptionId(IDS_ITEM_CHESTPLATE_DIAMOND)->setUseDescriptionId(IDS_DESC_CHESTPLATE_DIAMOND) ); - Item::chestplate_gold = (ArmorItem *) ( ( new ArmorItem(59, ArmorItem::ArmorMaterial::GOLD, 4, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_gold) ->setTextureName(L"chestplateGold")->setDescriptionId(IDS_ITEM_CHESTPLATE_GOLD)->setUseDescriptionId(IDS_DESC_CHESTPLATE_GOLD) ); + Item::chestplate_leather = (ArmorItem *) ( ( new ArmorItem(43, ArmorItem::ArmorMaterial::CLOTH, 0, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_cloth) ->setIconName(L"chestplateCloth")->setDescriptionId(IDS_ITEM_CHESTPLATE_CLOTH)->setUseDescriptionId(IDS_DESC_CHESTPLATE_LEATHER) ); + Item::chestplate_iron = (ArmorItem *) ( ( new ArmorItem(51, ArmorItem::ArmorMaterial::IRON, 2, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_iron) ->setIconName(L"chestplateIron")->setDescriptionId(IDS_ITEM_CHESTPLATE_IRON)->setUseDescriptionId(IDS_DESC_CHESTPLATE_IRON) ); + Item::chestplate_diamond = (ArmorItem *) ( ( new ArmorItem(55, ArmorItem::ArmorMaterial::DIAMOND, 3, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_diamond) ->setIconName(L"chestplateDiamond")->setDescriptionId(IDS_ITEM_CHESTPLATE_DIAMOND)->setUseDescriptionId(IDS_DESC_CHESTPLATE_DIAMOND) ); + Item::chestplate_gold = (ArmorItem *) ( ( new ArmorItem(59, ArmorItem::ArmorMaterial::GOLD, 4, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_gold) ->setIconName(L"chestplateGold")->setDescriptionId(IDS_ITEM_CHESTPLATE_GOLD)->setUseDescriptionId(IDS_DESC_CHESTPLATE_GOLD) ); - Item::leggings_cloth = (ArmorItem *) ( ( new ArmorItem(44, ArmorItem::ArmorMaterial::CLOTH, 0, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_cloth) ->setTextureName(L"leggingsCloth")->setDescriptionId(IDS_ITEM_LEGGINGS_CLOTH)->setUseDescriptionId(IDS_DESC_LEGGINGS_LEATHER) ); - Item::leggings_iron = (ArmorItem *) ( ( new ArmorItem(52, ArmorItem::ArmorMaterial::IRON, 2, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_iron) ->setTextureName(L"leggingsIron")->setDescriptionId(IDS_ITEM_LEGGINGS_IRON)->setUseDescriptionId(IDS_DESC_LEGGINGS_IRON) ); - Item::leggings_diamond = (ArmorItem *) ( ( new ArmorItem(56, ArmorItem::ArmorMaterial::DIAMOND, 3, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_diamond) ->setTextureName(L"leggingsDiamond")->setDescriptionId(IDS_ITEM_LEGGINGS_DIAMOND)->setUseDescriptionId(IDS_DESC_LEGGINGS_DIAMOND) ); - Item::leggings_gold = (ArmorItem *) ( ( new ArmorItem(60, ArmorItem::ArmorMaterial::GOLD, 4, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_gold) ->setTextureName(L"leggingsGold")->setDescriptionId(IDS_ITEM_LEGGINGS_GOLD)->setUseDescriptionId(IDS_DESC_LEGGINGS_GOLD) ); + Item::leggings_leather = (ArmorItem *) ( ( new ArmorItem(44, ArmorItem::ArmorMaterial::CLOTH, 0, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_cloth) ->setIconName(L"leggingsCloth")->setDescriptionId(IDS_ITEM_LEGGINGS_CLOTH)->setUseDescriptionId(IDS_DESC_LEGGINGS_LEATHER) ); + Item::leggings_iron = (ArmorItem *) ( ( new ArmorItem(52, ArmorItem::ArmorMaterial::IRON, 2, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_iron) ->setIconName(L"leggingsIron")->setDescriptionId(IDS_ITEM_LEGGINGS_IRON)->setUseDescriptionId(IDS_DESC_LEGGINGS_IRON) ); + Item::leggings_diamond = (ArmorItem *) ( ( new ArmorItem(56, ArmorItem::ArmorMaterial::DIAMOND, 3, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_diamond) ->setIconName(L"leggingsDiamond")->setDescriptionId(IDS_ITEM_LEGGINGS_DIAMOND)->setUseDescriptionId(IDS_DESC_LEGGINGS_DIAMOND) ); + Item::leggings_gold = (ArmorItem *) ( ( new ArmorItem(60, ArmorItem::ArmorMaterial::GOLD, 4, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_gold) ->setIconName(L"leggingsGold")->setDescriptionId(IDS_ITEM_LEGGINGS_GOLD)->setUseDescriptionId(IDS_DESC_LEGGINGS_GOLD) ); - Item::helmet_chain = (ArmorItem *) ( ( new ArmorItem(46, ArmorItem::ArmorMaterial::CHAIN, 1, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_chain) ->setTextureName(L"helmetChain")->setDescriptionId(IDS_ITEM_HELMET_CHAIN)->setUseDescriptionId(IDS_DESC_HELMET_CHAIN) ); - Item::chestplate_chain = (ArmorItem *) ( ( new ArmorItem(47, ArmorItem::ArmorMaterial::CHAIN, 1, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_chain) ->setTextureName(L"chestplateChain")->setDescriptionId(IDS_ITEM_CHESTPLATE_CHAIN)->setUseDescriptionId(IDS_DESC_CHESTPLATE_CHAIN) ); - Item::leggings_chain = (ArmorItem *) ( ( new ArmorItem(48, ArmorItem::ArmorMaterial::CHAIN, 1, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_chain) ->setTextureName(L"leggingsChain")->setDescriptionId(IDS_ITEM_LEGGINGS_CHAIN)->setUseDescriptionId(IDS_DESC_LEGGINGS_CHAIN) ); - Item::boots_chain = (ArmorItem *) ( ( new ArmorItem(49, ArmorItem::ArmorMaterial::CHAIN, 1, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_chain) ->setTextureName(L"bootsChain")->setDescriptionId(IDS_ITEM_BOOTS_CHAIN)->setUseDescriptionId(IDS_DESC_BOOTS_CHAIN) ); + Item::helmet_chain = (ArmorItem *) ( ( new ArmorItem(46, ArmorItem::ArmorMaterial::CHAIN, 1, ArmorItem::SLOT_HEAD) ) ->setBaseItemTypeAndMaterial(eBaseItemType_helmet, eMaterial_chain) ->setIconName(L"helmetChain")->setDescriptionId(IDS_ITEM_HELMET_CHAIN)->setUseDescriptionId(IDS_DESC_HELMET_CHAIN) ); + Item::chestplate_chain = (ArmorItem *) ( ( new ArmorItem(47, ArmorItem::ArmorMaterial::CHAIN, 1, ArmorItem::SLOT_TORSO) ) ->setBaseItemTypeAndMaterial(eBaseItemType_chestplate, eMaterial_chain) ->setIconName(L"chestplateChain")->setDescriptionId(IDS_ITEM_CHESTPLATE_CHAIN)->setUseDescriptionId(IDS_DESC_CHESTPLATE_CHAIN) ); + Item::leggings_chain = (ArmorItem *) ( ( new ArmorItem(48, ArmorItem::ArmorMaterial::CHAIN, 1, ArmorItem::SLOT_LEGS) ) ->setBaseItemTypeAndMaterial(eBaseItemType_leggings, eMaterial_chain) ->setIconName(L"leggingsChain")->setDescriptionId(IDS_ITEM_LEGGINGS_CHAIN)->setUseDescriptionId(IDS_DESC_LEGGINGS_CHAIN) ); + Item::boots_chain = (ArmorItem *) ( ( new ArmorItem(49, ArmorItem::ArmorMaterial::CHAIN, 1, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_chain) ->setIconName(L"bootsChain")->setDescriptionId(IDS_ITEM_BOOTS_CHAIN)->setUseDescriptionId(IDS_DESC_BOOTS_CHAIN) ); - Item::boots_cloth = (ArmorItem *) ( ( new ArmorItem(45, ArmorItem::ArmorMaterial::CLOTH, 0, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_cloth) ->setTextureName(L"bootsCloth")->setDescriptionId(IDS_ITEM_BOOTS_CLOTH)->setUseDescriptionId(IDS_DESC_BOOTS_LEATHER) ); - Item::boots_iron = (ArmorItem *) ( ( new ArmorItem(53, ArmorItem::ArmorMaterial::IRON, 2, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_iron) ->setTextureName(L"bootsIron")->setDescriptionId(IDS_ITEM_BOOTS_IRON)->setUseDescriptionId(IDS_DESC_BOOTS_IRON) ); - Item::boots_diamond = (ArmorItem *) ( ( new ArmorItem(57, ArmorItem::ArmorMaterial::DIAMOND, 3, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_diamond) ->setTextureName(L"bootsDiamond")->setDescriptionId(IDS_ITEM_BOOTS_DIAMOND)->setUseDescriptionId(IDS_DESC_BOOTS_DIAMOND) ); - Item::boots_gold = (ArmorItem *) ( ( new ArmorItem(61, ArmorItem::ArmorMaterial::GOLD, 4, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_gold) ->setTextureName(L"bootsGold")->setDescriptionId(IDS_ITEM_BOOTS_GOLD)->setUseDescriptionId(IDS_DESC_BOOTS_GOLD) ); + Item::boots_leather = (ArmorItem *) ( ( new ArmorItem(45, ArmorItem::ArmorMaterial::CLOTH, 0, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_cloth) ->setIconName(L"bootsCloth")->setDescriptionId(IDS_ITEM_BOOTS_CLOTH)->setUseDescriptionId(IDS_DESC_BOOTS_LEATHER) ); + Item::boots_iron = (ArmorItem *) ( ( new ArmorItem(53, ArmorItem::ArmorMaterial::IRON, 2, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_iron) ->setIconName(L"bootsIron")->setDescriptionId(IDS_ITEM_BOOTS_IRON)->setUseDescriptionId(IDS_DESC_BOOTS_IRON) ); + Item::boots_diamond = (ArmorItem *) ( ( new ArmorItem(57, ArmorItem::ArmorMaterial::DIAMOND, 3, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_diamond) ->setIconName(L"bootsDiamond")->setDescriptionId(IDS_ITEM_BOOTS_DIAMOND)->setUseDescriptionId(IDS_DESC_BOOTS_DIAMOND) ); + Item::boots_gold = (ArmorItem *) ( ( new ArmorItem(61, ArmorItem::ArmorMaterial::GOLD, 4, ArmorItem::SLOT_FEET) ) ->setBaseItemTypeAndMaterial(eBaseItemType_boots, eMaterial_gold) ->setIconName(L"bootsGold")->setDescriptionId(IDS_ITEM_BOOTS_GOLD)->setUseDescriptionId(IDS_DESC_BOOTS_GOLD) ); - Item::ironIngot = ( new Item(9) )->setTextureName(L"ingotIron") ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_iron)->setDescriptionId(IDS_ITEM_INGOT_IRON)->setUseDescriptionId(IDS_DESC_INGOT); - Item::goldIngot = ( new Item(10) )->setTextureName(L"ingotGold") ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_gold)->setDescriptionId(IDS_ITEM_INGOT_GOLD)->setUseDescriptionId(IDS_DESC_INGOT); + Item::ironIngot = ( new Item(9) )->setIconName(L"ingotIron") ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_iron)->setDescriptionId(IDS_ITEM_INGOT_IRON)->setUseDescriptionId(IDS_DESC_INGOT); + Item::goldIngot = ( new Item(10) )->setIconName(L"ingotGold") ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_gold)->setDescriptionId(IDS_ITEM_INGOT_GOLD)->setUseDescriptionId(IDS_DESC_INGOT); // 4J-PB - todo - add materials and base types to the ones below - Item::bucket_empty = ( new BucketItem(69, 0) ) ->setBaseItemTypeAndMaterial(eBaseItemType_utensil, eMaterial_water)->setTextureName(L"bucket")->setDescriptionId(IDS_ITEM_BUCKET)->setUseDescriptionId(IDS_DESC_BUCKET)->setMaxStackSize(16); - Item::bowl = ( new Item(25) ) ->setBaseItemTypeAndMaterial(eBaseItemType_utensil, eMaterial_wood)->setTextureName(L"bowl")->setDescriptionId(IDS_ITEM_BOWL)->setUseDescriptionId(IDS_DESC_BOWL)->setMaxStackSize(64); + Item::bucket_empty = ( new BucketItem(69, 0) ) ->setBaseItemTypeAndMaterial(eBaseItemType_utensil, eMaterial_water)->setIconName(L"bucket")->setDescriptionId(IDS_ITEM_BUCKET)->setUseDescriptionId(IDS_DESC_BUCKET)->setMaxStackSize(16); + Item::bowl = ( new Item(25) ) ->setBaseItemTypeAndMaterial(eBaseItemType_utensil, eMaterial_wood)->setIconName(L"bowl")->setDescriptionId(IDS_ITEM_BOWL)->setUseDescriptionId(IDS_DESC_BOWL)->setMaxStackSize(64); - Item::bucket_water = ( new BucketItem(70, Tile::water_Id) ) ->setTextureName(L"bucketWater")->setDescriptionId(IDS_ITEM_BUCKET_WATER)->setCraftingRemainingItem(Item::bucket_empty)->setUseDescriptionId(IDS_DESC_BUCKET_WATER); - Item::bucket_lava = ( new BucketItem(71, Tile::lava_Id) ) ->setTextureName(L"bucketLava")->setDescriptionId(IDS_ITEM_BUCKET_LAVA)->setCraftingRemainingItem(Item::bucket_empty)->setUseDescriptionId(IDS_DESC_BUCKET_LAVA); - Item::milk = ( new MilkBucketItem(79) )->setTextureName(L"milk")->setDescriptionId(IDS_ITEM_BUCKET_MILK)->setCraftingRemainingItem(Item::bucket_empty)->setUseDescriptionId(IDS_DESC_BUCKET_MILK); + Item::bucket_water = ( new BucketItem(70, Tile::water_Id) ) ->setIconName(L"bucketWater")->setDescriptionId(IDS_ITEM_BUCKET_WATER)->setCraftingRemainingItem(Item::bucket_empty)->setUseDescriptionId(IDS_DESC_BUCKET_WATER); + Item::bucket_lava = ( new BucketItem(71, Tile::lava_Id) ) ->setIconName(L"bucketLava")->setDescriptionId(IDS_ITEM_BUCKET_LAVA)->setCraftingRemainingItem(Item::bucket_empty)->setUseDescriptionId(IDS_DESC_BUCKET_LAVA); + Item::bucket_milk = ( new MilkBucketItem(79) )->setIconName(L"milk")->setDescriptionId(IDS_ITEM_BUCKET_MILK)->setCraftingRemainingItem(Item::bucket_empty)->setUseDescriptionId(IDS_DESC_BUCKET_MILK); - Item::bow = (BowItem *)( new BowItem(5) ) ->setTextureName(L"bow")->setBaseItemTypeAndMaterial(eBaseItemType_bow, eMaterial_bow) ->setDescriptionId(IDS_ITEM_BOW)->setUseDescriptionId(IDS_DESC_BOW); - Item::arrow = ( new Item(6) ) ->setTextureName(L"arrow")->setBaseItemTypeAndMaterial(eBaseItemType_bow, eMaterial_arrow) ->setDescriptionId(IDS_ITEM_ARROW)->setUseDescriptionId(IDS_DESC_ARROW); + Item::bow = (BowItem *)( new BowItem(5) ) ->setIconName(L"bow")->setBaseItemTypeAndMaterial(eBaseItemType_bow, eMaterial_bow) ->setDescriptionId(IDS_ITEM_BOW)->setUseDescriptionId(IDS_DESC_BOW); + Item::arrow = ( new Item(6) ) ->setIconName(L"arrow")->setBaseItemTypeAndMaterial(eBaseItemType_bow, eMaterial_arrow) ->setDescriptionId(IDS_ITEM_ARROW)->setUseDescriptionId(IDS_DESC_ARROW); - Item::compass = ( new CompassItem(89) ) ->setTextureName(L"compass")->setBaseItemTypeAndMaterial(eBaseItemType_pockettool, eMaterial_compass) ->setDescriptionId(IDS_ITEM_COMPASS)->setUseDescriptionId(IDS_DESC_COMPASS); - Item::clock = ( new ClockItem(91) ) ->setTextureName(L"clock")->setBaseItemTypeAndMaterial(eBaseItemType_pockettool, eMaterial_clock) ->setDescriptionId(IDS_ITEM_CLOCK)->setUseDescriptionId(IDS_DESC_CLOCK); - Item::map = (MapItem *) ( new MapItem(102) ) ->setTextureName(L"map")->setBaseItemTypeAndMaterial(eBaseItemType_pockettool, eMaterial_map) ->setDescriptionId(IDS_ITEM_MAP)->setUseDescriptionId(IDS_DESC_MAP); + Item::compass = ( new CompassItem(89) ) ->setIconName(L"compass")->setBaseItemTypeAndMaterial(eBaseItemType_pockettool, eMaterial_compass) ->setDescriptionId(IDS_ITEM_COMPASS)->setUseDescriptionId(IDS_DESC_COMPASS); + Item::clock = ( new ClockItem(91) ) ->setIconName(L"clock")->setBaseItemTypeAndMaterial(eBaseItemType_pockettool, eMaterial_clock) ->setDescriptionId(IDS_ITEM_CLOCK)->setUseDescriptionId(IDS_DESC_CLOCK); + Item::map = (MapItem *) ( new MapItem(102) ) ->setIconName(L"map")->setBaseItemTypeAndMaterial(eBaseItemType_pockettool, eMaterial_map) ->setDescriptionId(IDS_ITEM_MAP)->setUseDescriptionId(IDS_DESC_MAP); - Item::flintAndSteel = ( new FlintAndSteelItem(3) ) ->setTextureName(L"flintAndSteel")->setBaseItemTypeAndMaterial(eBaseItemType_devicetool, eMaterial_flintandsteel)->setDescriptionId(IDS_ITEM_FLINT_AND_STEEL)->setUseDescriptionId(IDS_DESC_FLINTANDSTEEL); - Item::apple = ( new FoodItem(4, 4, FoodConstants::FOOD_SATURATION_LOW, false) ) ->setTextureName(L"apple")->setDescriptionId(IDS_ITEM_APPLE)->setUseDescriptionId(IDS_DESC_APPLE); - Item::coal = ( new CoalItem(7) ) ->setTextureName(L"coal")->setDescriptionId(IDS_ITEM_COAL)->setUseDescriptionId(IDS_DESC_COAL); - Item::diamond = ( new Item(8) ) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_diamond)->setTextureName(L"diamond")->setDescriptionId(IDS_ITEM_DIAMOND)->setUseDescriptionId(IDS_DESC_DIAMONDS); - Item::stick = ( new Item(24) ) ->setTextureName(L"stick")->handEquipped()->setDescriptionId(IDS_ITEM_STICK)->setUseDescriptionId(IDS_DESC_STICK); - Item::mushroomStew = ( new BowlFoodItem(26, 6) ) ->setTextureName(L"mushroomStew")->setDescriptionId(IDS_ITEM_MUSHROOM_STEW)->setUseDescriptionId(IDS_DESC_MUSHROOMSTEW); + Item::flintAndSteel = ( new FlintAndSteelItem(3) ) ->setIconName(L"flintAndSteel")->setBaseItemTypeAndMaterial(eBaseItemType_devicetool, eMaterial_flintandsteel)->setDescriptionId(IDS_ITEM_FLINT_AND_STEEL)->setUseDescriptionId(IDS_DESC_FLINTANDSTEEL); + Item::apple = ( new FoodItem(4, 4, FoodConstants::FOOD_SATURATION_LOW, false) ) ->setIconName(L"apple")->setDescriptionId(IDS_ITEM_APPLE)->setUseDescriptionId(IDS_DESC_APPLE); + Item::coal = ( new CoalItem(7) ) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_coal)->setIconName(L"coal")->setDescriptionId(IDS_ITEM_COAL)->setUseDescriptionId(IDS_DESC_COAL); + Item::diamond = ( new Item(8) ) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_diamond)->setIconName(L"diamond")->setDescriptionId(IDS_ITEM_DIAMOND)->setUseDescriptionId(IDS_DESC_DIAMONDS); + Item::stick = ( new Item(24) ) ->setIconName(L"stick")->handEquipped()->setDescriptionId(IDS_ITEM_STICK)->setUseDescriptionId(IDS_DESC_STICK); + Item::mushroomStew = ( new BowlFoodItem(26, 6) ) ->setIconName(L"mushroomStew")->setDescriptionId(IDS_ITEM_MUSHROOM_STEW)->setUseDescriptionId(IDS_DESC_MUSHROOMSTEW); - Item::string = ( new TilePlanterItem(31, Tile::tripWire) ) ->setTextureName(L"string")->setDescriptionId(IDS_ITEM_STRING)->setUseDescriptionId(IDS_DESC_STRING); - Item::feather = ( new Item(32) ) ->setTextureName(L"feather")->setDescriptionId(IDS_ITEM_FEATHER)->setUseDescriptionId(IDS_DESC_FEATHER); - Item::sulphur = ( new Item(33) ) ->setTextureName(L"sulphur")->setDescriptionId(IDS_ITEM_SULPHUR)->setUseDescriptionId(IDS_DESC_SULPHUR)->setPotionBrewingFormula(PotionBrewing::MOD_GUNPOWDER); + Item::string = ( new TilePlanterItem(31, Tile::tripWire) ) ->setIconName(L"string")->setDescriptionId(IDS_ITEM_STRING)->setUseDescriptionId(IDS_DESC_STRING); + Item::feather = ( new Item(32) ) ->setIconName(L"feather")->setDescriptionId(IDS_ITEM_FEATHER)->setUseDescriptionId(IDS_DESC_FEATHER); + Item::gunpowder = ( new Item(33) ) ->setIconName(L"sulphur")->setDescriptionId(IDS_ITEM_SULPHUR)->setUseDescriptionId(IDS_DESC_SULPHUR)->setPotionBrewingFormula(PotionBrewing::MOD_GUNPOWDER); - Item::seeds_wheat = ( new SeedItem(39, Tile::crops_Id, Tile::farmland_Id) ) ->setTextureName(L"seeds")->setDescriptionId(IDS_ITEM_WHEAT_SEEDS)->setUseDescriptionId(IDS_DESC_WHEAT_SEEDS); - Item::wheat = ( new Item(40) ) ->setTextureName(L"wheat")->setDescriptionId(IDS_ITEM_WHEAT)->setUseDescriptionId(IDS_DESC_WHEAT); - Item::bread = ( new FoodItem(41, 5, FoodConstants::FOOD_SATURATION_NORMAL, false) ) ->setTextureName(L"bread")->setDescriptionId(IDS_ITEM_BREAD)->setUseDescriptionId(IDS_DESC_BREAD); + Item::seeds_wheat = ( new SeedItem(39, Tile::wheat_Id, Tile::farmland_Id) ) ->setIconName(L"seeds")->setDescriptionId(IDS_ITEM_WHEAT_SEEDS)->setUseDescriptionId(IDS_DESC_WHEAT_SEEDS); + Item::wheat = ( new Item(40) ) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_wheat)->setIconName(L"wheat")->setDescriptionId(IDS_ITEM_WHEAT)->setUseDescriptionId(IDS_DESC_WHEAT); + Item::bread = ( new FoodItem(41, 5, FoodConstants::FOOD_SATURATION_NORMAL, false) ) ->setIconName(L"bread")->setDescriptionId(IDS_ITEM_BREAD)->setUseDescriptionId(IDS_DESC_BREAD); - Item::flint = ( new Item(62) ) ->setTextureName(L"flint")->setDescriptionId(IDS_ITEM_FLINT)->setUseDescriptionId(IDS_DESC_FLINT); - Item::porkChop_raw = ( new FoodItem(63, 3, FoodConstants::FOOD_SATURATION_LOW, true) ) ->setTextureName(L"porkchopRaw")->setDescriptionId(IDS_ITEM_PORKCHOP_RAW)->setUseDescriptionId(IDS_DESC_PORKCHOP_RAW); - Item::porkChop_cooked = ( new FoodItem(64, 8, FoodConstants::FOOD_SATURATION_GOOD, true) ) ->setTextureName(L"porkchopCooked")->setDescriptionId(IDS_ITEM_PORKCHOP_COOKED)->setUseDescriptionId(IDS_DESC_PORKCHOP_COOKED); - Item::painting = ( new HangingEntityItem(65,eTYPE_PAINTING) ) ->setBaseItemTypeAndMaterial(eBaseItemType_HangingItem, eMaterial_cloth)->setTextureName(L"painting")->setDescriptionId(IDS_ITEM_PAINTING)->setUseDescriptionId(IDS_DESC_PICTURE); + Item::flint = ( new Item(62) ) ->setIconName(L"flint")->setDescriptionId(IDS_ITEM_FLINT)->setUseDescriptionId(IDS_DESC_FLINT); + Item::porkChop_raw = ( new FoodItem(63, 3, FoodConstants::FOOD_SATURATION_LOW, true) ) ->setIconName(L"porkchopRaw")->setDescriptionId(IDS_ITEM_PORKCHOP_RAW)->setUseDescriptionId(IDS_DESC_PORKCHOP_RAW); + Item::porkChop_cooked = ( new FoodItem(64, 8, FoodConstants::FOOD_SATURATION_GOOD, true) ) ->setIconName(L"porkchopCooked")->setDescriptionId(IDS_ITEM_PORKCHOP_COOKED)->setUseDescriptionId(IDS_DESC_PORKCHOP_COOKED); + Item::painting = ( new HangingEntityItem(65,eTYPE_PAINTING) ) ->setBaseItemTypeAndMaterial(eBaseItemType_HangingItem, eMaterial_cloth)->setIconName(L"painting")->setDescriptionId(IDS_ITEM_PAINTING)->setUseDescriptionId(IDS_DESC_PICTURE); - Item::apple_gold = ( new GoldenAppleItem(66, 4, FoodConstants::FOOD_SATURATION_SUPERNATURAL, false) )->setCanAlwaysEat()->setEatEffect(MobEffect::regeneration->id, 5, 0, 1.0f) - ->setBaseItemTypeAndMaterial(eBaseItemType_giltFruit,eMaterial_apple)->setTextureName(L"appleGold")->setDescriptionId(IDS_ITEM_APPLE_GOLD);//->setUseDescriptionId(IDS_DESC_GOLDENAPPLE); + Item::apple_gold = ( new GoldenAppleItem(66, 4, FoodConstants::FOOD_SATURATION_SUPERNATURAL, false) )->setCanAlwaysEat()->setEatEffect(MobEffect::regeneration->id, 5, 1, 1.0f) + ->setBaseItemTypeAndMaterial(eBaseItemType_giltFruit,eMaterial_apple)->setIconName(L"appleGold")->setDescriptionId(IDS_ITEM_APPLE_GOLD);//->setUseDescriptionId(IDS_DESC_GOLDENAPPLE); - Item::sign = ( new SignItem(67) ) ->setBaseItemTypeAndMaterial(eBaseItemType_HangingItem, eMaterial_wood)->setTextureName(L"sign")->setDescriptionId(IDS_ITEM_SIGN)->setUseDescriptionId(IDS_DESC_SIGN); + Item::sign = ( new SignItem(67) ) ->setBaseItemTypeAndMaterial(eBaseItemType_HangingItem, eMaterial_wood)->setIconName(L"sign")->setDescriptionId(IDS_ITEM_SIGN)->setUseDescriptionId(IDS_DESC_SIGN); - Item::minecart = ( new MinecartItem(72, Minecart::RIDEABLE) ) ->setTextureName(L"minecart")->setDescriptionId(IDS_ITEM_MINECART)->setUseDescriptionId(IDS_DESC_MINECART); - Item::saddle = ( new SaddleItem(73) ) ->setTextureName(L"saddle")->setDescriptionId(IDS_ITEM_SADDLE)->setUseDescriptionId(IDS_DESC_SADDLE); - Item::redStone = ( new RedStoneItem(75) ) ->setTextureName(L"redstone")->setDescriptionId(IDS_ITEM_REDSTONE)->setUseDescriptionId(IDS_DESC_REDSTONE_DUST)->setPotionBrewingFormula(PotionBrewing::MOD_REDSTONE); - Item::snowBall = ( new SnowballItem(76) ) ->setTextureName(L"snowball")->setDescriptionId(IDS_ITEM_SNOWBALL)->setUseDescriptionId(IDS_DESC_SNOWBALL); - - Item::boat = ( new BoatItem(77) ) ->setTextureName(L"boat")->setDescriptionId(IDS_ITEM_BOAT)->setUseDescriptionId(IDS_DESC_BOAT); - - Item::leather = ( new Item(78) ) ->setTextureName(L"leather")->setDescriptionId(IDS_ITEM_LEATHER)->setUseDescriptionId(IDS_DESC_LEATHER); - Item::brick = ( new Item(80) ) ->setTextureName(L"brick")->setDescriptionId(IDS_ITEM_BRICK)->setUseDescriptionId(IDS_DESC_BRICK); - Item::clay = ( new Item(81) ) ->setTextureName(L"clay")->setDescriptionId(IDS_ITEM_CLAY)->setUseDescriptionId(IDS_DESC_CLAY); - Item::reeds = ( new TilePlanterItem(82, Tile::reeds) ) ->setTextureName(L"reeds")->setDescriptionId(IDS_ITEM_REEDS)->setUseDescriptionId(IDS_DESC_REEDS); - Item::paper = ( new Item(83) ) ->setTextureName(L"paper")->setDescriptionId(IDS_ITEM_PAPER)->setUseDescriptionId(IDS_DESC_PAPER); - Item::book = ( new BookItem(84) ) ->setTextureName(L"book")->setDescriptionId(IDS_ITEM_BOOK)->setUseDescriptionId(IDS_DESC_BOOK); - Item::slimeBall = ( new Item(85) ) ->setTextureName(L"slimeball")->setDescriptionId(IDS_ITEM_SLIMEBALL)->setUseDescriptionId(IDS_DESC_SLIMEBALL); - Item::minecart_chest = ( new MinecartItem(86, Minecart::CHEST) ) ->setTextureName(L"minecartChest")->setDescriptionId(IDS_ITEM_MINECART_CHEST)->setUseDescriptionId(IDS_DESC_MINECARTWITHCHEST); - Item::minecart_furnace = ( new MinecartItem(87, Minecart::FURNACE) )->setTextureName(L"minecartFurnace")->setDescriptionId(IDS_ITEM_MINECART_FURNACE)->setUseDescriptionId(IDS_DESC_MINECARTWITHFURNACE); - Item::egg = ( new EggItem(88) ) ->setTextureName(L"egg")->setDescriptionId(IDS_ITEM_EGG)->setUseDescriptionId(IDS_DESC_EGG); - Item::fishingRod = (FishingRodItem *)( new FishingRodItem(90) ) ->setBaseItemTypeAndMaterial(eBaseItemType_rod, eMaterial_wood)->setTextureName(L"fishingRod")->setDescriptionId(IDS_ITEM_FISHING_ROD)->setUseDescriptionId(IDS_DESC_FISHINGROD); - Item::yellowDust = ( new Item(92) ) ->setTextureName(L"yellowDust")->setDescriptionId(IDS_ITEM_YELLOW_DUST)->setUseDescriptionId(IDS_DESC_YELLOW_DUST)->setPotionBrewingFormula(PotionBrewing::MOD_GLOWSTONE); - Item::fish_raw = ( new FoodItem(93, 2, FoodConstants::FOOD_SATURATION_LOW, false) ) ->setTextureName(L"fishRaw")->setDescriptionId(IDS_ITEM_FISH_RAW)->setUseDescriptionId(IDS_DESC_FISH_RAW); - Item::fish_cooked = ( new FoodItem(94, 5, FoodConstants::FOOD_SATURATION_NORMAL, false) ) ->setTextureName(L"fishCooked")->setDescriptionId(IDS_ITEM_FISH_COOKED)->setUseDescriptionId(IDS_DESC_FISH_COOKED); - - Item::dye_powder = ( new DyePowderItem(95) ) ->setBaseItemTypeAndMaterial(eBaseItemType_dyepowder, eMaterial_dye)->setTextureName(L"dyePowder")->setDescriptionId(IDS_ITEM_DYE_POWDER)->setUseDescriptionId(-1); - - Item::bone = ( new Item(96) ) ->setTextureName(L"bone")->setDescriptionId(IDS_ITEM_BONE)->handEquipped()->setUseDescriptionId(IDS_DESC_BONE); - Item::sugar = ( new Item(97) ) ->setTextureName(L"sugar")->setDescriptionId(IDS_ITEM_SUGAR)->setUseDescriptionId(IDS_DESC_SUGAR)->setPotionBrewingFormula(PotionBrewing::MOD_SUGAR); + Item::minecart = ( new MinecartItem(72, Minecart::TYPE_RIDEABLE) ) ->setIconName(L"minecart")->setDescriptionId(IDS_ITEM_MINECART)->setUseDescriptionId(IDS_DESC_MINECART); + Item::saddle = ( new SaddleItem(73) ) ->setIconName(L"saddle")->setDescriptionId(IDS_ITEM_SADDLE)->setUseDescriptionId(IDS_DESC_SADDLE); + Item::redStone = ( new RedStoneItem(75) ) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_redstone)->setIconName(L"redstone")->setDescriptionId(IDS_ITEM_REDSTONE)->setUseDescriptionId(IDS_DESC_REDSTONE_DUST)->setPotionBrewingFormula(PotionBrewing::MOD_REDSTONE); + Item::snowBall = ( new SnowballItem(76) ) ->setIconName(L"snowball")->setDescriptionId(IDS_ITEM_SNOWBALL)->setUseDescriptionId(IDS_DESC_SNOWBALL); + + Item::boat = ( new BoatItem(77) ) ->setIconName(L"boat")->setDescriptionId(IDS_ITEM_BOAT)->setUseDescriptionId(IDS_DESC_BOAT); + + Item::leather = ( new Item(78) ) ->setIconName(L"leather")->setDescriptionId(IDS_ITEM_LEATHER)->setUseDescriptionId(IDS_DESC_LEATHER); + Item::brick = ( new Item(80) ) ->setIconName(L"brick")->setDescriptionId(IDS_ITEM_BRICK)->setUseDescriptionId(IDS_DESC_BRICK); + Item::clay = ( new Item(81) ) ->setIconName(L"clay")->setDescriptionId(IDS_ITEM_CLAY)->setUseDescriptionId(IDS_DESC_CLAY); + Item::reeds = ( new TilePlanterItem(82, Tile::reeds) ) ->setIconName(L"reeds")->setDescriptionId(IDS_ITEM_REEDS)->setUseDescriptionId(IDS_DESC_REEDS); + Item::paper = ( new Item(83) ) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_paper, Item::eMaterial_paper)->setIconName(L"paper")->setDescriptionId(IDS_ITEM_PAPER)->setUseDescriptionId(IDS_DESC_PAPER); + Item::book = ( new BookItem(84) ) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_paper, Item::eMaterial_book)->setIconName(L"book")->setDescriptionId(IDS_ITEM_BOOK)->setUseDescriptionId(IDS_DESC_BOOK); + Item::slimeBall = ( new Item(85) ) ->setIconName(L"slimeball")->setDescriptionId(IDS_ITEM_SLIMEBALL)->setUseDescriptionId(IDS_DESC_SLIMEBALL); + Item::minecart_chest = ( new MinecartItem(86, Minecart::TYPE_CHEST) ) ->setIconName(L"minecart_chest")->setDescriptionId(IDS_ITEM_MINECART_CHEST)->setUseDescriptionId(IDS_DESC_MINECARTWITHCHEST); + Item::minecart_furnace = ( new MinecartItem(87, Minecart::TYPE_FURNACE) )->setIconName(L"minecart_furnace")->setDescriptionId(IDS_ITEM_MINECART_FURNACE)->setUseDescriptionId(IDS_DESC_MINECARTWITHFURNACE); + Item::egg = ( new EggItem(88) ) ->setIconName(L"egg")->setDescriptionId(IDS_ITEM_EGG)->setUseDescriptionId(IDS_DESC_EGG); + Item::fishingRod = (FishingRodItem *)( new FishingRodItem(90) ) ->setBaseItemTypeAndMaterial(eBaseItemType_rod, eMaterial_wood)->setIconName(L"fishingRod")->setDescriptionId(IDS_ITEM_FISHING_ROD)->setUseDescriptionId(IDS_DESC_FISHINGROD); + Item::yellowDust = ( new Item(92) ) ->setIconName(L"yellowDust")->setDescriptionId(IDS_ITEM_YELLOW_DUST)->setUseDescriptionId(IDS_DESC_YELLOW_DUST)->setPotionBrewingFormula(PotionBrewing::MOD_GLOWSTONE); + Item::fish_raw = ( new FoodItem(93, 2, FoodConstants::FOOD_SATURATION_LOW, false) ) ->setIconName(L"fishRaw")->setDescriptionId(IDS_ITEM_FISH_RAW)->setUseDescriptionId(IDS_DESC_FISH_RAW); + Item::fish_cooked = ( new FoodItem(94, 5, FoodConstants::FOOD_SATURATION_NORMAL, false) ) ->setIconName(L"fishCooked")->setDescriptionId(IDS_ITEM_FISH_COOKED)->setUseDescriptionId(IDS_DESC_FISH_COOKED); + + Item::dye_powder = ( new DyePowderItem(95) ) ->setBaseItemTypeAndMaterial(eBaseItemType_dyepowder, eMaterial_dye)->setIconName(L"dyePowder")->setDescriptionId(IDS_ITEM_DYE_POWDER)->setUseDescriptionId(-1); + + Item::bone = ( new Item(96) ) ->setIconName(L"bone")->setDescriptionId(IDS_ITEM_BONE)->handEquipped()->setUseDescriptionId(IDS_DESC_BONE); + Item::sugar = ( new Item(97) ) ->setIconName(L"sugar")->setDescriptionId(IDS_ITEM_SUGAR)->setUseDescriptionId(IDS_DESC_SUGAR)->setPotionBrewingFormula(PotionBrewing::MOD_SUGAR); // 4J-PB - changing the cake to be stackable - Jens ok'ed this 23/10/12 //Item::cake = ( new TilePlanterItem(98, Tile::cake) )->setMaxStackSize(1)->setIcon(13, 1)->setDescriptionId(IDS_ITEM_CAKE)->setUseDescriptionId(IDS_DESC_CAKE); - Item::cake = ( new TilePlanterItem(98, Tile::cake) ) ->setTextureName(L"cake")->setDescriptionId(IDS_ITEM_CAKE)->setUseDescriptionId(IDS_DESC_CAKE); + Item::cake = ( new TilePlanterItem(98, Tile::cake) ) ->setIconName(L"cake")->setDescriptionId(IDS_ITEM_CAKE)->setUseDescriptionId(IDS_DESC_CAKE); - Item::bed = ( new BedItem(99) ) ->setMaxStackSize(1)->setTextureName(L"bed")->setDescriptionId(IDS_ITEM_BED)->setUseDescriptionId(IDS_DESC_BED); + Item::bed = ( new BedItem(99) ) ->setMaxStackSize(1)->setIconName(L"bed")->setDescriptionId(IDS_ITEM_BED)->setUseDescriptionId(IDS_DESC_BED); - Item::diode = ( new TilePlanterItem(100, (Tile *)Tile::diode_off) ) ->setTextureName(L"diode")->setDescriptionId(IDS_ITEM_DIODE)->setUseDescriptionId(IDS_DESC_REDSTONEREPEATER); - Item::cookie = ( new FoodItem(101, 2, FoodConstants::FOOD_SATURATION_POOR, false) ) ->setTextureName(L"cookie")->setDescriptionId(IDS_ITEM_COOKIE)->setUseDescriptionId(IDS_DESC_COOKIE); + Item::repeater = ( new TilePlanterItem(100, (Tile *)Tile::diode_off) ) ->setIconName(L"diode")->setDescriptionId(IDS_ITEM_DIODE)->setUseDescriptionId(IDS_DESC_REDSTONEREPEATER); + Item::cookie = ( new FoodItem(101, 2, FoodConstants::FOOD_SATURATION_POOR, false) ) ->setIconName(L"cookie")->setDescriptionId(IDS_ITEM_COOKIE)->setUseDescriptionId(IDS_DESC_COOKIE); - Item::shears = (ShearsItem *)( new ShearsItem(103) ) ->setTextureName(L"shears")->setBaseItemTypeAndMaterial(eBaseItemType_devicetool, eMaterial_shears)->setDescriptionId(IDS_ITEM_SHEARS)->setUseDescriptionId(IDS_DESC_SHEARS); + Item::shears = (ShearsItem *)( new ShearsItem(103) ) ->setIconName(L"shears")->setBaseItemTypeAndMaterial(eBaseItemType_devicetool, eMaterial_shears)->setDescriptionId(IDS_ITEM_SHEARS)->setUseDescriptionId(IDS_DESC_SHEARS); - Item::melon = (new FoodItem(104, 2, FoodConstants::FOOD_SATURATION_LOW, false)) ->setTextureName(L"melon")->setDescriptionId(IDS_ITEM_MELON_SLICE)->setUseDescriptionId(IDS_DESC_MELON_SLICE); + Item::melon = (new FoodItem(104, 2, FoodConstants::FOOD_SATURATION_LOW, false)) ->setIconName(L"melon")->setDescriptionId(IDS_ITEM_MELON_SLICE)->setUseDescriptionId(IDS_DESC_MELON_SLICE); - Item::seeds_pumpkin = (new SeedItem(105, Tile::pumpkinStem_Id, Tile::farmland_Id)) ->setTextureName(L"seeds_pumpkin")->setBaseItemTypeAndMaterial(eBaseItemType_seed, eMaterial_pumpkin)->setDescriptionId(IDS_ITEM_PUMPKIN_SEEDS)->setUseDescriptionId(IDS_DESC_PUMPKIN_SEEDS); - Item::seeds_melon = (new SeedItem(106, Tile::melonStem_Id, Tile::farmland_Id)) ->setTextureName(L"seeds_melon")->setBaseItemTypeAndMaterial(eBaseItemType_seed, eMaterial_melon)->setDescriptionId(IDS_ITEM_MELON_SEEDS)->setUseDescriptionId(IDS_DESC_MELON_SEEDS); + Item::seeds_pumpkin = (new SeedItem(105, Tile::pumpkinStem_Id, Tile::farmland_Id)) ->setIconName(L"seeds_pumpkin")->setBaseItemTypeAndMaterial(eBaseItemType_seed, eMaterial_pumpkin)->setDescriptionId(IDS_ITEM_PUMPKIN_SEEDS)->setUseDescriptionId(IDS_DESC_PUMPKIN_SEEDS); + Item::seeds_melon = (new SeedItem(106, Tile::melonStem_Id, Tile::farmland_Id)) ->setIconName(L"seeds_melon")->setBaseItemTypeAndMaterial(eBaseItemType_seed, eMaterial_melon)->setDescriptionId(IDS_ITEM_MELON_SEEDS)->setUseDescriptionId(IDS_DESC_MELON_SEEDS); - Item::beef_raw = (new FoodItem(107, 3, FoodConstants::FOOD_SATURATION_LOW, true)) ->setTextureName(L"beefRaw")->setDescriptionId(IDS_ITEM_BEEF_RAW)->setUseDescriptionId(IDS_DESC_BEEF_RAW); - Item::beef_cooked = (new FoodItem(108, 8, FoodConstants::FOOD_SATURATION_GOOD, true))->setTextureName(L"beefCooked")->setDescriptionId(IDS_ITEM_BEEF_COOKED)->setUseDescriptionId(IDS_DESC_BEEF_COOKED); - Item::chicken_raw = (new FoodItem(109, 2, FoodConstants::FOOD_SATURATION_LOW, true))->setEatEffect(MobEffect::hunger->id, 30, 0, .3f)->setTextureName(L"chickenRaw")->setDescriptionId(IDS_ITEM_CHICKEN_RAW)->setUseDescriptionId(IDS_DESC_CHICKEN_RAW); - Item::chicken_cooked = (new FoodItem(110, 6, FoodConstants::FOOD_SATURATION_NORMAL, true))->setTextureName(L"chickenCooked")->setDescriptionId(IDS_ITEM_CHICKEN_COOKED)->setUseDescriptionId(IDS_DESC_CHICKEN_COOKED); - Item::rotten_flesh = (new FoodItem(111, 4, FoodConstants::FOOD_SATURATION_POOR, true))->setEatEffect(MobEffect::hunger->id, 30, 0, .8f)->setTextureName(L"rottenFlesh")->setDescriptionId(IDS_ITEM_ROTTEN_FLESH)->setUseDescriptionId(IDS_DESC_ROTTEN_FLESH); + Item::beef_raw = (new FoodItem(107, 3, FoodConstants::FOOD_SATURATION_LOW, true)) ->setIconName(L"beefRaw")->setDescriptionId(IDS_ITEM_BEEF_RAW)->setUseDescriptionId(IDS_DESC_BEEF_RAW); + Item::beef_cooked = (new FoodItem(108, 8, FoodConstants::FOOD_SATURATION_GOOD, true))->setIconName(L"beefCooked")->setDescriptionId(IDS_ITEM_BEEF_COOKED)->setUseDescriptionId(IDS_DESC_BEEF_COOKED); + Item::chicken_raw = (new FoodItem(109, 2, FoodConstants::FOOD_SATURATION_LOW, true))->setEatEffect(MobEffect::hunger->id, 30, 0, .3f)->setIconName(L"chickenRaw")->setDescriptionId(IDS_ITEM_CHICKEN_RAW)->setUseDescriptionId(IDS_DESC_CHICKEN_RAW); + Item::chicken_cooked = (new FoodItem(110, 6, FoodConstants::FOOD_SATURATION_NORMAL, true))->setIconName(L"chickenCooked")->setDescriptionId(IDS_ITEM_CHICKEN_COOKED)->setUseDescriptionId(IDS_DESC_CHICKEN_COOKED); + Item::rotten_flesh = (new FoodItem(111, 4, FoodConstants::FOOD_SATURATION_POOR, true))->setEatEffect(MobEffect::hunger->id, 30, 0, .8f)->setIconName(L"rottenFlesh")->setDescriptionId(IDS_ITEM_ROTTEN_FLESH)->setUseDescriptionId(IDS_DESC_ROTTEN_FLESH); - Item::enderPearl = (new EnderpearlItem(112)) ->setTextureName(L"enderPearl")->setDescriptionId(IDS_ITEM_ENDER_PEARL)->setUseDescriptionId(IDS_DESC_ENDER_PEARL); + Item::enderPearl = (new EnderpearlItem(112)) ->setIconName(L"enderPearl")->setDescriptionId(IDS_ITEM_ENDER_PEARL)->setUseDescriptionId(IDS_DESC_ENDER_PEARL); - Item::blazeRod = (new Item(113) ) ->setTextureName(L"blazeRod")->setDescriptionId(IDS_ITEM_BLAZE_ROD)->setUseDescriptionId(IDS_DESC_BLAZE_ROD)->handEquipped(); - Item::ghastTear = (new Item(114) ) ->setTextureName(L"ghastTear")->setDescriptionId(IDS_ITEM_GHAST_TEAR)->setUseDescriptionId(IDS_DESC_GHAST_TEAR)->setPotionBrewingFormula(PotionBrewing::MOD_GHASTTEARS); - Item::goldNugget = (new Item(115) ) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_gold)->setTextureName(L"goldNugget")->setDescriptionId(IDS_ITEM_GOLD_NUGGET)->setUseDescriptionId(IDS_DESC_GOLD_NUGGET); + Item::blazeRod = (new Item(113) ) ->setIconName(L"blazeRod")->setDescriptionId(IDS_ITEM_BLAZE_ROD)->setUseDescriptionId(IDS_DESC_BLAZE_ROD)->handEquipped(); + Item::ghastTear = (new Item(114) ) ->setIconName(L"ghastTear")->setDescriptionId(IDS_ITEM_GHAST_TEAR)->setUseDescriptionId(IDS_DESC_GHAST_TEAR)->setPotionBrewingFormula(PotionBrewing::MOD_GHASTTEARS); + Item::goldNugget = (new Item(115) ) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_gold)->setIconName(L"goldNugget")->setDescriptionId(IDS_ITEM_GOLD_NUGGET)->setUseDescriptionId(IDS_DESC_GOLD_NUGGET); - Item::netherStalkSeeds = (new SeedItem(116, Tile::netherStalk_Id, Tile::hellSand_Id) ) ->setTextureName(L"netherStalkSeeds")->setDescriptionId(IDS_ITEM_NETHER_STALK_SEEDS)->setUseDescriptionId(IDS_DESC_NETHER_STALK_SEEDS)->setPotionBrewingFormula(PotionBrewing::MOD_NETHERWART); + Item::netherwart_seeds = (new SeedItem(116, Tile::netherStalk_Id, Tile::soulsand_Id) ) ->setIconName(L"netherStalkSeeds")->setDescriptionId(IDS_ITEM_NETHER_STALK_SEEDS)->setUseDescriptionId(IDS_DESC_NETHER_STALK_SEEDS)->setPotionBrewingFormula(PotionBrewing::MOD_NETHERWART); - Item::potion = (PotionItem *) ( ( new PotionItem(117) ) ->setTextureName(L"potion")->setDescriptionId(IDS_ITEM_POTION)->setUseDescriptionId(IDS_DESC_POTION) ); - Item::glassBottle = (new BottleItem(118) ) ->setBaseItemTypeAndMaterial(eBaseItemType_utensil, eMaterial_glass)->setTextureName(L"glassBottle")->setDescriptionId(IDS_ITEM_GLASS_BOTTLE)->setUseDescriptionId(IDS_DESC_GLASS_BOTTLE); + Item::potion = (PotionItem *) ( ( new PotionItem(117) ) ->setIconName(L"potion")->setDescriptionId(IDS_ITEM_POTION)->setUseDescriptionId(IDS_DESC_POTION) ); + Item::glassBottle = (new BottleItem(118) ) ->setBaseItemTypeAndMaterial(eBaseItemType_utensil, eMaterial_glass)->setIconName(L"glassBottle")->setDescriptionId(IDS_ITEM_GLASS_BOTTLE)->setUseDescriptionId(IDS_DESC_GLASS_BOTTLE); - Item::spiderEye = (new FoodItem(119, 2, FoodConstants::FOOD_SATURATION_GOOD, false) ) ->setEatEffect(MobEffect::poison->id, 5, 0, 1.0f)->setTextureName(L"spiderEye")->setDescriptionId(IDS_ITEM_SPIDER_EYE)->setUseDescriptionId(IDS_DESC_SPIDER_EYE)->setPotionBrewingFormula(PotionBrewing::MOD_SPIDEREYE); - Item::fermentedSpiderEye = (new Item(120) ) ->setTextureName(L"fermentedSpiderEye")->setDescriptionId(IDS_ITEM_FERMENTED_SPIDER_EYE)->setUseDescriptionId(IDS_DESC_FERMENTED_SPIDER_EYE)->setPotionBrewingFormula(PotionBrewing::MOD_FERMENTEDEYE); + Item::spiderEye = (new FoodItem(119, 2, FoodConstants::FOOD_SATURATION_GOOD, false) ) ->setEatEffect(MobEffect::poison->id, 5, 0, 1.0f)->setIconName(L"spiderEye")->setDescriptionId(IDS_ITEM_SPIDER_EYE)->setUseDescriptionId(IDS_DESC_SPIDER_EYE)->setPotionBrewingFormula(PotionBrewing::MOD_SPIDEREYE); + Item::fermentedSpiderEye = (new Item(120) ) ->setIconName(L"fermentedSpiderEye")->setDescriptionId(IDS_ITEM_FERMENTED_SPIDER_EYE)->setUseDescriptionId(IDS_DESC_FERMENTED_SPIDER_EYE)->setPotionBrewingFormula(PotionBrewing::MOD_FERMENTEDEYE); - Item::blazePowder = (new Item(121) ) ->setTextureName(L"blazePowder")->setDescriptionId(IDS_ITEM_BLAZE_POWDER)->setUseDescriptionId(IDS_DESC_BLAZE_POWDER)->setPotionBrewingFormula(PotionBrewing::MOD_BLAZEPOWDER); - Item::magmaCream = (new Item(122) ) ->setTextureName(L"magmaCream")->setDescriptionId(IDS_ITEM_MAGMA_CREAM)->setUseDescriptionId(IDS_DESC_MAGMA_CREAM)->setPotionBrewingFormula(PotionBrewing::MOD_MAGMACREAM); + Item::blazePowder = (new Item(121) ) ->setIconName(L"blazePowder")->setDescriptionId(IDS_ITEM_BLAZE_POWDER)->setUseDescriptionId(IDS_DESC_BLAZE_POWDER)->setPotionBrewingFormula(PotionBrewing::MOD_BLAZEPOWDER); + Item::magmaCream = (new Item(122) ) ->setIconName(L"magmaCream")->setDescriptionId(IDS_ITEM_MAGMA_CREAM)->setUseDescriptionId(IDS_DESC_MAGMA_CREAM)->setPotionBrewingFormula(PotionBrewing::MOD_MAGMACREAM); - Item::brewingStand = (new TilePlanterItem(123, Tile::brewingStand) ) ->setBaseItemTypeAndMaterial(eBaseItemType_device, eMaterial_blaze)->setTextureName(L"brewingStand")->setDescriptionId(IDS_ITEM_BREWING_STAND)->setUseDescriptionId(IDS_DESC_BREWING_STAND); - Item::cauldron = (new TilePlanterItem(124, Tile::cauldron) ) ->setBaseItemTypeAndMaterial(eBaseItemType_utensil, eMaterial_iron)->setTextureName(L"cauldron")->setDescriptionId(IDS_ITEM_CAULDRON)->setUseDescriptionId(IDS_DESC_CAULDRON); - Item::eyeOfEnder = (new EnderEyeItem(125) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pockettool, eMaterial_ender)->setTextureName(L"eyeOfEnder")->setDescriptionId(IDS_ITEM_EYE_OF_ENDER)->setUseDescriptionId(IDS_DESC_EYE_OF_ENDER); - Item::speckledMelon = (new Item(126) ) ->setBaseItemTypeAndMaterial(eBaseItemType_giltFruit, eMaterial_melon)->setTextureName(L"speckledMelon")->setDescriptionId(IDS_ITEM_SPECKLED_MELON)->setUseDescriptionId(IDS_DESC_SPECKLED_MELON)->setPotionBrewingFormula(PotionBrewing::MOD_SPECKLEDMELON); + Item::brewingStand = (new TilePlanterItem(123, Tile::brewingStand) ) ->setBaseItemTypeAndMaterial(eBaseItemType_device, eMaterial_blaze)->setIconName(L"brewingStand")->setDescriptionId(IDS_ITEM_BREWING_STAND)->setUseDescriptionId(IDS_DESC_BREWING_STAND); + Item::cauldron = (new TilePlanterItem(124, Tile::cauldron) ) ->setBaseItemTypeAndMaterial(eBaseItemType_utensil, eMaterial_iron)->setIconName(L"cauldron")->setDescriptionId(IDS_ITEM_CAULDRON)->setUseDescriptionId(IDS_DESC_CAULDRON); + Item::eyeOfEnder = (new EnderEyeItem(125) ) ->setBaseItemTypeAndMaterial(eBaseItemType_pockettool, eMaterial_ender)->setIconName(L"eyeOfEnder")->setDescriptionId(IDS_ITEM_EYE_OF_ENDER)->setUseDescriptionId(IDS_DESC_EYE_OF_ENDER); + Item::speckledMelon = (new Item(126) ) ->setBaseItemTypeAndMaterial(eBaseItemType_giltFruit, eMaterial_melon)->setIconName(L"speckledMelon")->setDescriptionId(IDS_ITEM_SPECKLED_MELON)->setUseDescriptionId(IDS_DESC_SPECKLED_MELON)->setPotionBrewingFormula(PotionBrewing::MOD_SPECKLEDMELON); - Item::monsterPlacer = (new MonsterPlacerItem(127)) ->setTextureName(L"monsterPlacer")->setDescriptionId(IDS_ITEM_MONSTER_SPAWNER)->setUseDescriptionId(IDS_DESC_MONSTER_SPAWNER); + Item::spawnEgg = (new SpawnEggItem(127)) ->setIconName(L"monsterPlacer")->setDescriptionId(IDS_ITEM_MONSTER_SPAWNER)->setUseDescriptionId(IDS_DESC_MONSTER_SPAWNER); // 4J Stu - Brought this forward - Item::expBottle = (new ExperienceItem(128)) ->setTextureName(L"expBottle")->setDescriptionId(IDS_ITEM_EXP_BOTTLE)->setUseDescriptionId(IDS_DESC_EXP_BOTTLE); + Item::expBottle = (new ExperienceItem(128)) ->setIconName(L"expBottle")->setDescriptionId(IDS_ITEM_EXP_BOTTLE)->setUseDescriptionId(IDS_DESC_EXP_BOTTLE); - Item::record_01 = ( new RecordingItem(2000, L"13") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_01)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_02 = ( new RecordingItem(2001, L"cat") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_02)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_01 = ( new RecordingItem(2000, L"13") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_01)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_02 = ( new RecordingItem(2001, L"cat") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_02)->setUseDescriptionId(IDS_DESC_RECORD); // 4J - new records brought forward from 1.2.3 - Item::record_03 = ( new RecordingItem(2002, L"blocks") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_03)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_04 = ( new RecordingItem(2003, L"chirp") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_04)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_05 = ( new RecordingItem(2004, L"far") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_05)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_06 = ( new RecordingItem(2005, L"mall") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_06)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_07 = ( new RecordingItem(2006, L"mellohi") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_07)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_09 = ( new RecordingItem(2007, L"stal") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_08)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_10 = ( new RecordingItem(2008, L"strad") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_09)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_11 = ( new RecordingItem(2009, L"ward") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_10)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_12 = ( new RecordingItem(2010, L"11") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_11)->setUseDescriptionId(IDS_DESC_RECORD); - Item::record_08 = ( new RecordingItem(2011, L"where are we now") ) ->setTextureName(L"record")->setDescriptionId(IDS_ITEM_RECORD_12)->setUseDescriptionId(IDS_DESC_RECORD); - + Item::record_03 = ( new RecordingItem(2002, L"blocks") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_03)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_04 = ( new RecordingItem(2003, L"chirp") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_04)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_05 = ( new RecordingItem(2004, L"far") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_05)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_06 = ( new RecordingItem(2005, L"mall") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_06)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_07 = ( new RecordingItem(2006, L"mellohi") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_07)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_09 = ( new RecordingItem(2007, L"stal") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_08)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_10 = ( new RecordingItem(2008, L"strad") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_09)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_11 = ( new RecordingItem(2009, L"ward") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_10)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_12 = ( new RecordingItem(2010, L"11") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_11)->setUseDescriptionId(IDS_DESC_RECORD); + Item::record_08 = ( new RecordingItem(2011, L"where are we now") ) ->setIconName(L"record")->setDescriptionId(IDS_ITEM_RECORD_12)->setUseDescriptionId(IDS_DESC_RECORD); // TU9 // putting the fire charge in as a torch, so that it stacks without being near the middle of the selection boxes - Item::fireball = (new FireChargeItem(129)) ->setBaseItemTypeAndMaterial(eBaseItemType_torch, eMaterial_setfire)->setTextureName(L"fireball")->setDescriptionId(IDS_ITEM_FIREBALL)->setUseDescriptionId(IDS_DESC_FIREBALL); - Item::frame = (new HangingEntityItem(133,eTYPE_ITEM_FRAME)) ->setBaseItemTypeAndMaterial(eBaseItemType_HangingItem, eMaterial_glass)->setTextureName(L"frame")->setDescriptionId(IDS_ITEM_ITEMFRAME)->setUseDescriptionId(IDS_DESC_ITEMFRAME); - Item::netherbrick = (new Item(149)) ->setTextureName(L"netherbrick")->setDescriptionId(IDS_ITEM_NETHERBRICK)->setUseDescriptionId(IDS_DESC_ITEM_NETHERBRICK); + Item::fireball = (new FireChargeItem(129)) ->setBaseItemTypeAndMaterial(eBaseItemType_torch, eMaterial_setfire)->setIconName(L"fireball")->setDescriptionId(IDS_ITEM_FIREBALL)->setUseDescriptionId(IDS_DESC_FIREBALL); + Item::frame = (new HangingEntityItem(133,eTYPE_ITEM_FRAME)) ->setBaseItemTypeAndMaterial(eBaseItemType_HangingItem, eMaterial_glass)->setIconName(L"frame")->setDescriptionId(IDS_ITEM_ITEMFRAME)->setUseDescriptionId(IDS_DESC_ITEMFRAME); + // TU12 - Item::skull = (new SkullItem(141)) ->setTextureName(L"skull")->setDescriptionId(IDS_ITEM_SKULL)->setUseDescriptionId(IDS_DESC_SKULL); + Item::skull = (new SkullItem(141)) ->setIconName(L"skull")->setDescriptionId(IDS_ITEM_SKULL)->setUseDescriptionId(IDS_DESC_SKULL); // TU14 //Item::writingBook = (new WritingBookItem(130))->setIcon(11, 11)->setDescriptionId("writingBook"); //Item::writtenBook = (new WrittenBookItem(131))->setIcon(12, 11)->setDescriptionId("writtenBook"); - Item::emerald = (new Item(132)) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_emerald)->setTextureName(L"emerald")->setDescriptionId(IDS_ITEM_EMERALD)->setUseDescriptionId(IDS_DESC_EMERALD); + Item::emerald = (new Item(132)) ->setBaseItemTypeAndMaterial(eBaseItemType_treasure, eMaterial_emerald)->setIconName(L"emerald")->setDescriptionId(IDS_ITEM_EMERALD)->setUseDescriptionId(IDS_DESC_EMERALD); - Item::flowerPot = (new TilePlanterItem(134, Tile::flowerPot)) ->setTextureName(L"flowerPot")->setDescriptionId(IDS_FLOWERPOT)->setUseDescriptionId(IDS_DESC_FLOWERPOT); + Item::flowerPot = (new TilePlanterItem(134, Tile::flowerPot)) ->setIconName(L"flowerPot")->setDescriptionId(IDS_FLOWERPOT)->setUseDescriptionId(IDS_DESC_FLOWERPOT); - Item::carrots = (new SeedFoodItem(135, 4, FoodConstants::FOOD_SATURATION_NORMAL, Tile::carrots_Id, Tile::farmland_Id)) ->setTextureName(L"carrots")->setDescriptionId(IDS_CARROTS)->setUseDescriptionId(IDS_DESC_CARROTS); - Item::potato = (new SeedFoodItem(136, 1, FoodConstants::FOOD_SATURATION_LOW, Tile::potatoes_Id, Tile::farmland_Id)) ->setTextureName(L"potato")->setDescriptionId(IDS_POTATO)->setUseDescriptionId(IDS_DESC_POTATO); - Item::potatoBaked = (new FoodItem(137, 6, FoodConstants::FOOD_SATURATION_NORMAL, false)) ->setTextureName(L"potatoBaked")->setDescriptionId(IDS_ITEM_POTATO_BAKED)->setUseDescriptionId(IDS_DESC_POTATO_BAKED); - Item::potatoPoisonous = (new FoodItem(138, 2, FoodConstants::FOOD_SATURATION_LOW, false)) ->setEatEffect(MobEffect::poison->id, 5, 0, .6f)->setTextureName(L"potatoPoisonous")->setDescriptionId(IDS_ITEM_POTATO_POISONOUS)->setUseDescriptionId(IDS_DESC_POTATO_POISONOUS); + Item::carrots = (new SeedFoodItem(135, 4, FoodConstants::FOOD_SATURATION_NORMAL, Tile::carrots_Id, Tile::farmland_Id)) ->setIconName(L"carrots")->setDescriptionId(IDS_CARROTS)->setUseDescriptionId(IDS_DESC_CARROTS); + Item::potato = (new SeedFoodItem(136, 1, FoodConstants::FOOD_SATURATION_LOW, Tile::potatoes_Id, Tile::farmland_Id)) ->setIconName(L"potato")->setDescriptionId(IDS_POTATO)->setUseDescriptionId(IDS_DESC_POTATO); + Item::potatoBaked = (new FoodItem(137, 6, FoodConstants::FOOD_SATURATION_NORMAL, false)) ->setIconName(L"potatoBaked")->setDescriptionId(IDS_ITEM_POTATO_BAKED)->setUseDescriptionId(IDS_DESC_POTATO_BAKED); + Item::potatoPoisonous = (new FoodItem(138, 2, FoodConstants::FOOD_SATURATION_LOW, false)) ->setEatEffect(MobEffect::poison->id, 5, 0, .6f)->setIconName(L"potatoPoisonous")->setDescriptionId(IDS_ITEM_POTATO_POISONOUS)->setUseDescriptionId(IDS_DESC_POTATO_POISONOUS); - Item::carrotGolden = (new FoodItem(140, 6, FoodConstants::FOOD_SATURATION_SUPERNATURAL, false)) ->setBaseItemTypeAndMaterial(eBaseItemType_giltFruit, eMaterial_carrot)->setTextureName(L"carrotGolden")->setPotionBrewingFormula(PotionBrewing::MOD_GOLDENCARROT)->setDescriptionId(IDS_ITEM_CARROT_GOLDEN)->setUseDescriptionId(IDS_DESC_CARROT_GOLDEN); + Item::emptyMap = (EmptyMapItem *) (new EmptyMapItem(139))->setIconName(L"map_empty")->setDescriptionId(IDS_ITEM_MAP_EMPTY)->setUseDescriptionId(IDS_DESC_MAP_EMPTY); - Item::carrotOnAStick = (new CarrotOnAStickItem(142)) ->setBaseItemTypeAndMaterial(eBaseItemType_rod, eMaterial_carrot)->setTextureName(L"carrotOnAStick")->setDescriptionId(IDS_ITEM_CARROT_ON_A_STICK)->setUseDescriptionId(IDS_DESC_CARROT_ON_A_STICK); - Item::pumpkinPie = (new FoodItem(144, 8, FoodConstants::FOOD_SATURATION_LOW, false)) ->setTextureName(L"pumpkinPie")->setDescriptionId(IDS_ITEM_PUMPKIN_PIE)->setUseDescriptionId(IDS_DESC_PUMPKIN_PIE); + Item::carrotGolden = (new FoodItem(140, 6, FoodConstants::FOOD_SATURATION_SUPERNATURAL, false)) ->setBaseItemTypeAndMaterial(eBaseItemType_giltFruit, eMaterial_carrot)->setIconName(L"carrotGolden")->setPotionBrewingFormula(PotionBrewing::MOD_GOLDENCARROT)->setDescriptionId(IDS_ITEM_CARROT_GOLDEN)->setUseDescriptionId(IDS_DESC_CARROT_GOLDEN); - EnchantedBookItem::enchantedBook = (EnchantedBookItem *)(new EnchantedBookItem(147)) ->setMaxStackSize(1)->setTextureName(L"enchantedBook")->setDescriptionId(IDS_ITEM_ENCHANTED_BOOK)->setUseDescriptionId(IDS_DESC_ENCHANTED_BOOK); - Item::netherQuartz = (new Item(150))->setTextureName(L"netherquartz")->setDescriptionId(IDS_ITEM_NETHER_QUARTZ)->setUseDescriptionId(IDS_DESC_NETHER_QUARTZ); -} + Item::carrotOnAStick = (new CarrotOnAStickItem(142)) ->setBaseItemTypeAndMaterial(eBaseItemType_rod, eMaterial_carrot)->setIconName(L"carrotOnAStick")->setDescriptionId(IDS_ITEM_CARROT_ON_A_STICK)->setUseDescriptionId(IDS_DESC_CARROT_ON_A_STICK); + Item::netherStar = (new SimpleFoiledItem(143)) ->setIconName(L"nether_star")->setDescriptionId(IDS_NETHER_STAR)->setUseDescriptionId(IDS_DESC_NETHER_STAR); + Item::pumpkinPie = (new FoodItem(144, 8, FoodConstants::FOOD_SATURATION_LOW, false)) ->setIconName(L"pumpkinPie")->setDescriptionId(IDS_ITEM_PUMPKIN_PIE)->setUseDescriptionId(IDS_DESC_PUMPKIN_PIE); + Item::fireworks = (new FireworksItem(145)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fireworks, Item::eMaterial_undefined)->setIconName(L"fireworks")->setDescriptionId(IDS_FIREWORKS)->setUseDescriptionId(IDS_DESC_FIREWORKS); + Item::fireworksCharge = (new FireworksChargeItem(146)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fireworks, Item::eMaterial_undefined)->setIconName(L"fireworks_charge")->setDescriptionId(IDS_FIREWORKS_CHARGE)->setUseDescriptionId(IDS_DESC_FIREWORKS_CHARGE); + EnchantedBookItem::enchantedBook = (EnchantedBookItem *)(new EnchantedBookItem(147)) ->setMaxStackSize(1)->setIconName(L"enchantedBook")->setDescriptionId(IDS_ITEM_ENCHANTED_BOOK)->setUseDescriptionId(IDS_DESC_ENCHANTED_BOOK); + Item::comparator = (new TilePlanterItem(148, Tile::comparator_off)) ->setIconName(L"comparator")->setDescriptionId(IDS_ITEM_COMPARATOR)->setUseDescriptionId(IDS_DESC_COMPARATOR); + Item::netherbrick = (new Item(149)) ->setIconName(L"netherbrick")->setDescriptionId(IDS_ITEM_NETHERBRICK)->setUseDescriptionId(IDS_DESC_ITEM_NETHERBRICK); + Item::netherQuartz = (new Item(150)) ->setIconName(L"netherquartz")->setDescriptionId(IDS_ITEM_NETHER_QUARTZ)->setUseDescriptionId(IDS_DESC_NETHER_QUARTZ); + Item::minecart_tnt = (new MinecartItem(151, Minecart::TYPE_TNT)) ->setIconName(L"minecart_tnt")->setDescriptionId(IDS_ITEM_MINECART_TNT)->setUseDescriptionId(IDS_DESC_MINECART_TNT); + Item::minecart_hopper = (new MinecartItem(152, Minecart::TYPE_HOPPER)) ->setIconName(L"minecart_hopper")->setDescriptionId(IDS_ITEM_MINECART_HOPPER)->setUseDescriptionId(IDS_DESC_MINECART_HOPPER); + + Item::horseArmorMetal = (new Item(161)) ->setIconName(L"iron_horse_armor")->setMaxStackSize(1)->setDescriptionId(IDS_ITEM_IRON_HORSE_ARMOR)->setUseDescriptionId(IDS_DESC_IRON_HORSE_ARMOR); + Item::horseArmorGold = (new Item(162)) ->setIconName(L"gold_horse_armor")->setMaxStackSize(1)->setDescriptionId(IDS_ITEM_GOLD_HORSE_ARMOR)->setUseDescriptionId(IDS_DESC_GOLD_HORSE_ARMOR); + Item::horseArmorDiamond = (new Item(163)) ->setIconName(L"diamond_horse_armor")->setMaxStackSize(1)->setDescriptionId(IDS_ITEM_DIAMOND_HORSE_ARMOR)->setUseDescriptionId(IDS_DESC_DIAMOND_HORSE_ARMOR); + Item::lead = (new LeashItem(164)) ->setBaseItemTypeAndMaterial(eBaseItemType_pockettool, eMaterial_undefined)->setIconName(L"lead")->setDescriptionId(IDS_ITEM_LEAD)->setUseDescriptionId(IDS_DESC_LEAD); + Item::nameTag = (new NameTagItem(165)) ->setIconName(L"name_tag")->setDescriptionId(IDS_ITEM_NAME_TAG)->setUseDescriptionId(IDS_DESC_NAME_TAG);} // 4J Stu - We need to do this after the staticCtor AND after staticCtors for other class @@ -476,7 +504,7 @@ void Item::staticInit() } -_Tier::Tier(int level, int uses, float speed, int damage, int enchantmentValue) : +_Tier::Tier(int level, int uses, float speed, float damage, int enchantmentValue) : level( level ), uses( uses ), speed( speed ), @@ -496,7 +524,7 @@ float _Tier::getSpeed() const return speed; } -int _Tier::getAttackDamageBonus() const +float _Tier::getAttackDamageBonus() const { return damage; } @@ -519,7 +547,7 @@ int _Tier::getTierItemId() const } else if (this == Tier::STONE) { - return Tile::stoneBrick_Id; + return Tile::cobblestone_Id; } else if (this == Tier::GOLD) { @@ -582,13 +610,18 @@ int Item::getMaterial() return this->m_iMaterial; } -Item *Item::setTextureName(const wstring &name) +Item *Item::setIconName(const wstring &name) { m_textureName = name; return this; } +wstring Item::getIconName() +{ + return m_textureName; +} + Item *Item::setMaxStackSize(int max) { maxStackSize = max; @@ -610,11 +643,6 @@ Icon *Item::getIcon(shared_ptr itemInstance) return getIcon(itemInstance->getAuxValue()); } -const bool Item::useOn(shared_ptr itemInstance, Level *level, int x, int y, int z, int face, bool bTestUseOnOnly) -{ - return false; -} - bool Item::useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { return false; @@ -625,7 +653,7 @@ float Item::getDestroySpeed(shared_ptr itemInstance, Tile *tile) return 1; } -bool Item::TestUse(Level *level, shared_ptr player) +bool Item::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { return false; } @@ -689,7 +717,7 @@ bool Item::canBeDepleted() * @param attacker * @return */ -bool Item::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) +bool Item::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) { return false; } @@ -705,7 +733,7 @@ bool Item::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, * @param owner * @return */ -bool Item::mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner) +bool Item::mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner) { return false; } @@ -720,14 +748,14 @@ bool Item::canDestroySpecial(Tile *tile) return false; } -bool Item::interactEnemy(shared_ptr itemInstance, shared_ptr mob) +bool Item::interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr mob) { return false; } Item *Item::handEquipped() { - this->m_handEquipped = true; + m_handEquipped = true; return this; } @@ -864,7 +892,7 @@ bool Item::hasPotionBrewingFormula() return !potionBrewingFormula.empty(); } -void Item::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced, vector &unformattedStrings) +void Item::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced) { } @@ -935,6 +963,11 @@ Icon *Item::getLayerIcon(int auxValue, int spriteLayer) return getIcon(auxValue); } +bool Item::mayBePlacedInAdventureMode() +{ + return true; +} + bool Item::isValidRepairItem(shared_ptr source, shared_ptr repairItem) { return false; @@ -945,6 +978,11 @@ void Item::registerIcons(IconRegister *iconRegister) icon = iconRegister->registerIcon(m_textureName); } +attrAttrModMap *Item::getDefaultAttributeModifiers() +{ + return new attrAttrModMap(); +} + /* 4J: These are necesary on the PS3. @@ -984,7 +1022,7 @@ const int Item::pickAxe_gold_Id ; const int Item::hatchet_gold_Id ; const int Item::string_Id ; const int Item::feather_Id ; -const int Item::sulphur_Id ; +const int Item::gunpowder_Id ; const int Item::hoe_wood_Id ; const int Item::hoe_stone_Id ; const int Item::hoe_iron_Id ; @@ -993,10 +1031,10 @@ const int Item::hoe_gold_Id ; const int Item::seeds_wheat_Id ; const int Item::wheat_Id ; const int Item::bread_Id ; -const int Item::helmet_cloth_Id ; -const int Item::chestplate_cloth_Id ; -const int Item::leggings_cloth_Id ; -const int Item::boots_cloth_Id ; +const int Item::helmet_leather_Id ; +const int Item::chestplate_leather_Id ; +const int Item::leggings_leather_Id ; +const int Item::boots_leather_Id ; const int Item::helmet_chain_Id ; const int Item::chestplate_chain_Id ; const int Item::leggings_chain_Id ; @@ -1030,7 +1068,7 @@ const int Item::redStone_Id ; const int Item::snowBall_Id ; const int Item::boat_Id ; const int Item::leather_Id ; -const int Item::milk_Id ; +const int Item::bucket_milk_Id ; const int Item::brick_Id ; const int Item::clay_Id ; const int Item::reeds_Id ; @@ -1051,7 +1089,7 @@ const int Item::bone_Id ; const int Item::sugar_Id ; const int Item::cake_Id ; const int Item::bed_Id ; -const int Item::diode_Id ; +const int Item::repeater_Id ; const int Item::cookie_Id ; const int Item::map_Id ; const int Item::shears_Id ; @@ -1067,7 +1105,7 @@ const int Item::enderPearl_Id ; const int Item::blazeRod_Id ; const int Item::ghastTear_Id ; const int Item::goldNugget_Id ; -const int Item::netherStalkSeeds_Id ; +const int Item::netherwart_seeds_Id; const int Item::potion_Id ; const int Item::glassBottle_Id ; const int Item::spiderEye_Id ; @@ -1078,7 +1116,7 @@ const int Item::brewingStand_Id ; const int Item::cauldron_Id ; const int Item::eyeOfEnder_Id ; const int Item::speckledMelon_Id ; -const int Item::monsterPlacer_Id ; +const int Item::spawnEgg_Id; const int Item::expBottle_Id ; const int Item::skull_Id ; const int Item::record_01_Id ; diff --git a/Minecraft.World/Item.h b/Minecraft.World/Item.h index 727fc661..0f9a8b1b 100644 --- a/Minecraft.World/Item.h +++ b/Minecraft.World/Item.h @@ -20,12 +20,16 @@ class ArmorItem; class BowItem; class FishingRodItem; class EnchantedBookItem; +class EmptyMapItem; #define ITEM_ICON_COLUMNS 16 class Item : public enable_shared_from_this { +protected: + //static const UUID BASE_ATTACK_DAMAGE_UUID; + public: static const int ITEM_NUM_COUNT = 32000; @@ -79,7 +83,14 @@ public: eMaterial_emerald, eMaterial_quartz, eMaterial_apple, - eMaterial_carrot + eMaterial_carrot, + eMaterial_redstone, + eMaterial_coal, + eMaterial_paper, + eMaterial_book, + eMaterial_bookshelf, + eMaterial_wheat, + } eMaterial; @@ -123,6 +134,12 @@ public: eBaseItemType_rod, eBaseItemType_giltFruit, eBaseItemType_carpet, + eBaseItemType_clay, + eBaseItemType_glass, + eBaseItemType_redstoneContainer, + eBaseItemType_fireworks, + eBaseItemType_lever, + eBaseItemType_paper, eBaseItemType_MAXTYPES, } eBaseItemType; @@ -146,25 +163,20 @@ public: const int level; const int uses; const float speed; - const int damage; + const float damage; const int enchantmentValue; // 4J Stu - Had to make this public but was protected // We shouldn't be creating these except the static initialisation public: - Tier(int level, int uses, float speed, int damage, int enchantmentValue); + Tier(int level, int uses, float speed, float damage, int enchantmentValue); public: int getUses() const; - float getSpeed() const; - - int getAttackDamageBonus() const; - + float getAttackDamageBonus() const; int getLevel() const; - int getEnchantmentValue() const; - int getTierItemId() const; }; @@ -216,7 +228,7 @@ public: static Item *string; static Item *feather; - static Item *sulphur; + static Item *gunpowder; static Item *hoe_wood; static Item *hoe_stone; @@ -228,10 +240,10 @@ public: static Item *wheat; static Item *bread; - static ArmorItem *helmet_cloth; - static ArmorItem *chestplate_cloth; - static ArmorItem *leggings_cloth; - static ArmorItem *boots_cloth; + static ArmorItem *helmet_leather; + static ArmorItem *chestplate_leather; + static ArmorItem *leggings_leather; + static ArmorItem *boots_leather; static ArmorItem *helmet_chain; static ArmorItem *chestplate_chain; @@ -276,7 +288,7 @@ public: static Item *boat; static Item *leather; - static Item *milk; + static Item *bucket_milk; static Item *brick; static Item *clay; static Item *reeds; @@ -300,7 +312,7 @@ public: static Item *bed; - static Item *diode; + static Item *repeater; static Item *cookie; static MapItem *map; @@ -324,7 +336,7 @@ public: static Item *ghastTear; static Item *goldNugget; - static Item *netherStalkSeeds; + static Item *netherwart_seeds; static PotionItem *potion; static Item *glassBottle; @@ -340,7 +352,7 @@ public: static Item *eyeOfEnder; static Item *speckledMelon; - static Item *monsterPlacer; + static Item *spawnEgg; static Item *expBottle; @@ -362,7 +374,6 @@ public: // TU9 static Item *fireball; static Item *frame; - static Item *netherbrick; // TU14 //static Item writingBook; @@ -377,13 +388,29 @@ public: static Item *potatoBaked; static Item *potatoPoisonous; + static EmptyMapItem *emptyMap; + static Item *carrotGolden; static Item *carrotOnAStick; + static Item *netherStar; static Item *pumpkinPie; + + static Item *fireworks; + static Item *fireworksCharge; static Item *netherQuartz; + static Item *comparator; + static Item *netherbrick; static EnchantedBookItem *enchantedBook; + static Item *minecart_tnt; + static Item *minecart_hopper; + + static Item *horseArmorMetal; + static Item *horseArmorGold; + static Item *horseArmorDiamond; + static Item *lead; + static Item *nameTag; static const int shovel_iron_Id = 256; @@ -419,7 +446,7 @@ public: static const int hatchet_gold_Id = 286; static const int string_Id = 287; static const int feather_Id = 288; - static const int sulphur_Id = 289; + static const int gunpowder_Id = 289; static const int hoe_wood_Id = 290; static const int hoe_stone_Id = 291; static const int hoe_iron_Id = 292; @@ -429,10 +456,10 @@ public: static const int wheat_Id = 296; static const int bread_Id = 297; - static const int helmet_cloth_Id = 298; - static const int chestplate_cloth_Id = 299; - static const int leggings_cloth_Id = 300; - static const int boots_cloth_Id = 301; + static const int helmet_leather_Id = 298; + static const int chestplate_leather_Id = 299; + static const int leggings_leather_Id = 300; + static const int boots_leather_Id = 301; static const int helmet_chain_Id = 302; static const int chestplate_chain_Id = 303; @@ -471,7 +498,7 @@ public: static const int snowBall_Id = 332; static const int boat_Id = 333; static const int leather_Id = 334; - static const int milk_Id = 335; + static const int bucket_milk_Id = 335; static const int brick_Id = 336; static const int clay_Id = 337; static const int reeds_Id = 338; @@ -492,7 +519,7 @@ public: static const int sugar_Id = 353; static const int cake_Id = 354; static const int bed_Id = 355; - static const int diode_Id = 356; + static const int repeater_Id = 356; static const int cookie_Id = 357; static const int map_Id = 358; @@ -514,7 +541,7 @@ public: static const int blazeRod_Id = 369; static const int ghastTear_Id = 370; static const int goldNugget_Id = 371; - static const int netherStalkSeeds_Id = 372; + static const int netherwart_seeds_Id = 372; static const int potion_Id = 373; static const int glassBottle_Id = 374; static const int spiderEye_Id = 375; @@ -527,7 +554,7 @@ public: static const int speckledMelon_Id = 382; // 1.1 - static const int monsterPlacer_Id = 383; + static const int spawnEgg_Id = 383; static const int expBottle_Id = 384; @@ -552,7 +579,6 @@ public: // TU9 static const int fireball_Id = 385; static const int itemFrame_Id = 389; - static const int netherbrick_Id = 405; // TU14 //static const int writingBook_Id = 130; @@ -567,14 +593,30 @@ public: static const int potatoBaked_Id = 393; static const int potatoPoisonous_Id = 394; + static const int emptyMap_Id = 395; static const int carrotGolden_Id = 396; static const int carrotOnAStick_Id = 398; + static const int netherStar_Id = 399; static const int pumpkinPie_Id = 400; + static const int fireworks_Id = 401; + static const int fireworksCharge_Id = 402; + static const int enchantedBook_Id = 403; + + static const int comparator_Id = 404; + static const int netherbrick_Id = 405; static const int netherQuartz_Id = 406; + static const int minecart_tnt_Id = 407; + static const int minecart_hopper_Id = 408; + + static const int horseArmorMetal_Id = 417; + static const int horseArmorGold_Id = 418; + static const int horseArmorDiamond_Id = 419; + static const int lead_Id = 420; + static const int nameTag_Id = 421; public: const int id; @@ -610,7 +652,8 @@ protected: public: // 4J Using per-item textures now - Item *setTextureName(const wstring &name); + Item *setIconName(const wstring &name); + wstring getIconName(); Item *setMaxStackSize(int max); Item *setBaseItemTypeAndMaterial(int iType,int iMaterial); int getBaseItemType(); @@ -620,11 +663,9 @@ public: virtual Icon *getIcon(int auxValue); Icon *getIcon(shared_ptr itemInstance); - const bool useOn(shared_ptr itemInstance, Level *level, int x, int y, int z, int face, bool bTestUseOnOnly=false); - virtual bool useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); virtual float getDestroySpeed(shared_ptr itemInstance, Tile *tile); - virtual bool TestUse(Level *level, shared_ptr player); + virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); virtual shared_ptr useTimeDepleted(shared_ptr itemInstance, Level *level, shared_ptr player); virtual int getMaxStackSize(); @@ -651,7 +692,7 @@ public: * @param attacker * @return */ - virtual bool hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker); + virtual bool hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker); /** * Returns true when the item was used to mine more efficiently @@ -664,10 +705,10 @@ public: * @param owner * @return */ - virtual bool mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner); + virtual bool mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner); virtual int getAttackDamage(shared_ptr entity); virtual bool canDestroySpecial(Tile *tile); - virtual bool interactEnemy(shared_ptr itemInstance, shared_ptr mob); + virtual bool interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr mob); Item *handEquipped(); virtual bool isHandEquipped(); virtual bool isMirroredArt(); @@ -700,7 +741,7 @@ protected: public: virtual wstring getPotionBrewingFormula(); virtual bool hasPotionBrewingFormula(); - virtual void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced, vector &unformattedStrings); // 4J Added unformattedStrings + virtual void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced); virtual wstring getHoverName(shared_ptr itemInstance); virtual bool isFoil(shared_ptr itemInstance); virtual const Rarity *getRarity(shared_ptr itemInstance); @@ -713,6 +754,8 @@ public: virtual int getEnchantmentValue(); virtual bool hasMultipleSpriteLayers(); virtual Icon *getLayerIcon(int auxValue, int spriteLayer); + virtual bool mayBePlacedInAdventureMode(); virtual bool isValidRepairItem(shared_ptr source, shared_ptr repairItem); virtual void registerIcons(IconRegister *iconRegister); + virtual attrAttrModMap *getDefaultAttributeModifiers(); }; diff --git a/Minecraft.World/ItemDispenseBehaviors.cpp b/Minecraft.World/ItemDispenseBehaviors.cpp new file mode 100644 index 00000000..f66afe31 --- /dev/null +++ b/Minecraft.World/ItemDispenseBehaviors.cpp @@ -0,0 +1,457 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.entity.projectile.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.world.item.h" +#include "ItemDispenseBehaviors.h" + +/* Arrow */ + +shared_ptr ArrowDispenseBehavior::getProjectile(Level *world, Position *position) +{ + shared_ptr arrow = shared_ptr(new Arrow(world, position->getX(), position->getY(), position->getZ())); + arrow->pickup = Arrow::PICKUP_ALLOWED; + + return arrow; +} + +/* ThrownEgg */ + +shared_ptr EggDispenseBehavior::getProjectile(Level *world, Position *position) +{ + return shared_ptr(new ThrownEgg(world, position->getX(), position->getY(), position->getZ())); +} + + +/* Snowball */ + +shared_ptr SnowballDispenseBehavior::getProjectile(Level *world, Position *position) +{ + return shared_ptr(new Snowball(world, position->getX(), position->getY(), position->getZ())); +} + + +/* Exp Bottle */ + +shared_ptr ExpBottleDispenseBehavior::getProjectile(Level *world, Position *position) +{ + return shared_ptr(new ThrownExpBottle(world, position->getX(), position->getY(), position->getZ())); +} + +float ExpBottleDispenseBehavior::getUncertainty() +{ + return AbstractProjectileDispenseBehavior::getUncertainty() * .5f; +} + +float ExpBottleDispenseBehavior::getPower() +{ + return AbstractProjectileDispenseBehavior::getPower() * 1.25f; +} + + +/* Thrown Potion */ + +ThrownPotionDispenseBehavior::ThrownPotionDispenseBehavior(int potionValue) +{ + m_potionValue = potionValue; +} + +shared_ptr ThrownPotionDispenseBehavior::getProjectile(Level *world, Position *position) +{ + return shared_ptr(new ThrownPotion(world, position->getX(), position->getY(), position->getZ(), m_potionValue)); +} + +float ThrownPotionDispenseBehavior::getUncertainty() +{ + return AbstractProjectileDispenseBehavior::getUncertainty() * .5f; +} + +float ThrownPotionDispenseBehavior::getPower() +{ + return AbstractProjectileDispenseBehavior::getPower() * 1.25f; +} + + +/* Potion */ + +shared_ptr PotionDispenseBehavior::dispense(BlockSource *source, shared_ptr dispensed) +{ + if (PotionItem::isThrowable(dispensed->getAuxValue())) + { + return ThrownPotionDispenseBehavior(dispensed->getAuxValue()).dispense(source, dispensed); + } + else + { + return DefaultDispenseItemBehavior::dispense(source, dispensed); + } +} + + +/* SpawnEggItem */ + +shared_ptr SpawnEggDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + + // Spawn entity in the middle of the block in front of the dispenser + double spawnX = source->getX() + facing->getStepX(); + double spawnY = source->getBlockY() + .2f; // Above pressure plates + double spawnZ = source->getZ() + facing->getStepZ(); + + int iResult = 0; + shared_ptr entity = SpawnEggItem::spawnMobAt(source->getWorld(), dispensed->getAuxValue(), spawnX, spawnY, spawnZ, &iResult); + + // 4J-JEV: Added in-case spawn limit is encountered. + if (entity == NULL) + { + outcome = LEFT_ITEM; + return dispensed; + } + + if (entity->instanceof(eTYPE_MOB) && dispensed->hasCustomHoverName()) + { + dynamic_pointer_cast(entity)->setCustomName(dispensed->getHoverName()); + } + + outcome = ACTIVATED_ITEM; + + dispensed->remove(1); + return dispensed; +} + + +/* Fireworks*/ + +shared_ptr FireworksDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + Level *world = source->getWorld(); + if ( world->countInstanceOf(eTYPE_PROJECTILE,false) >= Level::MAX_DISPENSABLE_PROJECTILES ) + { + outcome = LEFT_ITEM; + return dispensed; + } + + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + + double spawnX = source->getX() + facing->getStepX(); + double spawnY = source->getBlockY() + .2f; + double spawnZ = source->getZ() + facing->getStepZ(); + + shared_ptr firework = shared_ptr(new FireworksRocketEntity(world, spawnX, spawnY, spawnZ, dispensed)); + source->getWorld()->addEntity(firework); + + outcome = ACTIVATED_ITEM; + + dispensed->remove(1); + return dispensed; +} + +void FireworksDispenseBehavior::playSound(BlockSource *source, eOUTCOME outcome) +{ + // 4J-JEV: This is exactly the same as the default at the moment. + //source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + + DefaultDispenseItemBehavior::playSound(source,outcome); +} + + +/* Fireballs */ + +shared_ptr FireballDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + Level *world = source->getWorld(); + if (world->countInstanceOf(eTYPE_SMALL_FIREBALL,true) >= Level::MAX_DISPENSABLE_FIREBALLS) + { + outcome = LEFT_ITEM; + return dispensed; + } + + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + + Position *position = DispenserTile::getDispensePosition(source); + double spawnX = position->getX() + facing->getStepX() * .3f; + double spawnY = position->getY() + facing->getStepX() * .3f; + double spawnZ = position->getZ() + facing->getStepZ() * .3f; + + delete position; + + Random *random = world->random; + + double dirX = random->nextGaussian() * .05 + facing->getStepX(); + double dirY = random->nextGaussian() * .05 + facing->getStepY(); + double dirZ = random->nextGaussian() * .05 + facing->getStepZ(); + + world->addEntity(shared_ptr(new SmallFireball(world, spawnX, spawnY, spawnZ, dirX, dirY, dirZ))); + + outcome = ACTIVATED_ITEM; + + dispensed->remove(1); + return dispensed; +} + +void FireballDispenseBehavior::playSound(BlockSource *source, eOUTCOME outcome) +{ + if (outcome == ACTIVATED_ITEM) + { + source->getWorld()->levelEvent(LevelEvent::SOUND_BLAZE_FIREBALL, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + } + else + { + DefaultDispenseItemBehavior::playSound(source, outcome); + } +} + + +/* Boats */ + +BoatDispenseBehavior::BoatDispenseBehavior() : DefaultDispenseItemBehavior() +{ + defaultDispenseItemBehavior = new DefaultDispenseItemBehavior(); +} + +BoatDispenseBehavior::~BoatDispenseBehavior() +{ + delete defaultDispenseItemBehavior; +} + +shared_ptr BoatDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + Level *world = source->getWorld(); + + // Spawn the boat 'just' outside the dispenser, it overlaps 2 'pixels' now. + double spawnX = source->getX() + facing->getStepX() * (1 + 2.0f / 16); + double spawnY = source->getY() + facing->getStepY() * (1 + 2.0f / 16); + double spawnZ = source->getZ() + facing->getStepZ() * (1 + 2.0f / 16); + + int frontX = source->getBlockX() + facing->getStepX(); + int frontY = source->getBlockY() + facing->getStepY(); + int frontZ = source->getBlockZ() + facing->getStepZ(); + Material *inFront = world->getMaterial(frontX, frontY, frontZ); + + double yOffset; + + // 4J: If we're at limit, just dispense item (instead of adding boat) + if (world->countInstanceOf(eTYPE_BOAT, true) >= Level::MAX_XBOX_BOATS) + { + return defaultDispenseItemBehavior->dispense(source, dispensed); + } + + if (Material::water == inFront) + { + yOffset = 1; + } + else if (Material::air == inFront && Material::water == world->getMaterial(frontX, frontY - 1, frontZ)) + { + yOffset = 0; + } + else + { + return defaultDispenseItemBehavior->dispense(source, dispensed); + } + + outcome = ACTIVATED_ITEM; + + shared_ptr boat = shared_ptr(new Boat(world, spawnX, spawnY + yOffset, spawnZ)); + world->addEntity(boat); + + dispensed->remove(1); + return dispensed; +} + +void BoatDispenseBehavior::playSound(BlockSource *source, eOUTCOME outcome) +{ + // 4J-JEV: This is exactly the same as the default at the moment. + //source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + DefaultDispenseItemBehavior::playSound(source,outcome); +} + + +/* FilledBucket */ + +shared_ptr FilledBucketDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + BucketItem *bucket = (BucketItem *)dispensed->getItem(); + int sourceX = source->getBlockX(); + int sourceY = source->getBlockY(); + int sourceZ = source->getBlockZ(); + + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + if (bucket->emptyBucket(source->getWorld(), sourceX + facing->getStepX(), sourceY + facing->getStepY(), sourceZ + facing->getStepZ())) + { + dispensed->id = Item::bucket_empty->id; + dispensed->count = 1; + + outcome = ACTIVATED_ITEM; + return dispensed; + } + + return DefaultDispenseItemBehavior::dispense(source, dispensed); +} + + +/* EmptyBucket */ + +shared_ptr EmptyBucketDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + Level *world = source->getWorld(); + + int targetX = source->getBlockX() + facing->getStepX(); + int targetY = source->getBlockY() + facing->getStepY(); + int targetZ = source->getBlockZ() + facing->getStepZ(); + + Material *material = world->getMaterial(targetX, targetY, targetZ); + int dataValue = world->getData(targetX, targetY, targetZ); + + Item *targetType; + if (Material::water == material && dataValue == 0) + { + targetType = Item::bucket_water; + } + else if (Material::lava == material && dataValue == 0) + { + targetType = Item::bucket_lava; + } + else + { + return DefaultDispenseItemBehavior::execute(source, dispensed, outcome); + } + + world->removeTile(targetX, targetY, targetZ); + if (--dispensed->count == 0) + { + dispensed->id = targetType->id; + dispensed->count = 1; + } + else if (dynamic_pointer_cast(source->getEntity())->addItem(shared_ptr(new ItemInstance(targetType))) < 0) + { + DefaultDispenseItemBehavior::dispense(source, shared_ptr(new ItemInstance(targetType))); + } + + outcome = ACTIVATED_ITEM; + return dispensed; +} + + +/* Flint and Steel */ + +shared_ptr FlintAndSteelDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + outcome = ACTIVATED_ITEM; + + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + Level *world = source->getWorld(); + + int targetX = source->getBlockX() + facing->getStepX(); + int targetY = source->getBlockY() + facing->getStepY(); + int targetZ = source->getBlockZ() + facing->getStepZ(); + + if (world->isEmptyTile(targetX, targetY, targetZ)) + { + world->setTileAndUpdate(targetX, targetY, targetZ, Tile::fire_Id); + + if (dispensed->hurt(1, world->random)) + { + dispensed->count = 0; + } + } + else if (world->getTile(targetX, targetY, targetZ) == Tile::tnt_Id) + { + Tile::tnt->destroy(world, targetX, targetY, targetZ, 1); + world->removeTile(targetX, targetY, targetZ); + } + else + { + outcome = LEFT_ITEM; + } + + return dispensed; +} + +void FlintAndSteelDispenseBehavior::playSound(BlockSource *source, eOUTCOME outcome) +{ + if (outcome == ACTIVATED_ITEM) + { + source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + } + else + { + source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK_FAIL, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + } +} + + +/* Dye */ + +shared_ptr DyeDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + if (dispensed->getAuxValue() == DyePowderItem::WHITE) + { + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + Level *world = source->getWorld(); + + int targetX = source->getBlockX() + facing->getStepX(); + int targetY = source->getBlockY() + facing->getStepY(); + int targetZ = source->getBlockZ() + facing->getStepZ(); + + if (DyePowderItem::growCrop(dispensed, world, targetX, targetY, targetZ, false)) + { + if (!world->isClientSide) world->levelEvent(LevelEvent::PARTICLES_PLANT_GROWTH, targetX, targetY, targetZ, 0); + outcome = ACTIVATED_ITEM; + } + else + { + outcome = LEFT_ITEM; + } + + + return dispensed; + } + else + { + return DefaultDispenseItemBehavior::execute(source, dispensed, outcome); + } +} + +void DyeDispenseBehavior::playSound(BlockSource *source, eOUTCOME outcome) +{ + if (outcome == ACTIVATED_ITEM) + { + source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + } + else + { + source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK_FAIL, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); + } +} + + +/* TNT */ + +shared_ptr TntDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + Level *world = source->getWorld(); + + if( world->newPrimedTntAllowed() && app.GetGameHostOption(eGameHostOption_TNT) ) + { + int targetX = source->getBlockX() + facing->getStepX(); + int targetY = source->getBlockY() + facing->getStepY(); + int targetZ = source->getBlockZ() + facing->getStepZ(); + + shared_ptr tnt = shared_ptr(new PrimedTnt(world, targetX + 0.5f, targetY + 0.5f, targetZ + 0.5f, nullptr)); + world->addEntity(tnt); + + outcome = ACTIVATED_ITEM; + + dispensed->count--; + } + else + { + outcome = LEFT_ITEM; + } + return dispensed; +} \ No newline at end of file diff --git a/Minecraft.World/ItemDispenseBehaviors.h b/Minecraft.World/ItemDispenseBehaviors.h new file mode 100644 index 00000000..4635c8a4 --- /dev/null +++ b/Minecraft.World/ItemDispenseBehaviors.h @@ -0,0 +1,117 @@ +#pragma once +#include "DefaultDispenseItemBehavior.h" +#include "AbstractProjectileDispenseBehavior.h" + +class ArrowDispenseBehavior : public AbstractProjectileDispenseBehavior +{ +protected: + virtual shared_ptr getProjectile(Level *world, Position *position); +}; + +class EggDispenseBehavior : public AbstractProjectileDispenseBehavior +{ +protected: + virtual shared_ptr getProjectile(Level *world, Position *position); +}; + +class SnowballDispenseBehavior : public AbstractProjectileDispenseBehavior +{ +protected: + virtual shared_ptr getProjectile(Level *world, Position *position); +}; + +class ExpBottleDispenseBehavior : public AbstractProjectileDispenseBehavior +{ +protected: + virtual shared_ptr getProjectile(Level *world, Position *position); + virtual float getUncertainty(); + virtual float getPower(); +}; + +class ThrownPotionDispenseBehavior : public AbstractProjectileDispenseBehavior +{ +private: + int m_potionValue; +public: + ThrownPotionDispenseBehavior(int potionValue); +protected: + virtual shared_ptr getProjectile(Level *world, Position *position); + virtual float getUncertainty(); + virtual float getPower(); +}; + +class PotionDispenseBehavior : public DefaultDispenseItemBehavior +{ +public: + virtual shared_ptr dispense(BlockSource *source, shared_ptr dispensed); +}; + +class SpawnEggDispenseBehavior : public DefaultDispenseItemBehavior +{ +public: + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +}; + +class FireworksDispenseBehavior : public DefaultDispenseItemBehavior +{ +public: + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +protected: + virtual void playSound(BlockSource *source, eOUTCOME outcome); +}; + +class FireballDispenseBehavior : public DefaultDispenseItemBehavior +{ +public: + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +protected: + virtual void playSound(BlockSource *source, eOUTCOME outcome); +}; + +class BoatDispenseBehavior : public DefaultDispenseItemBehavior +{ +public: + BoatDispenseBehavior(); + virtual ~BoatDispenseBehavior(); + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +protected: + virtual void playSound(BlockSource *source, eOUTCOME outcome); +private: + DefaultDispenseItemBehavior *defaultDispenseItemBehavior; +}; + +class FilledBucketDispenseBehavior : public DefaultDispenseItemBehavior +{ +public: + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +}; + +class EmptyBucketDispenseBehavior : public DefaultDispenseItemBehavior +{ +public: + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +}; + +class FlintAndSteelDispenseBehavior : public DefaultDispenseItemBehavior +{ + // bool success; // 4J-JEV: Removed because we have something cleaner for this now. +public: + shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +protected: + virtual void playSound(BlockSource *source, eOUTCOME outcome); +}; + +class DyeDispenseBehavior : public DefaultDispenseItemBehavior +{ + // bool success; // 4J-JEV: Removed because we have something cleaner for this now. +public: + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +protected: + virtual void playSound(BlockSource *source, eOUTCOME outcome); +}; + +class TntDispenseBehavior : public DefaultDispenseItemBehavior +{ +protected: + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); +}; \ No newline at end of file diff --git a/Minecraft.World/ItemEntity.cpp b/Minecraft.World/ItemEntity.cpp index eb7684a6..e6bdffa5 100644 --- a/Minecraft.World/ItemEntity.cpp +++ b/Minecraft.World/ItemEntity.cpp @@ -94,7 +94,7 @@ void ItemEntity::tick() xd = (random->nextFloat() - random->nextFloat()) * 0.2f; zd = (random->nextFloat() - random->nextFloat()) * 0.2f; MemSect(31); - level->playSound(shared_from_this(), eSoundType_RANDOM_FIZZ, 0.4f, 2.0f + random->nextFloat() * 0.4f); + playSound(eSoundType_RANDOM_FIZZ, 0.4f, 2.0f + random->nextFloat() * 0.4f); MemSect(0); } @@ -184,13 +184,15 @@ void ItemEntity::burn(int dmg) } -bool ItemEntity::hurt(DamageSource *source, int damage) +bool ItemEntity::hurt(DamageSource *source, float damage) { // 4J - added next line: found whilst debugging an issue with item entities getting into a bad state when being created by a cactus, since entities insides cactuses get hurt // and therefore depending on the timing of things they could get removed from the client when they weren't supposed to be. Are there really any cases were we would want // an itemEntity to be locally hurt? - if (level->isClientSide ) return false; + if (level->isClientSide ) return false; + if (isInvulnerable()) return false; + if (getItem() != NULL && getItem()->id == Item::netherStar_Id && source->isExplosion()) return false; markHurt(); health -= damage; if (health <= 0) @@ -254,7 +256,7 @@ void ItemEntity::playerTouch(shared_ptr player) if (item->id == Item::blazeRod_Id) player->awardStat(GenericStats::blazeRod(), GenericStats::param_blazeRod()); - level->playSound(shared_from_this(), eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f); + playSound(eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f); player->take(shared_from_this(), orgCount); // System.out.println(item.count + ", " + orgCount); if (item->count <= 0) remove(); @@ -267,6 +269,13 @@ wstring ItemEntity::getAName() //return I18n.get("item." + item.getDescriptionId()); } +void ItemEntity::changeDimension(int i) +{ + Entity::changeDimension(i); + + if (!level->isClientSide) mergeWithNeighbours(); +} + shared_ptr ItemEntity::getItem() { shared_ptr result = getEntityData()->getItemInstance(DATA_ITEM); @@ -278,7 +287,7 @@ shared_ptr ItemEntity::getItem() app.DebugPrintf("Item entity %d has no item?!\n", entityId); //level.getLogger().severe("Item entity " + entityId + " has no item?!"); } - return shared_ptr(new ItemInstance(Tile::rock)); + return shared_ptr(new ItemInstance(Tile::stone)); } return result; diff --git a/Minecraft.World/ItemEntity.h b/Minecraft.World/ItemEntity.h index 1f42bc21..3b442b90 100644 --- a/Minecraft.World/ItemEntity.h +++ b/Minecraft.World/ItemEntity.h @@ -58,13 +58,13 @@ protected: virtual void burn(int dmg); public: - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); virtual void addAdditonalSaveData(CompoundTag *entityTag); virtual void readAdditionalSaveData(CompoundTag *tag); virtual void playerTouch(shared_ptr player); virtual wstring getAName(); - + virtual void changeDimension(int i); shared_ptr getItem(); void setItem(shared_ptr item); virtual bool isAttackable(); diff --git a/Minecraft.World/ItemFrame.cpp b/Minecraft.World/ItemFrame.cpp index 141f0630..0d52b421 100644 --- a/Minecraft.World/ItemFrame.cpp +++ b/Minecraft.World/ItemFrame.cpp @@ -20,6 +20,8 @@ void ItemFrame::_init() // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + + dropChance = 1; } ItemFrame::ItemFrame(Level *level) : HangingEntity( level ) @@ -39,19 +41,45 @@ void ItemFrame::defineSynchedData() getEntityData()->define(DATA_ROTATION, (byte) 0); } -void ItemFrame::dropItem() +bool ItemFrame::shouldRenderAtSqrDistance(double distance) +{ + double size = 16; + size *= 64.0f * viewScale; + return distance < size * size; +} + +void ItemFrame::dropItem(shared_ptr causedBy) { - spawnAtLocation(shared_ptr(new ItemInstance(Item::frame)), 0.0f); shared_ptr item = getItem(); - if (item != NULL) + + if (causedBy != NULL && causedBy->instanceof(eTYPE_PLAYER)) { - shared_ptr data = Item::map->getSavedData(item, level); - data->removeItemFrameDecoration(item); + if (dynamic_pointer_cast(causedBy)->abilities.instabuild) + { + removeFramedMap(item); + return; + } + } - shared_ptr itemToDrop = item->copy(); - itemToDrop->setFramed(nullptr); - spawnAtLocation(itemToDrop, 0.0f); + spawnAtLocation( shared_ptr(new ItemInstance(Item::frame) ), 0); + if ( (item != NULL) && (random->nextFloat() < dropChance) ) + { + item = item->copy(); + removeFramedMap(item); + spawnAtLocation(item, 0); + } +} + +void ItemFrame::removeFramedMap(shared_ptr item) +{ + if (item == NULL) return; + if (item->id == Item::map_Id) + { + shared_ptr mapItemSavedData = Item::map->getSavedData(item, level); + mapItemSavedData->removeItemFrameDecoration(item); + //mapItemSavedData.decorations.remove("frame-" + entityId); } + item->setFramed(nullptr); } shared_ptr ItemFrame::getItem() @@ -88,7 +116,7 @@ void ItemFrame::addAdditonalSaveData(CompoundTag *tag) { tag->putCompound(L"Item", getItem()->save(new CompoundTag())); tag->putByte(L"ItemRotation", (byte) getRotation()); - //tag->putFloat(L"ItemDropChance", dropChance); + tag->putFloat(L"ItemDropChance", dropChance); } HangingEntity::addAdditonalSaveData(tag); } @@ -101,7 +129,7 @@ void ItemFrame::readAdditionalSaveData(CompoundTag *tag) setItem(ItemInstance::fromTag(itemTag)); setRotation(tag->getByte(L"ItemRotation")); - //if (tag->contains(L"ItemDropChance")) dropChance = tag->getFloat(L"ItemDropChance"); + if (tag->contains(L"ItemDropChance")) dropChance = tag->getFloat(L"ItemDropChance"); } HangingEntity::readAdditionalSaveData(tag); } @@ -125,10 +153,10 @@ bool ItemFrame::interact(shared_ptr player) if (!player->abilities.instabuild) { - if (--item->count <= 0) - { - player->inventory->setItem(player->inventory->selected, nullptr); - } + if (--item->count <= 0) + { + player->inventory->setItem(player->inventory->selected, nullptr); + } } } } diff --git a/Minecraft.World/ItemFrame.h b/Minecraft.World/ItemFrame.h index 1af5c2e9..06c1f111 100644 --- a/Minecraft.World/ItemFrame.h +++ b/Minecraft.World/ItemFrame.h @@ -14,6 +14,8 @@ private: static const int DATA_ITEM = 2; static const int DATA_ROTATION = 3; + float dropChance; + private: void _init(); @@ -24,12 +26,17 @@ public: protected: virtual void defineSynchedData(); + +public: virtual int getWidth() {return 9;} virtual int getHeight() {return 9;} - virtual void dropItem(); + virtual bool shouldRenderAtSqrDistance(double distance); + virtual void dropItem(shared_ptr causedBy); -public: +private: + void removeFramedMap(shared_ptr item); +public: shared_ptr getItem(); void setItem(shared_ptr item); int getRotation(); diff --git a/Minecraft.World/ItemInstance.cpp b/Minecraft.World/ItemInstance.cpp index ab042af0..c83b67dd 100644 --- a/Minecraft.World/ItemInstance.cpp +++ b/Minecraft.World/ItemInstance.cpp @@ -3,6 +3,8 @@ #include "net.minecraft.locale.h" #include "net.minecraft.stats.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" @@ -10,8 +12,9 @@ #include "net.minecraft.world.item.enchantment.h" #include "Item.h" #include "ItemInstance.h" +#include "HtmlString.h" - +const wstring ItemInstance::ATTRIBUTE_MODIFIER_FORMAT = L"#.###"; const wchar_t *ItemInstance::TAG_ENCH_ID = L"id"; const wchar_t *ItemInstance::TAG_ENCH_LEVEL = L"lvl"; @@ -45,29 +48,33 @@ ItemInstance::ItemInstance(MapItem *item, int count) ItemInstance::ItemInstance(Tile *tile, int count, int auxValue) { - _init(tile->id, count, auxValue); + _init(tile->id, count, auxValue); } ItemInstance::ItemInstance(Item *item) { - _init(item->id, 1, 0); + _init(item->id, 1, 0); } ItemInstance::ItemInstance(Item *item, int count) { - _init(item->id, count, 0); + _init(item->id, count, 0); } ItemInstance::ItemInstance(Item *item, int count, int auxValue) { - _init(item->id, count, auxValue); + _init(item->id, count, auxValue); } ItemInstance::ItemInstance(int id, int count, int damage) { - _init(id,count,damage); + _init(id,count,damage); + if (auxValue < 0) + { + auxValue = 0; + } } shared_ptr ItemInstance::fromTag(CompoundTag *itemTag) @@ -98,12 +105,12 @@ shared_ptr ItemInstance::remove(int count) Item *ItemInstance::getItem() const { - return Item::items[id]; + return Item::items[id]; } Icon *ItemInstance::getIcon() { - return getItem()->getIcon(shared_from_this()); + return getItem()->getIcon(shared_from_this()); } int ItemInstance::getIconType() @@ -118,17 +125,17 @@ bool ItemInstance::useOn(shared_ptr player, Level *level, int x, int y, float ItemInstance::getDestroySpeed(Tile *tile) { - return getItem()->getDestroySpeed(shared_from_this(), tile); + return getItem()->getDestroySpeed(shared_from_this(), tile); } -bool ItemInstance::TestUse(Level *level, shared_ptr player) +bool ItemInstance::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { - return getItem()->TestUse( level, player); + return getItem()->TestUse( itemInstance, level, player); } shared_ptr ItemInstance::use(Level *level, shared_ptr player) { - return getItem()->use(shared_from_this(), level, player); + return getItem()->use(shared_from_this(), level, player); } shared_ptr ItemInstance::useTimeDepleted(Level *level, shared_ptr player) @@ -138,135 +145,159 @@ shared_ptr ItemInstance::useTimeDepleted(Level *level, shared_ptr< CompoundTag *ItemInstance::save(CompoundTag *compoundTag) { - compoundTag->putShort(L"id", (short) id); - compoundTag->putByte(L"Count", (byte) count); - compoundTag->putShort(L"Damage", (short) auxValue); - if (this->tag != NULL) compoundTag->put(L"tag", tag->copy()); - return compoundTag; + compoundTag->putShort(L"id", (short) id); + compoundTag->putByte(L"Count", (byte) count); + compoundTag->putShort(L"Damage", (short) auxValue); + if (tag != NULL) compoundTag->put(L"tag", tag->copy()); + return compoundTag; } void ItemInstance::load(CompoundTag *compoundTag) { popTime = 0; - id = compoundTag->getShort(L"id"); - count = compoundTag->getByte(L"Count"); - auxValue = compoundTag->getShort(L"Damage"); + id = compoundTag->getShort(L"id"); + count = compoundTag->getByte(L"Count"); + auxValue = compoundTag->getShort(L"Damage"); + if (auxValue < 0) + { + auxValue = 0; + } if (compoundTag->contains(L"tag")) { + delete tag; tag = (CompoundTag *)compoundTag->getCompound(L"tag")->copy(); } } int ItemInstance::getMaxStackSize() { - return getItem()->getMaxStackSize(); + return getItem()->getMaxStackSize(); } bool ItemInstance::isStackable() { - return getMaxStackSize() > 1 && (!isDamageableItem() || !isDamaged()); + return getMaxStackSize() > 1 && (!isDamageableItem() || !isDamaged()); } bool ItemInstance::isDamageableItem() { - return Item::items[id]->getMaxDamage() > 0; + return Item::items[id]->getMaxDamage() > 0; } /** - * Returns true if this item type only can be stacked with items that have - * the same auxValue data. - * - * @return - */ +* Returns true if this item type only can be stacked with items that have +* the same auxValue data. +* +* @return +*/ bool ItemInstance::isStackedByData() { - return Item::items[id]->isStackedByData(); + return Item::items[id]->isStackedByData(); } bool ItemInstance::isDamaged() { - return isDamageableItem() && auxValue > 0; + return isDamageableItem() && auxValue > 0; } int ItemInstance::getDamageValue() { - return auxValue; + return auxValue; } int ItemInstance::getAuxValue() const { - return auxValue; + return auxValue; } void ItemInstance::setAuxValue(int value) { - auxValue = value; + auxValue = value; + if (auxValue < 0) + { + auxValue = 0; + } } int ItemInstance::getMaxDamage() { - return Item::items[id]->getMaxDamage(); + return Item::items[id]->getMaxDamage(); } -void ItemInstance::hurt(int i, shared_ptr owner) +bool ItemInstance::hurt(int dmg, Random *random) { - if (!isDamageableItem()) + if (!isDamageableItem()) { - return; - } + return false; + } - shared_ptr player = dynamic_pointer_cast(owner); - if (i > 0 && player != NULL) + if (dmg > 0) { - int enchanted = EnchantmentHelper::getDigDurability(player->inventory); - // Fix for #65233 - TU8: Content: Gameplay: Tools Enchanted with "Unbreaking" occasionally repair themselves. - // 4J Stu - If it's the clientside level, then always assume that no damage is done. This stops the case where the client random - // results in damage, but the server random does not - if (enchanted > 0 && (owner->level->isClientSide || owner->level->random->nextInt(enchanted + 1) > 0) ) + int level = EnchantmentHelper::getEnchantmentLevel(Enchantment::digDurability->id, shared_from_this()); + + int drop = 0; + for (int y = 0; level > 0 && y < dmg; y++) { - // enchantment prevents damage - return; + if (DigDurabilityEnchantment::shouldIgnoreDurabilityDrop(shared_from_this(), level, random)) + { + drop++; + } } + dmg -= drop; + + if (dmg <= 0) return false; } - // 4J Stu - Changed in TU6 to not damage items in creative mode - if (!(owner != NULL && player->abilities.instabuild)) auxValue += i; - - if (auxValue > getMaxDamage()) - { - owner->breakItem(shared_from_this()); - count--; - if (count < 0) count = 0; - auxValue = 0; - } + auxValue += dmg; + + return auxValue > getMaxDamage(); } -void ItemInstance::hurtEnemy(shared_ptr mob, shared_ptr attacker) +void ItemInstance::hurtAndBreak(int dmg, shared_ptr owner) { - //bool used = - Item::items[id]->hurtEnemy(shared_from_this(), mob, attacker); + shared_ptr player = dynamic_pointer_cast(owner); + if (player != NULL && player->abilities.instabuild) return; + if (!isDamageableItem()) return; + + if (hurt(dmg, owner->getRandom())) + { + owner->breakItem(shared_from_this()); + + count--; + if (player != NULL) + { + //player->awardStat(Stats::itemBroke[id], 1); + if (count == 0 && dynamic_cast( getItem() ) != NULL) + { + player->removeSelectedItem(); + } + } + if (count < 0) count = 0; + auxValue = 0; + } } -void ItemInstance::mineBlock(Level *level, int tile, int x, int y, int z, shared_ptr owner) +void ItemInstance::hurtEnemy(shared_ptr mob, shared_ptr attacker) { - //bool used = - Item::items[id]->mineBlock( shared_from_this(), level, tile, x, y, z, owner); + //bool used = + Item::items[id]->hurtEnemy(shared_from_this(), mob, attacker); } -int ItemInstance::getAttackDamage(shared_ptr entity) +void ItemInstance::mineBlock(Level *level, int tile, int x, int y, int z, shared_ptr owner) { - return Item::items[id]->getAttackDamage(entity); + //bool used = + Item::items[id]->mineBlock( shared_from_this(), level, tile, x, y, z, owner); } bool ItemInstance::canDestroySpecial(Tile *tile) { - return Item::items[id]->canDestroySpecial(tile); + return Item::items[id]->canDestroySpecial(tile); } -bool ItemInstance::interactEnemy(shared_ptr mob) +bool ItemInstance::interactEnemy(shared_ptr player, shared_ptr mob) { - return Item::items[id]->interactEnemy(shared_from_this(), mob); + return Item::items[id]->interactEnemy(shared_from_this(), player, mob); } shared_ptr ItemInstance::copy() const @@ -313,16 +344,16 @@ bool ItemInstance::tagMatches(shared_ptr a, shared_ptr a, shared_ptr b) { - if (a == NULL && b == NULL) return true; - if (a == NULL || b == NULL) return false; - return a->matches(b); + if (a == NULL && b == NULL) return true; + if (a == NULL || b == NULL) return false; + return a->matches(b); } bool ItemInstance::matches(shared_ptr b) { - if (count != b->count) return false; - if (id != b->id) return false; - if (auxValue != b->auxValue) return false; + if (count != b->count) return false; + if (id != b->id) return false; + if (auxValue != b->auxValue) return false; if (tag == NULL && b->tag != NULL) { return false; @@ -331,25 +362,25 @@ bool ItemInstance::matches(shared_ptr b) { return false; } - return true; + return true; } /** - * Checks if this item is the same item as the other one, disregarding the - * 'count' value. - * - * @param b - * @return - */ +* Checks if this item is the same item as the other one, disregarding the +* 'count' value. +* +* @param b +* @return +*/ bool ItemInstance::sameItem(shared_ptr b) { - return id == b->id && auxValue == b->auxValue; + return id == b->id && auxValue == b->auxValue; } bool ItemInstance::sameItemWithTags(shared_ptr b) { - if (id != b->id) return false; - if (auxValue != b->auxValue) return false; + if (id != b->id) return false; + if (auxValue != b->auxValue) return false; if (tag == NULL && b->tag != NULL) { return false; @@ -358,41 +389,41 @@ bool ItemInstance::sameItemWithTags(shared_ptr b) { return false; } - return true; + return true; } // 4J Stu - Added this for the one time when we compare with a non-shared pointer bool ItemInstance::sameItem_not_shared(ItemInstance *b) { - return id == b->id && auxValue == b->auxValue; + return id == b->id && auxValue == b->auxValue; } unsigned int ItemInstance::getUseDescriptionId() { - return Item::items[id]->getUseDescriptionId(shared_from_this()); + return Item::items[id]->getUseDescriptionId(shared_from_this()); } unsigned int ItemInstance::getDescriptionId(int iData /*= -1*/) { - return Item::items[id]->getDescriptionId(shared_from_this()); + return Item::items[id]->getDescriptionId(shared_from_this()); } ItemInstance *ItemInstance::setDescriptionId(unsigned int id) { // 4J Stu - I don't think this function is ever used. It if is, it should probably return shared_from_this() assert(false); - return this; + return this; } shared_ptr ItemInstance::clone(shared_ptr item) { - return item == NULL ? nullptr : item->copy(); + return item == NULL ? nullptr : item->copy(); } wstring ItemInstance::toString() { - //return count + "x" + Item::items[id]->getDescriptionId() + "@" + auxValue; - + //return count + "x" + Item::items[id]->getDescriptionId() + "@" + auxValue; + std::wostringstream oss; // 4J-PB - TODO - temp fix until ore recipe issue is fixed if(Item::items[id]==NULL) @@ -408,8 +439,8 @@ wstring ItemInstance::toString() void ItemInstance::inventoryTick(Level *level, shared_ptr owner, int slot, bool selected) { - if (popTime > 0) popTime--; - Item::items[id]->inventoryTick(shared_from_this(), level, owner, slot, selected); + if (popTime > 0) popTime--; + Item::items[id]->inventoryTick(shared_from_this(), level, owner, slot, selected); } void ItemInstance::onCraftedBy(Level *level, shared_ptr player, int craftCount) @@ -422,12 +453,12 @@ void ItemInstance::onCraftedBy(Level *level, shared_ptr player, int craf GenericStats::param_itemsCrafted(id, auxValue, craftCount) ); - Item::items[id]->onCraftedBy(shared_from_this(), level, player); + Item::items[id]->onCraftedBy(shared_from_this(), level, player); } bool ItemInstance::equals(shared_ptr ii) { - return id == ii->id && count == ii->count && auxValue == ii->auxValue; + return id == ii->id && count == ii->count && auxValue == ii->auxValue; } int ItemInstance::getUseDuration() @@ -467,6 +498,7 @@ ListTag *ItemInstance::getEnchantmentTags() void ItemInstance::setTag(CompoundTag *tag) { + delete this->tag; this->tag = tag; } @@ -494,6 +526,24 @@ void ItemInstance::setHoverName(const wstring &name) tag->getCompound(L"display")->putString(L"Name", name); } +void ItemInstance::resetHoverName() +{ + if (tag == NULL) return; + if (!tag->contains(L"display")) return; + CompoundTag *display = tag->getCompound(L"display"); + display->remove(L"Name"); + + if (display->isEmpty()) + { + tag->remove(L"display"); + + if (tag->isEmpty()) + { + setTag(NULL); + } + } +} + bool ItemInstance::hasCustomHoverName() { if (tag == NULL) return false; @@ -501,49 +551,49 @@ bool ItemInstance::hasCustomHoverName() return tag->getCompound(L"display")->contains(L"Name"); } -vector *ItemInstance::getHoverText(shared_ptr player, bool advanced, vector &unformattedStrings) +vector *ItemInstance::getHoverText(shared_ptr player, bool advanced) { - vector *lines = new vector(); + vector *lines = new vector(); Item *item = Item::items[id]; - wstring title = getHoverName(); - - // 4J Stu - We don't do italics, but do change colour. But handle this later in the process due to text length measuring on the Xbox360 - //if (hasCustomHoverName()) - //{ - // title = L"" + title + L""; - //} - - // 4J Stu - Don't currently have this - //if (advanced) - //{ - // String suffix = ""; - - // if (title.length() > 0) { - // title += " ("; - // suffix = ")"; - // } - - // if (isStackedByData()) - // { - // title += String.format("#%04d/%d%s", id, auxValue, suffix); - // } - // else - // { - // title += String.format("#%04d%s", id, suffix); - // } - //} - //else - // if (!hasCustomHoverName()) - //{ - // if (id == Item::map_Id) - // { - // title += L" #" + _toString(auxValue); - // } - //} + HtmlString title = HtmlString(getHoverName()); + + if (hasCustomHoverName()) + { + title.italics = true; + } + + // 4J: This is for showing aux values, not useful in console version + /* + if (advanced) + { + wstring suffix = L""; + + if (title.length() > 0) + { + title += L" ("; + suffix = L")"; + } + + if (isStackedByData()) + { + title += String.format("#%04d/%d%s", id, auxValue, suffix); + } + else + { + title += String.format("#%04d%s", id, suffix); + } + } + else if (!hasCustomHoverName() && id == Item::map_Id) + */ + + /*if (!hasCustomHoverName() && id == Item::map_Id) + { + title.text += L" #" + _toString(auxValue); + }*/ lines->push_back(title); - unformattedStrings.push_back(title); - item->appendHoverText(shared_from_this(), player, lines, advanced, unformattedStrings); + + item->appendHoverText(shared_from_this(), player, lines, advanced); if (hasTag()) { @@ -558,22 +608,87 @@ vector *ItemInstance::getHoverText(shared_ptr player, bool adva if (Enchantment::enchantments[type] != NULL) { wstring unformatted = L""; - lines->push_back(Enchantment::enchantments[type]->getFullname(level, unformatted)); - unformattedStrings.push_back(unformatted); + lines->push_back(Enchantment::enchantments[type]->getFullname(level)); } } } + + if (tag->contains(L"display")) + { + //CompoundTag *display = tag->getCompound(L"display"); + + //if (display->contains(L"color")) + //{ + // if (advanced) + // { + // wchar_t text [256]; + // swprintf(text, 256, L"Color: LOCALISE #%08X", display->getInt(L"color")); + // lines->push_back(HtmlString(text)); + // } + // else + // { + // lines->push_back(HtmlString(L"Dyed LOCALISE", eMinecraftColour_NOT_SET, true)); + // } + //} + + // 4J: Lore isn't in use in game + /*if (display->contains(L"Lore")) + { + ListTag *lore = (ListTag *) display->getList(L"Lore"); + if (lore->size() > 0) + { + for (int i = 0; i < lore->size(); i++) + { + //lines->push_back(ChatFormatting::DARK_PURPLE + "" + ChatFormatting::ITALIC + lore->get(i)->data); + lines->push_back(lore->get(i)->data); + } + } + }*/ + } } + + attrAttrModMap *modifiers = getAttributeModifiers(); + + if (!modifiers->empty()) + { + // New line + lines->push_back(HtmlString(L"")); + + // Modifier descriptions + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) + { + // 4J: Moved modifier string building to AttributeModifier + lines->push_back(it->second->getHoverText(it->first)); + } + } + + // Delete modifiers map + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) + { + AttributeModifier *modifier = it->second; + delete modifier; + } + delete modifiers; + + if (advanced) + { + if (isDamaged()) + { + wstring damageStr = L"Durability: LOCALISE " + _toString((getMaxDamage()) - getDamageValue()) + L" / " + _toString(getMaxDamage()); + lines->push_back(HtmlString(damageStr)); + } + } + return lines; } // 4J Added -vector *ItemInstance::getHoverTextOnly(shared_ptr player, bool advanced, vector &unformattedStrings) +vector *ItemInstance::getHoverTextOnly(shared_ptr player, bool advanced) { - vector *lines = new vector(); + vector *lines = new vector(); Item *item = Item::items[id]; - item->appendHoverText(shared_from_this(), player, lines, advanced, unformattedStrings); + item->appendHoverText(shared_from_this(), player, lines, advanced); if (hasTag()) { @@ -588,8 +703,7 @@ vector *ItemInstance::getHoverTextOnly(shared_ptr player, bool if (Enchantment::enchantments[type] != NULL) { wstring unformatted = L""; - lines->push_back(Enchantment::enchantments[type]->getFullname(level,unformatted)); - unformattedStrings.push_back(unformatted); + lines->push_back(Enchantment::enchantments[type]->getFullname(level)); } } } @@ -636,11 +750,78 @@ void ItemInstance::addTagElement(wstring name, Tag *tag) { if (this->tag == NULL) { - this->setTag(new CompoundTag()); + setTag(new CompoundTag()); } this->tag->put((wchar_t *)name.c_str(), tag); } +bool ItemInstance::mayBePlacedInAdventureMode() +{ + return getItem()->mayBePlacedInAdventureMode(); +} + +bool ItemInstance::isFramed() +{ + return frame != NULL; +} + +void ItemInstance::setFramed(shared_ptr frame) +{ + this->frame = frame; +} + +shared_ptr ItemInstance::getFrame() +{ + return frame; +} + +int ItemInstance::getBaseRepairCost() +{ + if (hasTag() && tag->contains(L"RepairCost")) + { + return tag->getInt(L"RepairCost"); + } + else + { + return 0; + } +} + +void ItemInstance::setRepairCost(int cost) +{ + if (!hasTag()) tag = new CompoundTag(); + tag->putInt(L"RepairCost", cost); +} + +attrAttrModMap *ItemInstance::getAttributeModifiers() +{ + attrAttrModMap *result = NULL; + + if (hasTag() && tag->contains(L"AttributeModifiers")) + { + result = new attrAttrModMap(); + ListTag *entries = (ListTag *) tag->getList(L"AttributeModifiers"); + + for (int i = 0; i < entries->size(); i++) + { + CompoundTag *entry = entries->get(i); + AttributeModifier *attribute = SharedMonsterAttributes::loadAttributeModifier(entry); + + // 4J Not sure why but this is a check that the attribute ID is not empty + /*if (attribute->getId()->getLeastSignificantBits() != 0 && attribute->getId()->getMostSignificantBits() != 0) + {*/ + result->insert(std::pair(static_cast(entry->getInt(L"ID")), attribute)); + /*}*/ + } + } + else + { + result = getItem()->getDefaultAttributeModifiers(); + } + + return result; +} + void ItemInstance::set4JData(int data) { if(tag == NULL && data == 0) return; @@ -689,39 +870,4 @@ int ItemInstance::GetPotionStrength() { return (auxValue&MASK_LEVEL2EXTENDED)>>5; } -} - -// TU9 - -bool ItemInstance::isFramed() -{ - return frame != NULL; -} - -void ItemInstance::setFramed(shared_ptr frame) -{ - this->frame = frame; -} - -shared_ptr ItemInstance::getFrame() -{ - return frame; -} - -int ItemInstance::getBaseRepairCost() -{ - if (hasTag() && tag->contains(L"RepairCost")) - { - return tag->getInt(L"RepairCost"); - } - else - { - return 0; - } -} - -void ItemInstance::setRepairCost(int cost) -{ - if (!hasTag()) tag = new CompoundTag(); - tag->putInt(L"RepairCost", cost); -} +} \ No newline at end of file diff --git a/Minecraft.World/ItemInstance.h b/Minecraft.World/ItemInstance.h index c1e52177..034c72f8 100644 --- a/Minecraft.World/ItemInstance.h +++ b/Minecraft.World/ItemInstance.h @@ -3,39 +3,45 @@ using namespace std; #include "UseAnim.h" #include "com.mojang.nbt.h" +#include "Attribute.h" class Entity; class Level; class Player; class Mob; +class LivingEntity; class CompoundTag; class Enchantment; class Rarity; +class AttributeModifier; +class Random; // 4J-PB - added class MapItem; class ItemFrame; class Icon; +class HtmlString; // 4J Stu - While this is not really an abstract class, we don't want to make new instances of it, // mainly because there are too many ctors and that doesn't fit well into out macroisation setup class ItemInstance: public enable_shared_from_this { public: + static const wstring ATTRIBUTE_MODIFIER_FORMAT; static const wchar_t *TAG_ENCH_ID; - static const wchar_t *TAG_ENCH_LEVEL; + static const wchar_t *TAG_ENCH_LEVEL; int count; - int popTime; - int id; + int popTime; + int id; // 4J Stu - Brought forward for enchanting/game rules CompoundTag *tag; - /** - * This was previously the damage value, but is now used for different stuff - * depending on item / tile. Use the getter methods to make sure the value - * is interpreted correctly. - */ + /** + * This was previously the damage value, but is now used for different stuff + * depending on item / tile. Use the getter methods to make sure the value + * is interpreted correctly. + */ private: int auxValue; // 4J-PB - added for trading menu @@ -71,7 +77,7 @@ public: int getIconType(); bool useOn(shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); float getDestroySpeed(Tile *tile); - bool TestUse(Level *level, shared_ptr player); + bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); shared_ptr use(Level *level, shared_ptr player); shared_ptr useTimeDepleted(Level *level, shared_ptr player); CompoundTag *save(CompoundTag *compoundTag); @@ -85,12 +91,12 @@ public: int getAuxValue() const; void setAuxValue(int value); int getMaxDamage(); - void hurt(int i, shared_ptr owner); - void hurtEnemy(shared_ptr mob, shared_ptr attacker); + bool hurt(int dmg, Random *random); + void hurtAndBreak(int dmg, shared_ptr owner); + void hurtEnemy(shared_ptr mob, shared_ptr attacker); void mineBlock(Level *level, int tile, int x, int y, int z, shared_ptr owner); - int getAttackDamage(shared_ptr entity); bool canDestroySpecial(Tile *tile); - bool interactEnemy(shared_ptr mob); + bool interactEnemy(shared_ptr player, shared_ptr mob); shared_ptr copy() const; ItemInstance *copy_not_shared() const; // 4J Stu - Added for use in recipes static bool tagMatches(shared_ptr a, shared_ptr b); // 4J Brought forward from 1.2 @@ -128,27 +134,27 @@ public: void setTag(CompoundTag *tag); wstring getHoverName(); void setHoverName(const wstring &name); + void resetHoverName(); bool hasCustomHoverName(); - vector *getHoverText(shared_ptr player, bool advanced, vector &unformattedStrings); - vector *getHoverTextOnly(shared_ptr player, bool advanced, vector &unformattedStrings); // 4J Added + vector *getHoverText(shared_ptr player, bool advanced); + vector *getHoverTextOnly(shared_ptr player, bool advanced); // 4J Added bool isFoil(); const Rarity *getRarity(); bool isEnchantable(); void enchant(const Enchantment *enchantment, int level); bool isEnchanted(); void addTagElement(wstring name, Tag *tag); + bool mayBePlacedInAdventureMode(); + bool isFramed(); + void setFramed(shared_ptr frame); + shared_ptr getFrame(); + int getBaseRepairCost(); + void setRepairCost(int cost); + attrAttrModMap *getAttributeModifiers(); // 4J Added void set4JData(int data); int get4JData(); bool hasPotionStrengthBar(); int GetPotionStrength(); - - // TU9 - bool isFramed(); - void setFramed(shared_ptr frame); - shared_ptr getFrame(); - - int getBaseRepairCost(); - void setRepairCost(int cost); }; \ No newline at end of file diff --git a/Minecraft.World/JukeboxTile.cpp b/Minecraft.World/JukeboxTile.cpp new file mode 100644 index 00000000..cf53a751 --- /dev/null +++ b/Minecraft.World/JukeboxTile.cpp @@ -0,0 +1,167 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.redstone.h" +#include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.h" +#include "net.minecraft.world.h" +#include "JukeboxTile.h" +#include "LevelEvent.h" + +JukeboxTile::Entity::Entity() : TileEntity() +{ + record = nullptr; +} + +void JukeboxTile::Entity::load(CompoundTag *tag) +{ + TileEntity::load(tag); + + if (tag->contains(L"RecordItem")) + { + setRecord(ItemInstance::fromTag(tag->getCompound(L"RecordItem"))); + } + else if (tag->getInt(L"Record") > 0) + { + setRecord(shared_ptr( new ItemInstance(tag->getInt(L"Record"), 1, 0))); + } +} + +void JukeboxTile::Entity::save(CompoundTag *tag) +{ + TileEntity::save(tag); + + if (getRecord() != NULL) + { + tag->putCompound(L"RecordItem", getRecord()->save(new CompoundTag())); + + tag->putInt(L"Record", getRecord()->id); + } +} + +// 4J Added +shared_ptr JukeboxTile::Entity::clone() +{ + shared_ptr result = shared_ptr( new JukeboxTile::Entity() ); + TileEntity::clone(result); + + result->record = record; + + return result; +} + +shared_ptr JukeboxTile::Entity::getRecord() +{ + return record; +} + +void JukeboxTile::Entity::setRecord(shared_ptr record) +{ + this->record = record; + setChanged(); +} + +JukeboxTile::JukeboxTile(int id) : BaseEntityTile(id, Material::wood) +{ + iconTop = NULL; +} + +Icon *JukeboxTile::getTexture(int face, int data) +{ + if (face == Facing::UP) + { + return iconTop; + } + return icon; +} + +// 4J-PB - Adding a TestUse for tooltip display +bool JukeboxTile::TestUse(Level *level, int x, int y, int z, shared_ptr player) +{ + // if the jukebox is empty, return true + if (level->getData(x, y, z) == 0) return false; + return true; +} + +bool JukeboxTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param +{ + if (soundOnly) return false; + if (level->getData(x, y, z) == 0) return false; + dropRecording(level, x, y, z); + return true; +} + +void JukeboxTile::setRecord(Level *level, int x, int y, int z, shared_ptr record) +{ + if (level->isClientSide) return; + + shared_ptr rte = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + rte->setRecord(record->copy()); + rte->setChanged(); + + level->setData(x, y, z, 1, Tile::UPDATE_CLIENTS); +} + +void JukeboxTile::dropRecording(Level *level, int x, int y, int z) +{ + if (level->isClientSide) return; + + shared_ptr rte = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + if( rte == NULL ) return; + + shared_ptr oldRecord = rte->getRecord(); + if (oldRecord == NULL) return; + + + level->levelEvent(LevelEvent::SOUND_PLAY_RECORDING, x, y, z, 0); + // 4J-PB- the level event will play the music + //level->playStreamingMusic(L"", x, y, z); + rte->setRecord(nullptr); + rte->setChanged(); + level->setData(x, y, z, 0, Tile::UPDATE_CLIENTS); + + float s = 0.7f; + double xo = level->random->nextFloat() * s + (1 - s) * 0.5; + double yo = level->random->nextFloat() * s + (1 - s) * 0.2 + 0.6; + double zo = level->random->nextFloat() * s + (1 - s) * 0.5; + + shared_ptr itemInstance = oldRecord->copy(); + + shared_ptr item = shared_ptr( new ItemEntity(level, x + xo, y + yo, z + zo, itemInstance ) ); + item->throwTime = 10; + level->addEntity(item); +} + +void JukeboxTile::onRemove(Level *level, int x, int y, int z, int id, int data) +{ + dropRecording(level, x, y, z); + Tile::onRemove(level, x, y, z, id, data); +} + +void JukeboxTile::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus) +{ + if (level->isClientSide) return; + Tile::spawnResources(level, x, y, z, data, odds, 0); +} + +shared_ptr JukeboxTile::newTileEntity(Level *level) +{ + return shared_ptr( new JukeboxTile::Entity() ); +} + +void JukeboxTile::registerIcons(IconRegister *iconRegister) +{ + icon = iconRegister->registerIcon(getIconName() + L"_side"); + iconTop = iconRegister->registerIcon(getIconName() + L"_top"); +} + +bool JukeboxTile::hasAnalogOutputSignal() +{ + return true; +} + +int JukeboxTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + shared_ptr record = dynamic_pointer_cast( level->getTileEntity(x, y, z))->getRecord(); + return record == NULL ? Redstone::SIGNAL_NONE : record->id + 1 - Item::record_01_Id; +} \ No newline at end of file diff --git a/Minecraft.World/JukeboxTile.h b/Minecraft.World/JukeboxTile.h new file mode 100644 index 00000000..dd592872 --- /dev/null +++ b/Minecraft.World/JukeboxTile.h @@ -0,0 +1,55 @@ +#pragma once + +#include "BaseEntityTile.h" +#include "CompoundTag.h" +#include "TileEntity.h" + +class CompoundTag; +class ChunkRebuildData; + +class JukeboxTile : public BaseEntityTile +{ + friend class Tile; + friend class ChunkRebuildData; +public: + class Entity : public TileEntity + { + public: + eINSTANCEOF GetType() { return eTYPE_RECORDPLAYERTILE; } + static TileEntity *create() { return new JukeboxTile::Entity(); } + + private: + shared_ptr record; + + public: + Entity(); + + virtual void load(CompoundTag *tag); + virtual void save(CompoundTag *tag); + virtual shared_ptr getRecord(); + virtual void setRecord(shared_ptr record); + + // 4J Added + shared_ptr clone(); + }; + +private: + Icon *iconTop; + +protected: + JukeboxTile(int id); + +public: + virtual Icon *getTexture(int face, int data); + virtual bool TestUse(Level *level, int x, int y, int z, shared_ptr player); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + void setRecord(Level *level, int x, int y, int z, shared_ptr record); + void dropRecording(Level *level, int x, int y, int z); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); + + virtual shared_ptr newTileEntity(Level *level); + virtual void registerIcons(IconRegister *iconRegister); + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); +}; diff --git a/Minecraft.World/JungleBiome.cpp b/Minecraft.World/JungleBiome.cpp index ba30a896..1388e97f 100644 --- a/Minecraft.World/JungleBiome.cpp +++ b/Minecraft.World/JungleBiome.cpp @@ -12,7 +12,7 @@ JungleBiome::JungleBiome(int id) : Biome(id) decorator->grassCount = 25; decorator->flowerCount = 4; - enemies.push_back(new MobSpawnerData(eTYPE_OZELOT, 2, 1, 1)); + enemies.push_back(new MobSpawnerData(eTYPE_OCELOT, 2, 1, 1)); // make chicken a lot more common in the jungle friendlies.push_back(new MobSpawnerData(eTYPE_CHICKEN, 10, 4, 4)); diff --git a/Minecraft.World/KillCommand.cpp b/Minecraft.World/KillCommand.cpp index 30a7880e..c726b21f 100644 --- a/Minecraft.World/KillCommand.cpp +++ b/Minecraft.World/KillCommand.cpp @@ -2,6 +2,7 @@ #include "net.minecraft.commands.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.damagesource.h" +#include "BasicTypeContainers.h" #include "KillCommand.h" EGameCommand KillCommand::getId() @@ -9,11 +10,17 @@ EGameCommand KillCommand::getId() return eGameCommand_Kill; } +int KillCommand::getPermissionLevel() +{ + return LEVEL_ALL; +} + void KillCommand::execute(shared_ptr source, byteArray commandData) { shared_ptr player = dynamic_pointer_cast(source); - player->hurt(DamageSource::outOfWorld, 1000); + player->hurt(DamageSource::outOfWorld, Float::MAX_VALUE); source->sendMessage(L"Ouch. That look like it hurt."); +//source.sendMessage(ChatMessageComponent.forTranslation("commands.kill.success")); } \ No newline at end of file diff --git a/Minecraft.World/KillCommand.h b/Minecraft.World/KillCommand.h index a88b2069..50db2c79 100644 --- a/Minecraft.World/KillCommand.h +++ b/Minecraft.World/KillCommand.h @@ -6,5 +6,6 @@ class KillCommand : public Command { public: virtual EGameCommand getId(); + virtual int getPermissionLevel(); virtual void execute(shared_ptr source, byteArray commandData); }; \ No newline at end of file diff --git a/Minecraft.World/LadderTile.cpp b/Minecraft.World/LadderTile.cpp index 32f35ed8..438d2bbf 100644 --- a/Minecraft.World/LadderTile.cpp +++ b/Minecraft.World/LadderTile.cpp @@ -15,8 +15,8 @@ AABB *LadderTile::getAABB(Level *level, int x, int y, int z) AABB *LadderTile::getTileAABB(Level *level, int x, int y, int z) { - updateShape(level, x, y, z); - return Tile::getTileAABB(level, x, y, z); + updateShape(level, x, y, z); + return Tile::getTileAABB(level, x, y, z); } void LadderTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param @@ -57,53 +57,53 @@ int LadderTile::getRenderShape() bool LadderTile::mayPlace(Level *level, int x, int y, int z) { - if (level->isSolidBlockingTile(x - 1, y, z)) + if (level->isSolidBlockingTile(x - 1, y, z)) { - return true; - } + return true; + } else if (level->isSolidBlockingTile(x + 1, y, z)) { - return true; + return true; } else if (level->isSolidBlockingTile(x, y, z - 1)) { - return true; - } + return true; + } else if (level->isSolidBlockingTile(x, y, z + 1)) { - return true; - } - return false; + return true; + } + return false; } int LadderTile::getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) { - int dir = level->getData(x, y, z); + int dir = level->getData(x, y, z); - if ((dir == 0 || face == 2) && level->isSolidBlockingTile(x, y, z + 1)) dir = 2; - if ((dir == 0 || face == 3) && level->isSolidBlockingTile(x, y, z - 1)) dir = 3; - if ((dir == 0 || face == 4) && level->isSolidBlockingTile(x + 1, y, z)) dir = 4; - if ((dir == 0 || face == 5) && level->isSolidBlockingTile(x - 1, y, z)) dir = 5; + if ((dir == 0 || face == 2) && level->isSolidBlockingTile(x, y, z + 1)) dir = 2; + if ((dir == 0 || face == 3) && level->isSolidBlockingTile(x, y, z - 1)) dir = 3; + if ((dir == 0 || face == 4) && level->isSolidBlockingTile(x + 1, y, z)) dir = 4; + if ((dir == 0 || face == 5) && level->isSolidBlockingTile(x - 1, y, z)) dir = 5; - return dir; + return dir; } void LadderTile::neighborChanged(Level *level, int x, int y, int z, int type) { - int face = level->getData(x, y, z); - bool ok = false; - - if (face == 2 && level->isSolidBlockingTile(x, y, z + 1)) ok = true; - if (face == 3 && level->isSolidBlockingTile(x, y, z - 1)) ok = true; - if (face == 4 && level->isSolidBlockingTile(x + 1, y, z)) ok = true; - if (face == 5 && level->isSolidBlockingTile(x - 1, y, z)) ok = true; - if (!ok) + int face = level->getData(x, y, z); + bool ok = false; + + if (face == 2 && level->isSolidBlockingTile(x, y, z + 1)) ok = true; + if (face == 3 && level->isSolidBlockingTile(x, y, z - 1)) ok = true; + if (face == 4 && level->isSolidBlockingTile(x + 1, y, z)) ok = true; + if (face == 5 && level->isSolidBlockingTile(x - 1, y, z)) ok = true; + if (!ok) { - spawnResources(level, x, y, z, face, 0); - level->setTile(x, y, z, 0); - } + spawnResources(level, x, y, z, face, 0); + level->removeTile(x, y, z); + } - Tile::neighborChanged(level, x, y, z, type); + Tile::neighborChanged(level, x, y, z, type); } int LadderTile::getResourceCount(Random* random) diff --git a/Minecraft.World/LakeFeature.cpp b/Minecraft.World/LakeFeature.cpp index 7450450d..ac240e61 100644 --- a/Minecraft.World/LakeFeature.cpp +++ b/Minecraft.World/LakeFeature.cpp @@ -11,16 +11,16 @@ LakeFeature::LakeFeature(int tile) bool LakeFeature::place(Level *level, Random *random, int x, int y, int z) { - x -= 8; - z -= 8; - while (y > 5 && level->isEmptyTile(x, y, z)) - y--; + x -= 8; + z -= 8; + while (y > 5 && level->isEmptyTile(x, y, z)) + y--; if (y <= 4) { return false; } - y -= 4; + y -= 4; bool grid[16*16*8] = {0}; @@ -32,7 +32,7 @@ bool LakeFeature::place(Level *level, Random *random, int x, int y, int z) int minX = x; int minY = y; int minZ = z; - + int maxX = x + 16; int maxY = y + 8; int maxZ = z + 16; @@ -45,98 +45,97 @@ bool LakeFeature::place(Level *level, Random *random, int x, int y, int z) } } - int spots = random->nextInt(4) + 4; - for (int i = 0; i < spots; i++) + int spots = random->nextInt(4) + 4; + for (int i = 0; i < spots; i++) { - double xr = random->nextDouble() * 6 + 3; - double yr = random->nextDouble() * 4 + 2; - double zr = random->nextDouble() * 6 + 3; + double xr = random->nextDouble() * 6 + 3; + double yr = random->nextDouble() * 4 + 2; + double zr = random->nextDouble() * 6 + 3; - double xp = random->nextDouble() * (16 - xr - 2) + 1 + xr / 2; - double yp = random->nextDouble() * (8 - yr - 4) + 2 + yr / 2; - double zp = random->nextDouble() * (16 - zr - 2) + 1 + zr / 2; + double xp = random->nextDouble() * (16 - xr - 2) + 1 + xr / 2; + double yp = random->nextDouble() * (8 - yr - 4) + 2 + yr / 2; + double zp = random->nextDouble() * (16 - zr - 2) + 1 + zr / 2; - for (int xx = 1; xx < 15; xx++) + for (int xx = 1; xx < 15; xx++) { - for (int zz = 1; zz < 15; zz++) + for (int zz = 1; zz < 15; zz++) { - for (int yy = 1; yy < 7; yy++) + for (int yy = 1; yy < 7; yy++) { - double xd = ((xx - xp) / (xr / 2)); - double yd = ((yy - yp) / (yr / 2)); - double zd = ((zz - zp) / (zr / 2)); - double d = xd * xd + yd * yd + zd * zd; - if (d < 1) grid[((xx) * 16 + (zz)) * 8 + (yy)] = true; - } - } - } - } - - for (int xx = 0; xx < 16; xx++) + double xd = ((xx - xp) / (xr / 2)); + double yd = ((yy - yp) / (yr / 2)); + double zd = ((zz - zp) / (zr / 2)); + double d = xd * xd + yd * yd + zd * zd; + if (d < 1) grid[((xx) * 16 + (zz)) * 8 + (yy)] = true; + } + } + } + } + + for (int xx = 0; xx < 16; xx++) { - for (int zz = 0; zz < 16; zz++) + for (int zz = 0; zz < 16; zz++) { - for (int yy = 0; yy < 8; yy++) + for (int yy = 0; yy < 8; yy++) { - bool check = !grid[((xx) * 16 + (zz)) * 8 + (yy)] && ( - (xx < 15 && grid[((xx + 1) * 16 + (zz)) * 8 + (yy)]) - || (xx > 0 && grid[((xx - 1) * 16 + (zz)) * 8 + (yy)]) - || (zz < 15 && grid[((xx) * 16 + (zz + 1)) * 8 + (yy)]) - || (zz > 0 && grid[((xx) * 16 + (zz - 1)) * 8 + (yy)]) - || (yy < 7 && grid[((xx) * 16 + (zz)) * 8 + (yy + 1)]) - || (yy > 0 && grid[((xx) * 16 + (zz)) * 8 + (yy - 1)])); - - if (check) + bool check = !grid[((xx) * 16 + (zz)) * 8 + (yy)] && ((xx < 15 && grid[((xx + 1) * 16 + (zz)) * 8 + (yy)])// + || (xx > 0 && grid[((xx - 1) * 16 + (zz)) * 8 + (yy)]) + || (zz < 15 && grid[((xx) * 16 + (zz + 1)) * 8 + (yy)]) + || (zz > 0 && grid[((xx) * 16 + (zz - 1)) * 8 + (yy)]) + || (yy < 7 && grid[((xx) * 16 + (zz)) * 8 + (yy + 1)]) + || (yy > 0 && grid[((xx) * 16 + (zz)) * 8 + (yy - 1)])); + + if (check) { - Material *m = level->getMaterial(x + xx, y + yy, z + zz); - if (yy >= 4 && m->isLiquid()) return false; - if (yy < 4 && (!m->isSolid() && level->getTile(x + xx, y + yy, z + zz) != tile)) return false; + Material *m = level->getMaterial(x + xx, y + yy, z + zz); + if (yy >= 4 && m->isLiquid()) return false; + if (yy < 4 && (!m->isSolid() && level->getTile(x + xx, y + yy, z + zz) != tile)) return false; - } - } - } - } + } + } + } + } - for (int xx = 0; xx < 16; xx++) + for (int xx = 0; xx < 16; xx++) { - for (int zz = 0; zz < 16; zz++) + for (int zz = 0; zz < 16; zz++) { - for (int yy = 0; yy < 8; yy++) + for (int yy = 0; yy < 8; yy++) { - if (grid[((xx) * 16 + (zz)) * 8 + (yy)]) + if (grid[((xx) * 16 + (zz)) * 8 + (yy)]) { - level->setTileNoUpdate(x + xx, y + yy, z + zz, yy >= 4 ? 0 : tile); - } - } - } - } + level->setTileAndData(x + xx, y + yy, z + zz, yy >= 4 ? 0 : tile, 0, Tile::UPDATE_CLIENTS); + } + } + } + } - for (int xx = 0; xx < 16; xx++) + for (int xx = 0; xx < 16; xx++) { - for (int zz = 0; zz < 16; zz++) + for (int zz = 0; zz < 16; zz++) { - for (int yy = 4; yy < 8; yy++) + for (int yy = 4; yy < 8; yy++) { - if (grid[((xx) * 16 + (zz)) * 8 + (yy)]) + if (grid[((xx) * 16 + (zz)) * 8 + (yy)]) { - if (level->getTile(x + xx, y + yy - 1, z + zz) == Tile::dirt_Id && level->getBrightness(LightLayer::Sky, x + xx, y + yy, z + zz) > 0) + if (level->getTile(x + xx, y + yy - 1, z + zz) == Tile::dirt_Id && level->getBrightness(LightLayer::Sky, x + xx, y + yy, z + zz) > 0) { Biome *b = level->getBiome(x + xx, z + zz); - if (b->topMaterial == Tile::mycel_Id) level->setTileNoUpdate(x + xx, y + yy - 1, z + zz, Tile::mycel_Id); - else level->setTileNoUpdate(x + xx, y + yy - 1, z + zz, Tile::grass_Id); - } - } - } - } - } - - if (Tile::tiles[tile]->material == Material::lava) + if (b->topMaterial == Tile::mycel_Id) level->setTileAndData(x + xx, y + yy - 1, z + zz, Tile::mycel_Id, 0, Tile::UPDATE_CLIENTS); + else level->setTileAndData(x + xx, y + yy - 1, z + zz, Tile::grass_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } + } + } + + if (Tile::tiles[tile]->material == Material::lava) { - for (int xx = 0; xx < 16; xx++) + for (int xx = 0; xx < 16; xx++) { - for (int zz = 0; zz < 16; zz++) + for (int zz = 0; zz < 16; zz++) { - for (int yy = 0; yy < 8; yy++) + for (int yy = 0; yy < 8; yy++) { bool check = !grid[((xx) * 16 + (zz)) * 8 + (yy)] && ( (xx < 15 && grid[(((xx + 1) * 16 + (zz)) * 8 + (yy))]) @@ -146,30 +145,30 @@ bool LakeFeature::place(Level *level, Random *random, int x, int y, int z) || (yy < 7 && grid[(((xx) * 16 + (zz)) * 8 + (yy + 1))]) || (yy > 0 && grid[(((xx) * 16 + (zz)) * 8 + (yy - 1))])); - if (check) + if (check) { - if ((yy<4 || random->nextInt(2)!=0) && level->getMaterial(x + xx, y + yy, z + zz)->isSolid()) + if ((yy<4 || random->nextInt(2)!=0) && level->getMaterial(x + xx, y + yy, z + zz)->isSolid()) { - level->setTileNoUpdate(x + xx, y + yy, z + zz, Tile::rock_Id); - } - } - } - } - } - } + level->setTileAndData(x + xx, y + yy, z + zz, Tile::stone_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } + } + } + } // 4J - brought forward from 1.8.2 - if (Tile::tiles[tile]->material == Material::water) + if (Tile::tiles[tile]->material == Material::water) { - for (int xx = 0; xx < 16; xx++) + for (int xx = 0; xx < 16; xx++) { - for (int zz = 0; zz < 16; zz++) + for (int zz = 0; zz < 16; zz++) { - int yy = 4; - if (level->shouldFreezeIgnoreNeighbors(x + xx, y + yy, z + zz)) level->setTileNoUpdate(x + xx, y + yy, z + zz, Tile::ice_Id); - } - } - } + int yy = 4; + if (level->shouldFreezeIgnoreNeighbors(x + xx, y + yy, z + zz)) level->setTileAndData(x + xx, y + yy, z + zz, Tile::ice_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/LargeCaveFeature.cpp b/Minecraft.World/LargeCaveFeature.cpp index 20b83a30..c05447cf 100644 --- a/Minecraft.World/LargeCaveFeature.cpp +++ b/Minecraft.World/LargeCaveFeature.cpp @@ -11,186 +11,186 @@ void LargeCaveFeature::addRoom(__int64 seed, int xOffs, int zOffs, byteArray blo void LargeCaveFeature::addTunnel(__int64 seed, int xOffs, int zOffs, byteArray blocks, double xCave, double yCave, double zCave, float thickness, float yRot, float xRot, int step, int dist, double yScale) { - double xMid = xOffs * 16 + 8; - double zMid = zOffs * 16 + 8; + double xMid = xOffs * 16 + 8; + double zMid = zOffs * 16 + 8; - float yRota = 0; - float xRota = 0; - Random random = Random(seed); + float yRota = 0; + float xRota = 0; + Random random = Random(seed); - if (dist <= 0) + if (dist <= 0) { - int max = radius * 16 - 16; - dist = max - random.nextInt(max / 4); - } - bool singleStep = false; + int max = radius * 16 - 16; + dist = max - random.nextInt(max / 4); + } + bool singleStep = false; - if (step == -1) + if (step == -1) { - step = dist / 2; - singleStep = true; - } + step = dist / 2; + singleStep = true; + } - int splitPoint = random.nextInt(dist / 2) + dist / 4; - bool steep = random.nextInt(6) == 0; + int splitPoint = random.nextInt(dist / 2) + dist / 4; + bool steep = random.nextInt(6) == 0; - for (; step < dist; step++) + for (; step < dist; step++) { - double rad = 1.5 + (Mth::sin(step * PI / dist) * thickness) * 1; - double yRad = rad * yScale; + double rad = 1.5 + (Mth::sin(step * PI / dist) * thickness) * 1; + double yRad = rad * yScale; - float xc = Mth::cos(xRot); - float xs = Mth::sin(xRot); - xCave += Mth::cos(yRot) * xc; - yCave += xs; - zCave += Mth::sin(yRot) * xc; + float xc = Mth::cos(xRot); + float xs = Mth::sin(xRot); + xCave += Mth::cos(yRot) * xc; + yCave += xs; + zCave += Mth::sin(yRot) * xc; - if (steep) + if (steep) { - xRot *= 0.92f; - } + xRot *= 0.92f; + } else { - xRot *= 0.7f; - } - xRot += xRota * 0.1f; - yRot += yRota * 0.1f; + xRot *= 0.7f; + } + xRot += xRota * 0.1f; + yRot += yRota * 0.1f; - xRota *= 0.90f; - yRota *= 0.75f; - xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2; - yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4; + xRota *= 0.90f; + yRota *= 0.75f; + xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2; + yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4; - if (!singleStep && step == splitPoint && thickness > 1 && dist > 0) + if (!singleStep && step == splitPoint && thickness > 1 && dist > 0) { - addTunnel(random.nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - PI / 2, xRot / 3, step, dist, 1.0); - addTunnel(random.nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + PI / 2, xRot / 3, step, dist, 1.0); - return; - } - if (!singleStep && random.nextInt(4) == 0) continue; - { - double xd = xCave - xMid; - double zd = zCave - zMid; - double remaining = dist - step; - double rr = (thickness + 2) + 16; - if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) + addTunnel(random.nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - PI / 2, xRot / 3, step, dist, 1.0); + addTunnel(random.nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + PI / 2, xRot / 3, step, dist, 1.0); + return; + } + if (!singleStep && random.nextInt(4) == 0) continue; + { + double xd = xCave - xMid; + double zd = zCave - zMid; + double remaining = dist - step; + double rr = (thickness + 2) + 16; + if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) { - return; - } - } + return; + } + } - if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; + if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; - int x0 = Mth::floor(xCave - rad) - xOffs * 16 - 1; - int x1 = Mth::floor(xCave + rad) - xOffs * 16 + 1; + int x0 = Mth::floor(xCave - rad) - xOffs * 16 - 1; + int x1 = Mth::floor(xCave + rad) - xOffs * 16 + 1; - int y0 = Mth::floor(yCave - yRad) - 1; - int y1 = Mth::floor(yCave + yRad) + 1; + int y0 = Mth::floor(yCave - yRad) - 1; + int y1 = Mth::floor(yCave + yRad) + 1; - int z0 = Mth::floor(zCave - rad) - zOffs * 16 - 1; - int z1 = Mth::floor(zCave + rad) - zOffs * 16 + 1; + int z0 = Mth::floor(zCave - rad) - zOffs * 16 - 1; + int z1 = Mth::floor(zCave + rad) - zOffs * 16 + 1; - if (x0 < 0) x0 = 0; - if (x1 > 16) x1 = 16; + if (x0 < 0) x0 = 0; + if (x1 > 16) x1 = 16; - if (y0 < 1) y0 = 1; - if (y1 > Level::genDepth - 8) y1 = Level::genDepth - 8; + if (y0 < 1) y0 = 1; + if (y1 > Level::genDepth - 8) y1 = Level::genDepth - 8; - if (z0 < 0) z0 = 0; - if (z1 > 16) z1 = 16; + if (z0 < 0) z0 = 0; + if (z1 > 16) z1 = 16; - bool detectedWater = false; - for (int xx = x0; !detectedWater && xx < x1; xx++) + bool detectedWater = false; + for (int xx = x0; !detectedWater && xx < x1; xx++) { - for (int zz = z0; !detectedWater && zz < z1; zz++) + for (int zz = z0; !detectedWater && zz < z1; zz++) { - for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) + for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) { - int p = (xx * 16 + zz) * Level::genDepth + yy; - if (yy < 0 || yy >= Level::genDepth) continue; - if (blocks[p] == Tile::water_Id || blocks[p] == Tile::calmWater_Id) + int p = (xx * 16 + zz) * Level::genDepth + yy; + if (yy < 0 || yy >= Level::genDepth) continue; + if (blocks[p] == Tile::water_Id || blocks[p] == Tile::calmWater_Id) { - detectedWater = true; - } - if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) + detectedWater = true; + } + if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) { - yy = y0; - } - } - } - } - if (detectedWater) continue; - - for (int xx = x0; xx < x1; xx++) + yy = y0; + } + } + } + } + if (detectedWater) continue; + + for (int xx = x0; xx < x1; xx++) { - double xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; - for (int zz = z0; zz < z1; zz++) + double xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; + for (int zz = z0; zz < z1; zz++) { - double zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; - int p = (xx * 16 + zz) * Level::genDepth + y1; - bool hasGrass = false; - if (xd * xd + zd * zd < 1) + double zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; + int p = (xx * 16 + zz) * Level::genDepth + y1; + bool hasGrass = false; + if (xd * xd + zd * zd < 1) { - for (int yy = y1 - 1; yy >= y0; yy--) + for (int yy = y1 - 1; yy >= y0; yy--) { - double yd = (yy + 0.5 - yCave) / yRad; - if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) + double yd = (yy + 0.5 - yCave) / yRad; + if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) { - int block = blocks[p]; - if (block == Tile::grass_Id) hasGrass = true; - if (block == Tile::rock_Id || block == Tile::dirt_Id || block == Tile::grass_Id) + int block = blocks[p]; + if (block == Tile::grass_Id) hasGrass = true; + if (block == Tile::stone_Id || block == Tile::dirt_Id || block == Tile::grass_Id) { - if (yy < 10) + if (yy < 10) { - blocks[p] = (byte) Tile::lava_Id; - } + blocks[p] = (byte) Tile::lava_Id; + } else { - blocks[p] = (byte) 0; - if (hasGrass && blocks[p - 1] == Tile::dirt_Id) blocks[p - 1] = (byte) level->getBiome(xx + xOffs * 16, zz + zOffs * 16)->topMaterial; - } - } - } - p--; - } - } - } - } - if (singleStep) break; - } + blocks[p] = (byte) 0; + if (hasGrass && blocks[p - 1] == Tile::dirt_Id) blocks[p - 1] = (byte) level->getBiome(xx + xOffs * 16, zz + zOffs * 16)->topMaterial; + } + } + } + p--; + } + } + } + } + if (singleStep) break; + } } void LargeCaveFeature::addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks) { int caves = random->nextInt(random->nextInt(random->nextInt(40) + 1) + 1); - if (random->nextInt(15) != 0) caves = 0; + if (random->nextInt(15) != 0) caves = 0; - for (int cave = 0; cave < caves; cave++) + for (int cave = 0; cave < caves; cave++) { - double xCave = x * 16 + random->nextInt(16); - double yCave = random->nextInt(random->nextInt(Level::genDepth - 8) + 8); - double zCave = z * 16 + random->nextInt(16); + double xCave = x * 16 + random->nextInt(16); + double yCave = random->nextInt(random->nextInt(Level::genDepth - 8) + 8); + double zCave = z * 16 + random->nextInt(16); - int tunnels = 1; - if (random->nextInt(4) == 0) + int tunnels = 1; + if (random->nextInt(4) == 0) { - addRoom(random->nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave); - tunnels += random->nextInt(4); - } + addRoom(random->nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave); + tunnels += random->nextInt(4); + } - for (int i = 0; i < tunnels; i++) + for (int i = 0; i < tunnels; i++) { - float yRot = random->nextFloat() * PI * 2; - float xRot = ((random->nextFloat() - 0.5f) * 2) / 8; - float thickness = random->nextFloat() * 2 + random->nextFloat(); + float yRot = random->nextFloat() * PI * 2; + float xRot = ((random->nextFloat() - 0.5f) * 2) / 8; + float thickness = random->nextFloat() * 2 + random->nextFloat(); if (random->nextInt(10) == 0) thickness *= random->nextFloat() * random->nextFloat() * 3 + 1; - addTunnel(random->nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 1.0); - } - } + addTunnel(random->nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave, thickness, yRot, xRot, 0, 0, 1.0); + } + } } diff --git a/Minecraft.World/LargeFireball.cpp b/Minecraft.World/LargeFireball.cpp new file mode 100644 index 00000000..9f8da92c --- /dev/null +++ b/Minecraft.World/LargeFireball.cpp @@ -0,0 +1,47 @@ +#include "stdafx.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.phys.h" +#include "LargeFireball.h" + +LargeFireball::LargeFireball(Level *level) : Fireball(level) +{ + explosionPower = 1; +} + +LargeFireball::LargeFireball(Level *level, double x, double y, double z, double xa, double ya, double za) : Fireball(level, x, y, z, xa, ya, za) +{ + explosionPower = 1; +} + +LargeFireball::LargeFireball(Level *level, shared_ptr mob, double xa, double ya, double za) : Fireball(level, mob, xa, ya, za) +{ + explosionPower = 1; +} + +void LargeFireball::onHit(HitResult *res) +{ + if (!level->isClientSide) + { + if (res->entity != NULL) + { + DamageSource *damageSource = DamageSource::fireball(dynamic_pointer_cast( shared_from_this() ), owner); + res->entity->hurt(damageSource, 6); + delete damageSource; + } + level->explode(nullptr, x, y, z, explosionPower, true, level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)); + remove(); + } +} + +void LargeFireball::addAdditonalSaveData(CompoundTag *tag) +{ + Fireball::addAdditonalSaveData(tag); + tag->putInt(L"ExplosionPower", explosionPower); +} + +void LargeFireball::readAdditionalSaveData(CompoundTag *tag) +{ + Fireball::readAdditionalSaveData(tag); + if (tag->contains(L"ExplosionPower")) explosionPower = tag->getInt(L"ExplosionPower"); +} \ No newline at end of file diff --git a/Minecraft.World/LargeFireball.h b/Minecraft.World/LargeFireball.h new file mode 100644 index 00000000..555569c7 --- /dev/null +++ b/Minecraft.World/LargeFireball.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Fireball.h" + +class LargeFireball : public Fireball +{ +public: + eINSTANCEOF GetType() { return eTYPE_LARGE_FIREBALL; } + static Entity *create(Level *level) { return new LargeFireball(level); } + +public: + int explosionPower; + + LargeFireball(Level *level); + LargeFireball(Level *level, double x, double y, double z, double xa, double ya, double za); + LargeFireball(Level *level, shared_ptr mob, double xa, double ya, double za); + +protected: + void onHit(HitResult *res); + +public: + void addAdditonalSaveData(CompoundTag *tag); + void readAdditionalSaveData(CompoundTag *tag); +}; \ No newline at end of file diff --git a/Minecraft.World/LargeHellCaveFeature.cpp b/Minecraft.World/LargeHellCaveFeature.cpp index ac5d0eda..b1e636eb 100644 --- a/Minecraft.World/LargeHellCaveFeature.cpp +++ b/Minecraft.World/LargeHellCaveFeature.cpp @@ -3,182 +3,181 @@ #include "LargeHellCaveFeature.h" #include "net.minecraft.world.level.tile.h" -void LargeHellCaveFeature::addRoom(int xOffs, int zOffs, byteArray blocks, double xRoom, double yRoom, double zRoom) +void LargeHellCaveFeature::addRoom(__int64 seed, int xOffs, int zOffs, byteArray blocks, double xRoom, double yRoom, double zRoom) { - addTunnel(xOffs, zOffs, blocks, xRoom, yRoom, zRoom, 1 + random->nextFloat() * 6, 0, 0, -1, -1, 0.5); + addTunnel(seed, xOffs, zOffs, blocks, xRoom, yRoom, zRoom, 1 + random->nextFloat() * 6, 0, 0, -1, -1, 0.5); } -void LargeHellCaveFeature::addTunnel(int xOffs, int zOffs, byteArray blocks, double xCave, double yCave, double zCave, float thickness, float yRot, float xRot, int step, int dist, double yScale) +void LargeHellCaveFeature::addTunnel(__int64 seed, int xOffs, int zOffs, byteArray blocks, double xCave, double yCave, double zCave, float thickness, float yRot, float xRot, int step, int dist, double yScale) { - double xMid = xOffs * 16 + 8; - double zMid = zOffs * 16 + 8; + double xMid = xOffs * 16 + 8; + double zMid = zOffs * 16 + 8; - float yRota = 0; - float xRota = 0; - Random *random = new Random(this->random->nextLong()); + float yRota = 0; + float xRota = 0; + Random random(seed); - if (dist <= 0) + if (dist <= 0) { - int max = radius * 16 - 16; - dist = max - random->nextInt(max / 4); - } - bool singleStep = false; + int max = radius * 16 - 16; + dist = max - random.nextInt(max / 4); + } + bool singleStep = false; - if (step == -1) + if (step == -1) { - step = dist / 2; - singleStep = true; - } + step = dist / 2; + singleStep = true; + } - int splitPoint = random->nextInt(dist / 2) + dist / 4; - bool steep = random->nextInt(6) == 0; + int splitPoint = random.nextInt(dist / 2) + dist / 4; + bool steep = random.nextInt(6) == 0; - for (; step < dist; step++) + for (; step < dist; step++) { - double rad = 1.5 + (Mth::sin(step * PI / dist) * thickness) * 1; - double yRad = rad * yScale; + double rad = 1.5 + (Mth::sin(step * PI / dist) * thickness) * 1; + double yRad = rad * yScale; - float xc = Mth::cos(xRot); - float xs = Mth::sin(xRot); - xCave += Mth::cos(yRot) * xc; - yCave += xs; - zCave += Mth::sin(yRot) * xc; + float xc = Mth::cos(xRot); + float xs = Mth::sin(xRot); + xCave += Mth::cos(yRot) * xc; + yCave += xs; + zCave += Mth::sin(yRot) * xc; - if (steep) + if (steep) { - xRot *= 0.92f; - } + xRot *= 0.92f; + } else { - xRot *= 0.7f; - } - xRot += xRota * 0.1f; - yRot += yRota * 0.1f; + xRot *= 0.7f; + } + xRot += xRota * 0.1f; + yRot += yRota * 0.1f; - xRota *= 0.90f; - yRota *= 0.75f; - xRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 2; - yRota += (random->nextFloat() - random->nextFloat()) * random->nextFloat() * 4; + xRota *= 0.90f; + yRota *= 0.75f; + xRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 2; + yRota += (random.nextFloat() - random.nextFloat()) * random.nextFloat() * 4; - if (!singleStep && step == splitPoint && thickness > 1) + if (!singleStep && step == splitPoint && thickness > 1) { - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random->nextFloat() * 0.5f + 0.5f, yRot - PI / 2, xRot / 3, step, dist, 1.0); - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, random->nextFloat() * 0.5f + 0.5f, yRot + PI / 2, xRot / 3, step, dist, 1.0); - delete random; - return; - } - if (!singleStep && random->nextInt(4) == 0) continue; - - { - double xd = xCave - xMid; - double zd = zCave - zMid; - double remaining = dist - step; - double rr = (thickness + 2) + 16; - if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) + addTunnel(random.nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot - PI / 2, xRot / 3, step, dist, 1.0); + addTunnel(random.nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave, random.nextFloat() * 0.5f + 0.5f, yRot + PI / 2, xRot / 3, step, dist, 1.0); + return; + } + if (!singleStep && random.nextInt(4) == 0) continue; + + { + double xd = xCave - xMid; + double zd = zCave - zMid; + double remaining = dist - step; + double rr = (thickness + 2) + 16; + if (xd * xd + zd * zd - (remaining * remaining) > rr * rr) { - delete random; - return; - } - } + return; + } + } - if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; + if (xCave < xMid - 16 - rad * 2 || zCave < zMid - 16 - rad * 2 || xCave > xMid + 16 + rad * 2 || zCave > zMid + 16 + rad * 2) continue; - int x0 = Mth::floor(xCave - rad) - xOffs * 16 - 1; - int x1 = Mth::floor(xCave + rad) - xOffs * 16 + 1; + int x0 = Mth::floor(xCave - rad) - xOffs * 16 - 1; + int x1 = Mth::floor(xCave + rad) - xOffs * 16 + 1; - int y0 = Mth::floor(yCave - yRad) - 1; - int y1 = Mth::floor(yCave + yRad) + 1; + int y0 = Mth::floor(yCave - yRad) - 1; + int y1 = Mth::floor(yCave + yRad) + 1; - int z0 = Mth::floor(zCave - rad) - zOffs * 16 - 1; - int z1 = Mth::floor(zCave + rad) - zOffs * 16 + 1; + int z0 = Mth::floor(zCave - rad) - zOffs * 16 - 1; + int z1 = Mth::floor(zCave + rad) - zOffs * 16 + 1; - if (x0 < 0) x0 = 0; - if (x1 > 16) x1 = 16; + if (x0 < 0) x0 = 0; + if (x1 > 16) x1 = 16; - if (y0 < 1) y0 = 1; - if (y1 > Level::genDepth - 8) y1 = Level::genDepth - 8; + if (y0 < 1) y0 = 1; + if (y1 > Level::genDepth - 8) y1 = Level::genDepth - 8; - if (z0 < 0) z0 = 0; - if (z1 > 16) z1 = 16; + if (z0 < 0) z0 = 0; + if (z1 > 16) z1 = 16; - bool detectedWater = false; - for (int xx = x0; !detectedWater && xx < x1; xx++) + bool detectedWater = false; + for (int xx = x0; !detectedWater && xx < x1; xx++) { - for (int zz = z0; !detectedWater && zz < z1; zz++) + for (int zz = z0; !detectedWater && zz < z1; zz++) { - for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) + for (int yy = y1 + 1; !detectedWater && yy >= y0 - 1; yy--) { - int p = (xx * 16 + zz) * Level::genDepth + yy; - if (yy < 0 || yy >= Level::genDepth) continue; - if (blocks[p] == Tile::lava_Id || blocks[p] == Tile::calmLava_Id) + int p = (xx * 16 + zz) * Level::genDepth + yy; + if (yy < 0 || yy >= Level::genDepth) continue; + if (blocks[p] == Tile::lava_Id || blocks[p] == Tile::calmLava_Id) { - detectedWater = true; - } - if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) + detectedWater = true; + } + if (yy != y0 - 1 && xx != x0 && xx != x1 - 1 && zz != z0 && zz != z1 - 1) { - yy = y0; - } - } - } - } - if (detectedWater) continue; - - for (int xx = x0; xx < x1; xx++) + yy = y0; + } + } + } + } + if (detectedWater) continue; + + for (int xx = x0; xx < x1; xx++) { - double xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; - for (int zz = z0; zz < z1; zz++) + double xd = ((xx + xOffs * 16 + 0.5) - xCave) / rad; + for (int zz = z0; zz < z1; zz++) { - double zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; - int p = (xx * 16 + zz) * Level::genDepth + y1; - for (int yy = y1 - 1; yy >= y0; yy--) + double zd = ((zz + zOffs * 16 + 0.5) - zCave) / rad; + int p = (xx * 16 + zz) * Level::genDepth + y1; + for (int yy = y1 - 1; yy >= y0; yy--) { - double yd = (yy + 0.5 - yCave) / yRad; - if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) + double yd = (yy + 0.5 - yCave) / yRad; + if (yd > -0.7 && xd * xd + yd * yd + zd * zd < 1) { - int block = blocks[p]; - if (block == Tile::hellRock_Id || block == Tile::dirt_Id || block == Tile::grass_Id) + int block = blocks[p]; + if (block == Tile::netherRack_Id || block == Tile::dirt_Id || block == Tile::grass_Id) { - blocks[p] = (byte) 0; - } - } - p--; - } - } - } - if (singleStep) break; - } - delete random; + blocks[p] = (byte) 0; + } + } + p--; + } + } + } + if (singleStep) break; + } } void LargeHellCaveFeature::addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks) { - int caves = random->nextInt(random->nextInt(random->nextInt(10) + 1) + 1); - if (random->nextInt(5) != 0) caves = 0; + int caves = random->nextInt(random->nextInt(random->nextInt(10) + 1) + 1); + if (random->nextInt(5) != 0) caves = 0; - for (int cave = 0; cave < caves; cave++) + for (int cave = 0; cave < caves; cave++) { - double xCave = x * 16 + random->nextInt(16); - double yCave = random->nextInt(Level::genDepth); - double zCave = z * 16 + random->nextInt(16); + double xCave = x * 16 + random->nextInt(16); + double yCave = random->nextInt(Level::genDepth); + double zCave = z * 16 + random->nextInt(16); - int tunnels = 1; - if (random->nextInt(4) == 0) { - addRoom(xOffs, zOffs, blocks, xCave, yCave, zCave); - tunnels += random->nextInt(4); - } + int tunnels = 1; + if (random->nextInt(4) == 0) + { + addRoom(random->nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave); + tunnels += random->nextInt(4); + } - for (int i = 0; i < tunnels; i++) { + for (int i = 0; i < tunnels; i++) + { - float yRot = random->nextFloat() * PI * 2; - float xRot = ((random->nextFloat() - 0.5f) * 2) / 8; - float thickness = random->nextFloat() * 2 + random->nextFloat(); + float yRot = random->nextFloat() * PI * 2; + float xRot = ((random->nextFloat() - 0.5f) * 2) / 8; + float thickness = random->nextFloat() * 2 + random->nextFloat(); - addTunnel(xOffs, zOffs, blocks, xCave, yCave, zCave, thickness*2, yRot, xRot, 0, 0, 0.5); - } - } + addTunnel(random->nextLong(), xOffs, zOffs, blocks, xCave, yCave, zCave, thickness*2, yRot, xRot, 0, 0, 0.5); + } + } } diff --git a/Minecraft.World/LargeHellCaveFeature.h b/Minecraft.World/LargeHellCaveFeature.h index 53d33692..ab6558b8 100644 --- a/Minecraft.World/LargeHellCaveFeature.h +++ b/Minecraft.World/LargeHellCaveFeature.h @@ -5,7 +5,7 @@ class LargeHellCaveFeature : public LargeFeature { protected: - void addRoom(int xOffs, int zOffs, byteArray blocks, double xRoom, double yRoom, double zRoom); - void addTunnel(int xOffs, int zOffs, byteArray blocks, double xCave, double yCave, double zCave, float thickness, float yRot, float xRot, int step, int dist, double yScale); + void addRoom(__int64 seed, int xOffs, int zOffs, byteArray blocks, double xRoom, double yRoom, double zRoom); + void addTunnel(__int64 seed, int xOffs, int zOffs, byteArray blocks, double xCave, double yCave, double zCave, float thickness, float yRot, float xRot, int step, int dist, double yScale); virtual void addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks); }; diff --git a/Minecraft.World/LavaSlime.cpp b/Minecraft.World/LavaSlime.cpp index 3ab32d90..21982995 100644 --- a/Minecraft.World/LavaSlime.cpp +++ b/Minecraft.World/LavaSlime.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.item.h" #include "..\Minecraft.Client\Textures.h" #include "LavaSlime.h" @@ -14,13 +16,16 @@ LavaSlime::LavaSlime(Level *level) : Slime(level) // the derived version of the function is called // 4J Stu - The Slime ctor has already called this, and as we don't override it here don't need to call it //this->defineSynchedData(); + registerAttributes(); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_LAVA; // 4J was "/mob/lava.png"; fireImmune = true; - walkingSpeed = .2f; +} + +void LavaSlime::registerAttributes() +{ + Slime::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.2f); } bool LavaSlime::canSpawn() @@ -95,7 +100,7 @@ void LavaSlime::decreaseSquish() void LavaSlime::jumpFromGround() { yd = 0.42f + getSize() * .1f; - this->hasImpulse = true; + hasImpulse = true; } void LavaSlime::causeFallDamage(float distance) @@ -114,12 +119,12 @@ int LavaSlime::getAttackDamage() int LavaSlime::getHurtSound() { - return eSoundType_MOB_SLIME; + return getSize() > 1 ? eSoundType_MOB_SLIME_BIG : eSoundType_MOB_SLIME_SMALL; } int LavaSlime::getDeathSound() { - return eSoundType_MOB_SLIME; + return getSize() > 1 ? eSoundType_MOB_SLIME_BIG : eSoundType_MOB_SLIME_SMALL; } int LavaSlime::getSquishSound() diff --git a/Minecraft.World/LavaSlime.h b/Minecraft.World/LavaSlime.h index 08857ca9..b16a7e6f 100644 --- a/Minecraft.World/LavaSlime.h +++ b/Minecraft.World/LavaSlime.h @@ -11,6 +11,10 @@ public: public: LavaSlime(Level *level); +protected: + virtual void registerAttributes(); + +public: virtual bool canSpawn(); virtual int getArmorValue(); diff --git a/Minecraft.World/Layer.cpp b/Minecraft.World/Layer.cpp index 1d010e72..956a8917 100644 --- a/Minecraft.World/Layer.cpp +++ b/Minecraft.World/Layer.cpp @@ -86,7 +86,7 @@ LayerArray Layer::getDefaultLayers(__int64 seed, LevelType *levelType) #ifndef _CONTENT_PACKAGE #ifdef _BIOME_OVERRIDE - if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<(new BiomeOverrideLayer(1)); } diff --git a/Minecraft.World/LeafTile.cpp b/Minecraft.World/LeafTile.cpp index 8b7d381c..684618a7 100644 --- a/Minecraft.World/LeafTile.cpp +++ b/Minecraft.World/LeafTile.cpp @@ -8,18 +8,18 @@ #include "net.minecraft.world.h" const unsigned int LeafTile::LEAF_NAMES[LEAF_NAMES_LENGTH] = { IDS_TILE_LEAVES_OAK, - IDS_TILE_LEAVES_SPRUCE, - IDS_TILE_LEAVES_BIRCH, - IDS_TILE_LEAVES_JUNGLE, - }; + IDS_TILE_LEAVES_SPRUCE, + IDS_TILE_LEAVES_BIRCH, + IDS_TILE_LEAVES_JUNGLE, +}; const wstring LeafTile::TEXTURES[2][4] = { {L"leaves", L"leaves_spruce", L"leaves", L"leaves_jungle"}, {L"leaves_opaque", L"leaves_spruce_opaque", L"leaves_opaque", L"leaves_jungle_opaque"},}; LeafTile::LeafTile(int id) : TransparentTile(id, Material::leaves, false, isSolidRender()) { checkBuffer = NULL; - fancyTextureSet = 0; - setTicking(true); + fancyTextureSet = 0; + setTicking(true); } LeafTile::~LeafTile() @@ -30,26 +30,26 @@ LeafTile::~LeafTile() int LeafTile::getColor() const { // 4J Stu - Not using this any more - //double temp = 0.5; - //double rain = 1.0; + //double temp = 0.5; + //double rain = 1.0; - //return FoliageColor::get(temp, rain); + //return FoliageColor::get(temp, rain); return Minecraft::GetInstance()->getColourTable()->getColor( eMinecraftColour_Foliage_Common ); } int LeafTile::getColor(int data) { - if ((data & LEAF_TYPE_MASK) == EVERGREEN_LEAF) + if ((data & LEAF_TYPE_MASK) == EVERGREEN_LEAF) { - return FoliageColor::getEvergreenColor(); - } - if ((data & LEAF_TYPE_MASK) == BIRCH_LEAF) + return FoliageColor::getEvergreenColor(); + } + if ((data & LEAF_TYPE_MASK) == BIRCH_LEAF) { - return FoliageColor::getBirchColor(); - } + return FoliageColor::getBirchColor(); + } - return FoliageColor::getDefaultColor(); + return FoliageColor::getDefaultColor(); } int LeafTile::getColor(LevelSource *level, int x, int y, int z) @@ -60,14 +60,14 @@ int LeafTile::getColor(LevelSource *level, int x, int y, int z) // 4J - changed interface to have data passed in, and put existing interface as wrapper above int LeafTile::getColor(LevelSource *level, int x, int y, int z, int data) { - if ((data & LEAF_TYPE_MASK) == EVERGREEN_LEAF) + if ((data & LEAF_TYPE_MASK) == EVERGREEN_LEAF) { - return FoliageColor::getEvergreenColor(); - } - if ((data & LEAF_TYPE_MASK) == BIRCH_LEAF) + return FoliageColor::getEvergreenColor(); + } + if ((data & LEAF_TYPE_MASK) == BIRCH_LEAF) { - return FoliageColor::getBirchColor(); - } + return FoliageColor::getBirchColor(); + } int totalRed = 0; int totalGreen = 0; @@ -90,113 +90,113 @@ int LeafTile::getColor(LevelSource *level, int x, int y, int z, int data) void LeafTile::onRemove(Level *level, int x, int y, int z, int id, int data) { - int r = 1; - int r2 = r + 1; + int r = 1; + int r2 = r + 1; - if (level->hasChunksAt(x - r2, y - r2, z - r2, x + r2, y + r2, z + r2)) + if (level->hasChunksAt(x - r2, y - r2, z - r2, x + r2, y + r2, z + r2)) { - for (int xo = -r; xo <= r; xo++) - for (int yo = -r; yo <= r; yo++) - for (int zo = -r; zo <= r; zo++) + for (int xo = -r; xo <= r; xo++) + for (int yo = -r; yo <= r; yo++) + for (int zo = -r; zo <= r; zo++) { - int t = level->getTile(x + xo, y + yo, z + zo); - if (t == Tile::leaves_Id) + int t = level->getTile(x + xo, y + yo, z + zo); + if (t == Tile::leaves_Id) { - int currentData = level->getData(x + xo, y + yo, z + zo); - level->setDataNoUpdate(x + xo, y + yo, z + zo, currentData | UPDATE_LEAF_BIT); - } - } - } + int currentData = level->getData(x + xo, y + yo, z + zo); + level->setData(x + xo, y + yo, z + zo, currentData | UPDATE_LEAF_BIT, Tile::UPDATE_NONE); + } + } + } } void LeafTile::tick(Level *level, int x, int y, int z, Random *random) { - if (level->isClientSide) return; + if (level->isClientSide) return; - int currentData = level->getData(x, y, z); - if ((currentData & UPDATE_LEAF_BIT) != 0 && (currentData & PERSISTENT_LEAF_BIT) == 0) + int currentData = level->getData(x, y, z); + if ((currentData & UPDATE_LEAF_BIT) != 0 && (currentData & PERSISTENT_LEAF_BIT) == 0) { - int r = LeafTile::REQUIRED_WOOD_RANGE; - int r2 = r + 1; + int r = REQUIRED_WOOD_RANGE; + int r2 = r + 1; - int W = 32; - int WW = W * W; - int WO = W / 2; - if (checkBuffer == NULL) + int W = 32; + int WW = W * W; + int WO = W / 2; + if (checkBuffer == NULL) { - checkBuffer = new int[W * W * W]; - } + checkBuffer = new int[W * W * W]; + } - if (level->hasChunksAt(x - r2, y - r2, z - r2, x + r2, y + r2, z + r2)) + if (level->hasChunksAt(x - r2, y - r2, z - r2, x + r2, y + r2, z + r2)) { // 4J Stu - Assuming we remain in the same chunk, getTile accesses an array that varies least by y // Changing the ordering here to loop by y last - for (int xo = -r; xo <= r; xo++) + for (int xo = -r; xo <= r; xo++) for (int zo = -r; zo <= r; zo++) for (int yo = -r; yo <= r; yo++) { - int t = level->getTile(x + xo, y + yo, z + zo); - if (t == Tile::treeTrunk_Id) + int t = level->getTile(x + xo, y + yo, z + zo); + if (t == Tile::treeTrunk_Id) { - checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] = 0; + checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] = 0; } else if (t == Tile::leaves_Id) { - checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] = -2; - } + checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] = -2; + } else { - checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] = -1; - } - } - for (int i = 1; i <= LeafTile::REQUIRED_WOOD_RANGE; i++) - { - for (int xo = -r; xo <= r; xo++) - for (int yo = -r; yo <= r; yo++) - for (int zo = -r; zo <= r; zo++) - { - if (checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] == i - 1) - { - if (checkBuffer[(xo + WO - 1) * WW + (yo + WO) * W + (zo + WO)] == -2) - { - checkBuffer[(xo + WO - 1) * WW + (yo + WO) * W + (zo + WO)] = i; - } - if (checkBuffer[(xo + WO + 1) * WW + (yo + WO) * W + (zo + WO)] == -2) - { - checkBuffer[(xo + WO + 1) * WW + (yo + WO) * W + (zo + WO)] = i; - } - if (checkBuffer[(xo + WO) * WW + (yo + WO - 1) * W + (zo + WO)] == -2) - { - checkBuffer[(xo + WO) * WW + (yo + WO - 1) * W + (zo + WO)] = i; - } - if (checkBuffer[(xo + WO) * WW + (yo + WO + 1) * W + (zo + WO)] == -2) - { - checkBuffer[(xo + WO) * WW + (yo + WO + 1) * W + (zo + WO)] = i; - } - if (checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO - 1)] == -2) - { - checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO - 1)] = i; - } - if (checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO + 1)] == -2) + checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] = -1; + } + } + for (int i = 1; i <= REQUIRED_WOOD_RANGE; i++) + { + for (int xo = -r; xo <= r; xo++) + for (int yo = -r; yo <= r; yo++) + for (int zo = -r; zo <= r; zo++) { - checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO + 1)] = i; - } - } - } - } - } - - int mid = checkBuffer[(WO) * WW + (WO) * W + (WO)]; - if (mid >= 0) + if (checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO)] == i - 1) + { + if (checkBuffer[(xo + WO - 1) * WW + (yo + WO) * W + (zo + WO)] == -2) + { + checkBuffer[(xo + WO - 1) * WW + (yo + WO) * W + (zo + WO)] = i; + } + if (checkBuffer[(xo + WO + 1) * WW + (yo + WO) * W + (zo + WO)] == -2) + { + checkBuffer[(xo + WO + 1) * WW + (yo + WO) * W + (zo + WO)] = i; + } + if (checkBuffer[(xo + WO) * WW + (yo + WO - 1) * W + (zo + WO)] == -2) + { + checkBuffer[(xo + WO) * WW + (yo + WO - 1) * W + (zo + WO)] = i; + } + if (checkBuffer[(xo + WO) * WW + (yo + WO + 1) * W + (zo + WO)] == -2) + { + checkBuffer[(xo + WO) * WW + (yo + WO + 1) * W + (zo + WO)] = i; + } + if (checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO - 1)] == -2) + { + checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO - 1)] = i; + } + if (checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO + 1)] == -2) + { + checkBuffer[(xo + WO) * WW + (yo + WO) * W + (zo + WO + 1)] = i; + } + } + } + } + } + + int mid = checkBuffer[(WO) * WW + (WO) * W + (WO)]; + if (mid >= 0) { - level->setDataNoUpdate(x, y, z, currentData & ~UPDATE_LEAF_BIT); - } + level->setData(x, y, z, currentData & ~UPDATE_LEAF_BIT, Tile::UPDATE_NONE); + } else { - die(level, x, y, z); - } - } + die(level, x, y, z); + } + } } @@ -214,8 +214,8 @@ void LeafTile::animateTick(Level *level, int x, int y, int z, Random *random) void LeafTile::die(Level *level, int x, int y, int z) { - Tile::spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + Tile::spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); } int LeafTile::getResourceCount(Random *random) @@ -238,13 +238,30 @@ void LeafTile::spawnResources(Level *level, int x, int y, int z, int data, float { chance = 40; } + if (playerBonusLevel > 0) + { + chance -= 2 << playerBonusLevel; + if (chance < 10) + { + chance = 10; + } + } if (level->random->nextInt(chance) == 0) { int type = getResource(data, level->random,playerBonusLevel); popResource(level, x, y, z, shared_ptr( new ItemInstance(type, 1, getSpawnResourcesAuxValue(data)))); } - if ((data & LEAF_TYPE_MASK) == NORMAL_LEAF && level->random->nextInt(200) == 0) + chance = 200; + if (playerBonusLevel > 0) + { + chance -= 10 << playerBonusLevel; + if (chance < 40) + { + chance = 40; + } + } + if ((data & LEAF_TYPE_MASK) == NORMAL_LEAF && level->random->nextInt(chance) == 0) { popResource(level, x, y, z, shared_ptr(new ItemInstance(Item::apple_Id, 1, 0))); } @@ -253,20 +270,20 @@ void LeafTile::spawnResources(Level *level, int x, int y, int z, int data, float void LeafTile::playerDestroy(Level *level, shared_ptr player, int x, int y, int z, int data) { - if (!level->isClientSide && player->getSelectedItem() != NULL && player->getSelectedItem()->id == Item::shears->id) + if (!level->isClientSide && player->getSelectedItem() != NULL && player->getSelectedItem()->id == Item::shears->id) { - player->awardStat( + player->awardStat( GenericStats::blocksMined(id), GenericStats::param_blocksMined(id,data,1) ); - // drop leaf block instead of sapling - popResource(level, x, y, z, shared_ptr(new ItemInstance(Tile::leaves_Id, 1, data & LEAF_TYPE_MASK))); - } + // drop leaf block instead of sapling + popResource(level, x, y, z, shared_ptr(new ItemInstance(Tile::leaves_Id, 1, data & LEAF_TYPE_MASK))); + } else { - TransparentTile::playerDestroy(level, player, x, y, z, data); - } + TransparentTile::playerDestroy(level, player, x, y, z, data); + } } int LeafTile::getSpawnResourcesAuxValue(int data) @@ -284,21 +301,25 @@ bool LeafTile::isSolidRender(bool isServerLevel) Icon *LeafTile::getTexture(int face, int data) { - if ((data & LEAF_TYPE_MASK) == EVERGREEN_LEAF) + if ((data & LEAF_TYPE_MASK) == EVERGREEN_LEAF) { - return icons[fancyTextureSet][EVERGREEN_LEAF]; - } - if ((data & LEAF_TYPE_MASK) == JUNGLE_LEAF) + return icons[fancyTextureSet][EVERGREEN_LEAF]; + } + if ((data & LEAF_TYPE_MASK) == JUNGLE_LEAF) + { + return icons[fancyTextureSet][JUNGLE_LEAF]; + } + if ((data & LEAF_TYPE_MASK) == BIRCH_LEAF) { - return icons[fancyTextureSet][JUNGLE_LEAF]; - } - return icons[fancyTextureSet][0]; + return icons[fancyTextureSet][BIRCH_LEAF]; + } + return icons[fancyTextureSet][0]; } void LeafTile::setFancy(bool fancyGraphics) { - allowSame = fancyGraphics; - fancyTextureSet = (fancyGraphics ? 0 : 1); + allowSame = fancyGraphics; + fancyTextureSet = (fancyGraphics ? 0 : 1); } shared_ptr LeafTile::getSilkTouchItemInstance(int data) @@ -314,7 +335,7 @@ void LeafTile::stepOn(Level *level, int x, int y, int z, shared_ptr enti bool LeafTile::shouldTileTick(Level *level, int x,int y,int z) { int currentData = level->getData(x, y, z); - return (currentData & UPDATE_LEAF_BIT) != 0; + return (currentData & UPDATE_LEAF_BIT) != 0; } unsigned int LeafTile::getDescriptionId(int iData /*= -1*/) diff --git a/Minecraft.World/LeapAtTargetGoal.cpp b/Minecraft.World/LeapAtTargetGoal.cpp index ea4a1c0e..6aebc9a8 100644 --- a/Minecraft.World/LeapAtTargetGoal.cpp +++ b/Minecraft.World/LeapAtTargetGoal.cpp @@ -5,7 +5,7 @@ LeapAtTargetGoal::LeapAtTargetGoal(Mob *mob, float yd) { - target = weak_ptr(); + target = weak_ptr(); this->mob = mob; this->yd = yd; @@ -14,7 +14,7 @@ LeapAtTargetGoal::LeapAtTargetGoal(Mob *mob, float yd) bool LeapAtTargetGoal::canUse() { - target = weak_ptr(mob->getTarget()); + target = weak_ptr(mob->getTarget()); if (target.lock() == NULL) return false; double d = mob->distanceToSqr(target.lock()); if (d < 2 * 2 || d > 4 * 4) return false; diff --git a/Minecraft.World/LeapAtTargetGoal.h b/Minecraft.World/LeapAtTargetGoal.h index 6495e131..a6e667ed 100644 --- a/Minecraft.World/LeapAtTargetGoal.h +++ b/Minecraft.World/LeapAtTargetGoal.h @@ -6,7 +6,7 @@ class LeapAtTargetGoal : public Goal { private: Mob *mob; // Owner of this goal - weak_ptr target; + weak_ptr target; float yd; public: diff --git a/Minecraft.World/LeashFenceKnotEntity.cpp b/Minecraft.World/LeashFenceKnotEntity.cpp new file mode 100644 index 00000000..21f98a6a --- /dev/null +++ b/Minecraft.World/LeashFenceKnotEntity.cpp @@ -0,0 +1,157 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.phys.h" +#include "LeashFenceKnotEntity.h" + +void LeashFenceKnotEntity::_init() +{ + defineSynchedData(); +} + +LeashFenceKnotEntity::LeashFenceKnotEntity(Level *level) : HangingEntity(level) +{ + _init(); +} + +LeashFenceKnotEntity::LeashFenceKnotEntity(Level *level, int xTile, int yTile, int zTile) : HangingEntity(level, xTile, yTile, zTile, 0) +{ + _init(); + setPos(xTile + .5, yTile + .5, zTile + .5); +} + +void LeashFenceKnotEntity::defineSynchedData() +{ + HangingEntity::defineSynchedData(); +} + +void LeashFenceKnotEntity::setDir(int dir) +{ + // override to do nothing, knots don't have directions +} + +int LeashFenceKnotEntity::getWidth() +{ + return 9; +} + +int LeashFenceKnotEntity::getHeight() +{ + return 9; +} + +bool LeashFenceKnotEntity::shouldRenderAtSqrDistance(double distance) +{ + return distance < 32 * 32; +} + +void LeashFenceKnotEntity::dropItem(shared_ptr causedBy) +{ + +} + +bool LeashFenceKnotEntity::save(CompoundTag *entityTag) +{ + // knots are not saved, they are recreated by the entities that are tied + return false; +} + +void LeashFenceKnotEntity::addAdditonalSaveData(CompoundTag *tag) +{ +} + +void LeashFenceKnotEntity::readAdditionalSaveData(CompoundTag *tag) +{ +} + +bool LeashFenceKnotEntity::interact(shared_ptr player) +{ + shared_ptr item = player->getCarriedItem(); + + bool attachedMob = false; + if (item != NULL && item->id == Item::lead_Id) + { + if (!level->isClientSide) + { + // look for entities that can be attached to the fence + double range = 7; + vector > *mobs = level->getEntitiesOfClass(typeid(Mob), AABB::newTemp(x - range, y - range, z - range, x + range, y + range, z + range)); + if (mobs != NULL) + { + for(AUTO_VAR(it, mobs->begin()); it != mobs->end(); ++it) + { + shared_ptr mob = dynamic_pointer_cast( *it ); + if (mob->isLeashed() && mob->getLeashHolder() == player) + { + mob->setLeashedTo(shared_from_this(), true); + attachedMob = true; + } + } + delete mobs; + } + } + } + if (!level->isClientSide && !attachedMob) + { + remove(); + + if (player->abilities.instabuild) + { + // if the player is in creative mode, attempt to remove all leashed mobs without dropping additional items + double range = 7; + vector > *mobs = level->getEntitiesOfClass(typeid(Mob), AABB::newTemp(x - range, y - range, z - range, x + range, y + range, z + range)); + if (mobs != NULL) + { + for(AUTO_VAR(it, mobs->begin()); it != mobs->end(); ++it) + { + shared_ptr mob = dynamic_pointer_cast( *it ); + if (mob->isLeashed() && mob->getLeashHolder() == shared_from_this()) + { + mob->dropLeash(true, false); + } + } + delete mobs; + } + } + } + return true; +} + +bool LeashFenceKnotEntity::survives() +{ + // knots are placed on top of fence tiles + int tile = level->getTile(xTile, yTile, zTile); + if (Tile::tiles[tile] != NULL && Tile::tiles[tile]->getRenderShape() == Tile::SHAPE_FENCE) + { + return true; + } + return false; +} + +shared_ptr LeashFenceKnotEntity::createAndAddKnot(Level *level, int x, int y, int z) +{ + shared_ptr knot = shared_ptr( new LeashFenceKnotEntity(level, x, y, z) ); + knot->forcedLoading = true; + level->addEntity(knot); + return knot; +} + +shared_ptr LeashFenceKnotEntity::findKnotAt(Level *level, int x, int y, int z) +{ + vector > *knots = level->getEntitiesOfClass(typeid(LeashFenceKnotEntity), AABB::newTemp(x - 1.0, y - 1.0, z - 1.0, x + 1.0, y + 1.0, z + 1.0)); + if (knots != NULL) + { + for(AUTO_VAR(it, knots->begin()); it != knots->end(); ++it) + { + shared_ptr knot = dynamic_pointer_cast( *it ); + if (knot->xTile == x && knot->yTile == y && knot->zTile == z) + { + delete knots; + return knot; + } + } + delete knots; + } + return nullptr; +} \ No newline at end of file diff --git a/Minecraft.World/LeashFenceKnotEntity.h b/Minecraft.World/LeashFenceKnotEntity.h new file mode 100644 index 00000000..1bf3a7b7 --- /dev/null +++ b/Minecraft.World/LeashFenceKnotEntity.h @@ -0,0 +1,36 @@ +#pragma once + +#include "HangingEntity.h" + +class LeashFenceKnotEntity : public HangingEntity +{ + +public: + eINSTANCEOF GetType() { return eTYPE_LEASHFENCEKNOT; }; + static Entity *create(Level *level) { return new LeashFenceKnotEntity(level); } + +private: + + void _init(); + +public: + LeashFenceKnotEntity(Level *level); + LeashFenceKnotEntity(Level *level, int xTile, int yTile, int zTile); + +protected: + void defineSynchedData(); + +public: + void setDir(int dir); + int getWidth(); + int getHeight(); + bool shouldRenderAtSqrDistance(double distance); + void dropItem(shared_ptr causedBy); + bool save(CompoundTag *entityTag); + void addAdditonalSaveData(CompoundTag *tag); + void readAdditionalSaveData(CompoundTag *tag); + bool interact(shared_ptr player); + virtual bool survives(); + static shared_ptr createAndAddKnot(Level *level, int x, int y, int z); + static shared_ptr findKnotAt(Level *level, int x, int y, int z); +}; \ No newline at end of file diff --git a/Minecraft.World/LeashItem.cpp b/Minecraft.World/LeashItem.cpp new file mode 100644 index 00000000..d8d7b3fc --- /dev/null +++ b/Minecraft.World/LeashItem.cpp @@ -0,0 +1,74 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.phys.h" +#include "LeashItem.h" + +LeashItem::LeashItem(int id) : Item(id) +{ +} + +bool LeashItem::useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) +{ + int tile = level->getTile(x, y, z); + if (Tile::tiles[tile] != NULL && Tile::tiles[tile]->getRenderShape() == Tile::SHAPE_FENCE) + { + if (bTestUseOnOnly) return bindPlayerMobsTest(player, level, x,y,z); + + if (level->isClientSide) + { + return true; + } + + bindPlayerMobs(player, level, x, y, z); + return true; + } + return false; +} + +bool LeashItem::bindPlayerMobs(shared_ptr player, Level *level, int x, int y, int z) +{ + // check if there is a knot at the given coordinate + shared_ptr activeKnot = LeashFenceKnotEntity::findKnotAt(level, x, y, z); + + // look for entities that can be attached to the fence + bool foundMobs = false; + double range = 7; + vector > *mobs = level->getEntitiesOfClass(typeid(Mob), AABB::newTemp(x - range, y - range, z - range, x + range, y + range, z + range)); + if (mobs != NULL) + { + for(AUTO_VAR(it,mobs->begin()); it != mobs->end(); ++it) + { + shared_ptr mob = dynamic_pointer_cast(*it); + if (mob->isLeashed() && mob->getLeashHolder() == player) + { + if (activeKnot == NULL) + { + activeKnot = LeashFenceKnotEntity::createAndAddKnot(level, x, y, z); + } + mob->setLeashedTo(activeKnot, true); + foundMobs = true; + } + } + } + return foundMobs; +} + +// 4J-JEV: Similar to bindPlayerMobs, but doesn't actually bind mobs, +bool LeashItem::bindPlayerMobsTest(shared_ptr player, Level *level, int x, int y, int z) +{ + // look for entities that can be attached to the fence + double range = 7; + vector > *mobs = level->getEntitiesOfClass(typeid(Mob), AABB::newTemp(x - range, y - range, z - range, x + range, y + range, z + range)); + + if (mobs != NULL) + { + for(AUTO_VAR(it,mobs->begin()); it != mobs->end(); ++it) + { + shared_ptr mob = dynamic_pointer_cast(*it); + if (mob->isLeashed() && mob->getLeashHolder() == player) return true; + } + } + return false; +} \ No newline at end of file diff --git a/Minecraft.World/LeashItem.h b/Minecraft.World/LeashItem.h new file mode 100644 index 00000000..373bfdfa --- /dev/null +++ b/Minecraft.World/LeashItem.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Item.h" + +class LeashItem : public Item +{ +public: + LeashItem(int id); + + bool useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); + static bool bindPlayerMobs(shared_ptr player, Level *level, int x, int y, int z); + static bool bindPlayerMobsTest(shared_ptr player, Level *level, int x, int y, int z); +}; \ No newline at end of file diff --git a/Minecraft.World/Level.cpp b/Minecraft.World/Level.cpp index 4b6a64f5..f9c383ed 100644 --- a/Minecraft.World/Level.cpp +++ b/Minecraft.World/Level.cpp @@ -18,14 +18,11 @@ #include "net.minecraft.world.level.levelgen.h" #include "net.minecraft.world.level.storage.h" #include "net.minecraft.world.level.pathfinder.h" +#include "net.minecraft.world.level.redstone.h" +#include "net.minecraft.world.scores.h" #include "net.minecraft.world.phys.h" -#include "ChunkPos.h" #include "Explosion.h" #include "LevelListener.h" -#include "LightLayer.h" -#include "MobSpawner.h" -#include "Region.h" -#include "TickNextTickData.h" #include "Level.h" #include "ThreadName.h" #include "WeighedRandom.h" @@ -41,6 +38,7 @@ #include "..\Minecraft.Client\DLCTexturePack.h" #include "..\Minecraft.Client\Common\DLC\DLCPack.h" #include "..\Minecraft.Client\PS3\PS3Extras\ShutdownManager.h" +#include "..\Minecraft.Client\MinecraftServer.h" DWORD Level::tlsIdx = TlsAlloc(); @@ -103,12 +101,80 @@ void Level::destroyLightingCache() XPhysicalFree(cache); } -void Level::initCache(lightCache_t *cache) +inline int GetIndex(int x, int y, int z) +{ + return ( ( x & 15 ) << 8 ) | ( ( y & 15 ) << 4 ) | ( z & 15 ); +} + +void Level::initCachePartial(lightCache_t *cache, int xc, int yc, int zc) { cachewritten = false; if( cache == NULL ) return; + int idx; + if( !(yc & 0xffffff00) ) + { + idx = GetIndex(xc, yc, zc); + cache[idx] = 0; + idx = GetIndex(xc - 1, yc, zc); + cache[idx] = 0; + idx = GetIndex(xc + 1, yc, zc); + cache[idx] = 0; + idx = GetIndex(xc, yc, zc - 1); + cache[idx] = 0; + idx = GetIndex(xc, yc, zc + 1); + cache[idx] = 0; + } + if( !((yc-1) & 0xffffff00) ) + { + idx = GetIndex(xc, yc - 1, zc); + cache[idx] = 0; + } + if( !((yc+1) & 0xffffff00) ) + { + idx = GetIndex(xc, yc + 1, zc); + cache[idx] = 0; + } +} + +void Level::initCacheComplete(lightCache_t *cache, int xc, int yc, int zc) +{ + lightCache_t old[7]; + if( !(yc & 0xffffff00) ) + { + old[0] = cache[GetIndex(xc, yc, zc)]; + old[1] = cache[GetIndex(xc - 1, yc, zc)]; + old[2] = cache[GetIndex(xc + 1, yc, zc)]; + old[5] = cache[GetIndex(xc, yc, zc - 1)]; + old[6] = cache[GetIndex(xc, yc, zc + 1)]; + } + if( !((yc-1) & 0xffffff00) ) + { + old[3] = cache[GetIndex(xc, yc - 1, zc)]; + } + if( !((yc+1) & 0xffffff00) ) + { + old[4] = cache[GetIndex(xc, yc + 1, zc)]; + } + XMemSet128(cache,0,16*16*16*sizeof(lightCache_t)); + + if( !(yc & 0xffffff00) ) + { + cache[GetIndex(xc, yc, zc)] = old[0]; + cache[GetIndex(xc - 1, yc, zc)] = old[1]; + cache[GetIndex(xc + 1, yc, zc)] = old[2]; + cache[GetIndex(xc, yc, zc - 1)] = old[5]; + cache[GetIndex(xc, yc, zc + 1)] = old[6]; + } + if( !((yc-1) & 0xffffff00) ) + { + cache[GetIndex(xc, yc - 1, zc)] = old[3]; + } + if( !((yc+1) & 0xffffff00) ) + { + cache[GetIndex(xc, yc + 1, zc)] = old[4]; + } } // Set a brightness value, going through the cache if enabled for this thread @@ -122,15 +188,15 @@ void inline Level::setBrightnessCached(lightCache_t *cache, __uint64 *cacheUse, if( y & 0xffffff00 ) return; // Eliminate -ve ys and values > 255 int idx = ( ( x & 15 ) << 8 ) | - ( ( y & 15 ) << 4 ) | - ( z & 15 ); + ( ( y & 15 ) << 4 ) | + ( z & 15 ); lightCache_t posbits = ( ( x & 0x3f0 ) << 6 ) | - ( ( y & 0x0f0 ) << 2 ) | - ( ( z & 0x3f0 ) >> 4 ); + ( ( y & 0x0f0 ) << 2 ) | + ( ( z & 0x3f0 ) >> 4 ); #ifdef _LARGE_WORLDS // Add in the higher bits for x and z posbits |= ( ( ((__uint64)x) & 0x3FFFC00L) << 38) | - ( ( ((__uint64)z) & 0x3FFFC00L) << 22); + ( ( ((__uint64)z) & 0x3FFFC00L) << 22); #endif lightCache_t cacheValue = cache[idx]; @@ -181,15 +247,15 @@ inline int Level::getBrightnessCached(lightCache_t *cache, LightLayer::variety l if( y & 0xffffff00 ) return getBrightness(layer, x, y, z); // Fall back on original method for out-of-bounds y int idx = ( ( x & 15 ) << 8 ) | - ( ( y & 15 ) << 4 ) | - ( z & 15 ); + ( ( y & 15 ) << 4 ) | + ( z & 15 ); lightCache_t posbits = ( ( x & 0x3f0 ) << 6 ) | - ( ( y & 0x0f0 ) << 2 ) | - ( ( z & 0x3f0 ) >> 4 ); + ( ( y & 0x0f0 ) << 2 ) | + ( ( z & 0x3f0 ) >> 4 ); #ifdef _LARGE_WORLDS // Add in the higher bits for x and z posbits |= ( ( ((__uint64)x) & 0x3FFFC00L) << 38) | - ( ( ((__uint64)z) & 0x3FFFC00L) << 22); + ( ( ((__uint64)z) & 0x3FFFC00L) << 22); #endif lightCache_t cacheValue = cache[idx]; @@ -248,15 +314,15 @@ inline int Level::getEmissionCached(lightCache_t *cache, int ct, int x, int y, i if( cache == NULL ) return Tile::lightEmission[ct]; int idx = ( ( x & 15 ) << 8 ) | - ( ( y & 15 ) << 4 ) | - ( z & 15 ); + ( ( y & 15 ) << 4 ) | + ( z & 15 ); lightCache_t posbits = ( ( x & 0x3f0 ) << 6 ) | - ( ( y & 0x0f0 ) << 2 ) | - ( ( z & 0x3f0 ) >> 4 ); + ( ( y & 0x0f0 ) << 2 ) | + ( ( z & 0x3f0 ) >> 4 ); #ifdef _LARGE_WORLDS // Add in the higher bits for x and z posbits |= ( ( ((__uint64)x) & 0x3FFFC00) << 38) | - ( ( ((__uint64)z) & 0x3FFFC00) << 22); + ( ( ((__uint64)z) & 0x3FFFC00) << 22); #endif lightCache_t cacheValue = cache[idx]; @@ -285,7 +351,7 @@ inline int Level::getEmissionCached(lightCache_t *cache, int ct, int x, int y, i #endif setBrightness(LightLayer::Block, xx, yy, zz, val, true); } - + // Update both emission & blocking values whilst we are here cacheValue = posbits | EMISSION_VALID | BLOCKING_VALID; int t = getTile(x,y,z); @@ -324,15 +390,15 @@ inline int Level::getBlockingCached(lightCache_t *cache, LightLayer::variety lay } int idx = ( ( x & 15 ) << 8 ) | - ( ( y & 15 ) << 4 ) | - ( z & 15 ); + ( ( y & 15 ) << 4 ) | + ( z & 15 ); lightCache_t posbits = ( ( x & 0x3f0 ) << 6 ) | - ( ( y & 0x0f0 ) << 2 ) | - ( ( z & 0x3f0 ) >> 4 ); + ( ( y & 0x0f0 ) << 2 ) | + ( ( z & 0x3f0 ) >> 4 ); #ifdef _LARGE_WORLDS // Add in the higher bits for x and z posbits |= ( ( ((__uint64)x) & 0x3FFFC00L) << 38) | - ( ( ((__uint64)z) & 0x3FFFC00L) << 22); + ( ( ((__uint64)z) & 0x3FFFC00L) << 22); #endif lightCache_t cacheValue = cache[idx]; @@ -361,7 +427,7 @@ inline int Level::getBlockingCached(lightCache_t *cache, LightLayer::variety lay #endif setBrightness(layer, xx, yy, zz, val, true); } - + // Update both emission & blocking values whilst we are here cacheValue = posbits | EMISSION_VALID | BLOCKING_VALID; int t = getTile(x,y,z); @@ -488,11 +554,7 @@ void Level::_init() oThunderLevel = thunderLevel = 0.0f; - lightningTime = 0; - - lightningBoltTime = 0; - - noNeighborUpdate = false; + skyFlashTime = 0; difficulty = 0; @@ -522,11 +584,10 @@ void Level::_init() InitializeCriticalSection(&m_entitiesCS); InitializeCriticalSection(&m_tileEntityListCS); - m_timeOfDayOverride = -1; - updatingTileEntities = false; villageSiege = new VillageSiege(this); + scoreboard = new Scoreboard(); toCheckLevel = new int[ 32 * 32 * 32]; // 4J - brought forward from 1.8.2 InitializeCriticalSectionAndSpinCount(&m_checkLightCS, 5120); // 4J - added for 1.8.2 lighting @@ -540,17 +601,17 @@ void Level::_init() // 4J - brought forward from 1.8.2 Biome *Level::getBiome(int x, int z) { - if (hasChunkAt(x, 0, z)) + if (hasChunkAt(x, 0, z)) { - LevelChunk *lc = getChunkAt(x, z); - if (lc != NULL) + LevelChunk *lc = getChunkAt(x, z); + if (lc != NULL) { // Water chunks at the edge of the world return NULL for their biome as they can't store it, so should fall back on the normal method below Biome *biome = lc->getBiome(x & 0xf, z & 0xf, dimension->biomeSource); - if( biome ) return biome; - } - } - return dimension->biomeSource->getBiome(x, z); + if( biome ) return biome; + } + } + return dimension->biomeSource->getBiome(x, z); } BiomeSource *Level::getBiomeSource() @@ -564,9 +625,9 @@ Level::Level(shared_ptr levelStorage, const wstring& name, Dimensi _init(); this->levelStorage = levelStorage;//shared_ptr(levelStorage); this->dimension = dimension; - this->levelData = new LevelData(levelSettings, name); + levelData = new LevelData(levelSettings, name); if( !this->levelData->useNewSeaLevel() ) seaLevel = Level::genDepth / 2; // 4J added - sea level is one unit lower since 1.8.2, maintain older height for old levels - this->savedDataStorage = new SavedDataStorage(levelStorage.get()); + savedDataStorage = new SavedDataStorage(levelStorage.get()); shared_ptr savedVillages = dynamic_pointer_cast(savedDataStorage->get(typeid(Villages), Villages::VILLAGE_FILE_ID)); if (savedVillages == NULL) @@ -587,36 +648,6 @@ Level::Level(shared_ptr levelStorage, const wstring& name, Dimensi prepareWeather(); } - -Level::Level(Level *level, Dimension *dimension) - :seaLevel( constSeaLevel ) -{ - _init(); - this->levelStorage = level->levelStorage; - this->levelData = new LevelData(level->levelData); - if( !this->levelData->useNewSeaLevel() ) seaLevel = Level::genDepth / 2; // 4J added - sea level is one unit lower since 1.8.2, maintain older height for old levels - this->savedDataStorage = new SavedDataStorage( levelStorage.get() ); - - shared_ptr savedVillages = dynamic_pointer_cast(savedDataStorage->get(typeid(Villages), Villages::VILLAGE_FILE_ID)); - if (savedVillages == NULL) - { - villages = shared_ptr(new Villages(this)); - savedDataStorage->set(Villages::VILLAGE_FILE_ID, villages); - } - else - { - villages = savedVillages; - villages->setLevel(this); - } - - this->dimension = dimension; - dimension->init(this); - chunkSource = NULL; - updateSkyBrightness(); - prepareWeather(); -} - - Level::Level(shared_ptrlevelStorage, const wstring& levelName, LevelSettings *levelSettings) : seaLevel( constSeaLevel ) { @@ -634,7 +665,7 @@ void Level::_init(shared_ptrlevelStorage, const wstring& levelName { _init(); this->levelStorage = levelStorage;//shared_ptr(levelStorage); - this->savedDataStorage = new SavedDataStorage(levelStorage.get()); + savedDataStorage = new SavedDataStorage(levelStorage.get()); shared_ptr savedVillages = dynamic_pointer_cast(savedDataStorage->get(typeid(Villages), Villages::VILLAGE_FILE_ID)); if (savedVillages == NULL) @@ -676,7 +707,7 @@ void Level::_init(shared_ptrlevelStorage, const wstring& levelName if( !this->levelData->useNewSeaLevel() ) seaLevel = Level::genDepth / 2; // 4J added - sea level is one unit lower since 1.8.2, maintain older height for old levels ((Dimension *) dimension)->init( this ); - + chunkSource = doCreateChunkSource ? createChunkSource() : NULL; // 4J - added flag so chunk source can be called from derived class instead // 4J Stu- Moved to derived classes @@ -698,6 +729,8 @@ Level::~Level() delete chunkSource; delete levelData; delete toCheckLevel; + delete scoreboard; + delete villageSiege; if( !isClientSide ) { @@ -715,8 +748,8 @@ Level::~Level() // 4J Stu - At least one of the listeners is something we cannot delete, the LevelRenderer /* for(int i = 0; i < listeners.size(); i++) - delete listeners[i]; - */ + delete listeners[i]; + */ } void Level::initializeLevel(LevelSettings *settings) @@ -791,6 +824,16 @@ int Level::getTileRenderShape(int x, int y, int z) return Tile::SHAPE_INVISIBLE; } +// 4J Added to slightly optimise and avoid getTile call if we already know the tile +int Level::getTileRenderShape(int t) +{ + if (Tile::tiles[t] != NULL) + { + return Tile::tiles[t]->getRenderShape(); + } + return Tile::SHAPE_INVISIBLE; +} + bool Level::hasChunkAt(int x, int y, int z) { if (y < minBuildHeight || y >= maxBuildHeight) return false; @@ -870,13 +913,7 @@ LevelChunk *Level::getChunk(int x, int z) return this->chunkSource->getChunk(x, z); } - -bool Level::setTileAndDataNoUpdate(int x, int y, int z, int tile, int data) -{ - return setTileAndDataNoUpdate(x, y, z, tile, data, true); -} - -bool Level::setTileAndDataNoUpdate(int x, int y, int z, int tile, int data, bool informClients) +bool Level::setTileAndData(int x, int y, int z, int tile, int data, int updateFlags) { if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) { @@ -885,56 +922,44 @@ bool Level::setTileAndDataNoUpdate(int x, int y, int z, int tile, int data, bool if (y < 0) return false; if (y >= maxBuildHeight) return false; LevelChunk *c = getChunk(x >> 4, z >> 4); - // 4J - changes for lighting brought forward from 1.8.2 + + int oldTile = 0; + if ((updateFlags & Tile::UPDATE_NEIGHBORS) != 0) + { + oldTile = c->getTile(x & 15, y, z & 15); + } bool result; #ifndef _CONTENT_PACKAGE int old = c->getTile(x & 15, y, z & 15); int olddata = c->getData( x & 15, y, z & 15); #endif result = c->setTileAndData(x & 15, y, z & 15, tile, data); + if( updateFlags != Tile::UPDATE_INVISIBLE_NO_LIGHT) + { #ifndef _CONTENT_PACKAGE - PIXBeginNamedEvent(0,"Checking light %d %d %d",x,y,z); - PIXBeginNamedEvent(0,"was %d, %d now %d, %d",old,olddata,tile,data); + PIXBeginNamedEvent(0,"Checking light %d %d %d",x,y,z); + PIXBeginNamedEvent(0,"was %d, %d now %d, %d",old,olddata,tile,data); #endif - this->checkLight(x, y, z); - PIXEndNamedEvent(); - PIXEndNamedEvent(); - if (informClients && result && (isClientSide || c->seenByPlayer)) sendTileUpdated(x, y, z); - return result; -} - - -bool Level::setTileNoUpdate(int x, int y, int z, int tile) -{ - if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) - { - return false; + checkLight(x, y, z); + PIXEndNamedEvent(); + PIXEndNamedEvent(); } - if (y < 0) return false; - if (y >= maxBuildHeight) return false; - LevelChunk *c = getChunk(x >> 4, z >> 4); - // 4J - changes for lighting brought forward from 1.8.2 - bool result = c->setTile(x & 15, y, z & 15, tile); - this->checkLight(x, y, z); - if (result && (isClientSide || c->seenByPlayer)) sendTileUpdated(x, y, z); - return result; -} - -bool Level::setTileNoUpdateNoLightCheck(int x, int y, int z, int tile) -{ - if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) + if (result) { - return false; + if ((updateFlags & Tile::UPDATE_CLIENTS) != 0 && !(isClientSide && (updateFlags & Tile::UPDATE_INVISIBLE) != 0)) + { + sendTileUpdated(x, y, z); + } + if (!isClientSide && (updateFlags & Tile::UPDATE_NEIGHBORS) != 0) + { + tileUpdated(x, y, z, oldTile); + Tile *tobj = Tile::tiles[tile]; + if (tobj != NULL && tobj->hasAnalogOutputSignal()) updateNeighbourForOutputSignal(x, y, z, tile); + } } - if (y < 0) return false; - if (y >= maxBuildHeight) return false; - LevelChunk *c = getChunk(x >> 4, z >> 4); - // 4J - changes for lighting brought forward from 1.8.2 - bool result = c->setTile(x & 15, y, z & 15, tile); return result; } - Material *Level::getMaterial(int x, int y, int z) { int t = getTile(x, y, z); @@ -942,7 +967,6 @@ Material *Level::getMaterial(int x, int y, int z) return Tile::tiles[t]->material; } - int Level::getData(int x, int y, int z) { if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) @@ -957,16 +981,7 @@ int Level::getData(int x, int y, int z) return c->getData(x, y, z); } - -void Level::setData(int x, int y, int z, int data, bool forceUpdate/*=false*/) // 4J added forceUpdate -{ - if (setDataNoUpdate(x, y, z, data) || forceUpdate) - { - tileUpdated(x, y, z, getTile(x, y, z)); - } -} - -bool Level::setDataNoUpdate(int x, int y, int z, int data) +bool Level::setData(int x, int y, int z, int data, int updateFlags, bool forceUpdate/*=false*/) // 4J added forceUpdate) { if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) { @@ -985,30 +1000,65 @@ bool Level::setDataNoUpdate(int x, int y, int z, int data) bool maskedBitsChanged; bool result = c->setData(cx, y, cz, data, importantMask, &maskedBitsChanged); - if (result && (isClientSide || (c->seenByPlayer && sendTileData && maskedBitsChanged))) sendTileUpdated(x, y, z); + if (result || forceUpdate) + { + int tile = c->getTile(cx, y, cz); + if (forceUpdate || ((updateFlags & Tile::UPDATE_CLIENTS) != 0 && !(isClientSide && (updateFlags & Tile::UPDATE_INVISIBLE) != 0))) + { + sendTileUpdated(x, y, z); + } + if (!isClientSide && (forceUpdate || (updateFlags & Tile::UPDATE_NEIGHBORS) != 0) ) + { + tileUpdated(x, y, z, tile); + Tile *tobj = Tile::tiles[tile]; + if (tobj != NULL && tobj->hasAnalogOutputSignal()) updateNeighbourForOutputSignal(x, y, z, tile); + } + } return result; } +/** +* Sets a tile to air without dropping resources or showing any animation. +* +* @param x +* @param y +* @param z +* @return +*/ +bool Level::removeTile(int x, int y, int z) +{ + return setTileAndData(x, y, z, 0, 0, Tile::UPDATE_ALL); +} -bool Level::setTile(int x, int y, int z, int tile) +/** +* Sets a tile to air and plays a destruction animation, with option to also +* drop resources. +* +* @param x +* @param y +* @param z +* @param dropResources +* @return True if anything was changed +*/ +bool Level::destroyTile(int x, int y, int z, bool dropResources) { - if (setTileNoUpdate(x, y, z, tile)) + int tile = getTile(x, y, z); + if (tile > 0) { - tileUpdated(x, y, z, tile); - return true; + int data = getData(x, y, z); + levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, x, y, z, tile + (data << Tile::TILE_NUM_SHIFT)); + if (dropResources) + { + Tile::tiles[tile]->spawnResources(this, x, y, z, data, 0); + } + return setTileAndData(x, y, z, 0, 0, Tile::UPDATE_ALL); } return false; } - -bool Level::setTileAndData(int x, int y, int z, int tile, int data) +bool Level::setTileAndUpdate(int x, int y, int z, int tile) { - if (setTileAndDataNoUpdate(x, y, z, tile, data)) - { - tileUpdated(x, y, z, tile); - return true; - } - return false; + return setTileAndData(x, y, z, tile, 0, Tile::UPDATE_ALL); } void Level::sendTileUpdated(int x, int y, int z) @@ -1022,10 +1072,9 @@ void Level::sendTileUpdated(int x, int y, int z) void Level::tileUpdated(int x, int y, int z, int tile) { - this->updateNeighborsAt(x, y, z, tile); + updateNeighborsAt(x, y, z, tile); } - void Level::lightColumnChanged(int x, int z, int y0, int y1) { PIXBeginNamedEvent(0,"LightColumnChanged (%d,%d) %d to %d",x,z,y0,y1); @@ -1073,22 +1122,6 @@ void Level::setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1) } } - -void Level::swap(int x1, int y1, int z1, int x2, int y2, int z2) -{ - int t1 = getTile(x1, y1, z1); - int d1 = getData(x1, y1, z1); - int t2 = getTile(x2, y2, z2); - int d2 = getData(x2, y2, z2); - - setTileAndDataNoUpdate(x1, y1, z1, t2, d2); - setTileAndDataNoUpdate(x2, y2, z2, t1, d1); - - updateNeighborsAt(x1, y1, z1, t2); - updateNeighborsAt(x2, y2, z2, t1); -} - - void Level::updateNeighborsAt(int x, int y, int z, int tile) { neighborChanged(x - 1, y, z, tile); @@ -1099,15 +1132,32 @@ void Level::updateNeighborsAt(int x, int y, int z, int tile) neighborChanged(x, y, z + 1, tile); } +void Level::updateNeighborsAtExceptFromFacing(int x, int y, int z, int tile, int skipFacing) +{ + if (skipFacing != Facing::WEST) neighborChanged(x - 1, y, z, tile); + if (skipFacing != Facing::EAST) neighborChanged(x + 1, y, z, tile); + if (skipFacing != Facing::DOWN) neighborChanged(x, y - 1, z, tile); + if (skipFacing != Facing::UP) neighborChanged(x, y + 1, z, tile); + if (skipFacing != Facing::NORTH) neighborChanged(x, y, z - 1, tile); + if (skipFacing != Facing::SOUTH) neighborChanged(x, y, z + 1, tile); +} void Level::neighborChanged(int x, int y, int z, int type) { - if (noNeighborUpdate || isClientSide) return; - Tile *tile = Tile::tiles[getTile(x, y, z)]; - if (tile != NULL) tile->neighborChanged(this, x, y, z, type); -} + if (isClientSide) return; + int id = getTile(x, y, z); + Tile *tile = Tile::tiles[id]; + if (tile != NULL) + { + tile->neighborChanged(this, x, y, z, type); + } +} +bool Level::isTileToBeTickedAt(int x, int y, int z, int tileId) +{ + return false; +} bool Level::canSeeSky(int x, int y, int z) { @@ -1139,13 +1189,7 @@ int Level::getRawBrightness(int x, int y, int z, bool propagate) if (propagate) { int id = getTile(x, y, z); - switch(id) - { - case Tile::stoneSlabHalf_Id: - case Tile::woodSlabHalf_Id: - case Tile::farmland_Id: - case Tile::stairs_stone_Id: - case Tile::stairs_wood_Id: + if (Tile::propagate[id]) { int br = getRawBrightness(x, y + 1, z, false); int br1 = getRawBrightness(x + 1, y, z, false); @@ -1158,8 +1202,6 @@ int Level::getRawBrightness(int x, int y, int z, bool propagate) if (br4 > br) br = br4; return br; } - break; - } } if (y < 0) return 0; @@ -1203,6 +1245,17 @@ int Level::getHeightmap(int x, int z) return c->getHeightmap(x & 15, z & 15); } +int Level::getLowestHeightmap(int x, int z) +{ + if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) + { + return 0; + } + if (!hasChunk(x >> 4, z >> 4)) return 0; + + LevelChunk *c = getChunk(x >> 4, z >> 4); + return c->lowestHeightmap; +} void Level::updateLightIfOtherThan(LightLayer::variety layer, int x, int y, int z, int expected) { @@ -1231,44 +1284,44 @@ int Level::getBrightnessPropagate(LightLayer::variety layer, int x, int y, int z { if (dimension->hasCeiling && layer == LightLayer::Sky) return 0; - if (y < 0) y = 0; - if (y >= maxBuildHeight && layer == LightLayer::Sky) + if (y < 0) y = 0; + if (y >= maxBuildHeight && layer == LightLayer::Sky) { // 4J Stu - The java LightLayer was an enum class type with a member "surrounding" which is what we // were returning here. Surrounding has the same value as the enum value in our C++ code, so just cast // it to an int return (int)layer; - } - if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) + } + if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) { // 4J Stu - The java LightLayer was an enum class type with a member "surrounding" which is what we // were returning here. Surrounding has the same value as the enum value in our C++ code, so just cast // it to an int return (int)layer; - } - int xc = x >> 4; - int zc = z >> 4; - if (!hasChunk(xc, zc)) return (int)layer; + } + int xc = x >> 4; + int zc = z >> 4; + if (!hasChunk(xc, zc)) return (int)layer; - { + { int id = tileId > -1 ? tileId : getTile(x,y,z); if (Tile::propagate[id]) { - int br = getBrightness(layer, x, y + 1, z); - int br1 = getBrightness(layer, x + 1, y, z); - int br2 = getBrightness(layer, x - 1, y, z); - int br3 = getBrightness(layer, x, y, z + 1); - int br4 = getBrightness(layer, x, y, z - 1); - if (br1 > br) br = br1; - if (br2 > br) br = br2; - if (br3 > br) br = br3; - if (br4 > br) br = br4; - return br; - } - } + int br = getBrightness(layer, x, y + 1, z); + int br1 = getBrightness(layer, x + 1, y, z); + int br2 = getBrightness(layer, x - 1, y, z); + int br3 = getBrightness(layer, x, y, z + 1); + int br4 = getBrightness(layer, x, y, z - 1); + if (br1 > br) br = br1; + if (br2 > br) br = br2; + if (br3 > br) br = br3; + if (br4 > br) br = br4; + return br; + } + } - LevelChunk *c = getChunk(xc, zc); - return c->getBrightness(layer, x & 15, y, z & 15); + LevelChunk *c = getChunk(xc, zc); + return c->getBrightness(layer, x & 15, y, z & 15); } int Level::getBrightness(LightLayer::variety layer, int x, int y, int z) @@ -1288,8 +1341,8 @@ int Level::getBrightness(LightLayer::variety layer, int x, int y, int z) if( c == NULL ) return (int)layer; - if (y < 0) y = 0; - if (y >= maxBuildHeight) y = maxBuildHeight - 1; + if (y < 0) y = 0; + if (y >= maxBuildHeight) y = maxBuildHeight - 1; return c->getBrightness(layer, x & 15, y, z & 15); } @@ -1410,9 +1463,9 @@ void Level::setTileBrightnessChanged(int x, int y, int z) int Level::getLightColor(int x, int y, int z, int emitt, int tileId/*=-1*/) { int s = getBrightnessPropagate(LightLayer::Sky, x, y, z, tileId); - int b = getBrightnessPropagate(LightLayer::Block, x, y, z, tileId); - if (b < emitt) b = emitt; - return s << 20 | b << 4; + int b = getBrightnessPropagate(LightLayer::Block, x, y, z, tileId); + if (b < emitt) b = emitt; + return s << 20 | b << 4; } float Level::getBrightness(int x, int y, int z, int emitt) @@ -1431,7 +1484,7 @@ float Level::getBrightness(int x, int y, int z) bool Level::isDay() { - return this->skyDarken < 4; + return skyDarken < 4; } @@ -1581,7 +1634,7 @@ HitResult *Level::clip(Vec3 *a, Vec3 *b, bool liquid, bool solidOnly) } -void Level::playSound(shared_ptr entity, int iSound, float volume, float pitch) +void Level::playEntitySound(shared_ptr entity, int iSound, float volume, float pitch) { if(entity == NULL) return; AUTO_VAR(itEnd, listeners.end()); @@ -1591,8 +1644,8 @@ void Level::playSound(shared_ptr entity, int iSound, float volume, float if(entity->GetType() == eTYPE_SERVERPLAYER) { //app.DebugPrintf("ENTITY is serverplayer\n"); - - (*it)->playSound(entity,iSound, entity->x, entity->y - entity->heightOffset, entity->z, volume, pitch); + + (*it)->playSound(iSound, entity->x, entity->y - entity->heightOffset, entity->z, volume, pitch); } else { @@ -1601,6 +1654,15 @@ void Level::playSound(shared_ptr entity, int iSound, float volume, float } } +void Level::playPlayerSound(shared_ptr entity, int iSound, float volume, float pitch) +{ + if (entity == NULL) return; + AUTO_VAR(itEnd, listeners.end()); + for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) + { + (*it)->playSoundExceptPlayer(entity, iSound, entity->x, entity->y - entity->heightOffset, entity->z, volume, pitch); + } +} //void Level::playSound(double x, double y, double z, const wstring& name, float volume, float pitch) void Level::playSound(double x, double y, double z, int iSound, float volume, float pitch, float fClipSoundDist) @@ -1612,7 +1674,7 @@ void Level::playSound(double x, double y, double z, int iSound, float volume, fl } } -void Level::playLocalSound(double x, double y, double z, int iSound, float volume, float pitch, float fClipSoundDist) +void Level::playLocalSound(double x, double y, double z, int iSound, float volume, float pitch, bool distanceDelay, float fClipSoundDist) { } @@ -1634,9 +1696,9 @@ void Level::playMusic(double x, double y, double z, const wstring& string, float /* void Level::addParticle(const wstring& id, double x, double y, double z, double xd, double yd, double zd) { - AUTO_VAR(itEnd, listeners.end()); - for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) - (*it)->addParticle(id, x, y, z, xd, yd, zd); +AUTO_VAR(itEnd, listeners.end()); +for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) +(*it)->addParticle(id, x, y, z, xd, yd, zd); } */ @@ -1666,15 +1728,15 @@ bool Level::addEntity(shared_ptr e) return false; } - bool forced = false; - if (dynamic_pointer_cast( e ) != NULL) + bool forced = e->forcedLoading; + if (e->instanceof(eTYPE_PLAYER)) { forced = true; } if (forced || hasChunk(xc, zc)) { - if (dynamic_pointer_cast( e ) != NULL) + if (e->instanceof(eTYPE_PLAYER)) { shared_ptr player = dynamic_pointer_cast(e); @@ -1744,7 +1806,7 @@ void Level::removeEntity(shared_ptr e) e->ride(nullptr); } e->remove(); - if (dynamic_pointer_cast( e ) != NULL) + if (e->instanceof(eTYPE_PLAYER)) { vector >::iterator it = players.begin(); vector >::iterator itEnd = players.end(); @@ -1766,7 +1828,7 @@ void Level::removeEntityImmediately(shared_ptr e) { e->remove(); - if (dynamic_pointer_cast( e ) != NULL) + if (e->instanceof(eTYPE_PLAYER)) { vector >::iterator it = players.begin(); vector >::iterator itEnd = players.end(); @@ -1823,7 +1885,7 @@ void Level::removeListener(LevelListener *listener) // 4J - added noEntities and blockAtEdge parameter -AABBList *Level::getCubes(shared_ptr source, AABB *box, bool noEntities, bool blockAtEdge) +AABBList *Level::getCubes(shared_ptr source, AABB *box, bool noEntities/* = false*/, bool blockAtEdge/* = false*/) { boxes.clear(); int x0 = Mth::floor(box->x0); @@ -1843,7 +1905,7 @@ AABBList *Level::getCubes(shared_ptr source, AABB *box, bool noEntities, { for (int y = y0 - 1; y < y1; y++) { - Tile::rock->addAABBs(this, x, y, z, box, &boxes, source); + Tile::stone->addAABBs(this, x, y, z, box, &boxes, source); } } else @@ -1861,62 +1923,62 @@ AABBList *Level::getCubes(shared_ptr source, AABB *box, bool noEntities, } } } - // 4J - also stop player falling out of the bottom of the map if blockAtEdge is true. Again, rock is an arbitrary choice here - // 4J Stu - Don't stop entities falling into the void while in The End (it has no bedrock) - if( blockAtEdge && ( ( y0 - 1 ) < 0 ) && dimension->id != 1 ) - { - for (int y = y0 - 1; y < 0; y++) + // 4J - also stop player falling out of the bottom of the map if blockAtEdge is true. Again, rock is an arbitrary choice here + // 4J Stu - Don't stop entities falling into the void while in The End (it has no bedrock) + if( blockAtEdge && ( ( y0 - 1 ) < 0 ) && dimension->id != 1 ) { - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) - { - Tile::rock->addAABBs(this, x, y, z, box, &boxes, source ); - } + for (int y = y0 - 1; y < 0; y++) + { + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + Tile::stone->addAABBs(this, x, y, z, box, &boxes, source ); + } + } } - } - // 4J - final bounds check - limit vertical movement so we can't move above maxMovementHeight - if( blockAtEdge && ( y1 > maxMovementHeight ) ) - { - for (int y = maxMovementHeight; y < y1; y++) + // 4J - final bounds check - limit vertical movement so we can't move above maxMovementHeight + if( blockAtEdge && ( y1 > maxMovementHeight ) ) { - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) - { - Tile::rock->addAABBs(this, x, y, z, box, &boxes, source ); - } + for (int y = maxMovementHeight; y < y1; y++) + { + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + Tile::stone->addAABBs(this, x, y, z, box, &boxes, source ); + } + } } - } - // 4J - now add in collision for any blocks which have actually been removed, but haven't had their render data updated to reflect this yet. This is to stop the player - // being able to move the view position inside a tile which is (visually) still there, and see out of the world. This is particularly a problem when moving upwards in - // creative mode as the player can get very close to the edge of tiles whilst looking upwards and can therefore very quickly move inside one. - Minecraft::GetInstance()->levelRenderer->destroyedTileManager->addAABBs( this, box, &boxes); - - // 4J - added - if( noEntities ) return &boxes; - - double r = 0.25; - vector > *ee = getEntities(source, box->grow(r, r, r)); - vector >::iterator itEnd = ee->end(); - for (AUTO_VAR(it, ee->begin()); it != itEnd; it++) - { - AABB *collideBox = (*it)->getCollideBox(); - if (collideBox != NULL && collideBox->intersects(box)) + // 4J - now add in collision for any blocks which have actually been removed, but haven't had their render data updated to reflect this yet. This is to stop the player + // being able to move the view position inside a tile which is (visually) still there, and see out of the world. This is particularly a problem when moving upwards in + // creative mode as the player can get very close to the edge of tiles whilst looking upwards and can therefore very quickly move inside one. + Minecraft::GetInstance()->levelRenderer->destroyedTileManager->addAABBs( this, box, &boxes); + + // 4J - added + if( noEntities ) return &boxes; + + double r = 0.25; + vector > *ee = getEntities(source, box->grow(r, r, r)); + vector >::iterator itEnd = ee->end(); + for (AUTO_VAR(it, ee->begin()); it != itEnd; it++) { - boxes.push_back(collideBox); - } + AABB *collideBox = (*it)->getCollideBox(); + if (collideBox != NULL && collideBox->intersects(box)) + { + boxes.push_back(collideBox); + } - collideBox = source->getCollideAgainstBox(*it); - if (collideBox != NULL && collideBox->intersects(box)) - { - boxes.push_back(collideBox); + collideBox = source->getCollideAgainstBox(*it); + if (collideBox != NULL && collideBox->intersects(box)) + { + boxes.push_back(collideBox); + } } - } - return &boxes; + return &boxes; } // 4J Stu - Brought forward from 12w36 to fix #46282 - TU5: Gameplay: Exiting the minecart in a tight corridor damages the player -AABBList *Level::getTileCubes(AABB *box, bool blockAtEdge) +AABBList *Level::getTileCubes(AABB *box, bool blockAtEdge/* = false */) { return getCubes(nullptr, box, true, blockAtEdge); //boxes.clear(); @@ -1969,19 +2031,19 @@ int Level::getOldSkyDarken(float a) //4J - change brought forward from 1.8.2 float Level::getSkyDarken(float a) { - float td = getTimeOfDay(a); + float td = getTimeOfDay(a); - float br = 1 - (Mth::cos(td * PI * 2) * 2 + 0.2f); - if (br < 0.0f) br = 0.0f; - if (br > 1.0f) br = 1.0f; + float br = 1 - (Mth::cos(td * PI * 2) * 2 + 0.2f); + if (br < 0.0f) br = 0.0f; + if (br > 1.0f) br = 1.0f; - br = 1.0f - br; + br = 1.0f - br; - br *= 1.0f - (getRainLevel(a) * 5.0f / 16.0f); - br *= 1.0f - (getThunderLevel(a) * 5.0f / 16.0f); - // return ((int) (br * 13)); + br *= 1.0f - (getRainLevel(a) * 5.0f / 16.0f); + br *= 1.0f - (getThunderLevel(a) * 5.0f / 16.0f); + // return ((int) (br * 13)); - return br * 0.8f + 0.2f; + return br * 0.8f + 0.2f; } @@ -2028,9 +2090,9 @@ Vec3 *Level::getSkyColor(shared_ptr source, float a) b = b * ba + mid * (1 - ba); } - if (lightningBoltTime > 0) + if (skyFlashTime > 0) { - float f = (lightningBoltTime - a); + float f = (skyFlashTime - a); if (f > 1) f = 1; f = f * 0.45f; r = r * (1 - f) + 0.8f * f; @@ -2052,19 +2114,17 @@ float Level::getTimeOfDay(float a) /* if (this != NULL) return 0.5f; */ // 4J Added if so we can override timeOfDay without changing the time that affects ticking of things - if( m_timeOfDayOverride >= 0 ) - { - return dimension->getTimeOfDay(m_timeOfDayOverride, a); - } - else - { - return dimension->getTimeOfDay(levelData->getTime(), a);; - } + return dimension->getTimeOfDay(levelData->getDayTime(), a);; +} + +int Level::getMoonPhase() +{ + return dimension->getMoonPhase(levelData->getDayTime()); } -int Level::getMoonPhase(float a) +float Level::getMoonBrightness() { - return dimension->getMoonPhase(levelData->getTime(), a); + return Dimension::MOON_BRIGHTNESS_PER_PHASE[dimension->getMoonPhase(levelData->getDayTime())]; } float Level::getSunAngle(float a) @@ -2185,26 +2245,28 @@ float Level::getStarBrightness(float a) return br * br * 0.5f; } - void Level::addToTickNextTick(int x, int y, int z, int tileId, int tickDelay) { } -void Level::forceAddTileTick(int x, int y, int z, int tileId, int tickDelay) +void Level::addToTickNextTick(int x, int y, int z, int tileId, int tickDelay, int priorityTilt) +{ +} + +void Level::forceAddTileTick(int x, int y, int z, int tileId, int tickDelay, int prioTilt) { } void Level::tickEntities() { - //for (int i = 0; i < globalEntities.size(); i++) vector >::iterator itGE = globalEntities.begin(); while( itGE != globalEntities.end() ) { - shared_ptr e = *itGE;//globalEntities.at(i); + shared_ptr e = *itGE; + e->tickCount++; e->tick(); if (e->removed) { - //globalEntities.remove(i--); itGE = globalEntities.erase( itGE ); } else @@ -2213,7 +2275,6 @@ void Level::tickEntities() } } - //entities.removeAll(entitiesToRemove); EnterCriticalSection(&m_entitiesCS); for( AUTO_VAR(it, entities.begin()); it != entities.end(); ) @@ -2261,14 +2322,14 @@ void Level::tickEntities() //for (int i = 0; i < entities.size(); i++) /* 4J Jev, using an iterator causes problems here as - * the vector is modified from inside this loop. - */ + * the vector is modified from inside this loop. + */ EnterCriticalSection(&m_entitiesCS); for (unsigned int i = 0; i < entities.size(); ) { shared_ptr e = entities.at(i); - + if (e->riding != NULL) { if (e->riding->removed || e->riding->rider.lock() != e) @@ -2286,7 +2347,7 @@ void Level::tickEntities() if (!e->removed) { #ifndef _FINAL_BUILD - if(!( app.DebugSettingsOn() && app.GetMobsDontTickEnabled() && (dynamic_pointer_cast(e) != NULL) && (dynamic_pointer_cast(e) == NULL))) + if ( !( app.DebugSettingsOn() && app.GetMobsDontTickEnabled() && e->instanceof(eTYPE_MOB) && !e->instanceof(eTYPE_PLAYER)) ) #endif { tick(e); @@ -2357,7 +2418,7 @@ void Level::tickEntities() } updatingTileEntities = false; -// 4J-PB - Stuart - check this is correct here + // 4J-PB - Stuart - check this is correct here if (!tileEntitiesToUnload.empty()) { @@ -2407,7 +2468,7 @@ void Level::tickEntities() if (lc != NULL) lc->setTileEntity(e->x & 15, e->y, e->z & 15, e); } - sendTileUpdated(e->x, e->y, e->z); + sendTileUpdated(e->x, e->y, e->z); } } pendingTileEntities.clear(); @@ -2469,6 +2530,7 @@ void Level::tick(shared_ptr e, bool actual) if (actual && e->inChunk ) #endif { + e->tickCount++; if (e->riding != NULL) { e->rideTick(); @@ -2677,7 +2739,9 @@ bool Level::checkAndHandleWater(AABB *box, Material *material, shared_ptrlength() > 0) + } + } + if (current->length() > 0 && e->isPushedByWater()) { current = current->normalize(); double pow = 0.014; @@ -2713,7 +2779,9 @@ bool Level::containsMaterial(AABB *box, Material *material) int z1 = Mth::floor(box->z1 + 1); for (int x = x0; x < x1; x++) + { for (int y = y0; y < y1; y++) + { for (int z = z0; z < z1; z++) { Tile *tile = Tile::tiles[getTile(x, y, z)]; @@ -2722,6 +2790,8 @@ bool Level::containsMaterial(AABB *box, Material *material) return true; } } + } + } return false; } @@ -2736,7 +2806,9 @@ bool Level::containsLiquid(AABB *box, Material *material) int z1 = Mth::floor(box->z1 + 1); for (int x = x0; x < x1; x++) + { for (int y = y0; y < y1; y++) + { for (int z = z0; z < z1; z++) { Tile *tile = Tile::tiles[getTile(x, y, z)]; @@ -2754,6 +2826,8 @@ bool Level::containsLiquid(AABB *box, Material *material) } } } + } + } return false; } @@ -2795,7 +2869,7 @@ float Level::getSeenPercent(Vec3 *center, AABB *bb) count++; } - return hits / (float) count; + return hits / (float) count; } @@ -2811,7 +2885,7 @@ bool Level::extinguishFire(shared_ptr player, int x, int y, int z, int f if (getTile(x, y, z) == Tile::fire_Id) { levelEvent(player, LevelEvent::SOUND_FIZZ, x, y, z, 0); - setTile(x, y, z, 0); + removeTile(x, y, z); return true; } return false; @@ -2820,7 +2894,7 @@ bool Level::extinguishFire(shared_ptr player, int x, int y, int z, int f /* shared_ptr Level::findSubclassOf(Entity::Class *entityClass) { - return shared_ptr(); +return shared_ptr(); } */ @@ -2829,7 +2903,7 @@ wstring Level::gatherStats() { wchar_t buf[64]; EnterCriticalSection(&m_entitiesCS); - swprintf(buf,64,L"All:%d",this->entities.size()); + swprintf(buf,64,L"All:%d",entities.size()); LeaveCriticalSection(&m_entitiesCS); return wstring(buf); } @@ -2843,81 +2917,110 @@ wstring Level::gatherChunkSourceStats() shared_ptr Level::getTileEntity(int x, int y, int z) { - if (y >= Level::maxBuildHeight) + if (y < minBuildHeight || y >= maxBuildHeight) { return nullptr; } - LevelChunk *lc = getChunk(x >> 4, z >> 4); - if (lc != NULL) return lc->getTileEntity(x & 15, y, z & 15); + shared_ptr tileEntity = nullptr; - if (lc != NULL) + if (updatingTileEntities) { - shared_ptr tileEntity = lc->getTileEntity(x & 15, y, z & 15); - - if (tileEntity == NULL) + EnterCriticalSection(&m_tileEntityListCS); + for (int i = 0; i < pendingTileEntities.size(); i++) { - EnterCriticalSection(&m_tileEntityListCS); - for( AUTO_VAR(it, pendingTileEntities.begin()); it != pendingTileEntities.end(); it++ ) + shared_ptr e = pendingTileEntities.at(i); + if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) { - shared_ptr e = *it; - - if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) - { - tileEntity = e; - break; - } - } - LeaveCriticalSection(&m_tileEntityListCS); - } - return tileEntity; - } - - return nullptr; -} + tileEntity = e; + break; + } + } + LeaveCriticalSection(&m_tileEntityListCS); + } + + if (tileEntity == NULL) + { + LevelChunk *lc = getChunk(x >> 4, z >> 4); + if (lc != NULL) + { + tileEntity = lc->getTileEntity(x & 15, y, z & 15); + } + } + + if (tileEntity == NULL) + { + EnterCriticalSection(&m_tileEntityListCS); + for( AUTO_VAR(it, pendingTileEntities.begin()); it != pendingTileEntities.end(); it++ ) + { + shared_ptr e = *it; + + if (!e->isRemoved() && e->x == x && e->y == y && e->z == z) + { + tileEntity = e; + break; + } + } + LeaveCriticalSection(&m_tileEntityListCS); + } + return tileEntity; +} void Level::setTileEntity(int x, int y, int z, shared_ptr tileEntity) { - if (tileEntity != NULL && !tileEntity->isRemoved()) + if (tileEntity != NULL && !tileEntity->isRemoved()) { EnterCriticalSection(&m_tileEntityListCS); - if (updatingTileEntities) + if (updatingTileEntities) { - tileEntity->x = x; - tileEntity->y = y; - tileEntity->z = z; - pendingTileEntities.push_back(tileEntity); - } + tileEntity->x = x; + tileEntity->y = y; + tileEntity->z = z; + + // avoid adding duplicates + for( AUTO_VAR(it, pendingTileEntities.begin()); it != pendingTileEntities.end();) + { + shared_ptr next = *it; + if (next->x == x && next->y == y && next->z == z) + { + next->setRemoved(); + it = pendingTileEntities.erase(it); + } + else + { + ++it; + } + } + + pendingTileEntities.push_back(tileEntity); + } else { - tileEntityList.push_back(tileEntity); + tileEntityList.push_back(tileEntity); LevelChunk *lc = getChunk(x >> 4, z >> 4); if (lc != NULL) lc->setTileEntity(x & 15, y, z & 15, tileEntity); } LeaveCriticalSection(&m_tileEntityListCS); } - - } - void Level::removeTileEntity(int x, int y, int z) { EnterCriticalSection(&m_tileEntityListCS); - shared_ptr te = getTileEntity(x, y, z); - if (te != NULL && updatingTileEntities) + shared_ptr te = getTileEntity(x, y, z); + if (te != NULL && updatingTileEntities) { - te->setRemoved(); + te->setRemoved(); AUTO_VAR(it, find(pendingTileEntities.begin(), pendingTileEntities.end(), te )); if( it != pendingTileEntities.end() ) { pendingTileEntities.erase(it); } - } + } else { - if (te != NULL) + if (te != NULL) { AUTO_VAR(it, find(pendingTileEntities.begin(), pendingTileEntities.end(), te )); if( it != pendingTileEntities.end() ) @@ -2929,7 +3032,7 @@ void Level::removeTileEntity(int x, int y, int z) { tileEntityList.erase(it2); } - } + } LevelChunk *lc = getChunk(x >> 4, z >> 4); if (lc != NULL) lc->removeTileEntity(x & 15, y, z & 15); } @@ -2945,7 +3048,7 @@ bool Level::isSolidRenderTile(int x, int y, int z) { Tile *tile = Tile::tiles[getTile(x, y, z)]; if (tile == NULL) return false; - + // 4J - addition here to make rendering big blocks of leaves more efficient. Normally leaves never consider themselves as solid, so // blocks of leaves will have all sides of each block completely visible. Changing to consider as solid if this block is surrounded by // other leaves (or solid things). This is paired with another change in Tile::getTexture which makes such solid tiles actually visibly solid (these @@ -2978,51 +3081,67 @@ bool Level::isSolidBlockingTile(int x, int y, int z) } /** - * This method does the same as isSolidBlockingTile, except it will not - * check the tile if the coordinates is in an unloaded or empty chunk. This - * is to help vs the problem of "popping" torches in SMP. - */ +* This method does the same as isSolidBlockingTile, except it will not +* check the tile if the coordinates is in an unloaded or empty chunk. This +* is to help vs the problem of "popping" torches in SMP. +*/ bool Level::isSolidBlockingTileInLoadedChunk(int x, int y, int z, bool valueIfNotLoaded) { - if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) + if (x < -MAX_LEVEL_SIZE || z < -MAX_LEVEL_SIZE || x >= MAX_LEVEL_SIZE || z >= MAX_LEVEL_SIZE) { - return valueIfNotLoaded; - } - LevelChunk *chunk = chunkSource->getChunk(x >> 4, z >> 4); - if (chunk == NULL || chunk->isEmpty()) + return valueIfNotLoaded; + } + LevelChunk *chunk = chunkSource->getChunk(x >> 4, z >> 4); + if (chunk == NULL || chunk->isEmpty()) { - return valueIfNotLoaded; - } + return valueIfNotLoaded; + } - Tile *tile = Tile::tiles[getTile(x, y, z)]; - if (tile == NULL) return false; - return tile->material->isSolidBlocking() && tile->isCubeShaped(); + Tile *tile = Tile::tiles[getTile(x, y, z)]; + if (tile == NULL) return false; + return tile->material->isSolidBlocking() && tile->isCubeShaped(); +} + +bool Level::isFullAABBTile(int x, int y, int z) +{ + int tile = getTile(x, y, z); + if (tile == 0 || Tile::tiles[tile] == NULL) + { + return false; + } + AABB *aabb = Tile::tiles[tile]->getAABB(this, x, y, z); + return aabb != NULL && aabb->getSize() >= 1; } -// 4J - brought forward from 1.3.2 bool Level::isTopSolidBlocking(int x, int y, int z) { - // Temporary workaround until tahgs per-face solidity is finished - Tile *tile = Tile::tiles[getTile(x, y, z)]; - if (tile == NULL) return false; + // Temporary workaround until tahgs per-face solidity is finished + Tile *tile = Tile::tiles[getTile(x, y, z)]; + return isTopSolidBlocking(tile, getData(x, y, z)); +} - if (tile->material->isSolidBlocking() && tile->isCubeShaped()) return true; +bool Level::isTopSolidBlocking(Tile *tile, int data) +{ + if (tile == NULL) return false; + + if (tile->material->isSolidBlocking() && tile->isCubeShaped()) return true; if (dynamic_cast(tile) != NULL) { - return (getData(x, y, z) & StairTile::UPSIDEDOWN_BIT) == StairTile::UPSIDEDOWN_BIT; + return (data & StairTile::UPSIDEDOWN_BIT) == StairTile::UPSIDEDOWN_BIT; } - if (dynamic_cast(tile) != NULL) + if (dynamic_cast(tile) != NULL) { - return (getData(x, y, z) & HalfSlabTile::TOP_SLOT_BIT) == HalfSlabTile::TOP_SLOT_BIT; + return (data & HalfSlabTile::TOP_SLOT_BIT) == HalfSlabTile::TOP_SLOT_BIT; } - if (dynamic_cast(tile) != NULL) return (getData(x, y, z) & TopSnowTile::HEIGHT_MASK) == TopSnowTile::MAX_HEIGHT + 1; - return false; + if (dynamic_cast(tile) != NULL) return true; + if (dynamic_cast(tile) != NULL) return (data & TopSnowTile::HEIGHT_MASK) == TopSnowTile::MAX_HEIGHT + 1; + return false; } void Level::updateSkyBrightness() { - int newDark = this->getOldSkyDarken(1); + int newDark = getOldSkyDarken(1); if (newDark != skyDarken) { skyDarken = newDark; @@ -3046,10 +3165,10 @@ void Level::prepareWeather() { if (levelData->isRaining()) { - this->rainLevel = 1; + rainLevel = 1; if (levelData->isThundering()) { - this->thunderLevel = 1; + thunderLevel = 1; } } } @@ -3073,11 +3192,6 @@ void Level::tickWeather() } #endif - if (lightningTime > 0) - { - lightningTime--; - } - int thunderTime = levelData->getThunderTime(); if (thunderTime <= 0) { @@ -3120,9 +3234,9 @@ void Level::tickWeather() { levelData->setRaining(!levelData->isRaining()); } -/* if( !levelData->isRaining() ) + /* if( !levelData->isRaining() ) { - levelData->setRaining(true); + levelData->setRaining(true); }*/ } @@ -3153,8 +3267,8 @@ void Level::tickWeather() void Level::toggleDownfall() { - // this will trick the tickWeather method to toggle rain next tick - levelData->setRainTime(1); + // this will trick the tickWeather method to toggle rain next tick + levelData->setRainTime(1); } void Level::buildAndPrepareChunksToPoll() @@ -3205,7 +3319,7 @@ void Level::buildAndPrepareChunksToPoll() delete [] xx; delete [] zz; #endif - + if (delayUntilNextMoodSound > 0) delayUntilNextMoodSound--; // 4J Stu - Added 1.2.3, but not sure if we want to do it @@ -3226,7 +3340,7 @@ void Level::tickClientSideTiles(int xo, int zo, LevelChunk *lc) { //lc->tick(); // 4J - brought this lighting update forward from 1.8.2 - if (delayUntilNextMoodSound == 0) + if (delayUntilNextMoodSound == 0 && !isClientSide) { randValue = randValue * 3 + addend; int val = (randValue >> 2); @@ -3248,7 +3362,7 @@ void Level::tickClientSideTiles(int xo, int zo, LevelChunk *lc) #else this->playSound(x + 0.5, y + 0.5, z + 0.5,eSoundType_AMBIENT_CAVE_CAVE, 0.7f, 0.8f + random->nextFloat() * 0.2f); #endif - delayUntilNextMoodSound = random->nextInt(20 * 60 * 10) + 20 * 60 * 5; + delayUntilNextMoodSound = random->nextInt(SharedConstants::TICKS_PER_SECOND * 60 * 10) + SharedConstants::TICKS_PER_SECOND * 60 * 5; } } } @@ -3264,123 +3378,94 @@ void Level::tickTiles() bool Level::shouldFreezeIgnoreNeighbors(int x, int y, int z) { - return shouldFreeze(x, y, z, false); + return shouldFreeze(x, y, z, false); } bool Level::shouldFreeze(int x, int y, int z) { - return shouldFreeze(x, y, z, true); + return shouldFreeze(x, y, z, true); } bool Level::shouldFreeze(int x, int y, int z, bool checkNeighbors) { - Biome *biome = getBiome(x, z); - float temp = biome->getTemperature(); - if (temp > 0.15f) return false; + Biome *biome = getBiome(x, z); + float temp = biome->getTemperature(); + if (temp > 0.15f) return false; - if (y >= 0 && y < maxBuildHeight && getBrightness(LightLayer::Block, x, y, z) < 10) + if (y >= 0 && y < maxBuildHeight && getBrightness(LightLayer::Block, x, y, z) < 10) { - int current = getTile(x, y, z); - if ((current == Tile::calmWater_Id || current == Tile::water_Id) && getData(x, y, z) == 0) + int current = getTile(x, y, z); + if ((current == Tile::calmWater_Id || current == Tile::water_Id) && getData(x, y, z) == 0) { - if (!checkNeighbors) return true; - - bool surroundedByWater = true; - if (surroundedByWater && getMaterial(x - 1, y, z) != Material::water) surroundedByWater = false; - if (surroundedByWater && getMaterial(x + 1, y, z) != Material::water) surroundedByWater = false; - if (surroundedByWater && getMaterial(x, y, z - 1) != Material::water) surroundedByWater = false; - if (surroundedByWater && getMaterial(x, y, z + 1) != Material::water) surroundedByWater = false; - if (!surroundedByWater) return true; - } - } - return false; + if (!checkNeighbors) return true; + + bool surroundedByWater = true; + if (surroundedByWater && getMaterial(x - 1, y, z) != Material::water) surroundedByWater = false; + if (surroundedByWater && getMaterial(x + 1, y, z) != Material::water) surroundedByWater = false; + if (surroundedByWater && getMaterial(x, y, z - 1) != Material::water) surroundedByWater = false; + if (surroundedByWater && getMaterial(x, y, z + 1) != Material::water) surroundedByWater = false; + if (!surroundedByWater) return true; + } + } + return false; } bool Level::shouldSnow(int x, int y, int z) { - Biome *biome = getBiome(x, z); - float temp = biome->getTemperature(); - if (temp > 0.15f) return false; + Biome *biome = getBiome(x, z); + float temp = biome->getTemperature(); + if (temp > 0.15f) return false; - if (y >= 0 && y < maxBuildHeight && getBrightness(LightLayer::Block, x, y, z) < 10) + if (y >= 0 && y < maxBuildHeight && getBrightness(LightLayer::Block, x, y, z) < 10) { - int below = getTile(x, y - 1, z); - int current = getTile(x, y, z); - if (current == 0) + int below = getTile(x, y - 1, z); + int current = getTile(x, y, z); + if (current == 0) { - if (Tile::topSnow->mayPlace(this, x, y, z) && (below != 0 && below != Tile::ice_Id && Tile::tiles[below]->material->blocksMotion())) + if (Tile::topSnow->mayPlace(this, x, y, z) && (below != 0 && below != Tile::ice_Id && Tile::tiles[below]->material->blocksMotion())) { - return true; - } - } - } + return true; + } + } + } - return false; + return false; } - void Level::checkLight(int x, int y, int z, bool force, bool rootOnlyEmissive) // 4J added force, rootOnlyEmissive parameters { - if (!dimension->hasCeiling) checkLight(LightLayer::Sky, x, y, z, force, false); - checkLight(LightLayer::Block, x, y, z, force, rootOnlyEmissive); + if (!dimension->hasCeiling) checkLight(LightLayer::Sky, x, y, z, force, false); + checkLight(LightLayer::Block, x, y, z, force, rootOnlyEmissive); } -int Level::getExpectedSkyColor(lightCache_t *cache, int oc, int x, int y , int z, int ct, int block) -{ - int expected = 0; - - if( block == 255 ) return 0; // 4J added as optimisation - if (canSeeSky(x, y, z)) - { - expected = 15; - } - else - { - if (block == 0) block = 1; - - // 4J - changed this to attempt to get all 6 brightnesses of neighbours in a single call, as an optimisation - int b[6]; - b[0] = getBrightnessCached(cache, LightLayer::Sky, x - 1, y, z); - b[1] = getBrightnessCached(cache, LightLayer::Sky, x + 1, y, z); - b[2] = getBrightnessCached(cache, LightLayer::Sky, x, y - 1, z); - b[3] = getBrightnessCached(cache, LightLayer::Sky, x, y + 1, z); - b[4] = getBrightnessCached(cache, LightLayer::Sky, x, y, z - 1); - b[5] = getBrightnessCached(cache, LightLayer::Sky, x, y, z + 1); - for( int i = 0; i < 6; i++ ) - { - if( ( b[i] - block ) > expected ) expected = b[i] - block; - } - } - - return expected; -} - -int Level::getExpectedBlockColor(lightCache_t *cache, int oc, int x, int y, int z, int ct, int block, bool propagatedOnly) +int Level::getExpectedLight(lightCache_t *cache, int x, int y, int z, LightLayer::variety layer, bool propagatedOnly) { - int expected = propagatedOnly ? 0 : getEmissionCached(cache, ct, x, y, z); + if (layer == LightLayer::Sky && canSeeSky(x, y, z)) return MAX_BRIGHTNESS; + int id = getTile(x, y, z); + int result = layer == LightLayer::Sky ? 0 : Tile::lightEmission[id]; + int block = Tile::lightBlock[id]; + if (block >= MAX_BRIGHTNESS && Tile::lightEmission[id] > 0) block = 1; + if (block < 1) block = 1; + if (block >= MAX_BRIGHTNESS) + { + return propagatedOnly ? 0 : getEmissionCached(cache, 0, x, y, z); + } - if( block >= 15 ) return expected; // 4J added as optimisation + if (result >= MAX_BRIGHTNESS - 1) return result; - // 4J - changed this to attempt to get all 6 brightnesses of neighbours in a single call, as an optimisation - int b[6]; - b[0] = getBrightnessCached(cache, LightLayer::Block, x - 1, y, z); - b[1] = getBrightnessCached(cache, LightLayer::Block, x + 1, y, z); - b[2] = getBrightnessCached(cache, LightLayer::Block, x, y - 1, z); - b[3] = getBrightnessCached(cache, LightLayer::Block, x, y + 1, z); - b[4] = getBrightnessCached(cache, LightLayer::Block, x, y, z - 1); - b[5] = getBrightnessCached(cache, LightLayer::Block, x, y, z + 1); - for( int i = 0; i < 6; i++ ) + for (int face = 0; face < 6; face++) { - if( ( b[i] - block ) > expected ) expected = b[i] - block; - } + int xx = x + Facing::STEP_X[face]; + int yy = y + Facing::STEP_Y[face]; + int zz = z + Facing::STEP_Z[face]; + int brightness = getBrightnessCached(cache, layer, xx, yy, zz) - block; - return expected; -} + if (brightness > result) result = brightness; + if (result >= MAX_BRIGHTNESS - 1) return result; + } -inline int GetIndex(int x, int y, int z) -{ - return ( ( x & 15 ) << 8 ) | ( ( y & 15 ) << 4 ) | ( z & 15 ); + return result; } // 4J - Made changes here so that lighting goes through a cache, if enabled for this thread @@ -3397,12 +3482,12 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool f else { // 4J - this is normal java behaviour - if (!hasChunksAt(xc, yc, zc, 17)) return; + if (!hasChunksAt(xc, yc, zc, 17)) return; } #if 0 ///////////////////////////////////////////////////////////////////////////////////////////// - // Get the frequency of the timer + // Get the frequency of the timer LARGE_INTEGER qwTicksPerSec, qwTime, qwNewTime, qwDeltaTime1, qwDeltaTime2; float fElapsedTime1 = 0.0f; float fElapsedTime2 = 0.0f; @@ -3415,42 +3500,10 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool f EnterCriticalSection(&m_checkLightCS); -#ifdef __PSVITA__ - // AP - only clear the one array element required to check if something has changed - cachewritten = false; - if( cache != NULL ) - { - int idx; - if( !(yc & 0xffffff00) ) - { - idx = GetIndex(xc, yc, zc); - cache[idx] = 0; - idx = GetIndex(xc - 1, yc, zc); - cache[idx] = 0; - idx = GetIndex(xc + 1, yc, zc); - cache[idx] = 0; - idx = GetIndex(xc, yc, zc - 1); - cache[idx] = 0; - idx = GetIndex(xc, yc, zc + 1); - cache[idx] = 0; - } - if( !((yc-1) & 0xffffff00) ) - { - idx = GetIndex(xc, yc - 1, zc); - cache[idx] = 0; - } - if( !((yc+1) & 0xffffff00) ) - { - idx = GetIndex(xc, yc + 1, zc); - cache[idx] = 0; - } - } -#else - initCache(cache); -#endif + initCachePartial(cache, xc, yc, zc); // If we're in cached mode, then use memory allocated after the cached data itself for the toCheck array, in an attempt to make both that & the other cached data sit on the CPU L2 cache better. - + int *toCheck; if( cache == NULL ) { @@ -3461,8 +3514,8 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool f toCheck = (int *)(cache + (16*16*16)); } - int tcp = 0; - int tcc = 0; + int checkedPosition = 0; + int toCheckCount = 0; //int darktcc = 0; @@ -3476,162 +3529,100 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool f } // Lock 128K of cache (containing all the lighting cache + first 112K of toCheck array) on L2 to try and stop any cached data getting knocked out of L2 by other non-cached reads (or vice-versa) -// if( cache ) XLockL2(XLOCKL2_INDEX_TITLE, cache, 128 * 1024, XLOCKL2_LOCK_SIZE_1_WAY, 0 ); - - { - int cc = getBrightnessCached(cache, layer, xc, yc, zc); - int ex = 0; - { - int ct = 0; - int block = getBlockingCached(cache, layer, &ct, xc, yc, zc); - if (block == 0) block = 1; - - int expected = 0; - if (layer == LightLayer::Sky) - { - expected = getExpectedSkyColor(cache, cc, xc, yc, zc, ct, block); - } - else - { - expected = getExpectedBlockColor(cache, cc, xc, yc, zc, ct, block, false); - } - - ex = expected; - - } + // if( cache ) XLockL2(XLOCKL2_INDEX_TITLE, cache, 128 * 1024, XLOCKL2_LOCK_SIZE_1_WAY, 0 ); -#ifdef __PSVITA__ - // AP - we only need to memset the entire array if we discover something has changed - if( ex != cc && cache ) + { + int centerCurrent = getBrightnessCached(cache, layer, xc, yc, zc); + int centerExpected = getExpectedLight(cache, xc, yc, zc, layer, false); + + if( centerExpected != centerCurrent && cache ) { - lightCache_t old[7]; - if( !(yc & 0xffffff00) ) - { - old[0] = cache[GetIndex(xc, yc, zc)]; - old[1] = cache[GetIndex(xc - 1, yc, zc)]; - old[2] = cache[GetIndex(xc + 1, yc, zc)]; - old[5] = cache[GetIndex(xc, yc, zc - 1)]; - old[6] = cache[GetIndex(xc, yc, zc + 1)]; - } - if( !((yc-1) & 0xffffff00) ) - { - old[3] = cache[GetIndex(xc, yc - 1, zc)]; - } - if( !((yc+1) & 0xffffff00) ) - { - old[4] = cache[GetIndex(xc, yc + 1, zc)]; - } - - XMemSet128(cache,0,16*16*16*sizeof(lightCache_t)); - - if( !(yc & 0xffffff00) ) - { - cache[GetIndex(xc, yc, zc)] = old[0]; - cache[GetIndex(xc - 1, yc, zc)] = old[1]; - cache[GetIndex(xc + 1, yc, zc)] = old[2]; - cache[GetIndex(xc, yc, zc - 1)] = old[5]; - cache[GetIndex(xc, yc, zc + 1)] = old[6]; - } - if( !((yc-1) & 0xffffff00) ) - { - cache[GetIndex(xc, yc - 1, zc)] = old[3]; - } - if( !((yc+1) & 0xffffff00) ) - { - cache[GetIndex(xc, yc + 1, zc)] = old[4]; - } + initCacheComplete(cache, xc, yc, zc); } -#endif - if (ex > cc) + if (centerExpected > centerCurrent) { - toCheck[tcc++] = ((32)) + ((32) << 6) + ((32) << 12); - } - else if (ex < cc) + toCheck[toCheckCount++] = 32 | (32 << 6) | (32 << 12); + } + else if (centerExpected < centerCurrent) { // 4J - added tcn. This is the code that is run when checkLight has been called for a light source that has got darker / turned off. // In the original version, after zeroing tiles brightnesses that are deemed to come from this light source, all the zeroed tiles are then passed to the next // stage of the function to potentially have their brightnesses put back up again. We shouldn't need to consider All these tiles as starting points for this process, now just // considering the edge tiles (defined as a tile where we have a neighbour that is brightner than can be explained by the original light source we are turning off) int tcn = 0; - if (layer == LightLayer::Block || true) + if (layer == LightLayer::Block || true) { - toCheck[tcc++] = ((32)) + ((32) << 6) + ((32) << 12) + (cc << 18); - while (tcp < tcc) + toCheck[toCheckCount++] = 32 | (32 << 6) | (32 << 12) | (centerCurrent << 18); + while (checkedPosition < toCheckCount) { - int p = toCheck[tcp++]; - int x = ((p) & 63) - 32 + xc; - int y = ((p >> 6) & 63) - 32 + yc; - int z = ((p >> 12) & 63) - 32 + zc; - int cexp = ((p >> 18) & 15); - int o = getBrightnessCached(cache, layer, x, y, z); - if (o == cexp) + int p = toCheck[checkedPosition++]; + int x = ((p) & 63) - 32 + xc; + int y = ((p >> 6) & 63) - 32 + yc; + int z = ((p >> 12) & 63) - 32 + zc; + int expected = ((p >> 18) & 15); + int current = getBrightnessCached(cache, layer, x, y, z); + if (current == expected) { - setBrightnessCached(cache, &cacheUse, layer, x, y, z, 0); - // cexp--; // 4J - removed, change from 1.2.3 - if (cexp > 0) + setBrightnessCached(cache, &cacheUse, layer, x, y, z, 0); + // cexp--; // 4J - removed, change from 1.2.3 + if (expected > 0) { - int xd = x - xc; - int yd = y - yc; - int zd = z - zc; - if (xd < 0) xd = -xd; - if (yd < 0) yd = -yd; - if (zd < 0) zd = -zd; - if (xd + yd + zd < 17) + int xd = Mth::abs(x - xc); + int yd = Mth::abs(y - yc); + int zd = Mth::abs(z - zc); + if (xd + yd + zd < 17) { bool edge = false; - for (int j = 0; j < 6; j++) + for (int face = 0; face < 6; face++) { - int flip = j % 2 * 2 - 1; - - int xx = x + ((j / 2) % 3 / 2) * flip; - int yy = y + ((j / 2 + 1) % 3 / 2) * flip; - int zz = z + ((j / 2 + 2) % 3 / 2) * flip; + int xx = x + Facing::STEP_X[face]; + int yy = y + Facing::STEP_Y[face]; + int zz = z + Facing::STEP_Z[face]; // 4J - added - don't let this lighting creep out of the normal fixed world and into the infinite water chunks beyond if( ( xx > maxXZ ) || ( xx < minXZ ) || ( zz > maxXZ ) || ( zz < minXZ ) ) continue; if( ( yy < 0 ) || ( yy >= maxBuildHeight ) ) continue; - o = getBrightnessCached(cache, layer, xx, yy, zz); // 4J - some changes here brought forward from 1.2.3 - int block = getBlockingCached(cache, layer, NULL, xx, yy, zz); - if (block == 0) block = 1; - if ((o == cexp - block) && (tcc < (32 * 32 * 32))) // 4J - 32 * 32 * 32 was toCheck.length + int block = max(1, getBlockingCached(cache, layer, NULL, xx, yy, zz) ); + current = getBrightnessCached(cache, layer, xx, yy, zz); + if ((current == expected - block) && (toCheckCount < (32 * 32 * 32))) // 4J - 32 * 32 * 32 was toCheck.length { - toCheck[tcc++] = (((xx - xc) + 32)) + (((yy - yc) + 32) << 6) + (((zz - zc) + 32) << 12) + ((cexp - block) << 18); + toCheck[toCheckCount++] = (xx - xc + 32) | ((yy - yc + 32) << 6) | ((zz - zc + 32) << 12) | ((expected - block) << 18); } else { // 4J - added - keep track of which tiles form the edge of the region we are zeroing - if( o > ( cexp - block ) ) + if( current > ( expected - block ) ) { edge = true; } } - } + } // 4J - added - keep track of which tiles form the edge of the region we are zeroing - can store over the original elements in the array because tcn must be <= tcp if( edge == true ) { toCheck[tcn++] = p; } - } - } + } + } - } - } - } - tcp = 0; -// darktcc = tcc; /////////////////////////////////////////////////// - tcc = tcn; // 4J added - we've moved all the edge tiles to the start of the array, so only need to process these now. The original processes all tcc tiles again in the next section - } - } + } + } + } + checkedPosition = 0; + // darktcc = tcc; /////////////////////////////////////////////////// + toCheckCount = tcn; // 4J added - we've moved all the edge tiles to the start of the array, so only need to process these now. The original processes all tcc tiles again in the next section + } + } - while (tcp < tcc) + while (checkedPosition < toCheckCount) { - int p = toCheck[tcp++]; - int x = ((p) & 63) - 32 + xc; - int y = ((p >> 6) & 63) - 32 + yc; - int z = ((p >> 12) & 63) - 32 + zc; + int p = toCheck[checkedPosition++]; + int x = ((p) & 63) - 32 + xc; + int y = ((p >> 6) & 63) - 32 + yc; + int z = ((p >> 12) & 63) - 32 + zc; // If force is set, then this is being used to in a special mode to try and light lava tiles as chunks are being loaded in. In this case, we // don't want a lighting update to drag in any neighbouring chunks that aren't loaded yet. @@ -3642,54 +3633,43 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool f continue; } } + int current = getBrightnessCached(cache, layer, x, y, z); - int c = getBrightnessCached(cache, layer, x, y, z); - int ct = 0; - int block = getBlockingCached(cache, layer, &ct, x, y, z); - if (block == 0) block = 1; - - int expected = 0; - if (layer == LightLayer::Sky) - { - expected = getExpectedSkyColor(cache, c, x, y, z, ct, block); - } - else + // If rootOnlyEmissive flag is set, then only consider the starting tile to be possibly emissive. + bool propagatedOnly = false; + if (layer == LightLayer::Block) { - // If rootOnlyEmissive flag is set, then only consider the starting tile to be possibly emissive. - bool propagatedOnly = false; if( rootOnlyEmissive ) { propagatedOnly = ( x != xc ) || ( y != yc ) || ( z != zc ); } - expected = getExpectedBlockColor(cache, c, x, y, z, ct, block, propagatedOnly); - } + } + int expected = getExpectedLight(cache, x, y, z, layer, propagatedOnly); - if (expected != c) + if (expected != current) { - setBrightnessCached(cache, &cacheUse, layer, x, y, z, expected); + setBrightnessCached(cache, &cacheUse, layer, x, y, z, expected); - if (expected > c) + if (expected > current) { - int xd = x - xc; - int yd = y - yc; - int zd = z - zc; - if (xd < 0) xd = -xd; - if (yd < 0) yd = -yd; - if (zd < 0) zd = -zd; - if (xd + yd + zd < 17 && tcc < (32 * 32 * 32) - 6) // 4J - 32 * 32 * 32 was toCheck.length + int xd = abs(x - xc); + int yd = abs(y - yc); + int zd = abs(z - zc); + bool withinBounds = toCheckCount < (32 * 32 * 32) - 6; // 4J - 32 * 32 * 32 was toCheck.length + if (xd + yd + zd < 17 && withinBounds) { // 4J - added extra checks here to stop lighting updates moving out of the actual fixed world and into the infinite water chunks - if( ( x - 1 ) >= minXZ ) { if (getBrightnessCached(cache, layer, x - 1, y, z) < expected) toCheck[tcc++] = (((x - 1 - xc) + 32)) + (((y - yc) + 32) << 6) + (((z - zc) + 32) << 12); } - if( ( x + 1 ) <= maxXZ ) { if (getBrightnessCached(cache, layer, x + 1, y, z) < expected) toCheck[tcc++] = (((x + 1 - xc) + 32)) + (((y - yc) + 32) << 6) + (((z - zc) + 32) << 12); } - if( ( y - 1 ) >= 0 ) { if (getBrightnessCached(cache, layer, x, y - 1, z) < expected) toCheck[tcc++] = (((x - xc) + 32)) + (((y - 1 - yc) + 32) << 6) + (((z - zc) + 32) << 12); } - if( ( y + 1 ) < maxBuildHeight ) { if (getBrightnessCached(cache, layer, x, y + 1, z) < expected) toCheck[tcc++] = (((x - xc) + 32)) + (((y + 1 - yc) + 32) << 6) + (((z - zc) + 32) << 12); } - if( ( z - 1 ) >= minXZ ) { if (getBrightnessCached(cache, layer, x, y, z - 1) < expected) toCheck[tcc++] = (((x - xc) + 32)) + (((y - yc) + 32) << 6) + (((z - 1 - zc) + 32) << 12); } - if( ( z + 1 ) <= maxXZ ) { if (getBrightnessCached(cache, layer, x, y, z + 1) < expected) toCheck[tcc++] = (((x - xc) + 32)) + (((y - yc) + 32) << 6) + (((z + 1 - zc) + 32) << 12); } - } - } - } - } -// if( cache ) XUnlockL2(XLOCKL2_INDEX_TITLE); + if( ( x - 1 ) >= minXZ ) { if (getBrightnessCached(cache, layer, x - 1, y, z) < expected) toCheck[toCheckCount++] = (((x - 1 - xc) + 32)) + (((y - yc) + 32) << 6) + (((z - zc) + 32) << 12); } + if( ( x + 1 ) <= maxXZ ) { if (getBrightnessCached(cache, layer, x + 1, y, z) < expected) toCheck[toCheckCount++] = (((x + 1 - xc) + 32)) + (((y - yc) + 32) << 6) + (((z - zc) + 32) << 12); } + if( ( y - 1 ) >= 0 ) { if (getBrightnessCached(cache, layer, x, y - 1, z) < expected) toCheck[toCheckCount++] = (((x - xc) + 32)) + (((y - 1 - yc) + 32) << 6) + (((z - zc) + 32) << 12); } + if( ( y + 1 ) < maxBuildHeight ) { if (getBrightnessCached(cache, layer, x, y + 1, z) < expected) toCheck[toCheckCount++] = (((x - xc) + 32)) + (((y + 1 - yc) + 32) << 6) + (((z - zc) + 32) << 12); } + if( ( z - 1 ) >= minXZ ) { if (getBrightnessCached(cache, layer, x, y, z - 1) < expected) toCheck[toCheckCount++] = (((x - xc) + 32)) + (((y - yc) + 32) << 6) + (((z - 1 - zc) + 32) << 12); } + if( ( z + 1 ) <= maxXZ ) { if (getBrightnessCached(cache, layer, x, y, z + 1) < expected) toCheck[toCheckCount++] = (((x - xc) + 32)) + (((y - yc) + 32) << 6) + (((z + 1 - zc) + 32) << 12); } + } + } + } + } + // if( cache ) XUnlockL2(XLOCKL2_INDEX_TITLE); #if 0 QueryPerformanceCounter( &qwNewTime ); qwDeltaTime1.QuadPart = qwNewTime.QuadPart - qwTime.QuadPart; @@ -3713,7 +3693,7 @@ void Level::checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool f ///////////////////////////////////////////////////////////////// #endif LeaveCriticalSection(&m_checkLightCS); - + } @@ -3729,6 +3709,11 @@ vector *Level::fetchTicksInChunk(LevelChunk *chunk, bool remov vector > *Level::getEntities(shared_ptr except, AABB *bb) +{ + return getEntities(except, bb, NULL); +} + +vector > *Level::getEntities(shared_ptr except, AABB *bb, const EntitySelector *selector) { MemSect(40); es.clear(); @@ -3751,24 +3736,28 @@ vector > *Level::getEntities(shared_ptr except, AABB { if (hasChunk(xc, zc)) { - getChunk(xc, zc)->getEntities(except, bb, es); + getChunk(xc, zc)->getEntities(except, bb, es, selector); } } - MemSect(0); + MemSect(0); #ifdef __PSVITA__ #ifdef _ENTITIES_RW_SECTION - LeaveCriticalRWSection(&LevelChunk::m_csEntities, false); + LeaveCriticalRWSection(&LevelChunk::m_csEntities, false); #else - LeaveCriticalSection(&LevelChunk::m_csEntities); + LeaveCriticalSection(&LevelChunk::m_csEntities); #endif #endif - return &es; + return &es; } - vector > *Level::getEntitiesOfClass(const type_info& baseClass, AABB *bb) +{ + return getEntitiesOfClass(baseClass, bb, NULL); +} + +vector > *Level::getEntitiesOfClass(const type_info& baseClass, AABB *bb, const EntitySelector *selector) { int xc0 = Mth::floor((bb->x0 - 2) / 16); int xc1 = Mth::floor((bb->x1 + 2) / 16); @@ -3786,13 +3775,15 @@ vector > *Level::getEntitiesOfClass(const type_info& baseClas #endif for (int xc = xc0; xc <= xc1; xc++) + { for (int zc = zc0; zc <= zc1; zc++) { if (hasChunk(xc, zc)) { - getChunk(xc, zc)->getEntitiesOfClass(baseClass, bb, *es); + getChunk(xc, zc)->getEntitiesOfClass(baseClass, bb, *es, selector); } } + } #ifdef __PSVITA__ #ifdef _ENTITIES_RW_SECTION @@ -3889,7 +3880,7 @@ unsigned int Level::countInstanceOf(eINSTANCEOF clas, bool singleType, unsigned } else { - if (e->GetType() & clas) count++; + if (e->instanceof(clas)) count++; } } LeaveCriticalSection(&m_entitiesCS); @@ -3905,7 +3896,7 @@ unsigned int Level::countInstanceOfInRange(eINSTANCEOF clas, bool singleType, in for (AUTO_VAR(it, entities.begin()); it != itEnd; it++) { shared_ptr e = *it;//entities.at(i); - + float sd = e->distanceTo(x,y,z); if (sd * sd > range * range) { @@ -3921,10 +3912,7 @@ unsigned int Level::countInstanceOfInRange(eINSTANCEOF clas, bool singleType, in } else { - if (e->GetType() & clas) - { - count++; - } + if (e->instanceof(clas)) count++; } } LeaveCriticalSection(&m_entitiesCS); @@ -3979,7 +3967,7 @@ void Level::removeEntities(vector > *list) entitiesToRemove.insert(entitiesToRemove.end(), list->begin(), list->end()); } -bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, int face, shared_ptr ignoreEntity) +bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, int face, shared_ptr ignoreEntity, shared_ptr item) { int targetType = getTile(x, y, z); Tile *targetTile = Tile::tiles[targetType]; @@ -3991,11 +3979,14 @@ bool Level::mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, int f if (aabb != NULL && !isUnobstructed(aabb, ignoreEntity)) return false; if (targetTile != NULL && (targetTile == Tile::water || targetTile == Tile::calmWater || targetTile == Tile::lava || - targetTile == Tile::calmLava || targetTile == Tile::fire || targetTile->material->isReplaceable())) targetTile = NULL; + targetTile == Tile::calmLava || targetTile == Tile::fire || targetTile->material->isReplaceable())) + { + targetTile = NULL; + } if (targetTile != NULL && targetTile->material == Material::decoration && tile == Tile::anvil) return true; if (tileId > 0 && targetTile == NULL) { - if (tile->mayPlace(this, x, y, z, face)) + if (tile->mayPlace(this, x, y, z, face, item)) { return true; } @@ -4023,7 +4014,7 @@ Path *Level::findPath(shared_ptr from, shared_ptr to, float maxD int x2 = x + r; int y2 = y + r; int z2 = z + r; - Region region = Region(this, x1, y1, z1, x2, y2, z2); + Region region = Region(this, x1, y1, z1, x2, y2, z2, 0); Path *path = (PathFinder(®ion, canPassDoors, canOpenDoors, avoidWater, canFloat)).findPath(from.get(), to.get(), maxDist); return path; } @@ -4042,55 +4033,79 @@ Path *Level::findPath(shared_ptr from, int xBest, int yBest, int zBest, int x2 = x + r; int y2 = y + r; int z2 = z + r; - Region region = Region(this, x1, y1, z1, x2, y2, z2); + Region region = Region(this, x1, y1, z1, x2, y2, z2, 0); Path *path = (PathFinder(®ion, canPassDoors, canOpenDoors, avoidWater, canFloat)).findPath(from.get(), xBest, yBest, zBest, maxDist); return path; } -bool Level::getDirectSignal(int x, int y, int z, int dir) +int Level::getDirectSignal(int x, int y, int z, int dir) { int t = getTile(x, y, z); - if (t == 0) return false; + if (t == 0) return Redstone::SIGNAL_NONE; return Tile::tiles[t]->getDirectSignal(this, x, y, z, dir); } +int Level::getDirectSignalTo(int x, int y, int z) +{ + int result = Redstone::SIGNAL_NONE; + result = max(result, getDirectSignal(x, y - 1, z, 0)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = max(result, getDirectSignal(x, y + 1, z, 1)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = max(result, getDirectSignal(x, y, z - 1, 2)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = max(result, getDirectSignal(x, y, z + 1, 3)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = max(result, getDirectSignal(x - 1, y, z, 4)); + if (result >= Redstone::SIGNAL_MAX) return result; + result = max(result, getDirectSignal(x + 1, y, z, 5)); + if (result >= Redstone::SIGNAL_MAX) return result; + return result; +} -bool Level::hasDirectSignal(int x, int y, int z) +bool Level::hasSignal(int x, int y, int z, int dir) { - if (getDirectSignal(x, y - 1, z, 0)) return true; - if (getDirectSignal(x, y + 1, z, 1)) return true; - if (getDirectSignal(x, y, z - 1, 2)) return true; - if (getDirectSignal(x, y, z + 1, 3)) return true; - if (getDirectSignal(x - 1, y, z, 4)) return true; - if (getDirectSignal(x + 1, y, z, 5)) return true; - return false; + return getSignal(x, y, z, dir) > Redstone::SIGNAL_NONE; } - -bool Level::getSignal(int x, int y, int z, int dir) +int Level::getSignal(int x, int y, int z, int dir) { if (isSolidBlockingTile(x, y, z)) { - return hasDirectSignal(x, y, z); + return getDirectSignalTo(x, y, z); } int t = getTile(x, y, z); - if (t == 0) return false; + if (t == 0) return Redstone::SIGNAL_NONE; return Tile::tiles[t]->getSignal(this, x, y, z, dir); } - bool Level::hasNeighborSignal(int x, int y, int z) { - if (getSignal(x, y - 1, z, 0)) return true; - if (getSignal(x, y + 1, z, 1)) return true; - if (getSignal(x, y, z - 1, 2)) return true; - if (getSignal(x, y, z + 1, 3)) return true; - if (getSignal(x - 1, y, z, 4)) return true; - if (getSignal(x + 1, y, z, 5)) return true; + if (getSignal(x, y - 1, z, 0) > 0) return true; + if (getSignal(x, y + 1, z, 1) > 0) return true; + if (getSignal(x, y, z - 1, 2) > 0) return true; + if (getSignal(x, y, z + 1, 3) > 0) return true; + if (getSignal(x - 1, y, z, 4) > 0) return true; + if (getSignal(x + 1, y, z, 5) > 0) return true; return false; } +int Level::getBestNeighborSignal(int x, int y, int z) +{ + int best = Redstone::SIGNAL_NONE; + + for (int i = 0; i < 6; i++) + { + int signal = getSignal(x + Facing::STEP_X[i], y + Facing::STEP_Y[i], z + Facing::STEP_Z[i], i); + + if (signal >= Redstone::SIGNAL_MAX) return Redstone::SIGNAL_MAX; + if (signal > best) best = signal; + } + + return best; +} + // 4J Stu - Added maxYDist param shared_ptr Level::getNearestPlayer(shared_ptr source, double maxDist, double maxYDist /*= -1*/) { @@ -4148,15 +4163,16 @@ shared_ptr Level::getNearestAttackablePlayer(shared_ptr source, shared_ptr Level::getNearestAttackablePlayer(double x, double y, double z, double maxDist) { - double best = -1; - - shared_ptr result = nullptr; + double best = -1; + + shared_ptr result = nullptr; AUTO_VAR(itEnd, players.end()); for (AUTO_VAR(it, players.begin()); it != itEnd; it++) { shared_ptr p = *it; - if (p->abilities.invulnerable) + // 4J Stu - Added privilege check + if (p->abilities.invulnerable || !p->isAlive() || p->hasInvisiblePrivilege() ) { continue; } @@ -4166,28 +4182,27 @@ shared_ptr Level::getNearestAttackablePlayer(double x, double y, double // decrease the max attackable distance if the target player // is sneaking or invisible - if (p->isSneaking()) + if (p->isSneaking()) { - visibleDist *= .8f; - } + visibleDist *= .8f; + } if (p->isInvisible()) { - float coverPercentage = p->getArmorCoverPercentage(); - if (coverPercentage < .1f) + float coverPercentage = p->getArmorCoverPercentage(); + if (coverPercentage < .1f) { - coverPercentage = .1f; - } - visibleDist *= (.7f * coverPercentage); - } - - // 4J Stu - Added check that this player is still alive and privilege check - if ((visibleDist < 0 || dist < visibleDist * visibleDist) && (best == -1 || dist < best) && p->isAlive() && !p->hasInvisiblePrivilege()) + coverPercentage = .1f; + } + visibleDist *= (.7f * coverPercentage); + } + + if ((visibleDist < 0 || dist < visibleDist * visibleDist) && (best == -1 || dist < best)) { - best = dist; - result = p; - } - } - return result; + best = dist; + result = p; + } + } + return result; } shared_ptr Level::getPlayerByName(const wstring& name) @@ -4195,7 +4210,7 @@ shared_ptr Level::getPlayerByName(const wstring& name) AUTO_VAR(itEnd, players.end()); for (AUTO_VAR(it, players.begin()); it != itEnd; it++) { - if (name.compare( (*it)->name) == 0) + if (name.compare( (*it)->getName()) == 0) { return *it; //players.at(i); } @@ -4318,25 +4333,13 @@ void Level::checkSession() } -void Level::setTime(__int64 time) +void Level::setGameTime(__int64 time) { // 4J : WESTY : Added to track game time played by players for other awards. if (time != 0) // Ignore setting time to 0, done at level start and during tutorial. { // Determine step in time and ensure it is reasonable ( we only have an int to store the player stat). - __int64 timeDiff = time - levelData->getTime(); - - // debug setting added to keep it at day time -#ifndef _FINAL_BUILD - if(app.DebugSettingsOn()) - { - if(app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<getTime(); - } - } -#endif + __int64 timeDiff = time - levelData->getGameTime(); if (timeDiff < 0) { @@ -4350,7 +4353,7 @@ void Level::setTime(__int64 time) } // Apply stat to each player. - if ( timeDiff > 0 && levelData->getTime() != -1 ) + if ( timeDiff > 0 && levelData->getGameTime() != -1 ) { AUTO_VAR(itEnd, players.end()); for (vector >::iterator it = players.begin(); it != itEnd; it++) @@ -4360,12 +4363,7 @@ void Level::setTime(__int64 time) } } - this->levelData->setTime(time); -} - -void Level::setOverrideTimeOfDay(__int64 time) -{ - m_timeOfDayOverride = time; + levelData->setGameTime(time); } __int64 Level::getSeed() @@ -4373,12 +4371,20 @@ __int64 Level::getSeed() return levelData->getSeed(); } +__int64 Level::getGameTime() +{ + return levelData->getGameTime(); +} -__int64 Level::getTime() +__int64 Level::getDayTime() { - return levelData->getTime(); + return levelData->getDayTime(); } +void Level::setDayTime(__int64 newTime) +{ + levelData->setDayTime(newTime); +} Pos *Level::getSharedSpawnPos() { @@ -4395,7 +4401,6 @@ void Level::setSpawnPos(Pos *spawnPos) setSpawnPos(spawnPos->x, spawnPos->y, spawnPos->z); } - void Level::ensureAdded(shared_ptr entity) { int xc = Mth::floor(entity->x / 16); @@ -4405,7 +4410,7 @@ void Level::ensureAdded(shared_ptr entity) { for (int z = zc - r; z <= zc + r; z++) { - this->getChunk(x, z); + getChunk(x, z); } } @@ -4452,6 +4457,10 @@ LevelData *Level::getLevelData() return levelData; } +GameRules *Level::getGameRules() +{ + return levelData->getGameRules(); +} void Level::updateSleepingPlayerList() { @@ -4471,7 +4480,7 @@ float Level::getRainLevel(float a) void Level::setRainLevel(float rainLevel) { - this->oRainLevel = rainLevel; + oRainLevel = rainLevel; this->rainLevel = rainLevel; } @@ -4494,7 +4503,7 @@ bool Level::isRainingAt(int x, int y, int z) if (!canSeeSky(x, y, z)) return false; if (getTopRainBlock(x, z) > y) return false; -// 4J - changed to use new method of getting biomedata that caches results of rain & snow + // 4J - changed to use new method of getting biomedata that caches results of rain & snow if (biomeHasSnow(x, z)) return false; return biomeHasRain(x, z); } @@ -4529,14 +4538,14 @@ int Level::getAuxValueForMap(PlayerUID xuid, int dimension, int centreXC, int ce return savedDataStorage->getAuxValueForMap(xuid, dimension, centreXC, centreZC, scale); } -// void Level::globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, int data) -// { -// auto itEnd = listeners.end(); -// for (auto it = listeners.begin(); it != itEnd; it++) -// { -// (*it)->globalLevelEvent(type, sourceX, sourceY, sourceZ, data); -// } -// } +void Level::globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, int data) +{ + AUTO_VAR(itEnd, listeners.end()); + for (AUTO_VAR(it, listeners.begin()); it != itEnd; it++) + { + (*it)->globalLevelEvent(type, sourceX, sourceY, sourceZ, data); + } +} void Level::levelEvent(int type, int x, int y, int z, int data) { @@ -4563,6 +4572,11 @@ int Level::getHeight() return dimension->hasCeiling ? genDepth : maxBuildHeight; } +Tickable *Level::makeSoundUpdater(shared_ptr minecart) +{ + return NULL; +} + Random *Level::getRandomFor(int x, int z, int blend) { __int64 seed = (x * 341873128712l + z * 132897987541l) + getLevelData()->getSeed() + blend; @@ -4570,14 +4584,9 @@ Random *Level::getRandomFor(int x, int z, int blend) return random; } -bool Level::updateLights() -{ - return false; -} - TilePos *Level::findNearestMapFeature(const wstring& featureName, int x, int y, int z) { - return getChunkSource()->findNearestMapFeature(this, featureName, x, y, z); + return getChunkSource()->findNearestMapFeature(this, featureName, x, y, z); } bool Level::isAllEmpty() @@ -4603,6 +4612,75 @@ void Level::destroyTileProgress(int id, int x, int y, int z, int progress) } } +void Level::createFireworks(double x, double y, double z, double xd, double yd, double zd, CompoundTag *infoTag) +{ + +} + +Scoreboard *Level::getScoreboard() +{ + return scoreboard; +} + +void Level::updateNeighbourForOutputSignal(int x, int y, int z, int source) +{ + for (int dir = 0; dir < 4; dir++) + { + int xx = x + Direction::STEP_X[dir]; + int zz = z + Direction::STEP_Z[dir]; + int id = getTile(xx, y, zz); + if (id == 0) continue; + Tile *tile = Tile::tiles[id]; + + if (Tile::comparator_off->isSameDiode(id)) + { + tile->neighborChanged(this, xx, y, zz, source); + } + else if (Tile::isSolidBlockingTile(id)) + { + xx += Direction::STEP_X[dir]; + zz += Direction::STEP_Z[dir]; + id = getTile(xx, y, zz); + tile = Tile::tiles[id]; + + if (Tile::comparator_off->isSameDiode(id)) + { + tile->neighborChanged(this, xx, y, zz, source); + } + } + } +} + +float Level::getDifficulty(double x, double y, double z) +{ + return getDifficulty(Mth::floor(x), Mth::floor(y), Mth::floor(z)); +} + +/** +* Returns a difficulty scaled from 0 (easiest) to 1 (normal), may overflow +* to 1.5 (hardest) if allowed by player. +*/ +float Level::getDifficulty(int x, int y, int z) +{ + float result = 0; + bool isHard = difficulty == Difficulty::HARD; + + if (hasChunkAt(x, y, z)) + { + float moonBrightness = getMoonBrightness(); + + result += Mth::clamp(getChunkAt(x, z)->inhabitedTime / (TICKS_PER_DAY * 150.0f), 0.0f, 1.0f) * (isHard ? 1.0f : 0.75f); + result += moonBrightness * 0.25f; + } + + if (difficulty < Difficulty::NORMAL) + { + result *= difficulty / 2.0f; + } + + return Mth::clamp(result, 0.0f, isHard ? 1.5f : 1.0f);; +} + bool Level::useNewSeaLevel() { return levelData->useNewSeaLevel(); @@ -4650,7 +4728,7 @@ bool Level::isChunkFinalised(int x, int z) if( !isChunkPostPostProcessed(x + xo, z + zo) ) return false; } - return true; + return true; } int Level::getUnsavedChunkCount() @@ -4672,7 +4750,7 @@ bool Level::canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType) { int count = 0; int max = 0; - if(spawnType == eSpawnType_Egg) + if(spawnType == eSpawnType_Egg || spawnType == eSpawnType_Portal) { switch(type) { @@ -4704,17 +4782,38 @@ bool Level::canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType) count = countInstanceOf( eTYPE_VILLAGERGOLEM, true); max = MobCategory::MAX_XBOX_IRONGOLEM; break; + case eTYPE_WITHERBOSS: + count = countInstanceOf(eTYPE_WITHERBOSS, true) + countInstanceOf(eTYPE_ENDERDRAGON, true); + max = MobCategory::MAX_CONSOLE_BOSS; + break; default: if((type & eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) == eTYPE_ANIMALS_SPAWN_LIMIT_CHECK) { count = countInstanceOf( eTYPE_ANIMALS_SPAWN_LIMIT_CHECK, false); max = MobCategory::MAX_XBOX_ANIMALS_WITH_SPAWN_EGG; } - else if( (type & eTYPE_MONSTER) == eTYPE_MONSTER) + // 4J: Use eTYPE_ENEMY instead of monster (slimes and ghasts aren't monsters) + else if(Entity::instanceof(type, eTYPE_ENEMY)) { - count = countInstanceOf( eTYPE_MONSTER, false); + count = countInstanceOf(eTYPE_ENEMY, false); max = MobCategory::MAX_XBOX_MONSTERS_WITH_SPAWN_EGG; } + else if( (type & eTYPE_AMBIENT) == eTYPE_AMBIENT) + { + count = countInstanceOf( eTYPE_AMBIENT, false); + max = MobCategory::MAX_AMBIENT_WITH_SPAWN_EGG; + } + // 4J: Added minecart and boats + else if (Entity::instanceof(type, eTYPE_MINECART)) + { + count = countInstanceOf(eTYPE_MINECART, false); + max = Level::MAX_CONSOLE_MINECARTS; + } + else if (Entity::instanceof(type, eTYPE_BOAT)) + { + count = countInstanceOf(eTYPE_BOAT, true); + max = Level::MAX_XBOX_BOATS; + } }; } else if(spawnType == eSpawnType_Breed) @@ -4750,5 +4849,6 @@ bool Level::canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType) break; } } - return count < max; + // 4J: Interpret 0 as no limit + return max == 0 || count < max; } \ No newline at end of file diff --git a/Minecraft.World/Level.h b/Minecraft.World/Level.h index 361a40e8..6e6b28cd 100644 --- a/Minecraft.World/Level.h +++ b/Minecraft.World/Level.h @@ -41,6 +41,11 @@ class LevelSettings; class Biome; class Villages; class VillageSiege; +class Tickable; +class Minecart; +class EntitySelector; +class Scoreboard; +class GameRules; class Level : public LevelSource { @@ -61,7 +66,7 @@ public: static const int MAX_LEVEL_SIZE = 30000000; static const int maxMovementHeight = 512; // 4J added - static const int minBuildHeight = 0; // 4J - brought forward from 1.2.3 + static const int minBuildHeight = 0; // 4J - brought forward from 1.2.3 static const int maxBuildHeight = 256; // 4J - brought forward from 1.2.3 static const int genDepthBits = 7; static const int genDepthBitsPlusFour = genDepthBits + 4; @@ -84,7 +89,7 @@ public: static bool getCacheTestEnabled(); static bool getInstaTick(); static void setInstaTick(bool enable); -// bool instaTick; // 4J - removed + // bool instaTick; // 4J - removed static const int MAX_BRIGHTNESS = 15; static const int TICKS_PER_DAY = 20 * 60 * 20; // ORG:20*60*20 @@ -124,16 +129,15 @@ public: protected: float oRainLevel, rainLevel; float oThunderLevel, thunderLevel; - int lightningTime; public: - int lightningBoltTime; - bool noNeighborUpdate; + int skyFlashTime; + int difficulty; Random *random; bool isNew; Dimension *dimension; - + protected: vector listeners; @@ -152,6 +156,13 @@ public: shared_ptr villages; VillageSiege *villageSiege; +private: + // 4J - Calendar is now static + // Calendar *calendar; + +protected: + Scoreboard *scoreboard; + public: Biome *getBiome(int x, int z); // 4J - brought forward from 1.2.3 virtual BiomeSource *getBiomeSource(); @@ -164,7 +175,6 @@ private: public: Level(shared_ptrlevelStorage, const wstring& name, Dimension *dimension, LevelSettings *levelSettings, bool doCreateChunkSource = true); - Level(Level *level, Dimension *dimension); Level(shared_ptrlevelStorage, const wstring& levelName, LevelSettings *levelSettings); Level(shared_ptrlevelStorage, const wstring& levelName, LevelSettings *levelSettings, Dimension *fixedDimension, bool doCreateChunkSource = true); @@ -187,6 +197,7 @@ public: bool isEmptyTile(int x, int y, int z); virtual bool isEntityTile(int x, int y, int z); int getTileRenderShape(int x, int y, int z); + int getTileRenderShape(int t); // 4J Added to slightly optimise and avoid getTile call if we already know the tile bool hasChunkAt(int x, int y, int z); bool hasChunksAt(int x, int y, int z, int r); bool hasChunksAt(int x0, int y0, int z0, int x1, int y1, int z1); @@ -201,36 +212,31 @@ public: public: LevelChunk *getChunkAt(int x, int z); LevelChunk *getChunk(int x, int z); - virtual bool setTileAndDataNoUpdate(int x, int y, int z, int tile, int data); - virtual bool setTileAndDataNoUpdate(int x, int y, int z, int tile, int data, bool informClients); - virtual bool setTileNoUpdate(int x, int y, int z, int tile); - bool setTileNoUpdateNoLightCheck(int x, int y, int z, int tile); // 4J added + virtual bool setTileAndData(int x, int y, int z, int tile, int data, int updateFlags); Material *getMaterial(int x, int y, int z); virtual int getData(int x, int y, int z); - void setData(int x, int y, int z, int data, bool forceUpdate=false); // 4J added forceUpdate - virtual bool setDataNoUpdate(int x, int y, int z, int data); - bool setTile(int x, int y, int z, int tile); - bool setTileAndData(int x, int y, int z, int tile, int data); - void sendTileUpdated(int x, int y, int z); + virtual bool setData(int x, int y, int z, int data, int updateFlags, bool forceUpdate =false); // 4J added forceUpdate + virtual bool removeTile(int x, int y, int z); + virtual bool destroyTile(int x, int y, int z, bool dropResources); + virtual bool setTileAndUpdate(int x, int y, int z, int tile); + virtual void sendTileUpdated(int x, int y, int z); public: virtual void tileUpdated(int x, int y, int z, int tile); void lightColumnChanged(int x, int z, int y0, int y1); void setTileDirty(int x, int y, int z); void setTilesDirty(int x0, int y0, int z0, int x1, int y1, int z1); - void swap(int x1, int y1, int z1, int x2, int y2, int z2); void updateNeighborsAt(int x, int y, int z, int tile); - -private: + void updateNeighborsAtExceptFromFacing(int x, int y, int z, int tile, int skipFacing); void neighborChanged(int x, int y, int z, int type); - -public: + virtual bool isTileToBeTickedAt(int x, int y, int z, int tileId); bool canSeeSky(int x, int y, int z); int getDaytimeRawBrightness(int x, int y, int z); int getRawBrightness(int x, int y, int z); int getRawBrightness(int x, int y, int z, bool propagate); bool isSkyLit(int x, int y, int z); int getHeightmap(int x, int z); + int getLowestHeightmap(int x, int z); void updateLightIfOtherThan(LightLayer::variety layer, int x, int y, int z, int expected); int getBrightnessPropagate(LightLayer::variety layer, int x, int y, int z, int tileId); // 4J added tileId void getNeighbourBrightnesses(int *brightnesses, LightLayer::variety layer, int x, int y, int z); // 4J added @@ -247,7 +253,8 @@ public: inline int getBrightnessCached(lightCache_t *cache, LightLayer::variety layer, int x, int y, int z); inline int getEmissionCached(lightCache_t *cache, int ct, int x, int y, int z); inline int getBlockingCached(lightCache_t *cache, LightLayer::variety layer, int *ct, int x, int y, int z); - void initCache(lightCache_t *cache); + void initCachePartial(lightCache_t *cache, int xc, int yc, int zc); + void initCacheComplete(lightCache_t *cache, int xc, int yc, int zc); void flushCache(lightCache_t *cache, __uint64 cacheUse, LightLayer::variety layer); bool cachewritten; @@ -278,10 +285,11 @@ public: HitResult *clip(Vec3 *a, Vec3 *b, bool liquid); HitResult *clip(Vec3 *a, Vec3 *b, bool liquid, bool solidOnly); - virtual void playSound(shared_ptr entity, int iSound, float volume, float pitch); + virtual void playEntitySound(shared_ptr entity, int iSound, float volume, float pitch); + virtual void playPlayerSound(shared_ptr entity, int iSound, float volume, float pitch); virtual void playSound(double x, double y, double z, int iSound, float volume, float pitch, float fClipSoundDist=16.0f); - virtual void playLocalSound(double x, double y, double z, int iSound, float volume, float pitch, float fClipSoundDist=16.0f); + virtual void playLocalSound(double x, double y, double z, int iSound, float volume, float pitch, bool distanceDelay, float fClipSoundDist=16.0f); void playStreamingMusic(const wstring& name, int x, int y, int z); void playMusic(double x, double y, double z, const wstring& string, float volume); @@ -305,13 +313,14 @@ private: AABBList boxes; public: - AABBList *getCubes(shared_ptr source, AABB *box, bool noEntities=false, bool blockAtEdge=false); // 4J - added noEntities & blockAtEdge parameters - AABBList *getTileCubes(AABB *box, bool blockAtEdge); // 4J Stu - Brought forward from 12w36 to fix #46282 - TU5: Gameplay: Exiting the minecart in a tight corridor damages the player + AABBList *getCubes(shared_ptr source, AABB *box, bool noEntities = false, bool blockAtEdge = false); // 4J: Added noEntities & blockAtEdge parameters + AABBList *getTileCubes(AABB *box, bool blockAtEdge = false); // 4J: Added noEntities & blockAtEdge parameters int getOldSkyDarken(float a); // 4J - change brought forward from 1.8.2 float getSkyDarken(float a); // 4J - change brought forward from 1.8.2 Vec3 *getSkyColor(shared_ptr source, float a); float getTimeOfDay(float a); - int getMoonPhase(float a); + int getMoonPhase(); + float getMoonBrightness(); float getSunAngle(float a); Vec3 *getCloudColor(float a); Vec3 *getFogColor(float a); @@ -322,7 +331,8 @@ public: int getLightDepth(int x, int z); float getStarBrightness(float a); virtual void addToTickNextTick(int x, int y, int z, int tileId, int tickDelay); - virtual void forceAddTileTick(int x, int y, int z, int tileId, int tickDelay); + virtual void addToTickNextTick(int x, int y, int z, int tileId, int tickDelay, int priorityTilt); + virtual void forceAddTileTick(int x, int y, int z, int tileId, int tickDelay, int prioTilt); virtual void tickEntities(); void addAllPendingTileEntities(vector< shared_ptr >& entities); void tick(shared_ptr e); @@ -350,7 +360,9 @@ public: virtual bool isSolidRenderTile(int x, int y, int z); virtual bool isSolidBlockingTile(int x, int y, int z); bool isSolidBlockingTileInLoadedChunk(int x, int y, int z, bool valueIfNotLoaded); + bool isFullAABBTile(int x, int y, int z); virtual bool isTopSolidBlocking(int x, int y, int z); // 4J - brought forward from 1.3.2 + bool isTopSolidBlocking(Tile *tile, int data); protected: bool spawnEnemies; @@ -386,7 +398,7 @@ protected: private: int delayUntilNextMoodSound; static const int CHUNK_POLL_RANGE = 9; - static const int CHUNK_TILE_TICK_COUNT = 80; + static const int CHUNK_TILE_TICK_COUNT = 80; static const int CHUNK_SECTION_TILE_TICK_COUNT = (CHUNK_TILE_TICK_COUNT / 8) + 1; protected: @@ -402,9 +414,8 @@ public: bool shouldSnow(int x, int y, int z); void checkLight(int x, int y, int z, bool force = false, bool rootOnlyEmissive = false); // 4J added force, rootOnlySource parameters private: - int *toCheckLevel; - int getExpectedSkyColor(lightCache_t *cache, int oc, int x, int y , int z, int ct, int block); - int getExpectedBlockColor(lightCache_t *cache, int oc, int x, int y, int z, int ct, int block, bool propagatedOnly); // 4J added parameter + int *toCheckLevel; + int getExpectedLight(lightCache_t *cache, int x, int y, int z, LightLayer::variety layer, bool propagatedOnly); public: void checkLight(LightLayer::variety layer, int xc, int yc, int zc, bool force = false, bool rootOnlyEmissive = false); // 4J added force, rootOnlySource parameters @@ -419,29 +430,34 @@ public: bool isClientSide; vector > *getEntities(shared_ptr except, AABB *bb); + vector > *getEntities(shared_ptr except, AABB *bb, const EntitySelector *selector); vector > *getEntitiesOfClass(const type_info& baseClass, AABB *bb); + vector > *getEntitiesOfClass(const type_info& baseClass, AABB *bb, const EntitySelector *selector); shared_ptr getClosestEntityOfClass(const type_info& baseClass, AABB *bb, shared_ptr source); + virtual shared_ptr getEntity(int entityId) = 0; vector > getAllEntities(); void tileEntityChanged(int x, int y, int z, shared_ptr te); -// unsigned int countInstanceOf(BaseObject::Class *clas); + // unsigned int countInstanceOf(BaseObject::Class *clas); unsigned int countInstanceOf(eINSTANCEOF clas, bool singleType, unsigned int *protectedCount = NULL, unsigned int *couldWanderCount = NULL); // 4J added unsigned int countInstanceOfInRange(eINSTANCEOF clas, bool singleType, int range, int x, int y, int z); // 4J Added void addEntities(vector > *list); virtual void removeEntities(vector > *list); - bool mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, int face, shared_ptr ignoreEntity); + bool mayPlace(int tileId, int x, int y, int z, bool ignoreEntities, int face, shared_ptr ignoreEntity, shared_ptr item); int getSeaLevel(); Path *findPath(shared_ptr from, shared_ptr to, float maxDist, bool canPassDoors, bool canOpenDoors, bool avoidWater, bool canFloat); Path *findPath(shared_ptr from, int xBest, int yBest, int zBest, float maxDist, bool canPassDoors, bool canOpenDoors, bool avoidWater, bool canFloat); - bool getDirectSignal(int x, int y, int z, int dir); - bool hasDirectSignal(int x, int y, int z); - bool getSignal(int x, int y, int z, int dir); + int getDirectSignal(int x, int y, int z, int dir); + int getDirectSignalTo(int x, int y, int z); + bool hasSignal(int x, int y, int z, int dir); + int getSignal(int x, int y, int z, int dir); bool hasNeighborSignal(int x, int y, int z); + int getBestNeighborSignal(int x, int y, int z); // 4J Added maxYDist param shared_ptr getNearestPlayer(shared_ptr source, double maxDist, double maxYDist = -1); shared_ptr getNearestPlayer(double x, double y, double z, double maxDist, double maxYDist = -1); shared_ptr getNearestPlayer(double x, double z, double maxDist); - shared_ptr getNearestAttackablePlayer(shared_ptr source, double maxDist); - shared_ptr getNearestAttackablePlayer(double x, double y, double z, double maxDist); + shared_ptr getNearestAttackablePlayer(shared_ptr source, double maxDist); + shared_ptr getNearestAttackablePlayer(double x, double y, double z, double maxDist); shared_ptr getPlayerByName(const wstring& name); shared_ptr getPlayerByUUID(const wstring& name); // 4J Added @@ -449,10 +465,11 @@ public: void setBlocksAndData(int x, int y, int z, int xs, int ys, int zs, byteArray data, bool includeLighting = true); virtual void disconnect(bool sendDisconnect = true); void checkSession(); - void setTime(__int64 time); - void setOverrideTimeOfDay(__int64 time); // 4J Added so we can override timeOfDay without changing tick time + void setGameTime(__int64 time); __int64 getSeed(); - __int64 getTime(); + __int64 getGameTime(); + __int64 getDayTime(); + void setDayTime(__int64 newTime); Pos *getSharedSpawnPos(); void setSpawnPos(int x, int y, int z); void setSpawnPos(Pos *spawnPos); @@ -463,6 +480,7 @@ public: virtual void tileEvent(int x, int y, int z, int tile, int b0, int b1); LevelStorage *getLevelStorage(); LevelData *getLevelData(); + GameRules *getGameRules(); virtual void updateSleepingPlayerList(); bool useNewSeaLevel(); // 4J added bool getHasBeenInCreative(); // 4J Added @@ -479,25 +497,27 @@ public: void setSavedData(const wstring& id, shared_ptr data); shared_ptr getSavedData(const type_info& clazz, const wstring& id); int getFreeAuxValueFor(const wstring& id); + void globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, int data); void levelEvent(int type, int x, int y, int z, int data); void levelEvent(shared_ptr source, int type, int x, int y, int z, int data); int getMaxBuildHeight(); int getHeight(); + virtual Tickable *makeSoundUpdater(shared_ptr minecart); Random *getRandomFor(int x, int z, int blend); - bool updateLights(); virtual bool isAllEmpty(); double getHorizonHeight() ; void destroyTileProgress(int id, int x, int y, int z, int progress); - TilePos *findNearestMapFeature(const wstring& featureName, int x, int y, int z); + // Calendar *getCalendar(); // 4J - Calendar is now static + virtual void createFireworks(double x, double y, double z, double xd, double yd, double zd, CompoundTag *infoTag); + virtual Scoreboard *getScoreboard(); + virtual void updateNeighbourForOutputSignal(int x, int y, int z, int source); + virtual float getDifficulty(double x, double y, double z); + virtual float getDifficulty(int x, int y, int z); + TilePos *findNearestMapFeature(const wstring& featureName, int x, int y, int z); // 4J Added int getAuxValueForMap(PlayerUID xuid, int dimension, int centreXC, int centreZC, int scale); - // 4J added - - - __int64 m_timeOfDayOverride; - // 4J - optimisation - keep direct reference of underlying cache here LevelChunk **chunkSourceCache; int chunkSourceXZSize; @@ -531,6 +551,7 @@ public: { eSpawnType_Egg, eSpawnType_Breed, + eSpawnType_Portal, }; bool canCreateMore(eINSTANCEOF type, ESPAWN_TYPE spawnType); diff --git a/Minecraft.World/LevelChunk.cpp b/Minecraft.World/LevelChunk.cpp index 823c7c4c..920fdfc1 100644 --- a/Minecraft.World/LevelChunk.cpp +++ b/Minecraft.World/LevelChunk.cpp @@ -11,10 +11,13 @@ #include "SparseLightStorage.h" #include "BlockReplacements.h" #include "LevelChunk.h" +#include "BasicTypeContainers.h" #include "..\Minecraft.Client\MinecraftServer.h" #include "..\Minecraft.Client\ServerLevel.h" #include "..\Minecraft.Client\ServerChunkCache.h" #include "..\Minecraft.Client\GameRenderer.h" +#include "ItemEntity.h" +#include "Minecart.h" #ifdef __PS3__ #include "C4JSpursJob.h" @@ -25,10 +28,10 @@ CRITICAL_SECTION LevelChunk::m_csSharing; #endif #ifdef _ENTITIES_RW_SECTION - // AP - use a RW critical section so we can have multiple threads reading the same data to avoid a clash - CRITICAL_RW_SECTION LevelChunk::m_csEntities; +// AP - use a RW critical section so we can have multiple threads reading the same data to avoid a clash +CRITICAL_RW_SECTION LevelChunk::m_csEntities; #else - CRITICAL_SECTION LevelChunk::m_csEntities; +CRITICAL_SECTION LevelChunk::m_csEntities; #endif CRITICAL_SECTION LevelChunk::m_csTileEntities; bool LevelChunk::touchedSky = false; @@ -78,11 +81,11 @@ void LevelChunk::init(Level *level, int x, int z) // 4J Stu - Not using this checkLightPosition = 0; //LIGHT_CHECK_MAX_POS; - this->level = level; - this->x = x; - this->z = z; + this->level = level; + this->x = x; + this->z = z; MemSect(1); - heightmap = byteArray(16 * 16); + heightmap = byteArray(16 * 16); #ifdef _ENTITIES_RW_SECTION EnterCriticalRWSection(&m_csEntities, true); #else @@ -90,8 +93,8 @@ void LevelChunk::init(Level *level, int x, int z) #endif for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) { - entityBlocks[i] = new vector >(); - } + entityBlocks[i] = new vector >(); + } #ifdef _ENTITIES_RW_SECTION LeaveCriticalRWSection(&m_csEntities, true); #else @@ -100,6 +103,9 @@ void LevelChunk::init(Level *level, int x, int z) MemSect(0); + lowestHeightmap = 256; + inhabitedTime = 0; + // Optimisation brought forward from 1.8.2, change from int to unsigned char & this special value changed from -999 to 255 for(int i = 0; i < 16 * 16; i++ ) { @@ -124,11 +130,11 @@ void LevelChunk::init(Level *level, int x, int z) // This ctor is used for loading a save into LevelChunk::LevelChunk(Level *level, int x, int z) : ENTITY_BLOCKS_LENGTH( Level::maxBuildHeight/16 ) { - init(level, x, z); + init(level, x, z); lowerBlocks = new CompressedTileStorage(); - lowerData = NULL; - lowerSkyLight = NULL; - lowerBlockLight = NULL; + lowerData = NULL; + lowerSkyLight = NULL; + lowerBlockLight = NULL; serverTerrainPopulated = NULL; if(Level::maxBuildHeight > Level::COMPRESSED_CHUNK_SECTION_HEIGHT) @@ -180,8 +186,8 @@ LevelChunk::LevelChunk(Level *level, byteArray blocks, int x, int z) : ENTITY_BL lowerSkyLight = new SparseLightStorage(true); lowerBlockLight = new SparseLightStorage(false); } -// skyLight = new DataLayer(blocks.length, level->depthBits); -// blockLight = new DataLayer(blocks.length, level->depthBits); + // skyLight = new DataLayer(blocks.length, level->depthBits); + // blockLight = new DataLayer(blocks.length, level->depthBits); if(Level::maxBuildHeight > Level::COMPRESSED_CHUNK_SECTION_HEIGHT) { @@ -209,16 +215,16 @@ LevelChunk::LevelChunk(Level *level, byteArray blocks, int x, int z) : ENTITY_BL // The original version this is shared from owns all the data that is shared into this copy, so it isn't deleted in the dtor. LevelChunk::LevelChunk(Level *level, int x, int z, LevelChunk *lc) : ENTITY_BLOCKS_LENGTH( Level::maxBuildHeight/16 ) { - init(level, x, z); + init(level, x, z); // 4J Stu - Copy over the biome data memcpy(biomes.data,lc->biomes.data,biomes.length); #ifdef SHARING_ENABLED - lowerBlocks = lc->lowerBlocks; - lowerData = lc->lowerData; - lowerSkyLight = new SparseLightStorage( lc->lowerSkyLight ); - lowerBlockLight = new SparseLightStorage( lc->lowerBlockLight ); + lowerBlocks = lc->lowerBlocks; + lowerData = lc->lowerData; + lowerSkyLight = new SparseLightStorage( lc->lowerSkyLight ); + lowerBlockLight = new SparseLightStorage( lc->lowerBlockLight ); upperBlocks = lc->upperBlocks; upperData = lc->upperData; upperSkyLight = new SparseLightStorage( lc->upperSkyLight ); @@ -454,12 +460,12 @@ LevelChunk::~LevelChunk() bool LevelChunk::isAt(int x, int z) { - return x == this->x && z == this->z; + return x == this->x && z == this->z; } int LevelChunk::getHeightmap(int x, int z) { - return heightmap[z << 4 | x] & 0xff; + return heightmap[z << 4 | x] & 0xff; } int LevelChunk::getHighestSectionPosition() @@ -499,7 +505,7 @@ void LevelChunk::recalcHeightmapOnly() #ifdef __PSVITA__ int Index = ( x << 11 ) + ( z << 7 ); int offset = Level::COMPRESSED_CHUNK_SECTION_TILES; - y = 127; + y = 127; while (y > 0 && Tile::lightBlock[blockData[Index + offset + (y - 1)]] == 0) // 4J - was blocks->get() was blocks[p + y - 1] { y--; @@ -533,7 +539,7 @@ void LevelChunk::recalcHeightmapOnly() this->setUnsaved(true); #ifdef __PSVITA__ - delete blockData.data; + delete blockData.data; #endif } @@ -544,18 +550,19 @@ void LevelChunk::recalcHeightmap() byteArray blockData = byteArray(Level::CHUNK_TILE_COUNT); getBlockData(blockData); #endif + lowestHeightmap = Integer::MAX_VALUE; - int min = Level::maxBuildHeight - 1; - for (int x = 0; x < 16; x++) - for (int z = 0; z < 16; z++) + int min = Level::maxBuildHeight - 1; + for (int x = 0; x < 16; x++) + for (int z = 0; z < 16; z++) { - int y = Level::maxBuildHeight - 1; -// int p = x << level->depthBitsPlusFour | z << level->depthBits; // 4J - removed - + int y = Level::maxBuildHeight - 1; + // int p = x << level->depthBitsPlusFour | z << level->depthBits; // 4J - removed + #ifdef __PSVITA__ int Index = ( x << 11 ) + ( z << 7 ); int offset = Level::COMPRESSED_CHUNK_SECTION_TILES; - y = 127; + y = 127; while (y > 0 && Tile::lightBlock[blockData[Index + offset + (y - 1)]] == 0) // 4J - was blocks->get() was blocks[p + y - 1] { y--; @@ -575,32 +582,33 @@ void LevelChunk::recalcHeightmap() } #else CompressedTileStorage *blocks = (y-1) >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT?upperBlocks : lowerBlocks; - while (y > 0 && Tile::lightBlock[blocks->get(x,(y-1) % Level::COMPRESSED_CHUNK_SECTION_HEIGHT,z) & 0xff] == 0) // 4J - was blocks->get() was blocks[p + y - 1] + while (y > 0 && Tile::lightBlock[blocks->get(x,(y-1) % Level::COMPRESSED_CHUNK_SECTION_HEIGHT,z) & 0xff] == 0) // 4J - was blocks->get() was blocks[p + y - 1] { - y--; + y--; blocks = (y-1) >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT?upperBlocks : lowerBlocks; } #endif - heightmap[z << 4 | x] = (byte) y; - if (y < min) min = y; + heightmap[z << 4 | x] = (byte) y; + if (y < min) min = y; + if (y < lowestHeightmap) lowestHeightmap = y; - if (!level->dimension->hasCeiling) + if (!level->dimension->hasCeiling) { - int br = Level::MAX_BRIGHTNESS; + int br = Level::MAX_BRIGHTNESS; int yy = Level::maxBuildHeight - 1; #ifdef __PSVITA__ int offset = Level::COMPRESSED_CHUNK_SECTION_TILES; SparseLightStorage *skyLight = upperSkyLight; yy = 127; - do + do { - br -= Tile::lightBlock[blockData[Index + offset + yy]]; // 4J - blocks->get() was blocks[p + yy] - if (br > 0) + br -= Tile::lightBlock[blockData[Index + offset + yy]]; // 4J - blocks->get() was blocks[p + yy] + if (br > 0) { - skyLight->set(x, yy, z, br); - } - yy--; - } while (yy > 0 && br > 0); + skyLight->set(x, yy, z, br); + } + yy--; + } while (yy > 0 && br > 0); if( yy == 0 && br > 0 ) { @@ -620,33 +628,33 @@ void LevelChunk::recalcHeightmap() #else CompressedTileStorage *blocks = yy >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT?upperBlocks : lowerBlocks; SparseLightStorage *skyLight = yy >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT? upperSkyLight : lowerSkyLight; - do + do { - br -= Tile::lightBlock[blocks->get(x,(yy % Level::COMPRESSED_CHUNK_SECTION_HEIGHT),z) & 0xff]; // 4J - blocks->get() was blocks[p + yy] - if (br > 0) + br -= Tile::lightBlock[blocks->get(x,(yy % Level::COMPRESSED_CHUNK_SECTION_HEIGHT),z) & 0xff]; // 4J - blocks->get() was blocks[p + yy] + if (br > 0) { - skyLight->set(x, (yy % Level::COMPRESSED_CHUNK_SECTION_HEIGHT), z, br); - } - yy--; + skyLight->set(x, (yy % Level::COMPRESSED_CHUNK_SECTION_HEIGHT), z, br); + } + yy--; blocks = yy >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT?upperBlocks : lowerBlocks; skyLight = yy >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT? upperSkyLight : lowerSkyLight; - } while (yy > 0 && br > 0); + } while (yy > 0 && br > 0); #endif - } - } + } + } - this->minHeight = min; + this->minHeight = min; - for (int x = 0; x < 16; x++) - for (int z = 0; z < 16; z++) - { - lightGaps(x, z); - } + for (int x = 0; x < 16; x++) + for (int z = 0; z < 16; z++) + { + lightGaps(x, z); + } - this->setUnsaved(true); + this->setUnsaved(true); #ifdef __PSVITA__ - delete blockData.data; + delete blockData.data; #endif } @@ -656,11 +664,11 @@ void LevelChunk::recalcHeightmap() void LevelChunk::lightLava() { if( !emissiveAdded ) return; - + for (int x = 0; x < 16; x++) for (int z = 0; z < 16; z++) { -// int p = x << 11 | z << 7; // 4J - removed + // int p = x << 11 | z << 7; // 4J - removed int ymax = getHeightmap(x,z); for (int y = 0; y < Level::COMPRESSED_CHUNK_SECTION_HEIGHT; y++) { @@ -668,7 +676,7 @@ void LevelChunk::lightLava() int emit = Tile::lightEmission[blocks->get(x,y,z)]; // 4J - blocks->get() was blocks[p + y] if( emit > 0 ) { -// printf("(%d,%d,%d)",this->x * 16 + x, y, this->z * 16 + z); + // printf("(%d,%d,%d)",this->x * 16 + x, y, this->z * 16 + z); // We'll be calling this function for a lot of chunks as they are post-processed. For every chunk that is // post-processed we're calling this for each of its neighbours in case some post-processing also created something // that needed lighting outside the starting chunk. Because of this, do a quick test on any emissive blocks that have @@ -681,7 +689,7 @@ void LevelChunk::lightLava() } } } - emissiveAdded = false; + emissiveAdded = false; } void LevelChunk::lightGaps(int x, int z) @@ -704,19 +712,19 @@ void LevelChunk::recheckGaps(bool bForce) int maxXZ = (level->dimension->getXZSize() * 16 ) / 2 - 1; // 4J - note - this test will currently return true for chunks at the edge of our world. Making further checks inside the loop now to address this issue. - if (level->hasChunksAt(x * 16 + 8, Level::maxBuildHeight / 2, z * 16 + 8, 16)) + if (level->hasChunksAt(x * 16 + 8, Level::maxBuildHeight / 2, z * 16 + 8, 16)) { - for (int x = 0; x < 16; x++) - for (int z = 0; z < 16; z++) + for (int x = 0; x < 16; x++) + for (int z = 0; z < 16; z++) { int slot = ( x >> 1 ) | (z * 8); int shift = ( x & 1 ) * 4; - if (bForce || ( columnFlags[slot] & ( eColumnFlag_recheck << shift ) ) ) + if (bForce || ( columnFlags[slot] & ( eColumnFlag_recheck << shift ) ) ) { - columnFlags[slot] &= ~( eColumnFlag_recheck << shift ); - int height = getHeightmap(x, z); - int xOffs = (this->x * 16) + x; - int zOffs = (this->z * 16) + z; + columnFlags[slot] &= ~( eColumnFlag_recheck << shift ); + int height = getHeightmap(x, z); + int xOffs = (this->x * 16) + x; + int zOffs = (this->z * 16) + z; // 4J - rewritten this to make sure that the minimum neighbour height which is calculated doesn't involve getting any heights from beyond the edge of the world, // which can lead to large, very expensive, non-existent cliff edges to be lit @@ -741,7 +749,7 @@ void LevelChunk::recheckGaps(bool bForce) int n = level->getHeightmap(xOffs, zOffs + 1); if ( n < nmin ) nmin = n; } - lightGap(xOffs, zOffs, nmin); + lightGap(xOffs, zOffs, nmin); if( !bForce ) // 4J - if doing a full forced thing over every single column, we don't need to do these offset checks too { @@ -751,77 +759,77 @@ void LevelChunk::recheckGaps(bool bForce) if( zOffs + 1 <= maxXZ ) lightGap(xOffs, zOffs + 1, height); } hasGapsToCheck = false; - } - } - } + } + } + } } void LevelChunk::lightGap(int x, int z, int source) { - int height = level->getHeightmap(x, z); + int height = level->getHeightmap(x, z); - if (height > source) + if (height > source) { - lightGap(x, z, source, height + 1); - } + lightGap(x, z, source, height + 1); + } else if (height < source) { - lightGap(x, z, height, source + 1); - } + lightGap(x, z, height, source + 1); + } } void LevelChunk::lightGap(int x, int z, int y1, int y2) { - if (y2 > y1) + if (y2 > y1) { - if (level->hasChunksAt(x, Level::maxBuildHeight / 2, z, 16)) + if (level->hasChunksAt(x, Level::maxBuildHeight / 2, z, 16)) { - for (int y = y1; y < y2; y++) + for (int y = y1; y < y2; y++) { - level->checkLight(LightLayer::Sky, x, y, z); - } - this->setUnsaved(true); - } - } + level->checkLight(LightLayer::Sky, x, y, z); + } + this->setUnsaved(true); + } + } } void LevelChunk::recalcHeight(int x, int yStart, int z) { - int yOld = heightmap[z << 4 | x] & 0xff; - int y = yOld; - if (yStart > yOld) y = yStart; + int yOld = heightmap[z << 4 | x] & 0xff; + int y = yOld; + if (yStart > yOld) y = yStart; + + // int p = x << level->depthBitsPlusFour | z << level->depthBits; // 4J - removed -// int p = x << level->depthBitsPlusFour | z << level->depthBits; // 4J - removed - CompressedTileStorage *blocks = (y-1) >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT?upperBlocks : lowerBlocks; while (y > 0 && Tile::lightBlock[blocks->get(x,(y-1) % Level::COMPRESSED_CHUNK_SECTION_HEIGHT,z) & 0xff] == 0) // 4J - blocks->get() was blocks[p + y - 1] { - y--; + y--; blocks = (y-1) >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT?upperBlocks : lowerBlocks; } - if (y == yOld) return; + if (y == yOld) return; -// level->lightColumnChanged(x, z, y, yOld); // 4J - this call moved below & corrected - see comment further down - heightmap[z << 4 | x] = (byte) y; + // level->lightColumnChanged(x, z, y, yOld); // 4J - this call moved below & corrected - see comment further down + heightmap[z << 4 | x] = (byte) y; - if (y < minHeight) + if (y < minHeight) { - minHeight = y; - } + minHeight = y; + } else { - int min = Level::maxBuildHeight - 1; - for (int _x = 0; _x < 16; _x++) - for (int _z = 0; _z < 16; _z++) + int min = Level::maxBuildHeight - 1; + for (int _x = 0; _x < 16; _x++) + for (int _z = 0; _z < 16; _z++) { - if ((heightmap[_z << 4 | _x] & 0xff) < min) min = (heightmap[_z << 4 | _x] & 0xff); - } - this->minHeight = min; - } + if ((heightmap[_z << 4 | _x] & 0xff) < min) min = (heightmap[_z << 4 | _x] & 0xff); + } + this->minHeight = min; + } - int xOffs = (this->x * 16) + x; - int zOffs = (this->z * 16) + z; + int xOffs = (this->x * 16) + x; + int zOffs = (this->z * 16) + z; if (!level->dimension->hasCeiling) { if (y < yOld) @@ -835,7 +843,7 @@ void LevelChunk::recalcHeight(int x, int yStart, int z) } else { // 4J - lighting change brought forward from 1.8.2 - // level->updateLight(LightLayer::Sky, xOffs, yOld, zOffs, xOffs, y, zOffs); + // level->updateLight(LightLayer::Sky, xOffs, yOld, zOffs, xOffs, y, zOffs); SparseLightStorage *skyLight = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT? upperSkyLight : lowerSkyLight; for (int yy = yOld; yy < y; yy++) { @@ -845,7 +853,7 @@ void LevelChunk::recalcHeight(int x, int yStart, int z) } int br = 15; - + SparseLightStorage *skyLight = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT? upperSkyLight : lowerSkyLight; while (y > 0 && br > 0) { @@ -857,7 +865,7 @@ void LevelChunk::recalcHeight(int x, int yStart, int z) if (br < 0) br = 0; skyLight->set(x, (y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT), z, br); // level.updateLightIfOtherThan(LightLayer.Sky, xOffs, y, zOffs, - // -1); + // -1); } } // 4J - changed to use xOffs and zOffs rather than the (incorrect) x and z it used to, and also moved so that it happens after all the lighting should be @@ -865,15 +873,16 @@ void LevelChunk::recalcHeight(int x, int yStart, int z) level->lightColumnChanged(xOffs, zOffs, y, yOld); // 4J - lighting changes brought forward from 1.8.2 - int height = heightmap[z << 4 | x]; - int y1 = yOld; - int y2 = height; - if (y2 < y1) - { - int tmp = y1; - y1 = y2; - y2 = tmp; - } + int height = heightmap[z << 4 | x]; + int y1 = yOld; + int y2 = height; + if (y2 < y1) + { + int tmp = y1; + y1 = y2; + y2 = tmp; + } + if (height < lowestHeightmap) lowestHeightmap = height; if (!level->dimension->hasCeiling) { PIXBeginNamedEvent(0,"Light gaps"); @@ -885,7 +894,7 @@ void LevelChunk::recalcHeight(int x, int yStart, int z) PIXEndNamedEvent(); } - this->setUnsaved(true); + this->setUnsaved(true); } /** @@ -910,25 +919,35 @@ int LevelChunk::getTile(int x, int y, int z) bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) { - byte tile = (byte) _tile; + byte tile = (byte) _tile; // Optimisation brought forward from 1.8.2, change from int to unsigned char & this special value changed from -999 to 255 - int slot = z << 4 | x; + int slot = z << 4 | x; - if (y >= ((int)rainHeights[slot]) - 1) + if (y >= ((int)rainHeights[slot]) - 1) { - rainHeights[slot] = 255; - } + rainHeights[slot] = 255; + } + + int oldHeight = heightmap[slot] & 0xff; - int oldHeight = heightmap[slot] & 0xff; - CompressedTileStorage *blocks = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperBlocks : lowerBlocks; SparseDataStorage *data = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperData : lowerData; int old = blocks->get(x,y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT,z); int oldData = data->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); - if (old == _tile && oldData == _data) return false; - int xOffs = this->x * 16 + x; - int zOffs = this->z * 16 + z; + if (old == _tile && oldData == _data) + { + // 4J Stu - Need to do this here otherwise double chests don't always work correctly + shared_ptr te = getTileEntity(x, y, z); + if (te != NULL) + { + te->clearCache(); + } + + return false; + } + int xOffs = this->x * 16 + x; + int zOffs = this->z * 16 + z; if (old != 0 && !level->isClientSide) { Tile::tiles[old]->onRemoving(level, xOffs, y, zOffs, oldData); @@ -936,9 +955,9 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) PIXBeginNamedEvent(0,"Chunk setting tile"); blocks->set(x,y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT,z,tile); PIXEndNamedEvent(); - if (old != 0) + if (old != 0) { - if (!level->isClientSide) + if (!level->isClientSide) { Tile::tiles[old]->onRemove(level, xOffs, y, zOffs, old, oldData); } @@ -946,7 +965,7 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) { level->removeTileEntity(xOffs, y, zOffs); } - } + } PIXBeginNamedEvent(0,"Chunk setting data"); data->set(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z, _data); PIXEndNamedEvent(); @@ -984,14 +1003,14 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) } // level.updateLight(LightLayer.Carried, xOffs, y, zOffs, xOffs, y, - // zOffs); + // zOffs); PIXBeginNamedEvent(0,"Lighting gaps"); lightGaps(x, z); PIXEndNamedEvent(); } PIXEndNamedEvent(); data->set(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z, _data); - if (_tile != 0) + if (_tile != 0) { if (!level->isClientSide) { @@ -1008,18 +1027,18 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) if(!Tile::tiles[_tile]->mayPlace(level, xOffs, y, zOffs )) { blocks->set(x,y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT,z,0); -// blocks[x << level->depthBitsPlusFour | z << level->depthBits | y] = 0; + // blocks[x << level->depthBitsPlusFour | z << level->depthBits | y] = 0; } } } // AP - changed the method of EntityTile detection cos it's well slow on Vita mate -// if (_tile > 0 && dynamic_cast(Tile::tiles[_tile]) != NULL) + // if (_tile > 0 && dynamic_cast(Tile::tiles[_tile]) != NULL) if (_tile > 0 && Tile::tiles[_tile] != NULL && Tile::tiles[_tile]->isEntityTile()) { shared_ptr te = getTileEntity(x, y, z); if (te == NULL) { - te = ((EntityTile *) Tile::tiles[_tile])->newTileEntity(level); + te = dynamic_cast(Tile::tiles[_tile])->newTileEntity(level); //app.DebugPrintf("%s: Setting tile id %d, created tileEntity type %d\n", level->isClientSide?"Client":"Server", _tile, te->GetType()); level->setTileEntity(xOffs, y, zOffs, te); } @@ -1031,7 +1050,7 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) } } // AP - changed the method of EntityTile detection cos it's well slow on Vita mate -// else if (old > 0 && dynamic_cast(Tile::tiles[old]) != NULL) + // else if (old > 0 && dynamic_cast(Tile::tiles[old]) != NULL) else if (old > 0 && Tile::tiles[_tile] != NULL && Tile::tiles[_tile]->isEntityTile()) { shared_ptr te = getTileEntity(x, y, z); @@ -1039,10 +1058,10 @@ bool LevelChunk::setTileAndData(int x, int y, int z, int _tile, int _data) { te->clearCache(); } - } + } - this->setUnsaved(true); - return true; + this->setUnsaved(true); + return true; } bool LevelChunk::setTile(int x, int y, int z, int _tile) @@ -1060,17 +1079,17 @@ int LevelChunk::getData(int x, int y, int z) bool LevelChunk::setData(int x, int y, int z, int val, int mask, bool *maskedBitsChanged) { SparseDataStorage *data = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperData : lowerData; - this->setUnsaved(true); + this->setUnsaved(true); int old = data->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); *maskedBitsChanged = ( ( old & mask ) != ( val & mask ) ); - if (old == val) + if (old == val) { - return false; - } + return false; + } - data->set(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z, val); + data->set(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z, val); int _tile = getTile(x, y, z); if (_tile > 0 && dynamic_cast( Tile::tiles[_tile] ) != NULL) { @@ -1086,19 +1105,23 @@ bool LevelChunk::setData(int x, int y, int z, int val, int mask, bool *maskedBit int LevelChunk::getBrightness(LightLayer::variety layer, int x, int y, int z) { - if (layer == LightLayer::Sky) + if (layer == LightLayer::Sky) { + if (level->dimension->hasCeiling) + { + return 0; + } SparseLightStorage *skyLight = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperSkyLight : lowerSkyLight; if(!skyLight) return 0; return skyLight->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); } - else if (layer == LightLayer::Block) + else if (layer == LightLayer::Block) { SparseLightStorage *blockLight = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperBlockLight : lowerBlockLight; if(!blockLight) return 0; return blockLight->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); } - else return 0; + else return 0; } // 4J added @@ -1116,12 +1139,12 @@ void LevelChunk::getNeighbourBrightnesses(int *brightnesses, LightLayer::variety brightnesses[5] = light->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z + 1); } - + if( layer == LightLayer::Sky ) light = (y-1) >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperSkyLight : lowerSkyLight; else light = (y-1) >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperBlockLight : lowerBlockLight; if(light) brightnesses[2] = light->get(x, (y - 1) % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); - + if( layer == LightLayer::Sky ) light = (y+1) >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperSkyLight : lowerSkyLight; else light = (y+1) >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperBlockLight : lowerBlockLight; if(light) brightnesses[3] = light->get(x, (y + 1) % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); @@ -1129,8 +1152,8 @@ void LevelChunk::getNeighbourBrightnesses(int *brightnesses, LightLayer::variety void LevelChunk::setBrightness(LightLayer::variety layer, int x, int y, int z, int brightness) { - this->setUnsaved(true); - if (layer == LightLayer::Sky) + this->setUnsaved(true); + if (layer == LightLayer::Sky) { if(!level->dimension->hasCeiling) { @@ -1138,7 +1161,7 @@ void LevelChunk::setBrightness(LightLayer::variety layer, int x, int y, int z, i skyLight->set(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z, brightness); } } - else if (layer == LightLayer::Block) + else if (layer == LightLayer::Block) { SparseLightStorage *blockLight = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperBlockLight : lowerBlockLight; blockLight->set(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z, brightness); @@ -1149,42 +1172,42 @@ int LevelChunk::getRawBrightness(int x, int y, int z, int skyDampen) { SparseLightStorage *skyLight = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperSkyLight : lowerSkyLight; int light = level->dimension->hasCeiling ? 0 : skyLight->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); - if (light > 0) LevelChunk::touchedSky = true; - light -= skyDampen; + if (light > 0) touchedSky = true; + light -= skyDampen; SparseLightStorage *blockLight = y >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT ? upperBlockLight : lowerBlockLight; int block = blockLight->get(x, y % Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z); - if (block > light) light = block; + if (block > light) light = block; - /* - * int xd = (absFloor(level.player.x-(this->x*16+x))); int yd = - * (absFloor(level.player.y-(y))); int zd = - * (absFloor(level.player.z-(this->z*16+z))); int dd = xd+yd+zd; if - * (dd<15){ int carried = 15-dd; if (carried<0) carried = 0; if - * (carried>15) carried = 15; if (carried > light) light = carried; } - */ + /* + * int xd = (absFloor(level.player.x-(this->x*16+x))); int yd = + * (absFloor(level.player.y-(y))); int zd = + * (absFloor(level.player.z-(this->z*16+z))); int dd = xd+yd+zd; if + * (dd<15){ int carried = 15-dd; if (carried<0) carried = 0; if + * (carried>15) carried = 15; if (carried > light) light = carried; } + */ - return light; + return light; } void LevelChunk::addEntity(shared_ptr e) { - lastSaveHadEntities = true; + lastSaveHadEntities = true; - int xc = Mth::floor(e->x / 16); - int zc = Mth::floor(e->z / 16); - if (xc != this->x || zc != this->z) + int xc = Mth::floor(e->x / 16); + int zc = Mth::floor(e->z / 16); + if (xc != this->x || zc != this->z) { app.DebugPrintf("Wrong location!"); -// System.out.println("Wrong location! " + e); -// Thread.dumpStack(); - } - int yc = Mth::floor(e->y / 16); - if (yc < 0) yc = 0; + // System.out.println("Wrong location! " + e); + // Thread.dumpStack(); + } + int yc = Mth::floor(e->y / 16); + if (yc < 0) yc = 0; if (yc >= ENTITY_BLOCKS_LENGTH) yc = ENTITY_BLOCKS_LENGTH - 1; - e->inChunk = true; - e->xChunk = x; - e->yChunk = yc; - e->zChunk = z; + e->inChunk = true; + e->xChunk = x; + e->yChunk = yc; + e->zChunk = z; #ifdef _ENTITIES_RW_SECTION EnterCriticalRWSection(&m_csEntities, true); @@ -1202,13 +1225,13 @@ void LevelChunk::addEntity(shared_ptr e) void LevelChunk::removeEntity(shared_ptr e) { - removeEntity(e, e->yChunk); + removeEntity(e, e->yChunk); } void LevelChunk::removeEntity(shared_ptr e, int yc) { - if (yc < 0) yc = 0; - if (yc >= ENTITY_BLOCKS_LENGTH) yc = ENTITY_BLOCKS_LENGTH - 1; + if (yc < 0) yc = 0; + if (yc >= ENTITY_BLOCKS_LENGTH) yc = ENTITY_BLOCKS_LENGTH - 1; #ifdef _ENTITIES_RW_SECTION EnterCriticalRWSection(&m_csEntities, true); @@ -1246,27 +1269,27 @@ void LevelChunk::removeEntity(shared_ptr e, int yc) bool LevelChunk::isSkyLit(int x, int y, int z) { - return y >= (heightmap[z << 4 | x] & 0xff); + return y >= (heightmap[z << 4 | x] & 0xff); } void LevelChunk::skyBrightnessChanged() { - int x0 = this->x * 16; - int y0 = this->minHeight - 16; - int z0 = this->z * 16; - int x1 = this->x * 16 + 16; - int y1 = Level::maxBuildHeight - 1; - int z1 = this->z * 16 + 16; + int x0 = this->x * 16; + int y0 = this->minHeight - 16; + int z0 = this->z * 16; + int x1 = this->x * 16 + 16; + int y1 = Level::maxBuildHeight - 1; + int z1 = this->z * 16 + 16; - level->setTilesDirty(x0, y0, z0, x1, y1, z1); + level->setTilesDirty(x0, y0, z0, x1, y1, z1); } shared_ptr LevelChunk::getTileEntity(int x, int y, int z) { - TilePos pos(x, y, z); + TilePos pos(x, y, z); // 4J Stu - Changed as we should not be using the [] accessor (causes an insert when we don't want one) - //shared_ptr tileEntity = tileEntities[pos]; + //shared_ptr tileEntity = tileEntities[pos]; EnterCriticalSection(&m_csTileEntities); shared_ptr tileEntity = nullptr; AUTO_VAR(it, tileEntities.find(pos)); @@ -1280,20 +1303,20 @@ shared_ptr LevelChunk::getTileEntity(int x, int y, int z) // which then causes new tile entities to be created if the neighbour has already been destroyed if(level->m_bDisableAddNewTileEntities) return nullptr; - int t = getTile(x, y, z); - if (t <= 0 || !Tile::tiles[t]->isEntityTile()) return nullptr; - + int t = getTile(x, y, z); + if (t <= 0 || !Tile::tiles[t]->isEntityTile()) return nullptr; + // 4J-PB changed from this in 1.7.3 //EntityTile *et = (EntityTile *) Tile::tiles[t]; - //et->onPlace(level, this->x * 16 + x, y, this->z * 16 + z); + //et->onPlace(level, this->x * 16 + x, y, this->z * 16 + z); //if (tileEntity == NULL) //{ - tileEntity = ((EntityTile *) Tile::tiles[t])->newTileEntity(level); - level->setTileEntity(this->x * 16 + x, y, this->z * 16 + z, tileEntity); + tileEntity = dynamic_cast(Tile::tiles[t])->newTileEntity(level); + level->setTileEntity(this->x * 16 + x, y, this->z * 16 + z, tileEntity); //} - //tileEntity = tileEntities[pos]; // 4J - TODO - this doesn't seem right - assignment wrong way? Check + //tileEntity = tileEntities[pos]; // 4J - TODO - this doesn't seem right - assignment wrong way? Check // 4J Stu - It should have been inserted by now, but check to be sure EnterCriticalSection(&m_csTileEntities); @@ -1303,29 +1326,29 @@ shared_ptr LevelChunk::getTileEntity(int x, int y, int z) tileEntity = newIt->second; } LeaveCriticalSection(&m_csTileEntities); - } + } else { tileEntity = it->second; LeaveCriticalSection(&m_csTileEntities); } - if (tileEntity != NULL && tileEntity->isRemoved()) + if (tileEntity != NULL && tileEntity->isRemoved()) { EnterCriticalSection(&m_csTileEntities); - tileEntities.erase(pos); + tileEntities.erase(pos); LeaveCriticalSection(&m_csTileEntities); - return nullptr; - } - - return tileEntity; + return nullptr; + } + + return tileEntity; } void LevelChunk::addTileEntity(shared_ptr te) { - int xx = (int)(te->x - this->x * 16); - int yy = (int)te->y; - int zz = (int)(te->z - this->z * 16); - setTileEntity(xx, yy, zz, te); + int xx = (int)(te->x - this->x * 16); + int yy = (int)te->y; + int zz = (int)(te->z - this->z * 16); + setTileEntity(xx, yy, zz, te); if( loaded ) { EnterCriticalSection(&level->m_tileEntityListCS); @@ -1336,37 +1359,39 @@ void LevelChunk::addTileEntity(shared_ptr te) void LevelChunk::setTileEntity(int x, int y, int z, shared_ptr tileEntity) { - TilePos pos(x, y, z); + TilePos pos(x, y, z); - tileEntity->setLevel(level); - tileEntity->x = this->x * 16 + x; - tileEntity->y = y; - tileEntity->z = this->z * 16 + z; + tileEntity->setLevel(level); + tileEntity->x = this->x * 16 + x; + tileEntity->y = y; + tileEntity->z = this->z * 16 + z; if (getTile(x, y, z) == 0 || !Tile::tiles[getTile(x, y, z)]->isEntityTile()) // 4J - was !(Tile.tiles[getTile(x, y, z)] instanceof EntityTile)) { - app.DebugPrintf("Attempted to place a tile entity where there was no entity tile!\n"); - return; - } + app.DebugPrintf("Attempted to place a tile entity where there was no entity tile!\n"); + return; + } + AUTO_VAR(it, tileEntities.find(pos) ); + if(it != tileEntities.end()) it->second->setRemoved(); tileEntity->clearRemoved(); EnterCriticalSection(&m_csTileEntities); - tileEntities[pos] = tileEntity; + tileEntities[pos] = tileEntity; LeaveCriticalSection(&m_csTileEntities); } void LevelChunk::removeTileEntity(int x, int y, int z) { - TilePos pos(x, y, z); + TilePos pos(x, y, z); if (loaded) { // 4J - was: // TileEntity removeThis = tileEntities.remove(pos); - // if (removeThis != null) { - // removeThis.setRemoved(); - // } + // if (removeThis != null) { + // removeThis.setRemoved(); + // } EnterCriticalSection(&m_csTileEntities); AUTO_VAR(it, tileEntities.find(pos)); if( it != tileEntities.end() ) @@ -1401,10 +1426,11 @@ void LevelChunk::load() for (int i = 0; i < entityTags->size(); i++) { CompoundTag *teTag = entityTags->get(i); - shared_ptr te = EntityIO::loadStatic(teTag, level); - if (te != NULL) + shared_ptr ent = EntityIO::loadStatic(teTag, level); + if (ent != NULL) { - addEntity(te); + ent->onLoadedFromSave(); + addEntity(ent); } } } @@ -1462,13 +1488,13 @@ void LevelChunk::load() void LevelChunk::unload(bool unloadTileEntities) // 4J - added parameter { - loaded = false; + loaded = false; if( unloadTileEntities ) { EnterCriticalSection(&m_csTileEntities); for( AUTO_VAR(it, tileEntities.begin()); it != tileEntities.end(); it++ ) { - // 4J-PB -m 1.7.3 was it->second->setRemoved(); + // 4J-PB -m 1.7.3 was it->second->setRemoved(); level->markForRemoval(it->second); } LeaveCriticalSection(&m_csTileEntities); @@ -1502,12 +1528,12 @@ void LevelChunk::unload(bool unloadTileEntities) // 4J - added parameter PIXBeginNamedEvent(0,"Saving entities"); ListTag *entityTags = new ListTag(); - EnterCriticalSection(&m_csEntities); + EnterCriticalSection(&m_csEntities); for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) { AUTO_VAR(itEnd, entityBlocks[i]->end()); for( vector >::iterator it = entityBlocks[i]->begin(); it != itEnd; it++ ) - { + { shared_ptr e = *it; CompoundTag *teTag = new CompoundTag(); if (e->save(teTag)) @@ -1520,7 +1546,7 @@ void LevelChunk::unload(bool unloadTileEntities) // 4J - added parameter // Clear out this list entityBlocks[i]->clear(); } - LeaveCriticalSection(&m_csEntities); + LeaveCriticalSection(&m_csEntities); m_unloadedEntitiesTag->put(L"Entities", entityTags); PIXEndNamedEvent(); @@ -1547,6 +1573,37 @@ void LevelChunk::unload(bool unloadTileEntities) // 4J - added parameter #endif } +bool LevelChunk::containsPlayer() +{ +#ifdef _ENTITIES_RW_SECTION + EnterCriticalRWSection(&m_csEntities, true); +#else + EnterCriticalSection(&m_csEntities); +#endif + for (int i = 0; i < ENTITY_BLOCKS_LENGTH; i++) + { + vector > *vecEntity = entityBlocks[i]; + for( int j = 0; j < vecEntity->size(); j++ ) + { + if(vecEntity->at(j)->GetType() == eTYPE_SERVERPLAYER ) + { +#ifdef _ENTITIES_RW_SECTION + LeaveCriticalRWSection(&m_csEntities, true); +#else + LeaveCriticalSection(&m_csEntities); +#endif + return true; + } + } + } +#ifdef _ENTITIES_RW_SECTION + LeaveCriticalRWSection(&m_csEntities, true); +#else + LeaveCriticalSection(&m_csEntities); +#endif + return false; +} + #ifdef _LARGE_WORLDS bool LevelChunk::isUnloaded() { @@ -1556,98 +1613,108 @@ bool LevelChunk::isUnloaded() void LevelChunk::markUnsaved() { - this->setUnsaved(true); + this->setUnsaved(true); } -void LevelChunk::getEntities(shared_ptr except, AABB *bb, vector > &es) +void LevelChunk::getEntities(shared_ptr except, AABB *bb, vector > &es, const EntitySelector *selector) { - int yc0 = Mth::floor((bb->y0 - 2) / 16); - int yc1 = Mth::floor((bb->y1 + 2) / 16); - if (yc0 < 0) yc0 = 0; - if (yc1 >= ENTITY_BLOCKS_LENGTH) yc1 = ENTITY_BLOCKS_LENGTH - 1; + int yc0 = Mth::floor((bb->y0 - 2) / 16); + int yc1 = Mth::floor((bb->y1 + 2) / 16); + if (yc0 < 0) yc0 = 0; + if (yc1 >= ENTITY_BLOCKS_LENGTH) yc1 = ENTITY_BLOCKS_LENGTH - 1; #ifndef __PSVITA__ // AP - RW critical sections are expensive so enter once in Level::getEntities EnterCriticalSection(&m_csEntities); #endif - for (int yc = yc0; yc <= yc1; yc++) + for (int yc = yc0; yc <= yc1; yc++) { - vector > *entities = entityBlocks[yc]; + vector > *entities = entityBlocks[yc]; AUTO_VAR(itEnd, entities->end()); for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) { - shared_ptr e = *it; //entities->at(i); - if (e != except && e->bb->intersects(bb)) + shared_ptr e = *it; //entities->at(i); + if (e != except && e->bb->intersects(bb) && (selector == NULL || selector->matches(e))) { es.push_back(e); - vector > *subs = e->getSubEntities(); - if (subs != NULL) + vector > *subs = e->getSubEntities(); + if (subs != NULL) { - for (int j = 0; j < subs->size(); j++) + for (int j = 0; j < subs->size(); j++) { - e = subs->at(j); - if (e != except && e->bb->intersects(bb)) + e = subs->at(j); + if (e != except && e->bb->intersects(bb) && (selector == NULL || selector->matches(e))) { - es.push_back(e); - } - } - } + es.push_back(e); + } + } + } } - } - } + } + } #ifndef __PSVITA__ LeaveCriticalSection(&m_csEntities); #endif } -void LevelChunk::getEntitiesOfClass(const type_info& ec, AABB *bb, vector > &es) +void LevelChunk::getEntitiesOfClass(const type_info& ec, AABB *bb, vector > &es, const EntitySelector *selector) { - int yc0 = Mth::floor((bb->y0 - 2) / 16); - int yc1 = Mth::floor((bb->y1 + 2) / 16); + int yc0 = Mth::floor((bb->y0 - 2) / 16); + int yc1 = Mth::floor((bb->y1 + 2) / 16); - if (yc0 < 0) + if (yc0 < 0) { - yc0 = 0; - } + yc0 = 0; + } else if (yc0 >= ENTITY_BLOCKS_LENGTH) { - yc0 = ENTITY_BLOCKS_LENGTH - 1; - } - if (yc1 >= ENTITY_BLOCKS_LENGTH) + yc0 = ENTITY_BLOCKS_LENGTH - 1; + } + if (yc1 >= ENTITY_BLOCKS_LENGTH) { - yc1 = ENTITY_BLOCKS_LENGTH - 1; - } + yc1 = ENTITY_BLOCKS_LENGTH - 1; + } else if (yc1 < 0) { - yc1 = 0; - } + yc1 = 0; + } #ifndef __PSVITA__ // AP - RW critical sections are expensive so enter once in Level::getEntitiesOfClass EnterCriticalSection(&m_csEntities); #endif - for (int yc = yc0; yc <= yc1; yc++) + for (int yc = yc0; yc <= yc1; yc++) { - vector > *entities = entityBlocks[yc]; - + vector > *entities = entityBlocks[yc]; + AUTO_VAR(itEnd, entities->end()); for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) { - shared_ptr e = *it; //entities->at(i); + shared_ptr e = *it; //entities->at(i); bool isAssignableFrom = false; // Some special cases where the base class is a general type that our class may be derived from, otherwise do a direct comparison of type_info - if( ec == typeid(Player) ) { if( dynamic_pointer_cast(e) != NULL ) isAssignableFrom = true; } - else if ( ec == typeid(Mob) ) { if( dynamic_pointer_cast(e) != NULL ) isAssignableFrom = true; } - else if ( ec == typeid(Monster) ) { if( dynamic_pointer_cast(e) != NULL ) isAssignableFrom = true; } - else if ( ec == typeid(Zombie) ) { if( dynamic_pointer_cast(e) != NULL ) isAssignableFrom = true; } + if ( ec==typeid(Player) ) isAssignableFrom = e->instanceof(eTYPE_PLAYER); + else if ( ec==typeid(Entity) ) isAssignableFrom = e->instanceof(eTYPE_ENTITY); + else if ( ec==typeid(Mob) ) isAssignableFrom = e->instanceof(eTYPE_MOB); + else if ( ec==typeid(LivingEntity) ) isAssignableFrom = e->instanceof(eTYPE_LIVINGENTITY); + else if ( ec==typeid(ItemEntity) ) isAssignableFrom = e->instanceof(eTYPE_ITEMENTITY); + else if ( ec==typeid(Minecart) ) isAssignableFrom = e->instanceof(eTYPE_MINECART); + else if ( ec==typeid(Monster) ) isAssignableFrom = e->instanceof(eTYPE_MONSTER); + else if ( ec==typeid(Zombie) ) isAssignableFrom = e->instanceof(eTYPE_ZOMBIE); else if(e != NULL && ec == typeid(*(e.get())) ) isAssignableFrom = true; - if (isAssignableFrom && e->bb->intersects(bb)) es.push_back(e); + if (isAssignableFrom && e->bb->intersects(bb)) + { + if (selector == NULL || selector->matches(e)) + { + es.push_back(e); + } + } // 4J - note needs to be equivalent to baseClass.isAssignableFrom(e.getClass()) - } - } + } + } #ifndef __PSVITA__ LeaveCriticalSection(&m_csEntities); #endif @@ -1655,16 +1722,16 @@ void LevelChunk::getEntitiesOfClass(const type_info& ec, AABB *bb, vectorsize(); - } + entityCount += (int)entityBlocks[yc]->size(); + } #ifdef _ENTITIES_RW_SECTION LeaveCriticalRWSection(&m_csEntities, false); #else @@ -1675,22 +1742,27 @@ int LevelChunk::countEntities() bool LevelChunk::shouldSave(bool force) { - if (dontSave) return false; - if (force) + if (dontSave) return false; + if (force) + { + if ((lastSaveHadEntities && level->getGameTime() != lastSaveTime) || m_unsaved) + { + return true; + } + } + else { - if (lastSaveHadEntities && level->getTime() != lastSaveTime) return true; - } else { - if (lastSaveHadEntities && level->getTime() >= lastSaveTime + 20 * 30) return true; - } + if (lastSaveHadEntities && level->getGameTime() >= lastSaveTime + 20 * 30) return true; + } - return m_unsaved; + return m_unsaved; } int LevelChunk::getBlocksAndData(byteArray *data, int x0, int y0, int z0, int x1, int y1, int z1, int p, bool includeLighting/* = true*/) { - int xs = x1 - x0; - int ys = y1 - y0; - int zs = z1 - z0; + int xs = x1 - x0; + int ys = y1 - y0; + int zs = z1 - z0; // 4J Stu - Added this because some "min" functions don't let us use our constants :( int compressedHeight = Level::COMPRESSED_CHUNK_SECTION_HEIGHT; @@ -1714,26 +1786,26 @@ int LevelChunk::getBlocksAndData(byteArray *data, int x0, int y0, int z0, int x1 } /* - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) - { - int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> 1; - int len = (y1 - y0) / 2; - System::arraycopy(blockLight->data, slot, data, p, len); - p += len; - } - - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) - { - int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> 1; - int len = (y1 - y0) / 2; - System::arraycopy(skyLight->data, slot, data, p, len); - p += len; - } - */ + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> 1; + int len = (y1 - y0) / 2; + System::arraycopy(blockLight->data, slot, data, p, len); + p += len; + } + + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> 1; + int len = (y1 - y0) / 2; + System::arraycopy(skyLight->data, slot, data, p, len); + p += len; + } + */ - return p; + return p; } // 4J added - return true if setBlocksAndData would change any blocks @@ -1791,16 +1863,16 @@ int LevelChunk::setBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, if(y0 < Level::COMPRESSED_CHUNK_SECTION_HEIGHT) p += lowerBlocks->setDataRegion( data, x0, y0, z0, x1, min(compressedHeight, y1), z1, p, includeLighting ? NULL : tileUpdatedCallback, this, 0 ); if(y1 > Level::COMPRESSED_CHUNK_SECTION_HEIGHT) p += upperBlocks->setDataRegion( data, x0, max(y0-compressedHeight,0), z0, x1, y1-Level::COMPRESSED_CHUNK_SECTION_HEIGHT, z1, p, includeLighting ? NULL : tileUpdatedCallback, this, Level::COMPRESSED_CHUNK_SECTION_HEIGHT ); /* - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) - { - int slot = x << level->depthBitsPlusFour | z << level->depthBits | y0; - int len = y1 - y0; - System::arraycopy(data, p, &blocks, slot, len); - p += len; - }*/ + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + int slot = x << level->depthBitsPlusFour | z << level->depthBits | y0; + int len = y1 - y0; + System::arraycopy(data, p, &blocks, slot, len); + p += len; + }*/ - recalcHeightmapOnly(); + recalcHeightmapOnly(); // 4J - replaced data storage as now uses SparseDataStorage if(y0 < Level::COMPRESSED_CHUNK_SECTION_HEIGHT) p += lowerData->setDataRegion( data, x0, y0, z0, x1, min(compressedHeight, y1), z1, p, includeLighting ? NULL : tileUpdatedCallback, this, 0 ); @@ -1838,30 +1910,30 @@ int LevelChunk::setBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, } /* - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) - { - int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> 1; - int len = (y1 - y0) / 2; - System::arraycopy(data, p, &blockLight->data, slot, len); - p += len; - } - - for (int x = x0; x < x1; x++) - for (int z = z0; z < z1; z++) - { - int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> 1; - int len = (y1 - y0) / 2; - System::arraycopy(data, p, &skyLight->data, slot, len); - p += len; - } - */ + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> 1; + int len = (y1 - y0) / 2; + System::arraycopy(data, p, &blockLight->data, slot, len); + p += len; + } + + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + int slot = (x << level->depthBitsPlusFour | z << level->depthBits | y0) >> 1; + int len = (y1 - y0) / 2; + System::arraycopy(data, p, &skyLight->data, slot, len); + p += len; + } + */ for(AUTO_VAR(it, tileEntities.begin()); it != tileEntities.end(); ++it) { it->second->clearCache(); } -// recalcHeightmap(); + // recalcHeightmap(); // If the includeLighting flag is set, then this is a full chunk's worth of data. This is a good time to compress everything that we've just set up. if( includeLighting ) @@ -1871,7 +1943,7 @@ int LevelChunk::setBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, compressData(); } - return p; + return p; } void LevelChunk::setCheckAllLight() @@ -1881,26 +1953,26 @@ void LevelChunk::setCheckAllLight() Random *LevelChunk::getRandom(__int64 l) { - return new Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l); + return new Random((level->getSeed() + x * x * 4987142 + x * 5947611 + z * z * 4392871l + z * 389711) ^ l); } bool LevelChunk::isEmpty() { - return false; + return false; } void LevelChunk::attemptCompression() { // 4J - removed #if 0 - try { - ByteArrayOutputStream *baos = new ByteArrayOutputStream(); - GZIPOutputStream *gzos = new GZIPOutputStream(baos); - DataOutputStream *dos = new DataOutputStream(gzos); - dos.close(); - System.out.println("Compressed size: " + baos.toByteArray().length); - } catch (Exception e) { - - } + try { + ByteArrayOutputStream *baos = new ByteArrayOutputStream(); + GZIPOutputStream *gzos = new GZIPOutputStream(baos); + DataOutputStream *dos = new DataOutputStream(gzos); + dos.close(); + System.out.println("Compressed size: " + baos.toByteArray().length); + } catch (Exception e) { + + } #endif } @@ -1955,7 +2027,7 @@ void LevelChunk::tick() ChunkPos *LevelChunk::getPos() { - return new ChunkPos(x, z); + return new ChunkPos(x, z); } bool LevelChunk::isYSpaceEmpty(int y1, int y2) @@ -1963,20 +2035,34 @@ bool LevelChunk::isYSpaceEmpty(int y1, int y2) return false; // 4J Unused /*if (y1 < 0) { - y1 = 0; + y1 = 0; } if (y2 >= Level.maxBuildHeight) { - y2 = Level.maxBuildHeight - 1; + y2 = Level.maxBuildHeight - 1; } for (int y = y1; y <= y2; y += 16) { - LevelChunkSection section = sections[y >> 4]; - if (section != null && !section.isEmpty()) { - return false; - } + LevelChunkSection section = sections[y >> 4]; + if (section != null && !section.isEmpty()) { + return false; + } } return true;*/ } +// 4J Added +void LevelChunk::reloadBiomes() +{ + BiomeSource *biomeSource = level->dimension->biomeSource; + for(unsigned int x = 0; x < 16; ++x) + { + for(unsigned int z = 0; z < 16; ++z) + { + Biome *biome = biomeSource->getBiome((this->x << 4) + x, (this->z << 4) + z); + biomes[(z << 4) | x] = (byte) ( (biome->id) & 0xff); + } + } +} + Biome *LevelChunk::getBiome(int x, int z, BiomeSource *biomeSource) { int value = biomes[(z << 4) | x] & 0xff; @@ -2007,33 +2093,33 @@ void LevelChunk::setBiomes(byteArray biomes) // 4J - optimisation brought forward from 1.8.2 int LevelChunk::getTopRainBlock(int x, int z) { - int slot = x | (z << 4); - int h = rainHeights[slot]; + int slot = x | (z << 4); + int h = rainHeights[slot]; - if (h == 255) + if (h == 255) { - int y = Level::maxBuildHeight - 1; - h = -1; - while (y > 0 && h == -1) + int y = Level::maxBuildHeight - 1; + h = -1; + while (y > 0 && h == -1) { - int t = getTile(x, y, z); - Material *m = t == 0 ? Material::air : Tile::tiles[t]->material; - if (!m->blocksMotion() && !m->isLiquid()) + int t = getTile(x, y, z); + Material *m = t == 0 ? Material::air : Tile::tiles[t]->material; + if (!m->blocksMotion() && !m->isLiquid()) { - y--; - } + y--; + } else { - h = y + 1; - } - } + h = y + 1; + } + } // 255 indicates that the rain height needs recalculated. If the rain height ever actually Does get to 255, then it will just keep not being cached, so // probably better just to let the rain height be 254 in this instance and suffer a slightly incorrect results if( h == 255 ) h = 254; rainHeights[slot] = h; - } + } - return h; + return h; } // 4J added as optimisation, these biome checks are expensive so caching through flags in levelchunk @@ -2313,7 +2399,14 @@ int LevelChunk::getBlocksAllocatedSize(int *count0, int *count1, int *count2, in int LevelChunk::getHighestNonEmptyY() { int highestNonEmptyY = -1; - if(upperBlocks) highestNonEmptyY = upperBlocks->getHighestNonEmptyY() + Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + if(upperBlocks) + { + int upperNonEmpty = upperBlocks->getHighestNonEmptyY(); + if( upperNonEmpty >= 0 ) + { + highestNonEmptyY = upperNonEmpty + Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + } + } if(highestNonEmptyY < 0) highestNonEmptyY = lowerBlocks->getHighestNonEmptyY(); if(highestNonEmptyY < 0) highestNonEmptyY = 0; @@ -2400,7 +2493,7 @@ void LevelChunk::reorderBlocksAndDataToXZY(int y0, int xs, int ys, int zs, byteA int y1 = y0 + ys; unsigned int tileCount = xs * ys * zs; unsigned int halfTileCount = tileCount/2; - + int sectionHeight = Level::COMPRESSED_CHUNK_SECTION_HEIGHT; int lowerYSpan = min(y1, sectionHeight) - y0; int upperYSpan = ys - lowerYSpan; diff --git a/Minecraft.World/LevelChunk.h b/Minecraft.World/LevelChunk.h index e9510ad5..bc45016b 100644 --- a/Minecraft.World/LevelChunk.h +++ b/Minecraft.World/LevelChunk.h @@ -5,6 +5,8 @@ class DataLayer; class TileEntity; class Random; class ChunkSource; +class EntitySelector; + #include "SparseLightStorage.h" #include "CompressedTileStorage.h" #include "SparseDataStorage.h" @@ -31,7 +33,7 @@ public: const int ENTITY_BLOCKS_LENGTH; static const int BLOCKS_LENGTH = Level::CHUNK_TILE_COUNT; // 4J added - static bool touchedSky; + static bool touchedSky; enum EColumnFlag { @@ -41,7 +43,7 @@ public: eColumnFlag_biomeHasRain = 8, }; -// byteArray blocks; + // byteArray blocks; // 4J - actual storage for blocks is now private with public methods to access it private: CompressedTileStorage *lowerBlocks; // 0 - 127 @@ -52,10 +54,10 @@ public: void getBlockData(byteArray data); // Sets data in passed in array of size 32768, from the block data in this chunk int getBlocksAllocatedSize(int *count0, int *count1, int *count2, int *count4, int *count8); - bool loaded; + bool loaded; unsigned char rainHeights[16*16]; // 4J - optimisation brought forward from 1.8.2 (was int arrayb in java though) unsigned char columnFlags[16*8]; // 4J - lighting update brought forward from 1.8.2, was a bool array but now mixed with other flags in our version, and stored in nybbles - Level *level; + Level *level; // 4J - actual storage for data is now private with public methods to access it private: @@ -65,7 +67,7 @@ public: void setDataData(byteArray data); // Set data to that passed in in the input array of size 32768 void getDataData(byteArray data); // Sets data in passed in array of size 16384, from the data in this chunk -// DataLayer *data; + // DataLayer *data; private: // 4J - actual storage for sky & block lights is now private with new methods to be able to access it. @@ -93,16 +95,16 @@ public: void readCompressedSkyLightData(DataInputStream *dis); void readCompressedBlockLightData(DataInputStream *dis); - byteArray heightmap; - int minHeight; - int x, z; + byteArray heightmap; + int minHeight; + int x, z; private: bool hasGapsToCheck; public: - unordered_map, TilePosKeyHash, TilePosKeyEq> tileEntities; - vector > **entityBlocks; - + unordered_map, TilePosKeyHash, TilePosKeyEq> tileEntities; + vector > **entityBlocks; + static const int sTerrainPopulatedFromHere = 2; static const int sTerrainPopulatedFromW = 4; static const int sTerrainPopulatedFromS = 8; @@ -116,17 +118,17 @@ public: static const int sTerrainPopulatedAllNeighbours = 1022; // The post-processing passes of all neighbours to this chunk are complete static const int sTerrainPostPostProcessed = 1024; // This chunk has been post-post-processed, which is only done when all neighbours have been post-processed - short terrainPopulated; // 4J - changed from bool to bitfield within short + short terrainPopulated; // 4J - changed from bool to bitfield within short short *serverTerrainPopulated; // 4J added void setUnsaved(bool unsaved); // 4J added protected: // 4J Stu - Stopped this being private so we can add some more logic to it - bool m_unsaved; + bool m_unsaved; public: - bool dontSave; - bool lastSaveHadEntities; + bool dontSave; + bool lastSaveHadEntities; #ifdef SHARING_ENABLED bool sharingTilesAndData; // 4J added #endif @@ -135,8 +137,10 @@ public: virtual void reSyncLighting(); // 4J added void startSharingTilesAndData(int forceMs = 0); // 4J added __int64 lastUnsharedTime; // 4J added - __int64 lastSaveTime; + __int64 lastSaveTime; bool seenByPlayer; + int lowestHeightmap; + __int64 inhabitedTime; #ifdef _LARGE_WORLDS bool m_bUnloaded; @@ -149,73 +153,74 @@ private: public: virtual void init(Level *level, int x, int z); - LevelChunk(Level *level, int x, int z); - LevelChunk(Level *level, byteArray blocks, int x, int z); + LevelChunk(Level *level, int x, int z); + LevelChunk(Level *level, byteArray blocks, int x, int z); LevelChunk(Level *level, int x, int z, LevelChunk *lc); ~LevelChunk(); - virtual bool isAt(int x, int z); + virtual bool isAt(int x, int z); - virtual int getHeightmap(int x, int z); + virtual int getHeightmap(int x, int z); int getHighestSectionPosition(); - virtual void recalcBlockLights(); + virtual void recalcBlockLights(); - virtual void recalcHeightmapOnly(); + virtual void recalcHeightmapOnly(); - virtual void recalcHeightmap(); + virtual void recalcHeightmap(); - virtual void lightLava(); + virtual void lightLava(); private: - void lightGaps(int x, int z); + void lightGaps(int x, int z); // 4J - changes for lighting brought forward from 1.8.2 public: void recheckGaps(bool bForce = false); // 4J - added parameter, made public private: - void lightGap(int x, int z, int source); + void lightGap(int x, int z, int source); void lightGap(int x, int z, int y1, int y2); - void recalcHeight(int x, int yStart, int z); + void recalcHeight(int x, int yStart, int z); public: virtual int getTileLightBlock(int x, int y, int z); - virtual int getTile(int x, int y, int z); - virtual bool setTileAndData(int x, int y, int z, int _tile, int _data); - virtual bool setTile(int x, int y, int z, int _tile); - virtual int getData(int x, int y, int z); - virtual bool setData(int x, int y, int z, int val, int mask, bool *maskedBitsChanged); // 4J added mask - virtual int getBrightness(LightLayer::variety layer, int x, int y, int z); + virtual int getTile(int x, int y, int z); + virtual bool setTileAndData(int x, int y, int z, int _tile, int _data); + virtual bool setTile(int x, int y, int z, int _tile); + virtual int getData(int x, int y, int z); + virtual bool setData(int x, int y, int z, int val, int mask, bool *maskedBitsChanged); // 4J added mask + virtual int getBrightness(LightLayer::variety layer, int x, int y, int z); virtual void getNeighbourBrightnesses(int *brightnesses, LightLayer::variety layer, int x, int y, int z); // 4J added - virtual void setBrightness(LightLayer::variety layer, int x, int y, int z, int brightness); - virtual int getRawBrightness(int x, int y, int z, int skyDampen); - virtual void addEntity(shared_ptr e); - virtual void removeEntity(shared_ptr e); - virtual void removeEntity(shared_ptr e, int yc); - virtual bool isSkyLit(int x, int y, int z); - virtual void skyBrightnessChanged(); - virtual shared_ptr getTileEntity(int x, int y, int z); - virtual void addTileEntity(shared_ptr te); - virtual void setTileEntity(int x, int y, int z, shared_ptr tileEntity); - virtual void removeTileEntity(int x, int y, int z); - virtual void load(); - virtual void unload(bool unloadTileEntities) ; // 4J - added parameter + virtual void setBrightness(LightLayer::variety layer, int x, int y, int z, int brightness); + virtual int getRawBrightness(int x, int y, int z, int skyDampen); + virtual void addEntity(shared_ptr e); + virtual void removeEntity(shared_ptr e); + virtual void removeEntity(shared_ptr e, int yc); + virtual bool isSkyLit(int x, int y, int z); + virtual void skyBrightnessChanged(); + virtual shared_ptr getTileEntity(int x, int y, int z); + virtual void addTileEntity(shared_ptr te); + virtual void setTileEntity(int x, int y, int z, shared_ptr tileEntity); + virtual void removeTileEntity(int x, int y, int z); + virtual void load(); + virtual void unload(bool unloadTileEntities) ; // 4J - added parameter + virtual bool containsPlayer(); // 4J - added #ifdef _LARGE_WORLDS virtual bool isUnloaded(); #endif - virtual void markUnsaved(); - virtual void getEntities(shared_ptr except, AABB *bb, vector > &es); - virtual void getEntitiesOfClass(const type_info& ec, AABB *bb, vector > &es); - virtual int countEntities(); - virtual bool shouldSave(bool force); - virtual int getBlocksAndData(byteArray *data, int x0, int y0, int z0, int x1, int y1, int z1, int p, bool includeLighting = true); // 4J - added includeLighting parameter + virtual void markUnsaved(); + virtual void getEntities(shared_ptr except, AABB *bb, vector > &es, const EntitySelector *selector); + virtual void getEntitiesOfClass(const type_info& ec, AABB *bb, vector > &es, const EntitySelector *selector); + virtual int countEntities(); + virtual bool shouldSave(bool force); + virtual int getBlocksAndData(byteArray *data, int x0, int y0, int z0, int x1, int y1, int z1, int p, bool includeLighting = true); // 4J - added includeLighting parameter static void tileUpdatedCallback(int x, int y, int z, void *param, int yparam); // 4J added - virtual int setBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, int y1, int z1, int p, bool includeLighting = true); // 4J - added includeLighting parameter + virtual int setBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, int y1, int z1, int p, bool includeLighting = true); // 4J - added includeLighting parameter virtual bool testSetBlocksAndData(byteArray data, int x0, int y0, int z0, int x1, int y1, int z1, int p); // 4J added virtual void setCheckAllLight(); - virtual Random *getRandom(__int64 l); - virtual bool isEmpty(); - virtual void attemptCompression(); + virtual Random *getRandom(__int64 l); + virtual bool isEmpty(); + virtual void attemptCompression(); #ifdef SHARING_ENABLED static CRITICAL_SECTION m_csSharing; // 4J added @@ -234,6 +239,7 @@ public: void tick(); // 4J - lighting change brought forward from 1.8.2 ChunkPos *getPos(); bool isYSpaceEmpty(int y1, int y2); + void reloadBiomes(); // 4J added virtual Biome *getBiome(int x, int z, BiomeSource *biomeSource); byteArray getBiomes(); void setBiomes(byteArray biomes); diff --git a/Minecraft.World/LevelData.cpp b/Minecraft.World/LevelData.cpp index 026dca70..91b72fe8 100644 --- a/Minecraft.World/LevelData.cpp +++ b/Minecraft.World/LevelData.cpp @@ -12,7 +12,7 @@ LevelData::LevelData() LevelData::LevelData(CompoundTag *tag) { - seed = tag->getLong(L"RandomSeed"); + seed = tag->getLong(L"RandomSeed"); m_pGenerator = LevelType::lvl_normal; if (tag->contains(L"generatorName")) { @@ -31,31 +31,41 @@ LevelData::LevelData(CompoundTag *tag) } m_pGenerator = m_pGenerator->getReplacementForVersion(generatorVersion); } + + if (tag->contains(L"generatorOptions")) generatorOptions = tag->getString(L"generatorOptions"); } gameType = GameType::byId(tag->getInt(L"GameType")); - if (tag->contains(L"MapFeatures")) + if (tag->contains(L"MapFeatures")) { - generateMapFeatures = tag->getBoolean(L"MapFeatures"); - } + generateMapFeatures = tag->getBoolean(L"MapFeatures"); + } else { generateMapFeatures = true; - } + } spawnBonusChest = tag->getBoolean(L"spawnBonusChest"); - xSpawn = tag->getInt(L"SpawnX"); - ySpawn = tag->getInt(L"SpawnY"); - zSpawn = tag->getInt(L"SpawnZ"); - time = tag->getLong(L"Time"); - lastPlayed = tag->getLong(L"LastPlayed"); - sizeOnDisk = tag->getLong(L"SizeOnDisk"); - levelName = tag->getString(L"LevelName"); - version = tag->getInt(L"version"); - rainTime = tag->getInt(L"rainTime"); - raining = tag->getBoolean(L"raining"); - thunderTime = tag->getInt(L"thunderTime"); - thundering = tag->getBoolean(L"thundering"); + xSpawn = tag->getInt(L"SpawnX"); + ySpawn = tag->getInt(L"SpawnY"); + zSpawn = tag->getInt(L"SpawnZ"); + gameTime = tag->getLong(L"Time"); + if (tag->contains(L"DayTime")) + { + dayTime = tag->getLong(L"DayTime"); + } + else + { + dayTime = gameTime; + } + lastPlayed = tag->getLong(L"LastPlayed"); + sizeOnDisk = tag->getLong(L"SizeOnDisk"); + levelName = tag->getString(L"LevelName"); + version = tag->getInt(L"version"); + rainTime = tag->getInt(L"rainTime"); + raining = tag->getBoolean(L"raining"); + thunderTime = tag->getInt(L"thunderTime"); + thundering = tag->getBoolean(L"thundering"); hardcore = tag->getBoolean(L"hardcore"); if (tag->contains(L"initialized")) @@ -76,6 +86,12 @@ LevelData::LevelData(CompoundTag *tag) allowCommands = gameType == GameType::CREATIVE; } + // 4J: Game rules are now stored with app game host options + /*if (tag->contains(L"GameRules")) + { + gameRules.loadFromTag(tag->getCompound(L"GameRules")); + }*/ + newSeaLevel = tag->getBoolean(L"newSeaLevel"); // 4J added - only use new sea level for newly created maps. This read defaults to false. (sea level changes in 1.8.2) hasBeenInCreative = tag->getBoolean(L"hasBeenInCreative"); // 4J added so we can not award achievements to levels modified in creative @@ -111,7 +127,33 @@ LevelData::LevelData(CompoundTag *tag) // 4J Added m_xzSize = tag->getInt(L"XZSize"); m_hellScale = tag->getInt(L"HellScale"); - + +#ifdef _LARGE_WORLDS + m_classicEdgeMoat = tag->getInt(L"ClassicMoat"); + m_smallEdgeMoat = tag->getInt(L"SmallMoat"); + m_mediumEdgeMoat = tag->getInt(L"MediumMoat"); + + int newWorldSize = app.GetGameNewWorldSize(); + int newHellScale = app.GetGameNewHellScale(); + m_hellScaleOld = m_hellScale; + m_xzSizeOld = m_xzSize; + if(newWorldSize > m_xzSize) + { + bool bUseMoat = app.GetGameNewWorldSizeUseMoat(); + switch (m_xzSize) + { + case LEVEL_WIDTH_CLASSIC: m_classicEdgeMoat = bUseMoat; break; + case LEVEL_WIDTH_SMALL: m_smallEdgeMoat = bUseMoat; break; + case LEVEL_WIDTH_MEDIUM: m_mediumEdgeMoat = bUseMoat; break; + default: assert(0); break; + } + assert(newWorldSize > m_xzSize); + m_xzSize = newWorldSize; + m_hellScale = newHellScale; + } +#endif + + m_xzSize = min(m_xzSize,LEVEL_MAX_WIDTH); m_xzSize = max(m_xzSize,LEVEL_MIN_WIDTH); @@ -125,15 +167,29 @@ LevelData::LevelData(CompoundTag *tag) hellXZSize = m_xzSize / m_hellScale; } +#ifdef _LARGE_WORLDS + // set the host option, in case it wasn't setup already + EGameHostOptionWorldSize hostOptionworldSize = e_worldSize_Unknown; + switch(m_xzSize) + { + case LEVEL_WIDTH_CLASSIC: hostOptionworldSize = e_worldSize_Classic; break; + case LEVEL_WIDTH_SMALL: hostOptionworldSize = e_worldSize_Small; break; + case LEVEL_WIDTH_MEDIUM: hostOptionworldSize = e_worldSize_Medium; break; + case LEVEL_WIDTH_LARGE: hostOptionworldSize = e_worldSize_Large; break; + default: assert(0); break; + } + app.SetGameHostOption(eGameHostOption_WorldSize, hostOptionworldSize ); +#endif + /* 4J - we don't store this anymore - if (tag->contains(L"Player")) + if (tag->contains(L"Player")) { - loadedPlayerTag = tag->getCompound(L"Player"); - dimension = loadedPlayerTag->getInt(L"Dimension"); - } + loadedPlayerTag = tag->getCompound(L"Player"); + dimension = loadedPlayerTag->getInt(L"Dimension"); + } else { - this->loadedPlayerTag = NULL; + this->loadedPlayerTag = NULL; } */ dimension = 0; @@ -141,45 +197,47 @@ LevelData::LevelData(CompoundTag *tag) LevelData::LevelData(LevelSettings *levelSettings, const wstring& levelName) { - this->seed = levelSettings->getSeed(); - this->gameType = levelSettings->getGameType(); - this->generateMapFeatures = levelSettings->isGenerateMapFeatures(); - this->spawnBonusChest = levelSettings->hasStartingBonusItems(); - this->levelName = levelName; - this->m_pGenerator = levelSettings->getLevelType(); - this->hardcore = levelSettings->isHardcore(); + seed = levelSettings->getSeed(); + gameType = levelSettings->getGameType(); + generateMapFeatures = levelSettings->isGenerateMapFeatures(); + spawnBonusChest = levelSettings->hasStartingBonusItems(); + this->levelName = levelName; + m_pGenerator = levelSettings->getLevelType(); + hardcore = levelSettings->isHardcore(); + generatorOptions = levelSettings->getLevelTypeOptions(); + allowCommands = levelSettings->getAllowCommands(); // 4J Stu - Default initers - this->xSpawn = 0; - this->ySpawn = 0; - this->zSpawn = 0; - this->time = -1; // 4J-JEV: Edited: To know when this is uninitialized. - this->lastPlayed = 0; - this->sizeOnDisk = 0; -// this->loadedPlayerTag = NULL; // 4J - we don't store this anymore - this->dimension = 0; - this->version = 0; - this->rainTime = 0; - this->raining = false; - this->thunderTime = 0; - this->thundering = false; - this->allowCommands = levelSettings->getAllowCommands(); - this->initialized = false; - this->newSeaLevel = levelSettings->useNewSeaLevel(); // 4J added - only use new sea level for newly created maps (sea level changes in 1.8.2) - this->hasBeenInCreative = levelSettings->getGameType() == GameType::CREATIVE; // 4J added + xSpawn = 0; + ySpawn = 0; + zSpawn = 0; + dayTime = -1; // 4J-JEV: Edited: To know when this is uninitialized. + gameTime = -1; + lastPlayed = 0; + sizeOnDisk = 0; + // this->loadedPlayerTag = NULL; // 4J - we don't store this anymore + dimension = 0; + version = 0; + rainTime = 0; + raining = false; + thunderTime = 0; + thundering = false; + initialized = false; + newSeaLevel = levelSettings->useNewSeaLevel(); // 4J added - only use new sea level for newly created maps (sea level changes in 1.8.2) + hasBeenInCreative = levelSettings->getGameType() == GameType::CREATIVE; // 4J added // 4J-PB for the stronghold position - this->bStronghold=false; - this->xStronghold = 0; - this->yStronghold = 0; - this->zStronghold = 0; - - this->xStrongholdEndPortal = 0; - this->zStrongholdEndPortal = 0; - this->bStrongholdEndPortal = false; + bStronghold=false; + xStronghold = 0; + yStronghold = 0; + zStronghold = 0; + + xStrongholdEndPortal = 0; + zStrongholdEndPortal = 0; + bStrongholdEndPortal = false; m_xzSize = levelSettings->getXZSize(); m_hellScale = levelSettings->getHellScale(); - + m_xzSize = min(m_xzSize,LEVEL_MAX_WIDTH); m_xzSize = max(m_xzSize,LEVEL_MIN_WIDTH); @@ -191,56 +249,74 @@ LevelData::LevelData(LevelSettings *levelSettings, const wstring& levelName) { ++m_hellScale; hellXZSize = m_xzSize / m_hellScale; -} + } +#ifdef _LARGE_WORLDS + m_hellScaleOld = m_hellScale; + m_xzSizeOld = m_xzSize; + m_classicEdgeMoat = false; + m_smallEdgeMoat = false; + m_mediumEdgeMoat = false; +#endif + } LevelData::LevelData(LevelData *copy) { - this->seed = copy->seed; - this->m_pGenerator = copy->m_pGenerator; - this->gameType = copy->gameType; - this->generateMapFeatures = copy->generateMapFeatures; - this->spawnBonusChest = copy->spawnBonusChest; - this->xSpawn = copy->xSpawn; - this->ySpawn = copy->ySpawn; - this->zSpawn = copy->zSpawn; - this->time = copy->time; - this->lastPlayed = copy->lastPlayed; - this->sizeOnDisk = copy->sizeOnDisk; -// this->loadedPlayerTag = copy->loadedPlayerTag; // 4J - we don't store this anymore - this->dimension = copy->dimension; - this->levelName = copy->levelName; - this->version = copy->version; - this->rainTime = copy->rainTime; - this->raining = copy->raining; - this->thunderTime = copy->thunderTime; - this->thundering = copy->thundering; - this->hardcore = copy->hardcore; - this->allowCommands = copy->allowCommands; - this->initialized = copy->initialized; - this->newSeaLevel = copy->newSeaLevel; - this->hasBeenInCreative = copy->hasBeenInCreative; + seed = copy->seed; + m_pGenerator = copy->m_pGenerator; + generatorOptions = copy->generatorOptions; + gameType = copy->gameType; + generateMapFeatures = copy->generateMapFeatures; + spawnBonusChest = copy->spawnBonusChest; + xSpawn = copy->xSpawn; + ySpawn = copy->ySpawn; + zSpawn = copy->zSpawn; + gameTime = copy->gameTime; + dayTime = copy->dayTime; + lastPlayed = copy->lastPlayed; + sizeOnDisk = copy->sizeOnDisk; + // this->loadedPlayerTag = copy->loadedPlayerTag; // 4J - we don't store this anymore + dimension = copy->dimension; + levelName = copy->levelName; + version = copy->version; + rainTime = copy->rainTime; + raining = copy->raining; + thunderTime = copy->thunderTime; + thundering = copy->thundering; + hardcore = copy->hardcore; + allowCommands = copy->allowCommands; + initialized = copy->initialized; + newSeaLevel = copy->newSeaLevel; + hasBeenInCreative = copy->hasBeenInCreative; + gameRules = copy->gameRules; // 4J-PB for the stronghold position - this->bStronghold=copy->bStronghold; - this->xStronghold = copy->xStronghold; - this->yStronghold = copy->yStronghold; - this->zStronghold = copy->zStronghold; - - this->xStrongholdEndPortal = copy->xStrongholdEndPortal; - this->zStrongholdEndPortal = copy->zStrongholdEndPortal; - this->bStrongholdEndPortal = copy->bStrongholdEndPortal; + bStronghold=copy->bStronghold; + xStronghold = copy->xStronghold; + yStronghold = copy->yStronghold; + zStronghold = copy->zStronghold; + + xStrongholdEndPortal = copy->xStrongholdEndPortal; + zStrongholdEndPortal = copy->zStrongholdEndPortal; + bStrongholdEndPortal = copy->bStrongholdEndPortal; m_xzSize = copy->m_xzSize; m_hellScale = copy->m_hellScale; +#ifdef _LARGE_WORLDS + m_classicEdgeMoat = copy->m_classicEdgeMoat; + m_smallEdgeMoat = copy->m_smallEdgeMoat; + m_mediumEdgeMoat = copy->m_mediumEdgeMoat; + m_xzSizeOld = copy->m_xzSizeOld; + m_hellScaleOld = copy->m_hellScaleOld; +#endif } CompoundTag *LevelData::createTag() { - CompoundTag *tag = new CompoundTag(); + CompoundTag *tag = new CompoundTag(); - setTagData(tag); + setTagData(tag); - return tag; + return tag; } CompoundTag *LevelData::createTag(vector > *players) @@ -251,27 +327,31 @@ CompoundTag *LevelData::createTag(vector > *players) void LevelData::setTagData(CompoundTag *tag) { - tag->putLong(L"RandomSeed", seed); + tag->putLong(L"RandomSeed", seed); tag->putString(L"generatorName", m_pGenerator->getGeneratorName()); tag->putInt(L"generatorVersion", m_pGenerator->getVersion()); - tag->putInt(L"GameType", gameType->getId()); - tag->putBoolean(L"MapFeatures", generateMapFeatures); + tag->putString(L"generatorOptions", generatorOptions); + tag->putInt(L"GameType", gameType->getId()); + tag->putBoolean(L"MapFeatures", generateMapFeatures); tag->putBoolean(L"spawnBonusChest",spawnBonusChest); - tag->putInt(L"SpawnX", xSpawn); - tag->putInt(L"SpawnY", ySpawn); - tag->putInt(L"SpawnZ", zSpawn); - tag->putLong(L"Time", time); - tag->putLong(L"SizeOnDisk", sizeOnDisk); - tag->putLong(L"LastPlayed", System::currentTimeMillis()); - tag->putString(L"LevelName", levelName); - tag->putInt(L"version", version); - tag->putInt(L"rainTime", rainTime); - tag->putBoolean(L"raining", raining); - tag->putInt(L"thunderTime", thunderTime); - tag->putBoolean(L"thundering", thundering); + tag->putInt(L"SpawnX", xSpawn); + tag->putInt(L"SpawnY", ySpawn); + tag->putInt(L"SpawnZ", zSpawn); + tag->putLong(L"Time", gameTime); + tag->putLong(L"DayTime", dayTime); + tag->putLong(L"SizeOnDisk", sizeOnDisk); + tag->putLong(L"LastPlayed", System::currentTimeMillis()); + tag->putString(L"LevelName", levelName); + tag->putInt(L"version", version); + tag->putInt(L"rainTime", rainTime); + tag->putBoolean(L"raining", raining); + tag->putInt(L"thunderTime", thunderTime); + tag->putBoolean(L"thundering", thundering); tag->putBoolean(L"hardcore", hardcore); tag->putBoolean(L"allowCommands", allowCommands); tag->putBoolean(L"initialized", initialized); + // 4J: Game rules are now stored with app game host options + //tag->putCompound(L"GameRules", gameRules.createTag()); tag->putBoolean(L"newSeaLevel", newSeaLevel); tag->putBoolean(L"hasBeenInCreative", hasBeenInCreative); // store the stronghold position @@ -284,27 +364,33 @@ void LevelData::setTagData(CompoundTag *tag) tag->putInt(L"StrongholdEndPortalX", xStrongholdEndPortal); tag->putInt(L"StrongholdEndPortalZ", zStrongholdEndPortal); tag->putInt(L"XZSize", m_xzSize); +#ifdef _LARGE_WORLDS + tag->putInt(L"ClassicMoat", m_classicEdgeMoat); + tag->putInt(L"SmallMoat", m_smallEdgeMoat); + tag->putInt(L"MediumMoat", m_mediumEdgeMoat); +#endif + tag->putInt(L"HellScale", m_hellScale); } __int64 LevelData::getSeed() { - return seed; + return seed; } int LevelData::getXSpawn() { - return xSpawn; + return xSpawn; } int LevelData::getYSpawn() { - return ySpawn; + return ySpawn; } int LevelData::getZSpawn() { - return zSpawn; + return zSpawn; } int LevelData::getXStronghold() @@ -329,19 +415,24 @@ int LevelData::getZStrongholdEndPortal() return zStrongholdEndPortal; } -__int64 LevelData::getTime() +__int64 LevelData::getGameTime() { - return time; + return gameTime; +} + +__int64 LevelData::getDayTime() +{ + return dayTime; } __int64 LevelData::getSizeOnDisk() { - return sizeOnDisk; + return sizeOnDisk; } CompoundTag *LevelData::getLoadedPlayerTag() { - return NULL; // 4J - we don't store this anymore + return NULL; // 4J - we don't store this anymore } // 4J Removed TU9 as it's never accurate due to the dimension never being set @@ -352,22 +443,22 @@ CompoundTag *LevelData::getLoadedPlayerTag() void LevelData::setSeed(__int64 seed) { - this->seed = seed; + this->seed = seed; } void LevelData::setXSpawn(int xSpawn) { - this->xSpawn = xSpawn; + this->xSpawn = xSpawn; } void LevelData::setYSpawn(int ySpawn) { - this->ySpawn = ySpawn; + this->ySpawn = ySpawn; } void LevelData::setZSpawn(int zSpawn) { - this->zSpawn = zSpawn; + this->zSpawn = zSpawn; } void LevelData::setHasStronghold() @@ -411,20 +502,25 @@ void LevelData::setZStrongholdEndPortal(int zStrongholdEndPortal) this->zStrongholdEndPortal = zStrongholdEndPortal; } -void LevelData::setTime(__int64 time) +void LevelData::setGameTime(__int64 time) +{ + gameTime = time; +} + +void LevelData::setDayTime(__int64 time) { - this->time = time; + dayTime = time; } void LevelData::setSizeOnDisk(__int64 sizeOnDisk) { - this->sizeOnDisk = sizeOnDisk; + this->sizeOnDisk = sizeOnDisk; } void LevelData::setLoadedPlayerTag(CompoundTag *loadedPlayerTag) { // 4J - we don't store this anymore -// this->loadedPlayerTag = loadedPlayerTag; + // this->loadedPlayerTag = loadedPlayerTag; } // 4J Remove TU9 as it's never used @@ -435,74 +531,74 @@ void LevelData::setLoadedPlayerTag(CompoundTag *loadedPlayerTag) void LevelData::setSpawn(int xSpawn, int ySpawn, int zSpawn) { - this->xSpawn = xSpawn; - this->ySpawn = ySpawn; - this->zSpawn = zSpawn; + this->xSpawn = xSpawn; + this->ySpawn = ySpawn; + this->zSpawn = zSpawn; } wstring LevelData::getLevelName() { - return levelName; + return levelName; } void LevelData::setLevelName(const wstring& levelName) { - this->levelName = levelName; + this->levelName = levelName; } int LevelData::getVersion() { - return version; + return version; } void LevelData::setVersion(int version) { - this->version = version; + this->version = version; } __int64 LevelData::getLastPlayed() { - return lastPlayed; + return lastPlayed; } bool LevelData::isThundering() { - return thundering; + return thundering; } void LevelData::setThundering(bool thundering) { - this->thundering = thundering; + this->thundering = thundering; } int LevelData::getThunderTime() { - return thunderTime; + return thunderTime; } void LevelData::setThunderTime(int thunderTime) { - this->thunderTime = thunderTime; + this->thunderTime = thunderTime; } bool LevelData::isRaining() { - return raining; + return raining; } void LevelData::setRaining(bool raining) { - this->raining = raining; + this->raining = raining; } int LevelData::getRainTime() { - return rainTime; + return rainTime; } void LevelData::setRainTime(int rainTime) { - this->rainTime = rainTime; + this->rainTime = rainTime; } GameType *LevelData::getGameType() @@ -525,7 +621,9 @@ void LevelData::setGameType(GameType *gameType) this->gameType = gameType; // 4J Added - hasBeenInCreative = hasBeenInCreative || (gameType == GameType::CREATIVE) || app.GetGameHostOption(eGameHostOption_CheatsEnabled) > 0; + hasBeenInCreative = hasBeenInCreative || + (gameType == GameType::CREATIVE) || + (app.GetGameHostOption(eGameHostOption_CheatsEnabled) > 0); } bool LevelData::useNewSeaLevel() @@ -553,6 +651,16 @@ void LevelData::setGenerator(LevelType *generator) m_pGenerator = generator; } +wstring LevelData::getGeneratorOptions() +{ + return generatorOptions; +} + +void LevelData::setGeneratorOptions(const wstring &options) +{ + generatorOptions = options; +} + bool LevelData::isHardcore() { return hardcore; @@ -578,11 +686,47 @@ void LevelData::setInitialized(bool initialized) this->initialized = initialized; } +GameRules *LevelData::getGameRules() +{ + return &gameRules; +} + int LevelData::getXZSize() { return m_xzSize; } +#ifdef _LARGE_WORLDS +int LevelData::getXZSizeOld() +{ + return m_xzSizeOld; +} + +void LevelData::getMoatFlags(bool* bClassicEdgeMoat, bool* bSmallEdgeMoat, bool* bMediumEdgeMoat) +{ + *bClassicEdgeMoat = m_classicEdgeMoat; + *bSmallEdgeMoat = m_smallEdgeMoat; + *bMediumEdgeMoat = m_mediumEdgeMoat; + +} + +int LevelData::getXZHellSizeOld() +{ + int hellXZSizeOld = ceil((float)m_xzSizeOld / m_hellScaleOld); + + while(hellXZSizeOld > HELL_LEVEL_MAX_WIDTH && m_hellScaleOld < HELL_LEVEL_MAX_SCALE) + { + assert(0); // should never get in here? + ++m_hellScaleOld; + hellXZSizeOld = m_xzSize / m_hellScale; + } + + return hellXZSizeOld; +} + + +#endif + int LevelData::getHellScale() { return m_hellScale; diff --git a/Minecraft.World/LevelData.h b/Minecraft.World/LevelData.h index 0afe9be2..2ab243c3 100644 --- a/Minecraft.World/LevelData.h +++ b/Minecraft.World/LevelData.h @@ -1,6 +1,8 @@ #pragma once using namespace std; +#include "GameRules.h" + class Player; class CompoundTag; class LevelSettings; @@ -13,22 +15,24 @@ class LevelData private: __int64 seed; LevelType *m_pGenerator;// = LevelType.normal; - int xSpawn; - int ySpawn; - int zSpawn; - __int64 time; - __int64 lastPlayed; - __int64 sizeOnDisk; + wstring generatorOptions; + int xSpawn; + int ySpawn; + int zSpawn; + __int64 gameTime; + __int64 dayTime; + __int64 lastPlayed; + __int64 sizeOnDisk; // CompoundTag *loadedPlayerTag; // 4J removed - int dimension; - wstring levelName; - int version; + int dimension; + wstring levelName; + int version; - bool raining; - int rainTime; + bool raining; + int rainTime; - bool thundering; - int thunderTime; + bool thundering; + int thunderTime; GameType *gameType; bool generateMapFeatures; bool hardcore; @@ -38,6 +42,13 @@ private: bool hasBeenInCreative; // 4J added bool spawnBonusChest; // 4J added int m_xzSize; // 4J Added +#ifdef _LARGE_WORLDS + int m_xzSizeOld; // 4J MGH Added, for expanding worlds + int m_hellScaleOld; + bool m_classicEdgeMoat; + bool m_smallEdgeMoat; + bool m_mediumEdgeMoat; +#endif int m_hellScale; // 4J Added // 4J added @@ -50,15 +61,17 @@ private: int zStrongholdEndPortal; bool bStrongholdEndPortal; + GameRules gameRules; + protected: LevelData(); public: LevelData(CompoundTag *tag); - LevelData(LevelSettings *levelSettings, const wstring& levelName); - LevelData(LevelData *copy); - CompoundTag *createTag(); - CompoundTag *createTag(vector > *players); + LevelData(LevelSettings *levelSettings, const wstring& levelName); + LevelData(LevelData *copy); + CompoundTag *createTag(); + CompoundTag *createTag(vector > *players); enum { @@ -71,63 +84,74 @@ protected: virtual void setTagData(CompoundTag *tag); // 4J - removed CompoundTag *playerTag public: - virtual __int64 getSeed(); - virtual int getXSpawn(); - virtual int getYSpawn(); - virtual int getZSpawn(); - virtual int getXStronghold(); - virtual int getZStronghold(); - virtual int getXStrongholdEndPortal(); - virtual int getZStrongholdEndPortal(); - virtual __int64 getTime(); - virtual __int64 getSizeOnDisk(); - virtual CompoundTag *getLoadedPlayerTag(); - //int getDimension(); // 4J Removed TU 9 as it's never accurate - virtual void setSeed(__int64 seed); - virtual void setXSpawn(int xSpawn); - virtual void setYSpawn(int ySpawn); - virtual void setZSpawn(int zSpawn); - virtual void setHasStronghold(); - virtual bool getHasStronghold(); - virtual void setXStronghold(int xStronghold); - virtual void setZStronghold(int zStronghold); - virtual void setHasStrongholdEndPortal(); - virtual bool getHasStrongholdEndPortal(); - virtual void setXStrongholdEndPortal(int xStrongholdEndPortal); - virtual void setZStrongholdEndPortal(int zStrongholdEndPortal); + virtual __int64 getSeed(); + virtual int getXSpawn(); + virtual int getYSpawn(); + virtual int getZSpawn(); + virtual int getXStronghold(); + virtual int getZStronghold(); + virtual int getXStrongholdEndPortal(); + virtual int getZStrongholdEndPortal(); + virtual __int64 getGameTime(); + virtual __int64 getDayTime(); + virtual __int64 getSizeOnDisk(); + virtual CompoundTag *getLoadedPlayerTag(); + //int getDimension(); // 4J Removed TU 9 as it's never accurate + virtual void setSeed(__int64 seed); + virtual void setXSpawn(int xSpawn); + virtual void setYSpawn(int ySpawn); + virtual void setZSpawn(int zSpawn); + virtual void setHasStronghold(); + virtual bool getHasStronghold(); + virtual void setXStronghold(int xStronghold); + virtual void setZStronghold(int zStronghold); + virtual void setHasStrongholdEndPortal(); + virtual bool getHasStrongholdEndPortal(); + virtual void setXStrongholdEndPortal(int xStrongholdEndPortal); + virtual void setZStrongholdEndPortal(int zStrongholdEndPortal); + + virtual void setGameTime(__int64 time); + virtual void setDayTime(__int64 time); + virtual void setSizeOnDisk(__int64 sizeOnDisk); + virtual void setLoadedPlayerTag(CompoundTag *loadedPlayerTag); + //void setDimension(int dimension); // 4J Removed TU 9 as it's never used + virtual void setSpawn(int xSpawn, int ySpawn, int zSpawn); + virtual wstring getLevelName(); + virtual void setLevelName(const wstring& levelName); + virtual int getVersion(); + virtual void setVersion(int version); + virtual __int64 getLastPlayed(); + virtual bool isThundering(); + virtual void setThundering(bool thundering); + virtual int getThunderTime(); + virtual void setThunderTime(int thunderTime); + virtual bool isRaining(); + virtual void setRaining(bool raining); + virtual int getRainTime(); + virtual void setRainTime(int rainTime); + virtual GameType *getGameType(); + virtual bool isGenerateMapFeatures(); + virtual bool getSpawnBonusChest(); + virtual void setGameType(GameType *gameType); + virtual bool useNewSeaLevel(); + virtual bool getHasBeenInCreative(); // 4J Added + virtual void setHasBeenInCreative(bool value); // 4J Added + virtual LevelType *getGenerator(); + virtual void setGenerator(LevelType *generator); + virtual wstring getGeneratorOptions(); + virtual void setGeneratorOptions(const wstring &options); + virtual bool isHardcore(); + virtual bool getAllowCommands(); + virtual void setAllowCommands(bool allowCommands); + virtual bool isInitialized(); + virtual void setInitialized(bool initialized); + virtual GameRules *getGameRules(); + virtual int getXZSize(); // 4J Added +#ifdef _LARGE_WORLDS + virtual int getXZSizeOld(); // 4J Added + virtual void getMoatFlags(bool* bClassicEdgeMoat, bool* bSmallEdgeMoat, bool* bMediumEdgeMoat); //4J MGH - added + virtual int getXZHellSizeOld(); // 4J Added - virtual void setTime(__int64 time); - virtual void setSizeOnDisk(__int64 sizeOnDisk); - virtual void setLoadedPlayerTag(CompoundTag *loadedPlayerTag); - //void setDimension(int dimension); // 4J Removed TU 9 as it's never used - virtual void setSpawn(int xSpawn, int ySpawn, int zSpawn); - virtual wstring getLevelName(); - virtual void setLevelName(const wstring& levelName); - virtual int getVersion(); - virtual void setVersion(int version); - virtual __int64 getLastPlayed(); - virtual bool isThundering(); - virtual void setThundering(bool thundering); - virtual int getThunderTime(); - virtual void setThunderTime(int thunderTime); - virtual bool isRaining(); - virtual void setRaining(bool raining); - virtual int getRainTime(); - virtual void setRainTime(int rainTime); - virtual GameType *getGameType(); - virtual bool isGenerateMapFeatures(); - virtual bool getSpawnBonusChest(); - virtual void setGameType(GameType *gameType); - virtual bool useNewSeaLevel(); - virtual bool getHasBeenInCreative(); // 4J Added - virtual void setHasBeenInCreative(bool value); // 4J Added - virtual LevelType *getGenerator(); - virtual void setGenerator(LevelType *generator); - virtual bool isHardcore(); - virtual bool getAllowCommands(); - virtual void setAllowCommands(bool allowCommands); - virtual bool isInitialized(); - virtual void setInitialized(bool initialized); - virtual int getXZSize(); // 4J Added - virtual int getHellScale(); // 4J Addded +#endif + virtual int getHellScale(); // 4J Addded }; diff --git a/Minecraft.World/LevelEvent.h b/Minecraft.World/LevelEvent.h index c78c3569..8bd3fea5 100644 --- a/Minecraft.World/LevelEvent.h +++ b/Minecraft.World/LevelEvent.h @@ -4,20 +4,20 @@ class LevelEvent { public: - static const int SOUND_CLICK = 1000; - static const int SOUND_CLICK_FAIL = 1001; - static const int SOUND_LAUNCH = 1002; - static const int SOUND_OPEN_DOOR = 1003; - static const int SOUND_FIZZ = 1004; + static const int SOUND_CLICK = 1000; + static const int SOUND_CLICK_FAIL = 1001; + static const int SOUND_LAUNCH = 1002; + static const int SOUND_OPEN_DOOR = 1003; + static const int SOUND_FIZZ = 1004; static const int SOUND_PLAY_RECORDING = 1005; - static const int SOUND_GHAST_WARNING = 1007; - static const int SOUND_GHAST_FIREBALL = 1008; - static const int SOUND_BLAZE_FIREBALL = 1009; + static const int SOUND_GHAST_WARNING = 1007; + static const int SOUND_GHAST_FIREBALL = 1008; + static const int SOUND_BLAZE_FIREBALL = 1009; - static const int SOUND_ZOMBIE_WOODEN_DOOR = 1010; - static const int SOUND_ZOMBIE_IRON_DOOR = 1011; - static const int SOUND_ZOMBIE_DOOR_CRASH = 1012; + static const int SOUND_ZOMBIE_WOODEN_DOOR = 1010; + static const int SOUND_ZOMBIE_IRON_DOOR = 1011; + static const int SOUND_ZOMBIE_DOOR_CRASH = 1012; static const int SOUND_WITHER_BOSS_SPAWN = 1013; static const int SOUND_WITHER_BOSS_SHOOT = 1014; static const int SOUND_BAT_LIFTOFF = 1015; @@ -29,11 +29,12 @@ public: static const int SOUND_ANVIL_USED = 1021; static const int SOUND_ANVIL_LAND = 1022; - static const int PARTICLES_SHOOT = 2000; - static const int PARTICLES_DESTROY_BLOCK = 2001; - static const int PARTICLES_POTION_SPLASH = 2002; - static const int PARTICLES_EYE_OF_ENDER_DEATH = 2003; - static const int PARTICLES_MOBTILE_SPAWN = 2004; + static const int PARTICLES_SHOOT = 2000; + static const int PARTICLES_DESTROY_BLOCK = 2001; + static const int PARTICLES_POTION_SPLASH = 2002; + static const int PARTICLES_EYE_OF_ENDER_DEATH = 2003; + static const int PARTICLES_MOBTILE_SPAWN = 2004; + static const int PARTICLES_PLANT_GROWTH = 2005; //static const int ENDERDRAGON_KILLED = 9000; // 4J Added to signal the the enderdragon was killed static const int ENDERDRAGON_FIREBALL_SPLASH = 9001; diff --git a/Minecraft.World/LevelEventPacket.cpp b/Minecraft.World/LevelEventPacket.cpp index a044aded..34992156 100644 --- a/Minecraft.World/LevelEventPacket.cpp +++ b/Minecraft.World/LevelEventPacket.cpp @@ -15,13 +15,14 @@ LevelEventPacket::LevelEventPacket() z = 0; } -LevelEventPacket::LevelEventPacket(int type, int x, int y, int z, int data) +LevelEventPacket::LevelEventPacket(int type, int x, int y, int z, int data, bool globalEvent) { this->type = type; this->x = x; this->y = y; this->z = z; this->data = data; + this->globalEvent = globalEvent; } void LevelEventPacket::read(DataInputStream *dis) //throws IOException @@ -31,6 +32,7 @@ void LevelEventPacket::read(DataInputStream *dis) //throws IOException y = dis->readByte() & 0xff; z = dis->readInt(); data = dis->readInt(); + globalEvent = dis->readBoolean(); } void LevelEventPacket::write(DataOutputStream *dos) //throws IOException @@ -40,6 +42,7 @@ void LevelEventPacket::write(DataOutputStream *dos) //throws IOException dos->writeByte(y & 0xff); dos->writeInt(z); dos->writeInt(data); + dos->writeBoolean(globalEvent); } void LevelEventPacket::handle(PacketListener *listener) @@ -52,3 +55,7 @@ int LevelEventPacket::getEstimatedSize() return 4 * 5 + 1; } +bool LevelEventPacket::isGlobalEvent() +{ + return globalEvent; +} diff --git a/Minecraft.World/LevelEventPacket.h b/Minecraft.World/LevelEventPacket.h index 6c2fdbaf..1d8c36e2 100644 --- a/Minecraft.World/LevelEventPacket.h +++ b/Minecraft.World/LevelEventPacket.h @@ -9,14 +9,16 @@ public: int type; int data; int x, y, z; + bool globalEvent; LevelEventPacket(); - LevelEventPacket(int type, int x, int y, int z, int data); + LevelEventPacket(int type, int x, int y, int z, int data, bool globalEvent); virtual void read(DataInputStream *dis); virtual void write(DataOutputStream *dos); virtual void handle(PacketListener *listener); virtual int getEstimatedSize(); + bool isGlobalEvent(); public: static shared_ptr create() { return shared_ptr(new LevelEventPacket()); } diff --git a/Minecraft.World/LevelListener.h b/Minecraft.World/LevelListener.h index ec9b11de..dcf30886 100644 --- a/Minecraft.World/LevelListener.h +++ b/Minecraft.World/LevelListener.h @@ -18,7 +18,7 @@ public: //virtual void playSound(const wstring& name, double x, double y, double z, float volume, float pitch) = 0; virtual void playSound(int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist=16.0f) = 0; - virtual void playSound(shared_ptr entity,int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist=16.0f) = 0; + virtual void playSoundExceptPlayer(shared_ptr player, int iSound, double x, double y, double z, float volume, float pitch, float fSoundClipDist=16.0f) = 0; // 4J removed - virtual void addParticle(const wstring& name, double x, double y, double z, double xa, double ya, double za) = 0; @@ -33,7 +33,7 @@ public: virtual void skyColorChanged() = 0; virtual void playStreamingMusic(const wstring& name, int x, int y, int z) = 0; - + virtual void globalLevelEvent(int type, int sourceX, int sourceY, int sourceZ, int data) = 0; virtual void levelEvent(shared_ptr source, int type, int x, int y, int z, int data) = 0; virtual void destroyTileProgress(int id, int x, int y, int z, int progress) = 0; diff --git a/Minecraft.World/LevelParticlesPacket.cpp b/Minecraft.World/LevelParticlesPacket.cpp new file mode 100644 index 00000000..4d53cf4f --- /dev/null +++ b/Minecraft.World/LevelParticlesPacket.cpp @@ -0,0 +1,110 @@ +#include "stdafx.h" +#include "PacketListener.h" +#include "LevelParticlesPacket.h" + +LevelParticlesPacket::LevelParticlesPacket() +{ + this->name = L""; + this->x = 0.0f; + this->y = 0.0f; + this->z = 0.0f; + this->xDist = 0.0f; + this->yDist = 0.0f; + this->zDist = 0.0f; + this->maxSpeed = 0.0f; + this->count = 0; +} + +LevelParticlesPacket::LevelParticlesPacket(const wstring &name, float x, float y, float z, float xDist, float yDist, float zDist, float maxSpeed, int count) +{ + this->name = name; + this->x = x; + this->y = y; + this->z = z; + this->xDist = xDist; + this->yDist = yDist; + this->zDist = zDist; + this->maxSpeed = maxSpeed; + this->count = count; +} + +void LevelParticlesPacket::read(DataInputStream *dis) +{ + name = readUtf(dis, 64); + x = dis->readFloat(); + y = dis->readFloat(); + z = dis->readFloat(); + xDist = dis->readFloat(); + yDist = dis->readFloat(); + zDist = dis->readFloat(); + maxSpeed = dis->readFloat(); + count = dis->readInt(); +} + +void LevelParticlesPacket::write(DataOutputStream *dos) +{ + writeUtf(name, dos); + dos->writeFloat(x); + dos->writeFloat(y); + dos->writeFloat(z); + dos->writeFloat(xDist); + dos->writeFloat(yDist); + dos->writeFloat(zDist); + dos->writeFloat(maxSpeed); + dos->writeInt(count); +} + +wstring LevelParticlesPacket::getName() +{ + return name; +} + +double LevelParticlesPacket::getX() +{ + return x; +} + +double LevelParticlesPacket::getY() +{ + return y; +} + +double LevelParticlesPacket::getZ() +{ + return z; +} + +float LevelParticlesPacket::getXDist() +{ + return xDist; +} + +float LevelParticlesPacket::getYDist() +{ + return yDist; +} + +float LevelParticlesPacket::getZDist() +{ + return zDist; +} + +float LevelParticlesPacket::getMaxSpeed() +{ + return maxSpeed; +} + +int LevelParticlesPacket::getCount() +{ + return count; +} + +void LevelParticlesPacket::handle(PacketListener *listener) +{ + listener->handleParticleEvent(shared_from_this()); +} + +int LevelParticlesPacket::getEstimatedSize() +{ + return 4 * 2 + 7 * 8; +} \ No newline at end of file diff --git a/Minecraft.World/LevelParticlesPacket.h b/Minecraft.World/LevelParticlesPacket.h new file mode 100644 index 00000000..7676f771 --- /dev/null +++ b/Minecraft.World/LevelParticlesPacket.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Packet.h" + +class LevelParticlesPacket : public Packet, public enable_shared_from_this +{ +private: + wstring name; + float x; + float y; + float z; + float xDist; + float yDist; + float zDist; + float maxSpeed; + int count; + +public: + LevelParticlesPacket(); + LevelParticlesPacket(const wstring &name, float x, float y, float z, float xDist, float yDist, float zDist, float maxSpeed, int count); + + void read(DataInputStream *dis); + void write(DataOutputStream *dos); + wstring getName(); + double getX(); + double getY(); + double getZ(); + float getXDist(); + float getYDist(); + float getZDist(); + float getMaxSpeed(); + int getCount(); + void handle(PacketListener *listener); + int getEstimatedSize(); + +public: + static shared_ptr create() { return shared_ptr(new LevelParticlesPacket()); } + virtual int getId() { return 63; } +}; \ No newline at end of file diff --git a/Minecraft.World/LevelSettings.cpp b/Minecraft.World/LevelSettings.cpp index 59faa1ca..dca8ce61 100644 --- a/Minecraft.World/LevelSettings.cpp +++ b/Minecraft.World/LevelSettings.cpp @@ -47,10 +47,10 @@ void GameType::updatePlayerAbilities(Abilities *abilities) abilities->invulnerable = false; abilities->flying = false; } - abilities->mayBuild = !isReadOnly(); + abilities->mayBuild = !isAdventureRestricted(); } -bool GameType::isReadOnly() +bool GameType::isAdventureRestricted() { return this == ADVENTURE; } @@ -95,6 +95,7 @@ void LevelSettings::_init(__int64 seed, GameType *gameType, bool generateMapFeat this->levelType = levelType; this->allowCommands = false; this->startingBonusItems = false; + levelTypeOptions = L""; m_xzSize = xzSize; m_hellScale = hellScale; } @@ -128,6 +129,12 @@ LevelSettings *LevelSettings::enableSinglePlayerCommands() return this; } +LevelSettings *LevelSettings::setLevelTypeOptions(const wstring &options) +{ + levelTypeOptions = options; + return this; +} + bool LevelSettings::hasStartingBonusItems() { return startingBonusItems; @@ -183,3 +190,8 @@ int LevelSettings::getHellScale() { return m_hellScale; } + +wstring LevelSettings::getLevelTypeOptions() +{ + return levelTypeOptions; +} \ No newline at end of file diff --git a/Minecraft.World/LevelSettings.h b/Minecraft.World/LevelSettings.h index c183df8c..906a6f70 100644 --- a/Minecraft.World/LevelSettings.h +++ b/Minecraft.World/LevelSettings.h @@ -4,6 +4,8 @@ class LevelType; class Abilities; class LevelData; +#define _ADVENTURE_MODE_ENABLED + // 4J Stu - Was Java enum class class GameType { @@ -25,7 +27,7 @@ public: int getId(); wstring getName(); void updatePlayerAbilities(Abilities *abilities); - bool isReadOnly(); + bool isAdventureRestricted(); bool isCreative(); bool isSurvival(); static GameType *byId(int id); @@ -43,6 +45,7 @@ private: LevelType *levelType; bool allowCommands; bool startingBonusItems; // 4J - brought forward from 1.3.2 + wstring levelTypeOptions; int m_xzSize; // 4J Added int m_hellScale; @@ -53,6 +56,7 @@ public: LevelSettings(LevelData *levelData); LevelSettings *enableStartingBonusItems(); // 4J - brought forward from 1.3.2 LevelSettings *enableSinglePlayerCommands(); + LevelSettings *setLevelTypeOptions(const wstring &options); bool hasStartingBonusItems(); // 4J - brought forward from 1.3.2 __int64 getSeed(); GameType *getGameType(); @@ -64,4 +68,5 @@ public: int getXZSize(); // 4J Added int getHellScale(); // 4J Added static GameType *validateGameType(int gameType); + wstring getLevelTypeOptions(); }; diff --git a/Minecraft.World/LevelSource.h b/Minecraft.World/LevelSource.h index 7ff99146..fbe64a99 100644 --- a/Minecraft.World/LevelSource.h +++ b/Minecraft.World/LevelSource.h @@ -25,5 +25,6 @@ public: virtual int getMaxBuildHeight() = 0; virtual bool isAllEmpty() = 0; virtual bool isTopSolidBlocking(int x, int y, int z) = 0; + virtual int getDirectSignal(int x, int y, int z, int dir) = 0; virtual ~LevelSource() {} }; \ No newline at end of file diff --git a/Minecraft.World/LevelType.cpp b/Minecraft.World/LevelType.cpp index 2fe1df95..30b08132 100644 --- a/Minecraft.World/LevelType.cpp +++ b/Minecraft.World/LevelType.cpp @@ -46,6 +46,7 @@ LevelType::LevelType(int id, wstring generatorName, int version) void LevelType::init(int id, wstring generatorName, int version) { + this->id = id; m_generatorName = generatorName; m_version = version; m_selectable = true; @@ -115,4 +116,7 @@ LevelType *LevelType::getLevelType(wstring name) return NULL; } - +int LevelType::getId() +{ + return id; +} \ No newline at end of file diff --git a/Minecraft.World/LevelType.h b/Minecraft.World/LevelType.h index a269c583..0aa015b5 100644 --- a/Minecraft.World/LevelType.h +++ b/Minecraft.World/LevelType.h @@ -14,6 +14,7 @@ public: static void staticCtor(); private: + int id; wstring m_generatorName; int m_version; bool m_selectable; @@ -36,4 +37,5 @@ private: public: bool hasReplacement(); static LevelType *getLevelType(wstring name); + int getId(); }; diff --git a/Minecraft.World/LeverTile.cpp b/Minecraft.World/LeverTile.cpp index a8231251..eea9e3d3 100644 --- a/Minecraft.World/LeverTile.cpp +++ b/Minecraft.World/LeverTile.cpp @@ -1,8 +1,8 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" #include "net.minecraft.h" #include "LeverTile.h" -#include "SoundTypes.h" LeverTile::LeverTile(int id) : Tile(id, Material::decoration,isSolidRender()) { @@ -35,38 +35,38 @@ int LeverTile::getRenderShape() bool LeverTile::mayPlace(Level *level, int x, int y, int z, int face) { - if (face == 0 && level->isSolidBlockingTile(x, y + 1, z)) return true; - if (face == 1 && level->isTopSolidBlocking(x, y - 1, z)) return true; - if (face == 2 && level->isSolidBlockingTile(x, y, z + 1)) return true; - if (face == 3 && level->isSolidBlockingTile(x, y, z - 1)) return true; - if (face == 4 && level->isSolidBlockingTile(x + 1, y, z)) return true; - if (face == 5 && level->isSolidBlockingTile(x - 1, y, z)) return true; - return false; + if (face == Facing::DOWN && level->isSolidBlockingTile(x, y + 1, z)) return true; + if (face == Facing::UP && level->isTopSolidBlocking(x, y - 1, z)) return true; + if (face == Facing::NORTH && level->isSolidBlockingTile(x, y, z + 1)) return true; + if (face == Facing::SOUTH && level->isSolidBlockingTile(x, y, z - 1)) return true; + if (face == Facing::WEST && level->isSolidBlockingTile(x + 1, y, z)) return true; + if (face == Facing::EAST && level->isSolidBlockingTile(x - 1, y, z)) return true; + return false; } bool LeverTile::mayPlace(Level *level, int x, int y, int z) { - if (level->isSolidBlockingTile(x - 1, y, z)) + if (level->isSolidBlockingTile(x - 1, y, z)) { - return true; - } else if (level->isSolidBlockingTile(x + 1, y, z)) + return true; + } else if (level->isSolidBlockingTile(x + 1, y, z)) { - return true; - } else if (level->isSolidBlockingTile(x, y, z - 1)) + return true; + } else if (level->isSolidBlockingTile(x, y, z - 1)) { - return true; - } else if (level->isSolidBlockingTile(x, y, z + 1)) + return true; + } else if (level->isSolidBlockingTile(x, y, z + 1)) { - return true; - } else if (level->isTopSolidBlocking(x, y - 1, z)) + return true; + } else if (level->isTopSolidBlocking(x, y - 1, z)) { - return true; - } + return true; + } else if (level->isSolidBlockingTile(x, y + 1, z)) { return true; } - return false; + return false; } int LeverTile::getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) @@ -88,6 +88,36 @@ int LeverTile::getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int f return dir + oldFlip; } +void LeverTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) +{ + int data = level->getData(x, y, z); + int dir = data & 7; + int flip = data & 8; + + if (dir == getLeverFacing(Facing::UP)) + { + if ((Mth::floor(by->yRot * 4 / (360) + 0.5) & 1) == 0) + { + level->setData(x, y, z, 5 | flip, Tile::UPDATE_CLIENTS); + } + else + { + level->setData(x, y, z, 6 | flip, Tile::UPDATE_CLIENTS); + } + } + else if (dir == getLeverFacing(Facing::DOWN)) + { + if ((Mth::floor(by->yRot * 4 / (360) + 0.5) & 1) == 0) + { + level->setData(x, y, z, 7 | flip, Tile::UPDATE_CLIENTS); + } + else + { + level->setData(x, y, z, 0 | flip, Tile::UPDATE_CLIENTS); + } + } +} + int LeverTile::getLeverFacing(int facing) { switch (facing) @@ -110,65 +140,65 @@ int LeverTile::getLeverFacing(int facing) void LeverTile::neighborChanged(Level *level, int x, int y, int z, int type) { - if (checkCanSurvive(level, x, y, z)) + if (checkCanSurvive(level, x, y, z)) { - int dir = level->getData(x, y, z) & 7; - bool replace = false; + int dir = level->getData(x, y, z) & 7; + bool replace = false; - if (!level->isSolidBlockingTile(x - 1, y, z) && dir == 1) replace = true; - if (!level->isSolidBlockingTile(x + 1, y, z) && dir == 2) replace = true; - if (!level->isSolidBlockingTile(x, y, z - 1) && dir == 3) replace = true; + if (!level->isSolidBlockingTile(x - 1, y, z) && dir == 1) replace = true; + if (!level->isSolidBlockingTile(x + 1, y, z) && dir == 2) replace = true; + if (!level->isSolidBlockingTile(x, y, z - 1) && dir == 3) replace = true; if (!level->isSolidBlockingTile(x, y, z + 1) && dir == 4) replace = true; if (!level->isTopSolidBlocking(x, y - 1, z) && dir == 5) replace = true; if (!level->isTopSolidBlocking(x, y - 1, z) && dir == 6) replace = true; if (!level->isSolidBlockingTile(x, y + 1, z) && dir == 0) replace = true; if (!level->isSolidBlockingTile(x, y + 1, z) && dir == 7) replace = true; - if (replace) + if (replace) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); - } - } + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); + } + } } bool LeverTile::checkCanSurvive(Level *level, int x, int y, int z) { - if (!mayPlace(level, x, y, z)) + if (!mayPlace(level, x, y, z)) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); - return false; - } - return true; + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); + return false; + } + return true; } void LeverTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { - int dir = level->getData(x, y, z) & 7; - float r = 3 / 16.0f; - if (dir == 1) + int dir = level->getData(x, y, z) & 7; + float r = 3 / 16.0f; + if (dir == 1) { - setShape(0, 0.2f, 0.5f - r, r * 2, 0.8f, 0.5f + r); - } + setShape(0, 0.2f, 0.5f - r, r * 2, 0.8f, 0.5f + r); + } else if (dir == 2) { - setShape(1 - r * 2, 0.2f, 0.5f - r, 1, 0.8f, 0.5f + r); - } + setShape(1 - r * 2, 0.2f, 0.5f - r, 1, 0.8f, 0.5f + r); + } else if (dir == 3) { - setShape(0.5f - r, 0.2f, 0, 0.5f + r, 0.8f, r * 2); - } + setShape(0.5f - r, 0.2f, 0, 0.5f + r, 0.8f, r * 2); + } else if (dir == 4) { - setShape(0.5f - r, 0.2f, 1 - r * 2, 0.5f + r, 0.8f, 1); - } + setShape(0.5f - r, 0.2f, 1 - r * 2, 0.5f + r, 0.8f, 1); + } else if (dir == 5 || dir == 6) { - r = 4 / 16.0f; - setShape(0.5f - r, 0.0f, 0.5f - r, 0.5f + r, 0.6f, 0.5f + r); - } + r = 4 / 16.0f; + setShape(0.5f - r, 0.0f, 0.5f - r, 0.5f + r, 0.6f, 0.5f + r); + } else if (dir == 0 || dir == 7) { r = 4 / 16.0f; @@ -176,11 +206,6 @@ void LeverTile::updateShape(LevelSource *level, int x, int y, int z, int forceDa } } -void LeverTile::attack(Level *level, int x, int y, int z, shared_ptr player) -{ - use(level, x, y, z, player, 0, 0, 0, 0); -} - // 4J-PB - Adding a TestUse for tooltip display bool LeverTile::TestUse() { @@ -198,7 +223,7 @@ bool LeverTile::use(Level *level, int x, int y, int z, shared_ptr player level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, open > 0 ? 0.6f : 0.5f); return false; } - if (level->isClientSide) + if (level->isClientSide) { // 4J - added stuff to play sound in this case too int data = level->getData(x, y, z); @@ -208,99 +233,99 @@ bool LeverTile::use(Level *level, int x, int y, int z, shared_ptr player return true; } - int data = level->getData(x, y, z); - int dir = data & 7; - int open = 8 - (data & 8); + int data = level->getData(x, y, z); + int dir = data & 7; + int open = 8 - (data & 8); - level->setData(x, y, z, dir + open); - level->setTilesDirty(x, y, z, x, y, z); + level->setData(x, y, z, dir + open, Tile::UPDATE_ALL); + level->setTilesDirty(x, y, z, x, y, z); - level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, open > 0 ? 0.6f : 0.5f); + level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, open > 0 ? 0.6f : 0.5f); - level->updateNeighborsAt(x, y, z, id); - if (dir == 1) + level->updateNeighborsAt(x, y, z, id); + if (dir == 1) { - level->updateNeighborsAt(x - 1, y, z, id); - } + level->updateNeighborsAt(x - 1, y, z, id); + } else if (dir == 2) { - level->updateNeighborsAt(x + 1, y, z, id); - } + level->updateNeighborsAt(x + 1, y, z, id); + } else if (dir == 3) { - level->updateNeighborsAt(x, y, z - 1, id); - } + level->updateNeighborsAt(x, y, z - 1, id); + } else if (dir == 4) { - level->updateNeighborsAt(x, y, z + 1, id); - } + level->updateNeighborsAt(x, y, z + 1, id); + } else if (dir == 5 || dir == 6) { - level->updateNeighborsAt(x, y - 1, z, id); - } + level->updateNeighborsAt(x, y - 1, z, id); + } else if (dir == 0 || dir == 7) { level->updateNeighborsAt(x, y + 1, z, id); } - return true; + return true; } void LeverTile::onRemove(Level *level, int x, int y, int z, int id, int data) { - if ((data & 8) > 0) + if ((data & 8) > 0) { - level->updateNeighborsAt(x, y, z, this->id); - int dir = data & 7; - if (dir == 1) + level->updateNeighborsAt(x, y, z, this->id); + int dir = data & 7; + if (dir == 1) { - level->updateNeighborsAt(x - 1, y, z, this->id); - } + level->updateNeighborsAt(x - 1, y, z, this->id); + } else if (dir == 2) { - level->updateNeighborsAt(x + 1, y, z, this->id); - } + level->updateNeighborsAt(x + 1, y, z, this->id); + } else if (dir == 3) { - level->updateNeighborsAt(x, y, z - 1, this->id); - } + level->updateNeighborsAt(x, y, z - 1, this->id); + } else if (dir == 4) { - level->updateNeighborsAt(x, y, z + 1, this->id); - } + level->updateNeighborsAt(x, y, z + 1, this->id); + } else if (dir == 5 || dir == 6) { - level->updateNeighborsAt(x, y - 1, z, this->id); + level->updateNeighborsAt(x, y - 1, z, this->id); } else if (dir == 0 || dir == 7) { level->updateNeighborsAt(x, y + 1, z, this->id); } - } - Tile::onRemove(level, x, y, z, id, data); + } + Tile::onRemove(level, x, y, z, id, data); } -bool LeverTile::getSignal(LevelSource *level, int x, int y, int z, int dir) +int LeverTile::getSignal(LevelSource *level, int x, int y, int z, int dir) { - return (level->getData(x, y, z) & 8) > 0; + return (level->getData(x, y, z) & 8) > 0 ? Redstone::SIGNAL_MAX : Redstone::SIGNAL_NONE; } -bool LeverTile::getDirectSignal(Level *level, int x, int y, int z, int dir) +int LeverTile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir) { - int data = level->getData(x, y, z); - if ((data & 8) == 0) return false; - int myDir = data & 7; - - if (myDir == 0 && dir == 0) return true; - if (myDir == 7 && dir == 0) return true; - if (myDir == 6 && dir == 1) return true; - if (myDir == 5 && dir == 1) return true; - if (myDir == 4 && dir == 2) return true; - if (myDir == 3 && dir == 3) return true; - if (myDir == 2 && dir == 4) return true; - if (myDir == 1 && dir == 5) return true; - - return false; + int data = level->getData(x, y, z); + if ((data & 8) == 0) return Redstone::SIGNAL_NONE; + int myDir = data & 7; + + if (myDir == 0 && dir == 0) return Redstone::SIGNAL_MAX; + if (myDir == 7 && dir == 0) return Redstone::SIGNAL_MAX; + if (myDir == 6 && dir == 1) return Redstone::SIGNAL_MAX; + if (myDir == 5 && dir == 1) return Redstone::SIGNAL_MAX; + if (myDir == 4 && dir == 2) return Redstone::SIGNAL_MAX; + if (myDir == 3 && dir == 3) return Redstone::SIGNAL_MAX; + if (myDir == 2 && dir == 4) return Redstone::SIGNAL_MAX; + if (myDir == 1 && dir == 5) return Redstone::SIGNAL_MAX; + + return Redstone::SIGNAL_NONE; } bool LeverTile::isSignalSource() diff --git a/Minecraft.World/LeverTile.h b/Minecraft.World/LeverTile.h index 4d00db78..da719868 100644 --- a/Minecraft.World/LeverTile.h +++ b/Minecraft.World/LeverTile.h @@ -7,25 +7,25 @@ class LeverTile : public Tile protected: LeverTile(int id); public: - virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual bool blocksLight(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); - virtual int getRenderShape(); - virtual bool mayPlace(Level *level, int x, int y, int z, int face); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); + virtual AABB *getAABB(Level *level, int x, int y, int z); + virtual bool blocksLight(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); + virtual int getRenderShape(); + virtual bool mayPlace(Level *level, int x, int y, int z, int face); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); static int getLeverFacing(int facing); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); private: virtual bool checkCanSurvive(Level *level, int x, int y, int z); public: virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param - virtual void attack(Level *level, int x, int y, int z, shared_ptr player); virtual bool TestUse(); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); - virtual bool getSignal(LevelSource *level, int x, int y, int z, int dir); - virtual bool getDirectSignal(Level *level, int x, int y, int z, int dir); - virtual bool isSignalSource(); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); + virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir); + virtual bool isSignalSource(); }; diff --git a/Minecraft.World/LightGemFeature.cpp b/Minecraft.World/LightGemFeature.cpp index f42d78ff..6ad1193a 100644 --- a/Minecraft.World/LightGemFeature.cpp +++ b/Minecraft.World/LightGemFeature.cpp @@ -5,33 +5,33 @@ bool LightGemFeature::place(Level *level, Random *random, int x, int y, int z) { - if (!level->isEmptyTile(x, y, z)) return false; - if (level->getTile(x, y + 1, z) != Tile::hellRock_Id) return false; - level->setTile(x, y, z, Tile::lightGem_Id); + if (!level->isEmptyTile(x, y, z)) return false; + if (level->getTile(x, y + 1, z) != Tile::netherRack_Id) return false; + level->setTileAndData(x, y, z, Tile::glowstone_Id, 0, Tile::UPDATE_CLIENTS); - for (int i = 0; i < 1500; i++) + for (int i = 0; i < 1500; i++) { - int x2 = x + random->nextInt(8) - random->nextInt(8); - int y2 = y - random->nextInt(12); - int z2 = z + random->nextInt(8) - random->nextInt(8); - if (level->getTile(x2, y2, z2) != 0) continue; + int x2 = x + random->nextInt(8) - random->nextInt(8); + int y2 = y - random->nextInt(12); + int z2 = z + random->nextInt(8) - random->nextInt(8); + if (level->getTile(x2, y2, z2) != 0) continue; - int count = 0; - for (int t = 0; t < 6; t++) + int count = 0; + for (int t = 0; t < 6; t++) { - int tile = 0; - if (t == 0) tile = level->getTile(x2 - 1, y2, z2); - if (t == 1) tile = level->getTile(x2 + 1, y2, z2); - if (t == 2) tile = level->getTile(x2, y2 - 1, z2); - if (t == 3) tile = level->getTile(x2, y2 + 1, z2); - if (t == 4) tile = level->getTile(x2, y2, z2 - 1); - if (t == 5) tile = level->getTile(x2, y2, z2 + 1); + int tile = 0; + if (t == 0) tile = level->getTile(x2 - 1, y2, z2); + if (t == 1) tile = level->getTile(x2 + 1, y2, z2); + if (t == 2) tile = level->getTile(x2, y2 - 1, z2); + if (t == 3) tile = level->getTile(x2, y2 + 1, z2); + if (t == 4) tile = level->getTile(x2, y2, z2 - 1); + if (t == 5) tile = level->getTile(x2, y2, z2 + 1); - if (tile == Tile::lightGem_Id) count++; - } + if (tile == Tile::glowstone_Id) count++; + } - if (count == 1) level->setTile(x2, y2, z2, Tile::lightGem_Id); - } + if (count == 1) level->setTileAndData(x2, y2, z2, Tile::glowstone_Id, 0, Tile::UPDATE_CLIENTS); + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/LightningBolt.cpp b/Minecraft.World/LightningBolt.cpp index 901bedf1..7f32c8ec 100644 --- a/Minecraft.World/LightningBolt.cpp +++ b/Minecraft.World/LightningBolt.cpp @@ -27,31 +27,28 @@ LightningBolt::LightningBolt(Level *level, double x, double y, double z) : flashes = 1; // 4J - added clientside check - if( !level->isClientSide ) + if( !level->isClientSide && level->getGameRules()->getBoolean(GameRules::RULE_DOFIRETICK)&&level->difficulty >= 2 && level->hasChunksAt( Mth::floor(x), Mth::floor(y), Mth::floor(z), 10)) { - if (level->difficulty >= 2 && level->hasChunksAt( Mth::floor(x), Mth::floor(y), Mth::floor(z), 10)) { + int xt = Mth::floor(x); + int yt = Mth::floor(y); + int zt = Mth::floor(z); + // 4J added - don't go setting tiles if we aren't tracking them for network synchronisation + if( MinecraftServer::getInstance()->getPlayers()->isTrackingTile(xt, yt, zt, level->dimension->id) ) { - int xt = Mth::floor(x); - int yt = Mth::floor(y); - int zt = Mth::floor(z); - // 4J added - don't go setting tiles if we aren't tracking them for network synchronisation - if( MinecraftServer::getInstance()->getPlayers()->isTrackingTile(xt, yt, zt, level->dimension->id) ) - { - if (level->getTile(xt, yt, zt) == 0 && Tile::fire->mayPlace(level, xt, yt, zt)) level->setTile(xt, yt, zt, Tile::fire_Id); - } + if (level->getTile(xt, yt, zt) == 0 && Tile::fire->mayPlace(level, xt, yt, zt)) level->setTileAndUpdate(xt, yt, zt, Tile::fire_Id); } + } - for (int i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) + { + int xt = Mth::floor(x) + random->nextInt(3) - 1; + int yt = Mth::floor(y) + random->nextInt(3) - 1; + int zt = Mth::floor(z) + random->nextInt(3) - 1; + // 4J added - don't go setting tiles if we aren't tracking them for network synchronisation + if( MinecraftServer::getInstance()->getPlayers()->isTrackingTile(xt, yt, zt, level->dimension->id) ) { - int xt = Mth::floor(x) + random->nextInt(3) - 1; - int yt = Mth::floor(y) + random->nextInt(3) - 1; - int zt = Mth::floor(z) + random->nextInt(3) - 1; - // 4J added - don't go setting tiles if we aren't tracking them for network synchronisation - if( MinecraftServer::getInstance()->getPlayers()->isTrackingTile(xt, yt, zt, level->dimension->id) ) - { - if (level->getTile(xt, yt, zt) == 0 && Tile::fire->mayPlace(level, xt, yt, zt)) level->setTile(xt, yt, zt, Tile::fire_Id); - } + if (level->getTile(xt, yt, zt) == 0 && Tile::fire->mayPlace(level, xt, yt, zt)) level->setTileAndUpdate(xt, yt, zt, Tile::fire_Id); } } } @@ -79,21 +76,18 @@ void LightningBolt::tick() { flashes--; life = 1; - // 4J - added clientside check - if( !level->isClientSide ) + + seed = random->nextLong(); + if (!level->isClientSide && level->getGameRules()->getBoolean(GameRules::RULE_DOFIRETICK) && level->hasChunksAt( (int) floor(x), (int) floor(y), (int) floor(z), 10)) { - seed = random->nextLong(); - if (level->hasChunksAt( (int) floor(x), (int) floor(y), (int) floor(z), 10)) + int xt = (int) floor(x); + int yt = (int) floor(y); + int zt = (int) floor(z); + + // 4J added - don't go setting tiles if we aren't tracking them for network synchronisation + if( MinecraftServer::getInstance()->getPlayers()->isTrackingTile(xt, yt, zt, level->dimension->id) ) { - int xt = (int) floor(x); - int yt = (int) floor(y); - int zt = (int) floor(z); - - // 4J added - don't go setting tiles if we aren't tracking them for network synchronisation - if( MinecraftServer::getInstance()->getPlayers()->isTrackingTile(xt, yt, zt, level->dimension->id) ) - { - if (level->getTile(xt, yt, zt) == 0 && Tile::fire->mayPlace(level, xt, yt, zt)) level->setTile(xt, yt, zt, Tile::fire_Id); - } + if (level->getTile(xt, yt, zt) == 0 && Tile::fire->mayPlace(level, xt, yt, zt)) level->setTileAndUpdate(xt, yt, zt, Tile::fire_Id); } } } @@ -101,10 +95,13 @@ void LightningBolt::tick() if (life >= 0) { - double r = 3; - // 4J - added clientside check - if( !level->isClientSide ) + if (level->isClientSide) + { + level->skyFlashTime = 2; + } + else { + double r = 3; vector > *entities = level->getEntities(shared_from_this(), AABB::newTemp(x - r, y - r, z - r, x + r, y + 6 + r, z + r)); AUTO_VAR(itEnd, entities->end()); for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) @@ -113,8 +110,6 @@ void LightningBolt::tick() e->thunderHit(this); } } - - level->lightningBoltTime = 2; } } diff --git a/Minecraft.World/LiquidTile.cpp b/Minecraft.World/LiquidTile.cpp index 466589a4..c31b6466 100644 --- a/Minecraft.World/LiquidTile.cpp +++ b/Minecraft.World/LiquidTile.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "JavaMath.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.dimension.h" #include "net.minecraft.world.level.biome.h" #include "net.minecraft.world.h" #include "LiquidTile.h" @@ -14,11 +15,11 @@ const wstring LiquidTile::TEXTURE_LAVA_FLOW = L"lava_flow"; LiquidTile::LiquidTile(int id, Material *material) : Tile(id, material,isSolidRender()) { - float yo = 0; - float e = 0; + float yo = 0; + float e = 0; - setShape(0 + e, 0 + yo, 0 + e, 1 + e, 1 + yo, 1 + e); - setTicking(true); + setShape(0 + e, 0 + yo, 0 + e, 1 + e, 1 + yo, 1 + e); + setTicking(true); } bool LiquidTile::isPathfindable(LevelSource *level, int x, int y, int z) @@ -64,34 +65,34 @@ int LiquidTile::getColor(LevelSource *level, int x, int y, int z, int d) float LiquidTile::getHeight(int d) { - if (d >= 8) d = 0; - return (d + 1) / 9.0f; + if (d >= 8) d = 0; + return (d + 1) / 9.0f; } Icon *LiquidTile::getTexture(int face, int data) { if (face == Facing::DOWN || face == Facing::UP) { - return icons[0]; + return icons[0]; } else { - return icons[1]; - } + return icons[1]; + } } int LiquidTile::getDepth(Level *level, int x, int y, int z) { - if (level->getMaterial(x, y, z) == material) return level->getData(x, y, z); + if (level->getMaterial(x, y, z) == material) return level->getData(x, y, z); else return -1; } int LiquidTile::getRenderedDepth(LevelSource *level, int x, int y, int z) { - if (level->getMaterial(x, y, z) != material) return -1; - int d = level->getData(x, y, z); - if (d >= 8) d = 0; - return d; + if (level->getMaterial(x, y, z) != material) return -1; + int d = level->getData(x, y, z); + if (d >= 8) d = 0; + return d; } bool LiquidTile::isCubeShaped() @@ -111,21 +112,21 @@ bool LiquidTile::mayPick(int data, bool liquid) bool LiquidTile::isSolidFace(LevelSource *level, int x, int y, int z, int face) { - Material *m = level->getMaterial(x, y, z); - if (m == this->material) return false; + Material *m = level->getMaterial(x, y, z); + if (m == material) return false; if (face == Facing::UP) return true; - if (m == Material::ice) return false; - - return Tile::isSolidFace(level, x, y, z, face); + if (m == Material::ice) return false; + + return Tile::isSolidFace(level, x, y, z, face); } bool LiquidTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { - Material *m = level->getMaterial(x, y, z); - if (m == this->material) return false; + Material *m = level->getMaterial(x, y, z); + if (m == material) return false; if (face == Facing::UP) return true; - if (m == Material::ice) return false; - return Tile::shouldRenderFace(level, x, y, z, face); + if (m == Material::ice) return false; + return Tile::shouldRenderFace(level, x, y, z, face); } AABB *LiquidTile::getAABB(Level *level, int x, int y, int z) @@ -150,94 +151,104 @@ int LiquidTile::getResourceCount(Random *random) Vec3 *LiquidTile::getFlow(LevelSource *level, int x, int y, int z) { - Vec3 *flow = Vec3::newTemp(0,0,0); - int mid = getRenderedDepth(level, x, y, z); - for (int d = 0; d < 4; d++) + Vec3 *flow = Vec3::newTemp(0,0,0); + int mid = getRenderedDepth(level, x, y, z); + for (int d = 0; d < 4; d++) { - int xt = x; - int yt = y; - int zt = z; + int xt = x; + int yt = y; + int zt = z; - if (d == 0) xt--; - if (d == 1) zt--; - if (d == 2) xt++; - if (d == 3) zt++; + if (d == 0) xt--; + if (d == 1) zt--; + if (d == 2) xt++; + if (d == 3) zt++; - int t = getRenderedDepth(level, xt, yt, zt); - if (t < 0) + int t = getRenderedDepth(level, xt, yt, zt); + if (t < 0) { - if (!level->getMaterial(xt, yt, zt)->blocksMotion()) + if (!level->getMaterial(xt, yt, zt)->blocksMotion()) { - t = getRenderedDepth(level, xt, yt - 1, zt); - if (t >= 0) + t = getRenderedDepth(level, xt, yt - 1, zt); + if (t >= 0) { - int dir = t - (mid - 8); - flow = flow->add((xt - x) * dir, (yt - y) * dir, (zt - z) * dir); - } - } - } else + int dir = t - (mid - 8); + flow = flow->add((xt - x) * dir, (yt - y) * dir, (zt - z) * dir); + } + } + } else { - if (t >= 0) + if (t >= 0) { - int dir = t - mid; - flow = flow->add((xt - x) * dir, (yt - y) * dir, (zt - z) * dir); - } - } + int dir = t - mid; + flow = flow->add((xt - x) * dir, (yt - y) * dir, (zt - z) * dir); + } + } - } - if (level->getData(x, y, z) >= 8) + } + if (level->getData(x, y, z) >= 8) { - bool ok = false; - if (ok || isSolidFace(level, x, y, z - 1, 2)) ok = true; - if (ok || isSolidFace(level, x, y, z + 1, 3)) ok = true; - if (ok || isSolidFace(level, x - 1, y, z, 4)) ok = true; - if (ok || isSolidFace(level, x + 1, y, z, 5)) ok = true; - if (ok || isSolidFace(level, x, y + 1, z - 1, 2)) ok = true; - if (ok || isSolidFace(level, x, y + 1, z + 1, 3)) ok = true; - if (ok || isSolidFace(level, x - 1, y + 1, z, 4)) ok = true; - if (ok || isSolidFace(level, x + 1, y + 1, z, 5)) ok = true; - if (ok) flow = flow->normalize()->add(0, -6, 0); - } - flow = flow->normalize(); - return flow; + bool ok = false; + if (ok || isSolidFace(level, x, y, z - 1, 2)) ok = true; + if (ok || isSolidFace(level, x, y, z + 1, 3)) ok = true; + if (ok || isSolidFace(level, x - 1, y, z, 4)) ok = true; + if (ok || isSolidFace(level, x + 1, y, z, 5)) ok = true; + if (ok || isSolidFace(level, x, y + 1, z - 1, 2)) ok = true; + if (ok || isSolidFace(level, x, y + 1, z + 1, 3)) ok = true; + if (ok || isSolidFace(level, x - 1, y + 1, z, 4)) ok = true; + if (ok || isSolidFace(level, x + 1, y + 1, z, 5)) ok = true; + if (ok) flow = flow->normalize()->add(0, -6, 0); + } + flow = flow->normalize(); + return flow; } void LiquidTile::handleEntityInside(Level *level, int x, int y, int z, shared_ptr e, Vec3 *current) { - Vec3 *flow = getFlow(level, x, y, z); - current->x += flow->x; - current->y += flow->y; - current->z += flow->z; + Vec3 *flow = getFlow(level, x, y, z); + current->x += flow->x; + current->y += flow->y; + current->z += flow->z; } -int LiquidTile::getTickDelay() +int LiquidTile::getTickDelay(Level *level) { - if (material == Material::water) return 5; - if (material == Material::lava) return 30; - return 0; + if (material == Material::water) return 5; + if (material == Material::lava) + { + if (level->dimension->hasCeiling) + { + return 10; + } + else + { + return 30; + } + } + return 0; } // 4J - change brought forward from 1.8.2 int LiquidTile::getLightColor(LevelSource *level, int x, int y, int z, int tileId/*=-1*/) { // 4J - note that this code seems to basically be a hack to fix a problem where post-processed things like lakes aren't getting lit properly - int a = level->getLightColor(x, y, z, 0, tileId); - int b = level->getLightColor(x, y + 1, z, 0, tileId); + int a = level->getLightColor(x, y, z, 0, tileId); + int b = level->getLightColor(x, y + 1, z, 0, tileId); - int aa = a & 0xff; - int ba = b & 0xff; - int ab = (a >> 16) & 0xff; - int bb = (b >> 16) & 0xff; + int aa = a & 0xff; + int ba = b & 0xff; + int ab = (a >> 16) & 0xff; + int bb = (b >> 16) & 0xff; - return (aa > ba ? aa : ba) | ((ab > bb ? ab : bb) << 16); + return (aa > ba ? aa : ba) | ((ab > bb ? ab : bb) << 16); } float LiquidTile::getBrightness(LevelSource *level, int x, int y, int z) { - float a = level->getBrightness(x, y, z); - float b = level->getBrightness(x, y + 1, z); - return a > b ? a : b; + float a = level->getBrightness(x, y, z); + float b = level->getBrightness(x, y + 1, z); + return a > b ? a : b; } int LiquidTile::getRenderLayer() @@ -247,102 +258,102 @@ int LiquidTile::getRenderLayer() void LiquidTile::animateTick(Level *level, int x, int y, int z, Random *random) { - if (material == Material::water) + if (material == Material::water) { - if (random->nextInt(10) == 0) + if (random->nextInt(10) == 0) { - int d = level->getData(x, y, z); - if (d <= 0 || d >= 8) + int d = level->getData(x, y, z); + if (d <= 0 || d >= 8) { - level->addParticle(eParticleType_suspended, x + random->nextFloat(), y + random->nextFloat(), z + random->nextFloat(), 0, 0, 0); - } - } + level->addParticle(eParticleType_suspended, x + random->nextFloat(), y + random->nextFloat(), z + random->nextFloat(), 0, 0, 0); + } + } // 4J-PB - this loop won't run! - for (int i = 0; i < 0; i++) + for (int i = 0; i < 0; i++) { // This was an attempt to add foam to // the bottoms of waterfalls. It // didn't went ok. - int dir = random->nextInt(4); - int xt = x; - int zt = z; - if (dir == 0) xt--; - if (dir == 1) xt++; - if (dir == 2) zt--; - if (dir == 3) zt++; - if (level->getMaterial(xt, y, zt) == Material::air && (level->getMaterial(xt, y - 1, zt)->blocksMotion() || level->getMaterial(xt, y - 1, zt)->isLiquid())) + int dir = random->nextInt(4); + int xt = x; + int zt = z; + if (dir == 0) xt--; + if (dir == 1) xt++; + if (dir == 2) zt--; + if (dir == 3) zt++; + if (level->getMaterial(xt, y, zt) == Material::air && (level->getMaterial(xt, y - 1, zt)->blocksMotion() || level->getMaterial(xt, y - 1, zt)->isLiquid())) { - float r = 1 / 16.0f; - double xx = x + random->nextFloat(); - double yy = y + random->nextFloat(); - double zz = z + random->nextFloat(); - if (dir == 0) xx = x - r; - if (dir == 1) xx = x + 1 + r; - if (dir == 2) zz = z - r; - if (dir == 3) zz = z + 1 + r; - - double xd = 0; - double zd = 0; - - if (dir == 0) xd = -r; - if (dir == 1) xd = +r; - if (dir == 2) zd = -r; - if (dir == 3) zd = +r; - - level->addParticle(eParticleType_splash, xx, yy, zz, xd, 0, zd); - } - } - } - if (material == Material::water && random->nextInt(64) == 0) + float r = 1 / 16.0f; + double xx = x + random->nextFloat(); + double yy = y + random->nextFloat(); + double zz = z + random->nextFloat(); + if (dir == 0) xx = x - r; + if (dir == 1) xx = x + 1 + r; + if (dir == 2) zz = z - r; + if (dir == 3) zz = z + 1 + r; + + double xd = 0; + double zd = 0; + + if (dir == 0) xd = -r; + if (dir == 1) xd = +r; + if (dir == 2) zd = -r; + if (dir == 3) zd = +r; + + level->addParticle(eParticleType_splash, xx, yy, zz, xd, 0, zd); + } + } + } + if (material == Material::water && random->nextInt(64) == 0) { - int d = level->getData(x, y, z); - if (d > 0 && d < 8) + int d = level->getData(x, y, z); + if (d > 0 && d < 8) { - level->playLocalSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_LIQUID_WATER, random->nextFloat() * 0.25f + 0.75f, random->nextFloat() * 1.0f + 0.5f); - } - } - if (material == Material::lava) + level->playLocalSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_LIQUID_WATER, random->nextFloat() * 0.25f + 0.75f, random->nextFloat() * 1.0f + 0.5f, false); + } + } + if (material == Material::lava) { - if (level->getMaterial(x, y + 1, z) == Material::air && !level->isSolidRenderTile(x, y + 1, z)) + if (level->getMaterial(x, y + 1, z) == Material::air && !level->isSolidRenderTile(x, y + 1, z)) { - if (random->nextInt(100) == 0) + if (random->nextInt(100) == 0) { ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); - double xx = x + random->nextFloat(); - double yy = y + tls->yy1; - double zz = z + random->nextFloat(); - level->addParticle(eParticleType_lava, xx, yy, zz, 0, 0, 0); + double xx = x + random->nextFloat(); + double yy = y + tls->yy1; + double zz = z + random->nextFloat(); + level->addParticle(eParticleType_lava, xx, yy, zz, 0, 0, 0); // 4J - new sound brought forward from 1.2.3 - level->playLocalSound(xx, yy, zz, eSoundType_LIQUID_LAVA_POP, 0.2f + random->nextFloat() * 0.2f, 0.9f + random->nextFloat() * 0.15f); - } + level->playLocalSound(xx, yy, zz, eSoundType_LIQUID_LAVA_POP, 0.2f + random->nextFloat() * 0.2f, 0.9f + random->nextFloat() * 0.15f, false); + } // 4J - new sound brought forward from 1.2.3 - if (random->nextInt(200) == 0) + if (random->nextInt(200) == 0) { - level->playLocalSound(x, y, z, eSoundType_LIQUID_LAVA, 0.2f + random->nextFloat() * 0.2f, 0.9f + random->nextFloat() * 0.15f); - } - } - } + level->playLocalSound(x, y, z, eSoundType_LIQUID_LAVA, 0.2f + random->nextFloat() * 0.2f, 0.9f + random->nextFloat() * 0.15f, false); + } + } + } - if (random->nextInt(10) == 0) + if (random->nextInt(10) == 0) { - if (level->isTopSolidBlocking(x, y - 1, z) && !level->getMaterial(x, y - 2, z)->blocksMotion()) + if (level->isTopSolidBlocking(x, y - 1, z) && !level->getMaterial(x, y - 2, z)->blocksMotion()) { - double xx = x + random->nextFloat(); - double yy = y - 1.05; - double zz = z + random->nextFloat(); + double xx = x + random->nextFloat(); + double yy = y - 1.05; + double zz = z + random->nextFloat(); if (material == Material::water) level->addParticle(eParticleType_dripWater, xx, yy, zz, 0, 0, 0); - else level->addParticle(eParticleType_dripLava, xx, yy, zz, 0, 0, 0); - } - } + else level->addParticle(eParticleType_dripLava, xx, yy, zz, 0, 0, 0); + } + } } double LiquidTile::getSlopeAngle(LevelSource *level, int x, int y, int z, Material *m) { - Vec3 *flow = NULL; - if (m == Material::water) flow = ((LiquidTile *) Tile::water)->getFlow(level, x, y, z); - if (m == Material::lava) flow = ((LiquidTile *) Tile::lava)->getFlow(level, x, y, z); - if (flow->x == 0 && flow->z == 0) return -1000; - return atan2(flow->z, flow->x) - PI / 2; + Vec3 *flow = NULL; + if (m == Material::water) flow = ((LiquidTile *) Tile::water)->getFlow(level, x, y, z); + if (m == Material::lava) flow = ((LiquidTile *) Tile::lava)->getFlow(level, x, y, z); + if (flow->x == 0 && flow->z == 0) return -1000; + return atan2(flow->z, flow->x) - PI / 2; } void LiquidTile::onPlace(Level *level, int x, int y, int z) @@ -357,41 +368,41 @@ void LiquidTile::neighborChanged(Level *level, int x, int y, int z, int type) void LiquidTile::updateLiquid(Level *level, int x, int y, int z) { - if (level->getTile(x, y, z) != id) return; - if (material == Material::lava) + if (level->getTile(x, y, z) != id) return; + if (material == Material::lava) { - bool water = false; - if (water || level->getMaterial(x, y, z - 1) == Material::water) water = true; - if (water || level->getMaterial(x, y, z + 1) == Material::water) water = true; - if (water || level->getMaterial(x - 1, y, z) == Material::water) water = true; - if (water || level->getMaterial(x + 1, y, z) == Material::water) water = true; - if (water || level->getMaterial(x, y + 1, z) == Material::water) water = true; - if (water) + bool water = false; + if (water || level->getMaterial(x, y, z - 1) == Material::water) water = true; + if (water || level->getMaterial(x, y, z + 1) == Material::water) water = true; + if (water || level->getMaterial(x - 1, y, z) == Material::water) water = true; + if (water || level->getMaterial(x + 1, y, z) == Material::water) water = true; + if (water || level->getMaterial(x, y + 1, z) == Material::water) water = true; + if (water) { - int data = level->getData(x, y, z); - if (data == 0) + int data = level->getData(x, y, z); + if (data == 0) { - level->setTile(x, y, z, Tile::obsidian_Id); - } + level->setTileAndUpdate(x, y, z, Tile::obsidian_Id); + } else if (data <= 4) { - level->setTile(x, y, z, Tile::stoneBrick_Id); - } - fizz(level, x, y, z); - } - } + level->setTileAndUpdate(x, y, z, Tile::cobblestone_Id); + } + fizz(level, x, y, z); + } + } } void LiquidTile::fizz(Level *level, int x, int y, int z) { MemSect(31); - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_RANDOM_FIZZ, 0.5f, 2.6f + (level->random->nextFloat() - level->random->nextFloat()) * 0.8f); + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_RANDOM_FIZZ, 0.5f, 2.6f + (level->random->nextFloat() - level->random->nextFloat()) * 0.8f); MemSect(0); - for (int i = 0; i < 8; i++) + for (int i = 0; i < 8; i++) { - level->addParticle(eParticleType_largesmoke, x +Math::random(), y + 1.2, z + Math::random(), 0, 0, 0); - } + level->addParticle(eParticleType_largesmoke, x +Math::random(), y + 1.2, z + Math::random(), 0, 0, 0); + } } void LiquidTile::registerIcons(IconRegister *iconRegister) diff --git a/Minecraft.World/LiquidTile.h b/Minecraft.World/LiquidTile.h index 67eb5b65..bcc00347 100644 --- a/Minecraft.World/LiquidTile.h +++ b/Minecraft.World/LiquidTile.h @@ -22,13 +22,13 @@ protected: public: virtual bool isPathfindable(LevelSource *level, int x, int y, int z); virtual int getColor() const; - virtual int getColor(LevelSource *level, int x, int y, int z); + virtual int getColor(LevelSource *level, int x, int y, int z); virtual int getColor(LevelSource *level, int x, int y, int z, int data); // 4J added - static float getHeight(int d); - virtual Icon *getTexture(int face, int data); + static float getHeight(int d); + virtual Icon *getTexture(int face, int data); protected: virtual int getDepth(Level *level, int x, int y, int z); - virtual int getRenderedDepth(LevelSource *level, int x, int y, int z); + virtual int getRenderedDepth(LevelSource *level, int x, int y, int z); public: virtual bool isCubeShaped(); virtual bool isSolidRender(bool isServerLevel = false); @@ -43,7 +43,7 @@ private: virtual Vec3 *getFlow(LevelSource *level, int x, int y, int z); public: virtual void handleEntityInside(Level *level, int x, int y, int z, shared_ptr e, Vec3 *current); - virtual int getTickDelay(); + virtual int getTickDelay(Level *level); virtual int getLightColor(LevelSource *level, int x, int y, int z, int tileId=-1); // 4J - brought forward from 1.8.2 virtual float getBrightness(LevelSource *level, int x, int y, int z); virtual int getRenderLayer(); diff --git a/Minecraft.World/LiquidTileDynamic.cpp b/Minecraft.World/LiquidTileDynamic.cpp index 14a93b93..2c7c74f4 100644 --- a/Minecraft.World/LiquidTileDynamic.cpp +++ b/Minecraft.World/LiquidTileDynamic.cpp @@ -6,8 +6,8 @@ LiquidTileDynamic::LiquidTileDynamic(int id, Material *material) : LiquidTile(id, material) { maxCount = 0; - result = new bool[4]; - dist = new int[4]; + result = new bool[4]; + dist = new int[4]; m_iterativeInstatick = false; } @@ -19,9 +19,8 @@ LiquidTileDynamic::~LiquidTileDynamic() void LiquidTileDynamic::setStatic(Level *level, int x, int y, int z) { - int d = level->getData(x, y, z); - level->setTileAndDataNoUpdate(x, y, z, id + 1, d); - level->setTilesDirty(x, y, z, x, y, z); + int d = level->getData(x, y, z); + level->setTileAndData(x, y, z, id + 1, d, Tile::UPDATE_CLIENTS); } bool LiquidTileDynamic::isPathfindable(LevelSource *level, int x, int y, int z) @@ -32,13 +31,16 @@ bool LiquidTileDynamic::isPathfindable(LevelSource *level, int x, int y, int z) void LiquidTileDynamic::iterativeTick(Level *level, int x, int y, int z, Random *random) { m_tilesToTick.push_back(LiquidTickData(level, x,y,z,random)); - - while(m_tilesToTick.size() > 0) + + int failsafe = 100; + while((m_tilesToTick.size() > 0) && ( failsafe > 0 ) ) { LiquidTickData tickData = m_tilesToTick.front(); m_tilesToTick.pop_front(); mainTick(tickData.level, tickData.x, tickData.y, tickData.z, tickData.random); + failsafe--; } + m_tilesToTick.clear(); } void LiquidTileDynamic::tick(Level *level, int x, int y, int z, Random *random) @@ -63,117 +65,119 @@ void LiquidTileDynamic::tick(Level *level, int x, int y, int z, Random *random) // This is to fix the stack overflow that occurs sometimes when instaticking on level gen. void LiquidTileDynamic::mainTick(Level *level, int x, int y, int z, Random *random) { - int depth = getDepth(level, x, y, z); + int depth = getDepth(level, x, y, z); - int dropOff = 1; - if (material == Material::lava && !level->dimension->ultraWarm) dropOff = 2; + int dropOff = 1; + if (material == Material::lava && !level->dimension->ultraWarm) dropOff = 2; - bool becomeStatic = true; - if (depth > 0) + bool becomeStatic = true; + int tickDelay = getTickDelay(level); + if (depth > 0) { - int highest = -100; - maxCount = 0; - highest = getHighest(level, x - 1, y, z, highest); - highest = getHighest(level, x + 1, y, z, highest); - highest = getHighest(level, x, y, z - 1, highest); - highest = getHighest(level, x, y, z + 1, highest); + int highest = -100; + maxCount = 0; + highest = getHighest(level, x - 1, y, z, highest); + highest = getHighest(level, x + 1, y, z, highest); + highest = getHighest(level, x, y, z - 1, highest); + highest = getHighest(level, x, y, z + 1, highest); - int newDepth = highest + dropOff; - if (newDepth >= 8 || highest < 0) + int newDepth = highest + dropOff; + if (newDepth >= 8 || highest < 0) { - newDepth = -1; - } - if (getDepth(level, x, y + 1, z) >= 0) + newDepth = -1; + } + if (getDepth(level, x, y + 1, z) >= 0) { - int above = getDepth(level, x, y + 1, z); - if (above >= 8) newDepth = above; - else newDepth = above + 8; - } - if (maxCount >= 2 && material == Material::water) + int above = getDepth(level, x, y + 1, z); + if (above >= 8) newDepth = above; + else newDepth = above + 8; + } + if (maxCount >= 2 && material == Material::water) { - // Only spread spring if it's on top of an existing spring, or + // Only spread spring if it's on top of an existing spring, or // on top of solid ground. - if (level->getMaterial(x, y - 1, z)->isSolid()) + if (level->getMaterial(x, y - 1, z)->isSolid()) { - newDepth = 0; - } + newDepth = 0; + } else if (level->getMaterial(x, y - 1, z) == material && level->getData(x, y - 1, z) == 0) { - newDepth = 0; - } - } - if (material == Material::lava) + newDepth = 0; + } + } + if (material == Material::lava) { - if (depth < 8 && newDepth < 8) + if (depth < 8 && newDepth < 8) { - if (newDepth > depth) + if (newDepth > depth) { - if (random->nextInt(4) != 0) + if (random->nextInt(4) != 0) { - newDepth = depth; - becomeStatic = false; - } - } - } - } - if (newDepth == depth) + tickDelay = tickDelay * 4; + } + } + } + } + if (newDepth == depth) { - if (becomeStatic) + if (becomeStatic) { setStatic(level, x, y, z); } - } + } else { - depth = newDepth; - if (depth < 0) + depth = newDepth; + if (depth < 0) { - level->setTile(x, y, z, 0); - } else + level->removeTile(x, y, z); + } + else { - level->setData(x, y, z, depth); - level->addToTickNextTick(x, y, z, id, getTickDelay()); - level->updateNeighborsAt(x, y, z, id); - } - } - } else + level->setData(x, y, z, depth, Tile::UPDATE_CLIENTS); + level->addToTickNextTick(x, y, z, id, tickDelay); + level->updateNeighborsAt(x, y, z, id); + } + } + } + else { - setStatic(level, x, y, z); - } - if (canSpreadTo(level, x, y - 1, z)) + setStatic(level, x, y, z); + } + if (canSpreadTo(level, x, y - 1, z)) { - if (material == Material::lava) + if (material == Material::lava) { - if (level->getMaterial(x, y - 1, z) == Material::water) + if (level->getMaterial(x, y - 1, z) == Material::water) { - level->setTile(x, y - 1, z, Tile::rock_Id); - fizz(level, x, y - 1, z); - return; - } - } + level->setTileAndUpdate(x, y - 1, z, Tile::stone_Id); + fizz(level, x, y - 1, z); + return; + } + } - if (depth >= 8) trySpreadTo(level, x, y - 1, z, depth); - else trySpreadTo(level, x, y - 1, z, depth + 8); - } + if (depth >= 8) trySpreadTo(level, x, y - 1, z, depth); + else trySpreadTo(level, x, y - 1, z, depth + 8); + } else if (depth >= 0 && (depth == 0 || isWaterBlocking(level, x, y - 1, z))) { - bool *spreads = getSpread(level, x, y, z); - int neighbor = depth + dropOff; - if (depth >= 8) + bool *spreads = getSpread(level, x, y, z); + int neighbor = depth + dropOff; + if (depth >= 8) { - neighbor = 1; - } - if (neighbor >= 8) return; - if (spreads[0]) trySpreadTo(level, x - 1, y, z, neighbor); - if (spreads[1]) trySpreadTo(level, x + 1, y, z, neighbor); - if (spreads[2]) trySpreadTo(level, x, y, z - 1, neighbor); - if (spreads[3]) trySpreadTo(level, x, y, z + 1, neighbor); - } + neighbor = 1; + } + if (neighbor >= 8) return; + if (spreads[0]) trySpreadTo(level, x - 1, y, z, neighbor); + if (spreads[1]) trySpreadTo(level, x + 1, y, z, neighbor); + if (spreads[2]) trySpreadTo(level, x, y, z - 1, neighbor); + if (spreads[3]) trySpreadTo(level, x, y, z + 1, neighbor); + } } void LiquidTileDynamic::trySpreadTo(Level *level, int x, int y, int z, int neighbor) { - if (canSpreadTo(level, x, y, z)) + if (canSpreadTo(level, x, y, z)) { { int old = level->getTile(x, y, z); @@ -189,129 +193,129 @@ void LiquidTileDynamic::trySpreadTo(Level *level, int x, int y, int z, int neigh } } } - level->setTileAndData(x, y, z, id, neighbor); - } + level->setTileAndData(x, y, z, id, neighbor, Tile::UPDATE_ALL); + } } int LiquidTileDynamic::getSlopeDistance(Level *level, int x, int y, int z, int pass, int from) { - int lowest = 1000; - for (int d = 0; d < 4; d++) + int lowest = 1000; + for (int d = 0; d < 4; d++) { - if (d == 0 && from == 1) continue; - if (d == 1 && from == 0) continue; - if (d == 2 && from == 3) continue; - if (d == 3 && from == 2) continue; + if (d == 0 && from == 1) continue; + if (d == 1 && from == 0) continue; + if (d == 2 && from == 3) continue; + if (d == 3 && from == 2) continue; - int xx = x; - int yy = y; - int zz = z; + int xx = x; + int yy = y; + int zz = z; - if (d == 0) xx--; - if (d == 1) xx++; - if (d == 2) zz--; - if (d == 3) zz++; + if (d == 0) xx--; + if (d == 1) xx++; + if (d == 2) zz--; + if (d == 3) zz++; - if (isWaterBlocking(level, xx, yy, zz)) + if (isWaterBlocking(level, xx, yy, zz)) { - continue; - } else if (level->getMaterial(xx, yy, zz) == material && level->getData(xx, yy, zz) == 0) + continue; + } else if (level->getMaterial(xx, yy, zz) == material && level->getData(xx, yy, zz) == 0) { - continue; - } + continue; + } else { - if (isWaterBlocking(level, xx, yy - 1, zz)) + if (isWaterBlocking(level, xx, yy - 1, zz)) { - if (pass < 4) + if (pass < 4) { - int v = getSlopeDistance(level, xx, yy, zz, pass + 1, d); - if (v < lowest) lowest = v; - } - } + int v = getSlopeDistance(level, xx, yy, zz, pass + 1, d); + if (v < lowest) lowest = v; + } + } else { - return pass; - } - } - } - return lowest; + return pass; + } + } + } + return lowest; } bool *LiquidTileDynamic::getSpread(Level *level, int x, int y, int z) { - for (int d = 0; d < 4; d++) + for (int d = 0; d < 4; d++) { - dist[d] = 1000; - int xx = x; - int yy = y; - int zz = z; + dist[d] = 1000; + int xx = x; + int yy = y; + int zz = z; - if (d == 0) xx--; - if (d == 1) xx++; - if (d == 2) zz--; - if (d == 3) zz++; - if (isWaterBlocking(level, xx, yy, zz)) + if (d == 0) xx--; + if (d == 1) xx++; + if (d == 2) zz--; + if (d == 3) zz++; + if (isWaterBlocking(level, xx, yy, zz)) { - continue; - } + continue; + } else if (level->getMaterial(xx, yy, zz) == material && level->getData(xx, yy, zz) == 0) { - continue; - } + continue; + } { - if (isWaterBlocking(level, xx, yy - 1, zz)) + if (isWaterBlocking(level, xx, yy - 1, zz)) { - dist[d] = getSlopeDistance(level, xx, yy, zz, 1, d); - } + dist[d] = getSlopeDistance(level, xx, yy, zz, 1, d); + } else { - dist[d] = 0; - } - } - } + dist[d] = 0; + } + } + } - int lowest = dist[0]; - for (int d = 1; d < 4; d++) + int lowest = dist[0]; + for (int d = 1; d < 4; d++) { - if (dist[d] < lowest) lowest = dist[d]; - } + if (dist[d] < lowest) lowest = dist[d]; + } - for (int d = 0; d < 4; d++) + for (int d = 0; d < 4; d++) { - result[d] = (dist[d] == lowest); - } - return result; + result[d] = (dist[d] == lowest); + } + return result; } bool LiquidTileDynamic::isWaterBlocking(Level *level, int x, int y, int z) { - int t = level->getTile(x, y, z); - if (t == Tile::door_wood_Id || t == Tile::door_iron_Id || t == Tile::sign_Id || t == Tile::ladder_Id || t == Tile::reeds_Id) + int t = level->getTile(x, y, z); + if (t == Tile::door_wood_Id || t == Tile::door_iron_Id || t == Tile::sign_Id || t == Tile::ladder_Id || t == Tile::reeds_Id) { - return true; - } - if (t == 0) return false; - Material *m = Tile::tiles[t]->material; - if (m == Material::portal) return true; - if (m->blocksMotion()) return true; - return false; + return true; + } + if (t == 0) return false; + Material *m = Tile::tiles[t]->material; + if (m == Material::portal) return true; + if (m->blocksMotion()) return true; + return false; } int LiquidTileDynamic::getHighest(Level *level, int x, int y, int z, int current) { - int d = getDepth(level, x, y, z); - if (d < 0) return current; - if (d == 0) maxCount++; - if (d >= 8) + int d = getDepth(level, x, y, z); + if (d < 0) return current; + if (d == 0) maxCount++; + if (d >= 8) { - d = 0; - } - return current < 0 || d < current ? d : current; + d = 0; + } + return current < 0 || d < current ? d : current; } bool LiquidTileDynamic::canSpreadTo(Level *level, int x, int y, int z) @@ -326,17 +330,22 @@ bool LiquidTileDynamic::canSpreadTo(Level *level, int x, int y, int z) if( ( ix < 0 ) || ( ix >= level->chunkSourceXZSize ) ) return false; if( ( iz < 0 ) || ( iz >= level->chunkSourceXZSize ) ) return false; - Material *target = level->getMaterial(x, y, z); - if (target == material) return false; - if (target == Material::lava) return false; - return !isWaterBlocking(level, x, y, z); + Material *target = level->getMaterial(x, y, z); + if (target == material) return false; + if (target == Material::lava) return false; + return !isWaterBlocking(level, x, y, z); } void LiquidTileDynamic::onPlace(Level *level, int x, int y, int z) { - LiquidTile::onPlace(level, x, y, z); - if (level->getTile(x, y, z) == id) + LiquidTile::onPlace(level, x, y, z); + if (level->getTile(x, y, z) == id) { - level->addToTickNextTick(x, y, z, id, getTickDelay()); - } + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); + } } + +bool LiquidTileDynamic::canInstantlyTick() +{ + return true; +} \ No newline at end of file diff --git a/Minecraft.World/LiquidTileDynamic.h b/Minecraft.World/LiquidTileDynamic.h index 51bbf181..bf0c9a6d 100644 --- a/Minecraft.World/LiquidTileDynamic.h +++ b/Minecraft.World/LiquidTileDynamic.h @@ -25,7 +25,7 @@ protected: virtual ~LiquidTileDynamic(); private: void setStatic(Level *level, int x, int y, int z); - int maxCount; + int maxCount; public: virtual bool isPathfindable(LevelSource *level, int x, int y, int z); @@ -38,17 +38,18 @@ public: private: void trySpreadTo(Level *level, int x, int y, int z, int neighbor); - bool *result; - int *dist; + bool *result; + int *dist; private: int getSlopeDistance(Level *level, int x, int y, int z, int pass, int from); - bool *getSpread(Level *level, int x, int y, int z); - bool isWaterBlocking(Level *level, int x, int y, int z); + bool *getSpread(Level *level, int x, int y, int z); + bool isWaterBlocking(Level *level, int x, int y, int z); protected: int getHighest(Level *level, int x, int y, int z, int current); private: bool canSpreadTo(Level *level, int x, int y, int z); public: void onPlace(Level *level, int x, int y, int z); + bool canInstantlyTick(); }; \ No newline at end of file diff --git a/Minecraft.World/LiquidTileStatic.cpp b/Minecraft.World/LiquidTileStatic.cpp index 1d82d3dd..46018093 100644 --- a/Minecraft.World/LiquidTileStatic.cpp +++ b/Minecraft.World/LiquidTileStatic.cpp @@ -5,8 +5,8 @@ LiquidTileStatic::LiquidTileStatic(int id, Material *material) : LiquidTile(id, material) { - setTicking(false); - if (material == Material::lava) setTicking(true); + setTicking(false); + if (material == Material::lava) setTicking(true); } bool LiquidTileStatic::isPathfindable(LevelSource *level, int x, int y, int z) @@ -16,53 +16,50 @@ bool LiquidTileStatic::isPathfindable(LevelSource *level, int x, int y, int z) void LiquidTileStatic::neighborChanged(Level *level, int x, int y, int z, int type) { - LiquidTile::neighborChanged(level, x, y, z, type); - if (level->getTile(x, y, z) == id) + LiquidTile::neighborChanged(level, x, y, z, type); + if (level->getTile(x, y, z) == id) { - setDynamic(level, x, y, z); - } + setDynamic(level, x, y, z); + } } void LiquidTileStatic::setDynamic(Level *level, int x, int y, int z) { - int d = level->getData(x, y, z); - level->noNeighborUpdate = true; - level->setTileAndDataNoUpdate(x, y, z, id - 1, d); - level->setTilesDirty(x, y, z, x, y, z); - level->addToTickNextTick(x, y, z, id - 1, getTickDelay()); - level->noNeighborUpdate = false; + int d = level->getData(x, y, z); + level->setTileAndData(x, y, z, id - 1, d, Tile::UPDATE_CLIENTS); + level->addToTickNextTick(x, y, z, id - 1, getTickDelay(level)); } void LiquidTileStatic::tick(Level *level, int x, int y, int z, Random *random) { - if (material == Material::lava) + if (material == Material::lava) { - int h = random->nextInt(3); - for (int i = 0; i < h; i++) + int h = random->nextInt(3); + for (int i = 0; i < h; i++) { - x += random->nextInt(3) - 1; - y++; - z += random->nextInt(3) - 1; - int t = level->getTile(x, y, z); - if (t == 0) + x += random->nextInt(3) - 1; + y++; + z += random->nextInt(3) - 1; + int t = level->getTile(x, y, z); + if (t == 0) { - if (isFlammable(level, x - 1, y, z) || + if (isFlammable(level, x - 1, y, z) || isFlammable(level, x + 1, y, z) || isFlammable(level, x, y, z - 1) || isFlammable(level, x, y, z + 1) || isFlammable(level, x, y - 1, z) || isFlammable(level, x, y + 1, z)) { - level->setTile(x, y, z, Tile::fire_Id); - return; - } - } + level->setTileAndUpdate(x, y, z, Tile::fire_Id); + return; + } + } else if (Tile::tiles[t]->material->blocksMotion()) { - return; - } + return; + } - } + } if (h == 0) { int ox = x; @@ -71,12 +68,13 @@ void LiquidTileStatic::tick(Level *level, int x, int y, int z, Random *random) { x = ox + random->nextInt(3) - 1; z = oz + random->nextInt(3) - 1; - if (level->isEmptyTile(x, y + 1, z) && isFlammable(level, x, y, z)) { - level->setTile(x, y + 1, z, Tile::fire_Id); + if (level->isEmptyTile(x, y + 1, z) && isFlammable(level, x, y, z)) + { + level->setTileAndUpdate(x, y + 1, z, Tile::fire_Id); } } } - } + } } bool LiquidTileStatic::isFlammable(Level *level, int x, int y, int z) diff --git a/Minecraft.World/ListTag.h b/Minecraft.World/ListTag.h index 9deeb22d..c80c0f39 100644 --- a/Minecraft.World/ListTag.h +++ b/Minecraft.World/ListTag.h @@ -5,51 +5,60 @@ using namespace std; template class ListTag : public Tag { private: - vector list; - byte type; + vector list; + byte type; public: ListTag() : Tag(L"") {} ListTag(const wstring &name) : Tag(name) {} - void write(DataOutput *dos) + void write(DataOutput *dos) { - if (list.size() > 0) type = (list[0])->getId(); - else type = 1; + if (list.size() > 0) type = (list[0])->getId(); + else type = 1; - dos->writeByte(type); - dos->writeInt((int)list.size()); + dos->writeByte(type); + dos->writeInt((int)list.size()); AUTO_VAR(itEnd, list.end()); - for (AUTO_VAR(it, list.begin()); it != itEnd; it++) - (*it)->write(dos); + for (AUTO_VAR(it, list.begin()); it != itEnd; it++) + (*it)->write(dos); } - void load(DataInput *dis) + + void load(DataInput *dis, int tagDepth) { - type = dis->readByte(); - int size = dis->readInt(); + if (tagDepth > MAX_DEPTH) + { +#ifndef _CONTENT_PACKAGE + printf("Tried to read NBT tag with too high complexity, depth > %d", MAX_DEPTH); + __debugbreak(); +#endif + return; + } + type = dis->readByte(); + int size = dis->readInt(); - list.clear(); - for (int i = 0; i < size; i++) + list.clear(); + for (int i = 0; i < size; i++) { - Tag *tag = Tag::newTag(type, L""); - tag->load(dis); - list.push_back(tag); - } + Tag *tag = Tag::newTag(type, L""); + tag->load(dis, tagDepth); + list.push_back(tag); + } } byte getId() { return TAG_List; } - wstring toString() + wstring toString() { static wchar_t buf[64]; swprintf(buf,64,L"%d entries of type %ls",list.size(),Tag::getTagName(type)); return wstring( buf ); } - void print(char *prefix, ostream out) + void print(char *prefix, ostream out) { - Tag::print(prefix, out); + Tag::print(prefix, out); out << prefix << "{" << endl; @@ -57,24 +66,29 @@ public: strcpy( newPrefix, prefix); strcat( newPrefix, " "); AUTO_VAR(itEnd, list.end()); - for (AUTO_VAR(it, list.begin()); it != itEnd; it++) - (*it)->print(newPrefix, out); + for (AUTO_VAR(it, list.begin()); it != itEnd; it++) + (*it)->print(newPrefix, out); delete[] newPrefix; out << prefix << "}" << endl; } - void add(T *tag) + void add(T *tag) { - type = tag->getId(); - list.push_back(tag); + type = tag->getId(); + // 4J: List tag write/load doesn't preserve tag names so remove them so we can safely do comparisons + // There are a few ways I could have fixed this but this seems the least invasive, most complete fix + // (covers other items that also use list tags and require equality checks to work) + // considering we can't change the write/load functions. + tag->setName(L""); + list.push_back(tag); } - T *get(int index) + T *get(int index) { return (T *) list[index]; } - int size() + int size() { return (int)list.size(); } @@ -82,18 +96,18 @@ public: virtual ~ListTag() { AUTO_VAR(itEnd, list.end()); - for (AUTO_VAR(it, list.begin()); it != itEnd; it++) + for (AUTO_VAR(it, list.begin()); it != itEnd; it++) { delete *it; } } - Tag *copy() + virtual Tag *copy() { ListTag *res = new ListTag(getName()); res->type = type; AUTO_VAR(itEnd, list.end()); - for (AUTO_VAR(it, list.begin()); it != itEnd; it++) + for (AUTO_VAR(it, list.begin()); it != itEnd; it++) { T *copy = (T *) (*it)->copy(); res->list.push_back(copy); @@ -101,8 +115,7 @@ public: return res; } -#if 0 - bool equals(Object obj) + virtual bool equals(Tag *obj) { if (Tag::equals(obj)) { @@ -115,10 +128,10 @@ public: equal = true; AUTO_VAR(itEnd, list.end()); // 4J Stu - Pretty inefficient method, but I think we can live with it give how often it will happen, and the small sizes of the data sets - for (AUTO_VAR(it, list.begin()); it != itEnd; it++) + for (AUTO_VAR(it, list.begin()); it != itEnd; ++it) { bool thisMatches = false; - for(AUTO_VAR(it2, o->list.begin()); it != o->list.end(); ++it2) + for(AUTO_VAR(it2, o->list.begin()); it2 != o->list.end(); ++it2) { if((*it)->equals(*it2)) { @@ -140,5 +153,4 @@ public: } return false; } -#endif }; \ No newline at end of file diff --git a/Minecraft.World/LivingEntity.cpp b/Minecraft.World/LivingEntity.cpp new file mode 100644 index 00000000..5f8a3dd1 --- /dev/null +++ b/Minecraft.World/LivingEntity.cpp @@ -0,0 +1,2005 @@ +#include "stdafx.h" +#include "JavaMath.h" +#include "Mth.h" +#include "net.minecraft.network.packet.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.ai.control.h" +#include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.ai.sensing.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.animal.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.chunk.h" +#include "net.minecraft.world.level.material.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.effect.h" +#include "net.minecraft.world.item.alchemy.h" +#include "net.minecraft.world.item.enchantment.h" +#include "net.minecraft.world.scores.h" +#include "com.mojang.nbt.h" +#include "LivingEntity.h" +#include "..\Minecraft.Client\Textures.h" +#include "..\Minecraft.Client\ServerLevel.h" +#include "..\Minecraft.Client\EntityTracker.h" +#include "SoundTypes.h" +#include "BasicTypeContainers.h" +#include "ParticleTypes.h" +#include "GenericStats.h" +#include "ItemEntity.h" + +const double LivingEntity::MIN_MOVEMENT_DISTANCE = 0.005; + +AttributeModifier *LivingEntity::SPEED_MODIFIER_SPRINTING = (new AttributeModifier(eModifierId_MOB_SPRINTING, 0.3f, AttributeModifier::OPERATION_MULTIPLY_TOTAL))->setSerialize(false); + +void LivingEntity::_init() +{ + attributes = NULL; + combatTracker = new CombatTracker(this); + lastEquipment = ItemInstanceArray(5); + + swinging = false; + swingTime = 0; + removeArrowTime = 0; + lastHealth = 0.0f; + + hurtTime = 0; + hurtDuration = 0; + hurtDir = 0.0f; + deathTime = 0; + attackTime = 0; + oAttackAnim = attackAnim = 0.0f; + + walkAnimSpeedO = 0.0f; + walkAnimSpeed = 0.0f; + walkAnimPos = 0.0f; + invulnerableDuration = 20; + oTilt = tilt = 0.0f; + timeOffs = 0.0f; + rotA = 0.0f; + yBodyRot = yBodyRotO = 0.0f; + yHeadRot = yHeadRotO = 0.0f; + flyingSpeed = 0.02f; + + lastHurtByPlayer = nullptr; + lastHurtByPlayerTime = 0; + dead = false; + noActionTime = 0; + oRun = run = 0.0f; + animStep = animStepO = 0.0f; + rotOffs = 0.0f; + deathScore = 0; + lastHurt = 0.0f; + jumping = false; + + xxa = 0.0f; + yya = 0.0f; + yRotA = 0.0f; + lSteps = 0; + lx = ly = lz = lyr = lxr = 0.0; + + effectsDirty = false; + + lastHurtByMob = nullptr; + lastHurtByMobTimestamp = 0; + lastHurtMob = nullptr; + lastHurtMobTimestamp = 0; + + speed = 0.0f; + noJumpDelay = 0; + absorptionAmount = 0.0f; +} + +LivingEntity::LivingEntity( Level* level) : Entity(level) +{ + MemSect(56); + _init(); + MemSect(0); + + // 4J Stu - This will not call the correct derived function, so moving to each derived class + //setHealth(0); + //registerAttributes(); + + blocksBuilding = true; + + rotA = (float) (Math::random() + 1) * 0.01f; + setPos(x, y, z); + timeOffs = (float) Math::random() * 12398; + yRot = (float) (Math::random() * PI * 2); + yHeadRot = yRot; + + footSize = 0.5f; +} + +LivingEntity::~LivingEntity() +{ + for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end(); ++it) + { + delete it->second; + } + + delete attributes; + delete combatTracker; + + if(lastEquipment.data != NULL) delete [] lastEquipment.data; +} + +void LivingEntity::defineSynchedData() +{ + entityData->define(DATA_EFFECT_COLOR_ID, 0); + entityData->define(DATA_EFFECT_AMBIENCE_ID, (byte) 0); + entityData->define(DATA_ARROW_COUNT_ID, (byte) 0); + entityData->define(DATA_HEALTH_ID, 1.0f); +} + +void LivingEntity::registerAttributes() +{ + getAttributes()->registerAttribute(SharedMonsterAttributes::MAX_HEALTH); + getAttributes()->registerAttribute(SharedMonsterAttributes::KNOCKBACK_RESISTANCE); + getAttributes()->registerAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + + if (!useNewAi()) + { + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.1f); + } +} + +void LivingEntity::checkFallDamage(double ya, bool onGround) +{ + if (!isInWater()) + { + // double-check if we've reached water in this move tick + updateInWaterState(); + } + + if (onGround && fallDistance > 0) + { + int xt = Mth::floor(x); + int yt = Mth::floor(y - 0.2f - heightOffset); + int zt = Mth::floor(z); + int t = level->getTile(xt, yt, zt); + if (t == 0) + { + int renderShape = level->getTileRenderShape(xt, yt - 1, zt); + if (renderShape == Tile::SHAPE_FENCE || renderShape == Tile::SHAPE_WALL || renderShape == Tile::SHAPE_FENCE_GATE) + { + t = level->getTile(xt, yt - 1, zt); + } + } + + if (t > 0) + { + Tile::tiles[t]->fallOn(level, xt, yt, zt, shared_from_this(), fallDistance); + } + } + + Entity::checkFallDamage(ya, onGround); +} + +bool LivingEntity::isWaterMob() +{ + return false; +} + +void LivingEntity::baseTick() +{ + oAttackAnim = attackAnim; + Entity::baseTick(); + + if (isAlive() && isInWall()) + { + hurt(DamageSource::inWall, 1); + } + + if (isFireImmune() || level->isClientSide) clearFire(); + shared_ptr thisPlayer = dynamic_pointer_cast(shared_from_this()); + bool isInvulnerable = (thisPlayer != NULL && thisPlayer->abilities.invulnerable); + + if (isAlive() && isUnderLiquid(Material::water)) + { + if(!isWaterMob() && !hasEffect(MobEffect::waterBreathing->id) && !isInvulnerable) + { + setAirSupply(decreaseAirSupply(getAirSupply())); + if (getAirSupply() == -20) + { + setAirSupply(0); + if(canCreateParticles()) + { + for (int i = 0; i < 8; i++) + { + float xo = random->nextFloat() - random->nextFloat(); + float yo = random->nextFloat() - random->nextFloat(); + float zo = random->nextFloat() - random->nextFloat(); + level->addParticle(eParticleType_bubble, x + xo, y + yo, z + zo, xd, yd, zd); + } + } + hurt(DamageSource::drown, 2); + } + } + + clearFire(); + if ( !level->isClientSide && isRiding() && riding->instanceof(eTYPE_LIVINGENTITY) ) + { + ride(nullptr); + } + } + else + { + setAirSupply(TOTAL_AIR_SUPPLY); + } + + oTilt = tilt; + + if (attackTime > 0) attackTime--; + if (hurtTime > 0) hurtTime--; + if (invulnerableTime > 0) invulnerableTime--; + if (getHealth() <= 0) + { + tickDeath(); + } + + if (lastHurtByPlayerTime > 0) lastHurtByPlayerTime--; + else + { + // Note - this used to just set to nullptr, but that has to create a new shared_ptr and free an old one, when generally this won't be doing anything at all. This + // is the lightweight but ugly alternative + if( lastHurtByPlayer ) + { + lastHurtByPlayer.reset(); + } + } + if (lastHurtMob != NULL && !lastHurtMob->isAlive()) + { + lastHurtMob = nullptr; + } + + // If lastHurtByMob is dead, remove it + if (lastHurtByMob != NULL && !lastHurtByMob->isAlive()) + { + setLastHurtByMob(nullptr); + } + + // Update effects + tickEffects(); + + animStepO = animStep; + + yBodyRotO = yBodyRot; + yHeadRotO = yHeadRot; + yRotO = yRot; + xRotO = xRot; +} + +bool LivingEntity::isBaby() +{ + return false; +} + +void LivingEntity::tickDeath() +{ + deathTime++; + if (deathTime == 20) + { + // 4J Stu - Added level->isClientSide check from 1.2 to fix XP orbs being created client side + if(!level->isClientSide && (lastHurtByPlayerTime > 0 || isAlwaysExperienceDropper()) ) + { + if (!isBaby() && level->getGameRules()->getBoolean(GameRules::RULE_DOMOBLOOT)) + { + int xpCount = this->getExperienceReward(lastHurtByPlayer); + while (xpCount > 0) + { + int newCount = ExperienceOrb::getExperienceValue(xpCount); + xpCount -= newCount; + level->addEntity(shared_ptr( new ExperienceOrb(level, x, y, z, newCount) ) ); + } + } + } + + remove(); + for (int i = 0; i < 20; i++) + { + double xa = random->nextGaussian() * 0.02; + double ya = random->nextGaussian() * 0.02; + double za = random->nextGaussian() * 0.02; + level->addParticle(eParticleType_explode, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); + } + } +} + +int LivingEntity::decreaseAirSupply(int currentSupply) +{ + int oxygenBonus = EnchantmentHelper::getOxygenBonus(dynamic_pointer_cast(shared_from_this())); + if (oxygenBonus > 0) + { + if (random->nextInt(oxygenBonus + 1) > 0) + { + // the oxygen bonus prevents us from drowning + return currentSupply; + } + } + if(instanceof(eTYPE_PLAYER)) + { + app.DebugPrintf("++++++++++ %s: Player decreasing air supply to %d\n", level->isClientSide ? "CLIENT" : "SERVER", currentSupply - 1 ); + } + return currentSupply - 1; +} + +int LivingEntity::getExperienceReward(shared_ptr killedBy) +{ + return 0; +} + +bool LivingEntity::isAlwaysExperienceDropper() +{ + return false; +} + +Random *LivingEntity::getRandom() +{ + return random; +} + +shared_ptr LivingEntity::getLastHurtByMob() +{ + return lastHurtByMob; +} + +int LivingEntity::getLastHurtByMobTimestamp() +{ + return lastHurtByMobTimestamp; +} + +void LivingEntity::setLastHurtByMob(shared_ptr target) +{ + lastHurtByMob = target; + lastHurtByMobTimestamp = tickCount; +} + +shared_ptr LivingEntity::getLastHurtMob() +{ + return lastHurtMob; +} + +int LivingEntity::getLastHurtMobTimestamp() +{ + return lastHurtMobTimestamp; +} + +void LivingEntity::setLastHurtMob(shared_ptr target) +{ + if ( target->instanceof(eTYPE_LIVINGENTITY) ) + { + lastHurtMob = dynamic_pointer_cast(target); + } + else + { + lastHurtMob = nullptr; + } + lastHurtMobTimestamp = tickCount; +} + +int LivingEntity::getNoActionTime() +{ + return noActionTime; +} + +void LivingEntity::addAdditonalSaveData(CompoundTag *entityTag) +{ + entityTag->putFloat(L"HealF", getHealth()); + entityTag->putShort(L"Health", (short) ceil(getHealth())); + entityTag->putShort(L"HurtTime", (short) hurtTime); + entityTag->putShort(L"DeathTime", (short) deathTime); + entityTag->putShort(L"AttackTime", (short) attackTime); + entityTag->putFloat(L"AbsorptionAmount", getAbsorptionAmount()); + + ItemInstanceArray items = getEquipmentSlots(); + for (unsigned int i = 0; i < items.length; ++i) + { + shared_ptr item = items[i]; + if (item != NULL) + { + attributes->removeItemModifiers(item); + } + } + + entityTag->put(L"Attributes", SharedMonsterAttributes::saveAttributes(getAttributes())); + + for (unsigned int i = 0; i < items.length; ++i) + { + shared_ptr item = items[i]; + if (item != NULL) + { + attributes->addItemModifiers(item); + } + } + + if (!activeEffects.empty()) + { + ListTag *listTag = new ListTag(); + + for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end(); ++it) + { + MobEffectInstance *effect = it->second; + listTag->add(effect->save(new CompoundTag())); + } + entityTag->put(L"ActiveEffects", listTag); + } +} + +void LivingEntity::readAdditionalSaveData(CompoundTag *tag) +{ + setAbsorptionAmount(tag->getFloat(L"AbsorptionAmount")); + + if (tag->contains(L"Attributes") && level != NULL && !level->isClientSide) + { + SharedMonsterAttributes::loadAttributes(getAttributes(), (ListTag *) tag->getList(L"Attributes")); + } + + if (tag->contains(L"ActiveEffects")) + { + ListTag *effects = (ListTag *) tag->getList(L"ActiveEffects"); + for (int i = 0; i < effects->size(); i++) + { + CompoundTag *effectTag = effects->get(i); + MobEffectInstance *effect = MobEffectInstance::load(effectTag); + activeEffects.insert( unordered_map::value_type( effect->getId(), effect ) ); + } + } + + if (tag->contains(L"HealF")) + { + setHealth( tag->getFloat(L"HealF") ); + } + else + { + Tag *healthTag = tag->get(L"Health"); + if (healthTag == NULL) + { + setHealth(getMaxHealth()); + } + else if (healthTag->getId() == Tag::TAG_Float) + { + setHealth(((FloatTag *) healthTag)->data); + } + else if (healthTag->getId() == Tag::TAG_Short) + { + // pre-1.6 health + setHealth((float) ((ShortTag *) healthTag)->data); + } + } + + hurtTime = tag->getShort(L"HurtTime"); + deathTime = tag->getShort(L"DeathTime"); + attackTime = tag->getShort(L"AttackTime"); +} + +void LivingEntity::tickEffects() +{ + bool removed = false; + for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end();) + { + MobEffectInstance *effect = it->second; + removed = false; + if (!effect->tick(dynamic_pointer_cast(shared_from_this()))) + { + if (!level->isClientSide) + { + it = activeEffects.erase( it ); + onEffectRemoved(effect); + delete effect; + removed = true; + } + } + else if (effect->getDuration() % (SharedConstants::TICKS_PER_SECOND * 30) == 0) + { + // update effects every 30 seconds to synchronize client-side + // timer + onEffectUpdated(effect, false); + } + if(!removed) + { + ++it; + } + } + if (effectsDirty) + { + if (!level->isClientSide) + { + if (activeEffects.empty()) + { + entityData->set(DATA_EFFECT_AMBIENCE_ID, (byte) 0); + entityData->set(DATA_EFFECT_COLOR_ID, 0); + setInvisible(false); + setWeakened(false); + } + else + { + vector values; + for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end();++it) + { + values.push_back(it->second); + } + int colorValue = PotionBrewing::getColorValue(&values); + entityData->set(DATA_EFFECT_AMBIENCE_ID, PotionBrewing::areAllEffectsAmbient(&values) ? (byte) 1 : (byte) 0); + values.clear(); + entityData->set(DATA_EFFECT_COLOR_ID, colorValue); + setInvisible(hasEffect(MobEffect::invisibility->id)); + setWeakened(hasEffect(MobEffect::weakness->id)); + } + } + effectsDirty = false; + } + int colorValue = entityData->getInteger(DATA_EFFECT_COLOR_ID); + bool ambient = entityData->getByte(DATA_EFFECT_AMBIENCE_ID) > 0; + + if (colorValue > 0) + { + boolean doParticle = false; + + if (!isInvisible()) + { + doParticle = random->nextBoolean(); + } + else + { + // much fewer particles when invisible + doParticle = random->nextInt(15) == 0; + } + + if (ambient) doParticle &= random->nextInt(5) == 0; + + if (doParticle) + { + // int colorValue = entityData.getInteger(DATA_EFFECT_COLOR_ID); + if (colorValue > 0) + { + double red = (double) ((colorValue >> 16) & 0xff) / 255.0; + double green = (double) ((colorValue >> 8) & 0xff) / 255.0; + double blue = (double) ((colorValue >> 0) & 0xff) / 255.0; + + level->addParticle(ambient? eParticleType_mobSpellAmbient : eParticleType_mobSpell, x + (random->nextDouble() - 0.5) * bbWidth, y + random->nextDouble() * bbHeight - heightOffset, z + (random->nextDouble() - 0.5) * bbWidth, red, green, blue); + } + } + } +} + +void LivingEntity::removeAllEffects() +{ + //Iterator effectIdIterator = activeEffects.keySet().iterator(); + //while (effectIdIterator.hasNext()) + for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end(); ) + { + //Integer effectId = effectIdIterator.next(); + MobEffectInstance *effect = it->second;//activeEffects.get(effectId); + + if (!level->isClientSide) + { + //effectIdIterator.remove(); + it = activeEffects.erase(it); + onEffectRemoved(effect); + delete effect; + } + else + { + ++it; + } + } +} + +vector *LivingEntity::getActiveEffects() +{ + vector *active = new vector(); + + for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end(); ++it) + { + active->push_back(it->second); + } + + return active; +} + +bool LivingEntity::hasEffect(int id) +{ + return activeEffects.find(id) != activeEffects.end();; +} + +bool LivingEntity::hasEffect(MobEffect *effect) +{ + return activeEffects.find(effect->id) != activeEffects.end(); +} + +MobEffectInstance *LivingEntity::getEffect(MobEffect *effect) +{ + MobEffectInstance *effectInst = NULL; + + AUTO_VAR(it, activeEffects.find(effect->id)); + if(it != activeEffects.end() ) effectInst = it->second; + + return effectInst; +} + +void LivingEntity::addEffect(MobEffectInstance *newEffect) +{ + if (!canBeAffected(newEffect)) + { + return; + } + + if (activeEffects.find(newEffect->getId()) != activeEffects.end() ) + { + // replace effect and update + MobEffectInstance *effectInst = activeEffects.find(newEffect->getId())->second; + effectInst->update(newEffect); + onEffectUpdated(effectInst, true); + } + else + { + activeEffects.insert( unordered_map::value_type( newEffect->getId(), newEffect ) ); + onEffectAdded(newEffect); + } +} + +// 4J Added +void LivingEntity::addEffectNoUpdate(MobEffectInstance *newEffect) +{ + if (!canBeAffected(newEffect)) + { + return; + } + + if (activeEffects.find(newEffect->getId()) != activeEffects.end() ) + { + // replace effect and update + MobEffectInstance *effectInst = activeEffects.find(newEffect->getId())->second; + effectInst->update(newEffect); + } + else + { + activeEffects.insert( unordered_map::value_type( newEffect->getId(), newEffect ) ); + } +} + +bool LivingEntity::canBeAffected(MobEffectInstance *newEffect) +{ + if (getMobType() == UNDEAD) + { + int id = newEffect->getId(); + if (id == MobEffect::regeneration->id || id == MobEffect::poison->id) + { + return false; + } + } + + return true; +} + +bool LivingEntity::isInvertedHealAndHarm() +{ + return getMobType() == UNDEAD; +} + +void LivingEntity::removeEffectNoUpdate(int effectId) +{ + AUTO_VAR(it, activeEffects.find(effectId)); + if (it != activeEffects.end()) + { + MobEffectInstance *effect = it->second; + if(effect != NULL) + { + delete effect; + } + activeEffects.erase(it); + } +} + +void LivingEntity::removeEffect(int effectId) +{ + AUTO_VAR(it, activeEffects.find(effectId)); + if (it != activeEffects.end()) + { + MobEffectInstance *effect = it->second; + if(effect != NULL) + { + onEffectRemoved(effect); + delete effect; + } + activeEffects.erase(it); + } +} + +void LivingEntity::onEffectAdded(MobEffectInstance *effect) +{ + effectsDirty = true; + if (!level->isClientSide) MobEffect::effects[effect->getId()]->addAttributeModifiers(dynamic_pointer_cast(shared_from_this()), getAttributes(), effect->getAmplifier()); +} + +void LivingEntity::onEffectUpdated(MobEffectInstance *effect, bool doRefreshAttributes) +{ + effectsDirty = true; + if (doRefreshAttributes && !level->isClientSide) + { + MobEffect::effects[effect->getId()]->removeAttributeModifiers(dynamic_pointer_cast(shared_from_this()), getAttributes(), effect->getAmplifier()); + MobEffect::effects[effect->getId()]->addAttributeModifiers(dynamic_pointer_cast(shared_from_this()), getAttributes(), effect->getAmplifier()); + } +} + +void LivingEntity::onEffectRemoved(MobEffectInstance *effect) +{ + effectsDirty = true; + if (!level->isClientSide) MobEffect::effects[effect->getId()]->removeAttributeModifiers(dynamic_pointer_cast(shared_from_this()), getAttributes(), effect->getAmplifier()); +} + +void LivingEntity::heal(float heal) +{ + float health = getHealth(); + if (health > 0) + { + setHealth(health + heal); + } +} + +float LivingEntity::getHealth() +{ + return entityData->getFloat(DATA_HEALTH_ID); +} + +void LivingEntity::setHealth(float health) +{ + entityData->set(DATA_HEALTH_ID, Mth::clamp(health, 0.0f, getMaxHealth())); +} + +bool LivingEntity::hurt(DamageSource *source, float dmg) +{ + if (isInvulnerable()) return false; + + // 4J Stu - Reworked this function a bit to show hurt damage on the client before the server responds. + // Fix for #8823 - Gameplay: Confirmation that a monster or animal has taken damage from an attack is highly delayed + // 4J Stu - Change to the fix to only show damage when attacked, rather than collision damage + // Fix for #10299 - When in corners, passive mobs may show that they are taking damage. + // 4J Stu - Change to the fix for TU6, as source is never NULL due to changes in 1.8.2 to what source actually is + if (level->isClientSide && dynamic_cast(source) == NULL) return false; + noActionTime = 0; + if (getHealth() <= 0) return false; + + if ( source->isFire() && hasEffect(MobEffect::fireResistance) ) + { + // 4J-JEV, for new achievement Stayin'Frosty, TODO merge with Java version. + if ( this->instanceof(eTYPE_PLAYER) && (source == DamageSource::lava) ) // Only award when in lava (not any fire). + { + shared_ptr plr = dynamic_pointer_cast(shared_from_this()); + plr->awardStat(GenericStats::stayinFrosty(),GenericStats::param_stayinFrosty()); + } + return false; + } + + if ((source == DamageSource::anvil || source == DamageSource::fallingBlock) && getCarried(SLOT_HELM) != NULL) + { + getCarried(SLOT_HELM)->hurtAndBreak((int) (dmg * 4 + random->nextFloat() * dmg * 2.0f), dynamic_pointer_cast( shared_from_this() )); + dmg *= 0.75f; + } + + walkAnimSpeed = 1.5f; + + bool sound = true; + if (invulnerableTime > invulnerableDuration / 2.0f) + { + if (dmg <= lastHurt) return false; + if(!level->isClientSide) actuallyHurt(source, dmg - lastHurt); + lastHurt = dmg; + sound = false; + } + else + { + lastHurt = dmg; + lastHealth = getHealth(); + invulnerableTime = invulnerableDuration; + if (!level->isClientSide) actuallyHurt(source, dmg); + hurtTime = hurtDuration = 10; + } + + hurtDir = 0; + + shared_ptr sourceEntity = source->getEntity(); + if (sourceEntity != NULL) + { + if ( sourceEntity->instanceof(eTYPE_LIVINGENTITY) ) + { + setLastHurtByMob(dynamic_pointer_cast(sourceEntity)); + } + + if ( sourceEntity->instanceof(eTYPE_PLAYER) ) + { + lastHurtByPlayerTime = PLAYER_HURT_EXPERIENCE_TIME; + lastHurtByPlayer = dynamic_pointer_cast(sourceEntity); + } + else if ( sourceEntity->instanceof(eTYPE_WOLF) ) + { + shared_ptr w = dynamic_pointer_cast(sourceEntity); + if (w->isTame()) + { + lastHurtByPlayerTime = PLAYER_HURT_EXPERIENCE_TIME; + lastHurtByPlayer = nullptr; + } + } + } + + if (sound && level->isClientSide) + { + return false; + } + + if (sound) + { + level->broadcastEntityEvent(shared_from_this(), EntityEvent::HURT); + if (source != DamageSource::drown) markHurt(); + if (sourceEntity != NULL) + { + double xd = sourceEntity->x - x; + double zd = sourceEntity->z - z; + while (xd * xd + zd * zd < 0.0001) + { + xd = (Math::random() - Math::random()) * 0.01; + zd = (Math::random() - Math::random()) * 0.01; + } + hurtDir = (float) (atan2(zd, xd) * 180 / PI) - yRot; + knockback(sourceEntity, dmg, xd, zd); + } + else + { + hurtDir = (float) (int) ((Math::random() * 2) * 180); // 4J This cast is the same as Java + } + } + + MemSect(31); + if (getHealth() <= 0) + { + if (sound) playSound(getDeathSound(), getSoundVolume(), getVoicePitch()); + die(source); + } + else + { + if (sound) playSound(getHurtSound(), getSoundVolume(), getVoicePitch()); + } + MemSect(0); + + return true; +} + +void LivingEntity::breakItem(shared_ptr itemInstance) +{ + playSound(eSoundType_RANDOM_BREAK, 0.8f, 0.8f + level->random->nextFloat() * 0.4f); + + for (int i = 0; i < 5; i++) + { + Vec3 *d = Vec3::newTemp((random->nextFloat() - 0.5) * 0.1, Math::random() * 0.1 + 0.1, 0); + d->xRot(-xRot * PI / 180); + d->yRot(-yRot * PI / 180); + + Vec3 *p = Vec3::newTemp((random->nextFloat() - 0.5) * 0.3, -random->nextFloat() * 0.6 - 0.3, 0.6); + p->xRot(-xRot * PI / 180); + p->yRot(-yRot * PI / 180); + p = p->add(x, y + getHeadHeight(), z); + level->addParticle(PARTICLE_ICONCRACK(itemInstance->getItem()->id,0), p->x, p->y, p->z, d->x, d->y + 0.05, d->z); + } +} + +void LivingEntity::die(DamageSource *source) +{ + shared_ptr sourceEntity = source->getEntity(); + shared_ptr killer = getKillCredit(); + if (deathScore >= 0 && killer != NULL) killer->awardKillScore(shared_from_this(), deathScore); + + if (sourceEntity != NULL) sourceEntity->killed( dynamic_pointer_cast( shared_from_this() ) ); + + dead = true; + + if (!level->isClientSide) + { + int playerBonus = 0; + + shared_ptr player = nullptr; + if ( (sourceEntity != NULL) && sourceEntity->instanceof(eTYPE_PLAYER) ) + { + player = dynamic_pointer_cast(sourceEntity); + playerBonus = EnchantmentHelper::getKillingLootBonus(dynamic_pointer_cast(player)); + } + + if (!isBaby() && level->getGameRules()->getBoolean(GameRules::RULE_DOMOBLOOT)) + { + dropDeathLoot(lastHurtByPlayerTime > 0, playerBonus); + dropEquipment(lastHurtByPlayerTime > 0, playerBonus); + if (lastHurtByPlayerTime > 0) + { + int rareLoot = random->nextInt(200) - playerBonus; + if (rareLoot < 5) + { + dropRareDeathLoot((rareLoot <= 0) ? 1 : 0); + } + } + } + + // 4J-JEV, hook for Durango mobKill event. + if (player != NULL) + { + player->awardStat(GenericStats::killMob(),GenericStats::param_mobKill(player, dynamic_pointer_cast(shared_from_this()), source)); + } + } + + level->broadcastEntityEvent(shared_from_this(), EntityEvent::DEATH); +} + +void LivingEntity::dropEquipment(bool byPlayer, int playerBonusLevel) +{ +} + +void LivingEntity::knockback(shared_ptr source, float dmg, double xd, double zd) +{ + if (random->nextDouble() < getAttribute(SharedMonsterAttributes::KNOCKBACK_RESISTANCE)->getValue()) + { + return; + } + + hasImpulse = true; + float dd = Mth::sqrt(xd * xd + zd * zd); + float pow = 0.4f; + + this->xd /= 2; + yd /= 2; + this->zd /= 2; + + this->xd -= xd / dd * pow; + yd += pow; + this->zd -= zd / dd * pow; + + if (yd > 0.4f) yd = 0.4f; +} + +int LivingEntity::getHurtSound() +{ + return eSoundType_DAMAGE_HURT; +} + +int LivingEntity::getDeathSound() +{ + return eSoundType_DAMAGE_HURT; +} + +/** +* Drop extra rare loot. Only occurs roughly 5% of the time, rareRootLevel +* is set to 1 (otherwise 0) 1% of the time. +* +* @param rareLootLevel +*/ +void LivingEntity::dropRareDeathLoot(int rareLootLevel) +{ + +} + +void LivingEntity::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) +{ +} + +bool LivingEntity::onLadder() +{ + int xt = Mth::floor(x); + int yt = Mth::floor(bb->y0); + int zt = Mth::floor(z); + + // 4J-PB - TU9 - add climbable vines + int iTile = level->getTile(xt, yt, zt); + return (iTile== Tile::ladder_Id) || (iTile== Tile::vine_Id); +} + +bool LivingEntity::isShootable() +{ + return true; +} + +bool LivingEntity::isAlive() +{ + return !removed && getHealth() > 0; +} + +void LivingEntity::causeFallDamage(float distance) +{ + Entity::causeFallDamage(distance); + MobEffectInstance *jumpBoost = getEffect(MobEffect::jump); + float padding = jumpBoost != NULL ? jumpBoost->getAmplifier() + 1 : 0; + + int dmg = (int) ceil(distance - 3 - padding); + if (dmg > 0) + { + // 4J - new sounds here brought forward from 1.2.3 + if (dmg > 4) + { + playSound(eSoundType_DAMAGE_FALL_BIG, 1, 1); + } + else + { + playSound(eSoundType_DAMAGE_FALL_SMALL, 1, 1); + } + hurt(DamageSource::fall, dmg); + + int t = level->getTile( Mth::floor(x), Mth::floor(y - 0.2f - this->heightOffset), Mth::floor(z)); + if (t > 0) + { + const Tile::SoundType *soundType = Tile::tiles[t]->soundType; + MemSect(31); + playSound(soundType->getStepSound(), soundType->getVolume() * 0.5f, soundType->getPitch() * 0.75f); + MemSect(0); + } + } +} + +void LivingEntity::animateHurt() +{ + hurtTime = hurtDuration = 10; + hurtDir = 0; +} + +/** +* Fetches the mob's armor value, from 0 (no armor) to 20 (full armor) +* +* @return +*/ +int LivingEntity::getArmorValue() +{ + int val = 0; + ItemInstanceArray items = getEquipmentSlots(); + for (unsigned int i = 0; i < items.length; ++i) + { + shared_ptr item = items[i]; + if (item != NULL && dynamic_cast(item->getItem()) != NULL) + { + int baseProtection = ((ArmorItem *) item->getItem())->defense; + val += baseProtection; + } + } + return val; +} + +void LivingEntity::hurtArmor(float damage) +{ +} + +float LivingEntity::getDamageAfterArmorAbsorb(DamageSource *damageSource, float damage) +{ + if (!damageSource->isBypassArmor()) + { + int absorb = 25 - getArmorValue(); + float v = (damage) * absorb; + hurtArmor(damage); + damage = v / 25; + } + return damage; +} + +float LivingEntity::getDamageAfterMagicAbsorb(DamageSource *damageSource, float damage) +{ + // [EB]: Stupid hack :( + if ( this->instanceof(eTYPE_ZOMBIE) ) + { + damage = damage; + } + if (hasEffect(MobEffect::damageResistance) && damageSource != DamageSource::outOfWorld) + { + int absorbValue = (getEffect(MobEffect::damageResistance)->getAmplifier() + 1) * 5; + int absorb = 25 - absorbValue; + float v = (damage) * absorb; + damage = v / 25; + } + + if (damage <= 0) return 0; + + int enchantmentArmor = EnchantmentHelper::getDamageProtection(getEquipmentSlots(), damageSource); + if (enchantmentArmor > 20) + { + enchantmentArmor = 20; + } + if (enchantmentArmor > 0 && enchantmentArmor <= 20) + { + int absorb = 25 - enchantmentArmor; + float v = damage * absorb; + damage = v / 25; + } + + return damage; +} + +void LivingEntity::actuallyHurt(DamageSource *source, float dmg) +{ + if (isInvulnerable()) return; + dmg = getDamageAfterArmorAbsorb(source, dmg); + dmg = getDamageAfterMagicAbsorb(source, dmg); + + float originalDamage = dmg; + dmg = max(dmg - getAbsorptionAmount(), 0.0f); + setAbsorptionAmount(getAbsorptionAmount() - (originalDamage - dmg)); + if (dmg == 0) return; + + float oldHealth = getHealth(); + setHealth(oldHealth - dmg); + getCombatTracker()->recordDamage(source, oldHealth, dmg); + setAbsorptionAmount(getAbsorptionAmount() - dmg); +} + +CombatTracker *LivingEntity::getCombatTracker() +{ + return combatTracker; +} + +shared_ptr LivingEntity::getKillCredit() +{ + if (combatTracker->getKiller() != NULL) return combatTracker->getKiller(); + if (lastHurtByPlayer != NULL) return lastHurtByPlayer; + if (lastHurtByMob != NULL) return lastHurtByMob; + return nullptr; +} + +float LivingEntity::getMaxHealth() +{ + return (float) getAttribute(SharedMonsterAttributes::MAX_HEALTH)->getValue(); +} + +int LivingEntity::getArrowCount() +{ + return entityData->getByte(DATA_ARROW_COUNT_ID); +} + +void LivingEntity::setArrowCount(int count) +{ + entityData->set(DATA_ARROW_COUNT_ID, (byte) count); +} + +int LivingEntity::getCurrentSwingDuration() +{ + if (hasEffect(MobEffect::digSpeed)) + { + return SWING_DURATION - (1 + getEffect(MobEffect::digSpeed)->getAmplifier()) * 1; + } + if (hasEffect(MobEffect::digSlowdown)) + { + return SWING_DURATION + (1 + getEffect(MobEffect::digSlowdown)->getAmplifier()) * 2; + } + return SWING_DURATION; +} + +void LivingEntity::swing() +{ + if (!swinging || swingTime >= getCurrentSwingDuration() / 2 || swingTime < 0) + { + swingTime = -1; + swinging = true; + + if (dynamic_cast(level) != NULL) + { + ((ServerLevel *) level)->getTracker()->broadcast(shared_from_this(), shared_ptr( new AnimatePacket(shared_from_this(), AnimatePacket::SWING))); + } + } +} + +void LivingEntity::handleEntityEvent(byte id) +{ + if (id == EntityEvent::HURT) + { + walkAnimSpeed = 1.5f; + + invulnerableTime = invulnerableDuration; + hurtTime = hurtDuration = 10; + hurtDir = 0; + + MemSect(31); + // 4J-PB -added because villagers have no sounds + int iHurtSound=getHurtSound(); + if(iHurtSound!=-1) + { + playSound(iHurtSound, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); + } + MemSect(0); + hurt(DamageSource::genericSource, 0); + } + else if (id == EntityEvent::DEATH) + { + MemSect(31); + // 4J-PB -added because villagers have no sounds + int iDeathSound=getDeathSound(); + if(iDeathSound!=-1) + { + playSound(iDeathSound, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); + } + MemSect(0); + setHealth(0); + die(DamageSource::genericSource); + } + else + { + Entity::handleEntityEvent(id); + } +} + +void LivingEntity::outOfWorld() +{ + hurt(DamageSource::outOfWorld, 4); +} + +void LivingEntity::updateSwingTime() +{ + int currentSwingDuration = getCurrentSwingDuration(); + if (swinging) + { + swingTime++; + if (swingTime >= currentSwingDuration) + { + swingTime = 0; + swinging = false; + } + } + else + { + swingTime = 0; + } + + attackAnim = swingTime / (float) currentSwingDuration; +} + +AttributeInstance *LivingEntity::getAttribute(Attribute *attribute) +{ + return getAttributes()->getInstance(attribute); +} + +BaseAttributeMap *LivingEntity::getAttributes() +{ + if (attributes == NULL) + { + attributes = new ServersideAttributeMap(); + } + + return attributes; +} + +MobType LivingEntity::getMobType() +{ + return UNDEFINED; +} + +void LivingEntity::setSprinting(bool value) +{ + Entity::setSprinting(value); + + AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + if (speed->getModifier(eModifierId_MOB_SPRINTING) != NULL) + { + speed->removeModifier(eModifierId_MOB_SPRINTING); + } + if (value) + { + speed->addModifier(new AttributeModifier(*SPEED_MODIFIER_SPRINTING)); + } +} + +float LivingEntity::getSoundVolume() +{ + return 1; +} + +float LivingEntity::getVoicePitch() +{ + if (isBaby()) + { + return (random->nextFloat() - random->nextFloat()) * 0.2f + 1.5f; + + } + return (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f; +} + +bool LivingEntity::isImmobile() +{ + return getHealth() <= 0; +} + +void LivingEntity::teleportTo(double x, double y, double z) +{ + moveTo(x, y, z, yRot, xRot); +} + +void LivingEntity::findStandUpPosition(shared_ptr vehicle) +{ + AABB *boundingBox; + double fallbackX = vehicle->x; + double fallbackY = vehicle->bb->y0 + vehicle->bbHeight; + double fallbackZ = vehicle->z; + + for (double xDiff = -1.5; xDiff < 2; xDiff += 1.5) + { + for (double zDiff = -1.5; zDiff < 2; zDiff += 1.5) + { + if (xDiff == 0 && zDiff == 0) + { + continue; + } + + int xToInt = (int) (x + xDiff); + int zToInt = (int) (z + zDiff); + boundingBox = bb->cloneMove(xDiff, 1, zDiff); + + if (level->getTileCubes(boundingBox, true)->empty()) + { + if (level->isTopSolidBlocking(xToInt, (int) y, zToInt)) + { + teleportTo(x + xDiff, y + 1, z + zDiff); + return; + } + else if (level->isTopSolidBlocking(xToInt, (int) y - 1, zToInt) || level->getMaterial(xToInt, (int) y - 1, zToInt) == Material::water) + { + fallbackX = x + xDiff; + fallbackY = y + 1; + fallbackZ = z + zDiff; + } + } + } + } + + teleportTo(fallbackX, fallbackY, fallbackZ); +} + +bool LivingEntity::shouldShowName() +{ + return false; +} + +Icon *LivingEntity::getItemInHandIcon(shared_ptr item, int layer) +{ + return item->getIcon(); +} + +void LivingEntity::jumpFromGround() +{ + yd = 0.42f; + if (hasEffect(MobEffect::jump)) + { + yd += (getEffect(MobEffect::jump)->getAmplifier() + 1) * .1f; + } + if (isSprinting()) + { + float rr = yRot * Mth::RAD_TO_GRAD; + + xd -= Mth::sin(rr) * 0.2f; + zd += Mth::cos(rr) * 0.2f; + } + this->hasImpulse = true; +} + +void LivingEntity::travel(float xa, float ya) +{ +#ifdef __PSVITA__ + // AP - dynamic_pointer_cast is a non-trivial call + Player *thisPlayer = NULL; + if( this->instanceof(eTYPE_PLAYER) ) + { + thisPlayer = (Player*) this; + } +#else + shared_ptr thisPlayer = dynamic_pointer_cast(shared_from_this()); +#endif + if (isInWater() && !(thisPlayer && thisPlayer->abilities.flying) ) + { + double yo = y; + moveRelative(xa, ya, useNewAi() ? 0.04f : 0.02f); + move(xd, yd, zd); + + xd *= 0.80f; + yd *= 0.80f; + zd *= 0.80f; + yd -= 0.02; + + if (horizontalCollision && isFree(xd, yd + 0.6f - y + yo, zd)) + { + yd = 0.3f; + } + } + else if (isInLava() && !(thisPlayer && thisPlayer->abilities.flying) ) + { + double yo = y; + moveRelative(xa, ya, 0.02f); + move(xd, yd, zd); + xd *= 0.50f; + yd *= 0.50f; + zd *= 0.50f; + yd -= 0.02; + + if (horizontalCollision && isFree(xd, yd + 0.6f - y + yo, zd)) + { + yd = 0.3f; + } + } + else + { + float friction = 0.91f; + if (onGround) + { + friction = 0.6f * 0.91f; + int t = level->getTile(Mth::floor(x), Mth::floor(bb->y0) - 1, Mth::floor(z)); + if (t > 0) + { + friction = Tile::tiles[t]->friction * 0.91f; + } + } + + float friction2 = (0.6f * 0.6f * 0.91f * 0.91f * 0.6f * 0.91f) / (friction * friction * friction); + + float speed; + if (onGround) + { + speed = getSpeed() * friction2; + } + else + { + speed = flyingSpeed; + } + + moveRelative(xa, ya, speed); + + friction = 0.91f; + if (onGround) + { + friction = 0.6f * 0.91f; + int t = level->getTile( Mth::floor(x), Mth::floor(bb->y0) - 1, Mth::floor(z)); + if (t > 0) + { + friction = Tile::tiles[t]->friction * 0.91f; + } + } + if (onLadder()) + { + float max = 0.15f; + if (xd < -max) xd = -max; + if (xd > max) xd = max; + if (zd < -max) zd = -max; + if (zd > max) zd = max; + fallDistance = 0; + if (yd < -0.15) yd = -0.15; + bool playerSneaking = isSneaking() && this->instanceof(eTYPE_PLAYER); + if (playerSneaking && yd < 0) yd = 0; + } + + move(xd, yd, zd); + + if (horizontalCollision && onLadder()) + { + yd = 0.2; + } + + if (!level->isClientSide || (level->hasChunkAt((int) x, 0, (int) z) && level->getChunkAt((int) x, (int) z)->loaded)) + { + yd -= 0.08; + } + else if (y > 0) + { + yd = -0.1; + } + else + { + yd = 0; + } + + yd *= 0.98f; + xd *= friction; + zd *= friction; + } + + walkAnimSpeedO = walkAnimSpeed; + double xxd = x - xo; + double zzd = z - zo; + float wst = Mth::sqrt(xxd * xxd + zzd * zzd) * 4; + if (wst > 1) wst = 1; + walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f; + walkAnimPos += walkAnimSpeed; +} + +// 4J - added for more accurate lighting of mobs. Takes a weighted average of all tiles touched by the bounding volume of the entity - the method in the Entity class (which used to be used for +// mobs too) simply gets a single tile's lighting value causing sudden changes of lighting values when entities go in and out of lit areas, for example when bobbing in the water. +int LivingEntity::getLightColor(float a) +{ + float accum[2] = {0,0}; + float totVol = ( bb->x1 - bb->x0 ) * ( bb->y1 - bb->y0 ) * ( bb->z1 - bb->z0 ); + int xmin = Mth::floor(bb->x0); + int xmax = Mth::floor(bb->x1); + int ymin = Mth::floor(bb->y0); + int ymax = Mth::floor(bb->y1); + int zmin = Mth::floor(bb->z0); + int zmax = Mth::floor(bb->z1); + for( int xt = xmin; xt <= xmax; xt++ ) + for( int yt = ymin; yt <= ymax; yt++ ) + for( int zt = zmin; zt <= zmax; zt++ ) + { + float tilexmin = (float)xt; + float tilexmax = (float)(xt+1); + float tileymin = (float)yt; + float tileymax = (float)(yt+1); + float tilezmin = (float)zt; + float tilezmax = (float)(zt+1); + if( tilexmin < bb->x0 ) tilexmin = bb->x0; + if( tilexmax > bb->x1 ) tilexmax = bb->x1; + if( tileymin < bb->y0 ) tileymin = bb->y0; + if( tileymax > bb->y1 ) tileymax = bb->y1; + if( tilezmin < bb->z0 ) tilezmin = bb->z0; + if( tilezmax > bb->z1 ) tilezmax = bb->z1; + float tileVol = ( tilexmax - tilexmin ) * ( tileymax - tileymin ) * ( tilezmax - tilezmin ); + float frac = tileVol / totVol; + int lc = level->getLightColor(xt, yt, zt, 0); + accum[0] += frac * (float)( lc & 0xffff ); + accum[1] += frac * (float)( lc >> 16 ); + } + + if( accum[0] > 240.0f ) accum[0] = 240.0f; + if( accum[1] > 240.0f ) accum[1] = 240.0f; + + return ( ( (int)accum[1])<<16) | ((int)accum[0]); +} + +bool LivingEntity::useNewAi() +{ + return false; +} + +float LivingEntity::getSpeed() +{ + if (useNewAi()) + { + return speed; + } + else + { + return 0.1f; + } +} + +void LivingEntity::setSpeed(float speed) +{ + this->speed = speed; +} + +bool LivingEntity::doHurtTarget(shared_ptr target) +{ + setLastHurtMob(target); + return false; +} + +bool LivingEntity::isSleeping() +{ + return false; +} + +void LivingEntity::tick() +{ + Entity::tick(); + + if (!level->isClientSide) + { + int arrowCount = getArrowCount(); + if (arrowCount > 0) + { + if (removeArrowTime <= 0) + { + removeArrowTime = SharedConstants::TICKS_PER_SECOND * (30 - arrowCount); + } + removeArrowTime--; + if (removeArrowTime <= 0) + { + setArrowCount(arrowCount - 1); + } + } + + for (int i = 0; i < 5; i++) + { + shared_ptr previous = lastEquipment[i]; + shared_ptr current = getCarried(i); + + if (!ItemInstance::matches(current, previous)) + { + ((ServerLevel *) level)->getTracker()->broadcast(shared_from_this(), shared_ptr( new SetEquippedItemPacket(entityId, i, current))); + if (previous != NULL) attributes->removeItemModifiers(previous); + if (current != NULL) attributes->addItemModifiers(current); + lastEquipment[i] = current == NULL ? nullptr : current->copy(); + } + } + } + + aiStep(); + + double xd = x - xo; + double zd = z - zo; + + float sideDist = xd * xd + zd * zd; + + float yBodyRotT = yBodyRot; + + float walkSpeed = 0; + oRun = run; + float tRun = 0; + if (sideDist > 0.05f * 0.05f) + { + tRun = 1; + walkSpeed = sqrt(sideDist) * 3; + yBodyRotT = ((float) atan2(zd, xd) * 180 / (float) PI - 90); + } + if (attackAnim > 0) + { + yBodyRotT = yRot; + } + if (!onGround) + { + tRun = 0; + } + run = run + (tRun - run) * 0.3f; + + walkSpeed = tickHeadTurn(yBodyRotT, walkSpeed); + + while (yRot - yRotO < -180) + yRotO -= 360; + while (yRot - yRotO >= 180) + yRotO += 360; + + while (yBodyRot - yBodyRotO < -180) + yBodyRotO -= 360; + while (yBodyRot - yBodyRotO >= 180) + yBodyRotO += 360; + + while (xRot - xRotO < -180) + xRotO -= 360; + while (xRot - xRotO >= 180) + xRotO += 360; + + while (yHeadRot - yHeadRotO < -180) + yHeadRotO -= 360; + while (yHeadRot - yHeadRotO >= 180) + yHeadRotO += 360; + + animStep += walkSpeed; +} + +float LivingEntity::tickHeadTurn(float yBodyRotT, float walkSpeed) +{ + float yBodyRotD = Mth::wrapDegrees(yBodyRotT - yBodyRot); + yBodyRot += yBodyRotD * 0.3f; + + float headDiff = Mth::wrapDegrees(yRot - yBodyRot); + bool behind = headDiff < -90 || headDiff >= 90; + if (headDiff < -75) headDiff = -75; + if (headDiff >= 75) headDiff = +75; + yBodyRot = yRot - headDiff; + if (headDiff * headDiff > 50 * 50) + { + yBodyRot += headDiff * 0.2f; + } + + if (behind) + { + walkSpeed *= -1; + } + + return walkSpeed; +} + +void LivingEntity::aiStep() +{ + if (noJumpDelay > 0) noJumpDelay--; + if (lSteps > 0) + { + double xt = x + (lx - x) / lSteps; + double yt = y + (ly - y) / lSteps; + double zt = z + (lz - z) / lSteps; + + double yrd = Mth::wrapDegrees(lyr - yRot); + double xrd = Mth::wrapDegrees(lxr - xRot); + + yRot += (float) ( (yrd) / lSteps ); + xRot += (float) ( (xrd) / lSteps ); + + lSteps--; + setPos(xt, yt, zt); + setRot(yRot, xRot); + + // 4J - this collision is carried out to try and stop the lerping push the mob through the floor, + // in which case gravity can then carry on moving the mob because the collision just won't work anymore. + // BB for collision used to be calculated as: bb->shrink(1 / 32.0, 0, 1 / 32.0) + // now using a reduced BB to try and get rid of some issues where mobs pop up the sides of walls, undersides of + // trees etc. + AABB *shrinkbb = bb->shrink(0.1, 0, 0.1); + shrinkbb->y1 = shrinkbb->y0 + 0.1; + AABBList *collisions = level->getCubes(shared_from_this(), shrinkbb); + if (collisions->size() > 0) + { + double yTop = 0; + AUTO_VAR(itEnd, collisions->end()); + for (AUTO_VAR(it, collisions->begin()); it != itEnd; it++) + { + AABB *ab = *it; //collisions->at(i); + if (ab->y1 > yTop) yTop = ab->y1; + } + + yt += yTop - bb->y0; + setPos(xt, yt, zt); + } + } + else if (!isEffectiveAi()) + { + // slow down predicted speed, to prevent mobs from sliding through + // walls etc + xd *= .98; + yd *= .98; + zd *= .98; + } + + if (abs(xd) < MIN_MOVEMENT_DISTANCE) xd = 0; + if (abs(yd) < MIN_MOVEMENT_DISTANCE) yd = 0; + if (abs(zd) < MIN_MOVEMENT_DISTANCE) zd = 0; + + if (isImmobile()) + { + jumping = false; + xxa = 0; + yya = 0; + yRotA = 0; + } + else + { + MemSect(25); + if (isEffectiveAi()) + { + if (useNewAi()) + { + newServerAiStep(); + } + else + { + serverAiStep(); + yHeadRot = yRot; + } + } + MemSect(0); + } + + if (jumping) + { + if (isInWater() || isInLava() ) + { + yd += 0.04f; + } + else if (onGround) + { + if (noJumpDelay == 0) + { + jumpFromGround(); + noJumpDelay = 10; + } + } + } + else + { + noJumpDelay = 0; + } + + + xxa *= 0.98f; + yya *= 0.98f; + yRotA *= 0.9f; + + travel(xxa, yya); + + if(!level->isClientSide) + { + pushEntities(); + } +} + +void LivingEntity::newServerAiStep() +{ +} + +void LivingEntity::pushEntities() +{ + + vector > *entities = level->getEntities(shared_from_this(), this->bb->grow(0.2f, 0, 0.2f)); + if (entities != NULL && !entities->empty()) + { + AUTO_VAR(itEnd, entities->end()); + for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) + { + shared_ptr e = *it; //entities->at(i); + if (e->isPushable()) e->push(shared_from_this()); + } + } +} + +void LivingEntity::doPush(shared_ptr e) +{ + e->push(shared_from_this()); +} + +void LivingEntity::rideTick() +{ + Entity::rideTick(); + oRun = run; + run = 0; + fallDistance = 0; +} + +void LivingEntity::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) +{ + heightOffset = 0; + lx = x; + ly = y; + lz = z; + lyr = yRot; + lxr = xRot; + + lSteps = steps; +} + +void LivingEntity::serverAiMobStep() +{ +} + +void LivingEntity::serverAiStep() +{ + noActionTime++; +} + +void LivingEntity::setJumping(bool jump) +{ + jumping = jump; +} + +void LivingEntity::take(shared_ptr e, int orgCount) +{ + if (!e->removed && !level->isClientSide) + { + EntityTracker *entityTracker = ((ServerLevel *) level)->getTracker(); + if ( e->instanceof(eTYPE_ITEMENTITY) ) + { + entityTracker->broadcast(e, shared_ptr( new TakeItemEntityPacket(e->entityId, entityId))); + } + else if ( e->instanceof(eTYPE_ARROW) ) + { + entityTracker->broadcast(e, shared_ptr( new TakeItemEntityPacket(e->entityId, entityId))); + } + else if ( e->instanceof(eTYPE_EXPERIENCEORB) ) + { + entityTracker->broadcast(e, shared_ptr( new TakeItemEntityPacket(e->entityId, entityId))); + } + } +} + +bool LivingEntity::canSee(shared_ptr target) +{ + HitResult *hres = level->clip(Vec3::newTemp(x, y + getHeadHeight(), z), Vec3::newTemp(target->x, target->y + target->getHeadHeight(), target->z)); + bool retVal = (hres == NULL); + delete hres; + return retVal; +} + +Vec3 *LivingEntity::getLookAngle() +{ + return getViewVector(1); +} + +Vec3 *LivingEntity::getViewVector(float a) +{ + if (a == 1) + { + float yCos = Mth::cos(-yRot * Mth::RAD_TO_GRAD - PI); + float ySin = Mth::sin(-yRot * Mth::RAD_TO_GRAD - PI); + float xCos = -Mth::cos(-xRot * Mth::RAD_TO_GRAD); + float xSin = Mth::sin(-xRot * Mth::RAD_TO_GRAD); + + return Vec3::newTemp(ySin * xCos, xSin, yCos * xCos); + } + float xRot = xRotO + (this->xRot - xRotO) * a; + float yRot = yRotO + (this->yRot - yRotO) * a; + + float yCos = Mth::cos(-yRot * Mth::RAD_TO_GRAD - PI); + float ySin = Mth::sin(-yRot * Mth::RAD_TO_GRAD - PI); + float xCos = -Mth::cos(-xRot * Mth::RAD_TO_GRAD); + float xSin = Mth::sin(-xRot * Mth::RAD_TO_GRAD); + + return Vec3::newTemp(ySin * xCos, xSin, yCos * xCos); +} + +float LivingEntity::getAttackAnim(float a) +{ + float diff = attackAnim - oAttackAnim; + if (diff < 0) diff += 1; + return oAttackAnim + diff * a; +} + +Vec3 *LivingEntity::getPos(float a) +{ + if (a == 1) + { + return Vec3::newTemp(x, y, z); + } + double x = xo + (this->x - xo) * a; + double y = yo + (this->y - yo) * a; + double z = zo + (this->z - zo) * a; + + return Vec3::newTemp(x, y, z); +} + +HitResult *LivingEntity::pick(double range, float a) +{ + Vec3 *from = getPos(a); + Vec3 *b = getViewVector(a); + Vec3 *to = from->add(b->x * range, b->y * range, b->z * range); + return level->clip(from, to); +} + +bool LivingEntity::isEffectiveAi() +{ + return !level->isClientSide; +} + +bool LivingEntity::isPickable() +{ + return !removed; +} + +bool LivingEntity::isPushable() +{ + return !removed; +} + +float LivingEntity::getHeadHeight() +{ + return bbHeight * 0.85f; +} + +void LivingEntity::markHurt() +{ + hurtMarked = random->nextDouble() >= getAttribute(SharedMonsterAttributes::KNOCKBACK_RESISTANCE)->getValue(); +} + +float LivingEntity::getYHeadRot() +{ + return yHeadRot; +} + +void LivingEntity::setYHeadRot(float yHeadRot) +{ + this->yHeadRot = yHeadRot; +} + +float LivingEntity::getAbsorptionAmount() +{ + return absorptionAmount; +} + +void LivingEntity::setAbsorptionAmount(float absorptionAmount) +{ + if (absorptionAmount < 0) absorptionAmount = 0; + this->absorptionAmount = absorptionAmount; +} + +Team *LivingEntity::getTeam() +{ + return NULL; +} + +bool LivingEntity::isAlliedTo(shared_ptr other) +{ + return isAlliedTo(other->getTeam()); +} + +bool LivingEntity::isAlliedTo(Team *other) +{ + if (getTeam() != NULL) + { + return getTeam()->isAlliedTo(other); + } + return false; +} \ No newline at end of file diff --git a/Minecraft.World/LivingEntity.h b/Minecraft.World/LivingEntity.h new file mode 100644 index 00000000..5869eeb2 --- /dev/null +++ b/Minecraft.World/LivingEntity.h @@ -0,0 +1,323 @@ +#pragma once +using namespace std; + +#include "Entity.h" +#include "MobType.h" +#include "GoalSelector.h" +#include "SharedConstants.h" + +class CombatTracker; +class AttributeInstance; +class AttributeModifier; +class MobEffectInstance; +class BaseAttributeMap; +class Team; +class Attribute; +class MobEffect; +class HitResult; +class Vec3; + +class LivingEntity : public Entity +{ + friend class MobSpawner; +protected: + // 4J - added for common ctor code + void _init(); +public: + // 4J-PB - added to replace (e instanceof Type), avoiding dynamic casts + eINSTANCEOF GetType() { return eTYPE_LIVINGENTITY;} + static Entity *create(Level *level) { return NULL; } + +private: + static AttributeModifier *SPEED_MODIFIER_SPRINTING; + +public: + static const int SLOT_WEAPON = 0; + static const int SLOT_BOOTS = 1; + static const int SLOT_LEGGINGS = 2; + static const int SLOT_CHEST = 3; + static const int SLOT_HELM = 4; + + static const int SWING_DURATION = 6; + static const int PLAYER_HURT_EXPERIENCE_TIME = SharedConstants::TICKS_PER_SECOND * 5; + +private: + static const double MIN_MOVEMENT_DISTANCE; + +public: + static const int DATA_HEALTH_ID = 6; + static const int DATA_EFFECT_COLOR_ID = 7; + static const int DATA_EFFECT_AMBIENCE_ID = 8; + static const int DATA_ARROW_COUNT_ID = 9; + +private: + BaseAttributeMap *attributes; + CombatTracker *combatTracker; + unordered_map activeEffects; + ItemInstanceArray lastEquipment; + +public: + bool swinging; + int swingTime; + int removeArrowTime; + float lastHealth; + + int hurtTime; + int hurtDuration; + float hurtDir; + int deathTime; + int attackTime; + float oAttackAnim, attackAnim; + + float walkAnimSpeedO; + float walkAnimSpeed; + float walkAnimPos; + int invulnerableDuration; + float oTilt, tilt; + float timeOffs; + float rotA; + float yBodyRot, yBodyRotO; + float yHeadRot, yHeadRotO; + float flyingSpeed; + +protected: + shared_ptr lastHurtByPlayer; + int lastHurtByPlayerTime; + bool dead; + int noActionTime; + float oRun, run; + float animStep, animStepO; + float rotOffs; + int deathScore; + float lastHurt; + bool jumping; + +public: + float xxa; + float yya; + +protected: + float yRotA; + int lSteps; + double lx, ly, lz, lyr, lxr; + +private: + bool effectsDirty; + + shared_ptr lastHurtByMob; + int lastHurtByMobTimestamp; + shared_ptr lastHurtMob; + int lastHurtMobTimestamp; + + float speed; + +protected: + int noJumpDelay; + +private: + float absorptionAmount; + +public: + LivingEntity(Level* level); + virtual ~LivingEntity(); + +protected: + virtual void defineSynchedData(); + virtual void registerAttributes(); + virtual void checkFallDamage(double ya, bool onGround); + +public: + virtual bool isWaterMob(); + virtual void baseTick(); + virtual bool isBaby(); + +protected: + virtual void tickDeath(); + virtual int decreaseAirSupply(int currentSupply); + virtual int getExperienceReward(shared_ptr killedBy); + virtual bool isAlwaysExperienceDropper(); + +public: + virtual Random *getRandom(); + virtual shared_ptr getLastHurtByMob(); + virtual int getLastHurtByMobTimestamp(); + virtual void setLastHurtByMob(shared_ptr hurtBy); + virtual shared_ptr getLastHurtMob(); + virtual int getLastHurtMobTimestamp(); + virtual void setLastHurtMob(shared_ptr target); + virtual int getNoActionTime(); + virtual void addAdditonalSaveData(CompoundTag *entityTag); + virtual void readAdditionalSaveData(CompoundTag *tag); + +protected: + virtual void tickEffects(); + +public: + virtual void removeAllEffects(); + virtual vector *getActiveEffects(); + virtual bool hasEffect(int id); + virtual bool hasEffect(MobEffect *effect); + virtual MobEffectInstance *getEffect(MobEffect *effect); + virtual void addEffect(MobEffectInstance *newEffect); + virtual void addEffectNoUpdate(MobEffectInstance *newEffect); // 4J added + virtual bool canBeAffected(MobEffectInstance *newEffect); + virtual bool isInvertedHealAndHarm(); + virtual void removeEffectNoUpdate(int effectId); + virtual void removeEffect(int effectId); + +protected: + virtual void onEffectAdded(MobEffectInstance *effect); + virtual void onEffectUpdated(MobEffectInstance *effect, bool doRefreshAttributes); + virtual void onEffectRemoved(MobEffectInstance *effect); + +public: + virtual void heal(float heal); + virtual float getHealth(); + virtual void setHealth(float health); + virtual bool hurt(DamageSource *source, float dmg); + virtual void breakItem(shared_ptr itemInstance); + virtual void die(DamageSource *source); + +protected: + virtual void dropEquipment(bool byPlayer, int playerBonusLevel); + +public: + virtual void knockback(shared_ptr source, float dmg, double xd, double zd); + +protected: + virtual int getHurtSound(); + virtual int getDeathSound(); + +protected: + virtual void dropRareDeathLoot(int rareLootLevel); + virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); + +public: + virtual bool onLadder(); + virtual bool isShootable(); + virtual bool isAlive(); + virtual void causeFallDamage(float distance); + virtual void animateHurt(); + virtual int getArmorValue(); + +protected: + virtual void hurtArmor(float damage); + virtual float getDamageAfterArmorAbsorb(DamageSource *damageSource, float damage); + virtual float getDamageAfterMagicAbsorb(DamageSource *damageSource, float damage); + virtual void actuallyHurt(DamageSource *source, float dmg); + +public: + virtual CombatTracker *getCombatTracker(); + virtual shared_ptr getKillCredit(); + virtual float getMaxHealth(); + virtual int getArrowCount(); + virtual void setArrowCount(int count); + +private: + int getCurrentSwingDuration(); + +public: + virtual void swing(); + virtual void handleEntityEvent(byte id); + +protected: + virtual void outOfWorld(); + virtual void updateSwingTime(); + +public: + virtual AttributeInstance *getAttribute(Attribute *attribute); + virtual BaseAttributeMap *getAttributes(); + virtual MobType getMobType(); + + virtual shared_ptr getCarriedItem() = 0; + virtual shared_ptr getCarried(int slot) = 0; + virtual shared_ptr getArmor(int pos) = 0; + virtual void setEquippedSlot(int slot, shared_ptr item) = 0; + virtual void setSprinting(bool value); + + virtual ItemInstanceArray getEquipmentSlots() = 0; + + virtual Icon *getItemInHandIcon(shared_ptr item, int layer); + +protected: + virtual float getSoundVolume(); + virtual float getVoicePitch(); + virtual bool isImmobile(); + +public: + virtual void teleportTo(double x, double y, double z); + +protected: + virtual void findStandUpPosition(shared_ptr vehicle); + +public: + virtual bool shouldShowName(); + +protected: + virtual void jumpFromGround(); + +public: + virtual void travel(float xa, float ya); + + virtual int getLightColor(float a); // 4J - added + +protected: + virtual bool useNewAi(); + +public: + virtual float getSpeed(); + virtual void setSpeed(float speed); + virtual bool doHurtTarget(shared_ptr target); + virtual bool isSleeping(); + virtual void tick(); + +protected: + virtual float tickHeadTurn(float yBodyRotT, float walkSpeed); + +public: + virtual void aiStep(); + +protected: + virtual void newServerAiStep(); + virtual void pushEntities(); + virtual void doPush(shared_ptr e); + +public: + virtual void rideTick(); + virtual void lerpTo(double x, double y, double z, float yRot, float xRot, int steps); + +protected: + virtual void serverAiMobStep(); + virtual void serverAiStep(); + +public: + virtual void setJumping(bool jump); + virtual void take(shared_ptr e, int orgCount); + virtual bool canSee(shared_ptr target); + + +public: + virtual Vec3 *getLookAngle(); + virtual Vec3 *getViewVector(float a); + virtual float getAttackAnim(float a); + virtual Vec3 *getPos(float a); + virtual HitResult *pick(double range, float a); + virtual bool isEffectiveAi(); + + virtual bool isPickable(); + virtual bool isPushable(); + virtual float getHeadHeight(); + +protected: + virtual void markHurt(); + +public: + virtual float getYHeadRot(); + virtual void setYHeadRot(float yHeadRot); + + virtual float getAbsorptionAmount(); + virtual void setAbsorptionAmount(float absorptionAmount); + virtual Team *getTeam(); + virtual bool isAlliedTo(shared_ptr other); + virtual bool isAlliedTo(Team *other); +}; diff --git a/Minecraft.World/LocatableSource.h b/Minecraft.World/LocatableSource.h new file mode 100644 index 00000000..980a3e4b --- /dev/null +++ b/Minecraft.World/LocatableSource.h @@ -0,0 +1,8 @@ +#pragma once + +#include "Source.h" +#include "Location.h" + +class LocatableSource : public Source, public Location +{ +}; \ No newline at end of file diff --git a/Minecraft.World/Location.h b/Minecraft.World/Location.h new file mode 100644 index 00000000..d00bca7a --- /dev/null +++ b/Minecraft.World/Location.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Position.h" + +class Level; + +class Location : public Position +{ +public: + virtual Level *getWorld() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/LockedChestTile.cpp b/Minecraft.World/LockedChestTile.cpp index 774fb929..8873820e 100644 --- a/Minecraft.World/LockedChestTile.cpp +++ b/Minecraft.World/LockedChestTile.cpp @@ -13,7 +13,7 @@ bool LockedChestTile::mayPlace(Level *level, int x, int y, int z) void LockedChestTile::tick(Level *level, int x, int y, int z, Random *random) { - level->setTile(x,y,z,0); + level->removeTile(x, y, z); } void LockedChestTile::registerIcons(IconRegister *iconRegister) diff --git a/Minecraft.World/LongTag.h b/Minecraft.World/LongTag.h index 2dcd3819..8cfae41d 100644 --- a/Minecraft.World/LongTag.h +++ b/Minecraft.World/LongTag.h @@ -9,7 +9,7 @@ public: LongTag(const wstring &name, __int64 data) : Tag(name) {this->data = data; } void write(DataOutput *dos) { dos->writeLong(data); } - void load(DataInput *dis) { data = dis->readLong(); } + void load(DataInput *dis, int tagDepth) { data = dis->readLong(); } byte getId() { return TAG_Long; } wstring toString() diff --git a/Minecraft.World/LookAtPlayerGoal.cpp b/Minecraft.World/LookAtPlayerGoal.cpp index f2dc10c3..dcf1ea4f 100644 --- a/Minecraft.World/LookAtPlayerGoal.cpp +++ b/Minecraft.World/LookAtPlayerGoal.cpp @@ -9,7 +9,7 @@ LookAtPlayerGoal::LookAtPlayerGoal(Mob *mob, const type_info& lookAtType, float { this->mob = mob; this->lookDistance = lookDistance; - this->probability = 0.02f; + probability = 0.02f; setRequiredControlFlags(Control::LookControlFlag); lookTime = 0; @@ -28,8 +28,19 @@ LookAtPlayerGoal::LookAtPlayerGoal(Mob *mob, const type_info& lookAtType, float bool LookAtPlayerGoal::canUse() { if (mob->getRandom()->nextFloat() >= probability) return false; - if (lookAtType == typeid(Player)) lookAt = mob->level->getNearestPlayer(mob->shared_from_this(), lookDistance); - else lookAt = weak_ptr(mob->level->getClosestEntityOfClass(lookAtType, mob->bb->grow(lookDistance, 3, lookDistance), mob->shared_from_this())); + + if (mob->getTarget() != NULL) + { + lookAt = mob->getTarget(); + } + if (lookAtType == typeid(Player)) + { + lookAt = mob->level->getNearestPlayer(mob->shared_from_this(), lookDistance); + } + else + { + lookAt = weak_ptr(mob->level->getClosestEntityOfClass(lookAtType, mob->bb->grow(lookDistance, 3, lookDistance), mob->shared_from_this())); + } return lookAt.lock() != NULL; } diff --git a/Minecraft.World/LookControl.cpp b/Minecraft.World/LookControl.cpp index 829c3e4a..1e0d5258 100644 --- a/Minecraft.World/LookControl.cpp +++ b/Minecraft.World/LookControl.cpp @@ -15,11 +15,10 @@ LookControl::LookControl(Mob *mob) void LookControl::setLookAt(shared_ptr target, float yMax, float xMax) { - this->wantedX = target->x; - shared_ptr targetMob = dynamic_pointer_cast(target); - if (targetMob != NULL) this->wantedY = target->y + targetMob->getHeadHeight(); - else this->wantedY = (target->bb->y0 + target->bb->y1) / 2; - this->wantedZ = target->z; + wantedX = target->x; + if ( target->instanceof(eTYPE_LIVINGENTITY) ) wantedY = target->y + dynamic_pointer_cast(target)->getHeadHeight(); + else wantedY = (target->bb->y0 + target->bb->y1) / 2; + wantedZ = target->z; this->yMax = yMax; this->xMax = xMax; hasWanted = true; @@ -27,9 +26,9 @@ void LookControl::setLookAt(shared_ptr target, float yMax, float xMax) void LookControl::setLookAt(double x, double y, double z, float yMax, float xMax) { - this->wantedX = x; - this->wantedY = y; - this->wantedZ = z; + wantedX = x; + wantedY = y; + wantedZ = z; this->yMax = yMax; this->xMax = xMax; hasWanted = true; diff --git a/Minecraft.World/MakeLoveGoal.cpp b/Minecraft.World/MakeLoveGoal.cpp index 89f09f1d..c399d632 100644 --- a/Minecraft.World/MakeLoveGoal.cpp +++ b/Minecraft.World/MakeLoveGoal.cpp @@ -78,6 +78,11 @@ bool MakeLoveGoal::villageNeedsMoreVillagers() shared_ptr _village = village.lock(); if( _village == NULL ) return false; + if (!_village->isBreedTimerOk()) + { + return false; + } + int idealSize = (int) ((float) _village->getDoorCount() * 0.35); // System.out.println("idealSize: " + idealSize + " pop: " + // village.getPopulationSize()); @@ -93,9 +98,8 @@ void MakeLoveGoal::breed() // 4J - added limit to number of animals that can be bred if(level->canCreateMore( eTYPE_VILLAGER, Level::eSpawnType_Breed) ) { - shared_ptr child = shared_ptr( new Villager(level) ); + shared_ptr child = dynamic_pointer_cast( villager->getBreedOffspring(partner.lock()) ); child->setAge(-20 * 60 * 20); - child->setProfession(villager->getRandom()->nextInt(Villager::PROFESSION_MAX)); child->moveTo(villager->x, villager->y, villager->z, 0, 0); level->addEntity(child); level->broadcastEntityEvent(child, EntityEvent::LOVE_HEARTS); diff --git a/Minecraft.World/MapCloningRecipe.h b/Minecraft.World/MapCloningRecipe.h new file mode 100644 index 00000000..272f9b86 --- /dev/null +++ b/Minecraft.World/MapCloningRecipe.h @@ -0,0 +1,63 @@ +#pragma once + +/* +class MapCloningRecipe implements Recipy { + @Override + public boolean matches(CraftingContainer craftSlots, Level level) { + int count = 0; + ItemInstance source = null; + + for (int slot = 0; slot < craftSlots.getContainerSize(); slot++) { + ItemInstance item = craftSlots.getItem(slot); + if (item == null) continue; + + if (item.id == Item.map.id) { + if (source != null) return false; + source = item; + } else if (item.id == Item.emptyMap.id) { + count++; + } else { + return false; + } + } + + return source != null && count > 0; + } + + @Override + public ItemInstance assemble(CraftingContainer craftSlots) { + int count = 0; + ItemInstance source = null; + + for (int slot = 0; slot < craftSlots.getContainerSize(); slot++) { + ItemInstance item = craftSlots.getItem(slot); + if (item == null) continue; + + if (item.id == Item.map.id) { + if (source != null) return null; + source = item; + } else if (item.id == Item.emptyMap.id) { + count++; + } else { + return null; + } + } + + if (source == null || count < 1) return null; + + ItemInstance result = new ItemInstance(Item.map, count + 1, source.getAuxValue()); + if (source.hasCustomHoverName()) result.setHoverName(source.getHoverName()); + return result; + } + + @Override + public int size() { + return 9; + } + + @Override + public ItemInstance getResultItem() { + return null; + } +}; +*/ \ No newline at end of file diff --git a/Minecraft.World/MapExtendingRecipe.h b/Minecraft.World/MapExtendingRecipe.h new file mode 100644 index 00000000..40f94937 --- /dev/null +++ b/Minecraft.World/MapExtendingRecipe.h @@ -0,0 +1,46 @@ +#pragma once +/* +class MapExtendingRecipe extends ShapedRecipy { + public MapExtendingRecipe() { + super(3, 3, new ItemInstance[] { + new ItemInstance(Item.paper), new ItemInstance(Item.paper), new ItemInstance(Item.paper), + new ItemInstance(Item.paper), new ItemInstance(Item.map, 0, Recipes.ANY_AUX_VALUE), new ItemInstance(Item.paper), + new ItemInstance(Item.paper), new ItemInstance(Item.paper), new ItemInstance(Item.paper), + }, new ItemInstance(Item.emptyMap, 0, 0)); + } + + @Override + public boolean matches(CraftingContainer craftSlots, Level level) { + if (!super.matches(craftSlots, level)) return false; + ItemInstance map = null; + + for (int i = 0; i < craftSlots.getContainerSize() && map == null; i++) { + ItemInstance item = craftSlots.getItem(i); + if (item != null && item.id == Item.map.id) map = item; + } + + if (map == null) return false; + MapItemSavedData data = Item.map.getSavedData(map, level); + if (data == null) return false; + return data.scale < MapItemSavedData.MAX_SCALE; + } + + @Override + public ItemInstance assemble(CraftingContainer craftSlots) { + ItemInstance map = null; + + for (int i = 0; i < craftSlots.getContainerSize() && map == null; i++) { + ItemInstance item = craftSlots.getItem(i); + if (item != null && item.id == Item.map.id) map = item; + } + + map = map.copy(); + map.count = 1; + + if (map.getTag() == null) map.setTag(new CompoundTag()); + map.getTag().putBoolean("map_is_scaling", true); + + return map; + } +}; +*/ \ No newline at end of file diff --git a/Minecraft.World/MapItem.cpp b/Minecraft.World/MapItem.cpp index abf4fb9a..a5143257 100644 --- a/Minecraft.World/MapItem.cpp +++ b/Minecraft.World/MapItem.cpp @@ -16,7 +16,7 @@ MapItem::MapItem(int id) : ComplexItem(id) { - this->setMaxStackSize(1); + setStackedByData(true); } shared_ptr MapItem::getSavedData(short idNum, Level *level) @@ -86,7 +86,7 @@ shared_ptr MapItem::getSavedData(shared_ptr item void MapItem::update(Level *level, shared_ptr player, shared_ptr data) { - if (level->dimension->id != data->dimension) + if ( (level->dimension->id != data->dimension) || !player->instanceof(eTYPE_PLAYER) ) { // Wrong dimension, abort return; @@ -108,11 +108,12 @@ void MapItem::update(Level *level, shared_ptr player, shared_ptrstep++; + shared_ptr hp = data->getHoldingPlayer(dynamic_pointer_cast(player)); + hp->step++; for (int x = xp - rad + 1; x < xp + rad; x++) { - if ((x & 15) != (data->step & 15)) continue; + if ((x & 15) != (hp->step & 15)) continue; int yd0 = 255; int yd1 = 0; @@ -130,11 +131,6 @@ void MapItem::update(Level *level, shared_ptr player, shared_ptr player, shared_ptr> 20) & 1) == 0) count[Tile::dirt_Id] += 10; - else count[Tile::rock_Id] += 10; + else count[Tile::stone_Id] += 10; hh = 100; } else @@ -201,9 +197,6 @@ void MapItem::update(Level *level, shared_ptr player, shared_ptr itemInstance, Level *level, if (level->isClientSide) return; shared_ptr data = getSavedData(itemInstance, level); - if (dynamic_pointer_cast(owner) != NULL) + if ( owner->instanceof(eTYPE_PLAYER) ) { shared_ptr player = dynamic_pointer_cast(owner); @@ -298,6 +291,17 @@ void MapItem::inventoryTick(shared_ptr itemInstance, Level *level, } } +shared_ptr MapItem::getUpdatePacket(shared_ptr itemInstance, Level *level, shared_ptr player) +{ + charArray data = MapItem::getSavedData(itemInstance, level)->getUpdatePacket(itemInstance, level, player); + + if (data.data == NULL || data.length == 0) return nullptr; + + shared_ptr retval = shared_ptr(new ComplexItemDataPacket((short) Item::map->id, (short) itemInstance->getAuxValue(), data)); + delete data.data; + return retval; +} + void MapItem::onCraftedBy(shared_ptr itemInstance, Level *level, shared_ptr player) { wchar_t buf[64]; @@ -335,13 +339,18 @@ void MapItem::onCraftedBy(shared_ptr itemInstance, Level *level, s data->setDirty(); } -shared_ptr MapItem::getUpdatePacket(shared_ptr itemInstance, Level *level, shared_ptr player) -{ - charArray data = MapItem::getSavedData(itemInstance, level)->getUpdatePacket(itemInstance, level, player); - - if (data.data == NULL || data.length == 0) return nullptr; - - shared_ptr retval = shared_ptr(new ComplexItemDataPacket((short) Item::map->id, (short) itemInstance->getAuxValue(), data)); - delete data.data; - return retval; +// 4J - Don't want +/* +void appendHoverText(ItemInstance itemInstance, Player player, List lines, boolean advanced) { + MapItemSavedData data = getSavedData(itemInstance, player.level); + + if (advanced) { + if (data == null) { + lines.add("Unknown map"); + } else { + lines.add("Scaling at 1:" + (1 << data.scale)); + lines.add("(Level " + data.scale + "/" + MapItemSavedData.MAX_SCALE + ")"); + } + } } +*/ diff --git a/Minecraft.World/MapItem.h b/Minecraft.World/MapItem.h index dc16339d..e6b113b2 100644 --- a/Minecraft.World/MapItem.h +++ b/Minecraft.World/MapItem.h @@ -18,6 +18,6 @@ public: // 4J Stu - Was protected in Java, but then we can't access it where we shared_ptr getSavedData(shared_ptr itemInstance, Level *level); void update(Level *level, shared_ptr player, shared_ptr data); virtual void inventoryTick(shared_ptr itemInstance, Level *level, shared_ptr owner, int slot, bool selected); - virtual void onCraftedBy(shared_ptr itemInstance, Level *level, shared_ptr player); shared_ptr getUpdatePacket(shared_ptr itemInstance, Level *level, shared_ptr player); + virtual void onCraftedBy(shared_ptr itemInstance, Level *level, shared_ptr player); }; diff --git a/Minecraft.World/MapItemSavedData.cpp b/Minecraft.World/MapItemSavedData.cpp index d69a7f53..6304aa62 100644 --- a/Minecraft.World/MapItemSavedData.cpp +++ b/Minecraft.World/MapItemSavedData.cpp @@ -31,6 +31,8 @@ MapItemSavedData::HoldingPlayer::HoldingPlayer(shared_ptr player, const tick = 0; sendPosTick = 0; + step = 0; + hasSentInitial = false; // java ctor //this->player = player; @@ -50,6 +52,15 @@ MapItemSavedData::HoldingPlayer::~HoldingPlayer() charArray MapItemSavedData::HoldingPlayer::nextUpdatePacket(shared_ptr itemInstance) { + if (!hasSentInitial) + { + charArray data(2); + data[0] = HEADER_METADATA; + data[1] = parent->scale; + + hasSentInitial = true; + return data; + } if (--sendPosTick < 0) { sendPosTick = 4; @@ -128,8 +139,7 @@ charArray MapItemSavedData::HoldingPlayer::nextUpdatePacket(shared_ptr servPlayer = dynamic_pointer_cast(player); for (int d = 0; d < 10; d++) { - int column = (tick * 11) % (MapItem::IMAGE_WIDTH); - tick++; + int column = (tick++ * 11) % (MapItem::IMAGE_WIDTH); if (rowsDirtyMin[column] >= 0) { @@ -137,7 +147,7 @@ charArray MapItemSavedData::HoldingPlayer::nextUpdatePacket(shared_ptrgetInt(L"zCenter"); scale = tag->getByte(L"scale"); if (scale < 0) scale = 0; - if (scale > 4) scale = 4; + if (scale > MAX_SCALE) scale = MAX_SCALE; int width = tag->getShort(L"width"); int height = tag->getShort(L"height"); @@ -332,7 +341,7 @@ void MapItemSavedData::tickCarriedBy(shared_ptr player, shared_ptrgetFrame()->dir * 90) * 16 / 360); if (dimension < 0) { - int s = step / 10; + int s = (int) (playerLevel->getLevelData()->getDayTime() / 10); rot = (char) ((s * s * 34187121 + s * 121) >> 15 & 15); } #ifdef _LARGE_WORLDS @@ -412,7 +421,7 @@ void MapItemSavedData::tickCarriedBy(shared_ptr player, shared_ptryRot * 16 / 360 + 0.5); if (dimension < 0) { - int s = step / 10; + int s = (int) (playerLevel->getLevelData()->getDayTime() / 10); rot = (char) ((s * s * 34187121 + s * 121) >> 15 & 15); } @@ -494,7 +503,7 @@ void MapItemSavedData::setDirty(int x, int y0, int y1) void MapItemSavedData::handleComplexItemData(charArray &data) { - if (data[0] == 0) + if (data[0] == HEADER_COLOURS) { int xx = data[1] & 0xff; int yy = data[2] & 0xff; @@ -505,7 +514,7 @@ void MapItemSavedData::handleComplexItemData(charArray &data) setDirty(); } - else if (data[0] == 1) + else if (data[0] == HEADER_DECORATIONS) { for( unsigned int i = 0; i < decorations.size(); i++ ) { @@ -529,6 +538,29 @@ void MapItemSavedData::handleComplexItemData(charArray &data) decorations.push_back(new MapDecoration(img, x, y, rot, entityId, visible)); } } + else if (data[0] == HEADER_METADATA) + { + scale = data[1]; + } +} + +shared_ptr MapItemSavedData::getHoldingPlayer(shared_ptr player) +{ + shared_ptr hp = nullptr; + AUTO_VAR(it,carriedByPlayers.find(player)); + + if (it == carriedByPlayers.end()) + { + hp = shared_ptr( new HoldingPlayer(player, this) ); + carriedByPlayers[player] = hp; + carriedBy.push_back(hp); + } + else + { + hp = it->second; + } + + return hp; } // 4J Added diff --git a/Minecraft.World/MapItemSavedData.h b/Minecraft.World/MapItemSavedData.h index fcbe5e30..21322644 100644 --- a/Minecraft.World/MapItemSavedData.h +++ b/Minecraft.World/MapItemSavedData.h @@ -5,6 +5,11 @@ class MapItemSavedData : public SavedData { +private: + static const int HEADER_COLOURS = 0; + static const int HEADER_DECORATIONS = 1; + static const int HEADER_METADATA = 2; + public: static const int MAP_SIZE = 64; static const int MAX_SCALE = 4; @@ -37,6 +42,12 @@ public: int sendPosTick; charArray lastSentDecorations; + public: + int step; + + private: + bool hasSentInitial; + protected: const MapItemSavedData *parent; @@ -52,10 +63,10 @@ public: char dimension; byte scale; byteArray colors; - int step; vector > carriedBy; private: + typedef unordered_map , shared_ptr , PlayerKeyHash, PlayerKeyEq> playerHoldingPlayerMapType; playerHoldingPlayerMapType carriedByPlayers; @@ -82,6 +93,7 @@ public: using SavedData::setDirty; void setDirty(int x, int y0, int y1); void handleComplexItemData(charArray &data); + shared_ptr getHoldingPlayer(shared_ptr player); // 4J Stu Added void mergeInMapData(shared_ptr dataToAdd); diff --git a/Minecraft.World/McRegionChunkStorage.cpp b/Minecraft.World/McRegionChunkStorage.cpp index a11cb1c1..d02125a6 100644 --- a/Minecraft.World/McRegionChunkStorage.cpp +++ b/Minecraft.World/McRegionChunkStorage.cpp @@ -160,6 +160,13 @@ LevelChunk *McRegionChunkStorage::load(Level *level, int x, int z) #endif delete chunkData; } +#ifndef _CONTENT_PACKAGE + if(levelChunk && app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<reloadBiomes(); + } +#endif return levelChunk; } diff --git a/Minecraft.World/MegaTreeFeature.cpp b/Minecraft.World/MegaTreeFeature.cpp index 77e06e30..09195fb4 100644 --- a/Minecraft.World/MegaTreeFeature.cpp +++ b/Minecraft.World/MegaTreeFeature.cpp @@ -55,10 +55,10 @@ bool MegaTreeFeature::place(Level *level, Random *random, int x, int y, int z) int belowTile = level->getTile(x, y - 1, z); if ((belowTile != Tile::grass_Id && belowTile != Tile::dirt_Id) || y >= Level::maxBuildHeight - treeHeight - 1) return false; - level->setTileNoUpdate(x, y - 1, z, Tile::dirt_Id); - level->setTileNoUpdate(x + 1, y - 1, z, Tile::dirt_Id); - level->setTileNoUpdate(x, y - 1, z + 1, Tile::dirt_Id); - level->setTileNoUpdate(x + 1, y - 1, z + 1, Tile::dirt_Id); + level->setTileAndData(x, y - 1, z, Tile::dirt_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + 1, y - 1, z, Tile::dirt_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z + 1, Tile::dirt_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + 1, y - 1, z + 1, Tile::dirt_Id, 0, Tile::UPDATE_CLIENTS); PIXBeginNamedEvent(0,"MegaTree placing leaves, %d, %d, %d", x, z, y+treeHeight); placeLeaves(level, x, z, y + treeHeight, 2, random); @@ -189,7 +189,7 @@ void MegaTreeFeature::placeLeaves(Level *level, int x, int z, int topPosition, i PIXBeginNamedEvent(0,"Getting tile"); int t = level->getTile(xx, yy, zz); PIXEndNamedEvent(); - if (!Tile::solid[t]) + if (t == 0 || t == Tile::leaves_Id) { PIXBeginNamedEvent(0,"Placing block"); placeBlock(level, xx, yy, zz, Tile::leaves_Id, leafType); diff --git a/Minecraft.World/MeleeAttackGoal.cpp b/Minecraft.World/MeleeAttackGoal.cpp index f3aa6455..7003609e 100644 --- a/Minecraft.World/MeleeAttackGoal.cpp +++ b/Minecraft.World/MeleeAttackGoal.cpp @@ -8,12 +8,12 @@ #include "net.minecraft.world.phys.h" #include "MeleeAttackGoal.h" -void MeleeAttackGoal::_init(Mob *mob, float speed, bool trackTarget) +void MeleeAttackGoal::_init(PathfinderMob *mob, double speedModifier, bool trackTarget) { this->attackType = eTYPE_NOTSET; this->mob = mob; - this->level = mob->level; - this->speed = speed; + level = mob->level; + this->speedModifier = speedModifier; this->trackTarget = trackTarget; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); @@ -23,15 +23,15 @@ void MeleeAttackGoal::_init(Mob *mob, float speed, bool trackTarget) timeToRecalcPath = 0; } -MeleeAttackGoal::MeleeAttackGoal(Mob *mob, eINSTANCEOF attackType, float speed, bool trackTarget) +MeleeAttackGoal::MeleeAttackGoal(PathfinderMob *mob, eINSTANCEOF attackType, double speedModifier, bool trackTarget) { - _init(mob, speed, trackTarget); + _init(mob, speedModifier, trackTarget); this->attackType = attackType; } -MeleeAttackGoal::MeleeAttackGoal(Mob *mob, float speed, bool trackTarget) +MeleeAttackGoal::MeleeAttackGoal(PathfinderMob *mob, double speedModifier, bool trackTarget) { - _init(mob,speed,trackTarget); + _init(mob,speedModifier,trackTarget); } MeleeAttackGoal::~MeleeAttackGoal() @@ -41,56 +41,56 @@ MeleeAttackGoal::~MeleeAttackGoal() bool MeleeAttackGoal::canUse() { - shared_ptr bestTarget = mob->getTarget(); - if (bestTarget == NULL) return false; - if(!bestTarget->isAlive()) return false; - if (attackType != eTYPE_NOTSET && (attackType & bestTarget->GetType()) != attackType) return false; - target = weak_ptr(bestTarget); + shared_ptr target = mob->getTarget(); + if (target == NULL) return false; + if (!target->isAlive()) return false; + if (attackType != NULL && !target->instanceof(attackType)) return false; delete path; - path = mob->getNavigation()->createPath(target.lock()); + path = mob->getNavigation()->createPath(target); return path != NULL; } bool MeleeAttackGoal::canContinueToUse() { - shared_ptr bestTarget = mob->getTarget(); - if (bestTarget == NULL) return false; - if (target.lock() == NULL || !target.lock()->isAlive()) return false; + shared_ptr target = mob->getTarget(); + if (target == NULL) return false; + if (!target->isAlive()) return false; if (!trackTarget) return !mob->getNavigation()->isDone(); - if (!mob->isWithinRestriction(Mth::floor(target.lock()->x), Mth::floor(target.lock()->y), Mth::floor(target.lock()->z))) return false; + if (!mob->isWithinRestriction(Mth::floor(target->x), Mth::floor(target->y), Mth::floor(target->z))) return false; return true; } void MeleeAttackGoal::start() { - mob->getNavigation()->moveTo(path, speed); + mob->getNavigation()->moveTo(path, speedModifier); path = NULL; timeToRecalcPath = 0; } void MeleeAttackGoal::stop() { - target = weak_ptr(); mob->getNavigation()->stop(); } void MeleeAttackGoal::tick() { - mob->getLookControl()->setLookAt(target.lock(), 30, 30); - if (trackTarget || mob->getSensing()->canSee(target.lock())) + shared_ptr target = mob->getTarget(); + mob->getLookControl()->setLookAt(target, 30, 30); + if (trackTarget || mob->getSensing()->canSee(target)) { if (--timeToRecalcPath <= 0) { timeToRecalcPath = 4 + mob->getRandom()->nextInt(7); - mob->getNavigation()->moveTo(target.lock(), speed); + mob->getNavigation()->moveTo(target, speedModifier); } } attackTime = max(attackTime - 1, 0); - double meleeRadiusSqr = (mob->bbWidth * 2) * (mob->bbWidth * 2); - if (mob->distanceToSqr(target.lock()->x, target.lock()->bb->y0, target.lock()->z) > meleeRadiusSqr) return; + double meleeRadiusSqr = (mob->bbWidth * 2) * (mob->bbWidth * 2) + target->bbWidth; + if (mob->distanceToSqr(target->x, target->bb->y0, target->z) > meleeRadiusSqr) return; if (attackTime > 0) return; attackTime = 20; - mob->doHurtTarget(target.lock()); + if (mob->getCarriedItem() != NULL) mob->swing(); + mob->doHurtTarget(target); } diff --git a/Minecraft.World/MeleeAttackGoal.h b/Minecraft.World/MeleeAttackGoal.h index c8f5e19d..dd6b1958 100644 --- a/Minecraft.World/MeleeAttackGoal.h +++ b/Minecraft.World/MeleeAttackGoal.h @@ -3,28 +3,26 @@ #include "Goal.h" class Level; -class Mob; +class PathfinderMob; class Path; class MeleeAttackGoal : public Goal { private: Level *level; - Mob *mob; // Owner of this goal - weak_ptr target; - + PathfinderMob *mob; // Owner of this goal int attackTime; - float speed; + double speedModifier; bool trackTarget; Path *path; eINSTANCEOF attackType; int timeToRecalcPath; - void _init(Mob *mob, float speed, bool trackTarget); + void _init(PathfinderMob *mob, double speedModifier, bool trackTarget); public: - MeleeAttackGoal(Mob *mob, eINSTANCEOF attackType, float speed, bool trackTarget); - MeleeAttackGoal(Mob *mob, float speed, bool trackTarget); + MeleeAttackGoal(PathfinderMob *mob, eINSTANCEOF attackType, double speedModifier, bool trackTarget); + MeleeAttackGoal(PathfinderMob *mob, double speedModifier, bool trackTarget); ~MeleeAttackGoal(); virtual bool canUse(); diff --git a/Minecraft.World/MelonTile.cpp b/Minecraft.World/MelonTile.cpp index 881eadc2..298ae61f 100644 --- a/Minecraft.World/MelonTile.cpp +++ b/Minecraft.World/MelonTile.cpp @@ -4,9 +4,6 @@ #include "net.minecraft.world.h" #include "Facing.h" -const wstring MelonTile::TEX = L"melon_side"; -const wstring MelonTile::TEX_TOP = L"melon_top"; - MelonTile::MelonTile(int id) : Tile(id, Material::vegetable) { iconTop = NULL; @@ -40,6 +37,6 @@ int MelonTile::getResourceCountForLootBonus(int bonusLevel, Random *random) void MelonTile::registerIcons(IconRegister *iconRegister) { - icon = iconRegister->registerIcon(TEX); - iconTop = iconRegister->registerIcon(TEX_TOP); + icon = iconRegister->registerIcon(getIconName() + L"_side"); + iconTop = iconRegister->registerIcon(getIconName() + L"_top"); } \ No newline at end of file diff --git a/Minecraft.World/MelonTile.h b/Minecraft.World/MelonTile.h index 029cb1cb..1b3d1a35 100644 --- a/Minecraft.World/MelonTile.h +++ b/Minecraft.World/MelonTile.h @@ -6,19 +6,16 @@ class MelonTile : public Tile { friend class ChunkRebuildData; private: - static const wstring TEX; - static const wstring TEX_TOP; - Icon *iconTop; // 4J Stu - I don't know why this is protected in Java -//protected: + //protected: public: MelonTile(int id); public: virtual Icon *getTexture(int face, int data); - virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual int getResourceCount(Random *random); + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual int getResourceCount(Random *random); virtual int getResourceCountForLootBonus(int bonusLevel, Random *random); void registerIcons(IconRegister *iconRegister); }; \ No newline at end of file diff --git a/Minecraft.World/MenuBackup.cpp b/Minecraft.World/MenuBackup.cpp index 6d09f3e3..b6d3ba09 100644 --- a/Minecraft.World/MenuBackup.cpp +++ b/Minecraft.World/MenuBackup.cpp @@ -15,11 +15,11 @@ MenuBackup::MenuBackup(shared_ptr inventory, AbstractContainerMenu *m void MenuBackup::save(short changeUid) { - ItemInstanceArray *backup = new ItemInstanceArray( (int)menu->slots->size() + 1 ); + ItemInstanceArray *backup = new ItemInstanceArray( (int)menu->slots.size() + 1 ); (*backup)[0] = ItemInstance::clone(inventory->getCarried()); - for (unsigned int i = 0; i < menu->slots->size(); i++) + for (unsigned int i = 0; i < menu->slots.size(); i++) { - (*backup)[i + 1] = ItemInstance::clone(menu->slots->at(i)->getItem()); + (*backup)[i + 1] = ItemInstance::clone(menu->slots.at(i)->getItem()); } // TODO Is unordered_map use correct? // Was backups.put(changeUid, backup); @@ -39,9 +39,9 @@ void MenuBackup::rollback(short changeUid) ItemInstanceArray *backup = backups->at(changeUid); backups->clear(); inventory->setCarried( (*backup)[0] ); - for (unsigned int i = 0; i < menu->slots->size(); i++) + for (unsigned int i = 0; i < menu->slots.size(); i++) { - menu->slots->at(i)->set( (*backup)[i + 1] ); + menu->slots.at(i)->set( (*backup)[i + 1] ); } } \ No newline at end of file diff --git a/Minecraft.World/Merchant.h b/Minecraft.World/Merchant.h index 8b4b7a69..f47e2acb 100644 --- a/Minecraft.World/Merchant.h +++ b/Minecraft.World/Merchant.h @@ -13,5 +13,5 @@ public: virtual void overrideOffers(MerchantRecipeList *recipeList) = 0; virtual void notifyTrade(MerchantRecipe *activeRecipe) = 0; virtual void notifyTradeUpdated(shared_ptr item) = 0; - virtual int getDisplayName() = 0; + virtual wstring getDisplayName() = 0; }; \ No newline at end of file diff --git a/Minecraft.World/MerchantContainer.cpp b/Minecraft.World/MerchantContainer.cpp index cadbe4e3..cd3fde5e 100644 --- a/Minecraft.World/MerchantContainer.cpp +++ b/Minecraft.World/MerchantContainer.cpp @@ -90,11 +90,21 @@ void MerchantContainer::setItem(unsigned int slot, shared_ptr item } } -int MerchantContainer::getName() +wstring MerchantContainer::getName() { return merchant->getDisplayName(); } +wstring MerchantContainer::getCustomName() +{ + return L""; +} + +bool MerchantContainer::hasCustomName() +{ + return false; +} + int MerchantContainer::getMaxStackSize() { return Container::LARGE_MAX_STACK_SIZE; @@ -113,6 +123,11 @@ void MerchantContainer::stopOpen() { } +bool MerchantContainer::canPlaceItem(int slot, shared_ptr item) +{ + return true; +} + void MerchantContainer::setChanged() { updateSellItem(); diff --git a/Minecraft.World/MerchantContainer.h b/Minecraft.World/MerchantContainer.h index efba13d6..91893c1b 100644 --- a/Minecraft.World/MerchantContainer.h +++ b/Minecraft.World/MerchantContainer.h @@ -30,11 +30,14 @@ private: public: shared_ptr removeItemNoUpdate(int slot); void setItem(unsigned int slot, shared_ptr item); - int getName(); + wstring getName(); + wstring getCustomName(); + bool hasCustomName(); int getMaxStackSize(); bool stillValid(shared_ptr player); void startOpen(); void stopOpen(); + bool canPlaceItem(int slot, shared_ptr item); void setChanged(); void updateSellItem(); MerchantRecipe *getActiveRecipe(); diff --git a/Minecraft.World/MerchantMenu.cpp b/Minecraft.World/MerchantMenu.cpp index a6dfca1f..52ce34f9 100644 --- a/Minecraft.World/MerchantMenu.cpp +++ b/Minecraft.World/MerchantMenu.cpp @@ -69,7 +69,7 @@ shared_ptr MerchantMenu::quickMoveStack(shared_ptr player, shared_ptr clicked = nullptr; Slot *slot = NULL; - if(slotIndex < slots->size()) slot = slots->at(slotIndex); + if(slotIndex < slots.size()) slot = slots.at(slotIndex); if (slot != NULL && slot->hasItem()) { shared_ptr stack = slot->getItem(); diff --git a/Minecraft.World/MineShaftFeature.cpp b/Minecraft.World/MineShaftFeature.cpp index ac4d0c3f..78178de0 100644 --- a/Minecraft.World/MineShaftFeature.cpp +++ b/Minecraft.World/MineShaftFeature.cpp @@ -1,6 +1,32 @@ #include "stdafx.h" #include "net.minecraft.world.level.levelgen.structure.h" #include "JavaMath.h" +#include "Mth.h" + +const wstring MineShaftFeature::OPTION_CHANCE = L"chance"; + +MineShaftFeature::MineShaftFeature() +{ + chance = 0.01; +} + +wstring MineShaftFeature::getFeatureName() +{ + return L"Mineshaft"; +} + +MineShaftFeature::MineShaftFeature(unordered_map options) +{ + chance = 0.01; + + for(AUTO_VAR(it,options.begin()); it != options.end(); ++it) + { + if (it->first.compare(OPTION_CHANCE) == 0) + { + chance = Mth::getDouble(it->second, chance); + } + } +} bool MineShaftFeature::isFeatureChunk(int x, int z, bool bIsSuperflat) { @@ -11,7 +37,7 @@ bool MineShaftFeature::isFeatureChunk(int x, int z, bool bIsSuperflat) forcePlacement = levelGenOptions->isFeatureChunk(x,z,eFeature_Mineshaft); } - return forcePlacement || (random->nextInt(100) == 0 && random->nextInt(80) < max(abs(x), abs(z))); + return forcePlacement || (random->nextDouble() < chance && random->nextInt(80) < max(abs(x), abs(z))); } StructureStart *MineShaftFeature::createStructureStart(int x, int z) diff --git a/Minecraft.World/MineShaftFeature.h b/Minecraft.World/MineShaftFeature.h index 698010ec..cec786c6 100644 --- a/Minecraft.World/MineShaftFeature.h +++ b/Minecraft.World/MineShaftFeature.h @@ -4,6 +4,19 @@ class MineShaftFeature : public StructureFeature { +public: + static const wstring OPTION_CHANCE; + +private: + double chance; + +public: + MineShaftFeature(); + + wstring getFeatureName(); + + MineShaftFeature(unordered_map options); + protected: virtual bool isFeatureChunk(int x, int z, bool bIsSuperflat=false); virtual StructureStart *createStructureStart(int x, int z); diff --git a/Minecraft.World/MineShaftPieces.cpp b/Minecraft.World/MineShaftPieces.cpp index fe13b49f..844514dc 100644 --- a/Minecraft.World/MineShaftPieces.cpp +++ b/Minecraft.World/MineShaftPieces.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.level.levelgen.structure.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" @@ -12,7 +13,7 @@ WeighedTreasureArray MineShaftPieces::smallTreasureItems;; void MineShaftPieces::staticCtor() { - smallTreasureItems = WeighedTreasureArray(11); + smallTreasureItems = WeighedTreasureArray(13); smallTreasureItems[0] = new WeighedTreasure(Item::ironIngot_Id, 0, 1, 5, 10); smallTreasureItems[1] = new WeighedTreasure(Item::goldIngot_Id, 0, 1, 3, 5); smallTreasureItems[2] = new WeighedTreasure(Item::redStone_Id, 0, 4, 9, 5); @@ -23,8 +24,18 @@ void MineShaftPieces::staticCtor() smallTreasureItems[7] = new WeighedTreasure(Item::pickAxe_iron_Id, 0, 1, 1, 1); smallTreasureItems[8] = new WeighedTreasure(Tile::rail_Id, 0, 4, 8, 1); smallTreasureItems[9] = new WeighedTreasure(Item::seeds_melon_Id, 0, 2, 4, 10); - // 4J-PB - Adding from 1.2.3 smallTreasureItems[10] = new WeighedTreasure(Item::seeds_pumpkin_Id, 0, 2, 4, 10); + // very rare for shafts ... + smallTreasureItems[11] = new WeighedTreasure(Item::saddle_Id, 0, 1, 1, 3); + smallTreasureItems[12] = new WeighedTreasure(Item::horseArmorMetal_Id, 0, 1, 1, 1); +} + +void MineShaftPieces::loadStatic() +{ + StructureFeatureIO::setPieceId( eStructurePiece_MineShaftCorridor, MineShaftCorridor::Create, L"MSCorridor"); + StructureFeatureIO::setPieceId( eStructurePiece_MineShaftCrossing, MineShaftCrossing::Create, L"MSCrossing"); + StructureFeatureIO::setPieceId( eStructurePiece_MineShaftRoom, MineShaftRoom::Create, L"MSRoom"); + StructureFeatureIO::setPieceId( eStructurePiece_MineShaftStairs, MineShaftStairs::Create, L"MSStairs"); } StructurePiece *MineShaftPieces::createRandomShaftPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) @@ -80,6 +91,10 @@ StructurePiece *MineShaftPieces::generateAndAddPiece(StructurePiece *startPiece, return newPiece; } +MineShaftPieces::MineShaftRoom::MineShaftRoom() +{ + // for reflection +} MineShaftPieces::MineShaftRoom::MineShaftRoom(int genDepth, Random *random, int west, int north) : StructurePiece(genDepth) { @@ -199,6 +214,46 @@ bool MineShaftPieces::MineShaftRoom::postProcess(Level *level, Random *random, B return true; } +void MineShaftPieces::MineShaftRoom::addAdditonalSaveData(CompoundTag *tag) +{ + ListTag *entrances = new ListTag(L"Entrances"); + for (AUTO_VAR(it,childEntranceBoxes.begin()); it != childEntranceBoxes.end(); ++it) + { + BoundingBox *bb =*it; + entrances->add(bb->createTag(L"")); + } + tag->put(L"Entrances", entrances); +} + +void MineShaftPieces::MineShaftRoom::readAdditonalSaveData(CompoundTag *tag) +{ + ListTag *entrances = (ListTag *) tag->getList(L"Entrances"); + for (int i = 0; i < entrances->size(); i++) + { + childEntranceBoxes.push_back(new BoundingBox(entrances->get(i)->data)); + } +} + +MineShaftPieces::MineShaftCorridor::MineShaftCorridor() +{ + // for reflection +} + +void MineShaftPieces::MineShaftCorridor::addAdditonalSaveData(CompoundTag *tag) +{ + tag->putBoolean(L"hr", hasRails); + tag->putBoolean(L"sc", spiderCorridor); + tag->putBoolean(L"hps", hasPlacedSpider); + tag->putInt(L"Num", numSections); +} + +void MineShaftPieces::MineShaftCorridor::readAdditonalSaveData(CompoundTag *tag) +{ + hasRails = tag->getBoolean(L"hr"); + spiderCorridor = tag->getBoolean(L"sc"); + hasPlacedSpider = tag->getBoolean(L"hps"); + numSections = tag->getInt(L"Num"); +} MineShaftPieces::MineShaftCorridor::MineShaftCorridor(int genDepth, Random *random, BoundingBox *corridorBox, int direction) : StructurePiece(genDepth) @@ -370,6 +425,27 @@ void MineShaftPieces::MineShaftCorridor::addChildren(StructurePiece *startPiece, } } +bool MineShaftPieces::MineShaftCorridor::createChest(Level *level, BoundingBox *chunkBB, Random *random, int x, int y, int z, WeighedTreasureArray treasure, int numRolls) +{ + int worldX = getWorldX(x, z); + int worldY = getWorldY(y); + int worldZ = getWorldZ(x, z); + + if (chunkBB->isInside(worldX, worldY, worldZ)) + { + if (level->getTile(worldX, worldY, worldZ) == 0) + { + level->setTileAndData(worldX, worldY, worldZ, Tile::rail_Id, getOrientationData(Tile::rail_Id, random->nextBoolean() ? RailTile::DIR_FLAT_X : RailTile::DIR_FLAT_Z), Tile::UPDATE_CLIENTS); + shared_ptr chest = shared_ptr( new MinecartChest(level, worldX + 0.5f, worldY + 0.5f, worldZ + 0.5f) ); + WeighedTreasure::addChestItems(random, treasure, chest, numRolls); + level->addEntity(chest); + return true; + } + } + + return false; +} + bool MineShaftPieces::MineShaftCorridor::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (edgesLiquid(level, chunkBB)) @@ -439,9 +515,9 @@ bool MineShaftPieces::MineShaftCorridor::postProcess(Level *level, Random *rando if (chunkBB->isInside(x, y, newZ)) { hasPlacedSpider = true; - level->setTile(x, y, newZ, Tile::mobSpawner_Id); + level->setTileAndData(x, y, newZ, Tile::mobSpawner_Id, 0, Tile::UPDATE_CLIENTS); shared_ptr entity = dynamic_pointer_cast( level->getTileEntity(x, y, newZ) ); - if (entity != NULL) entity->setEntityId(L"CaveSpider"); + if (entity != NULL) entity->getSpawner()->setEntityId(L"CaveSpider"); } } } @@ -466,7 +542,7 @@ bool MineShaftPieces::MineShaftCorridor::postProcess(Level *level, Random *rando int floor = getBlock(level, x0 + 1, y0 - 1, z, chunkBB); if (floor > 0 && Tile::solid[floor]) { - maybeGenerateBlock(level, chunkBB, random, .7f, x0 + 1, y0, z, Tile::rail_Id, getOrientationData(Tile::rail_Id, RailTile::DIR_FLAT_Z)); + maybeGenerateBlock(level, chunkBB, random, .7f, x0 + 1, y0, z, Tile::rail_Id, getOrientationData(Tile::rail_Id, BaseRailTile::DIR_FLAT_Z)); } } } @@ -474,6 +550,23 @@ bool MineShaftPieces::MineShaftCorridor::postProcess(Level *level, Random *rando return true; } +MineShaftPieces::MineShaftCrossing::MineShaftCrossing() +{ + // for reflection +} + +void MineShaftPieces::MineShaftCrossing::addAdditonalSaveData(CompoundTag *tag) +{ + tag->putBoolean(L"tf", isTwoFloored); + tag->putInt(L"D", direction); +} + +void MineShaftPieces::MineShaftCrossing::readAdditonalSaveData(CompoundTag *tag) +{ + isTwoFloored = tag->getBoolean(L"tf"); + direction = tag->getInt(L"D"); +} + MineShaftPieces::MineShaftCrossing::MineShaftCrossing(int genDepth, Random *random, BoundingBox *crossingBox, int direction) : StructurePiece(genDepth), direction(direction), isTwoFloored( crossingBox->getYSpan() > DEFAULT_SHAFT_HEIGHT ) { @@ -609,6 +702,10 @@ bool MineShaftPieces::MineShaftCrossing::postProcess(Level *level, Random *rando return true; } +MineShaftPieces::MineShaftStairs::MineShaftStairs() +{ + // for reflection +} MineShaftPieces::MineShaftStairs::MineShaftStairs(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StructurePiece(genDepth) { @@ -616,6 +713,15 @@ MineShaftPieces::MineShaftStairs::MineShaftStairs(int genDepth, Random *random, boundingBox = stairsBox; } + +void MineShaftPieces::MineShaftStairs::addAdditonalSaveData(CompoundTag *tag) +{ +} + +void MineShaftPieces::MineShaftStairs::readAdditonalSaveData(CompoundTag *tag) +{ +} + BoundingBox *MineShaftPieces::MineShaftStairs::findStairs(list *pieces, Random *random, int footX, int footY, int footZ, int direction) { // stairs are two steps in, 5x5 steps down, two steps out diff --git a/Minecraft.World/MineShaftPieces.h b/Minecraft.World/MineShaftPieces.h index 5f9cf000..c2278467 100644 --- a/Minecraft.World/MineShaftPieces.h +++ b/Minecraft.World/MineShaftPieces.h @@ -11,6 +11,10 @@ private: static const int MAX_DEPTH = 8; // 1.2.3 change +public: + static void loadStatic(); + +private: static StructurePiece *createRandomShaftPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); static StructurePiece *generateAndAddPiece(StructurePiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth); @@ -21,15 +25,24 @@ private: public: class MineShaftRoom : public StructurePiece { + public: + static StructurePiece *Create() { return new MineShaftRoom(); } + virtual EStructurePiece GetType() { return eStructurePiece_MineShaftRoom; } + private: list childEntranceBoxes; public: + MineShaftRoom(); MineShaftRoom(int genDepth, Random *random, int west, int north); ~MineShaftRoom(); virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + + protected: + void addAdditonalSaveData(CompoundTag *tag); + void readAdditonalSaveData(CompoundTag *tag); }; /** @@ -38,17 +51,33 @@ public: */ class MineShaftCorridor : public StructurePiece { + public: + static StructurePiece *Create() { return new MineShaftCorridor(); } + virtual EStructurePiece GetType() { return eStructurePiece_MineShaftCorridor; } + private: bool hasRails; // was final bool spiderCorridor; // was final bool hasPlacedSpider; int numSections; + public: + MineShaftCorridor(); + + protected: + void addAdditonalSaveData(CompoundTag *tag); + void readAdditonalSaveData(CompoundTag *tag); + public: MineShaftCorridor(int genDepth, Random *random, BoundingBox *corridorBox, int direction); static BoundingBox *findCorridorSize(list *pieces, Random *random, int footX, int footY, int footZ, int direction); virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + + protected: + virtual bool createChest(Level *level, BoundingBox *chunkBB, Random *random, int x, int y, int z, WeighedTreasureArray treasure, int numRolls); + + public: virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); }; @@ -58,9 +87,20 @@ public: */ class MineShaftCrossing : public StructurePiece { + public: + static StructurePiece *Create() { return new MineShaftCrossing(); } + virtual EStructurePiece GetType() { return eStructurePiece_MineShaftCrossing; } + private: - const int direction; - const bool isTwoFloored; + int direction; + bool isTwoFloored; + + public: + MineShaftCrossing(); + + protected: + void addAdditonalSaveData(CompoundTag *tag); + void readAdditonalSaveData(CompoundTag *tag); public: MineShaftCrossing(int genDepth, Random *random, BoundingBox *crossingBox, int direction); @@ -77,8 +117,18 @@ public: class MineShaftStairs : public StructurePiece { public: + static StructurePiece *Create() { return new MineShaftStairs(); } + virtual EStructurePiece GetType() { return eStructurePiece_MineShaftStairs; } + + public: + MineShaftStairs(); MineShaftStairs(int genDepth, Random *random, BoundingBox *stairsBox, int direction); + protected: + void addAdditonalSaveData(CompoundTag *tag); + void readAdditonalSaveData(CompoundTag *tag); + + public: static BoundingBox *findStairs(list *pieces, Random *random, int footX, int footY, int footZ, int direction); virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); diff --git a/Minecraft.World/MineShaftStart.cpp b/Minecraft.World/MineShaftStart.cpp index badd3a04..eaf9f7c8 100644 --- a/Minecraft.World/MineShaftStart.cpp +++ b/Minecraft.World/MineShaftStart.cpp @@ -1,7 +1,12 @@ #include "stdafx.h" #include "net.minecraft.world.level.levelgen.structure.h" -MineShaftStart::MineShaftStart(Level *level, Random *random, int chunkX, int chunkZ) +MineShaftStart::MineShaftStart() +{ + // for reflection +} + +MineShaftStart::MineShaftStart(Level *level, Random *random, int chunkX, int chunkZ) : StructureStart(chunkX, chunkZ) { MineShaftPieces::MineShaftRoom *mineShaftRoom = new MineShaftPieces::MineShaftRoom(0, random, (chunkX << 4) + 2, (chunkZ << 4) + 2); pieces.push_back(mineShaftRoom); diff --git a/Minecraft.World/MineShaftStart.h b/Minecraft.World/MineShaftStart.h index b46e3d67..7afb9b62 100644 --- a/Minecraft.World/MineShaftStart.h +++ b/Minecraft.World/MineShaftStart.h @@ -5,5 +5,10 @@ class MineShaftStart : public StructureStart { public: + static StructureStart *Create() { return new MineShaftStart(); } + virtual EStructureStart GetType() { return eStructureStart_MineShaftStart; } + +public: + MineShaftStart(); MineShaftStart(Level *level, Random *random, int chunkX, int chunkZ); }; \ No newline at end of file diff --git a/Minecraft.World/Minecart.cpp b/Minecraft.World/Minecart.cpp index 2b8fbb95..48787f55 100644 --- a/Minecraft.World/Minecart.cpp +++ b/Minecraft.World/Minecart.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "net.minecraft.world.level.dimension.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" @@ -8,6 +9,8 @@ #include "net.minecraft.world.entity.animal.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.damagesource.h" +#include "..\Minecraft.Client\MinecraftServer.h" +#include "..\Minecraft.Client\ServerLevel.h" #include "com.mojang.nbt.h" #include "Minecart.h" #include "SharedConstants.h" @@ -16,89 +19,23 @@ const int Minecart::EXITS[][2][3] = { // // - { - { - +0, +0, -1 - }, { - +0, +0, +1 - } - }, // 0 - { - { - -1, +0, +0 - }, { - +1, +0, +0 - } - }, // 1 - { - { - -1, -1, +0 - }, { - +1, +0, +0 - } - }, // 2 - { - { - -1, +0, +0 - }, { - +1, -1, +0 - } - }, // 3 - { - { - +0, +0, -1 - }, { - +0, -1, +1 - } - }, // 4 - { - { - +0, -1, -1 - }, { - +0, +0, +1 - } - }, // 5 - - { - { - +0, +0, +1 - }, { - +1, +0, +0 - } - }, // 6 - { - { - +0, +0, +1 - }, { - -1, +0, +0 - } - }, // 7 - { - { - +0, +0, -1 - }, { - -1, +0, +0 - } - }, // 8 - { - { - +0, +0, -1 - }, { - +1, +0, +0 - } - }, // 9 + {{+0, +0, -1}, {+0, +0, +1}}, // 0 + {{-1, +0, +0}, {+1, +0, +0}}, // 1 + {{-1, -1, +0}, {+1, +0, +0}}, // 2 + {{-1, +0, +0}, {+1, -1, +0}}, // 3 + {{+0, +0, -1}, {+0, -1, +1}}, // 4 + {{+0, -1, -1}, {+0, +0, +1}}, // 5 + + {{+0, +0, +1}, {+1, +0, +0}}, // 6 + {{+0, +0, +1}, {-1, +0, +0}}, // 7 + {{+0, +0, -1}, {-1, +0, +0}}, // 8 + {{+0, +0, -1}, {+1, +0, +0}}, // 9 }; void Minecart::_init() { - // 4J TODO This gets replaced again later so should maybe be inited as NULL? - items = new ItemInstanceArray(9 * 4); - flipped = false; - type = fuel = 0; - xPush = zPush = 0.0; - lSteps = 0; lx = ly = lz = lyr = lxr = 0.0; lxd = lyd = lzd = 0.0; @@ -107,6 +44,8 @@ void Minecart::_init() blocksBuilding = true; setSize(0.98f, 0.7f); heightOffset = bbHeight / 2.0f; + soundUpdater = NULL; + name = L""; // // 4J Added @@ -115,13 +54,34 @@ void Minecart::_init() Minecart::Minecart(Level *level) : Entity( level ) { - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that - // the derived version of the function is called - this->defineSynchedData(); - _init(); + + //soundUpdater = level != NULL ? level->makeSoundUpdater(this) : NULL; } +Minecart::~Minecart() +{ + delete soundUpdater; +} + +shared_ptr Minecart::createMinecart(Level *level, double x, double y, double z, int type) +{ + switch (type) + { + case TYPE_CHEST: + return shared_ptr( new MinecartChest(level, x, y, z) ); + case TYPE_FURNACE: + return shared_ptr( new MinecartFurnace(level, x, y, z) ); + case TYPE_TNT: + return shared_ptr( new MinecartTNT(level, x, y, z) ); + case TYPE_SPAWNER: + return shared_ptr( new MinecartSpawner(level, x, y, z) ); + case TYPE_HOPPER: + return shared_ptr( new MinecartHopper(level, x, y, z) ); + default: + return shared_ptr( new MinecartRideable(level, x, y, z) ); + } +} bool Minecart::makeStepSound() { @@ -130,21 +90,26 @@ bool Minecart::makeStepSound() void Minecart::defineSynchedData() { - entityData->define(DATA_ID_FUEL, (byte) 0); entityData->define(DATA_ID_HURT, 0); entityData->define(DATA_ID_HURTDIR, 1); - entityData->define(DATA_ID_DAMAGE, 0); + entityData->define(DATA_ID_DAMAGE, 0.0f); + entityData->define(DATA_ID_DISPLAY_TILE, 0); + entityData->define(DATA_ID_DISPLAY_OFFSET, 6); + entityData->define(DATA_ID_CUSTOM_DISPLAY, (byte) 0); } AABB *Minecart::getCollideAgainstBox(shared_ptr entity) { - return entity->bb; + if (entity->isPushable()) + { + return entity->bb; + } + return NULL; } AABB *Minecart::getCollideBox() { - // if (level->isClientSide) return NULL; return NULL; } @@ -153,14 +118,11 @@ bool Minecart::isPushable() return true; } -Minecart::Minecart(Level *level, double x, double y, double z, int type) : Entity( level ) +Minecart::Minecart(Level *level, double x, double y, double z) : Entity( level ) { - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that - // the derived version of the function is called - this->defineSynchedData(); _init(); - setPos(x, y + heightOffset, z); + setPos(x, y, z); xd = 0; yd = 0; @@ -169,7 +131,6 @@ Minecart::Minecart(Level *level, double x, double y, double z, int type) : Entit xo = x; yo = y; zo = z; - this->type = type; } double Minecart::getRideHeight() @@ -177,88 +138,65 @@ double Minecart::getRideHeight() return bbHeight * 0.0 - 0.3f; } -bool Minecart::hurt(DamageSource *source, int hurtDamage) +bool Minecart::hurt(DamageSource *source, float hurtDamage) { if (level->isClientSide || removed) return true; - + if (isInvulnerable()) return false; + // 4J-JEV: Fix for #88212, // Untrusted players shouldn't be able to damage minecarts or boats. if (dynamic_cast(source) != NULL) { shared_ptr attacker = source->getDirectEntity(); - if (dynamic_pointer_cast(attacker) != NULL && - !dynamic_pointer_cast(attacker)->isAllowedToHurtEntity( shared_from_this() )) + if ( attacker->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast(attacker)->isAllowedToHurtEntity( shared_from_this() )) + { return false; + } } setHurtDir(-getHurtDir()); setHurtTime(10); markHurt(); + setDamage(getDamage() + (hurtDamage * 10)); // 4J Stu - If someone is riding in this, then it can tick multiple times which causes the damage to // decrease too quickly. So just make the damage a bit higher to start with for similar behaviour // to an unridden one. Only do this change if the riding player is attacking it. if( rider.lock() != NULL && rider.lock() == source->getEntity() ) hurtDamage += 1; - // 4J Stu - Brought froward from 12w36 to fix #46611 - TU5: Gameplay: Minecarts and boat requires more hits than one to be destroyed in creative mode - shared_ptr player = dynamic_pointer_cast(source->getEntity()); - if (player != NULL && player->abilities.instabuild) this->setDamage(100); + bool creativePlayer = source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_PLAYER) && dynamic_pointer_cast(source->getEntity())->abilities.instabuild; - this->setDamage(getDamage() + (hurtDamage * 10)); - if (this->getDamage() > 20 * 2) + if (creativePlayer || getDamage() > 20 * 2) { // 4J HEG - Fixed issue with player falling through the ground on destroying a minecart while riding (issue #160607) if (rider.lock() != NULL) rider.lock()->ride(nullptr); - remove(); - spawnAtLocation(Item::minecart->id, 1, 0); - if (type == Minecart::CHEST) + if (!creativePlayer || hasCustomName()) { - shared_ptr container = dynamic_pointer_cast( shared_from_this() ); - for (unsigned int i = 0; i < container->getContainerSize(); i++) - { - shared_ptr item = container->getItem(i); - if (item != NULL) - { - float xo = random->nextFloat() * 0.8f + 0.1f; - float yo = random->nextFloat() * 0.8f + 0.1f; - float zo = random->nextFloat() * 0.8f + 0.1f; - - while (item->count > 0) - { - int count = random->nextInt(21) + 10; - if (count > item->count) count = item->count; - item->count -= count; - - shared_ptr itemEntity = shared_ptr( new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr( new ItemInstance(item->id, count, item->getAuxValue()) ) ) ); - float pow = 0.05f; - itemEntity->xd = (float) random->nextGaussian() * pow; - itemEntity->yd = (float) random->nextGaussian() * pow + 0.2f; - itemEntity->zd = (float) random->nextGaussian() * pow; - if (item->hasTag()) - { - itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); - } - level->addEntity(itemEntity); - } - } - } - spawnAtLocation(Tile::chest_Id, 1, 0); + destroy(source); } - else if (type == Minecart::FURNACE) + else { - spawnAtLocation(Tile::furnace_Id, 1, 0); + remove(); } } return true; } +void Minecart::destroy(DamageSource *source) +{ + remove(); + shared_ptr item = shared_ptr( new ItemInstance(Item::minecart, 1) ); + if (!name.empty()) item->setHoverName(name); + spawnAtLocation(item, 0); +} + void Minecart::animateHurt() { setHurtDir(-getHurtDir()); setHurtTime(10); - this->setDamage(this->getDamage() + (getDamage() * 10)); + setDamage(getDamage() + (getDamage() * 10)); } bool Minecart::isPickable() @@ -268,40 +206,13 @@ bool Minecart::isPickable() void Minecart::remove() { - for (unsigned int i = 0; i < getContainerSize(); i++) - { - shared_ptr item = getItem(i); - if (item != NULL) - { - float xo = random->nextFloat() * 0.8f + 0.1f; - float yo = random->nextFloat() * 0.8f + 0.1f; - float zo = random->nextFloat() * 0.8f + 0.1f; - - while (item->count > 0) - { - int count = random->nextInt(21) + 10; - if (count > item->count) count = item->count; - item->count -= count; - - shared_ptr itemEntity = shared_ptr( new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr( new ItemInstance(item->id, count, item->getAuxValue()) ) ) ); - float pow = 0.05f; - itemEntity->xd = (float) random->nextGaussian() * pow; - itemEntity->yd = (float) random->nextGaussian() * pow + 0.2f; - itemEntity->zd = (float) random->nextGaussian() * pow; - if (item->hasTag()) - { - itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); - } - level->addEntity(itemEntity); - } - } - } Entity::remove(); + //if (soundUpdater != NULL) soundUpdater->tick(); } - void Minecart::tick() { + //if (soundUpdater != NULL) soundUpdater->tick(); // 4J - make minecarts (server-side) tick twice, to put things back to how they were when we were accidently ticking them twice for( int i = 0; i < 2; i++ ) { @@ -312,9 +223,45 @@ void Minecart::tick() outOfWorld(); } - if (hasFuel() && random->nextInt(4) == 0) + if (!level->isClientSide && dynamic_cast(level) != NULL) { - level->addParticle(eParticleType_largesmoke, x, y + 0.8, z, 0, 0, 0); + MinecraftServer *server = ((ServerLevel *) level)->getServer(); + int waitTime = getPortalWaitTime(); + + if (isInsidePortal) + { + if (server->isNetherEnabled()) + { + if (riding == NULL) + { + if (portalTime++ >= waitTime) + { + portalTime = waitTime; + changingDimensionDelay = getDimensionChangingDelay(); + + int targetDimension; + + if (level->dimension->id == -1) + { + targetDimension = 0; + } + else + { + targetDimension = -1; + } + + changeDimension(targetDimension); + } + } + isInsidePortal = false; + } + } + else + { + if (portalTime > 0) portalTime -= 4; + if (portalTime < 0) portalTime = 0; + } + if (changingDimensionDelay > 0) changingDimensionDelay--; } // 4J Stu - Fix for #8284 - Gameplay: Collision: Minecart clips into/ through blocks at the end of the track, prevents player from riding @@ -332,13 +279,13 @@ void Minecart::tick() xRot += (float) ( (lxr - xRot) / lSteps ); lSteps--; - this->setPos(xt, yt, zt); - this->setRot(yRot, xRot); + setPos(xt, yt, zt); + setRot(yRot, xRot); } else { - this->setPos(x, y, z); - this->setRot(yRot, xRot); + setPos(x, y, z); + setRot(yRot, xRot); } return; // 4J - return here stops the client-side version of this from ticking twice @@ -352,7 +299,7 @@ void Minecart::tick() int xt = Mth::floor(x); int yt = Mth::floor(y); int zt = Mth::floor(z); - if (RailTile::isRail(level, xt, yt - 1, zt)) + if (BaseRailTile::isRail(level, xt, yt - 1, zt)) { yt--; } @@ -361,356 +308,330 @@ void Minecart::tick() double slideSpeed = 1 / 128.0; int tile = level->getTile(xt, yt, zt); - if (RailTile::isRail(tile)) + if (BaseRailTile::isRail(tile)) { - Vec3 *oldPos = getPos(x, y, z); int data = level->getData(xt, yt, zt); - y = yt; + moveAlongTrack(xt, yt, zt, max, slideSpeed, tile, data); - bool powerTrack = false; - bool haltTrack = false; - if (tile == Tile::goldenRail_Id) - { - powerTrack = (data & RailTile::RAIL_DATA_BIT) != 0; - haltTrack = !powerTrack; - } - if (((RailTile *) Tile::tiles[tile])->isUsesDataBit()) + if (tile == Tile::activatorRail_Id) { - data &= RailTile::RAIL_DIRECTION_MASK; + activateMinecart(xt, yt, zt, (data & BaseRailTile::RAIL_DATA_BIT) != 0); } + } + else + { + comeOffTrack(max); + } - if (data >= 2 && data <= 5) - { - y = yt + 1; - } + checkInsideTiles(); - if (data == 2) xd -= slideSpeed; - if (data == 3) xd += slideSpeed; - if (data == 4) zd += slideSpeed; - if (data == 5) zd -= slideSpeed; - - // 4J TODO Is this a good way to copy the bit of the array that we need? - int exits[2][3]; - memcpy( &exits, (void *)EXITS[data], sizeof(int) * 2 * 3); - //int exits[2][3] = EXITS[data]; - - double xD = exits[1][0] - exits[0][0]; - double zD = exits[1][2] - exits[0][2]; - double dd = sqrt(xD * xD + zD * zD); - - double flip = xd * xD + zd * zD; - if (flip < 0) - { - xD = -xD; - zD = -zD; - } + xRot = 0; + double xDiff = xo - x; + double zDiff = zo - z; + if (xDiff * xDiff + zDiff * zDiff > 0.001) + { + yRot = (float) (atan2(zDiff, xDiff) * 180 / PI); + if (flipped) yRot += 180; + } - double pow = sqrt(xd * xd + zd * zd); + double rotDiff = Mth::wrapDegrees(yRot - yRotO); - xd = pow * xD / dd; - zd = pow * zD / dd; - - shared_ptr sharedRider = rider.lock(); - if (sharedRider != NULL) - { - double riderDist = (sharedRider->xd * sharedRider->xd + sharedRider->zd * sharedRider->zd); - double ownDist = xd * xd + zd * zd; + if (rotDiff < -170 || rotDiff >= 170) + { + yRot += 180; + flipped = !flipped; + } + setRot(yRot, xRot); - if (riderDist > 0.0001 && ownDist < 0.01) + vector > *entities = level->getEntities(shared_from_this(), bb->grow(0.2f, 0, 0.2f)); + if (entities != NULL && !entities->empty()) + { + AUTO_VAR(itEnd, entities->end()); + for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) + { + shared_ptr e = (*it); //entities->at(i); + if (e != rider.lock() && e->isPushable() && e->instanceof(eTYPE_MINECART)) { - xd += sharedRider->xd * 0.1; - zd += sharedRider->zd * 0.1; + shared_ptr cart = dynamic_pointer_cast(e); + cart->m_bHasPushedCartThisTick = false; + cart->push(shared_from_this()); - haltTrack = false; + // 4J Added - We should only be pushed by one minecart per tick, the closest one + // Fix for #46937 - TU5: Gameplay: Crash/Freeze occurs when a minecart with an animal inside will be forced to despawn + if( cart->m_bHasPushedCartThisTick ) break; } } + } - // on golden rails without power, stop the cart - if (haltTrack) + if (rider.lock() != NULL) + { + if (rider.lock()->removed) { - double speedLength = sqrt(xd * xd + zd * zd); - if (speedLength < 0.03) - { - xd *= 0; - yd *= 0; - zd *= 0; - } - else + if (rider.lock()->riding == shared_from_this()) { - xd *= 0.5f; - yd *= 0; - zd *= 0.5f; + rider.lock()->riding = nullptr; } + rider = weak_ptr(); } + } + } +} - double progress = 0; - double x0 = xt + 0.5 + exits[0][0] * 0.5; - double z0 = zt + 0.5 + exits[0][2] * 0.5; - double x1 = xt + 0.5 + exits[1][0] * 0.5; - double z1 = zt + 0.5 + exits[1][2] * 0.5; +void Minecart::activateMinecart(int xt, int yt, int zt, bool state) +{ +} - xD = x1 - x0; - zD = z1 - z0; +void Minecart::comeOffTrack(double maxSpeed) +{ + if (xd < -maxSpeed) xd = -maxSpeed; + if (xd > +maxSpeed) xd = +maxSpeed; + if (zd < -maxSpeed) zd = -maxSpeed; + if (zd > +maxSpeed) zd = +maxSpeed; + if (onGround) + { + xd *= 0.5f; + yd *= 0.5f; + zd *= 0.5f; + } + move(xd, yd, zd); - if (xD == 0) - { - x = xt + 0.5; - progress = z - zt; - } - else if (zD == 0) - { - z = zt + 0.5; - progress = x - xt; - } - else - { + if (!onGround) + { + xd *= 0.95f; + yd *= 0.95f; + zd *= 0.95f; + } +} - double xx = x - x0; - double zz = z - z0; +void Minecart::moveAlongTrack(int xt, int yt, int zt, double maxSpeed, double slideSpeed, int tile, int data) +{ + fallDistance = 0; - progress = (xx * xD + zz * zD) * 2; - } + Vec3 *oldPos = getPos(x, y, z); + y = yt; - x = x0 + xD * progress; - z = z0 + zD * progress; + bool powerTrack = false; + bool haltTrack = false; + if (tile == Tile::goldenRail_Id) + { + powerTrack = (data & BaseRailTile::RAIL_DATA_BIT) != 0; + haltTrack = !powerTrack; + } + if (((BaseRailTile *) Tile::tiles[tile])->isUsesDataBit()) + { + data &= BaseRailTile::RAIL_DIRECTION_MASK; + } - setPos(x, y + heightOffset, z); + if (data >= 2 && data <= 5) + { + y = yt + 1; + } - double xdd = xd; - double zdd = zd; - if (rider.lock() != NULL) - { - xdd *= 0.75; - zdd *= 0.75; - } - if (xdd < -max) xdd = -max; - if (xdd > +max) xdd = +max; - if (zdd < -max) zdd = -max; - if (zdd > +max) zdd = +max; - move(xdd, 0, zdd); + if (data == 2) xd -= slideSpeed; + if (data == 3) xd += slideSpeed; + if (data == 4) zd += slideSpeed; + if (data == 5) zd -= slideSpeed; - if (exits[0][1] != 0 && Mth::floor(x) - xt == exits[0][0] && Mth::floor(z) - zt == exits[0][2]) - { - setPos(x, y + exits[0][1], z); - } - else if (exits[1][1] != 0 && Mth::floor(x) - xt == exits[1][0] && Mth::floor(z) - zt == exits[1][2]) - { - setPos(x, y + exits[1][1], z); - } - else - { - } + int exits[2][3]; + memcpy( exits, EXITS[data], sizeof(int) * 2 * 3); - if (rider.lock() != NULL) - { - xd *= 0.997f; - yd *= 0; - zd *= 0.997f; - } - else - { - if (type == Minecart::FURNACE) - { - double sd = xPush * xPush + zPush * zPush; - if (sd > 0.01 * 0.01) - { - sd = sqrt(sd); - xPush /= sd; - zPush /= sd; - double speed = 0.04; - xd *= 0.8f; - yd *= 0; - zd *= 0.8f; - xd += xPush * speed; - zd += zPush * speed; - } - else - { - xd *= 0.9f; - yd *= 0; - zd *= 0.9f; - } - } - xd *= 0.96f; - yd *= 0; - zd *= 0.96f; + double xD = exits[1][0] - exits[0][0]; + double zD = exits[1][2] - exits[0][2]; + double dd = sqrt(xD * xD + zD * zD); - } + double flip = xd * xD + zd * zD; + if (flip < 0) + { + xD = -xD; + zD = -zD; + } - Vec3 *newPos = getPos(x, y, z); - if (newPos != NULL && oldPos != NULL) - { - double speed = (oldPos->y - newPos->y) * 0.05; + double pow = sqrt(xd * xd + zd * zd); + if (pow > 2) + { + pow = 2; + } - pow = sqrt(xd * xd + zd * zd); - if (pow > 0) - { - xd = xd / pow * (pow + speed); - zd = zd / pow * (pow + speed); - } - setPos(x, newPos->y, z); - } + xd = pow * xD / dd; + zd = pow * zD / dd; - int xn = Mth::floor(x); - int zn = Mth::floor(z); - if (xn != xt || zn != zt) - { - pow = sqrt(xd * xd + zd * zd); + + if ( rider.lock() != NULL && rider.lock()->instanceof(eTYPE_LIVINGENTITY) ) + { + shared_ptr living = dynamic_pointer_cast(rider.lock()); - xd = pow * (xn - xt); - zd = pow * (zn - zt); - } + double forward = living->yya; - if (type == Minecart::FURNACE) - { - double sd = xPush * xPush + zPush * zPush; - if (sd > 0.01 * 0.01 && xd * xd + zd * zd > 0.001) - { - sd = sqrt(sd); - xPush /= sd; - zPush /= sd; + if (forward > 0) + { + double riderXd = -sin(living->yRot * PI / 180); + double riderZd = cos(living->yRot * PI / 180); - if (xPush * xd + zPush * zd < 0) - { - xPush = 0; - zPush = 0; - } - else - { - xPush = xd; - zPush = zd; - } - } - } + double ownDist = xd * xd + zd * zd; - // if on golden rail with power, increase speed - if (powerTrack) + if (ownDist < 0.01) { - double speedLength = sqrt(xd * xd + zd * zd); - if (speedLength > .01) - { - double speed = 0.06; - xd += xd / speedLength * speed; - zd += zd / speedLength * speed; - } - else - { - // if the minecart is standing still, accelerate it away - // from potentional walls - if (data == RailTile::DIR_FLAT_X) - { - if (level->isSolidBlockingTile(xt - 1, yt, zt)) - { - xd = .02; - } - else if (level->isSolidBlockingTile(xt + 1, yt, zt)) - { - xd = -.02; - } - } - else if (data == RailTile::DIR_FLAT_Z) - { - if (level->isSolidBlockingTile(xt, yt, zt - 1)) - { - zd = .02; - } - else if (level->isSolidBlockingTile(xt, yt, zt + 1)) - { - zd = -.02; - } - } - } + xd += riderXd * 0.1; + zd += riderZd * 0.1; + + haltTrack = false; } + } + } - checkInsideTiles(); + // on golden rails without power, stop the cart + if (haltTrack) + { + double speedLength = sqrt(xd * xd + zd * zd); + if (speedLength < .03) + { + xd *= 0; + yd *= 0; + zd *= 0; } else { - if (xd < -max) xd = -max; - if (xd > +max) xd = +max; - if (zd < -max) zd = -max; - if (zd > +max) zd = +max; - if (onGround) - { - xd *= 0.5f; - yd *= 0.5f; - zd *= 0.5f; - } - move(xd, yd, zd); - - if (onGround) - { - } - else - { - xd *= 0.95f; - yd *= 0.95f; - zd *= 0.95f; - } + xd *= 0.5f; + yd *= 0; + zd *= 0.5f; } + } - xRot = 0; - double xDiff = xo - x; - double zDiff = zo - z; - if (xDiff * xDiff + zDiff * zDiff > 0.001) + double progress = 0; + double x0 = xt + 0.5 + exits[0][0] * 0.5; + double z0 = zt + 0.5 + exits[0][2] * 0.5; + double x1 = xt + 0.5 + exits[1][0] * 0.5; + double z1 = zt + 0.5 + exits[1][2] * 0.5; + + xD = x1 - x0; + zD = z1 - z0; + + if (xD == 0) + { + x = xt + 0.5; + progress = z - zt; + } + else if (zD == 0) + { + z = zt + 0.5; + progress = x - xt; + } + else + { + + double xx = x - x0; + double zz = z - z0; + + progress = (xx * xD + zz * zD) * 2; + } + + x = x0 + xD * progress; + z = z0 + zD * progress; + + setPos(x, y + heightOffset, z); + + double xdd = xd; + double zdd = zd; + if (rider.lock() != NULL) + { + xdd *= 0.75; + zdd *= 0.75; + } + if (xdd < -maxSpeed) xdd = -maxSpeed; + if (xdd > +maxSpeed) xdd = +maxSpeed; + if (zdd < -maxSpeed) zdd = -maxSpeed; + if (zdd > +maxSpeed) zdd = +maxSpeed; + + move(xdd, 0, zdd); + + if (exits[0][1] != 0 && Mth::floor(x) - xt == exits[0][0] && Mth::floor(z) - zt == exits[0][2]) + { + setPos(x, y + exits[0][1], z); + } + else if (exits[1][1] != 0 && Mth::floor(x) - xt == exits[1][0] && Mth::floor(z) - zt == exits[1][2]) + { + setPos(x, y + exits[1][1], z); + } + + applyNaturalSlowdown(); + + Vec3 *newPos = getPos(x, y, z); + if (newPos != NULL && oldPos != NULL) + { + double speed = (oldPos->y - newPos->y) * 0.05; + + pow = sqrt(xd * xd + zd * zd); + if (pow > 0) { - yRot = (float) (atan2(zDiff, xDiff) * 180 / PI); - if (flipped) yRot += 180; + xd = xd / pow * (pow + speed); + zd = zd / pow * (pow + speed); } + setPos(x, newPos->y, z); + } - double rotDiff = Mth::wrapDegrees(yRot - yRotO); + int xn = Mth::floor(x); + int zn = Mth::floor(z); + if (xn != xt || zn != zt) + { + pow = sqrt(xd * xd + zd * zd); - if (rotDiff < -170 || rotDiff >= 170) + xd = pow * (xn - xt); + zd = pow * (zn - zt); + } + + // if on golden rail with power, increase speed + if (powerTrack) + { + double speedLength = sqrt(xd * xd + zd * zd); + if (speedLength > .01) { - yRot += 180; - flipped = !flipped; + double speed = 0.06; + xd += xd / speedLength * speed; + zd += zd / speedLength * speed; } - setRot(yRot, xRot); - - // if (!level->isClientSide) { + else { - vector > *entities = level->getEntities(shared_from_this(), this->bb->grow(0.2f, 0, 0.2f)); - if (entities != NULL && !entities->empty()) + // if the minecart is standing still, accelerate it away from + // potential walls + if (data == BaseRailTile::DIR_FLAT_X) { - AUTO_VAR(itEnd, entities->end()); - for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) + if (level->isSolidBlockingTile(xt - 1, yt, zt)) { - shared_ptr e = (*it); //entities->at(i); - if (e != rider.lock() && e->isPushable() && e->GetType() == eTYPE_MINECART) - { - shared_ptr cart = dynamic_pointer_cast(e); - cart->m_bHasPushedCartThisTick = false; - cart->push(shared_from_this()); - - // 4J Added - We should only be pushed by one minecart per tick, the closest one - // Fix for #46937 - TU5: Gameplay: Crash/Freeze occurs when a minecart with an animal inside will be forced to despawn - if( cart->m_bHasPushedCartThisTick ) break; - } + xd = .02; + } + else if (level->isSolidBlockingTile(xt + 1, yt, zt)) + { + xd = -.02; } } - } - - if (rider.lock() != NULL) - { - if (rider.lock()->removed) + else if (data == BaseRailTile::DIR_FLAT_Z) { - if (rider.lock()->riding == shared_from_this()) + if (level->isSolidBlockingTile(xt, yt, zt - 1)) { - rider.lock()->riding = nullptr; + zd = .02; + } + else if (level->isSolidBlockingTile(xt, yt, zt + 1)) + { + zd = -.02; } - rider = weak_ptr(); } } + } +} - if (fuel > 0) - { - fuel--; - } - if (fuel <= 0) - { - xPush = zPush = 0; - } - setHasFuel(fuel > 0); +void Minecart::applyNaturalSlowdown() +{ + if (rider.lock() != NULL) + { + xd *= 0.997f; + yd *= 0; + zd *= 0.997f; + } + else + { + xd *= 0.96f; + yd *= 0; + zd *= 0.96f; } } @@ -719,19 +640,19 @@ Vec3 *Minecart::getPosOffs(double x, double y, double z, double offs) int xt = Mth::floor(x); int yt = Mth::floor(y); int zt = Mth::floor(z); - if (RailTile::isRail(level, xt, yt - 1, zt)) + if (BaseRailTile::isRail(level, xt, yt - 1, zt)) { yt--; } int tile = level->getTile(xt, yt, zt); - if (RailTile::isRail(tile)) + if (BaseRailTile::isRail(tile)) { int data = level->getData(xt, yt, zt); - if (((RailTile *) Tile::tiles[tile])->isUsesDataBit()) + if (((BaseRailTile *) Tile::tiles[tile])->isUsesDataBit()) { - data &= RailTile::RAIL_DIRECTION_MASK; + data &= BaseRailTile::RAIL_DIRECTION_MASK; } y = yt; @@ -762,9 +683,6 @@ Vec3 *Minecart::getPosOffs(double x, double y, double z, double offs) { y += exits[1][1]; } - else - { - } return getPos(x, y, z); } @@ -776,20 +694,20 @@ Vec3 *Minecart::getPos(double x, double y, double z) int xt = Mth::floor(x); int yt = Mth::floor(y); int zt = Mth::floor(z); - if (RailTile::isRail(level, xt, yt - 1, zt)) + if (BaseRailTile::isRail(level, xt, yt - 1, zt)) { yt--; } int tile = level->getTile(xt, yt, zt); - if (RailTile::isRail(tile)) + if (BaseRailTile::isRail(tile)) { int data = level->getData(xt, yt, zt); y = yt; - if (((RailTile *) Tile::tiles[tile])->isUsesDataBit()) + if (((BaseRailTile *) Tile::tiles[tile])->isUsesDataBit()) { - data &= RailTile::RAIL_DIRECTION_MASK; + data &= BaseRailTile::RAIL_DIRECTION_MASK; } if (data >= 2 && data <= 5) @@ -843,57 +761,30 @@ Vec3 *Minecart::getPos(double x, double y, double z) return NULL; } - -void Minecart::addAdditonalSaveData(CompoundTag *base) +void Minecart::readAdditionalSaveData(CompoundTag *tag) { - base->putInt(L"Type", type); - - if (type == Minecart::FURNACE) + if (tag->getBoolean(L"CustomDisplayTile")) { - base->putDouble(L"PushX", xPush); - base->putDouble(L"PushZ", zPush); - base->putShort(L"Fuel", (short) fuel); + setDisplayTile(tag->getInt(L"DisplayTile")); + setDisplayData(tag->getInt(L"DisplayData")); + setDisplayOffset(tag->getInt(L"DisplayOffset")); } - else if (type == Minecart::CHEST) - { - ListTag *listTag = new ListTag(); - for (unsigned int i = 0; i < items->length; i++) - { - if ( (*items)[i] != NULL) - { - CompoundTag *tag = new CompoundTag(); - tag->putByte(L"Slot", (byte) i); - (*items)[i]->save(tag); - listTag->add(tag); - } - } - base->put(L"Items", listTag); - } + if (tag->contains(L"CustomName") && tag->getString(L"CustomName").length() > 0) name = tag->getString(L"CustomName"); } -void Minecart::readAdditionalSaveData(CompoundTag *base) +void Minecart::addAdditonalSaveData(CompoundTag *tag) { - type = base->getInt(L"Type"); - if (type == Minecart::FURNACE) - { - xPush = base->getDouble(L"PushX"); - zPush = base->getDouble(L"PushZ"); - fuel = base->getShort(L"Fuel"); - } - else if (type == Minecart::CHEST) + if (hasCustomDisplay()) { - ListTag *inventoryList = (ListTag *) base->getList(L"Items"); - items = new ItemInstanceArray( getContainerSize() ); - for (int i = 0; i < inventoryList->size(); i++) - { - CompoundTag *tag = inventoryList->get(i); - unsigned int slot = tag->getByte(L"Slot") & 0xff; - if (slot >= 0 && slot < items->length) (*items)[slot] = shared_ptr( ItemInstance::fromTag(tag) ); - } + tag->putBoolean(L"CustomDisplayTile", true); + tag->putInt(L"DisplayTile", getDisplayTile() == NULL ? 0 : getDisplayTile()->id); + tag->putInt(L"DisplayData", getDisplayData()); + tag->putInt(L"DisplayOffset", getDisplayOffset()); } -} + if (!name.empty()) tag->putString(L"CustomName", name); +} float Minecart::getShadowHeightOffs() { @@ -905,9 +796,9 @@ void Minecart::push(shared_ptr e) if (level->isClientSide) return; if (e == rider.lock()) return; - if (( dynamic_pointer_cast(e)!=NULL) && dynamic_pointer_cast(e)==NULL && dynamic_pointer_cast(e) == NULL && type == Minecart::RIDEABLE && xd * xd + zd * zd > 0.01) + if ( e->instanceof(eTYPE_LIVINGENTITY) && !e->instanceof(eTYPE_PLAYER) && !e->instanceof(eTYPE_VILLAGERGOLEM) && (getType() == TYPE_RIDEABLE) && (xd * xd + zd * zd > 0.01) ) { - if (rider.lock() == NULL && e->riding == NULL) + if ( (rider.lock() == NULL) && (e->riding == NULL) ) { e->ride( shared_from_this() ); } @@ -934,7 +825,7 @@ void Minecart::push(shared_ptr e) xa *= 0.5; za *= 0.5; - if (e->GetType() == eTYPE_MINECART) + if (e->instanceof(eTYPE_MINECART)) { double xo = e->x - x; double zo = e->z - z; @@ -955,16 +846,16 @@ void Minecart::push(shared_ptr e) double zdd = (e->zd + zd); shared_ptr cart = dynamic_pointer_cast(e); - if (cart != NULL && cart->type == Minecart::FURNACE && type != Minecart::FURNACE) + if (cart != NULL && cart->getType() == TYPE_FURNACE && getType() != TYPE_FURNACE) { xd *= 0.2f; zd *= 0.2f; - this->Entity::push( e->xd - xa, 0, e->zd - za); + push( e->xd - xa, 0, e->zd - za); e->xd *= 0.95f; e->zd *= 0.95f; m_bHasPushedCartThisTick = true; } - else if (cart != NULL && cart->type != Minecart::FURNACE && type == Minecart::FURNACE) + else if (cart != NULL && cart->getType() != TYPE_FURNACE && getType() == TYPE_FURNACE) { e->xd *= 0.2f; e->zd *= 0.2f; @@ -979,7 +870,7 @@ void Minecart::push(shared_ptr e) zdd /= 2; xd *= 0.2f; zd *= 0.2f; - this->Entity::push(xdd - xa, 0, zdd - za); + push(xdd - xa, 0, zdd - za); e->xd *= 0.2f; e->zd *= 0.2f; e->push(xdd + xa, 0, zdd + za); @@ -1006,206 +897,146 @@ void Minecart::push(shared_ptr e) } else { - this->Entity::push(-xa, 0, -za); + push(-xa, 0, -za); e->push(xa / 4, 0, za / 4); } } } -unsigned int Minecart::getContainerSize() +void Minecart::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) { - return 9 * 3; + lx = x; + ly = y; + lz = z; + lyr = yRot; + lxr = xRot; + + lSteps = steps + 2; + + xd = lxd; + yd = lyd; + zd = lzd; } -shared_ptr Minecart::getItem(unsigned int slot) +void Minecart::lerpMotion(double xd, double yd, double zd) { - return (*items)[slot]; + lxd = this->xd = xd; + lyd = this->yd = yd; + lzd = this->zd = zd; } -shared_ptr Minecart::removeItem(unsigned int slot, int count) +void Minecart::setDamage(float damage) { - if ( (*items)[slot] != NULL) - { - if ( (*items)[slot]->count <= count) - { - shared_ptr item = (*items)[slot]; - (*items)[slot] = nullptr; - return item; - } - else - { - shared_ptr i = (*items)[slot]->remove(count); - if ((*items)[slot]->count == 0) (*items)[slot] = nullptr; - return i; - } - } - return nullptr; + entityData->set(DATA_ID_DAMAGE, damage); } -shared_ptr Minecart::removeItemNoUpdate(int slot) +float Minecart::getDamage() { - if ( (*items)[slot] != NULL) - { - shared_ptr item = (*items)[slot]; - (*items)[slot] = nullptr; - return item; - } - return nullptr; + return entityData->getFloat(DATA_ID_DAMAGE); } -void Minecart::setItem(unsigned int slot, shared_ptr item) +void Minecart::setHurtTime(int hurtTime) { - (*items)[slot] = item; - if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); + entityData->set(DATA_ID_HURT, hurtTime); } -int Minecart::getName() +int Minecart::getHurtTime() { - return IDS_ITEM_MINECART; + return entityData->getInteger(DATA_ID_HURT); } -int Minecart::getMaxStackSize() +void Minecart::setHurtDir(int hurtDir) { - return Container::LARGE_MAX_STACK_SIZE; + entityData->set(DATA_ID_HURTDIR, hurtDir); } -void Minecart::setChanged() +int Minecart::getHurtDir() { + return entityData->getInteger(DATA_ID_HURTDIR); } -bool Minecart::interact(shared_ptr player) +Tile *Minecart::getDisplayTile() { - if (type == Minecart::RIDEABLE) - { - if (rider.lock() != NULL && dynamic_pointer_cast(rider.lock())!=NULL && rider.lock() != player) return true; - if (!level->isClientSide) - { - // 4J HEG - Fixed issue with player not being able to dismount minecart (issue #4455) - player->ride( rider.lock() == player ? nullptr : shared_from_this() ); - } - } - else if (type == Minecart::CHEST) - { - if ( player->isAllowedToInteract(shared_from_this()) ) - { - if (!level->isClientSide) - player->openContainer( dynamic_pointer_cast( shared_from_this() ) ); - } - else - { - return false; - } - } - else if (type == Minecart::FURNACE) - { - shared_ptr selected = player->inventory->getSelected(); - if (selected != NULL && selected->id == Item::coal->id) - { - if (--selected->count == 0) player->inventory->setItem(player->inventory->selected, nullptr); - fuel += SharedConstants::TICKS_PER_SECOND * 180; - - } - xPush = x - player->x; - zPush = z - player->z; - } - return true; + if (!hasCustomDisplay()) return getDefaultDisplayTile(); + int id = getEntityData()->getInteger(DATA_ID_DISPLAY_TILE) & 0xFFFF; + return id > 0 && id < Tile::TILE_NUM_COUNT ? Tile::tiles[id] : NULL; } -float Minecart::getLootContent() +Tile *Minecart::getDefaultDisplayTile() { - int count = 0; - for (unsigned int i = 0; i < items->length; i++) - { - if ( (*items)[i] != NULL) count++; - } - return count / (float) items->length; + return NULL; } - -void Minecart::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) +int Minecart::getDisplayData() { - lx = x; - ly = y; - lz = z; - lyr = yRot; - lxr = xRot; - - lSteps = steps + 2; - - this->xd = lxd; - this->yd = lyd; - this->zd = lzd; + if (!hasCustomDisplay()) return getDefaultDisplayData(); + return getEntityData()->getInteger(DATA_ID_DISPLAY_TILE) >> 16; } -void Minecart::lerpMotion(double xd, double yd, double zd) +int Minecart::getDefaultDisplayData() { - lxd = this->xd = xd; - lyd = this->yd = yd; - lzd = this->zd = zd; + return 0; } -bool Minecart::stillValid(shared_ptr player) +int Minecart::getDisplayOffset() { - if (this->removed) return false; - if (player->distanceToSqr(shared_from_this()) > 8 * 8) return false; - return true; + if (!hasCustomDisplay()) return getDefaultDisplayOffset(); + return getEntityData()->getInteger(DATA_ID_DISPLAY_OFFSET); } -bool Minecart::hasFuel() +int Minecart::getDefaultDisplayOffset() { - return (entityData->getByte(DATA_ID_FUEL) & 1) != 0; + return 6; } -void Minecart::setHasFuel(bool fuel) +void Minecart::setDisplayTile(int id) { - if (fuel) - { - entityData->set(DATA_ID_FUEL, (byte) (entityData->getByte(DATA_ID_FUEL) | 1)); - } - else - { - entityData->set(DATA_ID_FUEL, (byte) (entityData->getByte(DATA_ID_FUEL) & ~1)); - } + getEntityData()->set(DATA_ID_DISPLAY_TILE, (id & 0xFFFF) | (getDisplayData() << 16)); + setCustomDisplay(true); } -void Minecart::startOpen() +void Minecart::setDisplayData(int data) { - // TODO Auto-generated method stub + Tile *tile = getDisplayTile(); + int id = tile == NULL ? 0 : tile->id; + getEntityData()->set(DATA_ID_DISPLAY_TILE, (id & 0xFFFF) | (data << 16)); + setCustomDisplay(true); } -void Minecart::stopOpen() +void Minecart::setDisplayOffset(int offset) { - // TODO Auto-generated method stub - + getEntityData()->set(DATA_ID_DISPLAY_OFFSET, offset); + setCustomDisplay(true); } -void Minecart::setDamage(int damage) +bool Minecart::hasCustomDisplay() { - entityData->set(DATA_ID_DAMAGE, damage); + return getEntityData()->getByte(DATA_ID_CUSTOM_DISPLAY) == 1; } -int Minecart::getDamage() +void Minecart::setCustomDisplay(bool value) { - return entityData->getInteger(DATA_ID_DAMAGE); + getEntityData()->set(DATA_ID_CUSTOM_DISPLAY, (byte) (value ? 1 : 0)); } -void Minecart::setHurtTime(int hurtTime) +void Minecart::setCustomName(const wstring &name) { - entityData->set(DATA_ID_HURT, hurtTime); + this->name = name; } -int Minecart::getHurtTime() +wstring Minecart::getAName() { - return entityData->getInteger(DATA_ID_HURT); + if (!name.empty()) return name; + return Entity::getAName(); } -void Minecart::setHurtDir(int hurtDir) +bool Minecart::hasCustomName() { - entityData->set(DATA_ID_HURTDIR, hurtDir); + return !name.empty(); } -int Minecart::getHurtDir() +wstring Minecart::getCustomName() { - return entityData->getInteger(DATA_ID_HURTDIR); + return name; } \ No newline at end of file diff --git a/Minecraft.World/Minecart.h b/Minecraft.World/Minecart.h index ea119bce..bd1a69e6 100644 --- a/Minecraft.World/Minecart.h +++ b/Minecraft.World/Minecart.h @@ -1,48 +1,49 @@ #pragma once #include "Entity.h" -#include "Container.h" class DamageSource; +class Tickable; -class Minecart : public Entity, public Container +class Minecart : public Entity { + friend class MinecartRenderer; public: eINSTANCEOF GetType() { return eTYPE_MINECART; }; - static Entity *create(Level *level) { return new Minecart(level); } public: - static const int RIDEABLE = 0; - static const int CHEST = 1; - static const int FURNACE = 2; - -private: - ItemInstanceArray *items; // Array + static const int TYPE_RIDEABLE = 0; + static const int TYPE_CHEST = 1; + static const int TYPE_FURNACE = 2; + static const int TYPE_TNT = 3; + static const int TYPE_SPAWNER = 4; + static const int TYPE_HOPPER = 5; public: static const int serialVersionUID = 0; private: - static const int DATA_ID_FUEL = 16; static const int DATA_ID_HURT = 17; static const int DATA_ID_HURTDIR = 18; static const int DATA_ID_DAMAGE = 19; + static const int DATA_ID_DISPLAY_TILE = 20; + static const int DATA_ID_DISPLAY_OFFSET = 21; + static const int DATA_ID_CUSTOM_DISPLAY = 22; - int fuel; - -private: bool flipped; + Tickable *soundUpdater; + wstring name; protected: // 4J Added bool m_bHasPushedCartThisTick; public: - int type; - double xPush, zPush; - void _init(); Minecart(Level *level); + virtual ~Minecart(); + + static shared_ptr createMinecart(Level *level, double x, double y, double z, int type); protected: virtual bool makeStepSound(); @@ -53,10 +54,11 @@ public: virtual AABB *getCollideBox(); virtual bool isPushable(); - Minecart(Level *level, double x, double y, double z, int type); + Minecart(Level *level, double x, double y, double z); virtual double getRideHeight(); - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); + virtual void destroy(DamageSource *source); virtual void animateHurt(); virtual bool isPickable(); virtual void remove(); @@ -66,6 +68,12 @@ private: public: virtual void tick(); + virtual void activateMinecart(int xt, int yt, int zt, bool state); + +protected: + virtual void comeOffTrack(double maxSpeed); + virtual void moveAlongTrack(int xt, int yt, int zt, double maxSpeed, double slideSpeed, int tile, int data); + virtual void applyNaturalSlowdown(); virtual Vec3 *getPosOffs(double x, double y, double z, double offs); virtual Vec3 *getPos(double x, double y, double z); @@ -75,17 +83,8 @@ protected: public: virtual float getShadowHeightOffs(); + using Entity::push; virtual void push(shared_ptr e); - virtual unsigned int getContainerSize(); - virtual shared_ptr getItem(unsigned int slot); - virtual shared_ptr removeItem(unsigned int slot, int count); - virtual shared_ptr removeItemNoUpdate(int slot); - virtual void setItem(unsigned int slot, shared_ptr item); - int getName(); - virtual int getMaxStackSize(); - virtual void setChanged(); - virtual bool interact(shared_ptr player); - virtual float getLootContent(); private: int lSteps; @@ -95,20 +94,29 @@ private: public: virtual void lerpTo(double x, double y, double z, float yRot, float xRot, int steps); virtual void lerpMotion(double xd, double yd, double zd); - virtual bool stillValid(shared_ptr player); -protected: - bool hasFuel(); - void setHasFuel(bool fuel); - -public: - virtual void startOpen(); - virtual void stopOpen(); - - void setDamage(int damage); - int getDamage(); - void setHurtTime(int hurtTime); - int getHurtTime(); - void setHurtDir(int hurtDir); - int getHurtDir(); + virtual void setDamage(float damage); + virtual float getDamage(); + virtual void setHurtTime(int hurtTime); + virtual int getHurtTime(); + virtual void setHurtDir(int hurtDir); + virtual int getHurtDir(); + + virtual int getType() = 0; + + virtual Tile *getDisplayTile(); + virtual Tile *getDefaultDisplayTile(); + virtual int getDisplayData(); + virtual int getDefaultDisplayData(); + virtual int getDisplayOffset(); + virtual int getDefaultDisplayOffset(); + virtual void setDisplayTile(int id); + virtual void setDisplayData(int data); + virtual void setDisplayOffset(int offset); + virtual bool hasCustomDisplay(); + virtual void setCustomDisplay(bool value); + virtual void setCustomName(const wstring &name); + virtual wstring getAName(); + virtual bool hasCustomName(); + virtual wstring getCustomName(); }; diff --git a/Minecraft.World/MinecartChest.cpp b/Minecraft.World/MinecartChest.cpp new file mode 100644 index 00000000..af137826 --- /dev/null +++ b/Minecraft.World/MinecartChest.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.network.packet.h" +#include "MinecartChest.h" + +MinecartChest::MinecartChest(Level *level) : MinecartContainer(level) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); +} + +MinecartChest::MinecartChest(Level *level, double x, double y, double z) : MinecartContainer(level, x, y, z) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); +} + +// 4J Added +int MinecartChest::getContainerType() +{ + return ContainerOpenPacket::MINECART_CHEST; +} + +void MinecartChest::destroy(DamageSource *source) +{ + MinecartContainer::destroy(source); + + spawnAtLocation(Tile::chest_Id, 1, 0); +} + +unsigned int MinecartChest::getContainerSize() +{ + return 9 * 3; +} + +int MinecartChest::getType() +{ + return TYPE_CHEST; +} + +Tile *MinecartChest::getDefaultDisplayTile() +{ + return Tile::chest; +} + +int MinecartChest::getDefaultDisplayOffset() +{ + return 8; +} \ No newline at end of file diff --git a/Minecraft.World/MinecartChest.h b/Minecraft.World/MinecartChest.h new file mode 100644 index 00000000..5eccb7e6 --- /dev/null +++ b/Minecraft.World/MinecartChest.h @@ -0,0 +1,23 @@ +#pragma once + +#include "MinecartContainer.h" + +class MinecartChest : public MinecartContainer +{ +public: + eINSTANCEOF GetType() { return eTYPE_MINECART_CHEST; }; + static Entity *create(Level *level) { return new MinecartChest(level); } + +public: + MinecartChest(Level *level); + MinecartChest(Level *level, double x, double y, double z); + + // 4J added + virtual int getContainerType(); + + virtual void destroy(DamageSource *source); + virtual unsigned int getContainerSize(); + virtual int getType(); + virtual Tile *getDefaultDisplayTile(); + virtual int getDefaultDisplayOffset(); +}; \ No newline at end of file diff --git a/Minecraft.World/MinecartContainer.cpp b/Minecraft.World/MinecartContainer.cpp new file mode 100644 index 00000000..61d0d32b --- /dev/null +++ b/Minecraft.World/MinecartContainer.cpp @@ -0,0 +1,233 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.inventory.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" +#include "MinecartContainer.h" + +void MinecartContainer::_init() +{ + items = ItemInstanceArray(9 * 4); + dropEquipment = true; + + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); +} + +MinecartContainer::MinecartContainer(Level *level) : Minecart(level) +{ + _init(); +} + +MinecartContainer::MinecartContainer(Level *level, double x, double y, double z) : Minecart(level, x, y, z) +{ + _init(); +} + +void MinecartContainer::destroy(DamageSource *source) +{ + Minecart::destroy(source); + + for (int i = 0; i < getContainerSize(); i++) + { + shared_ptr item = getItem(i); + if (item != NULL) + { + float xo = random->nextFloat() * 0.8f + 0.1f; + float yo = random->nextFloat() * 0.8f + 0.1f; + float zo = random->nextFloat() * 0.8f + 0.1f; + + while (item->count > 0) + { + int count = random->nextInt(21) + 10; + if (count > item->count) count = item->count; + item->count -= count; + + shared_ptr itemEntity = shared_ptr( new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr( new ItemInstance(item->id, count, item->getAuxValue()))) ); + float pow = 0.05f; + itemEntity->xd = (float) random->nextGaussian() * pow; + itemEntity->yd = (float) random->nextGaussian() * pow + 0.2f; + itemEntity->zd = (float) random->nextGaussian() * pow; + level->addEntity(itemEntity); + } + } + } +} + +shared_ptr MinecartContainer::getItem(unsigned int slot) +{ + return items[slot]; +} + +shared_ptr MinecartContainer::removeItem(unsigned int slot, int count) +{ + if (items[slot] != NULL) + { + if (items[slot]->count <= count) + { + shared_ptr item = items[slot]; + items[slot] = nullptr; + return item; + } + else + { + shared_ptr i = items[slot]->remove(count); + if (items[slot]->count == 0) items[slot] = nullptr; + return i; + } + } + return nullptr; +} + +shared_ptr MinecartContainer::removeItemNoUpdate(int slot) +{ + if (items[slot] != NULL) + { + shared_ptr item = items[slot]; + items[slot] = nullptr; + return item; + } + return nullptr; +} + +void MinecartContainer::setItem(unsigned int slot, shared_ptr item) +{ + items[slot] = item; + if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); +} + +void MinecartContainer::setChanged() +{ +} + +bool MinecartContainer::stillValid(shared_ptr player) +{ + if (removed) return false; + if (player->distanceToSqr(shared_from_this()) > 8 * 8) return false; + return true; +} + +void MinecartContainer::startOpen() +{ +} + +void MinecartContainer::stopOpen() +{ +} + +bool MinecartContainer::canPlaceItem(int slot, shared_ptr item) +{ + return true; +} + +wstring MinecartContainer::getName() +{ + return hasCustomName() ? getCustomName() : app.GetString(IDS_CONTAINER_MINECART); +} + +int MinecartContainer::getMaxStackSize() +{ + return Container::LARGE_MAX_STACK_SIZE; +} + +void MinecartContainer::changeDimension(int i) +{ + dropEquipment = false; + Minecart::changeDimension(i); +} + +void MinecartContainer::remove() +{ + if (dropEquipment) + { + for (int i = 0; i < getContainerSize(); i++) + { + shared_ptr item = getItem(i); + if (item != NULL) + { + float xo = random->nextFloat() * 0.8f + 0.1f; + float yo = random->nextFloat() * 0.8f + 0.1f; + float zo = random->nextFloat() * 0.8f + 0.1f; + + while (item->count > 0) + { + int count = random->nextInt(21) + 10; + if (count > item->count) count = item->count; + item->count -= count; + + shared_ptr itemEntity = shared_ptr( new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr( new ItemInstance(item->id, count, item->getAuxValue())))); + + if (item->hasTag()) + { + itemEntity->getItem()->setTag((CompoundTag *) item->getTag()->copy()); + } + + float pow = 0.05f; + itemEntity->xd = (float) random->nextGaussian() * pow; + itemEntity->yd = (float) random->nextGaussian() * pow + 0.2f; + itemEntity->zd = (float) random->nextGaussian() * pow; + level->addEntity(itemEntity); + } + } + } + } + + Minecart::remove(); +} + +void MinecartContainer::addAdditonalSaveData(CompoundTag *base) +{ + Minecart::addAdditonalSaveData(base); + + ListTag *listTag = new ListTag(); + + for (int i = 0; i < items.length; i++) + { + if (items[i] != NULL) + { + CompoundTag *tag = new CompoundTag(); + tag->putByte(L"Slot", (byte) i); + items[i]->save(tag); + listTag->add(tag); + } + } + base->put(L"Items", listTag); +} + +void MinecartContainer::readAdditionalSaveData(CompoundTag *base) +{ + Minecart::readAdditionalSaveData(base); + + ListTag *inventoryList = (ListTag *) base->getList(L"Items"); + delete [] items.data; + items = ItemInstanceArray(getContainerSize()); + for (int i = 0; i < inventoryList->size(); i++) + { + CompoundTag *tag = inventoryList->get(i); + int slot = tag->getByte(L"Slot") & 0xff; + if (slot >= 0 && slot < items.length) items[slot] = ItemInstance::fromTag(tag); + } +} + +bool MinecartContainer::interact(shared_ptr player) +{ + if (!level->isClientSide) + { + player->openContainer( dynamic_pointer_cast(shared_from_this())); + } + + return true; +} + +void MinecartContainer::applyNaturalSlowdown() +{ + shared_ptr container = dynamic_pointer_cast(shared_from_this()); + int emptiness = Redstone::SIGNAL_MAX - AbstractContainerMenu::getRedstoneSignalFromContainer(container); + float keep = 0.98f + (emptiness * 0.001f); + + xd *= keep; + yd *= 0; + zd *= keep; +} \ No newline at end of file diff --git a/Minecraft.World/MinecartContainer.h b/Minecraft.World/MinecartContainer.h new file mode 100644 index 00000000..89517658 --- /dev/null +++ b/Minecraft.World/MinecartContainer.h @@ -0,0 +1,48 @@ +#pragma once + +#include "Minecart.h" +#include "Container.h" + +class MinecartContainer : public Minecart, public virtual Container +{ +private: + ItemInstanceArray items; + bool dropEquipment; + + void _init(); + +public: + MinecartContainer(Level *level); + MinecartContainer(Level *level, double x, double y, double z); + + virtual void destroy(DamageSource *source); + virtual shared_ptr getItem(unsigned int slot); + virtual shared_ptr removeItem(unsigned int slot, int count); + virtual shared_ptr removeItemNoUpdate(int slot); + virtual void setItem(unsigned int slot, shared_ptr item); + virtual void setChanged(); + virtual bool stillValid(shared_ptr player); + virtual void startOpen(); + virtual void stopOpen(); + virtual bool canPlaceItem(int slot, shared_ptr item); + virtual wstring getName(); + virtual int getMaxStackSize(); + virtual void changeDimension(int i); + virtual void remove(); + +protected: + virtual void addAdditonalSaveData(CompoundTag *base); + virtual void readAdditionalSaveData(CompoundTag *base); + +public: + virtual bool interact(shared_ptr player); + +protected: + virtual void applyNaturalSlowdown(); + +public: + + // 4J Stu - For container + virtual bool hasCustomName() { return Minecart::hasCustomName(); } + virtual wstring getCustomName() { return Minecart::getCustomName(); } +}; \ No newline at end of file diff --git a/Minecraft.World/MinecartFurnace.cpp b/Minecraft.World/MinecartFurnace.cpp new file mode 100644 index 00000000..24950d5c --- /dev/null +++ b/Minecraft.World/MinecartFurnace.cpp @@ -0,0 +1,179 @@ +#include "stdafx.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.network.packet.h" +#include "MinecartFurnace.h" + +MinecartFurnace::MinecartFurnace(Level *level) : Minecart(level) +{ + defineSynchedData(); + + fuel = 0; + xPush = zPush = 0.0f; +} + +MinecartFurnace::MinecartFurnace(Level *level, double x, double y, double z) : Minecart(level, x, y, z) +{ + defineSynchedData(); + + fuel = 0; + xPush = zPush = 0.0f; +} + +// 4J Added +int MinecartFurnace::getContainerType() +{ + return ContainerOpenPacket::MINECART_HOPPER; +} + +int MinecartFurnace::getType() +{ + return TYPE_FURNACE; +} + +void MinecartFurnace::defineSynchedData() +{ + Minecart::defineSynchedData(); + entityData->define(DATA_ID_FUEL, (byte) 0); +} + +void MinecartFurnace::tick() +{ + Minecart::tick(); + + if (fuel > 0) + { + fuel--; + } + if (fuel <= 0) + { + xPush = zPush = 0; + } + setHasFuel(fuel > 0); + + if (hasFuel() && random->nextInt(4) == 0) + { + level->addParticle(eParticleType_largesmoke, x, y + 0.8, z, 0, 0, 0); + } +} + +void MinecartFurnace::destroy(DamageSource *source) +{ + Minecart::destroy(source); + + if (!source->isExplosion()) + { + spawnAtLocation(shared_ptr(new ItemInstance(Tile::furnace, 1)), 0); + } +} + +void MinecartFurnace::moveAlongTrack(int xt, int yt, int zt, double maxSpeed, double slideSpeed, int tile, int data) +{ + Minecart::moveAlongTrack(xt, yt, zt, maxSpeed, slideSpeed, tile, data); + + double sd = xPush * xPush + zPush * zPush; + if (sd > 0.01 * 0.01 && xd * xd + zd * zd > 0.001) + { + sd = Mth::sqrt(sd); + xPush /= sd; + zPush /= sd; + + if (xPush * xd + zPush * zd < 0) + { + xPush = 0; + zPush = 0; + } + else + { + xPush = xd; + zPush = zd; + } + } +} + +void MinecartFurnace::applyNaturalSlowdown() +{ + double sd = xPush * xPush + zPush * zPush; + + if (sd > 0.01 * 0.01) + { + sd = Mth::sqrt(sd); + xPush /= sd; + zPush /= sd; + double speed = 0.05; + xd *= 0.8f; + yd *= 0; + zd *= 0.8f; + xd += xPush * speed; + zd += zPush * speed; + } + else + { + xd *= 0.98f; + yd *= 0; + zd *= 0.98f; + } + + Minecart::applyNaturalSlowdown(); +} + +bool MinecartFurnace::interact(shared_ptr player) +{ + shared_ptr selected = player->inventory->getSelected(); + if (selected != NULL && selected->id == Item::coal_Id) + { + if (!player->abilities.instabuild && --selected->count == 0) player->inventory->setItem(player->inventory->selected, nullptr); + fuel += SharedConstants::TICKS_PER_SECOND * 180; + + } + xPush = x - player->x; + zPush = z - player->z; + + return true; +} + +void MinecartFurnace::addAdditonalSaveData(CompoundTag *base) +{ + Minecart::addAdditonalSaveData(base); + base->putDouble(L"PushX", xPush); + base->putDouble(L"PushZ", zPush); + base->putShort(L"Fuel", (short) fuel); +} + +void MinecartFurnace::readAdditionalSaveData(CompoundTag *base) +{ + Minecart::readAdditionalSaveData(base); + xPush = base->getDouble(L"PushX"); + zPush = base->getDouble(L"PushZ"); + fuel = base->getShort(L"Fuel"); +} + +bool MinecartFurnace::hasFuel() +{ + return (entityData->getByte(DATA_ID_FUEL) & 1) != 0; +} + +void MinecartFurnace::setHasFuel(bool fuel) +{ + if (fuel) + { + entityData->set(DATA_ID_FUEL, (byte) (entityData->getByte(DATA_ID_FUEL) | 1)); + } + else + { + entityData->set(DATA_ID_FUEL, (byte) (entityData->getByte(DATA_ID_FUEL) & ~1)); + } +} + +Tile *MinecartFurnace::getDefaultDisplayTile() +{ + return Tile::furnace_lit; +} + +int MinecartFurnace::getDefaultDisplayData() +{ + return 2; +} \ No newline at end of file diff --git a/Minecraft.World/MinecartFurnace.h b/Minecraft.World/MinecartFurnace.h new file mode 100644 index 00000000..aa8bf9e0 --- /dev/null +++ b/Minecraft.World/MinecartFurnace.h @@ -0,0 +1,51 @@ +#pragma once + +#include "Minecart.h" + +class MinecartFurnace : public Minecart +{ +public: + eINSTANCEOF GetType() { return eTYPE_MINECART_FURNACE; }; + static Entity *create(Level *level) { return new MinecartFurnace(level); } + +private: + static const int DATA_ID_FUEL = 16; + +private: + int fuel; + +public: + double xPush, zPush; + + MinecartFurnace(Level *level); + MinecartFurnace(Level *level, double x, double y, double z); + + // 4J added + virtual int getContainerType(); + + int getType(); + +protected: + void defineSynchedData(); + +public: + void tick(); + void destroy(DamageSource *source); + +protected: + void moveAlongTrack(int xt, int yt, int zt, double maxSpeed, double slideSpeed, int tile, int data); + void applyNaturalSlowdown(); + +public: + bool interact(shared_ptr player); + +protected: + void addAdditonalSaveData(CompoundTag *base); + void readAdditionalSaveData(CompoundTag *base); + bool hasFuel(); + void setHasFuel(bool fuel); + +public: + Tile *getDefaultDisplayTile(); + int getDefaultDisplayData(); +}; \ No newline at end of file diff --git a/Minecraft.World/MinecartHopper.cpp b/Minecraft.World/MinecartHopper.cpp new file mode 100644 index 00000000..8bf02f8f --- /dev/null +++ b/Minecraft.World/MinecartHopper.cpp @@ -0,0 +1,165 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.phys.h" +#include "MinecartHopper.h" + +const int MinecartHopper::MOVE_ITEM_SPEED = HopperTileEntity::MOVE_ITEM_SPEED / 2; + +void MinecartHopper::_init() +{ + enabled = true; + cooldownTime = -1; + + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); +} + +MinecartHopper::MinecartHopper(Level *level) : MinecartContainer(level) +{ + _init(); +} + +MinecartHopper::MinecartHopper(Level *level, double x, double y, double z) : MinecartContainer(level, x, y, z) +{ + _init(); +} + +int MinecartHopper::getType() +{ + return TYPE_HOPPER; +} + +Tile *MinecartHopper::getDefaultDisplayTile() +{ + return Tile::hopper; +} + +int MinecartHopper::getDefaultDisplayOffset() +{ + return 1; +} + +unsigned int MinecartHopper::getContainerSize() +{ + return 5; +} + +bool MinecartHopper::interact(shared_ptr player) +{ + if (!level->isClientSide) + { + player->openHopper(dynamic_pointer_cast(shared_from_this())); + } + + return true; +} + +void MinecartHopper::activateMinecart(int xt, int yt, int zt, bool state) +{ + bool newEnabled = !state; + + if (newEnabled != isEnabled()) + { + setEnabled(newEnabled); + } +} + +bool MinecartHopper::isEnabled() +{ + return enabled; +} + +void MinecartHopper::setEnabled(bool enabled) +{ + this->enabled = enabled; +} + +Level *MinecartHopper::getLevel() +{ + return level; +} + +double MinecartHopper::getLevelX() +{ + return x; +} + +double MinecartHopper::getLevelY() +{ + return y; +} + +double MinecartHopper::getLevelZ() +{ + return z; +} + +void MinecartHopper::tick() +{ + MinecartContainer::tick(); + + if (!level->isClientSide && isAlive() && isEnabled()) + { + cooldownTime--; + if (!isOnCooldown()) + { + setCooldown(0); + + if (suckInItems()) + { + setCooldown(MOVE_ITEM_SPEED); + MinecartContainer::setChanged(); + } + } + } +} + +bool MinecartHopper::suckInItems() +{ + if (HopperTileEntity::suckInItems(this)) return true; + + vector > *items = level->getEntitiesOfClass(typeid(ItemEntity), bb->grow(0.25f, 0, 0.25f), EntitySelector::ENTITY_STILL_ALIVE); + + if (items->size() > 0) + { + HopperTileEntity::addItem( this, dynamic_pointer_cast(items->at(0)) ); + } + delete items; + + return false; +} + +void MinecartHopper::destroy(DamageSource *source) +{ + MinecartContainer::destroy(source); + + spawnAtLocation(Tile::hopper_Id, 1, 0); +} + +void MinecartHopper::addAdditonalSaveData(CompoundTag *base) +{ + MinecartContainer::addAdditonalSaveData(base); + base->putInt(L"TransferCooldown", cooldownTime); +} + +void MinecartHopper::readAdditionalSaveData(CompoundTag *base) +{ + MinecartContainer::readAdditionalSaveData(base); + cooldownTime = base->getInt(L"TransferCooldown"); +} + +void MinecartHopper::setCooldown(int time) +{ + cooldownTime = time; +} + +bool MinecartHopper::isOnCooldown() +{ + return cooldownTime > 0; +} \ No newline at end of file diff --git a/Minecraft.World/MinecartHopper.h b/Minecraft.World/MinecartHopper.h new file mode 100644 index 00000000..874bab6a --- /dev/null +++ b/Minecraft.World/MinecartHopper.h @@ -0,0 +1,64 @@ +#pragma once + +#include "MinecartContainer.h" +#include "Hopper.h" + +class MinecartHopper : public MinecartContainer, public Hopper +{ +public: + eINSTANCEOF GetType() { return eTYPE_MINECART_HOPPER; }; + static Entity *create(Level *level) { return new MinecartHopper(level); } + +public: + static const int MOVE_ITEM_SPEED; + +private: + bool enabled; + int cooldownTime; + + void _init(); + +public: + MinecartHopper(Level *level); + MinecartHopper(Level *level, double x, double y, double z); + + virtual int getType(); + virtual Tile *getDefaultDisplayTile(); + virtual int getDefaultDisplayOffset(); + virtual unsigned int getContainerSize(); + virtual bool interact(shared_ptr player); + virtual void activateMinecart(int xt, int yt, int zt, bool state); + virtual bool isEnabled(); + virtual void setEnabled(bool enabled); + virtual Level *getLevel(); + virtual double getLevelX(); + virtual double getLevelY(); + virtual double getLevelZ(); + virtual void tick(); + virtual bool suckInItems(); + virtual void destroy(DamageSource *source); + +protected: + virtual void addAdditonalSaveData(CompoundTag *base); + virtual void readAdditionalSaveData(CompoundTag *base); + +public: + void setCooldown(int time); + bool isOnCooldown(); + + // 4J For Hopper + virtual shared_ptr getItem(unsigned int slot) { return MinecartContainer::getItem(slot); } + virtual shared_ptr removeItem(unsigned int slot, int count) { return MinecartContainer::removeItem(slot, count); } + virtual shared_ptr removeItemNoUpdate(int slot) { return MinecartContainer::removeItemNoUpdate(slot); } + virtual void setItem(unsigned int slot, shared_ptr item) { MinecartContainer::setItem(slot, item); } + virtual wstring getName() { return MinecartContainer::getName(); } + virtual wstring getCustomName() { return MinecartContainer::getCustomName(); } + virtual bool hasCustomName() { return MinecartContainer::hasCustomName(); } + virtual int getMaxStackSize() { return MinecartContainer::getMaxStackSize(); } + + virtual void setChanged() { MinecartContainer::setChanged(); } + virtual bool stillValid(shared_ptr player) { return MinecartContainer::stillValid(player); } + virtual void startOpen() { MinecartContainer::startOpen(); } + virtual void stopOpen() { MinecartContainer::stopOpen(); } + virtual bool canPlaceItem(int slot, shared_ptr item) { return MinecartContainer::canPlaceItem(slot, item); } +}; \ No newline at end of file diff --git a/Minecraft.World/MinecartItem.cpp b/Minecraft.World/MinecartItem.cpp index 3b062ccf..6100be65 100644 --- a/Minecraft.World/MinecartItem.cpp +++ b/Minecraft.World/MinecartItem.cpp @@ -6,10 +6,68 @@ #include "ItemInstance.h" #include "MinecartItem.h" + +shared_ptr MinecartItem::MinecartDispenseBehavior::execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome) +{ + FacingEnum *facing = DispenserTile::getFacing(source->getData()); + Level *world = source->getWorld(); + + // Spawn the minecart 'just' outside the dispenser, it overlaps 2 'pixels' now. + // Also at half-block-height so it can connect with sloped rails + double spawnX = source->getX() + facing->getStepX() * (1 + 2.0f / 16); + double spawnY = source->getY() + facing->getStepY() * (1 + 2.0f / 16); + double spawnZ = source->getZ() + facing->getStepZ() * (1 + 2.0f / 16); + + int frontX = source->getBlockX() + facing->getStepX(); + int frontY = source->getBlockY() + facing->getStepY(); + int frontZ = source->getBlockZ() + facing->getStepZ(); + int inFront = world->getTile(frontX, frontY, frontZ); + + // 4J: If we're at limit, just dispense item (instead of adding minecart) + if (world->countInstanceOf(eTYPE_MINECART, false) >= Level::MAX_CONSOLE_MINECARTS) + { + outcome = DISPENCED_ITEM; + return defaultDispenseItemBehavior.dispense(source, dispensed); + } + + double yOffset; + if (BaseRailTile::isRail(inFront)) + { + yOffset = 0; + } + else if (inFront == 0 && BaseRailTile::isRail(world->getTile(frontX, frontY - 1, frontZ))) + { + yOffset = -1; + } + else + { + outcome = DISPENCED_ITEM; + return defaultDispenseItemBehavior.dispense(source, dispensed); + } + + outcome = ACTIVATED_ITEM; + + shared_ptr minecart = Minecart::createMinecart(world, spawnX, spawnY + yOffset, spawnZ, ((MinecartItem *) dispensed->getItem())->type); + if (dispensed->hasCustomHoverName()) + { + minecart->setCustomName(dispensed->getHoverName()); + } + world->addEntity(minecart); + + dispensed->remove(1); + return dispensed; +} + +void MinecartItem::MinecartDispenseBehavior::playSound(BlockSource *source) +{ + source->getWorld()->levelEvent(LevelEvent::SOUND_CLICK, source->getBlockX(), source->getBlockY(), source->getBlockZ(), 0); +} + MinecartItem::MinecartItem(int id, int type) : Item(id) { - this->maxStackSize = 1; + maxStackSize = 1; this->type = type; + DispenserTile::REGISTRY.add(this, new MinecartDispenseBehavior()); } bool MinecartItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) @@ -17,13 +75,18 @@ bool MinecartItem::useOn(shared_ptr instance, shared_ptr p // 4J-PB - Adding a test only version to allow tooltips to be displayed int targetType = level->getTile(x, y, z); - if (RailTile::isRail(targetType)) + if (BaseRailTile::isRail(targetType)) { if(!bTestUseOnOnly) { if (!level->isClientSide) { - level->addEntity(shared_ptr( new Minecart(level, x + 0.5f, y + 0.5f, z + 0.5f, type) ) ); + shared_ptr cart = Minecart::createMinecart(level, x + 0.5f, y + 0.5f, z + 0.5f, type); + if (instance->hasCustomHoverName()) + { + cart->setCustomName(instance->getHoverName()); + } + level->addEntity(cart); } instance->count--; } diff --git a/Minecraft.World/MinecartItem.h b/Minecraft.World/MinecartItem.h index c63082a1..ed06ff1f 100644 --- a/Minecraft.World/MinecartItem.h +++ b/Minecraft.World/MinecartItem.h @@ -2,9 +2,23 @@ using namespace std; #include "Item.h" +#include "DefaultDispenseItemBehavior.h" class MinecartItem : public Item { +private: + class MinecartDispenseBehavior : public DefaultDispenseItemBehavior + { + private: + DefaultDispenseItemBehavior defaultDispenseItemBehavior; + + public: + virtual shared_ptr execute(BlockSource *source, shared_ptr dispensed, eOUTCOME &outcome); + + protected: + virtual void playSound(BlockSource *source); + }; + public: int type; diff --git a/Minecraft.World/MinecartRideable.cpp b/Minecraft.World/MinecartRideable.cpp new file mode 100644 index 00000000..a006a2bc --- /dev/null +++ b/Minecraft.World/MinecartRideable.cpp @@ -0,0 +1,39 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "MinecartRideable.h" + + +MinecartRideable::MinecartRideable(Level *level) : Minecart(level) +{ + + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); +} + +MinecartRideable::MinecartRideable(Level *level, double x, double y, double z) : Minecart(level, x, y, z) +{ + + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); +} + +bool MinecartRideable::interact(shared_ptr player) +{ + if (rider.lock() != NULL && rider.lock()->instanceof(eTYPE_PLAYER) && rider.lock() != player) return true; + if (rider.lock() != NULL && rider.lock() != player) return false; + if (!level->isClientSide) + { + player->ride(shared_from_this()); + } + + return true; +} + +int MinecartRideable::getType() +{ + return TYPE_RIDEABLE; +} \ No newline at end of file diff --git a/Minecraft.World/MinecartRideable.h b/Minecraft.World/MinecartRideable.h new file mode 100644 index 00000000..e6156acc --- /dev/null +++ b/Minecraft.World/MinecartRideable.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Minecart.h" + +class MinecartRideable : public Minecart +{ +public: + eINSTANCEOF GetType() { return eTYPE_MINECART_RIDEABLE; }; + static Entity *create(Level *level) { return new MinecartRideable(level); } + +public: + MinecartRideable(Level *level); + MinecartRideable(Level *level, double x, double y, double z); + + virtual bool interact(shared_ptr player); + virtual int getType(); +}; \ No newline at end of file diff --git a/Minecraft.World/MinecartSpawner.cpp b/Minecraft.World/MinecartSpawner.cpp new file mode 100644 index 00000000..3fcd4ef0 --- /dev/null +++ b/Minecraft.World/MinecartSpawner.cpp @@ -0,0 +1,95 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "MinecartSpawner.h" + +MinecartSpawner::MinecartMobSpawner::MinecartMobSpawner(MinecartSpawner *parent) +{ + m_parent = parent; +} + +void MinecartSpawner::MinecartMobSpawner::broadcastEvent(int id) +{ + m_parent->level->broadcastEntityEvent(m_parent->shared_from_this(), (byte) id); +} + +Level *MinecartSpawner::MinecartMobSpawner::getLevel() +{ + return m_parent->level; +} + +int MinecartSpawner::MinecartMobSpawner::getX() +{ + return Mth::floor(m_parent->x); +} + +int MinecartSpawner::MinecartMobSpawner::getY() +{ + return Mth::floor(m_parent->y); +} + +int MinecartSpawner::MinecartMobSpawner::getZ() +{ + return Mth::floor(m_parent->z); +} + +MinecartSpawner::MinecartSpawner(Level *level) : Minecart(level) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); + + spawner = new MinecartMobSpawner(this); +} + +MinecartSpawner::MinecartSpawner(Level *level, double x, double y, double z) : Minecart(level, x, y, z) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); + + spawner = new MinecartMobSpawner(this); +} + +MinecartSpawner::~MinecartSpawner() +{ + delete spawner; +} + +int MinecartSpawner::getType() +{ + return TYPE_SPAWNER; +} + +Tile *MinecartSpawner::getDefaultDisplayTile() +{ + return Tile::mobSpawner; +} + +void MinecartSpawner::readAdditionalSaveData(CompoundTag *tag) +{ + Minecart::readAdditionalSaveData(tag); + spawner->load(tag); +} + +void MinecartSpawner::addAdditonalSaveData(CompoundTag *tag) +{ + Minecart::addAdditonalSaveData(tag); + spawner->save(tag); +} + +void MinecartSpawner::handleEntityEvent(byte eventId) +{ + spawner->onEventTriggered(eventId); +} + +void MinecartSpawner::tick() +{ + Minecart::tick(); + spawner->tick(); +} + +BaseMobSpawner *MinecartSpawner::getSpawner() +{ + return spawner; +} \ No newline at end of file diff --git a/Minecraft.World/MinecartSpawner.h b/Minecraft.World/MinecartSpawner.h new file mode 100644 index 00000000..a0b7944f --- /dev/null +++ b/Minecraft.World/MinecartSpawner.h @@ -0,0 +1,45 @@ +#pragma once + +#include "Minecart.h" +#include "BaseMobSpawner.h" + +class MinecartSpawner : public Minecart +{ +public: + eINSTANCEOF GetType() { return eTYPE_MINECART_SPAWNER; }; + static Entity *create(Level *level) { return new MinecartSpawner(level); } + +private: + BaseMobSpawner *spawner; + + class MinecartMobSpawner : public BaseMobSpawner + { + private: + MinecartSpawner *m_parent; + + public: + MinecartMobSpawner(MinecartSpawner *parent); + void broadcastEvent(int id); + Level *getLevel(); + int getX(); + int getY(); + int getZ(); + }; + +public: + MinecartSpawner(Level *level); + MinecartSpawner(Level *level, double x, double y, double z); + virtual ~MinecartSpawner(); + + virtual int getType(); + virtual Tile *getDefaultDisplayTile(); + +protected: + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *tag); + +public: + virtual void handleEntityEvent(byte eventId); + virtual void tick(); + virtual BaseMobSpawner *getSpawner(); +}; \ No newline at end of file diff --git a/Minecraft.World/MinecartTNT.cpp b/Minecraft.World/MinecartTNT.cpp new file mode 100644 index 00000000..26cac5cf --- /dev/null +++ b/Minecraft.World/MinecartTNT.cpp @@ -0,0 +1,168 @@ +#include "stdafx.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "MinecartTNT.h" + +void MinecartTNT::_init() +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); + + fuse = -1; +} + +MinecartTNT::MinecartTNT(Level *level) : Minecart(level) +{ + _init(); +} + +MinecartTNT::MinecartTNT(Level *level, double x, double y, double z) : Minecart(level, x, y, z) +{ + _init(); +} + +int MinecartTNT::getType() +{ + return TYPE_TNT; +} + +Tile *MinecartTNT::getDefaultDisplayTile() +{ + return Tile::tnt; +} + +void MinecartTNT::tick() +{ + Minecart::tick(); + + if (fuse > 0) + { + fuse--; + level->addParticle(eParticleType_smoke, x, y + 0.5f, z, 0, 0, 0); + } + else if (fuse == 0) + { + explode(xd * xd + zd * zd); + } + + if (horizontalCollision) + { + double speedSqr = xd * xd + zd * zd; + + if (speedSqr >= 0.01f) + { + explode(speedSqr); + } + } +} + +void MinecartTNT::destroy(DamageSource *source) +{ + Minecart::destroy(source); + + double speedSqr = xd * xd + zd * zd; + + if (!source->isExplosion()) + { + spawnAtLocation( shared_ptr( new ItemInstance(Tile::tnt, 1) ), 0); + } + + if (source->isFire() || source->isExplosion() || speedSqr >= 0.01f) + { + explode(speedSqr); + } +} + +void MinecartTNT::explode(double speedSqr) +{ + if (!level->isClientSide) + { + double speed = sqrt(speedSqr); + if (speed > 5) speed = 5; + level->explode(shared_from_this(), x, y, z, (float) (4 + random->nextDouble() * 1.5f * speed), true); + remove(); + } +} + +void MinecartTNT::causeFallDamage(float distance) +{ + if (distance >= 3) + { + float power = distance / 10; + explode(power * power); + } + + Minecart::causeFallDamage(distance); +} + +void MinecartTNT::activateMinecart(int xt, int yt, int zt, bool state) +{ + if (state && fuse < 0) + { + primeFuse(); + } +} + +void MinecartTNT::handleEntityEvent(byte eventId) +{ + if (eventId == EVENT_PRIME) + { + primeFuse(); + } + else + { + Minecart::handleEntityEvent(eventId); + } +} + +void MinecartTNT::primeFuse() +{ + fuse = 80; + + if (!level->isClientSide) + { + level->broadcastEntityEvent(shared_from_this(), EVENT_PRIME); + level->playEntitySound(shared_from_this(), eSoundType_RANDOM_FUSE, 1, 1.0f); + } +} + +int MinecartTNT::getFuse() +{ + return fuse; +} + +bool MinecartTNT::isPrimed() +{ + return fuse > -1; +} + +float MinecartTNT::getTileExplosionResistance(Explosion *explosion, Level *level, int x, int y, int z, Tile *tile) +{ + if (isPrimed() && (BaseRailTile::isRail(tile->id) || BaseRailTile::isRail(level, x, y + 1, z))) + { + return 0; + } + + return Minecart::getTileExplosionResistance(explosion, level, x, y, z, tile); +} + +bool MinecartTNT::shouldTileExplode(Explosion *explosion, Level *level, int x, int y, int z, int id, float power) +{ + if (isPrimed() && (BaseRailTile::isRail(id) || BaseRailTile::isRail(level, x, y + 1, z))) return false; + + return Minecart::shouldTileExplode(explosion, level, x, y, z, id, power); +} + +void MinecartTNT::readAdditionalSaveData(CompoundTag *tag) +{ + Minecart::readAdditionalSaveData(tag); + if (tag->contains(L"TNTFuse")) fuse = tag->getInt(L"TNTFuse"); +} + +void MinecartTNT::addAdditonalSaveData(CompoundTag *tag) +{ + Minecart::addAdditonalSaveData(tag); + tag->putInt(L"TNTFuse", fuse); +} \ No newline at end of file diff --git a/Minecraft.World/MinecartTNT.h b/Minecraft.World/MinecartTNT.h new file mode 100644 index 00000000..8637803c --- /dev/null +++ b/Minecraft.World/MinecartTNT.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Minecart.h" + +class MinecartTNT : public Minecart +{ +public: + eINSTANCEOF GetType() { return eTYPE_MINECART_TNT; }; + static Entity *create(Level *level) { return new MinecartTNT(level); } + +private: + static const byte EVENT_PRIME = 10; + + int fuse; + + void _init(); + +public: + MinecartTNT(Level *level); + MinecartTNT(Level *level, double x, double y, double z); + + virtual int getType(); + virtual Tile *getDefaultDisplayTile(); + virtual void tick(); + virtual void destroy(DamageSource *source); + +protected: + virtual void explode(double speedSqr); + virtual void causeFallDamage(float distance); + +public: + virtual void activateMinecart(int xt, int yt, int zt, bool state); + virtual void handleEntityEvent(byte eventId); + virtual void primeFuse(); + virtual int getFuse(); + virtual bool isPrimed(); + virtual float getTileExplosionResistance(Explosion *explosion, Level *level, int x, int y, int z, Tile *tile); + virtual bool shouldTileExplode(Explosion *explosion, Level *level, int x, int y, int z, int id, float power); + +protected: + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *tag); +}; \ No newline at end of file diff --git a/Minecraft.World/Minecraft.World.cpp b/Minecraft.World/Minecraft.World.cpp index 30495443..1ee6eb47 100644 --- a/Minecraft.World/Minecraft.World.cpp +++ b/Minecraft.World/Minecraft.World.cpp @@ -1,43 +1,21 @@ #include "stdafx.h" -#include "Packet.h" -#include "MaterialColor.h" -#include "Material.h" -#include "Tile.h" -#include "HatchetItem.h" -#include "PickaxeItem.h" -#include "ShovelItem.h" -#include "BlockReplacements.h" -#include "Biome.h" -#include "Item.h" -#include "FurnaceRecipes.h" -#include "Recipes.h" -#include "Stats.h" -#include "Achievements.h" -#include "Skeleton.h" -#include "PigZombie.h" -#include "TileEntity.h" -#include "EntityIO.h" -#include "SharedConstants.h" -#include "MobCategory.h" -#include "LevelChunk.h" -#include "MineShaftPieces.h" -#include "StrongholdFeature.h" -#include "VillageFeature.h" -#include "LevelType.h" -#include "EnderMan.h" -#include "PotionBrewing.h" -#include "Enchantment.h" -#include "VillagePieces.h" -#include "RandomScatteredLargeFeature.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.item.alchemy.h" +#include "net.minecraft.world.item.crafting.h" +#include "net.minecraft.world.item.enchantment.h" +#include "net.minecraft.world.level.chunk.h" +#include "net.minecraft.world.level.chunk.storage.h" +#include "net.minecraft.world.level.levelgen.structure.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.entity.npc.h" +#include "net.minecraft.world.effect.h" #include "Minecraft.World.h" #include "..\Minecraft.Client\ServerLevel.h" -#include "SparseLightStorage.h" -#include "SparseDataStorage.h" -#include "McRegionChunkStorage.h" -#include "Villager.h" -#include "LevelSettings.h" #ifdef _DURANGO #include "DurangoStats.h" @@ -60,7 +38,8 @@ void MinecraftWorld_RunStaticCtors() PickaxeItem::staticCtor(); ShovelItem::staticCtor(); BlockReplacements::staticCtor(); - Biome::staticCtor(); + Biome::staticCtor(); + MobEffect::staticCtor(); Item::staticCtor(); FurnaceRecipes::staticCtor(); Recipes::staticCtor(); @@ -71,8 +50,6 @@ void MinecraftWorld_RunStaticCtors() Stats::staticCtor(); #endif //Achievements::staticCtor(); // 4J Stu - This is now called from within the Stats::staticCtor() - Skeleton::staticCtor(); - PigZombie::staticCtor(); TileEntity::staticCtor(); EntityIO::staticCtor(); MobCategory::staticCtor(); @@ -82,11 +59,15 @@ void MinecraftWorld_RunStaticCtors() LevelType::staticCtor(); - MineShaftPieces::staticCtor(); - StrongholdFeature::staticCtor(); - VillagePieces::Smithy::staticCtor(); - VillageFeature::staticCtor(); - RandomScatteredLargeFeature::staticCtor(); + { + StructureFeatureIO::staticCtor(); + + MineShaftPieces::staticCtor(); + StrongholdFeature::staticCtor(); + VillagePieces::Smithy::staticCtor(); + VillageFeature::staticCtor(); + RandomScatteredLargeFeature::staticCtor(); + } } EnderMan::staticCtor(); PotionBrewing::staticCtor(); @@ -101,4 +82,5 @@ void MinecraftWorld_RunStaticCtors() McRegionChunkStorage::staticCtor(); Villager::staticCtor(); GameType::staticCtor(); + BeaconTileEntity::staticCtor(); } diff --git a/Minecraft.World/Minecraft.World.vcxproj b/Minecraft.World/Minecraft.World.vcxproj index 5146b56c..eeef292f 100644 --- a/Minecraft.World/Minecraft.World.vcxproj +++ b/Minecraft.World/Minecraft.World.vcxproj @@ -17,6 +17,10 @@ ContentPackage_NO_TU PSVita + + ContentPackage_NO_TU + Win32 + ContentPackage_NO_TU x64 @@ -41,6 +45,10 @@ CONTENTPACKAGE_SYMBOLS PSVita + + CONTENTPACKAGE_SYMBOLS + Win32 + CONTENTPACKAGE_SYMBOLS x64 @@ -65,6 +73,10 @@ ContentPackage_Vita PSVita + + ContentPackage_Vita + Win32 + ContentPackage_Vita x64 @@ -89,6 +101,10 @@ ContentPackage PSVita + + ContentPackage + Win32 + ContentPackage x64 @@ -113,6 +129,10 @@ Debug PSVita + + Debug + Win32 + Debug x64 @@ -137,6 +157,10 @@ ReleaseForArt PSVita + + ReleaseForArt + Win32 + ReleaseForArt x64 @@ -161,6 +185,10 @@ Release PSVita + + Release + Win32 + Release x64 @@ -179,7 +207,6 @@ SAK SAK title - 10.0 @@ -232,7 +259,11 @@ StaticLibrary MultiByte v143 - 10.0 + + + StaticLibrary + MultiByte + v143 StaticLibrary @@ -243,13 +274,22 @@ StaticLibrary MultiByte v143 - 10.0 + + + StaticLibrary + MultiByte + v143 StaticLibrary MultiByte v143 + + StaticLibrary + MultiByte + v143 + StaticLibrary Unicode @@ -323,21 +363,41 @@ MultiByte v143 + + StaticLibrary + MultiByte + v143 + StaticLibrary MultiByte v143 + + StaticLibrary + MultiByte + v143 + StaticLibrary MultiByte v143 + + StaticLibrary + MultiByte + v143 + StaticLibrary MultiByte v143 + + StaticLibrary + MultiByte + v143 + StaticLibrary Unicode @@ -361,7 +421,7 @@ StaticLibrary MultiByte - v110 + v143 Clang @@ -424,15 +484,24 @@ + + + + + + + + + @@ -478,15 +547,27 @@ + + + + + + + + + + + + @@ -518,7 +599,7 @@ $(OutDir)$(ProjectName).lib - $(SCE_PSP2_SDK_DIR)/target\src\npToolkit\include;$(ProjectDir)\..\Minecraft.Client\PSVita\PSVitaExtras;$(ProjectDir)..\Minecraft.World\x64headers;$(IncludePath) + $(SCE_PSP2_SDK_DIR)/target\src\npToolkit\include;$(ProjectDir)..\Minecraft.Client\PSVita\Assert;$(ProjectDir)\..\Minecraft.Client\PSVita\PSVitaExtras;$(ProjectDir)..\Minecraft.World\x64headers;$(IncludePath) $(OutDir)$(ProjectName).lib @@ -530,7 +611,7 @@ $(OutDir)$(ProjectName).lib - $(SCE_PSP2_SDK_DIR)/target\src\npToolkit\include;$(MINECRAFT_CONSOLES_DIR)\Minecraft.Client\PSVita\Assert;$(ProjectDir)\..\Minecraft.Client\PSVita\PSVitaExtras;$(ProjectDir)..\Minecraft.World\x64headers;$(IncludePath) + $(SCE_PSP2_SDK_DIR)/target\src\npToolkit\include;$(ProjectDir)\..\Minecraft.Client\PSVita\PSVitaExtras;$(ProjectDir)..\Minecraft.World\x64headers;$(IncludePath) $(OutDir)$(ProjectName).lib @@ -542,6 +623,12 @@ $(ProjectDir)\$(Platform)_$(Configuration)\ $(Platform)_$(Configuration)\ + + $(OutDir)$(ProjectName).lib + $(ProjectDir)\x64headers;$(IncludePath) + $(ProjectDir)\$(Platform)_$(Configuration)\ + $(Platform)_$(Configuration)\ + $(OutDir)$(ProjectName).lib $(ProjectDir)..\Minecraft.Client\Durango\DurangoExtras;$(ProjectDir)\x64headers;$(Console_SdkIncludeRoot) @@ -558,12 +645,24 @@ $(ProjectDir)\$(Platform)_$(Configuration)\ $(Platform)_$(Configuration)\ + + $(OutDir)$(ProjectName).lib + $(ProjectDir)\x64headers;$(IncludePath) + $(ProjectDir)\$(Platform)_$(Configuration)\ + $(Platform)_$(Configuration)\ + $(OutDir)$(ProjectName).lib $(ProjectDir)\x64headers;$(IncludePath) $(ProjectDir)\$(Platform)_$(Configuration)\ $(Platform)_$(Configuration)\ + + $(OutDir)$(ProjectName).lib + $(ProjectDir)\x64headers;$(IncludePath) + $(ProjectDir)\$(Platform)_$(Configuration)\ + $(Platform)_$(Configuration)\ + $(OutDir)$(ProjectName).lib $(ProjectDir)..\Minecraft.Client\Durango\DurangoExtras;$(ProjectDir)\x64headers;$(Console_SdkIncludeRoot) @@ -602,7 +701,7 @@ $(OutDir)$(ProjectName).lib - $(SCE_PSP2_SDK_DIR)/target\src\npToolkit\include;$(ProjectDir)\..\Minecraft.Client\PSVita\PSVitaExtras;$(ProjectDir)..\Minecraft.World\x64headers;$(IncludePath) + $(SCE_PSP2_SDK_DIR)/target\src\npToolkit\include;$(ProjectDir)..\Minecraft.Client\PSVita\Assert;$(ProjectDir)\..\Minecraft.Client\PSVita\PSVitaExtras;$(ProjectDir)..\Minecraft.World\x64headers;$(IncludePath) $(OutDir)$(ProjectName).lib @@ -633,24 +732,46 @@ $(ProjectDir)\$(Platform)_$(Configuration)\ $(Platform)_$(Configuration)\ + + $(OutDir)$(ProjectName).lib + $(ProjectDir)\x64header;$(DXSDK_DIR)include;$(IncludePath) + $(ProjectDir)\$(Platform)_$(Configuration)\ + $(Platform)_$(Configuration)\ + $(OutDir)$(ProjectName).lib $(ProjectDir)\x64header;$(DXSDK_DIR)include;$(IncludePath) $(ProjectDir)\$(Platform)_$(Configuration)\ $(Platform)_$(Configuration)\ + + $(OutDir)$(ProjectName).lib + $(ProjectDir)\x64header;$(DXSDK_DIR)include;$(IncludePath) + $(ProjectDir)\$(Platform)_$(Configuration)\ + $(Platform)_$(Configuration)\ + $(OutDir)$(ProjectName).lib $(ProjectDir)\x64header;$(DXSDK_DIR)include;$(IncludePath) $(ProjectDir)\$(Platform)_$(Configuration)\ $(Platform)_$(Configuration)\ + + $(OutDir)$(ProjectName).lib + $(ProjectDir)\x64header;$(DXSDK_DIR)include;$(IncludePath) + $(ProjectDir)\$(Platform)_$(Configuration)\ + $(Platform)_$(Configuration)\ + $(OutDir)$(ProjectName).lib $(ProjectDir)\x64header;$(DXSDK_DIR)include;$(IncludePath) $(ProjectDir)\$(Configuration)\ $(ProjectDir)\$(Configuration)\ + + $(OutDir)$(ProjectName).lib + $(ProjectDir)\x64header;$(DXSDK_DIR)include;$(IncludePath) + $(OutDir)$(ProjectName).lib $(ProjectDir)\x64headers;$(Console_SdkIncludeRoot) @@ -1016,6 +1137,28 @@ true + + + Use + Level3 + ProgramDatabase + Disabled + Sync + false + $(OutDir)$(ProjectName).pch + MultiThreadedDebug + _LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_DEBUG;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) + Disabled + true + false + false + true + Default + + + true + + Use @@ -1026,7 +1169,7 @@ true $(OutDir)$(ProjectName).pch MultiThreadedDebugDLL - SPLIT_SAVES;_LARGE_WORLDS;_EXTENDED_ACHIEVEMENTS;UNICODE;_UNICODE;__WRL_NO_DEFAULT_LIB__;WINAPI_FAMILY=WINAPI_FAMILY_TV_TITLE;WIN32_LEAN_AND_MEAN;_XM_AVX_INTRINSICS_;_DEBUG_MENUS_ENABLED;_DEBUG;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_DURANGO;%(PreprocessorDefinitions) + SPLIT_SAVES;_LARGE_WORLDS;_EXTENDED_ACHIEVEMENTS;UNICODE;_UNICODE;__WRL_NO_DEFAULT_LIB__;WINAPI_FAMILY=WINAPI_FAMILY_TV_TITLE;WIN32_LEAN_AND_MEAN;_XM_AVX_INTRINSICS_;_DEBUG_MENUS_ENABLED;_DEBUG;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_DURANGO;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions) Disabled true false @@ -1067,6 +1210,29 @@ true + + + Use + Level3 + ProgramDatabase + Full + Sync + false + $(OutDir)$(ProjectName).pch + MultiThreaded + _LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) + Disabled + true + false + false + true + Default + Speed + + + true + + Use @@ -1090,6 +1256,29 @@ true + + + Use + Level3 + ProgramDatabase + Full + Sync + false + $(OutDir)$(ProjectName).pch + MultiThreaded + _LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64;%(PreprocessorDefinitions) + Disabled + true + false + false + true + Default + Speed + + + true + + Use @@ -1414,6 +1603,7 @@ true Level2 Branchless2 + Cpp11 true @@ -1494,6 +1684,29 @@ true + + + Level3 + Use + Full + true + true + ProgramDatabase + Speed + Sync + false + $(OutDir)$(ProjectName).pch + MultiThreaded + _TU_BUILD;_FINAL_BUILD;NDEBUG;_XBOX;_LIB;_CONTENT_PACKAGE;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + + + true + true + true + + Level3 @@ -1517,6 +1730,29 @@ true + + + Level3 + Use + Full + true + true + ProgramDatabase + Speed + Sync + false + $(OutDir)$(ProjectName).pch + MultiThreaded + _TU_BUILD;_FINAL_BUILD;NDEBUG;_XBOX;_LIB;_CONTENT_PACKAGE;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + + + true + true + true + + Level3 @@ -1540,6 +1776,29 @@ true + + + Level3 + Use + Full + true + true + ProgramDatabase + Speed + Sync + false + $(OutDir)$(ProjectName).pch + MultiThreaded + _TU_BUILD;_FINAL_BUILD;NDEBUG;_XBOX;_LIB;_CONTENT_PACKAGE;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + + + true + true + true + + Level3 @@ -1563,6 +1822,29 @@ true + + + Level3 + Use + Full + true + true + ProgramDatabase + Speed + Sync + false + $(OutDir)$(ProjectName).pch + MultiThreaded + _TU_BUILD;_FINAL_BUILD;NDEBUG;_XBOX;_LIB;_CONTENT_PACKAGE;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + + + true + true + true + + Level3 @@ -1770,7 +2052,9 @@ Document + + @@ -1780,6 +2064,7 @@ + @@ -1795,7 +2080,9 @@ + + @@ -1805,20 +2092,32 @@ - + + + + + + + + + + + + + @@ -1832,6 +2131,8 @@ + + @@ -1839,7 +2140,47 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1878,6 +2219,8 @@ + + @@ -1887,50 +2230,6 @@ - - false - false - false - false - false - false - false - false - false - false - false - false - false - false - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - @@ -1938,6 +2237,8 @@ + + @@ -1945,6 +2246,7 @@ + @@ -1978,8 +2280,10 @@ true true true + true + @@ -2001,9 +2305,12 @@ + + + @@ -2013,7 +2320,9 @@ + + @@ -2025,6 +2334,7 @@ + @@ -2040,7 +2350,12 @@ + + + + + @@ -2055,13 +2370,37 @@ + - + + + + + + + + + + + + + + + + + + + + + + + + @@ -2069,6 +2408,7 @@ + @@ -2076,6 +2416,7 @@ + @@ -2084,72 +2425,107 @@ - + + - - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2162,6 +2538,8 @@ false + + @@ -2172,14 +2550,12 @@ - - @@ -2260,8 +2636,7 @@ - - + @@ -2330,7 +2705,7 @@ - + @@ -2386,9 +2761,9 @@ - + - + @@ -2457,7 +2832,7 @@ - + @@ -2477,7 +2852,7 @@ - + @@ -2542,16 +2917,66 @@ - + - + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + - + @@ -2584,7 +3009,7 @@ - + @@ -2614,7 +3039,6 @@ - @@ -2669,7 +3093,6 @@ - @@ -2709,6 +3132,7 @@ + @@ -2723,7 +3147,9 @@ + + @@ -2732,17 +3158,27 @@ - + + + + + + + + + + + @@ -2759,14 +3195,50 @@ + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2801,9 +3273,12 @@ false + false false false + false false + false false false @@ -2817,12 +3292,37 @@ - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2837,51 +3337,6 @@ - - false - false - false - false - false - false - false - false - false - false - false - false - false - false - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - true - - @@ -2895,7 +3350,10 @@ + + + true true @@ -2926,21 +3384,47 @@ true true true + true true + true true + true true + true true + true true + true true + true + + + + + + + + + + + + + + + + + + + @@ -3044,7 +3528,7 @@ - + @@ -3057,7 +3541,7 @@ - + @@ -3066,8 +3550,8 @@ - - + + @@ -3086,7 +3570,7 @@ - + @@ -3111,6 +3595,7 @@ + @@ -3118,6 +3603,9 @@ + + + false @@ -3139,13 +3627,11 @@ - - @@ -3180,7 +3666,7 @@ - + @@ -3235,9 +3721,9 @@ - + - + @@ -3276,9 +3762,12 @@ false + false false false + false false + false false false @@ -3290,7 +3779,7 @@ - + @@ -3320,9 +3809,13 @@ true true true + true true + true true + true true + true true true true @@ -3338,9 +3831,12 @@ true true true + true true true + true true + true true true true @@ -3365,9 +3861,13 @@ true true true + true true + true true + true true + true true true true @@ -3383,9 +3883,12 @@ true true true + true true true + true true + true true true true @@ -3410,9 +3913,13 @@ true true true + true true + true true + true true + true true true true @@ -3428,9 +3935,12 @@ true true true + true true true + true true + true true true true @@ -3464,7 +3974,7 @@ - + @@ -3481,9 +3991,13 @@ true true true + true true + true true + true true + true true true true @@ -3499,9 +4013,12 @@ true true true + true true true + true true + true true true true @@ -3550,14 +4067,64 @@ - + - + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + - + @@ -3593,7 +4160,7 @@ - + @@ -3606,9 +4173,12 @@ false + false false false + false false + false false false @@ -3628,9 +4198,12 @@ true true true + true true true + true true + true true true true @@ -3646,9 +4219,13 @@ true true true + true true + true true + true true + true true true true @@ -3675,7 +4252,6 @@ - @@ -3692,9 +4268,12 @@ Create Create Create + Create Create Create + Create Create + Create Create Create Create @@ -3710,18 +4289,25 @@ Create Create Create + Create Create + Create Create + Create Create + Create Create Create Create Create Create false + false false false + false false + false false false Create @@ -3796,7 +4382,6 @@ - @@ -3837,9 +4422,13 @@ true true true + true true + true true + true true + true true true true @@ -3855,9 +4444,12 @@ true true true + true true true + true true + true true true true @@ -3882,9 +4474,13 @@ true true true + true true + true true + true true + true true true true @@ -3900,9 +4496,12 @@ true true true + true true true + true true + true true true true @@ -3927,9 +4526,13 @@ true true true + true true + true true + true true + true true true true @@ -3945,9 +4548,12 @@ true true true + true true true + true true + true true true true @@ -3960,8 +4566,7 @@ - - + diff --git a/Minecraft.World/Minecraft.World.vcxproj.filters b/Minecraft.World/Minecraft.World.vcxproj.filters index eb5e4a8c..bf872596 100644 --- a/Minecraft.World/Minecraft.World.vcxproj.filters +++ b/Minecraft.World/Minecraft.World.vcxproj.filters @@ -39,9 +39,6 @@ {0a1baf2e-2c84-488f-afd0-f5ddba3ac849} - - {bf44f635-1f68-4c61-a946-acc2cca87955} - {b734aa5c-6770-4181-b8ab-e86980054dca} @@ -54,24 +51,6 @@ {b17885f1-37c1-481f-94b1-a74f0c886b29} - - {6252deb7-1b31-4ba0-83b7-db11fa2123eb} - - - {0954c9e3-8650-4c2c-b51c-1ab9a4476b14} - - - {1152442e-07f2-4ec9-85c0-7e3b040eee40} - - - {0023db14-c89d-4ce1-b0d3-b4d83c742c35} - - - {becb642b-be13-43a9-90e2-61d563c35682} - - - {be720f83-accf-4b92-8831-c890ef2fa69d} - {c29b0728-1151-40d1-ae10-4b5d1bd136cd} @@ -147,15 +126,6 @@ {2ac6971f-ddc3-438b-921a-315ea5e3ad5a} - - {a81770a3-9c91-487b-9321-e39f63998514} - - - {5abf2525-8223-4c6b-bb6b-5c9446334868} - - - {24e2f412-a3f1-447a-bbea-7aa6561a93eb} - {05f1cf3e-10f1-40a0-a72d-99bdd4d783d4} @@ -174,6 +144,51 @@ {c87ae9ac-b823-48e4-b007-39d45aff76e6} + + {e61b6eae-3e06-4649-86f6-ab1a6624833f} + + + {e43a9174-9dbd-4e7d-8aa0-7609d879b0e3} + + + {3cc9bf7f-fcf2-4819-85ea-3cdf5bbea411} + + + {1aaaae5f-20f2-4dea-9182-c5263a8085a6} + + + {5a6edf15-80d1-4d0f-b1a9-17073737227c} + + + {bf44f635-1f68-4c61-a946-acc2cca87955} + + + {6252deb7-1b31-4ba0-83b7-db11fa2123eb} + + + {0954c9e3-8650-4c2c-b51c-1ab9a4476b14} + + + {1152442e-07f2-4ec9-85c0-7e3b040eee40} + + + {0023db14-c89d-4ce1-b0d3-b4d83c742c35} + + + {becb642b-be13-43a9-90e2-61d563c35682} + + + {be720f83-accf-4b92-8831-c890ef2fa69d} + + + {a81770a3-9c91-487b-9321-e39f63998514} + + + {5abf2525-8223-4c6b-bb6b-5c9446334868} + + + {24e2f412-a3f1-447a-bbea-7aa6561a93eb} + {bd03576a-c1b3-4c04-bc52-d67abed85da4} @@ -183,12 +198,12 @@ {83228256-d4e1-447b-8102-4f824d131ff0} - - {5c2a5df8-8116-4e7e-ae85-c688843e36bc} - {569feaf7-5d52-44fc-883d-87c10196ea2f} + + {5c2a5df8-8116-4e7e-ae85-c688843e36bc} + {c554494b-5cc6-4251-8d1f-c70afdb4ba2d} @@ -198,17 +213,26 @@ {19721528-fc70-4673-8183-d9329e751555} - - {e61b6eae-3e06-4649-86f6-ab1a6624833f} + + {ef8aa915-dc0f-44c6-8533-1250c461b636} - - {e43a9174-9dbd-4e7d-8aa0-7609d879b0e3} + + {be58a6fd-f674-4c0d-b7e9-94dc4bab4cae} - - {3cc9bf7f-fcf2-4819-85ea-3cdf5bbea411} + + {d5c9e9a6-4945-40d7-8b19-f9c53ac83815} - - {1aaaae5f-20f2-4dea-9182-c5263a8085a6} + + {e76a4209-219e-4f30-8758-82af8ea845e2} + + + {b3d1eb81-7216-4d46-b742-3053cee0940b} + + + {8589c074-b333-49e2-bd6e-bb49f7052b70} + + + {fabb7f9b-01fe-446a-ac67-f231110fec0a} @@ -236,6 +260,10 @@ net\minecraft\world\damageSource + + net\minecraft\core + + @@ -553,9 +581,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -565,15 +590,9 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -613,12 +632,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -643,9 +656,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -667,9 +677,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -694,9 +701,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -1003,9 +1007,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -1072,9 +1073,6 @@ net\minecraft\world\level\tile\entity - - net\minecraft\world\item - net\minecraft\world\item @@ -1087,9 +1085,6 @@ net\minecraft\world\item - - net\minecraft\world\item - net\minecraft\world\item @@ -1339,9 +1334,6 @@ net\minecraft\network\packet - - net\minecraft\network\packet - net\minecraft\network\packet @@ -1936,9 +1928,6 @@ net\minecraft\world\level\levelgen\feature - - net\minecraft\world\item - net\minecraft\world\level\biome @@ -1990,9 +1979,6 @@ net\minecraft\world\entity\boss - - net\minecraft\world\entity\boss - net\minecraft\world\entity\boss\enderdragon @@ -2155,9 +2141,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -2203,9 +2186,6 @@ net\minecraft\network\packet - - net\minecraft\world\item - net\minecraft\network\packet @@ -2314,9 +2294,6 @@ net\minecraft\world\entity\ai\navigation - - net\minecraft\world\item - net\minecraft\world\level\biome @@ -2389,9 +2366,6 @@ net\minecraft\world\entity\ai\goal\target - - net\minecraft\world\entity\ai\goal - net\minecraft\world\entity\ai\goal @@ -2446,9 +2420,6 @@ net\minecraft\world\entity\ai\goal - - net\minecraft\world\entity\ai\goal - net\minecraft\world\entity\ai\goal @@ -2503,12 +2474,6 @@ net\minecraft\world\entity - - net\minecraft\world\entity\animal - - - net\minecraft\world\entity\animal - net\minecraft\world\entity\animal @@ -2650,9 +2615,6 @@ net\minecraft\world\entity\ai\goal - - net\minecraft\world\inventory - net\minecraft\world\inventory @@ -2767,131 +2729,590 @@ ConsoleHelpers\ConsoleSaveFileIO - - ConsoleHelpers\ConsoleSaveFileIO - ConsoleHelpers\ConsoleSaveFileIO ConsoleHelpers - - - - Source Files - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\levelgen\synth - - - net\minecraft\world\level\biome - - - net\minecraft\world\level\biome - - - net\minecraft\world\level\biome - - - net\minecraft\world\level\biome - - - net\minecraft\world\level\biome - - - net\minecraft\world\level\biome - - - net\minecraft\world\level\biome - - - net\minecraft\world\level\chunk - - - net\minecraft\world\level\chunk - - - net\minecraft\world\level\chunk - - - net\minecraft\world\level\chunk - - - net\minecraft\world\level\chunk\storage - - - net\minecraft\world\level\chunk\storage - - - com\mojang\nbt - - - com\mojang\nbt - - - net\minecraft\world\level\chunk\storage - - - net\minecraft\world\level\chunk\storage - - - net\minecraft\world\level\chunk\storage - - - net\minecraft\world\level\chunk\storage - - - net\minecraft\world\level\chunk\storage - - - net\minecraft\world\level\chunk\storage - - - net\minecraft\world\level\chunk\storage - - - net\minecraft\world\level\dimension - - - net\minecraft\world\level\dimension - - - net\minecraft\world\level\levelgen\feature - - - net\minecraft\world\level\levelgen\feature - - - net\minecraft\world\level\levelgen\feature - + + net\minecraft\commands\common + + + net\minecraft\commands\common + + + net\minecraft\commands\common + + + net\minecraft\commands\common + + + net\minecraft\commands\common + + + net\minecraft\commands\common + + + net\minecraft\commands\common + + + net\minecraft\commands\common + + + net\minecraft\commands + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\world\damageSource + + + net\minecraft\world\damageSource + + + net\minecraft\world\effect + + + net\minecraft\world\effect + + + net\minecraft\world\effect + + + net\minecraft\world\entity + + + net\minecraft\world\entity + + + net\minecraft\world\entity + + + net\minecraft\world\entity + + + net\minecraft\world\entity + + + net\minecraft\world\entity + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\goal + + + net\minecraft\world\entity\ai\goal + + + net\minecraft\world\entity\ai\goal + + + net\minecraft\world\entity\ambient + + + net\minecraft\world\entity\ambient + + + net\minecraft\world\entity\ambient + + + net\minecraft\world\entity\animal + + + net\minecraft\world\entity\boss + + + net\minecraft\world\entity\boss + + + net\minecraft\world\entity\boss\wither + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\animal + + + net\minecraft\world\entity\monster + + + net\minecraft\world\entity\monster + + + net\minecraft\world\entity\monster + + + net\minecraft\world\entity\projectile + + + net\minecraft\world\entity\projectile + + + net\minecraft\world\entity\projectile + + + net\minecraft\world\entity\projectile + + + net\minecraft\world\scores + + + net\minecraft\world\inventory + + + net\minecraft\world\inventory + + + net\minecraft\world\inventory + + + net\minecraft\world\inventory + + + net\minecraft\world\inventory + + + net\minecraft\world\item\crafting + + + net\minecraft\world\item\crafting + + + net\minecraft\world\item\crafting + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\level\levelgen\flat + + + net\minecraft\world\level\levelgen\flat + + + net\minecraft\world\level\levelgen\flat + + + net\minecraft\world\level\levelgen\structure + + + net\minecraft\world\level\levelgen\structure + + + net\minecraft\world\level\redstone + + + net\minecraft\world\level\redstone + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\world\scores\criteria + + + net\minecraft\world\scores\criteria + + + net\minecraft\world\scores\criteria + + + net\minecraft\world\scores\criteria + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\core + + + net\minecraft\world\level + + + net\minecraft\world\level + + + net\minecraft\world\level + + + net\minecraft\world\entity\item + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\util + + + net\minecraft\world\inventory + + + + + Source Files + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\levelgen\synth + + + net\minecraft\world\level\biome + + + net\minecraft\world\level\biome + + + net\minecraft\world\level\biome + + + net\minecraft\world\level\biome + + + net\minecraft\world\level\biome + + + net\minecraft\world\level\biome + + + net\minecraft\world\level\biome + + + net\minecraft\world\level\chunk + + + net\minecraft\world\level\chunk + + + net\minecraft\world\level\chunk + + + net\minecraft\world\level\chunk + + + net\minecraft\world\level\chunk\storage + + + net\minecraft\world\level\chunk\storage + + + com\mojang\nbt + + + com\mojang\nbt + + + net\minecraft\world\level\chunk\storage + + + net\minecraft\world\level\chunk\storage + + + net\minecraft\world\level\chunk\storage + + + net\minecraft\world\level\chunk\storage + + + net\minecraft\world\level\chunk\storage + + + net\minecraft\world\level\chunk\storage + + + net\minecraft\world\level\chunk\storage + + + net\minecraft\world\level\dimension + + + net\minecraft\world\level\dimension + + + net\minecraft\world\level\levelgen\feature + + + net\minecraft\world\level\levelgen\feature + + + net\minecraft\world\level\levelgen\feature + net\minecraft\world\level\levelgen\feature @@ -3006,9 +3427,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -3018,15 +3436,9 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -3060,16 +3472,10 @@ net\minecraft\world\level\tile - - net\minecraft\world\level - - - net\minecraft\world\level\tile - - - net\minecraft\world\level\tile + + net\minecraft\world\level - + net\minecraft\world\level\tile @@ -3090,9 +3496,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -3111,9 +3514,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -3138,9 +3538,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -3375,9 +3772,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -3426,9 +3820,6 @@ net\minecraft\world\level - - net\minecraft\world\item - net\minecraft\world\item @@ -3441,9 +3832,6 @@ net\minecraft\world\item - - net\minecraft\world\item - net\minecraft\world\item @@ -3666,9 +4054,6 @@ net\minecraft\network\packet - - net\minecraft\network\packet - net\minecraft\network\packet @@ -3828,9 +4213,6 @@ net\minecraft\util - - net\minecraft\world - net\minecraft\world\entity @@ -4194,9 +4576,6 @@ net\minecraft\world\level\levelgen\feature - - net\minecraft\world\item - net\minecraft\world\level\biome @@ -4239,12 +4618,6 @@ net\minecraft\world\entity\animal - - net\minecraft\world\entity\boss - - - net\minecraft\world\entity\boss - net\minecraft\world\entity\boss\enderdragon @@ -4350,9 +4723,6 @@ net\minecraft\world\level\tile - - net\minecraft\world\level\tile - net\minecraft\world\level\tile @@ -4509,9 +4879,6 @@ net\minecraft\world\entity\ai\navigation - - net\minecraft\world\item - net\minecraft\world\level\biome @@ -4536,9 +4903,6 @@ net\minecraft\world\entity - - net\minecraft\world\item - net\minecraft\world @@ -4578,9 +4942,6 @@ net\minecraft\world\entity\ai\goal\target - - net\minecraft\world\entity\ai\goal - net\minecraft\world\entity\ai\goal @@ -4635,9 +4996,6 @@ net\minecraft\world\entity\ai\goal - - net\minecraft\world\entity\ai\goal - net\minecraft\world\entity\ai\goal @@ -4683,12 +5041,6 @@ net\minecraft\world\entity - - net\minecraft\world\entity\animal - - - net\minecraft\world\entity\animal - net\minecraft\world\entity\animal @@ -4812,9 +5164,6 @@ net\minecraft\world\entity\ai\goal - - net\minecraft\world\inventory - net\minecraft\world\inventory @@ -4914,14 +5263,368 @@ ConsoleHelpers\ConsoleSaveFileIO - - ConsoleHelpers\ConsoleSaveFileIO - ConsoleHelpers\ConsoleSaveFileIO ConsoleHelpers + + net\minecraft\commands\common + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\network\packet + + + net\minecraft\world\damageSource + + + net\minecraft\world\damageSource + + + net\minecraft\world\effect + + + net\minecraft\world\effect + + + net\minecraft\world\effect + + + net\minecraft\world\entity + + + net\minecraft\world\entity + + + net\minecraft\world\entity + + + net\minecraft\world\entity + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\world\entity\ai\goal + + + net\minecraft\world\entity\ai\goal + + + net\minecraft\world\entity\ai\goal + + + net\minecraft\world\entity\ambient + + + net\minecraft\world\entity\ambient + + + net\minecraft\world\entity\animal + + + net\minecraft\world\entity\boss + + + net\minecraft\world\entity\boss\wither + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\item + + + net\minecraft\world\entity\animal + + + net\minecraft\world\entity\monster + + + net\minecraft\world\entity\monster + + + net\minecraft\world\entity\projectile + + + net\minecraft\world\entity\projectile + + + net\minecraft\world\entity\projectile + + + net\minecraft\world\inventory + + + net\minecraft\world\inventory + + + net\minecraft\world\inventory + + + net\minecraft\world\inventory + + + net\minecraft\world\inventory + + + net\minecraft\world\item\crafting + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\item + + + net\minecraft\world\level\levelgen\flat + + + net\minecraft\world\level\levelgen\flat + + + net\minecraft\world\level\levelgen\structure + + + net\minecraft\world\level\levelgen\structure + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile\entity + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\core + + + net\minecraft\core + + + net\minecraft\world\scores\criteria + + + net\minecraft\world\scores\criteria + + + net\minecraft\world\scores\criteria + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\world\scores + + + net\minecraft\core + + + net\minecraft\world\level + + + net\minecraft\world\level + + + net\minecraft\world\level + + + net\minecraft\world\entity\item + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\tile + + + net\minecraft\world\level\redstone + + + net\minecraft\world\entity\ai\attributes + + + net\minecraft\util + + + net\minecraft\world\inventory + + + net\minecraft\world\item + \ No newline at end of file diff --git a/Minecraft.World/Mob.cpp b/Minecraft.World/Mob.cpp index d2dcddfb..cac25ddb 100644 --- a/Minecraft.World/Mob.cpp +++ b/Minecraft.World/Mob.cpp @@ -1,8 +1,10 @@ #include "stdafx.h" #include "JavaMath.h" +#include "net.minecraft.network.packet.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.control.h" #include "net.minecraft.world.entity.ai.navigation.h" #include "net.minecraft.world.entity.ai.sensing.h" @@ -16,6 +18,9 @@ #include "net.minecraft.world.effect.h" #include "net.minecraft.world.item.alchemy.h" #include "net.minecraft.world.item.enchantment.h" +#include "net.minecraft.world.h" +#include "..\Minecraft.Client\ServerLevel.h" +#include "..\Minecraft.Client\EntityTracker.h" #include "com.mojang.nbt.h" #include "Mob.h" #include "..\Minecraft.Client\Textures.h" @@ -25,134 +30,63 @@ #include "GenericStats.h" #include "ItemEntity.h" -const double Mob::MIN_MOVEMENT_DISTANCE = 0.005; +const float Mob::MAX_WEARING_ARMOR_CHANCE = 0.15f; +const float Mob::MAX_PICKUP_LOOT_CHANCE = 0.55f; +const float Mob::MAX_ENCHANTED_ARMOR_CHANCE = 0.50f; +const float Mob::MAX_ENCHANTED_WEAPON_CHANCE = 0.25f; void Mob::_init() { - invulnerableDuration = 20; - timeOffs = 0.0f; - - yBodyRot = 0; - yBodyRotO = 0; - yHeadRot = 0; - yHeadRotO = 0; - - oRun = 0.0f; - run = 0.0f; - - animStep = 0.0f; - animStepO = 0.0f; - - MemSect(31); - hasHair = true; - textureIdx = TN_MOB_CHAR; // 4J was L"/mob/char.png"; - allowAlpha = true; - rotOffs = 0; - modelName = L""; - bobStrength = 1; - deathScore = 0; - renderOffset = 0; - MemSect(0); - - walkingSpeed = 0.1f; - flyingSpeed = 0.02f; - - oAttackAnim = 0.0f; - attackAnim = 0.0f; - - lastHealth = 0; - dmgSpill = 0; - ambientSoundTime = 0; - - hurtTime = 0; - hurtDuration = 0; - hurtDir = 0; - deathTime = 0; - attackTime = 0; - oTilt = 0; - tilt = 0; - - dead = false; xpReward = 0; - - modelNum = -1; - animSpeed = (float) (Math::random() * 0.9f + 0.1f); - - walkAnimSpeedO = 0.0f; - walkAnimSpeed = 0.0f; - walkAnimPos = 0.0f; - - lastHurtByPlayer = nullptr; - lastHurtByPlayerTime = 0; - lastHurtByMob = nullptr; - lastHurtByMobTime = 0; - lastHurtMob = nullptr; - - arrowCount = 0; - removeArrowTime = 0; - - lSteps = 0; - lx = ly = lz = lyr = lxr = 0.0; - - fallTime = 0.0f; - - lastHurt = 0; - - noActionTime = 0; - xxa = yya = yRotA = 0.0f; - jumping = false; defaultLookAngle = 0.0f; - runSpeed = 0.7f; - noJumpDelay = 0; - lookingAt = nullptr; lookTime = 0; - - effectsDirty = true; - effectColor = 0; - target = nullptr; sensing = NULL; - speed = 0.0f; - restrictCenter = new Pos(0, 0, 0); - restrictRadius = -1.0f; + equipment = ItemInstanceArray(5); + dropChances = floatArray(5); + for(unsigned int i = 0; i < 5; ++i) + { + equipment[i] = nullptr; + dropChances[i] = 0.0f; + } + + _canPickUpLoot = false; + persistenceRequired = false; + + _isLeashed = false; + leashHolder = nullptr; + leashInfoTag = NULL; } -Mob::Mob( Level* level) : Entity(level) +Mob::Mob( Level* level) : LivingEntity(level) { + MemSect(57); _init(); + MemSect(0); - // 4J Stu - This will not call the correct derived function, so moving to each derived class - //health = getMaxHealth(); - health = 0; - - blocksBuilding = true; + MemSect(58); + // 4J Stu - We call this again in the derived classes, but need to do it here for some internal members + registerAttributes(); + MemSect(0); lookControl = new LookControl(this); moveControl = new MoveControl(this); jumpControl = new JumpControl(this); bodyControl = new BodyControl(this); - navigation = new PathNavigation(this, level, 16); + navigation = new PathNavigation(this, level); sensing = new Sensing(this); - rotA = (float) (Math::random() + 1) * 0.01f; - setPos(x, y, z); - timeOffs = (float) Math::random() * 12398; - yRot = (float) (Math::random() * PI * 2); - yHeadRot = yRot; - - this->footSize = 0.5f; + for (int i = 0; i < 5; i++) + { + dropChances[i] = 0.085f; + } } Mob::~Mob() { - for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end(); ++it) - { - delete it->second; - } - if(lookControl != NULL) delete lookControl; if(moveControl != NULL) delete moveControl; if(jumpControl != NULL) delete jumpControl; @@ -160,7 +94,17 @@ Mob::~Mob() if(navigation != NULL) delete navigation; if(sensing != NULL) delete sensing; - delete restrictCenter; + if(leashInfoTag != NULL) delete leashInfoTag; + + if(equipment.data != NULL) delete [] equipment.data; + delete [] dropChances.data; +} + +void Mob::registerAttributes() +{ + LivingEntity::registerAttributes(); + + getAttributes()->registerAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->setBaseValue(16); } LookControl *Mob::getLookControl() @@ -188,65 +132,12 @@ Sensing *Mob::getSensing() return sensing; } -Random *Mob::getRandom() -{ - return random; -} - -shared_ptr Mob::getLastHurtByMob() -{ - return lastHurtByMob; -} - -shared_ptr Mob::getLastHurtMob() -{ - return lastHurtMob; -} - -void Mob::setLastHurtMob(shared_ptr target) -{ - shared_ptr mob = dynamic_pointer_cast(target); - if (mob != NULL) lastHurtMob = mob; -} - -int Mob::getNoActionTime() -{ - return noActionTime; -} - -float Mob::getYHeadRot() -{ - return yHeadRot; -} - -void Mob::setYHeadRot(float yHeadRot) -{ - this->yHeadRot = yHeadRot; -} - -float Mob::getSpeed() -{ - return speed; -} - -void Mob::setSpeed(float speed) -{ - this->speed = speed; - setYya(speed); -} - -bool Mob::doHurtTarget(shared_ptr target) -{ - setLastHurtMob(target); - return false; -} - -shared_ptr Mob::getTarget() +shared_ptr Mob::getTarget() { return target; } -void Mob::setTarget(shared_ptr target) +void Mob::setTarget(shared_ptr target) { this->target = target; } @@ -261,81 +152,11 @@ void Mob::ate() { } -// might move to navigation, might make area -bool Mob::isWithinRestriction() -{ - return isWithinRestriction(Mth::floor(x), Mth::floor(y), Mth::floor(z)); -} - -bool Mob::isWithinRestriction(int x, int y, int z) -{ - if (restrictRadius == -1) return true; - return restrictCenter->distSqr(x, y, z) < restrictRadius * restrictRadius; -} - -void Mob::restrictTo(int x, int y, int z, int radius) -{ - restrictCenter->set(x, y, z); - restrictRadius = radius; -} - -Pos *Mob::getRestrictCenter() -{ - return restrictCenter; -} - -float Mob::getRestrictRadius() -{ - return restrictRadius; -} - -void Mob::clearRestriction() -{ - restrictRadius = -1; -} - -bool Mob::hasRestriction() -{ - return restrictRadius != -1; -} - -void Mob::setLastHurtByMob(shared_ptr hurtBy) -{ - lastHurtByMob = hurtBy; - lastHurtByMobTime = lastHurtByMob != NULL ? PLAYER_HURT_EXPERIENCE_TIME : 0; -} - void Mob::defineSynchedData() { - entityData->define(DATA_EFFECT_COLOR_ID, effectColor); -} - -bool Mob::canSee(shared_ptr target) -{ - HitResult *hres = level->clip(Vec3::newTemp(x, y + getHeadHeight(), z), Vec3::newTemp(target->x, target->y + target->getHeadHeight(), target->z)); - bool retVal = (hres == NULL); - delete hres; - return retVal; -} - -int Mob::getTexture() -{ - return textureIdx; -} - -bool Mob::isPickable() -{ - return !removed; -} - -bool Mob::isPushable() -{ - return !removed; -} - -float Mob::getHeadHeight() -{ - return bbHeight * 0.85f; + LivingEntity::defineSynchedData(); + entityData->define(DATA_CUSTOM_NAME_VISIBLE, (byte) 0); + entityData->define(DATA_CUSTOM_NAME, L""); } int Mob::getAmbientSoundInterval() @@ -349,15 +170,14 @@ void Mob::playAmbientSound() int ambient = getAmbientSound(); if (ambient != -1) { - level->playSound(shared_from_this(), ambient, getSoundVolume(), getVoicePitch()); + playSound(ambient, getSoundVolume(), getVoicePitch()); } MemSect(0); } void Mob::baseTick() { - oAttackAnim = attackAnim; - Entity::baseTick(); + LivingEntity::baseTick(); if (isAlive() && random->nextInt(1000) < ambientSoundTime++) { @@ -365,126 +185,30 @@ void Mob::baseTick() playAmbientSound(); } +} - if (isAlive() && isInWall()) +int Mob::getExperienceReward(shared_ptr killedBy) +{ + if (xpReward > 0) { - hurt(DamageSource::inWall, 1); - } + int result = xpReward; - if (isFireImmune() || level->isClientSide) clearFire(); - - if (isAlive() && isUnderLiquid(Material::water) && !isWaterMob() && activeEffects.find(MobEffect::waterBreathing->id) == activeEffects.end()) - { - setAirSupply(decreaseAirSupply(getAirSupply())); - if (getAirSupply() == -20) + ItemInstanceArray slots = getEquipmentSlots(); + for (int i = 0; i < slots.length; i++) { - setAirSupply(0); - if(canCreateParticles()) + if (slots[i] != NULL && dropChances[i] <= 1) { - for (int i = 0; i < 8; i++) - { - float xo = random->nextFloat() - random->nextFloat(); - float yo = random->nextFloat() - random->nextFloat(); - float zo = random->nextFloat() - random->nextFloat(); - level->addParticle(eParticleType_bubble, x + xo, y + yo, z + zo, xd, yd, zd); - } + result += 1 + random->nextInt(3); } - hurt(DamageSource::drown, 2); } - clearFire(); - } - else - { - setAirSupply(TOTAL_AIR_SUPPLY); - } - - oTilt = tilt; - - if (attackTime > 0) attackTime--; - if (hurtTime > 0) hurtTime--; - if (invulnerableTime > 0) invulnerableTime--; - if (health <= 0) - { - tickDeath(); + return result; } - - if (lastHurtByPlayerTime > 0) lastHurtByPlayerTime--; else { - // Note - this used to just set to nullptr, but that has to create a new shared_ptr and free an old one, when generally this won't be doing anything at all. This - // is the lightweight but ugly alternative - if( lastHurtByPlayer ) - { - lastHurtByPlayer.reset(); - } + return xpReward; } - if (lastHurtMob != NULL && !lastHurtMob->isAlive()) lastHurtMob = nullptr; - - if (lastHurtByMob != NULL) - { - if (!lastHurtByMob->isAlive()) setLastHurtByMob(nullptr); - else if (lastHurtByMobTime > 0) lastHurtByMobTime--; - else setLastHurtByMob(nullptr); - } - - // update effects - tickEffects(); - - animStepO = animStep; - - yBodyRotO = yBodyRot; - yHeadRotO = yHeadRot; - yRotO = yRot; - xRotO = xRot; } - -void Mob::tickDeath() -{ - deathTime++; - if (deathTime == 20) - { - // 4J Stu - Added level->isClientSide check from 1.2 to fix XP orbs being created client side - if(!level->isClientSide && (lastHurtByPlayerTime > 0 || isAlwaysExperienceDropper()) ) - { - if (!isBaby()) - { - int xpCount = this->getExperienceReward(lastHurtByPlayer); - while (xpCount > 0) - { - int newCount = ExperienceOrb::getExperienceValue(xpCount); - xpCount -= newCount; - level->addEntity(shared_ptr( new ExperienceOrb(level, x, y, z, newCount) ) ); - } - } - } - - remove(); - for (int i = 0; i < 20; i++) - { - double xa = random->nextGaussian() * 0.02; - double ya = random->nextGaussian() * 0.02; - double za = random->nextGaussian() * 0.02; - level->addParticle(eParticleType_explode, x + random->nextFloat() * bbWidth * 2 - bbWidth, y + random->nextFloat() * bbHeight, z + random->nextFloat() * bbWidth * 2 - bbWidth, xa, ya, za); - } - } -} - -int Mob::decreaseAirSupply(int currentSupply) -{ - return currentSupply - 1; -} - -int Mob::getExperienceReward(shared_ptr killedBy) -{ - return xpReward; -} - -bool Mob::isAlwaysExperienceDropper() -{ - return false; -} - void Mob::spawnAnim() { for (int i = 0; i < 20; i++) @@ -498,408 +222,37 @@ void Mob::spawnAnim() } } -void Mob::rideTick() -{ - Entity::rideTick(); - oRun = run; - run = 0; - fallDistance = 0; -} - -void Mob::lerpTo(double x, double y, double z, float yRot, float xRot, int steps) -{ - heightOffset = 0; - lx = x; - ly = y; - lz = z; - lyr = yRot; - lxr = xRot; - - lSteps = steps; -} - -void Mob::superTick() -{ - Entity::tick(); -} - void Mob::tick() { - Entity::tick(); - - if (arrowCount > 0) - { - if (removeArrowTime <= 0) - { - removeArrowTime = 20 * 3; - } - removeArrowTime--; - if (removeArrowTime <= 0) - { - arrowCount--; - } - } - - aiStep(); - - double xd = x - xo; - double zd = z - zo; + LivingEntity::tick(); - float sideDist = xd * xd + zd * zd; - - float yBodyRotT = yBodyRot; - - float walkSpeed = 0; - oRun = run; - float tRun = 0; - if (sideDist <= 0.05f * 0.05f) - { - // animStep = 0; - } - else - { - tRun = 1; - walkSpeed = sqrt(sideDist) * 3; - yBodyRotT = ((float) atan2(zd, xd) * 180 / (float) PI - 90); - } - if (attackAnim > 0) + if (!level->isClientSide) { - yBodyRotT = yRot; + tickLeash(); } - if (!onGround) - { - tRun = 0; - } - run = run + (tRun - run) * 0.3f; - - /* - * float yBodyRotD = yRot-yBodyRot; while (yBodyRotD < -180) yBodyRotD - * += 360; while (yBodyRotD >= 180) yBodyRotD -= 360; yBodyRot += - * yBodyRotD * 0.1f; - */ +} +float Mob::tickHeadTurn(float yBodyRotT, float walkSpeed) +{ if (useNewAi()) { bodyControl->clientTick(); + return walkSpeed; } else { - float yBodyRotD = Mth::wrapDegrees(yBodyRotT - yBodyRot); - yBodyRot += yBodyRotD * 0.3f; - - float headDiff = Mth::wrapDegrees(yRot - yBodyRot); - bool behind = headDiff < -90 || headDiff >= 90; - if (headDiff < -75) headDiff = -75; - if (headDiff >= 75) headDiff = +75; - yBodyRot = yRot - headDiff; - if (headDiff * headDiff > 50 * 50) - { - yBodyRot += headDiff * 0.2f; - } - - if (behind) - { - walkSpeed *= -1; - } - } - while (yRot - yRotO < -180) - yRotO -= 360; - while (yRot - yRotO >= 180) - yRotO += 360; - - while (yBodyRot - yBodyRotO < -180) - yBodyRotO -= 360; - while (yBodyRot - yBodyRotO >= 180) - yBodyRotO += 360; - - while (xRot - xRotO < -180) - xRotO -= 360; - while (xRot - xRotO >= 180) - xRotO += 360; - - while (yHeadRot - yHeadRotO < -180) - yHeadRotO -= 360; - while (yHeadRot - yHeadRotO >= 180) - yHeadRotO += 360; - - animStep += walkSpeed; -} - -void Mob::heal(int heal) -{ - if (health <= 0) return; - health += heal; - if (health > getMaxHealth()) health = getMaxHealth(); - invulnerableTime = invulnerableDuration / 2; -} - -int Mob::getHealth() -{ - return health; -} - -void Mob::setHealth(int health) -{ - this->health = health; - if (health > getMaxHealth()) - { - health = getMaxHealth(); + return LivingEntity::tickHeadTurn(yBodyRotT, walkSpeed); } } -bool Mob::hurt(DamageSource *source, int dmg) -{ - // 4J Stu - Reworked this function a bit to show hurt damage on the client before the server responds. - // Fix for #8823 - Gameplay: Confirmation that a monster or animal has taken damage from an attack is highly delayed - // 4J Stu - Change to the fix to only show damage when attacked, rather than collision damage - // Fix for #10299 - When in corners, passive mobs may show that they are taking damage. - // 4J Stu - Change to the fix for TU6, as source is never NULL due to changes in 1.8.2 to what source actually is - if (level->isClientSide && dynamic_cast(source) == NULL) return false; - noActionTime = 0; - if (health <= 0) return false; - - if ( source->isFire() && hasEffect(MobEffect::fireResistance) ) - { - // 4J-JEV, for new achievement Stayin'Frosty, TODO merge with Java version. - shared_ptr plr = dynamic_pointer_cast(shared_from_this()); - if ( plr != NULL && source == DamageSource::lava ) // Only award when in lava (not any fire). - { - plr->awardStat(GenericStats::stayinFrosty(),GenericStats::param_stayinFrosty()); - } - return false; - } - - this->walkAnimSpeed = 1.5f; - - bool sound = true; - if (invulnerableTime > invulnerableDuration / 2.0f) - { - if (dmg <= lastHurt) return false; - if(!level->isClientSide) actuallyHurt(source, dmg - lastHurt); - lastHurt = dmg; - sound = false; - } - else - { - lastHurt = dmg; - lastHealth = health; - invulnerableTime = invulnerableDuration; - if (!level->isClientSide) actuallyHurt(source, dmg); - hurtTime = hurtDuration = 10; - } - - hurtDir = 0; - - shared_ptr sourceEntity = source->getEntity(); - if (sourceEntity != NULL) - { - if (dynamic_pointer_cast(sourceEntity) != NULL) { - setLastHurtByMob(dynamic_pointer_cast(sourceEntity)); - - } - if (dynamic_pointer_cast(sourceEntity) != NULL) - { - lastHurtByPlayerTime = PLAYER_HURT_EXPERIENCE_TIME; - lastHurtByPlayer = dynamic_pointer_cast(sourceEntity); - } - else if (dynamic_pointer_cast(sourceEntity)) - { - shared_ptr w = dynamic_pointer_cast(sourceEntity); - if (w->isTame()) - { - lastHurtByPlayerTime = PLAYER_HURT_EXPERIENCE_TIME; - lastHurtByPlayer = nullptr; - } - } - } - - if (sound && level->isClientSide) - { - return false; - } - - if (sound) - { - level->broadcastEntityEvent(shared_from_this(), EntityEvent::HURT); - if (source != DamageSource::drown && source != DamageSource::controlledExplosion) markHurt(); - if (sourceEntity != NULL) - { - double xd = sourceEntity->x - x; - double zd = sourceEntity->z - z; - while (xd * xd + zd * zd < 0.0001) - { - xd = (Math::random() - Math::random()) * 0.01; - zd = (Math::random() - Math::random()) * 0.01; - } - hurtDir = (float) (atan2(zd, xd) * 180 / PI) - yRot; - knockback(sourceEntity, dmg, xd, zd); - } - else - { - hurtDir = (float) (int) ((Math::random() * 2) * 180); // 4J This cast is the same as Java - } - } - - MemSect(31); - if (health <= 0) - { - if (sound) level->playSound(shared_from_this(), getDeathSound(), getSoundVolume(), getVoicePitch()); - die(source); - } - else - { - if (sound) level->playSound(shared_from_this(), getHurtSound(), getSoundVolume(), getVoicePitch()); - } - MemSect(0); - - return true; -} - -float Mob::getVoicePitch() -{ - if (isBaby()) - { - return (random->nextFloat() - random->nextFloat()) * 0.2f + 1.5f; - - } - return (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f; -} - -void Mob::animateHurt() -{ - hurtTime = hurtDuration = 10; - hurtDir = 0; -} - -int Mob::getArmorValue() -{ - return 0; -} - -void Mob::hurtArmor(int damage) -{ -} - -int Mob::getDamageAfterArmorAbsorb(DamageSource *damageSource, int damage) -{ - if (!damageSource->isBypassArmor()) - { - int absorb = 25 - getArmorValue(); - int v = (damage) * absorb + dmgSpill; - hurtArmor(damage); - damage = v / 25; - dmgSpill = v % 25; - } - return damage; -} - -int Mob::getDamageAfterMagicAbsorb(DamageSource *damageSource, int damage) -{ - if (hasEffect(MobEffect::damageResistance)) - { - int absorbValue = (getEffect(MobEffect::damageResistance)->getAmplifier() + 1) * 5; - int absorb = 25 - absorbValue; - int v = (damage) * absorb + dmgSpill; - damage = v / 25; - dmgSpill = v % 25; - } - return damage; -} - -void Mob::actuallyHurt(DamageSource *source, int dmg) -{ - dmg = getDamageAfterArmorAbsorb(source, dmg); - dmg = getDamageAfterMagicAbsorb(source, dmg); - health -= dmg; -} - - -float Mob::getSoundVolume() -{ - return 1; -} - int Mob::getAmbientSound() { return -1; } -int Mob::getHurtSound() -{ - return eSoundType_DAMAGE_HURT; -} - -int Mob::getDeathSound() -{ - return eSoundType_DAMAGE_HURT; -} - -void Mob::knockback(shared_ptr source, int dmg, double xd, double zd) -{ - hasImpulse = true; - float dd = (float) sqrt(xd * xd + zd * zd); - float pow = 0.4f; - - this->xd /= 2; - this->yd /= 2; - this->zd /= 2; - - this->xd -= xd / dd * pow; - this->yd += pow; - this->zd -= zd / dd * pow; - - if (this->yd > 0.4f) this->yd = 0.4f; -} - -void Mob::die(DamageSource *source) -{ - shared_ptr sourceEntity = source->getEntity(); - if (deathScore >= 0 && sourceEntity != NULL) sourceEntity->awardKillScore(shared_from_this(), deathScore); - - if (sourceEntity != NULL) sourceEntity->killed( dynamic_pointer_cast( shared_from_this() ) ); - - dead = true; - - if (!level->isClientSide) - { - int playerBonus = 0; - shared_ptr player = dynamic_pointer_cast(sourceEntity); - if (player != NULL) - { - playerBonus = EnchantmentHelper::getKillingLootBonus(player->inventory); - } - if (!isBaby()) - { - dropDeathLoot(lastHurtByPlayerTime > 0, playerBonus); - if (lastHurtByPlayerTime > 0) - { - int rareLoot = random->nextInt(200) - playerBonus; - if (rareLoot < 5) - { - dropRareDeathLoot((rareLoot <= 0) ? 1 : 0); - } - } - } - - // 4J-JEV, hook for Durango mobKill event. - if (player != NULL) - { - player->awardStat(GenericStats::killMob(),GenericStats::param_mobKill(player, dynamic_pointer_cast(shared_from_this()), source)); - } - } - - level->broadcastEntityEvent(shared_from_this(), EntityEvent::DEATH); -} - -/** -* Drop extra rare loot. Only occurs roughly 5% of the time, rareRootLevel -* is set to 1 (otherwise 0) 1% of the time. -* -* @param rareLootLevel -*/ -void Mob::dropRareDeathLoot(int rareLootLevel) +int Mob::getDeathLoot() { - + return 0; } void Mob::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) @@ -917,430 +270,191 @@ void Mob::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) } } -int Mob::getDeathLoot() -{ - return 0; -} - -void Mob::causeFallDamage(float distance) -{ - Entity::causeFallDamage(distance); - int dmg = (int) ceil(distance - 3); - if (dmg > 0) - { - // 4J - new sounds here brought forward from 1.2.3 - if (dmg > 4) - { - level->playSound(shared_from_this(), eSoundType_DAMAGE_FALL_BIG, 1, 1); - } - else - { - level->playSound(shared_from_this(), eSoundType_DAMAGE_FALL_SMALL, 1, 1); - } - hurt(DamageSource::fall, dmg); - - int t = level->getTile( Mth::floor(x), Mth::floor(y - 0.2f - this->heightOffset), Mth::floor(z)); - if (t > 0) - { - const Tile::SoundType *soundType = Tile::tiles[t]->soundType; - MemSect(31); - level->playSound(shared_from_this(), soundType->getStepSound(), soundType->getVolume() * 0.5f, soundType->getPitch() * 0.75f); - MemSect(0); - } - } -} - -void Mob::travel(float xa, float ya) -{ -#ifdef __PSVITA__ - // AP - dynamic_pointer_cast is a non-trivial call - Player *thisPlayer = NULL; - if( (GetType() & eTYPE_PLAYER) == eTYPE_PLAYER ) - { - thisPlayer = (Player*) this; - } -#else - shared_ptr thisPlayer = dynamic_pointer_cast(shared_from_this()); -#endif - if (isInWater() && !(thisPlayer && thisPlayer->abilities.flying) ) - { - double yo = y; - moveRelative(xa, ya, useNewAi() ? 0.04f : 0.02f); - move(xd, yd, zd); - - xd *= 0.80f; - yd *= 0.80f; - zd *= 0.80f; - yd -= 0.02; - - if (horizontalCollision && isFree(xd, yd + 0.6f - y + yo, zd)) - { - yd = 0.3f; - } - } - else if (isInLava() && !(thisPlayer && thisPlayer->abilities.flying) ) - { - double yo = y; - moveRelative(xa, ya, 0.02f); - move(xd, yd, zd); - xd *= 0.50f; - yd *= 0.50f; - zd *= 0.50f; - yd -= 0.02; - - if (horizontalCollision && isFree(xd, yd + 0.6f - y + yo, zd)) - { - yd = 0.3f; - } - } - else - { - float friction = 0.91f; - if (onGround) - { - friction = 0.6f * 0.91f; - int t = level->getTile(Mth::floor(x), Mth::floor(bb->y0) - 1, Mth::floor(z)); - if (t > 0) - { - friction = Tile::tiles[t]->friction * 0.91f; - } - } - - float friction2 = (0.6f * 0.6f * 0.91f * 0.91f * 0.6f * 0.91f) / (friction * friction * friction); - - float speed; - if (onGround) - { - if (useNewAi()) speed = getSpeed(); - else speed = walkingSpeed; - speed *= friction2; - } - else speed = flyingSpeed; - - moveRelative(xa, ya, speed); - - friction = 0.91f; - if (onGround) - { - friction = 0.6f * 0.91f; - int t = level->getTile( Mth::floor(x), Mth::floor(bb->y0) - 1, Mth::floor(z)); - if (t > 0) - { - friction = Tile::tiles[t]->friction * 0.91f; - } - } - if (onLadder()) - { - float max = 0.15f; - if (xd < -max) xd = -max; - if (xd > max) xd = max; - if (zd < -max) zd = -max; - if (zd > max) zd = max; - this->fallDistance = 0; - if (yd < -0.15) yd = -0.15; - bool playerSneaking = isSneaking() && dynamic_pointer_cast(shared_from_this()) != NULL; - if (playerSneaking && yd < 0) yd = 0; - } - - move(xd, yd, zd); - - if (horizontalCollision && onLadder()) - { - yd = 0.2; - } - - yd -= 0.08; - yd *= 0.98f; - xd *= friction; - zd *= friction; - } - - walkAnimSpeedO = walkAnimSpeed; - double xxd = x - xo; - double zzd = z - zo; - float wst = Mth::sqrt(xxd * xxd + zzd * zzd) * 4; - if (wst > 1) wst = 1; - walkAnimSpeed += (wst - walkAnimSpeed) * 0.4f; - walkAnimPos += walkAnimSpeed; -} - -bool Mob::onLadder() -{ - int xt = Mth::floor(x); - int yt = Mth::floor(bb->y0); - int zt = Mth::floor(z); - - // 4J-PB - TU9 - add climbable vines - int iTile = level->getTile(xt, yt, zt); - return (iTile== Tile::ladder_Id) || (iTile== Tile::vine_Id); -} - - -bool Mob::isShootable() -{ - return true; -} - void Mob::addAdditonalSaveData(CompoundTag *entityTag) { - entityTag->putShort(L"Health", (short) health); - entityTag->putShort(L"HurtTime", (short) hurtTime); - entityTag->putShort(L"DeathTime", (short) deathTime); - entityTag->putShort(L"AttackTime", (short) attackTime); - - if (!activeEffects.empty()) - { - ListTag *listTag = new ListTag(); - - for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end(); ++it) - { - MobEffectInstance *effect = it->second; - - CompoundTag *tag = new CompoundTag(); - tag->putByte(L"Id", (BYTE) effect->getId()); - tag->putByte(L"Amplifier", (char) effect->getAmplifier()); - tag->putInt(L"Duration", effect->getDuration()); - listTag->add(tag); - } - entityTag->put(L"ActiveEffects", listTag); - } -} - -void Mob::readAdditionalSaveData(CompoundTag *tag) -{ - if (health < Short::MIN_VALUE) health = Short::MIN_VALUE; - health = tag->getShort(L"Health"); - if (!tag->contains(L"Health")) health = getMaxHealth(); - hurtTime = tag->getShort(L"HurtTime"); - deathTime = tag->getShort(L"DeathTime"); - attackTime = tag->getShort(L"AttackTime"); - - if (tag->contains(L"ActiveEffects")) - { - ListTag *effects = (ListTag *) tag->getList(L"ActiveEffects"); - for (int i = 0; i < effects->size(); i++) - { - CompoundTag *effectTag = effects->get(i); - int id = effectTag->getByte(L"Id"); - int amplifier = effectTag->getByte(L"Amplifier"); - int duration = effectTag->getInt(L"Duration"); - - activeEffects.insert( unordered_map::value_type( id, new MobEffectInstance(id, duration, amplifier) ) ); - } - } -} - -bool Mob::isAlive() -{ - return !removed && health > 0; -} - -bool Mob::isWaterMob() -{ - return false; -} - -// 4J - added for more accurate lighting of mobs. Takes a weighted average of all tiles touched by the bounding volume of the entity - the method in the Entity class (which used to be used for -// mobs too) simply gets a single tile's lighting value causing sudden changes of lighting values when entities go in and out of lit areas, for example when bobbing in the water. -int Mob::getLightColor(float a) -{ - float accum[2] = {0,0}; - float totVol = ( bb->x1 - bb->x0 ) * ( bb->y1 - bb->y0 ) * ( bb->z1 - bb->z0 ); - int xmin = Mth::floor(bb->x0); - int xmax = Mth::floor(bb->x1); - int ymin = Mth::floor(bb->y0); - int ymax = Mth::floor(bb->y1); - int zmin = Mth::floor(bb->z0); - int zmax = Mth::floor(bb->z1); - for( int xt = xmin; xt <= xmax; xt++ ) - for( int yt = ymin; yt <= ymax; yt++ ) - for( int zt = zmin; zt <= zmax; zt++ ) - { - float tilexmin = (float)xt; - float tilexmax = (float)(xt+1); - float tileymin = (float)yt; - float tileymax = (float)(yt+1); - float tilezmin = (float)zt; - float tilezmax = (float)(zt+1); - if( tilexmin < bb->x0 ) tilexmin = bb->x0; - if( tilexmax > bb->x1 ) tilexmax = bb->x1; - if( tileymin < bb->y0 ) tileymin = bb->y0; - if( tileymax > bb->y1 ) tileymax = bb->y1; - if( tilezmin < bb->z0 ) tilezmin = bb->z0; - if( tilezmax > bb->z1 ) tilezmax = bb->z1; - float tileVol = ( tilexmax - tilexmin ) * ( tileymax - tileymin ) * ( tilezmax - tilezmin ); - float frac = tileVol / totVol; - int lc = level->getLightColor(xt, yt, zt, 0); - accum[0] += frac * (float)( lc & 0xffff ); - accum[1] += frac * (float)( lc >> 16 ); - } - - if( accum[0] > 240.0f ) accum[0] = 240.0f; - if( accum[1] > 240.0f ) accum[1] = 240.0f; - - return ( ( (int)accum[1])<<16) | ((int)accum[0]); -} - -void Mob::setYya(float yya) -{ - this->yya = yya; -} - -void Mob::setJumping(bool jump) -{ - jumping = jump; -} - -void Mob::aiStep() -{ - if (noJumpDelay > 0) noJumpDelay--; - if (lSteps > 0) - { - double xt = x + (lx - x) / lSteps; - double yt = y + (ly - y) / lSteps; - double zt = z + (lz - z) / lSteps; - - double yrd = Mth::wrapDegrees(lyr - yRot); - double xrd = Mth::wrapDegrees(lxr - xRot); - - yRot += (float) ( (yrd) / lSteps ); - xRot += (float) ( (xrd) / lSteps ); - - lSteps--; - this->setPos(xt, yt, zt); - this->setRot(yRot, xRot); - - // 4J - this collision is carried out to try and stop the lerping push the mob through the floor, - // in which case gravity can then carry on moving the mob because the collision just won't work anymore. - // BB for collision used to be calculated as: bb->shrink(1 / 32.0, 0, 1 / 32.0) - // now using a reduced BB to try and get rid of some issues where mobs pop up the sides of walls, undersides of - // trees etc. - AABB *shrinkbb = bb->shrink(0.1, 0, 0.1); - shrinkbb->y1 = shrinkbb->y0 + 0.1; - AABBList *collisions = level->getCubes(shared_from_this(), shrinkbb); - if (collisions->size() > 0) - { - double yTop = 0; - AUTO_VAR(itEnd, collisions->end()); - for (AUTO_VAR(it, collisions->begin()); it != itEnd; it++) - { - AABB *ab = *it; //collisions->at(i); - if (ab->y1 > yTop) yTop = ab->y1; - } + LivingEntity::addAdditonalSaveData(entityTag); + entityTag->putBoolean(L"CanPickUpLoot", canPickUpLoot()); + entityTag->putBoolean(L"PersistenceRequired", persistenceRequired); - yt += yTop - bb->y0; - setPos(xt, yt, zt); - } - if (abs(xd) < MIN_MOVEMENT_DISTANCE) xd = 0; - if (abs(yd) < MIN_MOVEMENT_DISTANCE) yd = 0; - if (abs(zd) < MIN_MOVEMENT_DISTANCE) zd = 0; - } - - if (isImmobile()) + ListTag *gear = new ListTag(); + for (int i = 0; i < equipment.length; i++) { - jumping = false; - xxa = 0; - yya = 0; - yRotA = 0; - } - else + CompoundTag *tag = new CompoundTag(); + if (equipment[i] != NULL) equipment[i]->save(tag); + gear->add(tag); + } + entityTag->put(L"Equipment", gear); + + ListTag *dropChanceList = new ListTag(); + for (int i = 0; i < dropChances.length; i++) { - MemSect(25); - if (isEffectiveAI()) - { - if (useNewAi()) - { - newServerAiStep(); - } - else - { - serverAiStep(); - yHeadRot = yRot; - } - } - MemSect(0); + dropChanceList->add(new FloatTag( _toString(i), dropChances[i])); } + entityTag->put(L"DropChances", dropChanceList); + entityTag->putString(L"CustomName", getCustomName()); + entityTag->putBoolean(L"CustomNameVisible", isCustomNameVisible()); - if (jumping) + // leash info + entityTag->putBoolean(L"Leashed", _isLeashed); + if (leashHolder != NULL) { - if (isInWater() || isInLava() ) + CompoundTag *leashTag = new CompoundTag(L"Leash"); + if ( leashHolder->instanceof(eTYPE_LIVINGENTITY) ) { - yd += 0.04f; + // a walking, talking, leash holder + leashTag->putString(L"UUID", leashHolder->getUUID()); } - else if (onGround) + else if ( leashHolder->instanceof(eTYPE_HANGING_ENTITY) ) { - if (noJumpDelay == 0) - { - jumpFromGround(); - noJumpDelay = 10; - } + // a fixed holder (that doesn't save itself) + shared_ptr hangInThere = dynamic_pointer_cast(leashHolder); + leashTag->putInt(L"X", hangInThere->xTile); + leashTag->putInt(L"Y", hangInThere->yTile); + leashTag->putInt(L"Z", hangInThere->zTile); } + entityTag->put(L"Leash", leashTag); } - else - { - noJumpDelay = 0; - } +} + +void Mob::readAdditionalSaveData(CompoundTag *tag) +{ + LivingEntity::readAdditionalSaveData(tag); + setCanPickUpLoot(tag->getBoolean(L"CanPickUpLoot")); + persistenceRequired = tag->getBoolean(L"PersistenceRequired"); + if (tag->contains(L"CustomName") && tag->getString(L"CustomName").length() > 0) setCustomName(tag->getString(L"CustomName")); + setCustomNameVisible(tag->getBoolean(L"CustomNameVisible")); - xxa *= 0.98f; - yya *= 0.98f; - yRotA *= 0.9f; + if (tag->contains(L"Equipment")) + { + ListTag *gear = (ListTag *) tag->getList(L"Equipment"); - float normalSpeed = walkingSpeed; - walkingSpeed *= getWalkingSpeedModifier(); - travel(xxa, yya); - walkingSpeed = normalSpeed; + for (int i = 0; i < equipment.length; i++) + { + equipment[i] = ItemInstance::fromTag(gear->get(i)); + } + } - if(!level->isClientSide) + if (tag->contains(L"DropChances")) { - vector > *entities = level->getEntities(shared_from_this(), this->bb->grow(0.2f, 0, 0.2f)); - if (entities != NULL && !entities->empty()) + ListTag *items = (ListTag *) tag->getList(L"DropChances"); + for (int i = 0; i < items->size(); i++) { - AUTO_VAR(itEnd, entities->end()); - for (AUTO_VAR(it, entities->begin()); it != itEnd; it++) - { - shared_ptr e = *it; //entities->at(i); - if (e->isPushable()) e->push(shared_from_this()); - } + dropChances[i] = items->get(i)->data; } } -} -bool Mob::useNewAi() -{ - return false; + _isLeashed = tag->getBoolean(L"Leashed"); + if (_isLeashed && tag->contains(L"Leash")) + { + leashInfoTag = (CompoundTag *)tag->getCompound(L"Leash")->copy(); + } } -bool Mob::isEffectiveAI() +void Mob::setYya(float yya) { - return !level->isClientSide; + this->yya = yya; } -bool Mob::isImmobile() +void Mob::setSpeed(float speed) { - return health <= 0; + LivingEntity::setSpeed(speed); + setYya(speed); } -bool Mob::isBlocking() +void Mob::aiStep() { - return false; -} + LivingEntity::aiStep(); -void Mob::jumpFromGround() -{ - yd = 0.42f; - if (hasEffect(MobEffect::jump)) - { - yd += (getEffect(MobEffect::jump)->getAmplifier() + 1) * .1f; - } - if (isSprinting()) + if (!level->isClientSide && canPickUpLoot() && !dead && level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) { - float rr = yRot * Mth::RAD_TO_GRAD; + vector > *entities = level->getEntitiesOfClass(typeid(ItemEntity), bb->grow(1, 0, 1)); + for (AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) + { + shared_ptr entity = dynamic_pointer_cast(*it); + if (entity->removed || entity->getItem() == NULL) continue; + shared_ptr item = entity->getItem(); + int slot = getEquipmentSlotForItem(item); - xd -= Mth::sin(rr) * 0.2f; - zd += Mth::cos(rr) * 0.2f; + if (slot > -1) + { + bool replace = true; + shared_ptr current = getCarried(slot); + + if (current != NULL) + { + if (slot == SLOT_WEAPON) + { + WeaponItem *newWeapon = dynamic_cast(item->getItem()); + WeaponItem *oldWeapon = dynamic_cast(current->getItem()); + if ( newWeapon != NULL && oldWeapon == NULL) + { + replace = true; + } + else if (newWeapon != NULL && oldWeapon != NULL) + { + if (newWeapon->getTierDamage() == oldWeapon->getTierDamage()) + { + replace = item->getAuxValue() > current->getAuxValue() || item->hasTag() && !current->hasTag(); + } + else + { + replace = newWeapon->getTierDamage() > oldWeapon->getTierDamage(); + } + } + else + { + replace = false; + } + } + else + { + ArmorItem *newArmor = dynamic_cast(item->getItem()); + ArmorItem *oldArmor = dynamic_cast(current->getItem()); + if (newArmor != NULL && oldArmor == NULL) + { + replace = true; + } + else if (newArmor != NULL && oldArmor != NULL) + { + if (newArmor->defense == oldArmor->defense) + { + replace = item->getAuxValue() > current->getAuxValue() || item->hasTag() && !current->hasTag(); + } + else + { + replace = newArmor->defense > oldArmor->defense; + } + } + else + { + replace = false; + } + } + } + + if (replace) + { + if (current != NULL && random->nextFloat() - 0.1f < dropChances[slot]) + { + spawnAtLocation(current, 0); + } + + setEquippedSlot(slot, item); + dropChances[slot] = 2; + persistenceRequired = true; + take(entity, 1); + entity->remove(); + } + } + } + delete entities; } - this->hasImpulse = true; +} + +bool Mob::useNewAi() +{ + return false; } bool Mob::removeWhenFarAway() @@ -1350,6 +464,11 @@ bool Mob::removeWhenFarAway() void Mob::checkDespawn() { + if (persistenceRequired) + { + noActionTime = 0; + return; + } shared_ptr player = level->getNearestPlayer(shared_from_this(), -1); if (player != NULL) { @@ -1376,36 +495,54 @@ void Mob::checkDespawn() void Mob::newServerAiStep() { + PIXBeginNamedEvent(0,"Tick target selector for %d",GetType()); MemSect(51); noActionTime++; + PIXBeginNamedEvent(0,"Check despawn"); checkDespawn(); - sensing->tick(); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Tick sensing"); + sensing->tick(); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Tick target selector"); targetSelector.tick(); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Tick goal selectors"); goalSelector.tick(); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Tick navigation"); navigation->tick(); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Tick server ai mob step"); serverAiMobStep(); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Tick move"); moveControl->tick(); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Tick look"); lookControl->tick(); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Tick jump"); jumpControl->tick(); + PIXEndNamedEvent(); // Consider this for extra strolling if it is protected against despawning. We aren't interested in ones that aren't protected as the whole point of this // extra wandering is to potentially transition from protected to not protected. + PIXBeginNamedEvent(0,"Consider extra wandering"); considerForExtraWandering( isDespawnProtected() ); + PIXEndNamedEvent(); MemSect(0); -} - -void Mob::serverAiMobStep() -{ + PIXEndNamedEvent(); } void Mob::serverAiStep() { - noActionTime++; - - checkDespawn(); + LivingEntity::serverAiStep(); xxa = 0; yya = 0; + checkDespawn(); + float lookDistance = 8; if (random->nextFloat() < 0.02f) { @@ -1454,11 +591,12 @@ void Mob::lookAt(shared_ptr e, float yMax, float xMax) double xd = e->x - x; double yd; double zd = e->z - z; + - shared_ptr mob = dynamic_pointer_cast(e); - if(mob != NULL) + if ( e->instanceof(eTYPE_LIVINGENTITY) ) { - yd = (y + getHeadHeight()) - (mob->y + mob->getHeadHeight()); + shared_ptr mob = dynamic_pointer_cast(e); + yd = (mob->y + mob->getHeadHeight()) - (y + getHeadHeight()); } else { @@ -1469,7 +607,7 @@ void Mob::lookAt(shared_ptr e, float yMax, float xMax) float yRotD = (float) (atan2(zd, xd) * 180 / PI) - 90; float xRotD = (float) -(atan2(yd, sd) * 180 / PI); - xRot = -rotlerp(xRot, xRotD, xMax); + xRot = rotlerp(xRot, xRotD, xMax); yRot = rotlerp(yRot, yRotD, yMax); } @@ -1503,59 +641,6 @@ bool Mob::canSpawn() return level->isUnobstructed(bb) && level->getCubes(shared_from_this(), bb)->empty() && !level->containsAnyLiquid_NoLoad(bb); } -void Mob::outOfWorld() -{ - hurt(DamageSource::outOfWorld, 4); -} - -float Mob::getAttackAnim(float a) -{ - float diff = attackAnim - oAttackAnim; - if (diff < 0) diff += 1; - return oAttackAnim + diff * a; -} - - -Vec3 *Mob::getPos(float a) -{ - if (a == 1) - { - return Vec3::newTemp(x, y, z); - } - double x = xo + (this->x - xo) * a; - double y = yo + (this->y - yo) * a; - double z = zo + (this->z - zo) * a; - - return Vec3::newTemp(x, y, z); -} - -Vec3 *Mob::getLookAngle() -{ - return getViewVector(1); -} - -Vec3 *Mob::getViewVector(float a) -{ - if (a == 1) - { - float yCos = Mth::cos(-yRot * Mth::RAD_TO_GRAD - PI); - float ySin = Mth::sin(-yRot * Mth::RAD_TO_GRAD - PI); - float xCos = -Mth::cos(-xRot * Mth::RAD_TO_GRAD); - float xSin = Mth::sin(-xRot * Mth::RAD_TO_GRAD); - - return Vec3::newTemp(ySin * xCos, xSin, yCos * xCos); - } - float xRot = xRotO + (this->xRot - xRotO) * a; - float yRot = yRotO + (this->yRot - yRotO) * a; - - float yCos = Mth::cos(-yRot * Mth::RAD_TO_GRAD - PI); - float ySin = Mth::sin(-yRot * Mth::RAD_TO_GRAD - PI); - float xCos = -Mth::cos(-xRot * Mth::RAD_TO_GRAD); - float xSin = Mth::sin(-xRot * Mth::RAD_TO_GRAD); - - return Vec3::newTemp(ySin * xCos, xSin, yCos * xCos); -} - float Mob::getSizeScale() { return 1.0f; @@ -1566,362 +651,421 @@ float Mob::getHeadSizeScale() return 1.0f; } -HitResult *Mob::pick(double range, float a) -{ - Vec3 *from = getPos(a); - Vec3 *b = getViewVector(a); - Vec3 *to = from->add(b->x * range, b->y * range, b->z * range); - return level->clip(from, to); -} - int Mob::getMaxSpawnClusterSize() { return 4; } -shared_ptr Mob::getCarriedItem() +int Mob::getMaxFallDistance() { - return nullptr; + if (getTarget() == NULL) return 3; + int sacrifice = (int) (getHealth() - (getMaxHealth() * 0.33f)); + sacrifice -= (3 - level->difficulty) * 4; + if (sacrifice < 0) sacrifice = 0; + return sacrifice + 3; } -shared_ptr Mob::getArmor(int pos) +shared_ptr Mob::getCarriedItem() { - // 4J Stu - Not implemented yet - return nullptr; - //return equipment[pos + 1]; + return equipment[SLOT_WEAPON]; } -void Mob::handleEntityEvent(byte id) +shared_ptr Mob::getCarried(int slot) { - if (id == EntityEvent::HURT) - { - this->walkAnimSpeed = 1.5f; - - invulnerableTime = invulnerableDuration; - hurtTime = hurtDuration = 10; - hurtDir = 0; - - MemSect(31); - // 4J-PB -added because villagers have no sounds - int iHurtSound=getHurtSound(); - if(iHurtSound!=-1) - { - level->playSound(shared_from_this(), iHurtSound, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); - } - MemSect(0); - hurt(DamageSource::genericSource, 0); - } - else if (id == EntityEvent::DEATH) - { - MemSect(31); - // 4J-PB -added because villagers have no sounds - int iDeathSound=getDeathSound(); - if(iDeathSound!=-1) - { - level->playSound(shared_from_this(), iDeathSound, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); - } - MemSect(0); - health = 0; - die(DamageSource::genericSource); - } - else - { - Entity::handleEntityEvent(id); - } + return equipment[slot]; } -bool Mob::isSleeping() +shared_ptr Mob::getArmor(int pos) { - return false; + return equipment[pos + 1]; } -Icon *Mob::getItemInHandIcon(shared_ptr item, int layer) +void Mob::setEquippedSlot(int slot, shared_ptr item) { - return item->getIcon(); + equipment[slot] = item; } -// 4J added so we can not render mobs before their chunks are loaded - to resolve bug 10327 :Gameplay: NPCs can spawn over chunks that have not yet been streamed and display jitter. -bool Mob::shouldRender(Vec3 *c) +ItemInstanceArray Mob::getEquipmentSlots() { - if( !level->reallyHasChunksAt( Mth::floor(bb->x0), Mth::floor(bb->y0), Mth::floor(bb->z0), Mth::floor(bb->x1), Mth::floor(bb->y1), Mth::floor(bb->z1))) - { - return false; - } - return Entity::shouldRender(c); + return equipment; } -void Mob::tickEffects() +void Mob::dropEquipment(bool byPlayer, int playerBonusLevel) { - bool removed = false; - for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end();) + for (int slot = 0; slot < getEquipmentSlots().length; slot++) { - MobEffectInstance *effect = it->second; - removed = false; - if (!effect->tick(dynamic_pointer_cast(shared_from_this()))) + shared_ptr item = getCarried(slot); + bool preserve = dropChances[slot] > 1; + + if (item != NULL && (byPlayer || preserve) && random->nextFloat() - playerBonusLevel * 0.01f < dropChances[slot]) { - if (!level->isClientSide) + if (!preserve && item->isDamageableItem()) { - it = activeEffects.erase( it ); - onEffectRemoved(effect); - delete effect; - removed = true; + int _max = max(item->getMaxDamage() - 25, 1); + int damage = item->getMaxDamage() - random->nextInt(random->nextInt(_max) + 1); + if (damage > _max) damage = _max; + if (damage < 1) damage = 1; + item->setAuxValue(damage); } - } - if(!removed) - { - ++it; + spawnAtLocation(item, 0); } } - if (effectsDirty) +} + +void Mob::populateDefaultEquipmentSlots() +{ + if (random->nextFloat() < MAX_WEARING_ARMOR_CHANCE * level->getDifficulty(x, y, z)) { - if (!level->isClientSide) + int armorType = random->nextInt(2); + float partialChance = level->difficulty == Difficulty::HARD ? 0.1f : 0.25f; + if (random->nextFloat() < 0.095f) armorType++; + if (random->nextFloat() < 0.095f) armorType++; + if (random->nextFloat() < 0.095f) armorType++; + + for (int i = 3; i >= 0; i--) { - if (activeEffects.empty()) - { - entityData->set(DATA_EFFECT_COLOR_ID, (int) 0); - setInvisible(false); - setWeakened(false); - } - else + shared_ptr item = getArmor(i); + if (i < 3 && random->nextFloat() < partialChance) break; + if (item == NULL) { - vector values; - for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end();++it) - { - values.push_back(it->second); - } - int colorValue = PotionBrewing::getColorValue(&values); - values.clear(); - entityData->set(DATA_EFFECT_COLOR_ID, colorValue); - setInvisible(hasEffect(MobEffect::invisibility->id)); - setWeakened(hasEffect(MobEffect::weakness->id)); + Item *equip = getEquipmentForSlot(i + 1, armorType); + if (equip != NULL) setEquippedSlot(i + 1, shared_ptr(new ItemInstance(equip))); } } - effectsDirty = false; } - if (random->nextBoolean()) +} + +int Mob::getEquipmentSlotForItem(shared_ptr item) +{ + if (item->id == Tile::pumpkin_Id || item->id == Item::skull_Id) { - int colorValue = entityData->getInteger(DATA_EFFECT_COLOR_ID); - if (colorValue > 0) - { - double red = (double) ((colorValue >> 16) & 0xff) / 255.0; - double green = (double) ((colorValue >> 8) & 0xff) / 255.0; - double blue = (double) ((colorValue >> 0) & 0xff) / 255.0; + return SLOT_HELM; + } - level->addParticle(eParticleType_mobSpell, x + (random->nextDouble() - 0.5) * bbWidth, y + random->nextDouble() * bbHeight - heightOffset, z + (random->nextDouble() - 0.5) * bbWidth, red, green, blue); + ArmorItem *armorItem = dynamic_cast(item->getItem()); + if (armorItem != NULL) + { + switch (armorItem->slot) + { + case ArmorItem::SLOT_FEET: + return SLOT_BOOTS; + case ArmorItem::SLOT_LEGS: + return SLOT_LEGGINGS; + case ArmorItem::SLOT_TORSO: + return SLOT_CHEST; + case ArmorItem::SLOT_HEAD: + return SLOT_HELM; } } + + return SLOT_WEAPON; } -void Mob::removeAllEffects() +Item *Mob::getEquipmentForSlot(int slot, int type) { - //Iterator effectIdIterator = activeEffects.keySet().iterator(); - //while (effectIdIterator.hasNext()) - for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end(); ) + switch (slot) { - //Integer effectId = effectIdIterator.next(); - MobEffectInstance *effect = it->second;//activeEffects.get(effectId); + case SLOT_HELM: + if (type == 0) return Item::helmet_leather; + if (type == 1) return Item::helmet_gold; + if (type == 2) return Item::helmet_chain; + if (type == 3) return Item::helmet_iron; + if (type == 4) return Item::helmet_diamond; + case SLOT_CHEST: + if (type == 0) return Item::chestplate_leather; + if (type == 1) return Item::chestplate_gold; + if (type == 2) return Item::chestplate_chain; + if (type == 3) return Item::chestplate_iron; + if (type == 4) return Item::chestplate_diamond; + case SLOT_LEGGINGS: + if (type == 0) return Item::leggings_leather; + if (type == 1) return Item::leggings_gold; + if (type == 2) return Item::leggings_chain; + if (type == 3) return Item::leggings_iron; + if (type == 4) return Item::leggings_diamond; + case SLOT_BOOTS: + if (type == 0) return Item::boots_leather; + if (type == 1) return Item::boots_gold; + if (type == 2) return Item::boots_chain; + if (type == 3) return Item::boots_iron; + if (type == 4) return Item::boots_diamond; + } - if (!level->isClientSide) - { - //effectIdIterator.remove(); - it = activeEffects.erase(it); - onEffectRemoved(effect); - delete effect; - } - else + return NULL; +} + +void Mob::populateDefaultEquipmentEnchantments() +{ + float difficulty = level->getDifficulty(x, y, z); + + if (getCarriedItem() != NULL && random->nextFloat() < MAX_ENCHANTED_WEAPON_CHANCE * difficulty) { + EnchantmentHelper::enchantItem(random, getCarriedItem(), (int) (5 + difficulty * random->nextInt(18))); + } + + for (int i = 0; i < 4; i++) + { + shared_ptr item = getArmor(i); + if (item != NULL && random->nextFloat() < MAX_ENCHANTED_ARMOR_CHANCE * difficulty) { - ++it; + EnchantmentHelper::enchantItem(random, item, (int) (5 + difficulty * random->nextInt(18))); } } } -vector *Mob::getActiveEffects() +/** +* Added this method so mobs can handle their own spawn settings instead of +* hacking MobSpawner.java +* +* @param groupData +* TODO +* @return TODO +*/ +MobGroupData *Mob::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param { - vector *active = new vector(); + // 4J Stu - Take this out, it's not great and nobody will notice. Also not great for performance. + //getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->addModifier(new AttributeModifier(random->nextGaussian() * 0.05, AttributeModifier::OPERATION_MULTIPLY_BASE)); - for(AUTO_VAR(it, activeEffects.begin()); it != activeEffects.end(); ++it) - { - active->push_back(it->second); - } + return groupData; +} - return active; +void Mob::finalizeSpawnEggSpawn(int extraData) +{ } -bool Mob::hasEffect(int id) +bool Mob::canBeControlledByRider() { - return activeEffects.find(id) != activeEffects.end();; + return false; } -bool Mob::hasEffect(MobEffect *effect) +wstring Mob::getAName() { - return activeEffects.find(effect->id) != activeEffects.end(); + if (hasCustomName()) return getCustomName(); + return LivingEntity::getAName(); } -MobEffectInstance *Mob::getEffect(MobEffect *effect) +void Mob::setPersistenceRequired() { - MobEffectInstance *effectInst = NULL; + persistenceRequired = true; +} - AUTO_VAR(it, activeEffects.find(effect->id)); - if(it != activeEffects.end() ) effectInst = it->second; +void Mob::setCustomName(const wstring &name) +{ + entityData->set(DATA_CUSTOM_NAME, name); +} - return effectInst; +wstring Mob::getCustomName() +{ + return entityData->getString(DATA_CUSTOM_NAME); } -void Mob::addEffect(MobEffectInstance *newEffect) +bool Mob::hasCustomName() { - if (!canBeAffected(newEffect)) - { - return; - } + return entityData->getString(DATA_CUSTOM_NAME).length() > 0; +} - if (activeEffects.find(newEffect->getId()) != activeEffects.end() ) - { - // replace effect and update - MobEffectInstance *effectInst = activeEffects.find(newEffect->getId())->second; - effectInst->update(newEffect); - onEffectUpdated(effectInst); - } - else - { - activeEffects.insert( unordered_map::value_type( newEffect->getId(), newEffect ) ); - onEffectAdded(newEffect); - } +void Mob::setCustomNameVisible(bool visible) +{ + entityData->set(DATA_CUSTOM_NAME_VISIBLE, visible ? (byte) 1 : (byte) 0); } -// 4J Added -void Mob::addEffectNoUpdate(MobEffectInstance *newEffect) +bool Mob::isCustomNameVisible() { - if (!canBeAffected(newEffect)) - { - return; - } + return entityData->getByte(DATA_CUSTOM_NAME_VISIBLE) == 1; +} - if (activeEffects.find(newEffect->getId()) != activeEffects.end() ) - { - // replace effect and update - MobEffectInstance *effectInst = activeEffects.find(newEffect->getId())->second; - effectInst->update(newEffect); - } - else - { - activeEffects.insert( unordered_map::value_type( newEffect->getId(), newEffect ) ); - } +bool Mob::shouldShowName() +{ + return isCustomNameVisible(); } -bool Mob::canBeAffected(MobEffectInstance *newEffect) +void Mob::setDropChance(int slot, float pct) { - if (getMobType() == UNDEAD) - { - int id = newEffect->getId(); - if (id == MobEffect::regeneration->id || id == MobEffect::poison->id) - { - return false; - } - } + dropChances[slot] = pct; +} - return true; +bool Mob::canPickUpLoot() +{ + return _canPickUpLoot; } -bool Mob::isInvertedHealAndHarm() +void Mob::setCanPickUpLoot(bool canPickUpLoot) { - return getMobType() == UNDEAD; + _canPickUpLoot = canPickUpLoot; } -void Mob::removeEffectNoUpdate(int effectId) +bool Mob::isPersistenceRequired() { - AUTO_VAR(it, activeEffects.find(effectId)); - if (it != activeEffects.end()) - { - MobEffectInstance *effect = it->second; - if(effect != NULL) - { - delete effect; - } - activeEffects.erase(it); - } + return persistenceRequired; } -void Mob::removeEffect(int effectId) +bool Mob::interact(shared_ptr player) { - AUTO_VAR(it, activeEffects.find(effectId)); - if (it != activeEffects.end()) + + if (isLeashed() && getLeashHolder() == player) + { + dropLeash(true, !player->abilities.instabuild); + return true; + } + + shared_ptr itemstack = player->inventory->getSelected(); + if (itemstack != NULL) { - MobEffectInstance *effect = it->second; - if(effect != NULL) + // it's inconvenient to have the leash code here, but it's because + // the mob.interact(player) method has priority over + // item.interact(mob) + if (itemstack->id == Item::lead_Id) { - onEffectRemoved(effect); - delete effect; + if (canBeLeashed()) + { + shared_ptr tamableAnimal = nullptr; + if ( shared_from_this()->instanceof(eTYPE_TAMABLE_ANIMAL) + && (tamableAnimal = dynamic_pointer_cast(shared_from_this()))->isTame() ) // 4J-JEV: excuse the assignment operator in here, don't want to dyn-cast if it's avoidable. + { + if (player->getUUID().compare(tamableAnimal->getOwnerUUID()) == 0) + { + setLeashedTo(player, true); + itemstack->count--; + return true; + } + } + else + { + setLeashedTo(player, true); + itemstack->count--; + return true; + } + } } - activeEffects.erase(it); } -} -void Mob::onEffectAdded(MobEffectInstance *effect) -{ - effectsDirty = true; -} + if (mobInteract(player)) + { + return true; + } -void Mob::onEffectUpdated(MobEffectInstance *effect) -{ - effectsDirty = true; + return LivingEntity::interact(player); } -void Mob::onEffectRemoved(MobEffectInstance *effect) +bool Mob::mobInteract(shared_ptr player) { - effectsDirty = true; + return false; } -float Mob::getWalkingSpeedModifier() +void Mob::tickLeash() { - float speed = 1.0f; - if (hasEffect(MobEffect::movementSpeed)) + if (leashInfoTag != NULL) + { + restoreLeashFromSave(); + } + if (!_isLeashed) + { + return; + } + + if (leashHolder == NULL || leashHolder->removed) { - speed *= 1.0f + .2f * (getEffect(MobEffect::movementSpeed)->getAmplifier() + 1); + dropLeash(true, true); + return; } - if (hasEffect(MobEffect::movementSlowdown)) +} + +void Mob::dropLeash(bool synch, bool createItemDrop) +{ + if (_isLeashed) { - speed *= 1.0f - .15f * (getEffect(MobEffect::movementSlowdown)->getAmplifier() + 1); + _isLeashed = false; + leashHolder = nullptr; + if (!level->isClientSide && createItemDrop) + { + spawnAtLocation(Item::lead_Id, 1); + } + + ServerLevel *serverLevel = dynamic_cast(level); + if (!level->isClientSide && synch && serverLevel != NULL) + { + serverLevel->getTracker()->broadcast(shared_from_this(), shared_ptr(new SetEntityLinkPacket(SetEntityLinkPacket::LEASH, shared_from_this(), nullptr))); + } } - return speed; } -void Mob::teleportTo(double x, double y, double z) +bool Mob::canBeLeashed() { - moveTo(x, y, z, yRot, xRot); + return !isLeashed() && !shared_from_this()->instanceof(eTYPE_ENEMY); } -bool Mob::isBaby() +bool Mob::isLeashed() { - return false; + return _isLeashed; } -MobType Mob::getMobType() +shared_ptr Mob::getLeashHolder() { - return UNDEFINED; + return leashHolder; } -void Mob::breakItem(shared_ptr itemInstance) +void Mob::setLeashedTo(shared_ptr holder, bool synch) { - level->playSound(shared_from_this(), eSoundType_RANDOM_BREAK, 0.8f, 0.8f + level->random->nextFloat() * 0.4f); + _isLeashed = true; + leashHolder = holder; + + ServerLevel *serverLevel = dynamic_cast(level); + if (!level->isClientSide && synch && serverLevel) + { + serverLevel->getTracker()->broadcast(shared_from_this(), shared_ptr( new SetEntityLinkPacket(SetEntityLinkPacket::LEASH, shared_from_this(), leashHolder))); + } +} - for (int i = 0; i < 5; i++) +void Mob::restoreLeashFromSave() +{ + // after being added to the world, attempt to recreate leash bond + if (_isLeashed && leashInfoTag != NULL) { - Vec3 *d = Vec3::newTemp((random->nextFloat() - 0.5) * 0.1, Math::random() * 0.1 + 0.1, 0); - d->xRot(-xRot * PI / 180); - d->yRot(-yRot * PI / 180); - - Vec3 *p = Vec3::newTemp((random->nextFloat() - 0.5) * 0.3, -random->nextFloat() * 0.6 - 0.3, 0.6); - p->xRot(-xRot * PI / 180); - p->yRot(-yRot * PI / 180); - p = p->add(x, y + getHeadHeight(), z); - level->addParticle(PARTICLE_ICONCRACK(itemInstance->getItem()->id,0), p->x, p->y, p->z, d->x, d->y + 0.05, d->z); + if (leashInfoTag->contains(L"UUID")) + { + wstring leashUuid = leashInfoTag->getString(L"UUID"); + vector > *livingEnts = level->getEntitiesOfClass(typeid(LivingEntity), bb->grow(10, 10, 10)); + for(AUTO_VAR(it, livingEnts->begin()); it != livingEnts->end(); ++it) + { + shared_ptr le = dynamic_pointer_cast(*it); + if (le->getUUID().compare(leashUuid) == 0) + { + leashHolder = le; + setLeashedTo(leashHolder, true); + break; + } + } + delete livingEnts; + } + else if (leashInfoTag->contains(L"X") && leashInfoTag->contains(L"Y") && leashInfoTag->contains(L"Z")) + { + int x = leashInfoTag->getInt(L"X"); + int y = leashInfoTag->getInt(L"Y"); + int z = leashInfoTag->getInt(L"Z"); + + shared_ptr activeKnot = LeashFenceKnotEntity::findKnotAt(level, x, y, z); + if (activeKnot == NULL) + { + activeKnot = LeashFenceKnotEntity::createAndAddKnot(level, x, y, z); + } + leashHolder = activeKnot; + setLeashedTo(leashHolder, true); + } + else + { + dropLeash(false, true); + } } + leashInfoTag = NULL; } -bool Mob::isInvulnerable() +// 4J added so we can not render mobs before their chunks are loaded - to resolve bug 10327 :Gameplay: NPCs can spawn over chunks that have not yet been streamed and display jitter. +bool Mob::shouldRender(Vec3 *c) { - // 4J-JEV: I have no idea what was going on here (it gets changed in a later java version). - return invulnerableTime > 0; // invulnerableTime <= invulnerableTime / 2; + if( !level->reallyHasChunksAt( Mth::floor(bb->x0), Mth::floor(bb->y0), Mth::floor(bb->z0), Mth::floor(bb->x1), Mth::floor(bb->y1), Mth::floor(bb->z1))) + { + return false; + } + return Entity::shouldRender(c); } void Mob::setLevel(Level *level) @@ -1930,14 +1074,4 @@ void Mob::setLevel(Level *level) navigation->setLevel(level); goalSelector.setLevel(level); targetSelector.setLevel(level); -} - -void Mob::finalizeMobSpawn() -{ - -} - -bool Mob::canBeControlledByRider() -{ - return false; -} +} \ No newline at end of file diff --git a/Minecraft.World/Mob.h b/Minecraft.World/Mob.h index 0e1af2be..11310509 100644 --- a/Minecraft.World/Mob.h +++ b/Minecraft.World/Mob.h @@ -1,7 +1,7 @@ #pragma once using namespace std; -#include "Entity.h" +#include "LivingEntity.h" #include "MobType.h" #include "GoalSelector.h" @@ -19,105 +19,33 @@ class PathNavigation; class Sensing; class Icon; class Pos; +class MobGroupData; -class Mob : public Entity +class Mob : public LivingEntity { friend class MobSpawner; -protected: - // 4J - added for common ctor code - void _init(); public: - Mob(Level* level); - virtual ~Mob(); - // 4J-PB - added to replace (e instanceof Type), avoiding dynamic casts eINSTANCEOF GetType() { return eTYPE_MOB;} static Entity *create(Level *level) { return NULL; } public: - static const int ATTACK_DURATION = 5; - static const int PLAYER_HURT_EXPERIENCE_TIME = 20 * 3; - -public: // 4J Stu - Made public - static const int DATA_EFFECT_COLOR_ID = 8; + static const float MAX_WEARING_ARMOR_CHANCE; + static const float MAX_PICKUP_LOOT_CHANCE; + static const float MAX_ENCHANTED_ARMOR_CHANCE; + static const float MAX_ENCHANTED_WEAPON_CHANCE; private: - static const double MIN_MOVEMENT_DISTANCE; - -public: - int invulnerableDuration; - float timeOffs; - float rotA; - float yBodyRot, yBodyRotO; - float yHeadRot, yHeadRotO; - -protected: - float oRun, run; - float animStep, animStepO; - bool hasHair; - // wstring textureName; - int textureIdx; // 4J changed from wstring textureName - bool allowAlpha; - float rotOffs; - wstring modelName; - float bobStrength; - int deathScore; - float renderOffset; - -public: - float walkingSpeed; - float flyingSpeed; - float oAttackAnim, attackAnim; - -protected: - int health; - -public: - int lastHealth; - -protected: - int dmgSpill; + static const int DATA_CUSTOM_NAME = 10; + static const int DATA_CUSTOM_NAME_VISIBLE = 11; public: int ambientSoundTime; - int hurtTime; - int hurtDuration; - float hurtDir; - int deathTime; - int attackTime; - float oTilt, tilt; protected: - bool dead; int xpReward; -public: - int modelNum; - float animSpeed; - float walkAnimSpeedO; - float walkAnimSpeed; - float walkAnimPos; - -protected: - shared_ptr lastHurtByPlayer; - int lastHurtByPlayerTime; - private: - shared_ptr lastHurtByMob; - int lastHurtByMobTime; - shared_ptr lastHurtMob; - -public: - int arrowCount; - int removeArrowTime; - -protected: - map activeEffects; - -private: - bool effectsDirty; - int effectColor; - LookControl *lookControl; MoveControl *moveControl; JumpControl *jumpControl; @@ -129,12 +57,28 @@ protected: GoalSelector targetSelector; private: - shared_ptr target; + shared_ptr target; Sensing *sensing; - float speed; - Pos *restrictCenter; - float restrictRadius; + ItemInstanceArray equipment; + +protected: + floatArray dropChances; + +private: + bool _canPickUpLoot; + bool persistenceRequired; + +protected: + // 4J - added for common ctor code + void _init(); + +public: + Mob(Level* level); + virtual ~Mob(); + +protected: + void registerAttributes(); public: virtual LookControl *getLookControl(); @@ -142,147 +86,46 @@ public: virtual JumpControl *getJumpControl(); virtual PathNavigation *getNavigation(); virtual Sensing *getSensing(); - virtual Random *getRandom(); - virtual shared_ptr getLastHurtByMob(); - virtual shared_ptr getLastHurtMob(); - void setLastHurtMob(shared_ptr target); - virtual int getNoActionTime(); - float getYHeadRot(); - void setYHeadRot(float yHeadRot); - float getSpeed(); - void setSpeed(float speed); - virtual bool doHurtTarget(shared_ptr target); - shared_ptr getTarget(); - virtual void setTarget(shared_ptr target); + shared_ptr getTarget(); + virtual void setTarget(shared_ptr target); virtual bool canAttackType(eINSTANCEOF targetType); virtual void ate(); - bool isWithinRestriction(); - bool isWithinRestriction(int x, int y, int z); - void restrictTo(int x, int y, int z, int radius); - Pos *getRestrictCenter(); - float getRestrictRadius(); - void clearRestriction(); - bool hasRestriction(); - - virtual void setLastHurtByMob(shared_ptr hurtBy); - protected: virtual void defineSynchedData(); public: - bool canSee(shared_ptr target); - virtual int getTexture(); // 4J - changed from wstring to int - virtual bool isPickable() ; - virtual bool isPushable(); - virtual float getHeadHeight(); virtual int getAmbientSoundInterval(); void playAmbientSound(); virtual void baseTick(); protected: - virtual void tickDeath(); - virtual int decreaseAirSupply(int currentSupply); virtual int getExperienceReward(shared_ptr killedBy); - virtual bool isAlwaysExperienceDropper(); - -public: - void spawnAnim(); - virtual void rideTick(); - -protected: - int lSteps; - double lx, ly, lz, lyr, lxr; public: - virtual void lerpTo(double x, double y, double z, float yRot, float xRot, int steps); - -private: - float fallTime; - -public: - void superTick(); + virtual void spawnAnim(); virtual void tick(); - virtual void heal(int heal); - virtual int getMaxHealth() = 0; - virtual int getHealth(); - virtual void setHealth(int health); - -protected: - int lastHurt; - -public: - virtual bool hurt(DamageSource *source, int dmg); protected: - float getVoicePitch(); - -public: - virtual void animateHurt(); - - /** - * Fetches the mob's armor value, from 0 (no armor) to 20 (full armor) - * - * @return - */ - virtual int getArmorValue(); - -protected: - virtual void hurtArmor(int damage); - virtual int getDamageAfterArmorAbsorb(DamageSource *damageSource, int damage); - virtual int getDamageAfterMagicAbsorb(DamageSource *damageSource, int damage); - - virtual void actuallyHurt(DamageSource *source, int dmg); - virtual float getSoundVolume(); + virtual float tickHeadTurn(float yBodyRotT, float walkSpeed); virtual int getAmbientSound(); - virtual int getHurtSound(); - virtual int getDeathSound(); - -public: - void knockback(shared_ptr source, int dmg, double xd, double zd); - virtual void die(DamageSource *source); - -protected: - virtual void dropRareDeathLoot(int rareLootLevel); - virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); virtual int getDeathLoot(); - virtual void causeFallDamage(float distance); + virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); public: - virtual void travel(float xa, float ya); - virtual bool onLadder(); - virtual bool isShootable(); virtual void addAdditonalSaveData(CompoundTag *entityTag); virtual void readAdditionalSaveData(CompoundTag *tag); - virtual bool isAlive(); - virtual bool isWaterMob(); - virtual int getLightColor(float a); // 4J - added protected: - int noActionTime; - float xxa, yya, yRotA; - bool jumping; float defaultLookAngle; - float runSpeed; -protected: - int noJumpDelay; public: virtual void setYya(float yya); - virtual void setJumping(bool jump); - + virtual void setSpeed(float speed); virtual void aiStep(); protected: virtual bool useNewAi(); - virtual bool isEffectiveAI(); - virtual bool isImmobile(); - -public: - virtual bool isBlocking(); - -protected: - virtual void jumpFromGround(); virtual bool removeWhenFarAway(); private: @@ -293,7 +136,6 @@ protected: virtual void checkDespawn(); virtual void newServerAiStep(); - virtual void serverAiMobStep(); virtual void serverAiStep(); public: @@ -309,60 +151,79 @@ private: public: virtual bool canSpawn(); - -protected: - virtual void outOfWorld(); - -public: - float getAttackAnim(float a); - virtual Vec3 *getPos(float a); - virtual Vec3 *getLookAngle(); - Vec3 *getViewVector(float a); virtual float getSizeScale(); virtual float getHeadSizeScale(); - HitResult *pick(double range, float a); virtual int getMaxSpawnClusterSize(); + virtual int getMaxFallDistance(); virtual shared_ptr getCarriedItem(); + virtual shared_ptr getCarried(int slot); virtual shared_ptr getArmor(int pos); - virtual void handleEntityEvent(byte id); - virtual bool isSleeping(); - virtual Icon *getItemInHandIcon(shared_ptr item, int layer); - virtual bool shouldRender(Vec3 *c); + virtual void setEquippedSlot(int slot, shared_ptr item); + virtual ItemInstanceArray getEquipmentSlots(); protected: - void tickEffects(); + virtual void dropEquipment(bool byPlayer, int playerBonusLevel); + virtual void populateDefaultEquipmentSlots(); public: - void removeAllEffects(); - vector *getActiveEffects(); - bool hasEffect(int id); - bool hasEffect(MobEffect *effect); - MobEffectInstance *getEffect(MobEffect *effect); - void addEffect(MobEffectInstance *newEffect); - void addEffectNoUpdate(MobEffectInstance *newEffect); // 4J Added - virtual bool canBeAffected(MobEffectInstance *newEffect); - virtual bool isInvertedHealAndHarm(); - void removeEffectNoUpdate(int effectId); - void removeEffect(int effectId); + static int getEquipmentSlotForItem(shared_ptr item); + static Item *getEquipmentForSlot(int slot, int type); protected: - virtual void onEffectAdded(MobEffectInstance *effect); - virtual void onEffectUpdated(MobEffectInstance *effect); - virtual void onEffectRemoved(MobEffectInstance *effect); + virtual void populateDefaultEquipmentEnchantments(); public: - virtual float getWalkingSpeedModifier(); + /** + * Added this method so mobs can handle their own spawn settings instead of + * hacking MobSpawner.java + * + * @param groupData + * TODO + * @return TODO + */ + virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param + virtual void finalizeSpawnEggSpawn(int extraData); // 4J Added + virtual bool canBeControlledByRider(); + virtual wstring getAName(); + virtual void setPersistenceRequired(); + virtual void setCustomName(const wstring &name); + virtual wstring getCustomName(); + virtual bool hasCustomName(); + virtual void setCustomNameVisible(bool visible); + virtual bool isCustomNameVisible(); + virtual bool shouldShowName(); + virtual void setDropChance(int slot, float pct); + virtual bool canPickUpLoot(); + virtual void setCanPickUpLoot(bool canPickUpLoot); + virtual bool isPersistenceRequired(); + virtual bool interact(shared_ptr player); - // 4J-Pb added (from 1.2.3) - virtual void teleportTo(double x, double y, double z); - virtual bool isBaby(); - virtual MobType getMobType(); - virtual void breakItem(shared_ptr itemInstance); +protected: + virtual bool mobInteract(shared_ptr player); - virtual bool isInvulnerable(); + // roper / leash methods - virtual void finalizeMobSpawn(); - virtual bool canBeControlledByRider(); +private: + bool _isLeashed; + shared_ptr leashHolder; + CompoundTag *leashInfoTag; + +protected: + virtual void tickLeash(); + +public: + virtual void dropLeash(bool synch, bool createItemDrop); + virtual bool canBeLeashed(); + virtual bool isLeashed(); + virtual shared_ptr getLeashHolder(); + virtual void setLeashedTo(shared_ptr holder, bool synch); + +private: + virtual void restoreLeashFromSave(); + virtual bool shouldRender(Vec3 *c); + + +public: // 4J Added override to update ai elements when loading entity from schematics virtual void setLevel(Level *level); diff --git a/Minecraft.World/MobCategory.cpp b/Minecraft.World/MobCategory.cpp index 787b2004..507be6ed 100644 --- a/Minecraft.World/MobCategory.cpp +++ b/Minecraft.World/MobCategory.cpp @@ -7,35 +7,38 @@ MobCategory *MobCategory::monster = NULL; MobCategory *MobCategory::creature = NULL; +MobCategory *MobCategory::ambient = NULL; MobCategory *MobCategory::waterCreature = NULL; // 4J - added these extra categories MobCategory *MobCategory::creature_wolf = NULL; MobCategory *MobCategory::creature_chicken = NULL; MobCategory *MobCategory::creature_mushroomcow = NULL; -MobCategoryArray MobCategory::values = MobCategoryArray(6); +MobCategoryArray MobCategory::values = MobCategoryArray(7); void MobCategory::staticCtor() { // 4J - adjusted the max levels here for the xbox version, which now represent the max levels in the whole world - monster = new MobCategory(70, Material::air, false, eTYPE_MONSTER, false, CONSOLE_MONSTERS_HARD_LIMIT); - creature = new MobCategory(10, Material::air, true, eTYPE_ANIMALS_SPAWN_LIMIT_CHECK, false, CONSOLE_ANIMALS_HARD_LIMIT); - waterCreature = new MobCategory(5, Material::water, true, eTYPE_WATERANIMAL, false, CONSOLE_SQUID_HARD_LIMIT); + monster = new MobCategory(70, Material::air, false, false, eTYPE_MONSTER, false, CONSOLE_MONSTERS_HARD_LIMIT); + creature = new MobCategory(10, Material::air, true, true, eTYPE_ANIMALS_SPAWN_LIMIT_CHECK, false, CONSOLE_ANIMALS_HARD_LIMIT); + ambient = new MobCategory(15, Material::air, true, false, eTYPE_AMBIENT, false, CONSOLE_AMBIENT_HARD_LIMIT), + waterCreature = new MobCategory(5, Material::water, true, false, eTYPE_WATERANIMAL, false, CONSOLE_SQUID_HARD_LIMIT); values[0] = monster; values[1] = creature; - values[2] = waterCreature; + values[2] = ambient; + values[3] = waterCreature; // 4J - added 2 new categories to give us better control over spawning wolves & chickens - creature_wolf = new MobCategory(3, Material::air, true, eTYPE_WOLF, true, MAX_XBOX_WOLVES); - creature_chicken = new MobCategory( 2, Material::air, true, eTYPE_CHICKEN, true, MAX_XBOX_CHICKENS); - creature_mushroomcow = new MobCategory(2, Material::air, true, eTYPE_MUSHROOMCOW, true, MAX_XBOX_MUSHROOMCOWS); - values[3] = creature_wolf; - values[4] = creature_chicken; - values[5] = creature_mushroomcow; + creature_wolf = new MobCategory(3, Material::air, true, true, eTYPE_WOLF, true, MAX_XBOX_WOLVES); + creature_chicken = new MobCategory( 2, Material::air, true, true, eTYPE_CHICKEN, true, MAX_XBOX_CHICKENS); + creature_mushroomcow = new MobCategory(2, Material::air, true, true, eTYPE_MUSHROOMCOW, true, MAX_XBOX_MUSHROOMCOWS); + values[4] = creature_wolf; + values[5] = creature_chicken; + values[6] = creature_mushroomcow; } -MobCategory::MobCategory(int maxVar, Material *spawnPositionMaterial, bool isFriendly, eINSTANCEOF eBase, bool isSingleType, int maxPerLevel) - : m_max(maxVar), spawnPositionMaterial(spawnPositionMaterial), m_isFriendly(isFriendly), m_eBase(eBase), m_isSingleType(isSingleType), m_maxPerLevel(maxPerLevel) +MobCategory::MobCategory(int maxVar, Material *spawnPositionMaterial, bool isFriendly, bool isPersistent, eINSTANCEOF eBase, bool isSingleType, int maxPerLevel) + : m_max(maxVar), spawnPositionMaterial(spawnPositionMaterial), m_isFriendly(isFriendly), m_isPersistent(isPersistent), m_eBase(eBase), m_isSingleType(isSingleType), m_maxPerLevel(maxPerLevel) { } @@ -69,3 +72,8 @@ bool MobCategory::isSingleType() { return m_isSingleType; } + +bool MobCategory::isPersistent() +{ + return m_isPersistent; +} diff --git a/Minecraft.World/MobCategory.h b/Minecraft.World/MobCategory.h index a978c40e..4fe5c826 100644 --- a/Minecraft.World/MobCategory.h +++ b/Minecraft.World/MobCategory.h @@ -9,6 +9,7 @@ public: // 4J - putting constants for xbox spawning in one place to tidy things up a bit - all numbers are per level static const int CONSOLE_MONSTERS_HARD_LIMIT = 50; // Max number of enemies (skeleton, zombie, creeper etc) that the mob spawner will produce static const int CONSOLE_ANIMALS_HARD_LIMIT = 50; // Max number of animals (cows, sheep, pigs) that the mob spawner will produce + static const int CONSOLE_AMBIENT_HARD_LIMIT = 20; // Ambient mobs static const int MAX_XBOX_CHICKENS = 8; // Max number of chickens that the mob spawner will produce static const int MAX_XBOX_WOLVES = 8; // Max number of wolves that the mob spawner will produce @@ -16,6 +17,7 @@ public: static const int MAX_XBOX_SNOWMEN = 16; // Max number of snow golems that can be created by placing blocks - 4J-PB increased limit due to player requests static const int MAX_XBOX_IRONGOLEM = 16; // Max number of iron golems that can be created by placing blocks - 4J-PB increased limit due to player requests static const int CONSOLE_SQUID_HARD_LIMIT = 5; + static const int MAX_CONSOLE_BOSS = 1; // Max number of bosses (enderdragon/wither) static const int MAX_XBOX_ANIMALS_WITH_BREEDING = CONSOLE_ANIMALS_HARD_LIMIT + 20; // Max number of animals that we can produce (in total), when breeding static const int MAX_XBOX_CHICKENS_WITH_BREEDING = MAX_XBOX_CHICKENS + 8; // Max number of chickens that we can produce (in total), when breeding/hatching @@ -30,6 +32,7 @@ public: static const int MAX_XBOX_VILLAGERS_WITH_SPAWN_EGG = MAX_VILLAGERS_WITH_BREEDING + 15; // 4J-PB - increased this limit due to player requests static const int MAX_XBOX_MUSHROOMCOWS_WITH_SPAWN_EGG = MAX_XBOX_MUSHROOMCOWS_WITH_BREEDING + 8; static const int MAX_XBOX_SQUIDS_WITH_SPAWN_EGG = CONSOLE_SQUID_HARD_LIMIT + 8; + static const int MAX_AMBIENT_WITH_SPAWN_EGG = CONSOLE_AMBIENT_HARD_LIMIT + 8; /* Maximum animals = 50 + 20 + 20 = 90 @@ -48,6 +51,7 @@ public: static MobCategory *monster; static MobCategory *creature; + static MobCategory *ambient; static MobCategory *waterCreature; // 4J added extra categories, to break these out of general creatures & give us more control of levels static MobCategory *creature_wolf; @@ -64,10 +68,11 @@ private: const int m_maxPerLevel; const Material *spawnPositionMaterial; const bool m_isFriendly; + const bool m_isPersistent; const bool m_isSingleType; // 4J Added - const eINSTANCEOF m_eBase; // 4J added + const eINSTANCEOF m_eBase; // 4J added - MobCategory(int maxVar, Material *spawnPositionMaterial, bool isFriendly, eINSTANCEOF eBase, bool isSingleType, int maxPerLevel); + MobCategory(int maxVar, Material *spawnPositionMaterial, bool isFriendly, bool isPersistent, eINSTANCEOF eBase, bool isSingleType, int maxPerLevel); public: const type_info getBaseClass(); @@ -77,6 +82,8 @@ public: Material *getSpawnPositionMaterial(); bool isFriendly(); bool isSingleType(); + bool isPersistent(); + public: static void staticCtor(); }; diff --git a/Minecraft.World/MobEffect.cpp b/Minecraft.World/MobEffect.cpp index f9687a15..61aee91f 100644 --- a/Minecraft.World/MobEffect.cpp +++ b/Minecraft.World/MobEffect.cpp @@ -1,5 +1,9 @@ #include "stdafx.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.level.h" #include "net.minecraft.world.damagesource.h" #include "net.minecraft.world.food.h" #include "net.minecraft.world.effect.h" @@ -7,39 +11,74 @@ MobEffect *MobEffect::effects[NUM_EFFECTS]; -MobEffect *MobEffect::voidEffect = NULL; -MobEffect *MobEffect::movementSpeed = (new MobEffect(1, false, eMinecraftColour_Effect_MovementSpeed)) ->setDescriptionId(IDS_POTION_MOVESPEED) ->setPostfixDescriptionId(IDS_POTION_MOVESPEED_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Speed); //setIcon(0, 0); -MobEffect *MobEffect::movementSlowdown = (new MobEffect(2, true, eMinecraftColour_Effect_MovementSlowDown)) ->setDescriptionId(IDS_POTION_MOVESLOWDOWN) ->setPostfixDescriptionId(IDS_POTION_MOVESLOWDOWN_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Slowness); //->setIcon(1, 0); -MobEffect *MobEffect::digSpeed = (new MobEffect(3, false, eMinecraftColour_Effect_DigSpeed)) ->setDescriptionId(IDS_POTION_DIGSPEED) ->setPostfixDescriptionId(IDS_POTION_DIGSPEED_POSTFIX)->setDurationModifier(1.5)->setIcon(MobEffect::e_MobEffectIcon_Haste); //->setIcon(2, 0); -MobEffect *MobEffect::digSlowdown = (new MobEffect(4, true, eMinecraftColour_Effect_DigSlowdown)) ->setDescriptionId(IDS_POTION_DIGSLOWDOWN) ->setPostfixDescriptionId(IDS_POTION_DIGSLOWDOWN_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_MiningFatigue); //->setIcon(3, 0); -MobEffect *MobEffect::damageBoost = (new MobEffect(5, false, eMinecraftColour_Effect_DamageBoost)) ->setDescriptionId(IDS_POTION_DAMAGEBOOST) ->setPostfixDescriptionId(IDS_POTION_DAMAGEBOOST_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Strength); //->setIcon(4, 0); -MobEffect *MobEffect::heal = (new InstantenousMobEffect(6, false, eMinecraftColour_Effect_Heal)) ->setDescriptionId(IDS_POTION_HEAL) ->setPostfixDescriptionId(IDS_POTION_HEAL_POSTFIX); -MobEffect *MobEffect::harm = (new InstantenousMobEffect(7, true, eMinecraftColour_Effect_Harm)) ->setDescriptionId(IDS_POTION_HARM) ->setPostfixDescriptionId(IDS_POTION_HARM_POSTFIX); -MobEffect *MobEffect::jump = (new MobEffect(8, false, eMinecraftColour_Effect_Jump)) ->setDescriptionId(IDS_POTION_JUMP) ->setPostfixDescriptionId(IDS_POTION_JUMP_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_JumpBoost); //->setIcon(2, 1); -MobEffect *MobEffect::confusion = (new MobEffect(9, true, eMinecraftColour_Effect_Confusion)) ->setDescriptionId(IDS_POTION_CONFUSION) ->setPostfixDescriptionId(IDS_POTION_CONFUSION_POSTFIX)->setDurationModifier(.25)->setIcon(MobEffect::e_MobEffectIcon_Nausea); //->setIcon(3, 1); -MobEffect *MobEffect::regeneration = (new MobEffect(10, false, eMinecraftColour_Effect_Regeneration)) ->setDescriptionId(IDS_POTION_REGENERATION) ->setPostfixDescriptionId(IDS_POTION_REGENERATION_POSTFIX)->setDurationModifier(.25)->setIcon(MobEffect::e_MobEffectIcon_Regeneration); //->setIcon(7, 0); -MobEffect *MobEffect::damageResistance = (new MobEffect(11, false, eMinecraftColour_Effect_DamageResistance))->setDescriptionId(IDS_POTION_RESISTANCE) ->setPostfixDescriptionId(IDS_POTION_RESISTANCE_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Resistance); //->setIcon(6, 1); -MobEffect *MobEffect::fireResistance = (new MobEffect(12, false, eMinecraftColour_Effect_FireResistance)) ->setDescriptionId(IDS_POTION_FIRERESISTANCE) ->setPostfixDescriptionId(IDS_POTION_FIRERESISTANCE_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_FireResistance); //->setIcon(7, 1); -MobEffect *MobEffect::waterBreathing = (new MobEffect(13, false, eMinecraftColour_Effect_WaterBreathing)) ->setDescriptionId(IDS_POTION_WATERBREATHING) ->setPostfixDescriptionId(IDS_POTION_WATERBREATHING_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_WaterBreathing); //->setIcon(0, 2); -MobEffect *MobEffect::invisibility = (new MobEffect(14, false, eMinecraftColour_Effect_Invisiblity)) ->setDescriptionId(IDS_POTION_INVISIBILITY) ->setPostfixDescriptionId(IDS_POTION_INVISIBILITY_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Invisiblity); //->setIcon(0, 1); -MobEffect *MobEffect::blindness = (new MobEffect(15, true, eMinecraftColour_Effect_Blindness)) ->setDescriptionId(IDS_POTION_BLINDNESS) ->setPostfixDescriptionId(IDS_POTION_BLINDNESS_POSTFIX)->setDurationModifier(.25)->setIcon(MobEffect::e_MobEffectIcon_Blindness); //->setIcon(5, 1); -MobEffect *MobEffect::nightVision = (new MobEffect(16, false, eMinecraftColour_Effect_NightVision)) ->setDescriptionId(IDS_POTION_NIGHTVISION) ->setPostfixDescriptionId(IDS_POTION_NIGHTVISION_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_NightVision); //->setIcon(4, 1); -MobEffect *MobEffect::hunger = (new MobEffect(17, true, eMinecraftColour_Effect_Hunger)) ->setDescriptionId(IDS_POTION_HUNGER) ->setPostfixDescriptionId(IDS_POTION_HUNGER_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Hunger); //->setIcon(1, 1); -MobEffect *MobEffect::weakness = (new MobEffect(18, true, eMinecraftColour_Effect_Weakness)) ->setDescriptionId(IDS_POTION_WEAKNESS) ->setPostfixDescriptionId(IDS_POTION_WEAKNESS_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Weakness); //->setIcon(5, 0); -MobEffect *MobEffect::poison = (new MobEffect(19, true, eMinecraftColour_Effect_Poison)) ->setDescriptionId(IDS_POTION_POISON) ->setPostfixDescriptionId(IDS_POTION_POISON_POSTFIX)->setDurationModifier(.25)->setIcon(MobEffect::e_MobEffectIcon_Poison); //->setIcon(6, 0); -MobEffect *MobEffect::reserved_20 = NULL; -MobEffect *MobEffect::reserved_21 = NULL; -MobEffect *MobEffect::reserved_22 = NULL; -MobEffect *MobEffect::reserved_23 = NULL; -MobEffect *MobEffect::reserved_24 = NULL; -MobEffect *MobEffect::reserved_25 = NULL; -MobEffect *MobEffect::reserved_26 = NULL; -MobEffect *MobEffect::reserved_27 = NULL; -MobEffect *MobEffect::reserved_28 = NULL; -MobEffect *MobEffect::reserved_29 = NULL; -MobEffect *MobEffect::reserved_30 = NULL; -MobEffect *MobEffect::reserved_31 = NULL; - +MobEffect *MobEffect::voidEffect; +MobEffect *MobEffect::movementSpeed; +MobEffect *MobEffect::movementSlowdown; +MobEffect *MobEffect::digSpeed; +MobEffect *MobEffect::digSlowdown; +MobEffect *MobEffect::damageBoost; +MobEffect *MobEffect::heal; +MobEffect *MobEffect::harm; +MobEffect *MobEffect::jump; +MobEffect *MobEffect::confusion; +MobEffect *MobEffect::regeneration; +MobEffect *MobEffect::damageResistance; +MobEffect *MobEffect::fireResistance; +MobEffect *MobEffect::waterBreathing; +MobEffect *MobEffect::invisibility; +MobEffect *MobEffect::blindness; +MobEffect *MobEffect::nightVision; +MobEffect *MobEffect::hunger; +MobEffect *MobEffect::weakness; +MobEffect *MobEffect::poison; +MobEffect *MobEffect::wither; +MobEffect *MobEffect::healthBoost; +MobEffect *MobEffect::absorption; +MobEffect *MobEffect::saturation; +MobEffect *MobEffect::reserved_24; +MobEffect *MobEffect::reserved_25; +MobEffect *MobEffect::reserved_26; +MobEffect *MobEffect::reserved_27; +MobEffect *MobEffect::reserved_28; +MobEffect *MobEffect::reserved_29; +MobEffect *MobEffect::reserved_30; +MobEffect *MobEffect::reserved_31; + +void MobEffect::staticCtor() +{ + voidEffect = NULL; + movementSpeed = (new MobEffect(1, false, eMinecraftColour_Effect_MovementSpeed)) ->setDescriptionId(IDS_POTION_MOVESPEED) ->setPostfixDescriptionId(IDS_POTION_MOVESPEED_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Speed)->addAttributeModifier(SharedMonsterAttributes::MOVEMENT_SPEED, eModifierId_POTION_MOVESPEED, 0.2f, AttributeModifier::OPERATION_MULTIPLY_TOTAL); //setIcon(0, 0); + movementSlowdown = (new MobEffect(2, true, eMinecraftColour_Effect_MovementSlowDown)) ->setDescriptionId(IDS_POTION_MOVESLOWDOWN) ->setPostfixDescriptionId(IDS_POTION_MOVESLOWDOWN_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Slowness)->addAttributeModifier(SharedMonsterAttributes::MOVEMENT_SPEED, eModifierId_POTION_MOVESLOWDOWN, -0.15f, AttributeModifier::OPERATION_MULTIPLY_TOTAL); //->setIcon(1, 0); + digSpeed = (new MobEffect(3, false, eMinecraftColour_Effect_DigSpeed)) ->setDescriptionId(IDS_POTION_DIGSPEED) ->setPostfixDescriptionId(IDS_POTION_DIGSPEED_POSTFIX)->setDurationModifier(1.5)->setIcon(MobEffect::e_MobEffectIcon_Haste); //->setIcon(2, 0); + digSlowdown = (new MobEffect(4, true, eMinecraftColour_Effect_DigSlowdown)) ->setDescriptionId(IDS_POTION_DIGSLOWDOWN) ->setPostfixDescriptionId(IDS_POTION_DIGSLOWDOWN_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_MiningFatigue); //->setIcon(3, 0); + damageBoost = (new AttackDamageMobEffect(5, false, eMinecraftColour_Effect_DamageBoost)) ->setDescriptionId(IDS_POTION_DAMAGEBOOST) ->setPostfixDescriptionId(IDS_POTION_DAMAGEBOOST_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Strength)->addAttributeModifier(SharedMonsterAttributes::ATTACK_DAMAGE, eModifierId_POTION_DAMAGEBOOST, 3, AttributeModifier::OPERATION_MULTIPLY_TOTAL); //->setIcon(4, 0); + heal = (new InstantenousMobEffect(6, false, eMinecraftColour_Effect_Heal)) ->setDescriptionId(IDS_POTION_HEAL) ->setPostfixDescriptionId(IDS_POTION_HEAL_POSTFIX); + harm = (new InstantenousMobEffect(7, true, eMinecraftColour_Effect_Harm)) ->setDescriptionId(IDS_POTION_HARM) ->setPostfixDescriptionId(IDS_POTION_HARM_POSTFIX); + jump = (new MobEffect(8, false, eMinecraftColour_Effect_Jump)) ->setDescriptionId(IDS_POTION_JUMP) ->setPostfixDescriptionId(IDS_POTION_JUMP_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_JumpBoost); //->setIcon(2, 1); + confusion = (new MobEffect(9, true, eMinecraftColour_Effect_Confusion)) ->setDescriptionId(IDS_POTION_CONFUSION) ->setPostfixDescriptionId(IDS_POTION_CONFUSION_POSTFIX)->setDurationModifier(.25)->setIcon(MobEffect::e_MobEffectIcon_Nausea); //->setIcon(3, 1); + regeneration = (new MobEffect(10, false, eMinecraftColour_Effect_Regeneration)) ->setDescriptionId(IDS_POTION_REGENERATION) ->setPostfixDescriptionId(IDS_POTION_REGENERATION_POSTFIX)->setDurationModifier(.25)->setIcon(MobEffect::e_MobEffectIcon_Regeneration); //->setIcon(7, 0); + damageResistance = (new MobEffect(11, false, eMinecraftColour_Effect_DamageResistance)) ->setDescriptionId(IDS_POTION_RESISTANCE) ->setPostfixDescriptionId(IDS_POTION_RESISTANCE_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Resistance); //->setIcon(6, 1); + fireResistance = (new MobEffect(12, false, eMinecraftColour_Effect_FireResistance)) ->setDescriptionId(IDS_POTION_FIRERESISTANCE) ->setPostfixDescriptionId(IDS_POTION_FIRERESISTANCE_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_FireResistance); //->setIcon(7, 1); + waterBreathing = (new MobEffect(13, false, eMinecraftColour_Effect_WaterBreathing)) ->setDescriptionId(IDS_POTION_WATERBREATHING) ->setPostfixDescriptionId(IDS_POTION_WATERBREATHING_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_WaterBreathing); //->setIcon(0, 2); + invisibility = (new MobEffect(14, false, eMinecraftColour_Effect_Invisiblity)) ->setDescriptionId(IDS_POTION_INVISIBILITY) ->setPostfixDescriptionId(IDS_POTION_INVISIBILITY_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Invisiblity); //->setIcon(0, 1); + blindness = (new MobEffect(15, true, eMinecraftColour_Effect_Blindness)) ->setDescriptionId(IDS_POTION_BLINDNESS) ->setPostfixDescriptionId(IDS_POTION_BLINDNESS_POSTFIX)->setDurationModifier(.25)->setIcon(MobEffect::e_MobEffectIcon_Blindness); //->setIcon(5, 1); + nightVision = (new MobEffect(16, false, eMinecraftColour_Effect_NightVision)) ->setDescriptionId(IDS_POTION_NIGHTVISION) ->setPostfixDescriptionId(IDS_POTION_NIGHTVISION_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_NightVision); //->setIcon(4, 1); + hunger = (new MobEffect(17, true, eMinecraftColour_Effect_Hunger)) ->setDescriptionId(IDS_POTION_HUNGER) ->setPostfixDescriptionId(IDS_POTION_HUNGER_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Hunger); //->setIcon(1, 1); + weakness = (new AttackDamageMobEffect(18, true, eMinecraftColour_Effect_Weakness)) ->setDescriptionId(IDS_POTION_WEAKNESS) ->setPostfixDescriptionId(IDS_POTION_WEAKNESS_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Weakness)->addAttributeModifier(SharedMonsterAttributes::ATTACK_DAMAGE, eModifierId_POTION_WEAKNESS, 2, AttributeModifier::OPERATION_ADDITION); //->setIcon(5, 0); + poison = (new MobEffect(19, true, eMinecraftColour_Effect_Poison)) ->setDescriptionId(IDS_POTION_POISON) ->setPostfixDescriptionId(IDS_POTION_POISON_POSTFIX)->setDurationModifier(.25)->setIcon(MobEffect::e_MobEffectIcon_Poison); //->setIcon(6, 0); + wither = (new MobEffect(20, true, eMinecraftColour_Effect_Wither)) ->setDescriptionId(IDS_POTION_WITHER) ->setPostfixDescriptionId(IDS_POTION_WITHER_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Wither)->setDurationModifier(.25); + healthBoost = (new HealthBoostMobEffect(21, false, eMinecraftColour_Effect_HealthBoost)) ->setDescriptionId(IDS_POTION_HEALTHBOOST) ->setPostfixDescriptionId(IDS_POTION_HEALTHBOOST_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_HealthBoost)->addAttributeModifier(SharedMonsterAttributes::MAX_HEALTH, eModifierId_POTION_HEALTHBOOST, 4, AttributeModifier::OPERATION_ADDITION); + absorption = (new AbsoptionMobEffect(22, false, eMinecraftColour_Effect_Absoprtion)) ->setDescriptionId(IDS_POTION_ABSORPTION) ->setPostfixDescriptionId(IDS_POTION_ABSORPTION_POSTFIX)->setIcon(MobEffect::e_MobEffectIcon_Absorption); + saturation = (new InstantenousMobEffect(23, false, eMinecraftColour_Effect_Saturation)) ->setDescriptionId(IDS_POTION_SATURATION) ->setPostfixDescriptionId(IDS_POTION_SATURATION_POSTFIX); + reserved_24 = NULL; + reserved_25 = NULL; + reserved_26 = NULL; + reserved_27 = NULL; + reserved_28 = NULL; + reserved_29 = NULL; + reserved_30 = NULL; + reserved_31 = NULL; +} MobEffect::MobEffect(int id, bool isHarmful, eMinecraftColour color) : id(id), _isHarmful(isHarmful), color(color) { @@ -86,9 +125,8 @@ int MobEffect::getId() * @param mob * @param amplification */ -void MobEffect::applyEffectTick(shared_ptr mob, int amplification) +void MobEffect::applyEffectTick(shared_ptr mob, int amplification) { - // Maybe move this to separate class implementations in the future? if (id == regeneration->id) { @@ -104,15 +142,26 @@ void MobEffect::applyEffectTick(shared_ptr mob, int amplification) mob->hurt(DamageSource::magic, 1); } } - else if (id == hunger->id && dynamic_pointer_cast(mob) != NULL) + else if (id == wither->id) + { + mob->hurt(DamageSource::wither, 1); + } + else if ( (id == hunger->id) && mob->instanceof(eTYPE_PLAYER) ) { // every tick, cause the same amount of exhaustion as when removing // a block, times amplification dynamic_pointer_cast(mob)->causeFoodExhaustion(FoodConstants::EXHAUSTION_MINE * (amplification + 1)); } + else if ( (id == saturation->id) && mob->instanceof(eTYPE_PLAYER) ) + { + if (!mob->level->isClientSide) + { + dynamic_pointer_cast(mob)->getFoodData()->eat(amplification + 1, FoodConstants::FOOD_SATURATION_MAX); + } + } else if ((id == heal->id && !mob->isInvertedHealAndHarm()) || (id == harm->id && mob->isInvertedHealAndHarm())) { - mob->heal(6 << amplification); + mob->heal(max(4 << amplification, 0)); } else if ((id == harm->id && !mob->isInvertedHealAndHarm()) || (id == heal->id && mob->isInvertedHealAndHarm())) { @@ -120,11 +169,11 @@ void MobEffect::applyEffectTick(shared_ptr mob, int amplification) } } -void MobEffect::applyInstantenousEffect(shared_ptr source, shared_ptr mob, int amplification, double scale) +void MobEffect::applyInstantenousEffect(shared_ptr source, shared_ptr mob, int amplification, double scale) { if ((id == heal->id && !mob->isInvertedHealAndHarm()) || (id == harm->id && mob->isInvertedHealAndHarm())) { - int amount = (int) (scale * (double) (6 << amplification) + .5); + int amount = (int) (scale * (double) (4 << amplification) + .5); mob->heal(amount); } else if ((id == harm->id && !mob->isInvertedHealAndHarm()) || (id == heal->id && mob->isInvertedHealAndHarm())) @@ -162,7 +211,17 @@ bool MobEffect::isDurationEffectTick(int remainingDuration, int amplification) { // Maybe move this to separate class implementations in the future? - if (id == regeneration->id || id == poison->id) + if (id == regeneration->id) + { + // tick intervals are 50, 25, 12, 6.. + int interval = 50 >> amplification; + if (interval > 0) + { + return (remainingDuration % interval) == 0; + } + return true; + } + else if (id == poison->id) { // tick intervals are 25, 12, 6.. int interval = 25 >> amplification; @@ -172,6 +231,15 @@ bool MobEffect::isDurationEffectTick(int remainingDuration, int amplification) } return true; } + else if (id == wither->id) + { + int interval = 40 >> amplification; + if (interval > 0) + { + return (remainingDuration % interval) == 0; + } + return true; + } else if (id == hunger->id) { return true; @@ -219,6 +287,10 @@ bool MobEffect::isHarmful() wstring MobEffect::formatDuration(MobEffectInstance *instance) { + if (instance->isNoCounter()) + { + return L"**:**"; + } int duration = instance->getDuration(); int seconds = duration / SharedConstants::TICKS_PER_SECOND; @@ -255,7 +327,7 @@ double MobEffect::getDurationModifier() MobEffect *MobEffect::setDisabled() { - this->_isDisabled = true; + _isDisabled = true; return this; } @@ -267,4 +339,49 @@ bool MobEffect::isDisabled() eMinecraftColour MobEffect::getColor() { return color; +} + +MobEffect *MobEffect::addAttributeModifier(Attribute *attribute, eMODIFIER_ID id, double amount, int operation) +{ + AttributeModifier *effect = new AttributeModifier(id, amount, operation); + attributeModifiers.insert(std::pair(attribute, effect)); + return this; +} + +unordered_map *MobEffect::getAttributeModifiers() +{ + return &attributeModifiers; +} + +void MobEffect::removeAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier) +{ + for (AUTO_VAR(it, attributeModifiers.begin()); it != attributeModifiers.end(); ++it) + { + AttributeInstance *attribute = attributes->getInstance(it->first); + + if (attribute != NULL) + { + attribute->removeModifier(it->second); + } + } +} + +void MobEffect::addAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier) +{ + for (AUTO_VAR(it, attributeModifiers.begin()); it != attributeModifiers.end(); ++it) + { + AttributeInstance *attribute = attributes->getInstance(it->first); + + if (attribute != NULL) + { + AttributeModifier *original = it->second; + attribute->removeModifier(original); + attribute->addModifier(new AttributeModifier(original->getId(), getAttributeModifierValue(amplifier, original), original->getOperation())); + } + } +} + +double MobEffect::getAttributeModifierValue(int amplifier, AttributeModifier *original) +{ + return original->getAmount() * (amplifier + 1); } \ No newline at end of file diff --git a/Minecraft.World/MobEffect.h b/Minecraft.World/MobEffect.h index b0460bf1..84068452 100644 --- a/Minecraft.World/MobEffect.h +++ b/Minecraft.World/MobEffect.h @@ -1,8 +1,11 @@ #pragma once using namespace std; +#include "AttributeModifier.h" + class Mob; class MobEffectInstance; +class Attribute; class MobEffect { @@ -27,6 +30,9 @@ public: e_MobEffectIcon_Strength, e_MobEffectIcon_WaterBreathing, e_MobEffectIcon_Weakness, + e_MobEffectIcon_Wither, + e_MobEffectIcon_HealthBoost, + e_MobEffectIcon_Absorption, e_MobEffectIcon_COUNT, }; @@ -34,42 +40,45 @@ public: static const int NUM_EFFECTS = 32; static MobEffect *effects[NUM_EFFECTS]; - static MobEffect *voidEffect; - static MobEffect *movementSpeed; - static MobEffect *movementSlowdown; - static MobEffect *digSpeed; - static MobEffect *digSlowdown; - static MobEffect *damageBoost; - static MobEffect *heal; - static MobEffect *harm; - static MobEffect *jump; - static MobEffect *confusion; - static MobEffect *regeneration; - static MobEffect *damageResistance; - static MobEffect *fireResistance; - static MobEffect *waterBreathing; - static MobEffect *invisibility; - static MobEffect *blindness; - static MobEffect *nightVision; - static MobEffect *hunger; - static MobEffect *weakness; - static MobEffect *poison; - static MobEffect *reserved_20; - static MobEffect *reserved_21; - static MobEffect *reserved_22; - static MobEffect *reserved_23; - static MobEffect *reserved_24; - static MobEffect *reserved_25; - static MobEffect *reserved_26; - static MobEffect *reserved_27; - static MobEffect *reserved_28; - static MobEffect *reserved_29; - static MobEffect *reserved_30; - static MobEffect *reserved_31; - - const int id; + static MobEffect *voidEffect; + static MobEffect *movementSpeed; + static MobEffect *movementSlowdown; + static MobEffect *digSpeed; + static MobEffect *digSlowdown; + static MobEffect *damageBoost; + static MobEffect *heal; + static MobEffect *harm; + static MobEffect *jump; + static MobEffect *confusion; + static MobEffect *regeneration; + static MobEffect *damageResistance; + static MobEffect *fireResistance; + static MobEffect *waterBreathing; + static MobEffect *invisibility; + static MobEffect *blindness; + static MobEffect *nightVision; + static MobEffect *hunger; + static MobEffect *weakness; + static MobEffect *poison; + static MobEffect *wither; + static MobEffect *healthBoost; + static MobEffect *absorption; + static MobEffect *saturation; + static MobEffect *reserved_24; + static MobEffect *reserved_25; + static MobEffect *reserved_26; + static MobEffect *reserved_27; + static MobEffect *reserved_28; + static MobEffect *reserved_29; + static MobEffect *reserved_30; + static MobEffect *reserved_31; + + const int id; + + static void staticCtor(); private: + unordered_map attributeModifiers; int descriptionId; int m_postfixDescriptionId; // 4J added EMobEffectIcon icon; // 4J changed type @@ -85,15 +94,15 @@ protected: MobEffect *setIcon(EMobEffectIcon icon); public: - int getId(); - void applyEffectTick(shared_ptr mob, int amplification); - void applyInstantenousEffect(shared_ptr source, shared_ptr mob, int amplification, double scale); - virtual bool isInstantenous(); - virtual bool isDurationEffectTick(int remainingDuration, int amplification); + virtual int getId(); + virtual void applyEffectTick(shared_ptr mob, int amplification); + virtual void applyInstantenousEffect(shared_ptr source, shared_ptr mob, int amplification, double scale); + virtual bool isInstantenous(); + virtual bool isDurationEffectTick(int remainingDuration, int amplification); MobEffect *setDescriptionId(unsigned int id); unsigned int getDescriptionId(int iData = -1); - + // 4J Added MobEffect *setPostfixDescriptionId(unsigned int id); unsigned int getPostfixDescriptionId(int iData = -1); @@ -107,8 +116,14 @@ protected: MobEffect *setDurationModifier(double durationModifier); public: - double getDurationModifier(); - MobEffect *setDisabled(); - bool isDisabled(); - eMinecraftColour getColor(); + virtual double getDurationModifier(); + virtual MobEffect *setDisabled(); + virtual bool isDisabled(); + virtual eMinecraftColour getColor(); + + virtual MobEffect *addAttributeModifier(Attribute *attribute, eMODIFIER_ID id, double amount, int operation); + virtual unordered_map *getAttributeModifiers(); + virtual void removeAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier); + virtual void addAttributeModifiers(shared_ptr entity, BaseAttributeMap *attributes, int amplifier); + virtual double getAttributeModifierValue(int amplifier, AttributeModifier *original); }; \ No newline at end of file diff --git a/Minecraft.World/MobEffectInstance.cpp b/Minecraft.World/MobEffectInstance.cpp index 1e15e58c..2ca696f6 100644 --- a/Minecraft.World/MobEffectInstance.cpp +++ b/Minecraft.World/MobEffectInstance.cpp @@ -6,6 +6,10 @@ void MobEffectInstance::_init(int id, int duration, int amplifier) this->id = id; this->duration = duration; this->amplifier = amplifier; + + splash = false; + ambient = false; + noCounter = false; } MobEffectInstance::MobEffectInstance(int id) @@ -23,27 +27,40 @@ MobEffectInstance::MobEffectInstance(int id, int duration, int amplifier) _init(id,duration,amplifier); } +MobEffectInstance::MobEffectInstance(int id, int duration, int amplifier, bool ambient) +{ + _init(id,duration,amplifier); + this->ambient = ambient; +} + MobEffectInstance::MobEffectInstance(MobEffectInstance *copy) { this->id = copy->id; this->duration = copy->duration; this->amplifier = copy->amplifier; + this->splash = copy->splash; + this->ambient = copy->ambient; + this->noCounter = copy->noCounter; } void MobEffectInstance::update(MobEffectInstance *takeOver) { - if (this->id != takeOver->id) + if (id != takeOver->id) { app.DebugPrintf("This method should only be called for matching effects!"); } - if (takeOver->amplifier > this->amplifier) + if (takeOver->amplifier > amplifier) { - this->amplifier = takeOver->amplifier; - this->duration = takeOver->duration; + amplifier = takeOver->amplifier; + duration = takeOver->duration; } - else if (takeOver->amplifier == this->amplifier && this->duration < takeOver->duration) + else if (takeOver->amplifier == amplifier && duration < takeOver->duration) { - this->duration = takeOver->duration; + duration = takeOver->duration; + } + else if (!takeOver->ambient && ambient) + { + ambient = takeOver->ambient; } } @@ -62,13 +79,28 @@ int MobEffectInstance::getAmplifier() return amplifier; } +bool MobEffectInstance::isSplash() +{ + return splash; +} + +void MobEffectInstance::setSplash(bool splash) +{ + this->splash = splash; +} + +bool MobEffectInstance::isAmbient() +{ + return ambient; +} + /** * Runs the effect on a Mob target. * * @param target * @return True if the effect is still active. */ -bool MobEffectInstance::tick(shared_ptr target) +bool MobEffectInstance::tick(shared_ptr target) { if (duration > 0) { @@ -86,7 +118,7 @@ int MobEffectInstance::tickDownDuration() return --duration; } -void MobEffectInstance::applyEffect(shared_ptr mob) +void MobEffectInstance::applyEffect(shared_ptr mob) { if (duration > 0) { @@ -133,7 +165,35 @@ wstring MobEffectInstance::toString() } // Was bool equals(Object obj) -bool MobEffectInstance::equals(MobEffectInstance *obj) +bool MobEffectInstance::equals(MobEffectInstance *instance) +{ + return id == instance->id && amplifier == instance->amplifier && duration == instance->duration && splash == instance->splash && ambient == instance->ambient; +} + +CompoundTag *MobEffectInstance::save(CompoundTag *tag) +{ + tag->putByte(L"Id", (byte) getId()); + tag->putByte(L"Amplifier", (byte) getAmplifier()); + tag->putInt(L"Duration", getDuration()); + tag->putBoolean(L"Ambient", isAmbient()); + return tag; +} + +MobEffectInstance *MobEffectInstance::load(CompoundTag *tag) +{ + int id = tag->getByte(L"Id"); + int amplifier = tag->getByte(L"Amplifier"); + int duration = tag->getInt(L"Duration"); + boolean ambient = tag->getBoolean(L"Ambient"); + return new MobEffectInstance(id, duration, amplifier, ambient); +} + +void MobEffectInstance::setNoCounter(bool noCounter) +{ + this->noCounter = noCounter; +} + +bool MobEffectInstance::isNoCounter() { - return this->id == obj->id && this->amplifier == obj->amplifier && this->duration == obj->duration; + return noCounter; } \ No newline at end of file diff --git a/Minecraft.World/MobEffectInstance.h b/Minecraft.World/MobEffectInstance.h index d1c716e6..5d9e68f6 100644 --- a/Minecraft.World/MobEffectInstance.h +++ b/Minecraft.World/MobEffectInstance.h @@ -11,6 +11,9 @@ private: int duration; // sent as byte int amplifier; + bool splash; + bool ambient; + bool noCounter; void _init(int id, int duration, int amplifier); @@ -18,19 +21,25 @@ public: MobEffectInstance(int id); MobEffectInstance(int id, int duration); MobEffectInstance(int id, int duration, int amplifier); + MobEffectInstance(int id, int duration, int amplifier, bool ambient); MobEffectInstance(MobEffectInstance *copy); void update(MobEffectInstance *takeOver); int getId(); int getDuration(); int getAmplifier(); - bool tick(shared_ptr target); + + bool isSplash(); + void setSplash(bool splash); + bool isAmbient(); + + bool tick(shared_ptr target); private: int tickDownDuration(); public: - void applyEffect(shared_ptr mob); + void applyEffect(shared_ptr mob); int getDescriptionId(); int getPostfixDescriptionId(); // 4J Added int hashCode(); @@ -39,4 +48,9 @@ public: // Was bool equals(Object obj) bool equals(MobEffectInstance *obj); + + CompoundTag *save(CompoundTag *tag); + static MobEffectInstance *load(CompoundTag *tag); + void setNoCounter(bool noCounter); + bool isNoCounter(); }; \ No newline at end of file diff --git a/Minecraft.World/MobGroupData.h b/Minecraft.World/MobGroupData.h new file mode 100644 index 00000000..f7b1e1b7 --- /dev/null +++ b/Minecraft.World/MobGroupData.h @@ -0,0 +1,8 @@ +#pragma once + +class MobGroupData +{ +public: + // Required so this class is polymorphic + virtual void emptyFunc() {} +}; \ No newline at end of file diff --git a/Minecraft.World/MobSpawner.cpp b/Minecraft.World/MobSpawner.cpp index d2b4f6fd..8cd60e92 100644 --- a/Minecraft.World/MobSpawner.cpp +++ b/Minecraft.World/MobSpawner.cpp @@ -39,7 +39,7 @@ TilePos MobSpawner::getRandomPosWithin(Level *level, int cx, int cz) unordered_map MobSpawner::chunksToPoll; #endif -const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies) +const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies, bool spawnPersistent) { #ifndef _CONTENT_PACKAGE @@ -94,7 +94,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie #endif #endif - if (!spawnEnemies && !spawnFriendlies) + if (!spawnEnemies && !spawnFriendlies && !spawnPersistent) { return 0; } @@ -193,15 +193,24 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie MemSect(31); Pos *spawnPos = level->getSharedSpawnPos(); MemSect(0); - + for (unsigned int i = 0; i < MobCategory::values.length; i++) { MobCategory *mobCategory = MobCategory::values[i]; - if ((mobCategory->isFriendly() && !spawnFriendlies) || (!mobCategory->isFriendly() && !spawnEnemies)) + if ((mobCategory->isFriendly() && !spawnFriendlies) || (!mobCategory->isFriendly() && !spawnEnemies) || (mobCategory->isPersistent() && !spawnPersistent)) { continue; } + // 4J - early out for non-main dimensions, if spawning anything friendly + if( mobCategory->isFriendly() ) + { + if( level->dimension->id != 0 ) + { + continue; + } + } + // 4J - this is now quite different to the java version. We just have global max counts for the level whereas the original has a max per chunk that // scales with the number of chunks to be polled. int categoryCount = level->countInstanceOf( mobCategory->getEnumBaseClass(), mobCategory->isSingleType()); @@ -221,8 +230,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie #endif if( it->second ) { - // don't add mobs to edge chunks, to prevent adding mobs - // "outside" of the active playground + // don't add mobs to edge chunks, to prevent adding mobs "outside" of the active playground continue; } ChunkPos *cp = (ChunkPos *) (&it->first); @@ -247,6 +255,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie int ss = 6; Biome::MobSpawnerData *currentMobType = NULL; + MobGroupData *groupData = NULL; for (int ll = 0; ll < 4; ll++) { @@ -349,8 +358,7 @@ const int MobSpawner::tick(ServerLevel *level, bool spawnEnemies, bool spawnFrie categoryCount++; mob->setDespawnProtected(); // 4J added - default to protected against despawning level->addEntity(mob); - finalizeMobSettings(mob, level, xx, yy, zz); - mob->finalizeMobSpawn(); + groupData = mob->finalizeMobSpawn(groupData); // 4J - change here so that we can't ever make more than the desired amount of entities in each priority. In the original java version // depending on the random spawn positions being considered the only limit as to the number of entities created per category is the number // of chunks to poll. @@ -420,171 +428,7 @@ bool MobSpawner::isSpawnPositionOk(MobCategory *category, Level *level, int x, i int tt = level->getTile(x, y - 1, z); return tt != Tile::unbreakable_Id && !level->isSolidBlockingTile(x, y, z) && !level->getMaterial(x, y, z)->isLiquid() && !level->isSolidBlockingTile(x, y + 1, z); } -} - - -void MobSpawner::finalizeMobSettings(shared_ptr mob, Level *level, float xx, float yy, float zz) -{ - if (dynamic_pointer_cast( mob ) != NULL && level->random->nextInt(100) == 0) - { - shared_ptr skeleton = shared_ptr( new Skeleton(level) ); - skeleton->moveTo(xx, yy, zz, mob->yRot, 0); - level->addEntity(skeleton); - skeleton->ride(mob); - } - else if (dynamic_pointer_cast( mob ) != NULL) - { - (dynamic_pointer_cast( mob ))->setColor(Sheep::getSheepColor(level->random)); - } - else if (dynamic_pointer_cast( mob ) != NULL) - { - if (level->random->nextInt(7) == 0) - { - for (int kitten = 0; kitten < 2; kitten++) - { - shared_ptr ozelot = shared_ptr(new Ozelot(level)); - ozelot->moveTo(xx, yy, zz, mob->yRot, 0); - ozelot->setAge(-20 * 60 * 20); - level->addEntity(ozelot); - } - } - } -} - - -// 4J Stu TODO This was an array of Class type. I haven't made a base Class type yet, but don't need to -// as this can be an array of Mob type? -eINSTANCEOF MobSpawner::bedEnemies[bedEnemyCount] = { - eTYPE_SPIDER, eTYPE_ZOMBIE, eTYPE_SKELETON -}; - - -bool MobSpawner::attackSleepingPlayers(Level *level, vector > *players) -{ - - bool somebodyWokeUp = false; - - PathFinder finder = PathFinder(level, true, false, false, true); - - AUTO_VAR(itEnd, players->end()); - for (AUTO_VAR(it, players->begin()); it != itEnd; it++) - { - shared_ptr player = (*it); - - bool nextPlayer = false; - - for (int attemptCount = 0; attemptCount < 20 && !nextPlayer; attemptCount++)\ - { - - - // limit position within the range of the player - int x = Mth::floor(player->x) + level->random->nextInt(32) - level->random->nextInt(32); - int z = Mth::floor(player->z) + level->random->nextInt(32) - level->random->nextInt(32); - int yStart = Mth::floor(player->y) + level->random->nextInt(16) - level->random->nextInt(16); - if (yStart < 1) - { - yStart = 1; - } - else if (yStart > Level::maxBuildHeight) - { - yStart = Level::maxBuildHeight; - } - - { - int type = level->random->nextInt(bedEnemyCount); - int y = yStart; - - while (y > 2 && !level->isTopSolidBlocking(x, y - 1, z)) - { - y--; - } - - while (!isSpawnPositionOk( (MobCategory *) MobCategory::monster, level, x, y, z) && y < (yStart + 16) && y < Level::maxBuildHeight) - { - y++; - } - if (y >= (yStart + 16) || y >= Level::maxBuildHeight) - { - y = yStart; - continue; } - else - { - float xx = x + 0.5f; - float yy = (float) y; - float zz = z + 0.5f; - - shared_ptr mob; -// 4J - removed try/catch -// try -// { - //mob = classes[type].getConstructor(Level.class).newInstance(level); - // 4J - there was a classes array here which duplicated the bedEnemies array but have removed it - mob = dynamic_pointer_cast(EntityIO::newByEnumType(bedEnemies[type], level )); -// } -// catch (exception e) -// { -// // TODO 4J Stu - We can't print a stack trace, and newInstance doesn't currently throw an exception anyway -// //e.printStackTrace(); -// return somebodyWokeUp; -// } - - // System.out.println("Placing night mob"); - mob->moveTo(xx, yy, zz, level->random->nextFloat() * 360, 0); - // check if the mob can spawn at this location - if (!mob->canSpawn()) - { - continue; - } - Pos *bedPos = BedTile::findStandUpPosition(level, Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z), 1); - if (bedPos == NULL) - { - // an unlikely case where the bed is - // completely blocked - bedPos = new Pos(x, y + 1, z); - } - - // 4J Stu - TU-1 hotfix - // Fix for #13152 - If the player sleeps in a bed next to a wall in an enclosed, well lit area they will be awoken by a monster - // The pathfinder should attempt to get close to the position that we will move the mob to, - // instead of the player who could be next to a wall. Otherwise the paths gets to the other - // side of the the wall, then moves the mob inside the building - //Path *findPath = finder.findPath(mob.get(), player.get(), 32.0f); - Path *findPath = finder.findPath(mob.get(), bedPos->x, bedPos->y, bedPos->z, 32.0f); - if (findPath != NULL && findPath->getSize() > 1) - { - Node *last = findPath->last(); - - if (abs(last->x - bedPos->x) < 1.5 && abs(last->z - bedPos->z) < 1.5 && abs(last->y - bedPos->y) < 1.5) - { - // System.out.println("Found path!"); - - mob->moveTo(bedPos->x + 0.5f, bedPos->y, bedPos->z + 0.5f, 0, 0); - // the mob would maybe not be able to - // spawn here, but we ignore that now (we assume - // it walked here) - { - level->addEntity(mob); - finalizeMobSettings(mob, level, bedPos->x + 0.5f, (float) bedPos->y, bedPos->z + 0.5f); - mob->finalizeMobSpawn(); - player->stopSleepInBed(true, false, false); - // play a sound effect to scare the player - mob->playAmbientSound(); - somebodyWokeUp = true; - nextPlayer = true; - } - } - delete findPath; - } - delete bedPos; - } - } - } - } - - - return somebodyWokeUp; -} void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo, int cellWidth, int cellHeight, Random *random) { @@ -599,6 +443,7 @@ void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo while (random->nextFloat() < biome->getCreatureProbability()) { Biome::MobSpawnerData *type = (Biome::MobSpawnerData *) WeighedRandom::getRandomItem(level->random, ((vector *)mobs)); + MobGroupData *groupData = NULL; int count = type->minCount + random->nextInt(1 + type->maxCount - type->minCount); int x = xo + random->nextInt(cellWidth); @@ -633,7 +478,7 @@ void MobSpawner::postProcessSpawnMobs(Level *level, Biome *biome, int xo, int zo mob->setDespawnProtected(); level->addEntity(mob); - finalizeMobSettings(mob, level, xx, yy, zz); + groupData = mob->finalizeMobSpawn(groupData); success = true; } diff --git a/Minecraft.World/MobSpawner.h b/Minecraft.World/MobSpawner.h index b5022a77..452ddcc4 100644 --- a/Minecraft.World/MobSpawner.h +++ b/Minecraft.World/MobSpawner.h @@ -26,19 +26,9 @@ private: #endif public: - static const int tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies); + static const int tick(ServerLevel *level, bool spawnEnemies, bool spawnFriendlies, bool spawnPersistent); static bool isSpawnPositionOk(MobCategory *category, Level *level, int x, int y, int z); -private: - static void finalizeMobSettings(shared_ptr mob, Level *level, float xx, float yy, float zz); - -protected: - // 4J Stu TODO This was an array of Class type. I haven't made a base Class type yet, but don't need to - // as this can be an array of Mob type? - static const int bedEnemyCount = 3; - static eINSTANCEOF bedEnemies[bedEnemyCount]; - - public: static bool attackSleepingPlayers(Level *level, vector > *players); diff --git a/Minecraft.World/MobSpawnerTile.cpp b/Minecraft.World/MobSpawnerTile.cpp index d926fc24..4665015a 100644 --- a/Minecraft.World/MobSpawnerTile.cpp +++ b/Minecraft.World/MobSpawnerTile.cpp @@ -3,7 +3,7 @@ #include "net.minecraft.world.level.tile.entity.h" #include "MobSpawnerTile.h" -MobSpawnerTile::MobSpawnerTile(int id) : EntityTile(id, Material::stone, isSolidRender() ) +MobSpawnerTile::MobSpawnerTile(int id) : BaseEntityTile(id, Material::stone, isSolidRender() ) { } diff --git a/Minecraft.World/MobSpawnerTile.h b/Minecraft.World/MobSpawnerTile.h index edf3c5e7..39fac148 100644 --- a/Minecraft.World/MobSpawnerTile.h +++ b/Minecraft.World/MobSpawnerTile.h @@ -1,19 +1,19 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" class Random; -class MobSpawnerTile : public EntityTile +class MobSpawnerTile : public BaseEntityTile { friend class Tile; protected: MobSpawnerTile(int id); public: - virtual shared_ptr newTileEntity(Level *level); + virtual shared_ptr newTileEntity(Level *level); virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual int getResourceCount(Random *random); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool blocksLight(); + virtual int getResourceCount(Random *random); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool blocksLight(); virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonusLevel); virtual int cloneTileId(Level *level, int x, int y, int z); }; \ No newline at end of file diff --git a/Minecraft.World/MobSpawnerTileEntity.cpp b/Minecraft.World/MobSpawnerTileEntity.cpp index ce7ae1dc..013503b6 100644 --- a/Minecraft.World/MobSpawnerTileEntity.cpp +++ b/Minecraft.World/MobSpawnerTileEntity.cpp @@ -1,233 +1,102 @@ #include "stdafx.h" -#include "com.mojang.nbt.h" -#include "TileEntity.h" -#include "LevelEvent.h" -#include "net.minecraft.world.level.h" -#include "net.minecraft.world.entity.item.h" -#include "net.minecraft.world.entity.player.h" -#include "net.minecraft.world.item.h" -#include "net.minecraft.world.entity.h" -#include "net.minecraft.world.phys.h" #include "net.minecraft.network.packet.h" -#include "SharedConstants.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" #include "MobSpawnerTileEntity.h" - - -const int MobSpawnerTileEntity::MAX_DIST = 16; - -MobSpawnerTileEntity::MobSpawnerTileEntity() : TileEntity() +MobSpawnerTileEntity::TileEntityMobSpawner::TileEntityMobSpawner(MobSpawnerTileEntity *parent) { - spin = 0; - oSpin = 0; - - // entityId = "Skeleton"; - entityId = L"Pig"; - m_bEntityIdUpdated = false; - - spawnData = NULL; - - spawnDelay = 20; - - minSpawnDelay = SharedConstants::TICKS_PER_SECOND * 10; - maxSpawnDelay = SharedConstants::TICKS_PER_SECOND * 40; - spawnCount = 4; - displayEntity = nullptr; + m_parent = parent; } -wstring MobSpawnerTileEntity::getEntityId() +void MobSpawnerTileEntity::TileEntityMobSpawner::broadcastEvent(int id) { - return entityId; + m_parent->level->tileEvent(m_parent->x, m_parent->y, m_parent->z, Tile::mobSpawner_Id, id, 0); } -void MobSpawnerTileEntity::setEntityId(const wstring& entityId) +Level *MobSpawnerTileEntity::TileEntityMobSpawner::getLevel() { - this->entityId = entityId; + return m_parent->level; } -bool MobSpawnerTileEntity::isNearPlayer() +int MobSpawnerTileEntity::TileEntityMobSpawner::getX() { - return level->getNearestPlayer(x + 0.5, y + 0.5, z + 0.5, MAX_DIST) != NULL; + return m_parent->x; } -void MobSpawnerTileEntity::tick() +int MobSpawnerTileEntity::TileEntityMobSpawner::getY() { - if (!isNearPlayer()) - { - return; - } - - if (level->isClientSide) - { - double xP = x + level->random->nextFloat(); - double yP = y + level->random->nextFloat(); - double zP = z + level->random->nextFloat(); - level->addParticle(eParticleType_smoke, xP, yP, zP, 0, 0, 0); - level->addParticle(eParticleType_flame, xP, yP, zP, 0, 0, 0); - - oSpin = spin; - spin += 1000 / 220.0f; - while (spin > 360) - { - spin -= 360; - } - while(oSpin > 360) - { - oSpin -= 360; - } - } - else - { - - if (spawnDelay == -1) delay(); - - if (spawnDelay > 0) - { - spawnDelay--; - return; - } - - for (int c = 0; c < spawnCount; c++) - { - shared_ptr entity = dynamic_pointer_cast (EntityIO::newEntity(entityId, level)); - if (entity == NULL) return; - - vector > *vecNearby = level->getEntitiesOfClass(typeid(*entity), AABB::newTemp(x, y, z, x + 1, y + 1, z + 1)->grow(8, 4, 8)); - int nearBy = (int)vecNearby->size(); //4J - IB, TODO, Mob contains no getClass - delete vecNearby; - - if (nearBy >= 6) - { - delay(); - return; - } - - // 4J added - our mobspawner tiles should only be spawning monsters. Also respect the global limits we have for those so we don't go - // creating silly numbers of them. Have set this limit slightly higher than the main spawner has so that this tile entity is more likely to - // actually make something (60 rather than 50) - if(level->countInstanceOf( eTYPE_MONSTER, false) >= 60 ) - { - return; - } - - if (entity != NULL) - { - double xp = x + (level->random->nextDouble() - level->random->nextDouble()) * 4; - double yp = y + level->random->nextInt(3) - 1; - double zp = z + (level->random->nextDouble() - level->random->nextDouble()) * 4; - shared_ptr mob = dynamic_pointer_cast( entity ); - - entity->moveTo(xp, yp, zp, level->random->nextFloat() * 360, 0); - - if (mob == NULL || mob->canSpawn()) - { - fillExtraData(entity); - - level->addEntity(entity); - - level->levelEvent(LevelEvent::PARTICLES_MOBTILE_SPAWN, x, y, z, 0); - - if (mob != NULL) mob->spawnAnim(); - delay(); - } - } - } - } - - TileEntity::tick(); + return m_parent->y; } -void MobSpawnerTileEntity::fillExtraData(shared_ptr entity) +int MobSpawnerTileEntity::TileEntityMobSpawner::getZ() { - if (spawnData != NULL) - { - CompoundTag *data = new CompoundTag(); - entity->save(data); + return m_parent->z; +} - vector *allTags = spawnData->getAllTags(); - for(AUTO_VAR(it, allTags->begin()); it != allTags->end(); ++it) - { - Tag *tag = *it; - data->put((wchar_t *)tag->getName().c_str(), tag->copy()); - } - if(allTags != NULL) delete allTags; +void MobSpawnerTileEntity::TileEntityMobSpawner::setNextSpawnData(BaseMobSpawner::SpawnData *nextSpawnData) +{ + BaseMobSpawner::setNextSpawnData(nextSpawnData); + if (getLevel() != NULL) getLevel()->sendTileUpdated(m_parent->x, m_parent->y, m_parent->z); +} - entity->load(data); - } +MobSpawnerTileEntity::MobSpawnerTileEntity() +{ + spawner = new TileEntityMobSpawner(this); } -void MobSpawnerTileEntity::delay() +MobSpawnerTileEntity::~MobSpawnerTileEntity() { - spawnDelay = minSpawnDelay + level->random->nextInt(maxSpawnDelay - minSpawnDelay); + delete spawner; } void MobSpawnerTileEntity::load(CompoundTag *tag) { TileEntity::load(tag); - entityId = tag->getString(L"EntityId"); - m_bEntityIdUpdated = true; - - spawnDelay = tag->getShort(L"Delay"); - - if (tag->contains(L"SpawnData")) - { - spawnData = tag->getCompound(L"SpawnData"); - } - else - { - spawnData = NULL; - } - - if (tag->contains(L"MinSpawnDelay")) - { - minSpawnDelay = tag->getShort(L"MinSpawnDelay"); - maxSpawnDelay = tag->getShort(L"MaxSpawnDelay"); - spawnCount = tag->getShort(L"SpawnCount"); - } + spawner->load(tag); } void MobSpawnerTileEntity::save(CompoundTag *tag) { TileEntity::save(tag); - tag->putString(L"EntityId", entityId ); - tag->putShort(L"Delay", (short) spawnDelay); - tag->putShort(L"MinSpawnDelay", (short) minSpawnDelay); - tag->putShort(L"MaxSpawnDelay", (short) maxSpawnDelay); - tag->putShort(L"SpawnCount", (short) spawnCount); - - if (spawnData != NULL) - { - tag->putCompound(L"SpawnData", spawnData); - } + spawner->save(tag); } -shared_ptr MobSpawnerTileEntity::getDisplayEntity() +void MobSpawnerTileEntity::tick() { - if (displayEntity == NULL || m_bEntityIdUpdated) - { - shared_ptr e = EntityIO::newEntity(getEntityId(), NULL); - fillExtraData(e); - displayEntity = e; - m_bEntityIdUpdated = false; - } - - return displayEntity; + spawner->tick(); + TileEntity::tick(); } shared_ptr MobSpawnerTileEntity::getUpdatePacket() { CompoundTag *tag = new CompoundTag(); save(tag); + tag->remove(L"SpawnPotentials"); return shared_ptr( new TileEntityDataPacket(x, y, z, TileEntityDataPacket::TYPE_MOB_SPAWNER, tag) ); } +bool MobSpawnerTileEntity::triggerEvent(int b0, int b1) +{ + if (spawner->onEventTriggered(b0)) return true; + return TileEntity::triggerEvent(b0, b1); +} + +BaseMobSpawner *MobSpawnerTileEntity::getSpawner() +{ + return spawner; +} + // 4J Added shared_ptr MobSpawnerTileEntity::clone() { shared_ptr result = shared_ptr( new MobSpawnerTileEntity() ); TileEntity::clone(result); - result->entityId = entityId; - result->spawnDelay = spawnDelay; return result; +} + +void MobSpawnerTileEntity::setEntityId(const wstring &id) +{ + spawner->setEntityId(id); } \ No newline at end of file diff --git a/Minecraft.World/MobSpawnerTileEntity.h b/Minecraft.World/MobSpawnerTileEntity.h index 9cfb9f2f..b649702b 100644 --- a/Minecraft.World/MobSpawnerTileEntity.h +++ b/Minecraft.World/MobSpawnerTileEntity.h @@ -2,6 +2,7 @@ using namespace std; #include "TileEntity.h" +#include "BaseMobSpawner.h" class Packet; class Entity; @@ -12,48 +13,37 @@ public: eINSTANCEOF GetType() { return eTYPE_MOBSPAWNERTILEENTITY; } static TileEntity *create() { return new MobSpawnerTileEntity(); } -using TileEntity::setChanged; - private: - static const int MAX_DIST; + class TileEntityMobSpawner : public BaseMobSpawner + { + private: + MobSpawnerTileEntity *m_parent; -public: - int spawnDelay; + public: + TileEntityMobSpawner(MobSpawnerTileEntity *parent); -private: - wstring entityId; - CompoundTag *spawnData; + void broadcastEvent(int id); + Level *getLevel(); + int getX(); + int getY(); + int getZ(); + void setNextSpawnData(BaseMobSpawner::SpawnData *nextSpawnData); + }; - bool m_bEntityIdUpdated; // 4J Added + BaseMobSpawner *spawner; -public: - double spin, oSpin; - -private: - int minSpawnDelay; - int maxSpawnDelay; - int spawnCount; - shared_ptr displayEntity; - public: MobSpawnerTileEntity(); + ~MobSpawnerTileEntity(); - wstring getEntityId(); - void setEntityId(const wstring& entityId); - bool isNearPlayer(); - virtual void tick(); - void fillExtraData(shared_ptr entity); - -private: - void delay(); - -public: virtual void load(CompoundTag *tag); virtual void save(CompoundTag *tag); - - shared_ptr getDisplayEntity(); + virtual void tick(); virtual shared_ptr getUpdatePacket(); + virtual bool triggerEvent(int b0, int b1); + virtual BaseMobSpawner *getSpawner(); // 4J Added virtual shared_ptr clone(); + void setEntityId(const wstring &id); }; diff --git a/Minecraft.World/ModifiableAttributeInstance.cpp b/Minecraft.World/ModifiableAttributeInstance.cpp new file mode 100644 index 00000000..50aa6504 --- /dev/null +++ b/Minecraft.World/ModifiableAttributeInstance.cpp @@ -0,0 +1,185 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "ModifiableAttributeInstance.h" + +ModifiableAttributeInstance::ModifiableAttributeInstance(BaseAttributeMap *attributeMap, Attribute *attribute) +{ + this->attributeMap = attributeMap; + this->attribute = attribute; + + dirty = true; + cachedValue = 0.0; + + baseValue = attribute->getDefaultValue(); +} + +ModifiableAttributeInstance::~ModifiableAttributeInstance() +{ + for (int i = 0; i < AttributeModifier::TOTAL_OPERATIONS; i++) + { + for (AUTO_VAR(it, modifiers[i].begin()); it != modifiers[i].end(); ++it) + { + // Delete all modifiers + delete *it; + } + } +} + +Attribute *ModifiableAttributeInstance::getAttribute() +{ + return attribute; +} + +double ModifiableAttributeInstance::getBaseValue() +{ + return baseValue; +} + +void ModifiableAttributeInstance::setBaseValue(double baseValue) +{ + if (baseValue == this->getBaseValue()) return; + this->baseValue = baseValue; + setDirty(); +} + +// Returns a pointer to an internally managed vector of modifers by operation +unordered_set *ModifiableAttributeInstance::getModifiers(int operation) +{ + return &modifiers[operation]; +} + +// Returns a pointer to a new vector of all modifiers +void ModifiableAttributeInstance::getModifiers(unordered_set& result) +{ + for (int i = 0; i < AttributeModifier::TOTAL_OPERATIONS; i++) + { + unordered_set *opModifiers = &modifiers[i]; + + for (AUTO_VAR(it, opModifiers->begin()); it != opModifiers->end(); ++it) + { + result.insert(*it); + } + } +} + +AttributeModifier *ModifiableAttributeInstance::getModifier(eMODIFIER_ID id) +{ + AttributeModifier *modifier = NULL; + + AUTO_VAR(it, modifierById.find(id)); + if(it != modifierById.end()) + { + modifier = it->second; + } + + return modifier; +} + +void ModifiableAttributeInstance::addModifiers(unordered_set *modifiers) +{ + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) + { + addModifier(*it); + } +} + +// Add new modifier to attribute instance (takes ownership of modifier) +void ModifiableAttributeInstance::addModifier(AttributeModifier *modifier) +{ + // Can't add modifiers with the same ID (unless the modifier is anonymous) + if (modifier->getId() != eModifierId_ANONYMOUS && getModifier(modifier->getId()) != NULL) + { + assert(0); + // throw new IllegalArgumentException("Modifier is already applied on this attribute!"); + return; + } + + modifiers[modifier->getOperation()].insert(modifier); + modifierById[modifier->getId()] = modifier; + + setDirty(); +} + +void ModifiableAttributeInstance::setDirty() +{ + dirty = true; + attributeMap->onAttributeModified(this); +} + +void ModifiableAttributeInstance::removeModifier(AttributeModifier *modifier) +{ + for (int i = 0; i < AttributeModifier::TOTAL_OPERATIONS; i++) + { + for (AUTO_VAR(it, modifiers[i].begin()); it != modifiers[i].end(); ++it) + { + if (modifier->equals(*it)) + { + modifiers[i].erase(it); + break; + } + } + } + + modifierById.erase(modifier->getId()); + + setDirty(); +} + +void ModifiableAttributeInstance::removeModifier(eMODIFIER_ID id) +{ + AttributeModifier *modifier = getModifier(id); + if (modifier != NULL) removeModifier(modifier); +} + +void ModifiableAttributeInstance::removeModifiers() +{ + unordered_set removingModifiers; + getModifiers(removingModifiers); + + for (AUTO_VAR(it, removingModifiers.begin()); it != removingModifiers.end(); ++it) + { + removeModifier(*it); + } +} + +double ModifiableAttributeInstance::getValue() +{ + if (dirty) + { + cachedValue = calculateValue(); + dirty = false; + } + + return cachedValue; +} + +double ModifiableAttributeInstance::calculateValue() +{ + double base = getBaseValue(); + unordered_set *modifiers; + + modifiers = getModifiers(AttributeModifier::OPERATION_ADDITION); + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) + { + AttributeModifier *modifier = *it; + base += modifier->getAmount(); + } + + double result = base; + + modifiers = getModifiers(AttributeModifier::OPERATION_MULTIPLY_BASE); + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) + { + AttributeModifier *modifier = *it; + result += base * modifier->getAmount(); + } + + modifiers = getModifiers(AttributeModifier::OPERATION_MULTIPLY_TOTAL); + for (AUTO_VAR(it, modifiers->begin()); it != modifiers->end(); ++it) + { + AttributeModifier *modifier = *it; + result *= 1 + modifier->getAmount(); + } + + return attribute->sanitizeValue(result); +} \ No newline at end of file diff --git a/Minecraft.World/ModifiableAttributeInstance.h b/Minecraft.World/ModifiableAttributeInstance.h new file mode 100644 index 00000000..6d118862 --- /dev/null +++ b/Minecraft.World/ModifiableAttributeInstance.h @@ -0,0 +1,40 @@ +#pragma once + +#include "AttributeInstance.h" + +class ModifiableAttributeInstance : public AttributeInstance +{ +private: + BaseAttributeMap *attributeMap; + Attribute *attribute; + unordered_set modifiers [AttributeModifier::TOTAL_OPERATIONS]; + unordered_map modifierById; + double baseValue; + bool dirty; + double cachedValue; + +public: + ModifiableAttributeInstance(BaseAttributeMap *attributeMap, Attribute *attribute); + ~ModifiableAttributeInstance(); + + Attribute *getAttribute(); + double getBaseValue(); + void setBaseValue(double baseValue); + unordered_set *getModifiers(int operation); + void getModifiers(unordered_set& result); + AttributeModifier *getModifier(eMODIFIER_ID id); + void addModifiers(unordered_set *modifiers); + void addModifier(AttributeModifier *modifier); + +private: + void setDirty(); + +public: + void removeModifier(AttributeModifier *modifier); + void removeModifier(eMODIFIER_ID id); + void removeModifiers(); + double getValue(); + +private: + double calculateValue(); +}; \ No newline at end of file diff --git a/Minecraft.World/Monster.cpp b/Minecraft.World/Monster.cpp index 627ce8d1..174a706c 100644 --- a/Minecraft.World/Monster.cpp +++ b/Minecraft.World/Monster.cpp @@ -2,7 +2,9 @@ #include "net.minecraft.world.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.damagesource.h" #include "net.minecraft.world.effect.h" #include "net.minecraft.world.item.enchantment.h" @@ -11,40 +13,27 @@ #include "..\Minecraft.Client\Minecraft.h" - -void Monster::_init() -{ - attackDamage = 2; -} - Monster::Monster(Level *level) : PathfinderMob( level ) { - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that - // the derived version of the function is called - - // 4J Stu - Only the most derived classes should call this - //this->defineSynchedData(); - - _init(); - xpReward = Enemy::XP_REWARD_MEDIUM; } void Monster::aiStep() { - float br = getBrightness(1); - if (br > 0.5f) + updateSwingTime(); + float br = getBrightness(1); + if (br > 0.5f) { - noActionTime += 2; - } + noActionTime += 2; + } - PathfinderMob::aiStep(); + PathfinderMob::aiStep(); } void Monster::tick() { - PathfinderMob::tick(); - if (!level->isClientSide && (level->difficulty == Difficulty::PEACEFUL || Minecraft::GetInstance()->isTutorial() ) ) remove(); + PathfinderMob::tick(); + if (!level->isClientSide && (level->difficulty == Difficulty::PEACEFUL || Minecraft::GetInstance()->isTutorial() ) ) remove(); } shared_ptr Monster::findAttackTarget() @@ -56,25 +45,26 @@ shared_ptr Monster::findAttackTarget() } #endif - shared_ptr player = level->getNearestAttackablePlayer(shared_from_this(), 16); + shared_ptr player = level->getNearestAttackablePlayer(shared_from_this(), 16); if (player != NULL && canSee(player) ) return player; - return shared_ptr(); + return shared_ptr(); } -bool Monster::hurt(DamageSource *source, int dmg) +bool Monster::hurt(DamageSource *source, float dmg) { - if (PathfinderMob::hurt(source, dmg)) + if (isInvulnerable()) return false; + if (PathfinderMob::hurt(source, dmg)) { shared_ptr sourceEntity = source->getEntity(); - if (rider.lock() == sourceEntity || riding == sourceEntity) return true; + if (rider.lock() == sourceEntity || riding == sourceEntity) return true; - if (sourceEntity != shared_from_this()) + if (sourceEntity != shared_from_this()) { - this->attackTarget = sourceEntity; - } - return true; - } - return false; + attackTarget = sourceEntity; + } + return true; + } + return false; } /** @@ -85,75 +75,86 @@ bool Monster::hurt(DamageSource *source, int dmg) */ bool Monster::doHurtTarget(shared_ptr target) { - int dmg = attackDamage; - if (hasEffect(MobEffect::damageBoost)) - { - dmg += (3 << getEffect(MobEffect::damageBoost)->getAmplifier()); - } - if (hasEffect(MobEffect::weakness)) + float dmg = (float) getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->getValue(); + int knockback = 0; + + + if ( target->instanceof(eTYPE_LIVINGENTITY) ) { - dmg -= (2 << getEffect(MobEffect::weakness)->getAmplifier()); + shared_ptr livingTarget = dynamic_pointer_cast(target); + dmg += EnchantmentHelper::getDamageBonus(dynamic_pointer_cast(shared_from_this()), livingTarget); + knockback += EnchantmentHelper::getKnockbackBonus(dynamic_pointer_cast(shared_from_this()), livingTarget); } - DamageSource *damageSource = DamageSource::mobAttack(dynamic_pointer_cast( shared_from_this() ) ); - bool didHurt = target->hurt(damageSource, dmg); - delete damageSource; + boolean wasHurt = target->hurt(DamageSource::mobAttack(dynamic_pointer_cast(shared_from_this())), dmg); - if (didHurt) + if (wasHurt) { - int fireAspect = EnchantmentHelper::getFireAspect(dynamic_pointer_cast(shared_from_this())); + if (knockback > 0) + { + target->push(-Mth::sin(yRot * PI / 180) * knockback * .5f, 0.1, Mth::cos(yRot * PI / 180) * knockback * .5f); + xd *= 0.6; + zd *= 0.6; + } + + int fireAspect = EnchantmentHelper::getFireAspect(dynamic_pointer_cast(shared_from_this())); if (fireAspect > 0) { target->setOnFire(fireAspect * 4); } - shared_ptr mob = dynamic_pointer_cast(target); - if (mob != NULL) + if (target->instanceof(eTYPE_LIVINGENTITY)) { - ThornsEnchantment::doThornsAfterAttack(shared_from_this(), mob, random); + shared_ptr livingTarget = dynamic_pointer_cast(target); + ThornsEnchantment::doThornsAfterAttack(shared_from_this(), livingTarget, random); } } - return didHurt; + return wasHurt; } void Monster::checkHurtTarget(shared_ptr target, float distance) { - if (attackTime <= 0 && distance < 2.0f && target->bb->y1 > bb->y0 && target->bb->y0 < bb->y1) + if (attackTime <= 0 && distance < 2.0f && target->bb->y1 > bb->y0 && target->bb->y0 < bb->y1) { - attackTime = 20; - doHurtTarget(target); - } + attackTime = 20; + doHurtTarget(target); + } } float Monster::getWalkTargetValue(int x, int y, int z) { - return 0.5f - level->getBrightness(x, y, z); + return 0.5f - level->getBrightness(x, y, z); } bool Monster::isDarkEnoughToSpawn() { - int xt = Mth::floor(x); - int yt = Mth::floor(bb->y0); - int zt = Mth::floor(z); - if (level->getBrightness(LightLayer::Sky, xt, yt, zt) > random->nextInt(32)) return false; + int xt = Mth::floor(x); + int yt = Mth::floor(bb->y0); + int zt = Mth::floor(z); + if (level->getBrightness(LightLayer::Sky, xt, yt, zt) > random->nextInt(32)) return false; - int br = level->getRawBrightness(xt, yt, zt); + int br = level->getRawBrightness(xt, yt, zt); - if (level->isThundering()) + if (level->isThundering()) { - int tmp = level->skyDarken; - level->skyDarken = 10; - br = level->getRawBrightness(xt, yt, zt); - level->skyDarken = tmp; - } + int tmp = level->skyDarken; + level->skyDarken = 10; + br = level->getRawBrightness(xt, yt, zt); + level->skyDarken = tmp; + } - return br <= random->nextInt(8); + return br <= random->nextInt(8); } bool Monster::canSpawn() { - // 4J Stu - // Fix for #8265 - AI: Monsters will flash briefly on the screen around Monster Spawners when the game settings are set to Peaceful. - return isDarkEnoughToSpawn() && PathfinderMob::canSpawn() && level->difficulty > Difficulty::PEACEFUL; + return level->difficulty > Difficulty::PEACEFUL && isDarkEnoughToSpawn() && PathfinderMob::canSpawn(); +} + +void Monster::registerAttributes() +{ + PathfinderMob::registerAttributes(); + + getAttributes()->registerAttribute(SharedMonsterAttributes::ATTACK_DAMAGE); } \ No newline at end of file diff --git a/Minecraft.World/Monster.h b/Minecraft.World/Monster.h index 2bad48da..33f72b0e 100644 --- a/Minecraft.World/Monster.h +++ b/Minecraft.World/Monster.h @@ -14,35 +14,31 @@ public: eINSTANCEOF GetType() { return eTYPE_MONSTER; } static Entity *create(Level *level) { return NULL; } -protected: - int attackDamage; - -private: - void _init(); - public: Monster(Level *level); - virtual void aiStep(); - virtual void tick(); + virtual void aiStep(); + virtual void tick(); protected: virtual shared_ptr findAttackTarget(); public: - virtual bool hurt(DamageSource *source, int dmg); + virtual bool hurt(DamageSource *source, float dmg); virtual bool doHurtTarget(shared_ptr target); protected: virtual void checkHurtTarget(shared_ptr target, float distance); public: - virtual float getWalkTargetValue(int x, int y, int z); + virtual float getWalkTargetValue(int x, int y, int z); protected: - virtual bool isDarkEnoughToSpawn(); + virtual bool isDarkEnoughToSpawn(); public: virtual bool canSpawn(); -}; +protected: + void registerAttributes(); +}; \ No newline at end of file diff --git a/Minecraft.World/MonsterRoomFeature.cpp b/Minecraft.World/MonsterRoomFeature.cpp index cd44376a..17ac55ae 100644 --- a/Minecraft.World/MonsterRoomFeature.cpp +++ b/Minecraft.World/MonsterRoomFeature.cpp @@ -4,8 +4,28 @@ #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.tile.entity.h" #include "net.minecraft.world.item.h" +#include "WeighedTreasure.h" #include "MonsterRoomFeature.h" +WeighedTreasure *MonsterRoomFeature::monsterRoomTreasure[MonsterRoomFeature::TREASURE_ITEMS_COUNT] = +{ + new WeighedTreasure(Item::saddle_Id, 0, 1, 1, 10), + new WeighedTreasure(Item::ironIngot_Id, 0, 1, 4, 10), + new WeighedTreasure(Item::bread_Id, 0, 1, 1, 10), + new WeighedTreasure(Item::wheat_Id, 0, 1, 4, 10), + new WeighedTreasure(Item::gunpowder_Id, 0, 1, 4, 10), + new WeighedTreasure(Item::string_Id, 0, 1, 4, 10), + new WeighedTreasure(Item::bucket_empty_Id, 0, 1, 1, 10), + new WeighedTreasure(Item::apple_gold_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::redStone_Id, 0, 1, 4, 10), + new WeighedTreasure(Item::record_01_Id, 0, 1, 1, 10), + new WeighedTreasure(Item::record_02_Id, 0, 1, 1, 10), + new WeighedTreasure(Item::nameTag_Id, 0, 1, 1, 10), + new WeighedTreasure(Item::horseArmorGold_Id, 0, 1, 1, 2), + new WeighedTreasure(Item::horseArmorMetal_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::horseArmorDiamond_Id, 0, 1, 1, 1), +}; + bool MonsterRoomFeature::place(Level *level, Random *random, int x, int y, int z) { int hr = 3; @@ -48,19 +68,22 @@ bool MonsterRoomFeature::place(Level *level, Random *random, int x, int y, int z { if (yy >= 0 && !level->getMaterial(xx, yy - 1, zz)->isSolid()) { - level->setTile(xx, yy, zz, 0); - } else if (level->getMaterial(xx, yy, zz)->isSolid()) + level->removeTile(xx, yy, zz); + } + else if (level->getMaterial(xx, yy, zz)->isSolid()) { if (yy == y - 1 && random->nextInt(4) != 0) { - level->setTile(xx, yy, zz, Tile::mossStone_Id); - } else { - level->setTile(xx, yy, zz, Tile::stoneBrick_Id); + level->setTileAndData(xx, yy, zz, Tile::mossyCobblestone_Id, 0, Tile::UPDATE_CLIENTS); + } + else + { + level->setTileAndData(xx, yy, zz, Tile::cobblestone_Id, 0, Tile::UPDATE_CLIENTS); } } } else { - level->setTile(xx, yy, zz, 0); + level->removeTile(xx, yy, zz); } } } @@ -83,15 +106,13 @@ bool MonsterRoomFeature::place(Level *level, Random *random, int x, int y, int z if (count != 1) continue; - level->setTile(xc, yc, zc, Tile::chest_Id); + level->setTileAndData(xc, yc, zc, Tile::chest_Id, 0, Tile::UPDATE_CLIENTS); + WeighedTreasureArray wrapperArray(monsterRoomTreasure, TREASURE_ITEMS_COUNT); + WeighedTreasureArray treasure = WeighedTreasure::addToTreasure(wrapperArray, Item::enchantedBook->createForRandomTreasure(random)); shared_ptr chest = dynamic_pointer_cast( level->getTileEntity(xc, yc, zc) ); if (chest != NULL ) { - for (int j = 0; j < 8; j++) - { - shared_ptr item = randomItem(random); - if (item != NULL) chest->setItem(random->nextInt(chest->getContainerSize()), item); - } + WeighedTreasure::addChestItems(random, treasure, chest, 8); } break; @@ -99,36 +120,17 @@ bool MonsterRoomFeature::place(Level *level, Random *random, int x, int y, int z } - level->setTile(x, y, z, Tile::mobSpawner_Id); + level->setTileAndData(x, y, z, Tile::mobSpawner_Id, 0, Tile::UPDATE_CLIENTS); shared_ptr entity = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); if( entity != NULL ) { - entity->setEntityId(randomEntityId(random)); + entity->getSpawner()->setEntityId(randomEntityId(random)); } return true; } -shared_ptr MonsterRoomFeature::randomItem(Random *random) -{ - int type = random->nextInt(12); - if (type == 0) return shared_ptr( new ItemInstance(Item::saddle) ); - if (type == 1) return shared_ptr( new ItemInstance(Item::ironIngot, random->nextInt(4) + 1) ); - if (type == 2) return shared_ptr( new ItemInstance(Item::bread) ); - if (type == 3) return shared_ptr( new ItemInstance(Item::wheat, random->nextInt(4) + 1) ); - if (type == 4) return shared_ptr( new ItemInstance(Item::sulphur, random->nextInt(4) + 1) ); - if (type == 5) return shared_ptr( new ItemInstance(Item::string, random->nextInt(4) + 1) ); - if (type == 6) return shared_ptr( new ItemInstance(Item::bucket_empty) ); - if (type == 7 && random->nextInt(100) == 0) return shared_ptr( new ItemInstance(Item::apple_gold) ); - if (type == 8 && random->nextInt(2) == 0) return shared_ptr( new ItemInstance(Item::redStone, random->nextInt(4) + 1) ); - if (type == 9 && random->nextInt(10) == 0) return shared_ptr( new ItemInstance( Item::items[Item::record_01->id + random->nextInt(2)]) ); - if (type == 10) return shared_ptr( new ItemInstance(Item::dye_powder, 1, DyePowderItem::BROWN) ); - if (type == 11) return Item::enchantedBook->createForRandomLoot(random); - - return shared_ptr(); -} - wstring MonsterRoomFeature::randomEntityId(Random *random) { int id = random->nextInt(4); diff --git a/Minecraft.World/MonsterRoomFeature.h b/Minecraft.World/MonsterRoomFeature.h index 88304ad6..2b911e10 100644 --- a/Minecraft.World/MonsterRoomFeature.h +++ b/Minecraft.World/MonsterRoomFeature.h @@ -2,15 +2,18 @@ #include "Feature.h" #include "Material.h" +class WeighedTreasure; + class MonsterRoomFeature : public Feature { private: - //int tile; + + static const int TREASURE_ITEMS_COUNT = 15; + static WeighedTreasure *monsterRoomTreasure[TREASURE_ITEMS_COUNT]; public: virtual bool place(Level *level, Random *random, int x, int y, int z); private: - shared_ptr randomItem(Random *random); - wstring randomEntityId(Random *random); + wstring randomEntityId(Random *random); }; diff --git a/Minecraft.World/MoveControl.cpp b/Minecraft.World/MoveControl.cpp index 30e94e68..02b5a9e0 100644 --- a/Minecraft.World/MoveControl.cpp +++ b/Minecraft.World/MoveControl.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" -#include "net.minecraft.world.entity.ai.control.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.ai.control.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.phys.h" #include "MoveControl.h" @@ -14,7 +16,7 @@ MoveControl::MoveControl(Mob *mob) wantedY = mob->y; wantedZ = mob->z; - speed = 0.0f; + speedModifier = 0.0; _hasWanted = false; } @@ -24,17 +26,17 @@ bool MoveControl::hasWanted() return _hasWanted; } -float MoveControl::getSpeed() +double MoveControl::getSpeedModifier() { - return speed; + return speedModifier; } -void MoveControl::setWantedPosition(double x, double y, double z, float speed) +void MoveControl::setWantedPosition(double x, double y, double z, double speedModifier) { wantedX = x; wantedY = y; wantedZ = z; - this->speed = speed; + this->speedModifier = speedModifier; _hasWanted = true; } @@ -55,7 +57,7 @@ void MoveControl::tick() float yRotD = (float) (atan2(zd, xd) * 180 / PI) - 90; mob->yRot = rotlerp(mob->yRot, yRotD, MAX_TURN); - mob->setSpeed(speed * mob->getWalkingSpeedModifier()); + mob->setSpeed((float) (speedModifier * mob->getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue())); if (yd > 0 && xd * xd + zd * zd < 1) mob->getJumpControl()->jump(); } diff --git a/Minecraft.World/MoveControl.h b/Minecraft.World/MoveControl.h index 4138280e..fdc5d65d 100644 --- a/Minecraft.World/MoveControl.h +++ b/Minecraft.World/MoveControl.h @@ -17,15 +17,15 @@ private: double wantedX; double wantedY; double wantedZ; - float speed; + double speedModifier; bool _hasWanted; public: MoveControl(Mob *mob); bool hasWanted(); - float getSpeed(); - void setWantedPosition(double x, double y, double z, float speed); + double getSpeedModifier(); + void setWantedPosition(double x, double y, double z, double speedModifier); void setSpeed(float speed); virtual void tick(); diff --git a/Minecraft.World/MoveIndoorsGoal.cpp b/Minecraft.World/MoveIndoorsGoal.cpp index 215f9a29..395fe578 100644 --- a/Minecraft.World/MoveIndoorsGoal.cpp +++ b/Minecraft.World/MoveIndoorsGoal.cpp @@ -45,9 +45,9 @@ void MoveIndoorsGoal::start() if (mob->distanceToSqr(_doorInfo->getIndoorX(), _doorInfo->y, _doorInfo->getIndoorZ()) > 16 * 16) { Vec3 *pos = RandomPos::getPosTowards(dynamic_pointer_cast(mob->shared_from_this()), 14, 3, Vec3::newTemp(_doorInfo->getIndoorX() + 0.5, _doorInfo->getIndoorY(), _doorInfo->getIndoorZ() + 0.5)); - if (pos != NULL) mob->getNavigation()->moveTo(pos->x, pos->y, pos->z, 0.3f); + if (pos != NULL) mob->getNavigation()->moveTo(pos->x, pos->y, pos->z, 1.0f); } - else mob->getNavigation()->moveTo(_doorInfo->getIndoorX() + 0.5, _doorInfo->getIndoorY(), _doorInfo->getIndoorZ() + 0.5, 0.3f); + else mob->getNavigation()->moveTo(_doorInfo->getIndoorX() + 0.5, _doorInfo->getIndoorY(), _doorInfo->getIndoorZ() + 0.5, 1.0f); } void MoveIndoorsGoal::stop() diff --git a/Minecraft.World/MoveThroughVillageGoal.cpp b/Minecraft.World/MoveThroughVillageGoal.cpp index 2405374f..d4cdde94 100644 --- a/Minecraft.World/MoveThroughVillageGoal.cpp +++ b/Minecraft.World/MoveThroughVillageGoal.cpp @@ -9,13 +9,13 @@ #include "MoveThroughVillageGoal.h" #include "Path.h" -MoveThroughVillageGoal::MoveThroughVillageGoal(PathfinderMob *mob, float speed, bool onlyAtNight) +MoveThroughVillageGoal::MoveThroughVillageGoal(PathfinderMob *mob, double speedModifier, bool onlyAtNight) { path = NULL; doorInfo = weak_ptr(); this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; this->onlyAtNight = onlyAtNight; setRequiredControlFlags(Control::MoveControlFlag); } @@ -67,7 +67,7 @@ bool MoveThroughVillageGoal::canContinueToUse() void MoveThroughVillageGoal::start() { - mob->getNavigation()->moveTo(path, speed); + mob->getNavigation()->moveTo(path, speedModifier); path = NULL; } diff --git a/Minecraft.World/MoveThroughVillageGoal.h b/Minecraft.World/MoveThroughVillageGoal.h index a087e522..73b9bd9a 100644 --- a/Minecraft.World/MoveThroughVillageGoal.h +++ b/Minecraft.World/MoveThroughVillageGoal.h @@ -10,14 +10,14 @@ class MoveThroughVillageGoal : public Goal { private: PathfinderMob *mob; - float speed; + double speedModifier; Path *path; weak_ptr doorInfo; bool onlyAtNight; vector< weak_ptr > visited; public: - MoveThroughVillageGoal(PathfinderMob *mob, float speed, bool onlyAtNight); + MoveThroughVillageGoal(PathfinderMob *mob, double speedModifier, bool onlyAtNight); ~MoveThroughVillageGoal(); virtual bool canUse(); diff --git a/Minecraft.World/MoveTowardsRestrictionGoal.cpp b/Minecraft.World/MoveTowardsRestrictionGoal.cpp index a1848d46..2c3900b6 100644 --- a/Minecraft.World/MoveTowardsRestrictionGoal.cpp +++ b/Minecraft.World/MoveTowardsRestrictionGoal.cpp @@ -6,12 +6,12 @@ #include "net.minecraft.world.level.h" #include "MoveTowardsRestrictionGoal.h" -MoveTowardsRestrictionGoal::MoveTowardsRestrictionGoal(PathfinderMob *mob, float speed) +MoveTowardsRestrictionGoal::MoveTowardsRestrictionGoal(PathfinderMob *mob, double speedModifier) { wantedX = wantedY = wantedZ = 0.0; this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag); } @@ -34,5 +34,5 @@ bool MoveTowardsRestrictionGoal::canContinueToUse() void MoveTowardsRestrictionGoal::start() { - mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speed); + mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speedModifier); } \ No newline at end of file diff --git a/Minecraft.World/MoveTowardsRestrictionGoal.h b/Minecraft.World/MoveTowardsRestrictionGoal.h index 859b5ee8..f2864a9b 100644 --- a/Minecraft.World/MoveTowardsRestrictionGoal.h +++ b/Minecraft.World/MoveTowardsRestrictionGoal.h @@ -7,10 +7,10 @@ class MoveTowardsRestrictionGoal : public Goal private: PathfinderMob *mob; double wantedX, wantedY, wantedZ; - float speed; + double speedModifier; public: - MoveTowardsRestrictionGoal(PathfinderMob *mob, float speed); + MoveTowardsRestrictionGoal(PathfinderMob *mob, double speedModifier); bool canUse(); bool canContinueToUse(); diff --git a/Minecraft.World/MoveTowardsTargetGoal.cpp b/Minecraft.World/MoveTowardsTargetGoal.cpp index 6d9810b5..c0537d1f 100644 --- a/Minecraft.World/MoveTowardsTargetGoal.cpp +++ b/Minecraft.World/MoveTowardsTargetGoal.cpp @@ -6,17 +6,17 @@ #include "net.minecraft.world.phys.h" #include "MoveTowardsTargetGoal.h" -MoveTowardsTargetGoal::MoveTowardsTargetGoal(PathfinderMob *mob, float speed, float within) +MoveTowardsTargetGoal::MoveTowardsTargetGoal(PathfinderMob *mob, double speedModifier, float within) { this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; this->within = within; setRequiredControlFlags(Control::MoveControlFlag); } bool MoveTowardsTargetGoal::canUse() { - target = weak_ptr(mob->getTarget()); + target = weak_ptr(mob->getTarget()); if (target.lock() == NULL) return false; if (target.lock()->distanceToSqr(mob->shared_from_this()) > within * within) return false; Vec3 *pos = RandomPos::getPosTowards(dynamic_pointer_cast(mob->shared_from_this()), 16, 7, Vec3::newTemp(target.lock()->x, target.lock()->y, target.lock()->z)); @@ -39,5 +39,5 @@ void MoveTowardsTargetGoal::stop() void MoveTowardsTargetGoal::start() { - mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speed); + mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speedModifier); } \ No newline at end of file diff --git a/Minecraft.World/MoveTowardsTargetGoal.h b/Minecraft.World/MoveTowardsTargetGoal.h index 5186b752..bf451301 100644 --- a/Minecraft.World/MoveTowardsTargetGoal.h +++ b/Minecraft.World/MoveTowardsTargetGoal.h @@ -6,12 +6,13 @@ class MoveTowardsTargetGoal : public Goal { private: PathfinderMob *mob; - weak_ptr target; + weak_ptr target; double wantedX, wantedY, wantedZ; - float speed, within; + double speedModifier; + float within; public: - MoveTowardsTargetGoal(PathfinderMob *mob, float speed, float within); + MoveTowardsTargetGoal(PathfinderMob *mob, double speedModifier, float within); bool canUse(); bool canContinueToUse(); diff --git a/Minecraft.World/Mth.cpp b/Minecraft.World/Mth.cpp index eccd828e..ab990e6c 100644 --- a/Minecraft.World/Mth.cpp +++ b/Minecraft.World/Mth.cpp @@ -1,12 +1,13 @@ #include "stdafx.h" #include "Mth.h" #include "Random.h" +#include "StringHelpers.h" const int Mth::BIG_ENOUGH_INT = 1024; const float Mth::BIG_ENOUGH_FLOAT = BIG_ENOUGH_INT; -const float Mth::RAD_TO_GRAD = PI / 180.0f; const float Mth::DEGRAD = PI / 180.0f; const float Mth::RADDEG = 180.0f / PI; +const float Mth::RAD_TO_GRAD = PI / 180.0f; float *Mth::_sin = NULL; @@ -15,11 +16,11 @@ const float Mth::sinScale = 65536.0f / (float) (PI * 2); // 4J - added - was in static constructor void Mth::init() { - _sin = new float[65536]; - for (int i = 0; i < 65536; i++) + _sin = new float[65536]; + for (int i = 0; i < 65536; i++) { - _sin[i] = (float) ::sin(i * PI * 2 / 65536.0f); - } + _sin[i] = (float) ::sin(i * PI * 2 / 65536.0f); + } } float Mth::sin(float i) @@ -46,14 +47,14 @@ float Mth::sqrt(double x) int Mth::floor(float v) { - int i = (int) v; - return v < i ? i - 1 : i; + int i = (int) v; + return v < i ? i - 1 : i; } __int64 Mth::lfloor(double v) { - __int64 i = (__int64) v; - return v < i ? i - 1 : i; + __int64 i = (__int64) v; + return v < i ? i - 1 : i; } int Mth::fastFloor(double x) @@ -63,8 +64,8 @@ int Mth::fastFloor(double x) int Mth::floor(double v) { - int i = (int) v; - return v < i ? i - 1 : i; + int i = (int) v; + return v < i ? i - 1 : i; } int Mth::absFloor(double v) @@ -84,21 +85,21 @@ int Mth::abs(int v) int Mth::ceil(float v) { - int i = (int) v; - return v > i ? i + 1 : i; + int i = (int) v; + return v > i ? i + 1 : i; } int Mth::clamp(int value, int min, int max) { - if (value < min) + if (value < min) { - return min; - } - if (value > max) + return min; + } + if (value > max) { - return max; - } - return value; + return max; + } + return value; } float Mth::clamp(float value, float min, float max) @@ -116,25 +117,37 @@ float Mth::clamp(float value, float min, float max) double Mth::asbMax(double a, double b) { - if (a < 0) a = -a; - if (b < 0) b = -b; - return a > b ? a : b; + if (a < 0) a = -a; + if (b < 0) b = -b; + return a > b ? a : b; } int Mth::intFloorDiv(int a, int b) { - if (a < 0) return -((-a - 1) / b) - 1; - return a / b; + if (a < 0) return -((-a - 1) / b) - 1; + return a / b; } int Mth::nextInt(Random *random, int minInclusive, int maxInclusive) { - if (minInclusive >= maxInclusive) + if (minInclusive >= maxInclusive) { - return minInclusive; - } - return random->nextInt(maxInclusive - minInclusive + 1) + minInclusive; + return minInclusive; + } + return random->nextInt(maxInclusive - minInclusive + 1) + minInclusive; +} + +float Mth::nextFloat(Random *random, float min, float max) +{ + if (min >= max) return min; + return (random->nextFloat() * (max - min)) + min; +} + +double Mth::nextDouble(Random *random, double min, double max) +{ + if (min >= max) return min; + return (random->nextDouble() * (max - min)) + min; } float Mth::wrapDegrees(float input) @@ -165,6 +178,66 @@ double Mth::wrapDegrees(double input) return input; } +int Mth::getInt(const wstring &input, int def) +{ + int result = def; + + result = _fromString(input); + + return result; +} + +int Mth::getInt(const wstring &input, int def, int min) +{ + int result = def; + + result = _fromString(input); + + if (result < min) result = min; + return result; +} + +double Mth::getDouble(const wstring &input, double def) +{ + double result = def; + + result = _fromString(input); + + return result; +} + +double Mth::getDouble(const wstring &input, double def, double min) +{ + double result = def; + + result = _fromString(input); + + if (result < min) result = min; + return result; +} + +// 4J Changed this to remove the use of the actuall UUID type +wstring Mth::createInsecureUUID(Random *random) +{ + wchar_t output[33]; + output[32] = 0; + __int64 high = (random->nextLong() & ~UUID_VERSION) | UUID_VERSION_TYPE_4; + __int64 low = (random->nextLong() & ~UUID_VARIANT) | UUID_VARIANT_2; + for(int i = 0; i < 16; i++ ) + { + wchar_t nybbleHigh = high & 0xf; + wchar_t nybbleLow = low & 0xf; + nybbleHigh = (nybbleHigh > 9 ) ? ( nybbleHigh + (L'a'-10) ) : ( nybbleHigh + L'0' ); + nybbleLow = (nybbleLow > 9 ) ? ( nybbleLow + (L'a'-10) ) : ( nybbleLow + L'0' ); + high >>= 4; + low >>= 4; + output[31 - i] = nybbleLow; + output[15 - i] = nybbleHigh; + } + return wstring(output); +} + + // 4J Added bool Mth::almostEquals( double double1, double double2, double precision) { diff --git a/Minecraft.World/Mth.h b/Minecraft.World/Mth.h index 17119fb1..4ce90893 100644 --- a/Minecraft.World/Mth.h +++ b/Minecraft.World/Mth.h @@ -4,13 +4,16 @@ class Mth { private: static const int BIG_ENOUGH_INT; - static const float BIG_ENOUGH_FLOAT; - -public: - static const float RAD_TO_GRAD; + static const float BIG_ENOUGH_FLOAT; public: static const float DEGRAD; static const float RADDEG; + static const float RAD_TO_GRAD; + + static const __int64 UUID_VERSION = 0x000000000000f000L; + static const __int64 UUID_VERSION_TYPE_4 = 0x0000000000004000L; + static const __int64 UUID_VARIANT = 0xc000000000000000L; + static const __int64 UUID_VARIANT_2 = 0x8000000000000000L; private: static float *_sin; private: @@ -18,24 +21,31 @@ private: public : static void init(); // 4J added static float sin(float i); - static float cos(float i); - static float sqrt(float x); - static float sqrt(double x); - static int floor(float v); + static float cos(float i); + static float sqrt(float x); + static float sqrt(double x); + static int floor(float v); static __int64 lfloor(double v); - static int fastFloor(double x); - static int floor(double v); - static int absFloor(double v); - static float abs(float v); + static int fastFloor(double x); + static int floor(double v); + static int absFloor(double v); + static float abs(float v); static int abs(int v); - static int ceil(float v); + static int ceil(float v); static int clamp(int value, int min, int max) ; static float clamp(float value, float min, float max); - static double asbMax(double a, double b); - static int intFloorDiv(int a, int b); - static int nextInt(Random *random, int minInclusive, int maxInclusive); + static double asbMax(double a, double b); + static int intFloorDiv(int a, int b); + static int nextInt(Random *random, int minInclusive, int maxInclusive); + static float nextFloat(Random *random, float min, float max); + static double nextDouble(Random *random, double min, double max); static float wrapDegrees(float input); static double wrapDegrees(double input); + static wstring createInsecureUUID(Random *random); + static int getInt(const wstring &input, int def); + static int getInt(const wstring &input, int def, int min); + static double getDouble(const wstring &input, double def); + static double getDouble(const wstring &input, double def, double min); // 4J Added static bool almostEquals( double double1, double double2, double precision); diff --git a/Minecraft.World/MultiEntityMob.h b/Minecraft.World/MultiEntityMob.h new file mode 100644 index 00000000..a52d0916 --- /dev/null +++ b/Minecraft.World/MultiEntityMob.h @@ -0,0 +1,10 @@ +#pragma once + +class MultiEntityMobPart; + +class MultiEntityMob +{ +public: + virtual Level *getLevel() = 0; + virtual bool hurt(shared_ptr MultiEntityMobPart, DamageSource *source, float damage) = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/MultiEntityMobPart.cpp b/Minecraft.World/MultiEntityMobPart.cpp new file mode 100644 index 00000000..dfca1b2f --- /dev/null +++ b/Minecraft.World/MultiEntityMobPart.cpp @@ -0,0 +1,42 @@ +#include "stdafx.h" +#include "BossMob.h" +#include "MultiEntityMob.h" +#include "MultiEntityMobPart.h" + +MultiEntityMobPart::MultiEntityMobPart(shared_ptrparentMob, const wstring &id, float w, float h) : Entity(parentMob->getLevel()), parentMob( parentMob ), id( id ) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); + + setSize(w, h); +} + + +void MultiEntityMobPart::defineSynchedData() +{ +} + +void MultiEntityMobPart::readAdditionalSaveData(CompoundTag *tag) +{ +} + +void MultiEntityMobPart::addAdditonalSaveData(CompoundTag *tag) +{ +} + + +bool MultiEntityMobPart::isPickable() +{ + return true; +} + +bool MultiEntityMobPart::hurt(DamageSource *source, float damage) +{ + return parentMob.lock()->hurt( dynamic_pointer_cast( shared_from_this() ), source, damage); +} + +bool MultiEntityMobPart::is(shared_ptr other) +{ + return shared_from_this() == other || parentMob.lock() == dynamic_pointer_cast(other); +} \ No newline at end of file diff --git a/Minecraft.World/MultiEntityMobPart.h b/Minecraft.World/MultiEntityMobPart.h new file mode 100644 index 00000000..b5322317 --- /dev/null +++ b/Minecraft.World/MultiEntityMobPart.h @@ -0,0 +1,27 @@ +#pragma once +using namespace std; +#include "Entity.h" + +class Level; +class MultiEntityMob; + +class MultiEntityMobPart : public Entity +{ +public: + eINSTANCEOF GetType() { return eTYPE_MULTIENTITY_MOB_PART; }; +public: + weak_ptr parentMob; + const wstring id; + + MultiEntityMobPart(shared_ptr parentMob, const wstring &id, float w, float h); + +protected: + virtual void defineSynchedData(); + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *tag); + +public: + virtual bool isPickable(); + virtual bool hurt(DamageSource *source, float damage); + virtual bool is(shared_ptr other); +}; \ No newline at end of file diff --git a/Minecraft.World/MultiTextureTileItem.cpp b/Minecraft.World/MultiTextureTileItem.cpp index a41a896f..88343275 100644 --- a/Minecraft.World/MultiTextureTileItem.cpp +++ b/Minecraft.World/MultiTextureTileItem.cpp @@ -1,14 +1,24 @@ #include "stdafx.h" #include "Tile.h" #include "MultiTextureTileItem.h" +#include "net.minecraft.world.item.crafting.h" -MultiTextureTileItem::MultiTextureTileItem(int id, Tile *parentTile, int *nameExtensions, int iLength) : TileItem(id) +MultiTextureTileItem::MultiTextureTileItem(int id, Tile *parentTile, int *nameExtensions, int iLength, int anyValueName) : TileItem(id) { this->parentTile = parentTile; this->nameExtensions = nameExtensions; this->m_iNameExtensionsLength=iLength; + if(anyValueName != -1) + { + m_anyValueName = anyValueName; + } + else + { + m_anyValueName = nameExtensions[0]; + } + setMaxDamage(0); setStackedByData(true); } @@ -29,18 +39,15 @@ unsigned int MultiTextureTileItem::getDescriptionId(int iData) { iData = 0; } - //return super.getDescriptionId() + "." + nameExtensions[auxValue]; return nameExtensions[iData]; } unsigned int MultiTextureTileItem::getDescriptionId(shared_ptr instance) { - int auxValue = instance->getAuxValue(); - if (auxValue < 0 || auxValue >= m_iNameExtensionsLength) - { - auxValue = 0; - } - //return super.getDescriptionId() + "." + nameExtensions[auxValue]; - return nameExtensions[auxValue]; -} - + int auxValue = instance->getAuxValue(); + if (auxValue == Recipes::ANY_AUX_VALUE || auxValue < 0 || auxValue >= m_iNameExtensionsLength) + { + return m_anyValueName; + } + return nameExtensions[auxValue]; +} \ No newline at end of file diff --git a/Minecraft.World/MultiTextureTileItem.h b/Minecraft.World/MultiTextureTileItem.h index 078357ea..510d1f0f 100644 --- a/Minecraft.World/MultiTextureTileItem.h +++ b/Minecraft.World/MultiTextureTileItem.h @@ -11,9 +11,10 @@ private: //private final String[] nameExtensions; int *nameExtensions; int m_iNameExtensionsLength; + int m_anyValueName; // 4J Added public: - MultiTextureTileItem(int id, Tile *parentTile,int *nameExtensions, int iLength); + MultiTextureTileItem(int id, Tile *parentTile,int *nameExtensions, int iLength, int anyValueName = -1); // 4J Added anyValueName virtual Icon *getIcon(int itemAuxValue); virtual int getLevelDataForAuxValue(int auxValue); diff --git a/Minecraft.World/Mushroom.cpp b/Minecraft.World/Mushroom.cpp index 1056cdec..6b20e0d1 100644 --- a/Minecraft.World/Mushroom.cpp +++ b/Minecraft.World/Mushroom.cpp @@ -4,54 +4,53 @@ #include "net.minecraft.world.h" #include "Mushroom.h" -Mushroom::Mushroom(int id, const wstring &texture) : Bush(id) +Mushroom::Mushroom(int id) : Bush(id) { - this->updateDefaultShape(); - this->setTicking(true); - this->texture = texture; + this->updateDefaultShape(); + this->setTicking(true); } // 4J Added override void Mushroom::updateDefaultShape() { - float ss = 0.2f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, ss * 2, 0.5f + ss); + float ss = 0.2f; + this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, ss * 2, 0.5f + ss); } void Mushroom::tick(Level *level, int x, int y, int z, Random *random) { - if (random->nextInt(25) == 0) + if (random->nextInt(25) == 0) { - int r = 4; - int max = 5; - for (int xx = x - r; xx <= x + r; xx++) - for (int zz = z - r; zz <= z + r; zz++) - for (int yy = y - 1; yy <= y + 1; yy++) + int r = 4; + int max = 5; + for (int xx = x - r; xx <= x + r; xx++) + for (int zz = z - r; zz <= z + r; zz++) + for (int yy = y - 1; yy <= y + 1; yy++) { - if (level->getTile(xx, yy, zz) == id && --max <= 0) return; - } + if (level->getTile(xx, yy, zz) == id && --max <= 0) return; + } - int x2 = x + random->nextInt(3) - 1; - int y2 = y + random->nextInt(2) - random->nextInt(2); - int z2 = z + random->nextInt(3) - 1; - for (int i = 0; i < 4; i++) - { - if (level->isEmptyTile(x2, y2, z2) && canSurvive(level, x2, y2, z2)) + int x2 = x + random->nextInt(3) - 1; + int y2 = y + random->nextInt(2) - random->nextInt(2); + int z2 = z + random->nextInt(3) - 1; + for (int i = 0; i < 4; i++) { - x = x2; - y = y2; - z = z2; - } - x2 = x + random->nextInt(3) - 1; - y2 = y + random->nextInt(2) - random->nextInt(2); - z2 = z + random->nextInt(3) - 1; - } + if (level->isEmptyTile(x2, y2, z2) && canSurvive(level, x2, y2, z2)) + { + x = x2; + y = y2; + z = z2; + } + x2 = x + random->nextInt(3) - 1; + y2 = y + random->nextInt(2) - random->nextInt(2); + z2 = z + random->nextInt(3) - 1; + } - if (level->isEmptyTile(x2, y2, z2) && canSurvive(level, x2, y2, z2)) - { - level->setTile(x2, y2, z2, id); - } - } + if (level->isEmptyTile(x2, y2, z2) && canSurvive(level, x2, y2, z2)) + { + level->setTileAndData(x2, y2, z2, id, 0, UPDATE_CLIENTS); + } + } } bool Mushroom::mayPlace(Level *level, int x, int y, int z) @@ -68,40 +67,35 @@ bool Mushroom::canSurvive(Level *level, int x, int y, int z) { if (y < 0 || y >= Level::maxBuildHeight) return false; - int below = level->getTile(x, y - 1, z); + int below = level->getTile(x, y - 1, z); - return below == Tile::mycel_Id || (level->getDaytimeRawBrightness(x, y, z) < 13 && mayPlaceOn(below)); + return below == Tile::mycel_Id || (level->getDaytimeRawBrightness(x, y, z) < 13 && mayPlaceOn(below)); } bool Mushroom::growTree(Level *level, int x, int y, int z, Random *random) { - int data = level->getData(x, y, z); + int data = level->getData(x, y, z); - level->setTileNoUpdate(x, y, z, 0); - Feature *f = NULL; + level->removeTile(x, y, z); + Feature *f = NULL; - if (id == Tile::mushroom1_Id) + if (id == Tile::mushroom_brown_Id) { - f = new HugeMushroomFeature(0); - } - else if (id == Tile::mushroom2_Id) + f = new HugeMushroomFeature(0); + } + else if (id == Tile::mushroom_red_Id) { - f = new HugeMushroomFeature(1); - } + f = new HugeMushroomFeature(1); + } - if (f == NULL || !f->place(level, random, x, y, z)) + if (f == NULL || !f->place(level, random, x, y, z)) { - level->setTileAndDataNoUpdate(x, y, z, this->id, data); + level->setTileAndData(x, y, z, id, data, Tile::UPDATE_ALL); if( f != NULL ) delete f; - return false; - } + return false; + } if( f != NULL ) delete f; - return true; -} - -void Mushroom::registerIcons(IconRegister *iconRegister) -{ - icon = iconRegister->registerIcon(texture); -} + return true; +} \ No newline at end of file diff --git a/Minecraft.World/Mushroom.h b/Minecraft.World/Mushroom.h index 260ba048..65a3ea1d 100644 --- a/Minecraft.World/Mushroom.h +++ b/Minecraft.World/Mushroom.h @@ -6,12 +6,10 @@ class Random; class Mushroom : public Bush { friend class Tile; -private: - wstring texture; protected: - Mushroom(int id, const wstring &texture); + Mushroom(int id); public: - virtual void updateDefaultShape(); // 4J Added override + virtual void updateDefaultShape(); // 4J Added override virtual void tick(Level *level, int x, int y, int z, Random *random); virtual bool mayPlace(Level *level, int x, int y, int z); protected: @@ -19,5 +17,4 @@ protected: public: virtual bool canSurvive(Level *level, int x, int y, int z); bool growTree(Level *level, int x, int y, int z, Random *random); - void registerIcons(IconRegister *iconRegister); }; diff --git a/Minecraft.World/MushroomCow.cpp b/Minecraft.World/MushroomCow.cpp index a2aef158..0f88c843 100644 --- a/Minecraft.World/MushroomCow.cpp +++ b/Minecraft.World/MushroomCow.cpp @@ -13,14 +13,15 @@ MushroomCow::MushroomCow(Level *level) : Cow(level) { - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); + setHealth(getMaxHealth()); - this->textureIdx = TN_MOB_RED_COW;// 4J was "/mob/redcow.png"; this->setSize(0.9f, 1.3f); } -bool MushroomCow::interact(shared_ptr player) +bool MushroomCow::mobInteract(shared_ptr player) { shared_ptr item = player->inventory->getSelected(); if (item != NULL && item->id == Item::bowl_Id && getAge() >= 0) @@ -36,14 +37,14 @@ bool MushroomCow::interact(shared_ptr player) player->inventory->removeItem(player->inventory->selected, 1); return true; } - } - if (item != NULL && item->id == Item::shears_Id && getAge() >= 0) + } + // 4J: Do not allow shearing if we can't create more cows + if (item != NULL && item->id == Item::shears_Id && getAge() >= 0 && level->canCreateMore(eTYPE_COW, Level::eSpawnType_Breed)) { remove(); level->addParticle(eParticleType_largeexplode, x, y + bbHeight / 2, z, 0, 0, 0); if(!level->isClientSide) { - // 4J Stu - We don't need to check spawn limits when adding the new cow, as we are removing the MushroomCow remove(); shared_ptr cow = shared_ptr( new Cow(level) ); cow->moveTo(x, y, z, yRot, xRot); @@ -52,13 +53,13 @@ bool MushroomCow::interact(shared_ptr player) level->addEntity(cow); for (int i = 0; i < 5; i++) { - level->addEntity( shared_ptr( new ItemEntity(level, x, y + bbHeight, z, shared_ptr( new ItemInstance(Tile::mushroom2))) )); + level->addEntity( shared_ptr( new ItemEntity(level, x, y + bbHeight, z, shared_ptr( new ItemInstance(Tile::mushroom_red))) )); } - return true; + return true; } return true; } - return Cow::interact(player); + return Cow::mobInteract(player); } // 4J - added so that mushroom cows have more of a chance of spawning, they can now spawn on mycelium as well as grass - seems a bit odd that they don't already really diff --git a/Minecraft.World/MushroomCow.h b/Minecraft.World/MushroomCow.h index 4ec97476..fb87bc67 100644 --- a/Minecraft.World/MushroomCow.h +++ b/Minecraft.World/MushroomCow.h @@ -11,7 +11,7 @@ public: public: MushroomCow(Level *level); - virtual bool interact(shared_ptr player); + virtual bool mobInteract(shared_ptr player); virtual bool canSpawn(); // 4J added virtual shared_ptr getBreedOffspring(shared_ptr target); }; \ No newline at end of file diff --git a/Minecraft.World/MusicTileEntity.cpp b/Minecraft.World/MusicTileEntity.cpp index 4c2d2615..d947cc69 100644 --- a/Minecraft.World/MusicTileEntity.cpp +++ b/Minecraft.World/MusicTileEntity.cpp @@ -12,8 +12,8 @@ MusicTileEntity::MusicTileEntity() : TileEntity() { - note = 0; - + note = 0; + on = false; } @@ -49,7 +49,7 @@ void MusicTileEntity::playNote(Level *level, int x, int y, int z) if (m == Material::glass) i = 3; if (m == Material::wood) i = 4; - level->tileEvent(x, y, z, Tile::musicBlock_Id, i, note); + level->tileEvent(x, y, z, Tile::noteblock_Id, i, note); } // 4J Added diff --git a/Minecraft.World/MycelTile.cpp b/Minecraft.World/MycelTile.cpp index 7b8a90e1..875a598d 100644 --- a/Minecraft.World/MycelTile.cpp +++ b/Minecraft.World/MycelTile.cpp @@ -7,24 +7,24 @@ MycelTile::MycelTile(int id) : Tile(id, Material::grass) { iconTop = NULL; - iconSnowSide = NULL; - setTicking(true); + iconSnowSide = NULL; + setTicking(true); } Icon *MycelTile::getTexture(int face, int data) { - if (face == Facing::UP) return iconTop; - if (face == Facing::DOWN) return Tile::dirt->getTexture(face); - return icon; + if (face == Facing::UP) return iconTop; + if (face == Facing::DOWN) return Tile::dirt->getTexture(face); + return icon; } Icon *MycelTile::getTexture(LevelSource *level, int x, int y, int z, int face) { - if (face == Facing::UP) return iconTop; - if (face == Facing::DOWN) return Tile::dirt->getTexture(face); - Material *above = level->getMaterial(x, y + 1, z); - if (above == Material::topSnow || above == Material::snow) return iconSnowSide; - else return icon; + if (face == Facing::UP) return iconTop; + if (face == Facing::DOWN) return Tile::dirt->getTexture(face); + Material *above = level->getMaterial(x, y + 1, z); + if (above == Material::topSnow || above == Material::snow) return iconSnowSide; + else return icon; } void MycelTile::registerIcons(IconRegister *iconRegister) @@ -40,7 +40,7 @@ void MycelTile::tick(Level *level, int x, int y, int z, Random *random) if (level->getRawBrightness(x, y + 1, z) < MIN_BRIGHTNESS && Tile::lightBlock[level->getTile(x, y + 1, z)] > 2) { - level->setTile(x, y, z, Tile::dirt_Id); + level->setTileAndUpdate(x, y, z, Tile::dirt_Id); } else { @@ -54,7 +54,7 @@ void MycelTile::tick(Level *level, int x, int y, int z, Random *random) int above = level->getTile(xt, yt + 1, zt); if (level->getTile(xt, yt, zt) == Tile::dirt_Id && level->getRawBrightness(xt, yt + 1, zt) >= MIN_BRIGHTNESS && Tile::lightBlock[above] <= 2) { - level->setTile(xt, yt, zt, id); + level->setTileAndUpdate(xt, yt, zt, id); } } } @@ -63,8 +63,8 @@ void MycelTile::tick(Level *level, int x, int y, int z, Random *random) void MycelTile::animateTick(Level *level, int x, int y, int z, Random *random) { - Tile::animateTick(level, x, y, z, random); - if (random->nextInt(10) == 0) level->addParticle(eParticleType_townaura, x + random->nextFloat(), y + 1.1f, z + random->nextFloat(), 0, 0, 0); + Tile::animateTick(level, x, y, z, random); + if (random->nextInt(10) == 0) level->addParticle(eParticleType_townaura, x + random->nextFloat(), y + 1.1f, z + random->nextFloat(), 0, 0, 0); } diff --git a/Minecraft.World/NameTagItem.cpp b/Minecraft.World/NameTagItem.cpp new file mode 100644 index 00000000..9c11f2af --- /dev/null +++ b/Minecraft.World/NameTagItem.cpp @@ -0,0 +1,23 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "NameTagItem.h" + +NameTagItem::NameTagItem(int id) : Item(id) +{ +} + +bool NameTagItem::interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr target) +{ + if (!itemInstance->hasCustomHoverName()) return false; + + if ( (target != NULL) && target->instanceof(eTYPE_MOB) ) + { + shared_ptr mob = dynamic_pointer_cast(target); + mob->setCustomName(itemInstance->getHoverName()); + mob->setPersistenceRequired(); + itemInstance->count--; + return true; + } + + return Item::interactEnemy(itemInstance, player, target); +} \ No newline at end of file diff --git a/Minecraft.World/NameTagItem.h b/Minecraft.World/NameTagItem.h new file mode 100644 index 00000000..d0aa32e4 --- /dev/null +++ b/Minecraft.World/NameTagItem.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Item.h" + +class NameTagItem : public Item +{ +public: + NameTagItem(int id); + + bool interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr target); +}; \ No newline at end of file diff --git a/Minecraft.World/NearestAttackableTargetGoal.cpp b/Minecraft.World/NearestAttackableTargetGoal.cpp index 5ed9f4f1..1dbf587e 100644 --- a/Minecraft.World/NearestAttackableTargetGoal.cpp +++ b/Minecraft.World/NearestAttackableTargetGoal.cpp @@ -4,6 +4,24 @@ #include "net.minecraft.world.phys.h" #include "NearestAttackableTargetGoal.h" +SubselectEntitySelector::SubselectEntitySelector(NearestAttackableTargetGoal *parent, EntitySelector *subselector) +{ + m_parent = parent; + m_subselector = subselector; +} + +SubselectEntitySelector::~SubselectEntitySelector() +{ + delete m_subselector; +} + +bool SubselectEntitySelector::matches(shared_ptr entity) const +{ + if (!entity->instanceof(eTYPE_LIVINGENTITY)) return false; + if (m_subselector != NULL && !m_subselector->matches(entity)) return false; + return m_parent->canAttack(dynamic_pointer_cast(entity), false); +} + NearestAttackableTargetGoal::DistComp::DistComp(Entity *source) { this->source = source; @@ -19,49 +37,39 @@ bool NearestAttackableTargetGoal::DistComp::operator() (shared_ptr e1, s return true; } -NearestAttackableTargetGoal::NearestAttackableTargetGoal(Mob *mob, const type_info& targetType, float within, int randomInterval, bool mustSee, bool mustReach /*= false*/) : TargetGoal(mob, within, mustSee, mustReach), targetType(targetType) +NearestAttackableTargetGoal::NearestAttackableTargetGoal(PathfinderMob *mob, const type_info& targetType, int randomInterval, bool mustSee, bool mustReach /*= false*/, EntitySelector *entitySelector /* =NULL */) + : TargetGoal(mob, mustSee, mustReach), targetType(targetType) { - //this->targetType = targetType; - this->within = within; this->randomInterval = randomInterval; this->distComp = new DistComp(mob); setRequiredControlFlags(TargetGoal::TargetFlag); + + this->selector = new SubselectEntitySelector(this, entitySelector); } NearestAttackableTargetGoal::~NearestAttackableTargetGoal() { delete distComp; + delete selector; } bool NearestAttackableTargetGoal::canUse() { if (randomInterval > 0 && mob->getRandom()->nextInt(randomInterval) != 0) return false; - if (targetType == typeid(Player)) - { - shared_ptr potentialTarget = mob->level->getNearestAttackablePlayer(mob->shared_from_this(), within); - if (canAttack(potentialTarget, false)) - { - target = weak_ptr(potentialTarget); - return true; - } - } - else + double within = getFollowDistance(); + + vector > *entities = mob->level->getEntitiesOfClass(targetType, mob->bb->grow(within, 4, within), selector); + + bool result = false; + if(entities != NULL && !entities->empty() ) { - vector > *entities = mob->level->getEntitiesOfClass(targetType, mob->bb->grow(within, 4, within)); - //Collections.sort(entities, distComp); std::sort(entities->begin(), entities->end(), *distComp); - for(AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) - { - shared_ptr potTarget = dynamic_pointer_cast(*it); - if (canAttack(potTarget, false)) - { - target = weak_ptr(potTarget); - return true; - } - } - delete entities; + target = weak_ptr(dynamic_pointer_cast(entities->at(0))); + result = true; } - return false; + + delete entities; + return result; } void NearestAttackableTargetGoal::start() diff --git a/Minecraft.World/NearestAttackableTargetGoal.h b/Minecraft.World/NearestAttackableTargetGoal.h index a10e9264..1ba6c519 100644 --- a/Minecraft.World/NearestAttackableTargetGoal.h +++ b/Minecraft.World/NearestAttackableTargetGoal.h @@ -1,9 +1,26 @@ #pragma once #include "TargetGoal.h" +#include "EntitySelector.h" + +class NearestAttackableTargetGoal; + +// Anonymous class from NearestAttackableTargetGoal +class SubselectEntitySelector : public EntitySelector +{ +private: + EntitySelector *m_subselector; + NearestAttackableTargetGoal *m_parent; + +public: + SubselectEntitySelector(NearestAttackableTargetGoal *parent, EntitySelector *subselector); + ~SubselectEntitySelector(); + bool matches(shared_ptr entity) const; +}; class NearestAttackableTargetGoal : public TargetGoal { + friend class SubselectEntitySelector; public: class DistComp { @@ -17,18 +34,15 @@ public: }; private: - weak_ptr target; const type_info& targetType; int randomInterval; DistComp *distComp; + EntitySelector *selector; + weak_ptr target; public: - //public NearestAttackableTargetGoal(Mob mob, const type_info& targetType, float within, int randomInterval, bool mustSee) - //{ - // this(mob, targetType, within, randomInterval, mustSee, false); - //} + NearestAttackableTargetGoal(PathfinderMob *mob, const type_info& targetType, int randomInterval, bool mustSee, bool mustReach = false, EntitySelector *entitySelector = NULL); - NearestAttackableTargetGoal(Mob *mob, const type_info& targetType, float within, int randomInterval, bool mustSee, bool mustReach = false); virtual ~NearestAttackableTargetGoal(); virtual bool canUse(); diff --git a/Minecraft.World/NetherBridgeFeature.cpp b/Minecraft.World/NetherBridgeFeature.cpp index b8308af7..2cf883c4 100644 --- a/Minecraft.World/NetherBridgeFeature.cpp +++ b/Minecraft.World/NetherBridgeFeature.cpp @@ -10,9 +10,10 @@ NetherBridgeFeature::NetherBridgeFeature() : StructureFeature() { - bridgeEnemies.push_back(new Biome::MobSpawnerData(eTYPE_BLAZE, 10, 2, 3)); - bridgeEnemies.push_back(new Biome::MobSpawnerData(eTYPE_PIGZOMBIE, 10, 4, 4)); - bridgeEnemies.push_back(new Biome::MobSpawnerData(eTYPE_LAVASLIME, 3, 4, 4)); + bridgeEnemies.push_back(new Biome::MobSpawnerData(eTYPE_BLAZE, 10, 2, 3)); + bridgeEnemies.push_back(new Biome::MobSpawnerData(eTYPE_PIGZOMBIE, 5, 4, 4)); + bridgeEnemies.push_back(new Biome::MobSpawnerData(eTYPE_SKELETON, 10, 4, 4)); + bridgeEnemies.push_back(new Biome::MobSpawnerData(eTYPE_LAVASLIME, 3, 4, 4)); isSpotSelected=false; netherFortressPos = NULL; @@ -23,6 +24,11 @@ NetherBridgeFeature::~NetherBridgeFeature() if( netherFortressPos != NULL ) delete netherFortressPos; } +wstring NetherBridgeFeature::getFeatureName() +{ + return L"Fortress"; +} + vector *NetherBridgeFeature::getBridgeEnemies() { return &bridgeEnemies; @@ -48,7 +54,7 @@ bool NetherBridgeFeature::isFeatureChunk(int x, int z, bool bIsSuperflat) isSpotSelected = true; } - + bool forcePlacement = false; LevelGenerationOptions *levelGenOptions = app.getLevelGenerationOptions(); if( levelGenOptions != NULL ) @@ -57,7 +63,7 @@ bool NetherBridgeFeature::isFeatureChunk(int x, int z, bool bIsSuperflat) } if(forcePlacement || (x == netherFortressPos->x && z == netherFortressPos->z) ) return true; - + #ifdef _LARGE_WORLDS int xzSize = level->dimension->getXZSize(); if(xzSize > 30) @@ -90,7 +96,7 @@ bool NetherBridgeFeature::isFeatureChunk(int x, int z, bool bIsSuperflat) StructureStart *NetherBridgeFeature::createStructureStart(int x, int z) { - return new NetherBridgeStart(level, random, x, z); + return new NetherBridgeStart(level, random, x, z); } void NetherBridgeFeature::clearCachedBuildings() @@ -98,22 +104,27 @@ void NetherBridgeFeature::clearCachedBuildings() cachedStructures.clear(); } -NetherBridgeFeature::NetherBridgeStart::NetherBridgeStart(Level *level, Random *random, int chunkX, int chunkZ) : StructureStart() +NetherBridgeFeature::NetherBridgeStart::NetherBridgeStart() { - NetherBridgePieces::StartPiece *start = new NetherBridgePieces::StartPiece(random, (chunkX << 4) + 2, (chunkZ << 4) + 2, level); - pieces.push_back(start); - start->addChildren(start, &pieces, random); + // for reflection +} + +NetherBridgeFeature::NetherBridgeStart::NetherBridgeStart(Level *level, Random *random, int chunkX, int chunkZ) : StructureStart(chunkX, chunkZ) +{ + NetherBridgePieces::StartPiece *start = new NetherBridgePieces::StartPiece(random, (chunkX << 4) + 2, (chunkZ << 4) + 2, level); + pieces.push_back(start); + start->addChildren(start, &pieces, random); - vector *pendingChildren = &start->pendingChildren; - while (!pendingChildren->empty()) + vector *pendingChildren = &start->pendingChildren; + while (!pendingChildren->empty()) { - int pos = random->nextInt((int)pendingChildren->size()); + int pos = random->nextInt((int)pendingChildren->size()); AUTO_VAR(it, pendingChildren->begin() + pos); - StructurePiece *structurePiece = *it; + StructurePiece *structurePiece = *it; pendingChildren->erase(it); - structurePiece->addChildren(start, &pieces, random); - } + structurePiece->addChildren(start, &pieces, random); + } - calculateBoundingBox(); - moveInsideHeights(level, random, 48, 70); + calculateBoundingBox(); + moveInsideHeights(level, random, 48, 70); } diff --git a/Minecraft.World/NetherBridgeFeature.h b/Minecraft.World/NetherBridgeFeature.h index cd7f315f..2fd1701a 100644 --- a/Minecraft.World/NetherBridgeFeature.h +++ b/Minecraft.World/NetherBridgeFeature.h @@ -15,16 +15,22 @@ private: public: NetherBridgeFeature(); ~NetherBridgeFeature(); - vector *getBridgeEnemies(); + wstring getFeatureName(); + vector *getBridgeEnemies(); protected: virtual bool isFeatureChunk(int x, int z, bool bIsSuperflat); - virtual StructureStart *createStructureStart(int x, int z); + virtual StructureStart *createStructureStart(int x, int z); public: void clearCachedBuildings(); -private: + class NetherBridgeStart : public StructureStart { +public: + static StructureStart *Create() { return new NetherBridgeStart(); } + virtual EStructureStart GetType() { return eStructureStart_NetherBridgeStart; } + public: + NetherBridgeStart(); NetherBridgeStart(Level *level, Random *random, int chunkX, int chunkZ); - }; + }; }; diff --git a/Minecraft.World/NetherBridgePieces.cpp b/Minecraft.World/NetherBridgePieces.cpp index 9a795e78..ff158fba 100644 --- a/Minecraft.World/NetherBridgePieces.cpp +++ b/Minecraft.World/NetherBridgePieces.cpp @@ -1,12 +1,34 @@ #include "stdafx.h" +#include "net.minecraft.world.item.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.tile.entity.h" #include "net.minecraft.world.level.levelgen.h" #include "net.minecraft.world.level.storage.h" +#include "net.minecraft.world.level.levelgen.structure.h" +#include "WeighedTreasure.h" #include "NetherBridgePieces.h" #include "Direction.h" +void NetherBridgePieces::loadStatic() +{ + StructureFeatureIO::setPieceId( eStructurePiece_BridgeCrossing, BridgeCrossing::Create, L"NeBCr"); + StructureFeatureIO::setPieceId( eStructurePiece_BridgeEndFiller, BridgeEndFiller::Create, L"NeBEF"); + StructureFeatureIO::setPieceId( eStructurePiece_BridgeStraight, BridgeStraight::Create, L"NeBS"); + StructureFeatureIO::setPieceId( eStructurePiece_CastleCorridorStairsPiece, CastleCorridorStairsPiece::Create, L"NeCCS"); + StructureFeatureIO::setPieceId( eStructurePiece_CastleCorridorTBalconyPiece, CastleCorridorTBalconyPiece::Create, L"NeCTB"); + StructureFeatureIO::setPieceId( eStructurePiece_CastleEntrance, CastleEntrance::Create, L"NeCE"); + StructureFeatureIO::setPieceId( eStructurePiece_CastleSmallCorridorCrossingPiece, CastleSmallCorridorCrossingPiece::Create, L"NeSCSC"); + StructureFeatureIO::setPieceId( eStructurePiece_CastleSmallCorridorLeftTurnPiece, CastleSmallCorridorLeftTurnPiece::Create, L"NeSCLT"); + StructureFeatureIO::setPieceId( eStructurePiece_CastleSmallCorridorPiece, CastleSmallCorridorPiece::Create, L"NeSC"); + StructureFeatureIO::setPieceId( eStructurePiece_CastleSmallCorridorRightTurnPiece, CastleSmallCorridorRightTurnPiece::Create, L"NeSCRT"); + StructureFeatureIO::setPieceId( eStructurePiece_CastleStalkRoom, CastleStalkRoom::Create, L"NeCSR"); + StructureFeatureIO::setPieceId( eStructurePiece_MonsterThrone, MonsterThrone::Create, L"NeMT"); + StructureFeatureIO::setPieceId( eStructurePiece_RoomCrossing, RoomCrossing::Create, L"NeRC"); + StructureFeatureIO::setPieceId( eStructurePiece_StairsRoom, StairsRoom::Create, L"NeSR"); + StructureFeatureIO::setPieceId( eStructurePiece_NetherBridgeStartPiece, StartPiece::Create, L"NeStart"); +} + NetherBridgePieces::PieceWeight::PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount, bool allowInRow) : weight(weight) { this->placeCount = 0; @@ -114,10 +136,37 @@ NetherBridgePieces::NetherBridgePiece *NetherBridgePieces::findAndCreateBridgePi return structurePiece; } +WeighedTreasure *NetherBridgePieces::NetherBridgePiece::fortressTreasureItems[FORTRESS_TREASURE_ITEMS_COUNT] = { + new WeighedTreasure(Item::diamond_Id, 0, 1, 3, 5), + new WeighedTreasure(Item::ironIngot_Id, 0, 1, 5, 5), + new WeighedTreasure(Item::goldIngot_Id, 0, 1, 3, 15), + new WeighedTreasure(Item::sword_gold_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::chestplate_gold_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::flintAndSteel_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::netherwart_seeds_Id, 0, 3, 7, 5), + new WeighedTreasure(Item::saddle_Id, 0, 1, 1, 10), + new WeighedTreasure(Item::horseArmorGold_Id, 0, 1, 1, 8), + new WeighedTreasure(Item::horseArmorMetal_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::horseArmorDiamond_Id, 0, 1, 1, 3), +}; + +NetherBridgePieces::NetherBridgePiece::NetherBridgePiece() +{ + // for reflection +} + NetherBridgePieces::NetherBridgePiece::NetherBridgePiece(int genDepth) : StructurePiece(genDepth) { } +void NetherBridgePieces::NetherBridgePiece::readAdditonalSaveData(CompoundTag *tag) +{ +} + +void NetherBridgePieces::NetherBridgePiece::addAdditonalSaveData(CompoundTag *tag) +{ +} + int NetherBridgePieces::NetherBridgePiece::updatePieceWeight(list *currentPieces) { bool hasAnyPieces = false; @@ -280,12 +329,12 @@ void NetherBridgePieces::NetherBridgePiece::generateLightPost(Level *level, Rand if (level->isEmptyTile(worldX, worldY, worldZ) && level->isEmptyTile(worldX, worldY + 1, worldZ) && level->isEmptyTile(worldX, worldY + 2, worldZ) && level->isEmptyTile(worldX, worldY + 3, worldZ)) { - level->setTileAndDataNoUpdate(worldX, worldY, worldZ, Tile::netherFence_Id, 0); - level->setTileAndDataNoUpdate(worldX, worldY + 1, worldZ, Tile::netherFence_Id, 0); - level->setTileAndDataNoUpdate(worldX, worldY + 2, worldZ, Tile::netherFence_Id, 0); - level->setTileAndDataNoUpdate(worldX, worldY + 3, worldZ, Tile::netherFence_Id, 0); + level->setTileAndData(worldX, worldY, worldZ, Tile::netherFence_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(worldX, worldY + 1, worldZ, Tile::netherFence_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(worldX, worldY + 2, worldZ, Tile::netherFence_Id, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(worldX, worldY + 3, worldZ, Tile::netherFence_Id, 0, Tile::UPDATE_CLIENTS); placeBlock(level, Tile::netherFence_Id, 0, x + xOff, y + 3, z + zOff, chunkBB); - placeBlock(level, Tile::lightGem_Id, 0, x + xOff, y + 2, z + zOff, chunkBB); + placeBlock(level, Tile::glowstone_Id, 0, x + xOff, y + 2, z + zOff, chunkBB); } } @@ -309,6 +358,10 @@ void NetherBridgePieces::NetherBridgePiece::generateLightPostFacingDown(Level *l generateLightPost(level, random, chunkBB, x, y, z, 0, -1); } +NetherBridgePieces::BridgeStraight::BridgeStraight() +{ + // for reflection +} NetherBridgePieces::BridgeStraight::BridgeStraight(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { @@ -328,7 +381,7 @@ NetherBridgePieces::BridgeStraight *NetherBridgePieces::BridgeStraight::createPi StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -375,6 +428,11 @@ bool NetherBridgePieces::BridgeStraight::postProcess(Level *level, Random *rando return true; } +NetherBridgePieces::BridgeEndFiller::BridgeEndFiller() +{ + // for reflection +} + NetherBridgePieces::BridgeEndFiller::BridgeEndFiller(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { orientation = direction; @@ -389,7 +447,7 @@ NetherBridgePieces::BridgeEndFiller *NetherBridgePieces::BridgeEndFiller::create StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -442,6 +500,25 @@ bool NetherBridgePieces::BridgeEndFiller::postProcess(Level *level, Random *rand return true; } +void NetherBridgePieces::BridgeEndFiller::readAdditonalSaveData(CompoundTag *tag) +{ + NetherBridgePiece::readAdditonalSaveData(tag); + + selfSeed = tag->getInt(L"Seed"); +} + +void NetherBridgePieces::BridgeEndFiller::addAdditonalSaveData(CompoundTag *tag) +{ + NetherBridgePiece::addAdditonalSaveData(tag); + + tag->putInt(L"Seed", selfSeed); +} + +NetherBridgePieces::BridgeCrossing::BridgeCrossing() +{ + // for reflection +} + NetherBridgePieces::BridgeCrossing::BridgeCrossing(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { orientation = direction; @@ -478,7 +555,7 @@ NetherBridgePieces::BridgeCrossing *NetherBridgePieces::BridgeCrossing::createPi StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -535,10 +612,14 @@ bool NetherBridgePieces::BridgeCrossing::postProcess(Level *level, Random *rando return true; } +NetherBridgePieces::StartPiece::StartPiece() +{ + // for reflection + previousPiece = NULL; +} NetherBridgePieces::StartPiece::StartPiece(Random *random, int west, int north, Level *level) : BridgeCrossing(random, west, north) { - isLibraryAdded = false; previousPiece = NULL; m_level = level; @@ -558,6 +639,20 @@ NetherBridgePieces::StartPiece::StartPiece(Random *random, int west, int north, } } +void NetherBridgePieces::StartPiece::readAdditonalSaveData(CompoundTag *tag) +{ + BridgeCrossing::readAdditonalSaveData(tag); +} + +void NetherBridgePieces::StartPiece::addAdditonalSaveData(CompoundTag *tag) +{ + BridgeCrossing::addAdditonalSaveData(tag); +} + +NetherBridgePieces::RoomCrossing::RoomCrossing() +{ + // for reflection +} NetherBridgePieces::RoomCrossing::RoomCrossing(int genDepth, Random *random, BoundingBox *box, int direction) : NetherBridgePiece(genDepth) { @@ -579,7 +674,7 @@ NetherBridgePieces::RoomCrossing *NetherBridgePieces::RoomCrossing::createPiece( StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -626,6 +721,11 @@ bool NetherBridgePieces::RoomCrossing::postProcess(Level *level, Random *random, return true; } +NetherBridgePieces::StairsRoom::StairsRoom() +{ + // for reflection +} + NetherBridgePieces::StairsRoom::StairsRoom(int genDepth, Random *random, BoundingBox *box, int direction) : NetherBridgePiece(genDepth) { orientation = direction; @@ -644,7 +744,7 @@ NetherBridgePieces::StairsRoom *NetherBridgePieces::StairsRoom::createPiece(list StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -699,6 +799,10 @@ bool NetherBridgePieces::StairsRoom::postProcess(Level *level, Random *random, B } +NetherBridgePieces::MonsterThrone::MonsterThrone() +{ + // for reflection +} NetherBridgePieces::MonsterThrone::MonsterThrone(int genDepth, Random *random, BoundingBox *box, int direction) : NetherBridgePiece(genDepth) { @@ -714,7 +818,7 @@ NetherBridgePieces::MonsterThrone *NetherBridgePieces::MonsterThrone::createPiec StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -723,6 +827,20 @@ NetherBridgePieces::MonsterThrone *NetherBridgePieces::MonsterThrone::createPiec return new MonsterThrone(genDepth, random, box, direction); } +void NetherBridgePieces::MonsterThrone::readAdditonalSaveData(CompoundTag *tag) +{ + NetherBridgePiece::readAdditonalSaveData(tag); + + hasPlacedMobSpawner = tag->getBoolean(L"Mob"); +} + +void NetherBridgePieces::MonsterThrone::addAdditonalSaveData(CompoundTag *tag) +{ + NetherBridgePiece::addAdditonalSaveData(tag); + + tag->putBoolean(L"Mob", hasPlacedMobSpawner); +} + bool NetherBridgePieces::MonsterThrone::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { generateBox(level, chunkBB, 0, 2, 0, 6, 7, 7, 0, 0, false); @@ -756,9 +874,9 @@ bool NetherBridgePieces::MonsterThrone::postProcess(Level *level, Random *random if (chunkBB->isInside(x, y, z)) { hasPlacedMobSpawner = true; - level->setTile(x, y, z, Tile::mobSpawner_Id); + level->setTileAndData(x, y, z, Tile::mobSpawner_Id, 0, Tile::UPDATE_CLIENTS); shared_ptr entity = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); - if (entity != NULL) entity->setEntityId(L"Blaze"); + if (entity != NULL) entity->getSpawner()->setEntityId(L"Blaze"); } } @@ -773,6 +891,10 @@ bool NetherBridgePieces::MonsterThrone::postProcess(Level *level, Random *random return true; } +NetherBridgePieces::CastleEntrance::CastleEntrance() +{ + // for reflection +} NetherBridgePieces::CastleEntrance::CastleEntrance(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { @@ -792,7 +914,7 @@ NetherBridgePieces::CastleEntrance *NetherBridgePieces::CastleEntrance::createPi StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -898,6 +1020,10 @@ bool NetherBridgePieces::CastleEntrance::postProcess(Level *level, Random *rando return true; } +NetherBridgePieces::CastleStalkRoom::CastleStalkRoom() +{ + // for reflection +} NetherBridgePieces::CastleStalkRoom::CastleStalkRoom(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { @@ -918,7 +1044,7 @@ NetherBridgePieces::CastleStalkRoom *NetherBridgePieces::CastleStalkRoom::create StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -1024,8 +1150,8 @@ bool NetherBridgePieces::CastleStalkRoom::postProcess(Level *level, Random *rand placeBlock(level, Tile::stairs_netherBricks_Id, eastOrientation, 8, 5, 10, chunkBB); // farmlands - generateBox(level, chunkBB, 3, 4, 4, 4, 4, 8, Tile::hellSand_Id, Tile::hellSand_Id, false); - generateBox(level, chunkBB, 8, 4, 4, 9, 4, 8, Tile::hellSand_Id, Tile::hellSand_Id, false); + generateBox(level, chunkBB, 3, 4, 4, 4, 4, 8, Tile::soulsand_Id, Tile::soulsand_Id, false); + generateBox(level, chunkBB, 8, 4, 4, 9, 4, 8, Tile::soulsand_Id, Tile::soulsand_Id, false); generateBox(level, chunkBB, 3, 5, 4, 4, 5, 8, Tile::netherStalk_Id, Tile::netherStalk_Id, false); generateBox(level, chunkBB, 8, 5, 4, 9, 5, 8, Tile::netherStalk_Id, Tile::netherStalk_Id, false); @@ -1059,6 +1185,10 @@ bool NetherBridgePieces::CastleStalkRoom::postProcess(Level *level, Random *rand } +NetherBridgePieces::CastleSmallCorridorPiece::CastleSmallCorridorPiece() +{ + // for reflection +} NetherBridgePieces::CastleSmallCorridorPiece::CastleSmallCorridorPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { @@ -1080,7 +1210,7 @@ NetherBridgePieces::CastleSmallCorridorPiece *NetherBridgePieces::CastleSmallCor StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -1119,6 +1249,10 @@ bool NetherBridgePieces::CastleSmallCorridorPiece::postProcess(Level *level, Ran return true; } +NetherBridgePieces::CastleSmallCorridorCrossingPiece::CastleSmallCorridorCrossingPiece() +{ + // for reflection +} NetherBridgePieces::CastleSmallCorridorCrossingPiece::CastleSmallCorridorCrossingPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { @@ -1140,7 +1274,7 @@ NetherBridgePieces::CastleSmallCorridorCrossingPiece *NetherBridgePieces::Castle StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -1177,11 +1311,31 @@ bool NetherBridgePieces::CastleSmallCorridorCrossingPiece::postProcess(Level *le return true; } +NetherBridgePieces::CastleSmallCorridorRightTurnPiece::CastleSmallCorridorRightTurnPiece() +{ + // for reflection + isNeedingChest = false; +} NetherBridgePieces::CastleSmallCorridorRightTurnPiece::CastleSmallCorridorRightTurnPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { orientation = direction; boundingBox = stairsBox; + isNeedingChest = random->nextInt(3) == 0; +} + +void NetherBridgePieces::CastleSmallCorridorRightTurnPiece::readAdditonalSaveData(CompoundTag *tag) +{ + NetherBridgePiece::readAdditonalSaveData(tag); + + isNeedingChest = tag->getBoolean(L"Chest"); +} + +void NetherBridgePieces::CastleSmallCorridorRightTurnPiece::addAdditonalSaveData(CompoundTag *tag) +{ + NetherBridgePiece::addAdditonalSaveData(tag); + + tag->putBoolean(L"Chest", isNeedingChest); } void NetherBridgePieces::CastleSmallCorridorRightTurnPiece::addChildren(StructurePiece *startPiece, list *pieces, Random *random) @@ -1196,7 +1350,7 @@ NetherBridgePieces::CastleSmallCorridorRightTurnPiece *NetherBridgePieces::Castl StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -1223,6 +1377,17 @@ bool NetherBridgePieces::CastleSmallCorridorRightTurnPiece::postProcess(Level *l generateBox(level, chunkBB, 1, 3, 4, 1, 4, 4, Tile::netherFence_Id, Tile::netherBrick_Id, false); generateBox(level, chunkBB, 3, 3, 4, 3, 4, 4, Tile::netherFence_Id, Tile::netherBrick_Id, false); + if (isNeedingChest) + { + int y = getWorldY(2); + int x = getWorldX(1, 3), z = getWorldZ(1, 3); + if (chunkBB->isInside(x, y, z)) + { + isNeedingChest = false; + createChest(level, chunkBB, random, 1, 2, 3, WeighedTreasureArray(fortressTreasureItems,FORTRESS_TREASURE_ITEMS_COUNT), 2 + random->nextInt(4)); + } + } + // roof generateBox(level, chunkBB, 0, 6, 0, 4, 6, 4, Tile::netherBrick_Id, Tile::netherBrick_Id, false); @@ -1238,11 +1403,31 @@ bool NetherBridgePieces::CastleSmallCorridorRightTurnPiece::postProcess(Level *l return true; } +NetherBridgePieces::CastleSmallCorridorLeftTurnPiece::CastleSmallCorridorLeftTurnPiece() +{ + isNeedingChest = false; + // for reflection +} NetherBridgePieces::CastleSmallCorridorLeftTurnPiece::CastleSmallCorridorLeftTurnPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { orientation = direction; boundingBox = stairsBox; + isNeedingChest = random->nextInt(3) == 0; +} + +void NetherBridgePieces::CastleSmallCorridorLeftTurnPiece::readAdditonalSaveData(CompoundTag *tag) +{ + NetherBridgePiece::readAdditonalSaveData(tag); + + isNeedingChest = tag->getBoolean(L"Chest"); +} + +void NetherBridgePieces::CastleSmallCorridorLeftTurnPiece::addAdditonalSaveData(CompoundTag *tag) +{ + NetherBridgePiece::addAdditonalSaveData(tag); + + tag->putBoolean(L"Chest", isNeedingChest); } void NetherBridgePieces::CastleSmallCorridorLeftTurnPiece::addChildren(StructurePiece *startPiece, list *pieces, Random *random) @@ -1257,7 +1442,7 @@ NetherBridgePieces::CastleSmallCorridorLeftTurnPiece *NetherBridgePieces::Castle StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -1284,6 +1469,17 @@ bool NetherBridgePieces::CastleSmallCorridorLeftTurnPiece::postProcess(Level *le generateBox(level, chunkBB, 1, 3, 4, 1, 4, 4, Tile::netherFence_Id, Tile::netherBrick_Id, false); generateBox(level, chunkBB, 3, 3, 4, 3, 4, 4, Tile::netherFence_Id, Tile::netherBrick_Id, false); + if (isNeedingChest) + { + int y = getWorldY(2); + int x = getWorldX(3, 3), z = getWorldZ(3, 3); + if (chunkBB->isInside(x, y, z)) + { + isNeedingChest = false; + createChest(level, chunkBB, random, 3, 2, 3, WeighedTreasureArray(fortressTreasureItems,FORTRESS_TREASURE_ITEMS_COUNT), 2 + random->nextInt(4)); + } + } + // roof generateBox(level, chunkBB, 0, 6, 0, 4, 6, 4, Tile::netherBrick_Id, Tile::netherBrick_Id, false); @@ -1299,6 +1495,10 @@ bool NetherBridgePieces::CastleSmallCorridorLeftTurnPiece::postProcess(Level *le return true; } +NetherBridgePieces::CastleCorridorStairsPiece::CastleCorridorStairsPiece() +{ + // for reflection +} NetherBridgePieces::CastleCorridorStairsPiece::CastleCorridorStairsPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { @@ -1318,7 +1518,7 @@ NetherBridgePieces::CastleCorridorStairsPiece *NetherBridgePieces::CastleCorrido StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; @@ -1369,6 +1569,10 @@ bool NetherBridgePieces::CastleCorridorStairsPiece::postProcess(Level *level, Ra return true; } +NetherBridgePieces::CastleCorridorTBalconyPiece::CastleCorridorTBalconyPiece() +{ + // for reflection +} NetherBridgePieces::CastleCorridorTBalconyPiece::CastleCorridorTBalconyPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : NetherBridgePiece(genDepth) { @@ -1396,7 +1600,7 @@ NetherBridgePieces::CastleCorridorTBalconyPiece *NetherBridgePieces::CastleCorri StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((NetherBridgePieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; return NULL; diff --git a/Minecraft.World/NetherBridgePieces.h b/Minecraft.World/NetherBridgePieces.h index 47d2ca67..81cb1560 100644 --- a/Minecraft.World/NetherBridgePieces.h +++ b/Minecraft.World/NetherBridgePieces.h @@ -5,8 +5,8 @@ class NetherBridgePieces { private: static const int MAX_DEPTH = 30; - // the dungeon starts at 64 and traverses downwards to this point - static const int LOWEST_Y_POSITION = 10; + // the dungeon starts at 64 and traverses downwards to this point + static const int LOWEST_Y_POSITION = 10; // 4J - added to replace use of Class within this class enum EPieceClass @@ -27,317 +27,433 @@ private: EPieceClass_CastleCorridorTBalconyPiece }; - class PieceWeight +public: + static void loadStatic(); + +private: + class PieceWeight { public: - EPieceClass pieceClass; - const int weight; - int placeCount; - int maxPlaceCount; - bool allowInRow; - - PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount, bool allowInRow); - PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount); - bool doPlace(int depth); - bool isValid(); - }; + EPieceClass pieceClass; + const int weight; + int placeCount; + int maxPlaceCount; + bool allowInRow; + + PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount, bool allowInRow); + PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount); + bool doPlace(int depth); + bool isValid(); + }; static const int BRIDGE_PIECEWEIGHTS_COUNT = 6; static const int CASTLE_PIECEWEIGHTS_COUNT = 7; - static NetherBridgePieces::PieceWeight *bridgePieceWeights[BRIDGE_PIECEWEIGHTS_COUNT]; + static NetherBridgePieces::PieceWeight *bridgePieceWeights[BRIDGE_PIECEWEIGHTS_COUNT]; static NetherBridgePieces::PieceWeight *castlePieceWeights[CASTLE_PIECEWEIGHTS_COUNT]; private: class NetherBridgePiece; static NetherBridgePiece *findAndCreateBridgePieceFactory(NetherBridgePieces::PieceWeight *piece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth); - /** - * - * - */ + /** + * + * + */ public: class StartPiece; private: - class NetherBridgePiece : public StructurePiece + class NetherBridgePiece : public StructurePiece { - protected: - NetherBridgePiece(int genDepth); + protected: + static const int FORTRESS_TREASURE_ITEMS_COUNT = 11; + static WeighedTreasure *fortressTreasureItems[FORTRESS_TREASURE_ITEMS_COUNT]; + + public: + NetherBridgePiece(); + + protected: + NetherBridgePiece(int genDepth); + + virtual void readAdditonalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *tag); + private: int updatePieceWeight(list *currentPieces); - NetherBridgePiece *generatePiece(StartPiece *startPiece, list *currentPieces, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth); - StructurePiece *generateAndAddPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth, bool isCastle); + NetherBridgePiece *generatePiece(StartPiece *startPiece, list *currentPieces, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth); + StructurePiece *generateAndAddPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth, bool isCastle); protected: StructurePiece *generateChildForward(StartPiece *startPiece, list *pieces, Random *random, int xOff, int yOff, bool isCastle); StructurePiece *generateChildLeft(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff, bool isCastle); StructurePiece *generateChildRight(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff, bool isCastle); - + static bool isOkBox(BoundingBox *box, StartPiece *startRoom); // 4J added startRoom param void generateLightPost(Level *level, Random *random, BoundingBox *chunkBB, int x, int y, int z, int xOff, int zOff); - + void generateLightPostFacingRight(Level *level, Random *random, BoundingBox *chunkBB, int x, int y, int z); void generateLightPostFacingLeft(Level *level, Random *random, BoundingBox *chunkBB, int x, int y, int z); void generateLightPostFacingUp(Level *level, Random *random, BoundingBox *chunkBB, int x, int y, int z); void generateLightPostFacingDown(Level *level, Random *random, BoundingBox *chunkBB, int x, int y, int z); - }; + }; - /** - * - * - */ + /** + * + * + */ class BridgeStraight : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new BridgeStraight(); } + virtual EStructurePiece GetType() { return eStructurePiece_BridgeStraight; } + private: static const int width = 5; - static const int height = 10; - static const int depth = 19; + static const int height = 10; + static const int depth = 19; public: + BridgeStraight(); BridgeStraight(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static BridgeStraight *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static BridgeStraight *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; - class BridgeEndFiller : public NetherBridgePiece + class BridgeEndFiller : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new BridgeEndFiller(); } + virtual EStructurePiece GetType() { return eStructurePiece_BridgeEndFiller; } + private: static const int width = 5; - static const int height = 10; - static const int depth = 8; + static const int height = 10; + static const int depth = 8; - int selfSeed; + int selfSeed; public: + BridgeEndFiller(); BridgeEndFiller(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - static BridgeEndFiller *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - class BridgeCrossing : public NetherBridgePiece + static BridgeEndFiller *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + + protected: + void readAdditonalSaveData(CompoundTag *tag); + void addAdditonalSaveData(CompoundTag *tag); + }; + + class BridgeCrossing : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new BridgeCrossing(); } + virtual EStructurePiece GetType() { return eStructurePiece_BridgeCrossing; } + private: static const int width = 19; - static const int height = 10; - static const int depth = 19; + static const int height = 10; + static const int depth = 19; public: + BridgeCrossing(); BridgeCrossing(int genDepth, Random *random, BoundingBox *stairsBox, int direction); protected: BridgeCrossing(Random *random, int west, int north); public: - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static BridgeCrossing *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static BridgeCrossing *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; public: - class StartPiece : public BridgeCrossing + class StartPiece : public BridgeCrossing { + public: + virtual EStructurePiece GetType() { return eStructurePiece_NetherBridgeStartPiece; } public: - bool isLibraryAdded; - PieceWeight *previousPiece; + PieceWeight *previousPiece; Level *m_level; - list availableBridgePieces; - list availableCastlePieces; + list availableBridgePieces; + list availableCastlePieces; - // this queue is used so that the addChildren calls are - // called in a random order - vector pendingChildren; + // this queue is used so that the addChildren calls are + // called in a random order + vector pendingChildren; - StartPiece(Random *random, int west, int north, Level *level); // 4J Added level param + StartPiece(); + StartPiece(Random *random, int west, int north, Level *level); // 4J Added level param - }; + protected: + virtual void readAdditonalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *tag); + }; private: - class RoomCrossing : public NetherBridgePiece + class RoomCrossing : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new RoomCrossing(); } + virtual EStructurePiece GetType() { return eStructurePiece_RoomCrossing; } + private: static const int width = 7; - static const int height = 9; - static const int depth = 7; + static const int height = 9; + static const int depth = 7; public: + RoomCrossing(); RoomCrossing(int genDepth, Random *random, BoundingBox *box, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static RoomCrossing *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static RoomCrossing *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; - class StairsRoom : public NetherBridgePiece + class StairsRoom : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new StairsRoom(); } + virtual EStructurePiece GetType() { return eStructurePiece_StairsRoom; } + private: static const int width = 7; - static const int height = 11; - static const int depth = 7; + static const int height = 11; + static const int depth = 7; public: + StairsRoom(); StairsRoom(int genDepth, Random *random, BoundingBox *box, int direction); virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static StairsRoom *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + static StairsRoom *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; - class MonsterThrone : public NetherBridgePiece + class MonsterThrone : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new MonsterThrone(); } + virtual EStructurePiece GetType() { return eStructurePiece_MonsterThrone; } + private: static const int width = 7; - static const int height = 8; - static const int depth = 9; + static const int height = 8; + static const int depth = 9; - bool hasPlacedMobSpawner; + bool hasPlacedMobSpawner; public: + MonsterThrone(); MonsterThrone(int genDepth, Random *random, BoundingBox *box, int direction); - static MonsterThrone *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - - /** - * - * - */ - class CastleEntrance : public NetherBridgePiece + + protected: + virtual void readAdditonalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *tag); + + public: + static MonsterThrone *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; + + /** + * + * + */ + class CastleEntrance : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new CastleEntrance(); } + virtual EStructurePiece GetType() { return eStructurePiece_CastleEntrance; } + private: - static const int width = 13; - static const int height = 14; - static const int depth = 13; - public: - CastleEntrance(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static CastleEntrance *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - - /** - * - * - */ - class CastleStalkRoom : public NetherBridgePiece + static const int width = 13; + static const int height = 14; + static const int depth = 13; + public: + CastleEntrance(); + CastleEntrance(int genDepth, Random *random, BoundingBox *stairsBox, int direction); + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static CastleEntrance *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; + + /** + * + * + */ + class CastleStalkRoom : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new CastleStalkRoom(); } + virtual EStructurePiece GetType() { return eStructurePiece_CastleStalkRoom; } + private: - static const int width = 13; - static const int height = 14; - static const int depth = 13; + static const int width = 13; + static const int height = 14; + static const int depth = 13; public: + CastleStalkRoom(); CastleStalkRoom(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static CastleStalkRoom *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - - /** - * - * - */ + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static CastleStalkRoom *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; + + /** + * + * + */ class CastleSmallCorridorPiece : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new CastleSmallCorridorPiece(); } + virtual EStructurePiece GetType() { return eStructurePiece_CastleSmallCorridorPiece; } + private: - static const int width = 5; - static const int height = 7; - static const int depth = 5; + static const int width = 5; + static const int height = 7; + static const int depth = 5; public: + CastleSmallCorridorPiece(); CastleSmallCorridorPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static CastleSmallCorridorPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - - /** - * - * - */ - class CastleSmallCorridorCrossingPiece : public NetherBridgePiece + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static CastleSmallCorridorPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; + + /** + * + * + */ + class CastleSmallCorridorCrossingPiece : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new CastleSmallCorridorCrossingPiece(); } + virtual EStructurePiece GetType() { return eStructurePiece_CastleSmallCorridorCrossingPiece; } + private: - static const int width = 5; - static const int height = 7; - static const int depth = 5; + static const int width = 5; + static const int height = 7; + static const int depth = 5; public: + CastleSmallCorridorCrossingPiece(); CastleSmallCorridorCrossingPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static CastleSmallCorridorCrossingPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - - /** - * - * - */ - class CastleSmallCorridorRightTurnPiece : public NetherBridgePiece + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static CastleSmallCorridorCrossingPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; + + /** + * + * + */ + class CastleSmallCorridorRightTurnPiece : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new CastleSmallCorridorRightTurnPiece(); } + virtual EStructurePiece GetType() { return eStructurePiece_CastleSmallCorridorRightTurnPiece; } + private: static const int width = 5; static const int height = 7; static const int depth = 5; + bool isNeedingChest; + public: + CastleSmallCorridorRightTurnPiece(); CastleSmallCorridorRightTurnPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static CastleSmallCorridorRightTurnPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + protected: + virtual void readAdditonalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *tag); + + public: + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static CastleSmallCorridorRightTurnPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + + }; - /** - * - * - */ - class CastleSmallCorridorLeftTurnPiece : public NetherBridgePiece + /** + * + * + */ + class CastleSmallCorridorLeftTurnPiece : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new CastleSmallCorridorLeftTurnPiece(); } + virtual EStructurePiece GetType() { return eStructurePiece_CastleSmallCorridorLeftTurnPiece; } + private: static const int width = 5; static const int height = 7; static const int depth = 5; + bool isNeedingChest; public: + CastleSmallCorridorLeftTurnPiece(); CastleSmallCorridorLeftTurnPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static CastleSmallCorridorLeftTurnPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - - /** - * - * - */ - class CastleCorridorStairsPiece : public NetherBridgePiece + + protected: + virtual void readAdditonalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *tag); + + public: + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static CastleSmallCorridorLeftTurnPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; + + /** + * + * + */ + class CastleCorridorStairsPiece : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new CastleCorridorStairsPiece(); } + virtual EStructurePiece GetType() { return eStructurePiece_CastleCorridorStairsPiece; } + private: static const int width = 5; static const int height = 14; static const int depth = 10; public: + CastleCorridorStairsPiece(); CastleCorridorStairsPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static CastleCorridorStairsPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static CastleCorridorStairsPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + }; - /** - * - * - */ - class CastleCorridorTBalconyPiece : public NetherBridgePiece + /** + * + * + */ + class CastleCorridorTBalconyPiece : public NetherBridgePiece { + public: + static StructurePiece *Create() { return new CastleCorridorTBalconyPiece(); } + virtual EStructurePiece GetType() { return eStructurePiece_CastleCorridorTBalconyPiece; } + private: - static const int width = 9; - static const int height = 7; - static const int depth = 9; + static const int width = 9; + static const int height = 7; + static const int depth = 9; public: + CastleCorridorTBalconyPiece(); CastleCorridorTBalconyPiece(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static CastleCorridorTBalconyPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static CastleCorridorTBalconyPiece *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; }; diff --git a/Minecraft.World/NetherWartTile.cpp b/Minecraft.World/NetherWartTile.cpp new file mode 100644 index 00000000..1faa57ca --- /dev/null +++ b/Minecraft.World/NetherWartTile.cpp @@ -0,0 +1,112 @@ +#include "stdafx.h" +#include "NetherWartTile.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.biome.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.h" + +NetherWartTile::NetherWartTile(int id) : Bush(id) +{ + setTicking(true); + updateDefaultShape(); +} + +// 4J Added override +void NetherWartTile::updateDefaultShape() +{ + float ss = 0.5f; + setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); +} + +bool NetherWartTile::mayPlaceOn(int tile) +{ + return tile == Tile::soulsand_Id; +} + +// Brought forward to fix #60073 - TU7: Content: Gameplay: Nether Warts cannot be placed next to each other in the Nether +bool NetherWartTile::canSurvive(Level *level, int x, int y, int z) +{ + return mayPlaceOn(level->getTile(x, y - 1, z)); +} + +void NetherWartTile::tick(Level *level, int x, int y, int z, Random *random) +{ + int age = level->getData(x, y, z); + if (age < MAX_AGE) + { + if (random->nextInt(10) == 0) + { + age++; + level->setData(x, y, z, age, Tile::UPDATE_CLIENTS); + } + } + + Bush::tick(level, x, y, z, random); +} + +void NetherWartTile::growCropsToMax(Level *level, int x, int y, int z) +{ + level->setData(x, y, z, MAX_AGE, Tile::UPDATE_CLIENTS); +} + +Icon *NetherWartTile::getTexture(int face, int data) +{ + if (data >= MAX_AGE) + { + return icons[2]; + } + if (data > 0) + { + return icons[1]; + } + return icons[0]; +} + +int NetherWartTile::getRenderShape() +{ + return Tile::SHAPE_ROWS; +} + +void NetherWartTile::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus) +{ + if (level->isClientSide) + { + return; + } + int count = 1; + if (data >= MAX_AGE) + { + count = 2 + level->random->nextInt(3); + if (playerBonus > 0) + { + count += level->random->nextInt(playerBonus + 1); + } + } + for (int i = 0; i < count; i++) + { + popResource(level, x, y, z, shared_ptr(new ItemInstance(Item::netherwart_seeds))); + } +} + +int NetherWartTile::getResource(int data, Random *random, int playerBonusLevel) +{ + return 0; +} + +int NetherWartTile::getResourceCount(Random *random) +{ + return 0; +} + +int NetherWartTile::cloneTileId(Level *level, int x, int y, int z) +{ + return Item::netherwart_seeds_Id; +} + +void NetherWartTile::registerIcons(IconRegister *iconRegister) +{ + for (int i = 0; i < NETHER_STALK_TEXTURE_COUNT; i++) + { + icons[i] = iconRegister->registerIcon(getIconName() + L"_stage_" + _toString(i) ); + } +} diff --git a/Minecraft.World/NetherWartTile.h b/Minecraft.World/NetherWartTile.h new file mode 100644 index 00000000..3e5088b2 --- /dev/null +++ b/Minecraft.World/NetherWartTile.h @@ -0,0 +1,31 @@ +#pragma once +#include "Bush.h" + +class ChunkRebuildData; +class NetherWartTile : public Bush +{ + friend class ChunkRebuildData; +private: + static const int MAX_AGE = 3; + + static const int NETHER_STALK_TEXTURE_COUNT = 3; + Icon *icons[NETHER_STALK_TEXTURE_COUNT]; + +public: + NetherWartTile(int id); + virtual void updateDefaultShape(); // 4J Added override + virtual bool mayPlaceOn(int tile); + + // Brought forward to fix #60073 - TU7: Content: Gameplay: Nether Warts cannot be placed next to each other in the Nether + virtual bool canSurvive(Level *level, int x, int y, int z); + + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual void growCropsToMax(Level *level, int x, int y, int z); + virtual Icon *getTexture(int face, int data); + virtual int getRenderShape(); + virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual int getResourceCount(Random *random); + virtual int cloneTileId(Level *level, int x, int y, int z); + void registerIcons(IconRegister *iconRegister); +}; diff --git a/Minecraft.World/NetherrackTile.cpp b/Minecraft.World/NetherrackTile.cpp new file mode 100644 index 00000000..8f99fb53 --- /dev/null +++ b/Minecraft.World/NetherrackTile.cpp @@ -0,0 +1,6 @@ +#include "stdafx.h" +#include "NetherrackTile.h" + +NetherrackTile::NetherrackTile(int id) : Tile(id, Material::stone) +{ +} \ No newline at end of file diff --git a/Minecraft.World/NetherrackTile.h b/Minecraft.World/NetherrackTile.h new file mode 100644 index 00000000..d137a229 --- /dev/null +++ b/Minecraft.World/NetherrackTile.h @@ -0,0 +1,8 @@ +#pragma once +#include "Tile.h" + +class NetherrackTile : public Tile +{ +public: + NetherrackTile(int id); +}; \ No newline at end of file diff --git a/Minecraft.World/NonTameRandomTargetGoal.cpp b/Minecraft.World/NonTameRandomTargetGoal.cpp index 734d637f..5fb6c79d 100644 --- a/Minecraft.World/NonTameRandomTargetGoal.cpp +++ b/Minecraft.World/NonTameRandomTargetGoal.cpp @@ -2,13 +2,12 @@ #include "net.minecraft.world.entity.animal.h" #include "NonTameRandomTargetGoal.h" -NonTameRandomTargetGoal::NonTameRandomTargetGoal(TamableAnimal *mob, const type_info& targetType, float within, int randomInterval, bool mustSee) : NearestAttackableTargetGoal(mob, targetType, within, randomInterval, mustSee) +NonTameRandomTargetGoal::NonTameRandomTargetGoal(TamableAnimal *mob, const type_info& targetType, int randomInterval, bool mustSee) : NearestAttackableTargetGoal(mob, targetType, randomInterval, mustSee) { - this->tamableMob = mob; + tamableMob = mob; } bool NonTameRandomTargetGoal::canUse() { - if (tamableMob->isTame()) return false; - return NearestAttackableTargetGoal::canUse(); + return !tamableMob->isTame() && NearestAttackableTargetGoal::canUse(); } diff --git a/Minecraft.World/NonTameRandomTargetGoal.h b/Minecraft.World/NonTameRandomTargetGoal.h index 8adba7df..f30244a1 100644 --- a/Minecraft.World/NonTameRandomTargetGoal.h +++ b/Minecraft.World/NonTameRandomTargetGoal.h @@ -10,7 +10,7 @@ private: TamableAnimal *tamableMob; // Owner of this goal public: - NonTameRandomTargetGoal(TamableAnimal *mob, const type_info& targetType, float within, int randomInterval, bool mustSee); + NonTameRandomTargetGoal(TamableAnimal *mob, const type_info& targetType, int randomInterval, bool mustSee); bool canUse(); }; \ No newline at end of file diff --git a/Minecraft.World/NotGateTile.cpp b/Minecraft.World/NotGateTile.cpp index a3971284..464e0ca5 100644 --- a/Minecraft.World/NotGateTile.cpp +++ b/Minecraft.World/NotGateTile.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" #include "NotGateTile.h" #include "SoundTypes.h" #include "net.minecraft.world.h" @@ -24,201 +25,209 @@ bool NotGateTile::isToggledTooFrequently(Level *level, int x, int y, int z, bool { recentToggles[level] = new deque; } - if (add) recentToggles[level]->push_back(Toggle(x, y, z, level->getTime())); - int count = 0; + if (add) recentToggles[level]->push_back(Toggle(x, y, z, level->getGameTime())); + int count = 0; AUTO_VAR(itEnd, recentToggles[level]->end()); for (AUTO_VAR(it, recentToggles[level]->begin()); it != itEnd; it++) { - if (it->x == x && it->y == y && it->z == z) + if (it->x == x && it->y == y && it->z == z) { - count++; - if (count >= MAX_RECENT_TOGGLES) + count++; + if (count >= MAX_RECENT_TOGGLES) { - return true; - } - } - } - return false; + return true; + } + } + } + return false; } NotGateTile::NotGateTile(int id, bool on) : TorchTile(id) { - this->on = on; - this->setTicking(true); + this->on = on; + this->setTicking(true); } -int NotGateTile::getTickDelay() +int NotGateTile::getTickDelay(Level *level) { return 2; } void NotGateTile::onPlace(Level *level, int x, int y, int z) { - if (level->getData(x, y, z) == 0) TorchTile::onPlace(level, x, y, z); - if (on) + if (level->getData(x, y, z) == 0) TorchTile::onPlace(level, x, y, z); + if (on) { - level->updateNeighborsAt(x, y - 1, z, id); - level->updateNeighborsAt(x, y + 1, z, id); - level->updateNeighborsAt(x - 1, y, z, id); - level->updateNeighborsAt(x + 1, y, z, id); - level->updateNeighborsAt(x, y, z - 1, id); - level->updateNeighborsAt(x, y, z + 1, id); - } + level->updateNeighborsAt(x, y - 1, z, id); + level->updateNeighborsAt(x, y + 1, z, id); + level->updateNeighborsAt(x - 1, y, z, id); + level->updateNeighborsAt(x + 1, y, z, id); + level->updateNeighborsAt(x, y, z - 1, id); + level->updateNeighborsAt(x, y, z + 1, id); + } } void NotGateTile::onRemove(Level *level, int x, int y, int z, int id, int data) { - if (on) + if (on) { - level->updateNeighborsAt(x, y - 1, z, this->id); - level->updateNeighborsAt(x, y + 1, z, this->id); - level->updateNeighborsAt(x - 1, y, z, this->id); - level->updateNeighborsAt(x + 1, y, z, this->id); - level->updateNeighborsAt(x, y, z - 1, this->id); - level->updateNeighborsAt(x, y, z + 1, this->id); - } + level->updateNeighborsAt(x, y - 1, z, this->id); + level->updateNeighborsAt(x, y + 1, z, this->id); + level->updateNeighborsAt(x - 1, y, z, this->id); + level->updateNeighborsAt(x + 1, y, z, this->id); + level->updateNeighborsAt(x, y, z - 1, this->id); + level->updateNeighborsAt(x, y, z + 1, this->id); + } } -bool NotGateTile::getSignal(LevelSource *level, int x, int y, int z, int face) +int NotGateTile::getSignal(LevelSource *level, int x, int y, int z, int face) { - if (!on) return false; + if (!on) return Redstone::SIGNAL_NONE; - int dir = level->getData(x, y, z); + int dir = level->getData(x, y, z); - if (dir == 5 && face == 1) return false; - if (dir == 3 && face == 3) return false; - if (dir == 4 && face == 2) return false; - if (dir == 1 && face == 5) return false; - if (dir == 2 && face == 4) return false; + if (dir == 5 && face == 1) return Redstone::SIGNAL_NONE; + if (dir == 3 && face == 3) return Redstone::SIGNAL_NONE; + if (dir == 4 && face == 2) return Redstone::SIGNAL_NONE; + if (dir == 1 && face == 5) return Redstone::SIGNAL_NONE; + if (dir == 2 && face == 4) return Redstone::SIGNAL_NONE; - return true; + return Redstone::SIGNAL_MAX; } bool NotGateTile::hasNeighborSignal(Level *level, int x, int y, int z) { - int dir = level->getData(x, y, z); + int dir = level->getData(x, y, z); - if (dir == 5 && level->getSignal(x, y - 1, z, 0)) return true; - if (dir == 3 && level->getSignal(x, y, z - 1, 2)) return true; - if (dir == 4 && level->getSignal(x, y, z + 1, 3)) return true; - if (dir == 1 && level->getSignal(x - 1, y, z, 4)) return true; - if (dir == 2 && level->getSignal(x + 1, y, z, 5)) return true; - return false; + if (dir == 5 && level->hasSignal(x, y - 1, z, 0)) return true; + if (dir == 3 && level->hasSignal(x, y, z - 1, 2)) return true; + if (dir == 4 && level->hasSignal(x, y, z + 1, 3)) return true; + if (dir == 1 && level->hasSignal(x - 1, y, z, 4)) return true; + if (dir == 2 && level->hasSignal(x + 1, y, z, 5)) return true; + return false; } void NotGateTile::tick(Level *level, int x, int y, int z, Random *random) { - bool neighborSignal = hasNeighborSignal(level, x, y, z); + bool neighborSignal = hasNeighborSignal(level, x, y, z); // 4J - brought forward changes from 1.3.2 to associate toggles with level if( recentToggles.find(level) != recentToggles.end() ) { deque *toggles = recentToggles[level]; - while (!toggles->empty() && level->getTime() - toggles->front().when > RECENT_TOGGLE_TIMER) + while (!toggles->empty() && level->getGameTime() - toggles->front().when > RECENT_TOGGLE_TIMER) { toggles->pop_front(); } } - if (on) + if (on) { - if (neighborSignal) + if (neighborSignal) { - level->setTileAndData(x, y, z, Tile::notGate_off_Id, level->getData(x, y, z)); + level->setTileAndData(x, y, z, Tile::redstoneTorch_off_Id, level->getData(x, y, z), Tile::UPDATE_ALL); - if (isToggledTooFrequently(level, x, y, z, true)) + if (isToggledTooFrequently(level, x, y, z, true)) { app.DebugPrintf("Torch at (%d,%d,%d) has toggled too many times\n",x,y,z); - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_RANDOM_FIZZ, 0.5f, 2.6f + (level->random->nextFloat() - level->random->nextFloat()) * 0.8f); - for (int i = 0; i < 5; i++) + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_RANDOM_FIZZ, 0.5f, 2.6f + (level->random->nextFloat() - level->random->nextFloat()) * 0.8f); + for (int i = 0; i < 5; i++) { - double xx = x + random->nextDouble() * 0.6 + 0.2; - double yy = y + random->nextDouble() * 0.6 + 0.2; - double zz = z + random->nextDouble() * 0.6 + 0.2; - - level->addParticle(eParticleType_smoke, xx, yy, zz, 0, 0, 0); - } - } - } - } + double xx = x + random->nextDouble() * 0.6 + 0.2; + double yy = y + random->nextDouble() * 0.6 + 0.2; + double zz = z + random->nextDouble() * 0.6 + 0.2; + + level->addParticle(eParticleType_smoke, xx, yy, zz, 0, 0, 0); + } + } + } + } else { - if (!neighborSignal) + if (!neighborSignal) { - if (!isToggledTooFrequently(level, x, y, z, false)) + if (!isToggledTooFrequently(level, x, y, z, false)) { - level->setTileAndData(x, y, z, Tile::notGate_on_Id, level->getData(x, y, z)); - } + level->setTileAndData(x, y, z, Tile::redstoneTorch_on_Id, level->getData(x, y, z), Tile::UPDATE_ALL); + } else { app.DebugPrintf("Torch at (%d,%d,%d) has toggled too many times\n",x,y,z); } - } - } + } + } } void NotGateTile::neighborChanged(Level *level, int x, int y, int z, int type) { - TorchTile::neighborChanged(level, x, y, z, type); - level->addToTickNextTick(x, y, z, id, getTickDelay()); + if (checkDoPop(level, x, y, z, type)) + { + return; + } + + bool neighborSignal = hasNeighborSignal(level, x, y, z); + if ((on && neighborSignal) || (!on && !neighborSignal)) + { + level->addToTickNextTick(x, y, z, id, getTickDelay(level)); + } } -bool NotGateTile::getDirectSignal(Level *level, int x, int y, int z, int face) +int NotGateTile::getDirectSignal(LevelSource *level, int x, int y, int z, int face) { - if (face == 0) + if (face == 0) { - return getSignal(level, x, y, z, face); - } - return false; + return getSignal(level, x, y, z, face); + } + return Redstone::SIGNAL_NONE; } int NotGateTile::getResource(int data, Random *random, int playerBonusLevel) { - return Tile::notGate_on_Id; + return Tile::redstoneTorch_on_Id; } bool NotGateTile::isSignalSource() { - return true; + return true; } void NotGateTile::animateTick(Level *level, int xt, int yt, int zt, Random *random) { - if (!on) return; - int dir = level->getData(xt, yt, zt); - double x = xt + 0.5f + (random->nextFloat() - 0.5f) * 0.2; - double y = yt + 0.7f + (random->nextFloat() - 0.5f) * 0.2; - double z = zt + 0.5f + (random->nextFloat() - 0.5f) * 0.2; - double h = 0.22f; - double r = 0.27f; - if (dir == 1) - { - level->addParticle(eParticleType_reddust, x - r, y + h, z, 0, 0, 0); - } + if (!on) return; + int dir = level->getData(xt, yt, zt); + double x = xt + 0.5f + (random->nextFloat() - 0.5f) * 0.2; + double y = yt + 0.7f + (random->nextFloat() - 0.5f) * 0.2; + double z = zt + 0.5f + (random->nextFloat() - 0.5f) * 0.2; + double h = 0.22f; + double r = 0.27f; + if (dir == 1) + { + level->addParticle(eParticleType_reddust, x - r, y + h, z, 0, 0, 0); + } else if(dir == 2) { - level->addParticle(eParticleType_reddust, x + r, y + h, z, 0, 0, 0); - } + level->addParticle(eParticleType_reddust, x + r, y + h, z, 0, 0, 0); + } else if (dir == 3) { - level->addParticle(eParticleType_reddust, x, y + h, z - r, 0, 0, 0); - } + level->addParticle(eParticleType_reddust, x, y + h, z - r, 0, 0, 0); + } else if (dir == 4) { - level->addParticle(eParticleType_reddust, x, y + h, z + r, 0, 0, 0); - } + level->addParticle(eParticleType_reddust, x, y + h, z + r, 0, 0, 0); + } else { - level->addParticle(eParticleType_reddust, x, y, z, 0, 0, 0); - } + level->addParticle(eParticleType_reddust, x, y, z, 0, 0, 0); + } } int NotGateTile::cloneTileId(Level *level, int x, int y, int z) { - return Tile::notGate_on_Id; + return Tile::redstoneTorch_on_Id; } void NotGateTile::levelTimeChanged(Level *level, __int64 delta, __int64 newTime) @@ -234,14 +243,7 @@ void NotGateTile::levelTimeChanged(Level *level, __int64 delta, __int64 newTime) } } -void NotGateTile::registerIcons(IconRegister *iconRegister) +bool NotGateTile::isMatching(int id) { - if (on) - { - icon = iconRegister->registerIcon(L"redtorch_lit"); - } - else - { - icon = iconRegister->registerIcon(L"redtorch"); - } + return id == Tile::redstoneTorch_off_Id || id == Tile::redstoneTorch_on_Id; } \ No newline at end of file diff --git a/Minecraft.World/NotGateTile.h b/Minecraft.World/NotGateTile.h index 52dd4a2e..b1f3431d 100644 --- a/Minecraft.World/NotGateTile.h +++ b/Minecraft.World/NotGateTile.h @@ -10,58 +10,57 @@ class NotGateTile : public TorchTile private: static const int RECENT_TOGGLE_TIMER = 20 * 3; - static const int MAX_RECENT_TOGGLES = 8; + static const int MAX_RECENT_TOGGLES = 8; - bool on; + bool on; public: - class Toggle + class Toggle { public: - int x, y, z; - __int64 when; + int x, y, z; + __int64 when; - Toggle(int x, int y, int z, __int64 when) + Toggle(int x, int y, int z, __int64 when) { - this->x = x; - this->y = y; - this->z = z; - this->when = when; - } - }; + this->x = x; + this->y = y; + this->z = z; + this->when = when; + } + }; private: static unordered_map *> recentToggles; // 4J - brought forward change from 1.3.2 public: static void removeLevelReferences(Level *level); // 4J added private: - bool isToggledTooFrequently(Level *level, int x, int y, int z, bool add); + bool isToggledTooFrequently(Level *level, int x, int y, int z, bool add); protected: NotGateTile(int id, bool on); public: - int getTickDelay(); + int getTickDelay(Level *level); void onPlace(Level *level, int x, int y, int z); void onRemove(Level *level, int x, int y, int z, int id, int data); - bool getSignal(LevelSource *level, int x, int y, int z, int face); + int getSignal(LevelSource *level, int x, int y, int z, int face); private: bool hasNeighborSignal(Level *level, int x, int y, int z); public: - void tick(Level *level, int x, int y, int z, Random *random); - void neighborChanged(Level *level, int x, int y, int z, int type); + void tick(Level *level, int x, int y, int z, Random *random); + void neighborChanged(Level *level, int x, int y, int z, int type); - bool getDirectSignal(Level *level, int x, int y, int z, int face); + int getDirectSignal(LevelSource *level, int x, int y, int z, int face); - int getResource(int data, Random *random, int playerBonusLevel); - bool isSignalSource(); + int getResource(int data, Random *random, int playerBonusLevel); + bool isSignalSource(); public: void animateTick(Level *level, int xt, int yt, int zt, Random *random); int cloneTileId(Level *level, int x, int y, int z); - void levelTimeChanged(Level *level, __int64 delta, __int64 newTime); - - void registerIcons(IconRegister *iconRegister); + void levelTimeChanged(Level *level, __int64 delta, __int64 newTime); + bool isMatching(int id); }; \ No newline at end of file diff --git a/Minecraft.World/NoteBlockTile.cpp b/Minecraft.World/NoteBlockTile.cpp new file mode 100644 index 00000000..25ea587a --- /dev/null +++ b/Minecraft.World/NoteBlockTile.cpp @@ -0,0 +1,86 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "NoteBlockTile.h" +#include "SoundTypes.h" + +NoteBlockTile::NoteBlockTile(int id) : BaseEntityTile(id, Material::wood) +{ +} + +void NoteBlockTile::neighborChanged(Level *level, int x, int y, int z, int type) +{ + app.DebugPrintf("-------- Neighbour changed type %d\n", type); + bool signal = level->hasNeighborSignal(x, y, z); + shared_ptr mte = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + app.DebugPrintf("-------- Signal is %s, tile is currently %s\n",signal?"TRUE":"FALSE", mte->on?"ON":"OFF"); + if (mte != NULL && mte->on != signal) + { + if (signal) + { + mte->playNote(level, x, y, z); + } + mte->on = signal; + } +} + +// 4J-PB - Adding a TestUse for tooltip display +bool NoteBlockTile::TestUse() +{ + return true; +} + +bool NoteBlockTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param +{ + if (soundOnly) return false; + if (level->isClientSide) return true; + shared_ptr mte = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + if (mte != NULL ) + { + mte->tune(); + mte->playNote(level, x, y, z); + } + return true; +} + +void NoteBlockTile::attack(Level *level, int x, int y, int z, shared_ptr player) +{ + if (level->isClientSide) return; + shared_ptr mte = dynamic_pointer_cast( level->getTileEntity(x, y, z) ); + if( mte != NULL ) mte->playNote(level, x, y, z); +} + +shared_ptr NoteBlockTile::newTileEntity(Level *level) +{ + return shared_ptr( new MusicTileEntity() ); +} + +bool NoteBlockTile::triggerEvent(Level *level, int x, int y, int z, int i, int note) +{ + float pitch = (float) pow(2, (note - 12) / 12.0); + + int iSound; + switch(i) + { + case 1: + iSound=eSoundType_NOTE_BD; + break; + case 2: + iSound=eSoundType_NOTE_SNARE; + break; + case 3: + iSound=eSoundType_NOTE_HAT; + break; + case 4: + iSound=eSoundType_NOTE_BASSATTACK; + break; + default: + iSound=eSoundType_NOTE_HARP; + break; + } + app.DebugPrintf("NoteBlockTile::triggerEvent - playSound - pitch = %f\n",pitch); + level->playSound(x + 0.5, y + 0.5, z + 0.5, iSound, 3, pitch); + level->addParticle(eParticleType_note, x + 0.5, y + 1.2, z + 0.5, note / 24.0, 0, 0); + + return true; +} diff --git a/Minecraft.World/NoteBlockTile.h b/Minecraft.World/NoteBlockTile.h new file mode 100644 index 00000000..e072b5e6 --- /dev/null +++ b/Minecraft.World/NoteBlockTile.h @@ -0,0 +1,16 @@ +#pragma once +#include "BaseEntityTile.h" + +class Player; + +class NoteBlockTile : public BaseEntityTile +{ +public: + NoteBlockTile(int id); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual bool TestUse(); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual void attack(Level *level, int x, int y, int z, shared_ptr player); + virtual shared_ptr newTileEntity(Level *level); + virtual bool triggerEvent(Level *level, int x, int y, int z, int i, int note); +}; \ No newline at end of file diff --git a/Minecraft.World/Objective.cpp b/Minecraft.World/Objective.cpp new file mode 100644 index 00000000..243713d4 --- /dev/null +++ b/Minecraft.World/Objective.cpp @@ -0,0 +1,38 @@ +#include "stdafx.h" +#include "net.minecraft.world.scores.h" +#include "Objective.h" + +Objective::Objective(Scoreboard *scoreboard, const wstring &name, ObjectiveCriteria *criteria) +{ + this->scoreboard = scoreboard; + this->name = name; + this->criteria = criteria; + + displayName = name; +} + +Scoreboard *Objective::getScoreboard() +{ + return scoreboard; +} + +wstring Objective::getName() +{ + return name; +} + +ObjectiveCriteria *Objective::getCriteria() +{ + return criteria; +} + +wstring Objective::getDisplayName() +{ + return displayName; +} + +void Objective::setDisplayName(const wstring &name) +{ + displayName = name; + scoreboard->onObjectiveChanged(this); +} \ No newline at end of file diff --git a/Minecraft.World/Objective.h b/Minecraft.World/Objective.h new file mode 100644 index 00000000..eebec31a --- /dev/null +++ b/Minecraft.World/Objective.h @@ -0,0 +1,26 @@ +#pragma once + +class Scoreboard; +class ObjectiveCriteria; + +class Objective +{ +public: + static const int MAX_NAME_LENGTH = 16; + static const int MAX_DISPLAY_NAME_LENGTH = 32; + +private: + Scoreboard *scoreboard; + wstring name; + ObjectiveCriteria *criteria; + wstring displayName; + +public: + Objective(Scoreboard *scoreboard, const wstring &name, ObjectiveCriteria *criteria); + + Scoreboard *getScoreboard(); + wstring getName(); + ObjectiveCriteria *getCriteria(); + wstring getDisplayName(); + void setDisplayName(const wstring &name); +}; \ No newline at end of file diff --git a/Minecraft.World/ObjectiveCriteria.cpp b/Minecraft.World/ObjectiveCriteria.cpp new file mode 100644 index 00000000..3f87890d --- /dev/null +++ b/Minecraft.World/ObjectiveCriteria.cpp @@ -0,0 +1,12 @@ +#include "stdafx.h" +#include "net.minecraft.world.scores.criteria.h" +#include "ObjectiveCriteria.h" + + +unordered_map ObjectiveCriteria::CRITERIA_BY_NAME; + +ObjectiveCriteria *ObjectiveCriteria::DUMMY = new DummyCriteria(L"dummy"); +ObjectiveCriteria *ObjectiveCriteria::DEATH_COUNT = new DummyCriteria(L"deathCount"); +ObjectiveCriteria *ObjectiveCriteria::KILL_COUNT_PLAYERS = new DummyCriteria(L"playerKillCount"); +ObjectiveCriteria *ObjectiveCriteria::KILL_COUNT_ALL = new DummyCriteria(L"totalKillCount"); +ObjectiveCriteria *ObjectiveCriteria::HEALTH = new HealthCriteria(L"health"); \ No newline at end of file diff --git a/Minecraft.World/ObjectiveCriteria.h b/Minecraft.World/ObjectiveCriteria.h new file mode 100644 index 00000000..833665e0 --- /dev/null +++ b/Minecraft.World/ObjectiveCriteria.h @@ -0,0 +1,17 @@ +#pragma once + +class ObjectiveCriteria +{ +public: + static unordered_map CRITERIA_BY_NAME; + + static ObjectiveCriteria *DUMMY; + static ObjectiveCriteria *DEATH_COUNT; + static ObjectiveCriteria *KILL_COUNT_PLAYERS; + static ObjectiveCriteria *KILL_COUNT_ALL; + static ObjectiveCriteria *HEALTH; + + virtual wstring getName() = 0; + virtual int getScoreModifier(vector > *players) = 0; + virtual bool isReadOnly() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/Ocelot.cpp b/Minecraft.World/Ocelot.cpp new file mode 100644 index 00000000..50285682 --- /dev/null +++ b/Minecraft.World/Ocelot.cpp @@ -0,0 +1,361 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.ai.control.h" +#include "net.minecraft.world.entity.ai.goal.target.h" +#include "net.minecraft.world.entity.ai.goal.h" +#include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.animal.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.phys.h" +#include "SynchedEntityData.h" +#include "StringHelpers.h" +#include "..\Minecraft.Client\Textures.h" +#include "..\Minecraft.Client\Minecraft.h" +#include "..\Minecraft.Client\MultiPlayerLocalPlayer.h" +#include "GenericStats.h" +#include "Ocelot.h" + +const double Ocelot::SNEAK_SPEED_MOD = 0.6; +const double Ocelot::WALK_SPEED_MOD = 0.8; +const double Ocelot::FOLLOW_SPEED_MOD = 1.0; +const double Ocelot::SPRINT_SPEED_MOD = 1.33; + +const int Ocelot::DATA_TYPE_ID = 18; + +Ocelot::Ocelot(Level *level) : TamableAnimal(level) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); + + setSize(0.6f, 0.8f); + + getNavigation()->setAvoidWater(true); + goalSelector.addGoal(1, new FloatGoal(this)); + goalSelector.addGoal(2, sitGoal, false); + goalSelector.addGoal(3, temptGoal = new TemptGoal(this, SNEAK_SPEED_MOD, Item::fish_raw_Id, true), false); + goalSelector.addGoal(4, new AvoidPlayerGoal(this, typeid(Player), 16, WALK_SPEED_MOD, SPRINT_SPEED_MOD)); + goalSelector.addGoal(5, new FollowOwnerGoal(this, FOLLOW_SPEED_MOD, 10, 5)); + goalSelector.addGoal(6, new OcelotSitOnTileGoal(this, SPRINT_SPEED_MOD)); + goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3f)); + goalSelector.addGoal(8, new OcelotAttackGoal(this)); + goalSelector.addGoal(9, new BreedGoal(this, WALK_SPEED_MOD)); + goalSelector.addGoal(10, new RandomStrollGoal(this, WALK_SPEED_MOD)); + goalSelector.addGoal(11, new LookAtPlayerGoal(this, typeid(Player), 10)); + + targetSelector.addGoal(1, new NonTameRandomTargetGoal(this, typeid(Chicken), 750, false)); +} + +void Ocelot::defineSynchedData() +{ + TamableAnimal::defineSynchedData(); + + entityData->define(DATA_TYPE_ID, (byte) 0); +} + +void Ocelot::serverAiMobStep() +{ + if (getMoveControl()->hasWanted()) + { + double speed = getMoveControl()->getSpeedModifier(); + if (speed == SNEAK_SPEED_MOD) + { + setSneaking(true); + setSprinting(false); + } + else if (speed == SPRINT_SPEED_MOD) + { + setSneaking(false); + setSprinting(true); + } + else + { + setSneaking(false); + setSprinting(false); + } + } + else + { + setSneaking(false); + setSprinting(false); + } +} + +bool Ocelot::removeWhenFarAway() +{ + return Animal::removeWhenFarAway() && !isTame() && tickCount > SharedConstants::TICKS_PER_SECOND * 60 * 2; +} + +bool Ocelot::useNewAi() +{ + return true; +} + +void Ocelot::registerAttributes() +{ + TamableAnimal::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(10); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.3f); +} + +void Ocelot::causeFallDamage(float distance) +{ + // do nothing +} + +void Ocelot::addAdditonalSaveData(CompoundTag *tag) +{ + TamableAnimal::addAdditonalSaveData(tag); + tag->putInt(L"CatType", getCatType()); +} + +void Ocelot::readAdditionalSaveData(CompoundTag *tag) +{ + TamableAnimal::readAdditionalSaveData(tag); + if(isTame()) + { + setCatType(tag->getInt(L"CatType")); + } + else + { + setCatType(TYPE_OCELOT); + } +} + +int Ocelot::getAmbientSound() +{ + if (isTame()) + { + if (isInLove()) + { + return eSoundType_MOB_CAT_PURR; + } + if (random->nextInt(4) == 0) + { + return eSoundType_MOB_CAT_PURREOW; + } + return eSoundType_MOB_CAT_MEOW; + } + + return -1; +} + +int Ocelot::getHurtSound() +{ + return eSoundType_MOB_CAT_HIT; +} + +int Ocelot::getDeathSound() +{ + return eSoundType_MOB_CAT_HIT; +} + +float Ocelot::getSoundVolume() +{ + return 0.4f; +} + +int Ocelot::getDeathLoot() +{ + return Item::leather_Id; +} + +bool Ocelot::doHurtTarget(shared_ptr target) +{ + return target->hurt(DamageSource::mobAttack(dynamic_pointer_cast(shared_from_this())), 3); +} + +bool Ocelot::hurt(DamageSource *source, float dmg) +{ + if (isInvulnerable()) return false; + sitGoal->wantToSit(false); + return TamableAnimal::hurt(source, dmg); +} + +void Ocelot::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) +{ +} + +bool Ocelot::mobInteract(shared_ptr player) +{ + shared_ptr item = player->inventory->getSelected(); + if (isTame()) + { + if (equalsIgnoreCase(player->getUUID(), getOwnerUUID())) + { + if (!level->isClientSide && !isFood(item)) + { + sitGoal->wantToSit(!isSitting()); + } + } + } + else + { + if (temptGoal->isRunning() && item != NULL && item->id == Item::fish_raw_Id && player->distanceToSqr(shared_from_this()) < 3 * 3) + { + // 4J-PB - don't lose the fish in creative mode + if (!player->abilities.instabuild) item->count--; + if (item->count <= 0) + { + player->inventory->setItem(player->inventory->selected, nullptr); + } + + if (!level->isClientSide) + { + if (random->nextInt(3) == 0) + { + setTame(true); + + // 4J-JEV, hook for durango event. + player->awardStat(GenericStats::tamedEntity(eTYPE_OCELOT),GenericStats::param_tamedEntity(eTYPE_OCELOT)); + + setCatType(1 + level->random->nextInt(3)); + setOwnerUUID(player->getUUID()); + spawnTamingParticles(true); + sitGoal->wantToSit(true); + level->broadcastEntityEvent(shared_from_this(), EntityEvent::TAMING_SUCCEEDED); + } + else + { + spawnTamingParticles(false); + level->broadcastEntityEvent(shared_from_this(), EntityEvent::TAMING_FAILED); + } + } + return true; + } + } + return TamableAnimal::mobInteract(player); +} + +shared_ptr Ocelot::getBreedOffspring(shared_ptr target) +{ + // 4J - added limit to number of animals that can be bred + if( level->canCreateMore( GetType(), Level::eSpawnType_Breed) ) + { + shared_ptr offspring = shared_ptr( new Ocelot(level) ); + if (isTame()) + { + offspring->setOwnerUUID(getOwnerUUID()); + offspring->setTame(true); + offspring->setCatType(getCatType()); + } + return offspring; + } + else + { + return nullptr; + } +} + +bool Ocelot::isFood(shared_ptr itemInstance) +{ + return itemInstance != NULL && itemInstance->id == Item::fish_raw_Id; +} + +bool Ocelot::canMate(shared_ptr animal) +{ + if (animal == shared_from_this()) return false; + if (!isTame()) return false; + + shared_ptr partner = dynamic_pointer_cast(animal); + if (partner == NULL) return false; + if (!partner->isTame()) return false; + + return isInLove() && partner->isInLove(); +} + +int Ocelot::getCatType() +{ + return entityData->getByte(DATA_TYPE_ID); +} + +void Ocelot::setCatType(int type) +{ + entityData->set(DATA_TYPE_ID, (byte) type); +} + +bool Ocelot::canSpawn() +{ + // artificially make ozelots more rare + if (level->random->nextInt(3) == 0) + { + return false; + } + if (level->isUnobstructed(bb) && level->getCubes(shared_from_this(), bb)->empty() && !level->containsAnyLiquid(bb)) + { + int xt = Mth::floor(x); + int yt = Mth::floor(bb->y0); + int zt = Mth::floor(z); + if (yt < level->seaLevel) + { + return false; + } + + int tile = level->getTile(xt, yt - 1, zt); + if (tile == Tile::grass_Id || tile == Tile::leaves_Id) + { + return true; + } + } + return false; +} + +wstring Ocelot::getAName() +{ + if (hasCustomName()) return getCustomName(); +#ifdef _DEBUG + if (isTame()) + { + return L"entity.Cat.name"; + } + return TamableAnimal::getAName(); +#else + return L""; +#endif +} + +MobGroupData *Ocelot::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param +{ + groupData = TamableAnimal::finalizeMobSpawn(groupData); + +#ifndef _CONTENT_PACKAGE + if (app.DebugArtToolsOn() && (extraData != 0)) + { + setTame(true); + setCatType(extraData - 1); + setOwnerUUID(Minecraft::GetInstance()->localplayers[ProfileManager.GetPrimaryPad()]->getUUID()); + } + else +#endif + if (level->random->nextInt(7) == 0) + { + for (int kitten = 0; kitten < 2; kitten++) + { + shared_ptr ocelot = shared_ptr( new Ocelot(level) ); + ocelot->moveTo(x, y, z, yRot, 0); + ocelot->setAge(-20 * 60 * 20); + level->addEntity(ocelot); + } + } + return groupData; +} + +void Ocelot::setSittingOnTile(bool val) +{ + byte current = entityData->getByte(DATA_FLAGS_ID); + entityData->set(DATA_FLAGS_ID, val ? (byte) (current | 0x02) : (byte) (current & ~0x02) ); +} + +bool Ocelot::isSittingOnTile() +{ + byte current = entityData->getByte(DATA_FLAGS_ID); + return (current & 0x02) > 0; +} \ No newline at end of file diff --git a/Minecraft.World/Ocelot.h b/Minecraft.World/Ocelot.h new file mode 100644 index 00000000..7f02bf02 --- /dev/null +++ b/Minecraft.World/Ocelot.h @@ -0,0 +1,90 @@ +#pragma once + +#include "TamableAnimal.h" + +class TemptGoal; + +class Ocelot : public TamableAnimal +{ + friend class OcelotSitOnTileGoal; + +public: + eINSTANCEOF GetType() { return eTYPE_OCELOT; } + static Entity *create(Level *level) { return new Ocelot(level); } + +public: + static const double SNEAK_SPEED_MOD; + static const double WALK_SPEED_MOD; + static const double FOLLOW_SPEED_MOD; + static const double SPRINT_SPEED_MOD; + +private: + static const int DATA_TYPE_ID; + +public: + enum + { + TYPE_OCELOT, + TYPE_BLACK, + TYPE_RED, + TYPE_SIAMESE, + }; + +private: + TemptGoal *temptGoal; + +public: + Ocelot(Level *level); + +protected: + virtual void defineSynchedData(); + +public: + virtual void serverAiMobStep(); + +protected: + virtual bool removeWhenFarAway(); + +public: + virtual bool useNewAi(); + +protected: + virtual void registerAttributes(); + virtual void causeFallDamage(float distance); + +public: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditionalSaveData(CompoundTag *tag); + +protected: + virtual int getAmbientSound(); + virtual int getHurtSound(); + virtual int getDeathSound(); + virtual float getSoundVolume(); + virtual int getDeathLoot(); + +public: + virtual bool doHurtTarget(shared_ptr target); + virtual bool hurt(DamageSource *source, float dmg); + +protected: + virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); + +public: + virtual bool mobInteract(shared_ptr player); + virtual shared_ptr getBreedOffspring(shared_ptr target); + virtual bool isFood(shared_ptr itemInstance); + virtual bool canMate(shared_ptr animal); + virtual int getCatType(); + virtual void setCatType(int type); + virtual bool canSpawn(); + virtual wstring getAName(); + virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param + + + // 4J-JEV: Added for tooltips, is cat annoying player by sitting on chest or furnace. +private: + void setSittingOnTile(bool val); +public: + bool isSittingOnTile(); +}; \ No newline at end of file diff --git a/Minecraft.World/OcelotAttackGoal.cpp b/Minecraft.World/OcelotAttackGoal.cpp new file mode 100644 index 00000000..d9e0f29b --- /dev/null +++ b/Minecraft.World/OcelotAttackGoal.cpp @@ -0,0 +1,61 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.ai.control.h" +#include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.animal.h" +#include "net.minecraft.world.phys.h" +#include "OcelotAttackGoal.h" + +OcelotAttackGoal::OcelotAttackGoal(Mob *mob) +{ + target = weak_ptr(); + attackTime = 0; + speed = 0; + trackTarget = false; + + this->mob = mob; + this->level = mob->level; + setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); +} + +bool OcelotAttackGoal::canUse() +{ + shared_ptr bestTarget = mob->getTarget(); + if (bestTarget == NULL) return false; + target = weak_ptr(bestTarget); + return true; +} + +bool OcelotAttackGoal::canContinueToUse() +{ + if (target.lock() == NULL || !target.lock()->isAlive()) return false; + if (mob->distanceToSqr(target.lock()) > 15 * 15) return false; + return !mob->getNavigation()->isDone() || canUse(); +} + +void OcelotAttackGoal::stop() +{ + target = weak_ptr(); + mob->getNavigation()->stop(); +} + +void OcelotAttackGoal::tick() +{ + mob->getLookControl()->setLookAt(target.lock(), 30, 30); + + double meleeRadiusSqr = (mob->bbWidth * 2) * (mob->bbWidth * 2); + double distSqr = mob->distanceToSqr(target.lock()->x, target.lock()->bb->y0, target.lock()->z); + + double speedModifier = Ocelot::WALK_SPEED_MOD; + if (distSqr > meleeRadiusSqr && distSqr < 4 * 4) speedModifier = Ocelot::SPRINT_SPEED_MOD; + else if (distSqr < 15 * 15) speedModifier = Ocelot::SNEAK_SPEED_MOD; + + mob->getNavigation()->moveTo(target.lock(), speedModifier); + + attackTime = max(attackTime - 1, 0); + + if (distSqr > meleeRadiusSqr) return; + if (attackTime > 0) return; + attackTime = 20; + mob->doHurtTarget(target.lock()); +} \ No newline at end of file diff --git a/Minecraft.World/OcelotAttackGoal.h b/Minecraft.World/OcelotAttackGoal.h new file mode 100644 index 00000000..8efabe32 --- /dev/null +++ b/Minecraft.World/OcelotAttackGoal.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Goal.h" + +class OcelotAttackGoal : public Goal +{ +private: + Level *level; + Mob *mob; + weak_ptr target; + int attackTime; + float speed; + bool trackTarget; + +public: + OcelotAttackGoal(Mob *mob); + + virtual bool canUse(); + virtual bool canContinueToUse(); + virtual void stop(); + virtual void tick(); + + // 4J Added override to update ai elements when loading entity from schematics + virtual void setLevel(Level *level) { this->level = level; } +}; \ No newline at end of file diff --git a/Minecraft.World/OcelotSitOnTileGoal.cpp b/Minecraft.World/OcelotSitOnTileGoal.cpp index f5cf7066..a35537fb 100644 --- a/Minecraft.World/OcelotSitOnTileGoal.cpp +++ b/Minecraft.World/OcelotSitOnTileGoal.cpp @@ -15,7 +15,7 @@ const int OcelotSitOnTileGoal::SIT_TICKS = 60 * SharedConstants::TICKS_PER_SECON const int OcelotSitOnTileGoal::SEARCH_RANGE = 8; const double OcelotSitOnTileGoal::SIT_CHANCE = 0.0065f; -OcelotSitOnTileGoal::OcelotSitOnTileGoal(Ozelot *ocelot, float speed) +OcelotSitOnTileGoal::OcelotSitOnTileGoal(Ocelot *ocelot, double speedModifier) { _tick = 0; tryTicks = 0; @@ -25,7 +25,7 @@ OcelotSitOnTileGoal::OcelotSitOnTileGoal(Ozelot *ocelot, float speed) tileZ = 0; this->ocelot = ocelot; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag | Control::JumpControlFlag); } @@ -41,16 +41,20 @@ bool OcelotSitOnTileGoal::canContinueToUse() void OcelotSitOnTileGoal::start() { - ocelot->getNavigation()->moveTo((float) tileX + 0.5, tileY + 1, (float) tileZ + 0.5, speed); + ocelot->getNavigation()->moveTo((float) tileX + 0.5, tileY + 1, (float) tileZ + 0.5, speedModifier); _tick = 0; tryTicks = 0; maxTicks = ocelot->getRandom()->nextInt(ocelot->getRandom()->nextInt(SIT_TICKS) + SIT_TICKS) + SIT_TICKS; ocelot->getSitGoal()->wantToSit(false); + + ocelot->setSittingOnTile(true); // 4J-Added. } void OcelotSitOnTileGoal::stop() { ocelot->setSitting(false); + + ocelot->setSittingOnTile(false); // 4J-Added. } void OcelotSitOnTileGoal::tick() @@ -60,7 +64,7 @@ void OcelotSitOnTileGoal::tick() if (ocelot->distanceToSqr(tileX, tileY + 1, tileZ) > 1) { ocelot->setSitting(false); - ocelot->getNavigation()->moveTo((float) tileX + 0.5, tileY + 1, (float) tileZ + 0.5, speed); + ocelot->getNavigation()->moveTo((float) tileX + 0.5, tileY + 1, (float) tileZ + 0.5, speedModifier); tryTicks++; } else if (!ocelot->isSitting()) @@ -88,9 +92,9 @@ bool OcelotSitOnTileGoal::findNearestTile() if (dist < distSqr) { - this->tileX = x; - this->tileY = y; - this->tileZ = z; + tileX = x; + tileY = y; + tileZ = z; distSqr = dist; } } diff --git a/Minecraft.World/OcelotSitOnTileGoal.h b/Minecraft.World/OcelotSitOnTileGoal.h index 6a8d9ed5..2691915a 100644 --- a/Minecraft.World/OcelotSitOnTileGoal.h +++ b/Minecraft.World/OcelotSitOnTileGoal.h @@ -2,7 +2,7 @@ #include "Goal.h" -class Ozelot; +class Ocelot; class OcelotSitOnTileGoal : public Goal { @@ -13,8 +13,8 @@ private: static const double SIT_CHANCE; private: - Ozelot *ocelot; // Owner of this goal - float speed; + Ocelot *ocelot; // Owner of this goal + double speedModifier; int _tick; int tryTicks; int maxTicks; @@ -23,7 +23,7 @@ private: int tileZ; public: - OcelotSitOnTileGoal(Ozelot *ocelot, float speed); + OcelotSitOnTileGoal(Ocelot *ocelot, double speedModifier); bool canUse(); bool canContinueToUse(); diff --git a/Minecraft.World/OldChunkStorage.cpp b/Minecraft.World/OldChunkStorage.cpp index 50c29a96..31f4394f 100644 --- a/Minecraft.World/OldChunkStorage.cpp +++ b/Minecraft.World/OldChunkStorage.cpp @@ -239,7 +239,8 @@ void OldChunkStorage::save(LevelChunk *lc, Level *level, DataOutputStream *dos) dos->writeShort(SAVE_FILE_VERSION_NUMBER); dos->writeInt(lc->x); dos->writeInt(lc->z); - dos->writeLong(level->getTime()); + dos->writeLong(level->getGameTime()); + dos->writeLong(lc->inhabitedTime); PIXBeginNamedEvent(0,"Getting block data"); lc->writeCompressedBlockData(dos); @@ -283,7 +284,7 @@ void OldChunkStorage::save(LevelChunk *lc, Level *level, DataOutputStream *dos) vector *ticksInChunk = level->fetchTicksInChunk(lc, false); if (ticksInChunk != NULL) { - __int64 levelTime = level->getTime(); + __int64 levelTime = level->getGameTime(); ListTag *tickTags = new ListTag(); for( int i = 0; i < ticksInChunk->size(); i++ ) @@ -313,7 +314,8 @@ void OldChunkStorage::save(LevelChunk *lc, Level *level, CompoundTag *tag) level->checkSession(); tag->putInt(L"xPos", lc->x); tag->putInt(L"zPos", lc->z); - tag->putLong(L"LastUpdate", level->getTime()); + tag->putLong(L"LastUpdate", level->getGameTime()); + tag->putLong(L"InhabitedTime", lc->inhabitedTime); // 4J - changes here for new storage. Now have static storage for getting lighting data for block, data, and sky & block lighting. This // wasn't required in the original version as we could just reference the information in the level itself, but with our new storage system // the full data doesn't normally exist & so getSkyLightData/getBlockLightData etc. need somewhere to output this data. Making this static so @@ -372,7 +374,7 @@ void OldChunkStorage::save(LevelChunk *lc, Level *level, CompoundTag *tag) vector *ticksInChunk = level->fetchTicksInChunk(lc, false); if (ticksInChunk != NULL) { - __int64 levelTime = level->getTime(); + __int64 levelTime = level->getGameTime(); ListTag *tickTags = new ListTag(); for( int i = 0; i < ticksInChunk->size(); i++ ) @@ -384,6 +386,7 @@ void OldChunkStorage::save(LevelChunk *lc, Level *level, CompoundTag *tag) teTag->putInt(L"y", td.y); teTag->putInt(L"z", td.z); teTag->putInt(L"t", (int) (td.m_delay - levelTime)); + teTag->putInt(L"p", td.priorityTilt); tickTags->add(teTag); } @@ -428,6 +431,7 @@ void OldChunkStorage::loadEntities(LevelChunk *lc, Level *level, CompoundTag *ta LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis) { + PIXBeginNamedEvent(0,"Loading chunk"); short version = dis->readShort(); int x = dis->readInt(); int z = dis->readInt(); @@ -435,6 +439,11 @@ LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis) LevelChunk *levelChunk = new LevelChunk(level, x, z); + if (version >= SAVE_FILE_VERSION_CHUNK_INHABITED_TIME) + { + levelChunk->inhabitedTime = dis->readLong(); + } + levelChunk->readCompressedBlockData(dis); levelChunk->readCompressedDataData(dis); levelChunk->readCompressedSkyLightData(dis); @@ -451,7 +460,19 @@ LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis) levelChunk->terrainPopulated |= LevelChunk::sTerrainPostPostProcessed; } - dis->readFully(levelChunk->biomes); +#ifndef _CONTENT_PACKAGE + if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<biomes.length); + dis->readFully(dummyBiomes); + delete [] dummyBiomes.data; + } + else +#endif + { + dis->readFully(levelChunk->biomes); + } CompoundTag *tag = NbtIo::read(dis); @@ -459,6 +480,7 @@ LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis) if (tag->contains(L"TileTicks")) { + PIXBeginNamedEvent(0,"Loading TileTicks"); ListTag *tileTicks = (ListTag *) tag->getList(L"TileTicks"); if (tileTicks != NULL) @@ -467,13 +489,16 @@ LevelChunk *OldChunkStorage::load(Level *level, DataInputStream *dis) { CompoundTag *teTag = tileTicks->get(i); - level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t")); + level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t"), teTag->getInt(L"p")); } } + PIXEndNamedEvent(); } delete tag; + PIXEndNamedEvent(); + return levelChunk; } @@ -556,9 +581,18 @@ LevelChunk *OldChunkStorage::load(Level *level, CompoundTag *tag) } #endif - if (tag->contains(L"Biomes")) +#ifndef _CONTENT_PACKAGE + if(app.DebugSettingsOn() && app.GetGameSettingsDebugMask(ProfileManager.GetPrimaryPad())&(1L<setBiomes(tag->getByteArray(L"Biomes")); + if (tag->contains(L"Biomes")) + { + levelChunk->setBiomes(tag->getByteArray(L"Biomes")); + } } loadEntities(levelChunk, level, tag); @@ -573,7 +607,7 @@ LevelChunk *OldChunkStorage::load(Level *level, CompoundTag *tag) { CompoundTag *teTag = tileTicks->get(i); - level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t")); + level->forceAddTileTick(teTag->getInt(L"x"), teTag->getInt(L"y"), teTag->getInt(L"z"), teTag->getInt(L"i"), teTag->getInt(L"t"), teTag->getInt(L"p")); } } } diff --git a/Minecraft.World/OpenDoorGoal.cpp b/Minecraft.World/OpenDoorGoal.cpp index dbe5b410..b19592bb 100644 --- a/Minecraft.World/OpenDoorGoal.cpp +++ b/Minecraft.World/OpenDoorGoal.cpp @@ -6,7 +6,7 @@ OpenDoorGoal::OpenDoorGoal(Mob *mob, bool closeDoorAfter) : DoorInteractGoal(mob) { this->mob = mob; - this->closeDoor = closeDoorAfter; + closeDoor = closeDoorAfter; } bool OpenDoorGoal::canContinueToUse() diff --git a/Minecraft.World/OreFeature.cpp b/Minecraft.World/OreFeature.cpp index 75482a57..c057511b 100644 --- a/Minecraft.World/OreFeature.cpp +++ b/Minecraft.World/OreFeature.cpp @@ -12,7 +12,7 @@ void OreFeature::_init(int tile, int count, int targetTile) OreFeature::OreFeature(int tile, int count) { - _init(tile, count, Tile::rock_Id); + _init(tile, count, Tile::stone_Id); } OreFeature::OreFeature(int tile, int count, int targetTile) @@ -23,18 +23,18 @@ OreFeature::OreFeature(int tile, int count, int targetTile) bool OreFeature::place(Level *level, Random *random, int x, int y, int z) { PIXBeginNamedEvent(0,"Place Ore Feature"); - float dir = random->nextFloat() * PI; + float dir = random->nextFloat() * PI; - double x0 = x + 8 + Mth::sin(dir) * count / 8; - double x1 = x + 8 - Mth::sin(dir) * count / 8; - double z0 = z + 8 + Mth::cos(dir) * count / 8; - double z1 = z + 8 - Mth::cos(dir) * count / 8; + double x0 = x + 8 + Mth::sin(dir) * count / 8; + double x1 = x + 8 - Mth::sin(dir) * count / 8; + double z0 = z + 8 + Mth::cos(dir) * count / 8; + double z1 = z + 8 - Mth::cos(dir) * count / 8; - double y0 = y + random->nextInt(3) - 2; - double y1 = y + random->nextInt(3) - 2; + double y0 = y + random->nextInt(3) - 2; + double y1 = y + random->nextInt(3) - 2; bool collisionsExpected = false; - + LevelGenerationOptions *levelGenOptions = NULL; if( app.getLevelGenerationOptions() != NULL ) { @@ -44,7 +44,7 @@ bool OreFeature::place(Level *level, Random *random, int x, int y, int z) int minX = x0 - 1; int minY = y0 - 1; int minZ = z0 - 1; - + double maxss = count / 16; double maxr = (Mth::sin(PI) + 1) * maxss + 1; double maxhr = (Mth::sin(PI) + 1) * maxss + 1; @@ -55,23 +55,32 @@ bool OreFeature::place(Level *level, Random *random, int x, int y, int z) collisionsExpected = levelGenOptions->checkIntersects(minX, minY, minZ, maxX, maxY, maxZ); } - for (int d = 0; d <= count; d++) + bool doEarlyRejectTest = false; + if( y0 > level->getSeaLevel() ) + { + doEarlyRejectTest = true; + } + + for (int d = 0; d <= count; d++) { - double xx = x0 + (x1 - x0) * d / count; - double yy = y0 + (y1 - y0) * d / count; - double zz = z0 + (z1 - z0) * d / count; + double xx = x0 + (x1 - x0) * d / count; + double yy = y0 + (y1 - y0) * d / count; + double zz = z0 + (z1 - z0) * d / count; double ss = random->nextDouble() * count / 16; double r = (Mth::sin(d * PI / count) + 1) * ss + 1; - double hr = (Mth::sin(d * PI / count) + 1) * ss + 1; + double hr = r; //(Mth::sin(d * PI / count) + 1) * ss + 1; + + double halfR = r/2; + double halfHR = halfR; //hr/2; - int xt0 = Mth::floor(xx - r / 2); - int yt0 = Mth::floor(yy - hr / 2); - int zt0 = Mth::floor(zz - r / 2); - - int xt1 = Mth::floor(xx + r / 2); - int yt1 = Mth::floor(yy + hr / 2); - int zt1 = Mth::floor(zz + r / 2); + int xt0 = Mth::floor(xx - halfR); + int yt0 = Mth::floor(yy - halfHR); + int zt0 = Mth::floor(zz - halfR); + + int xt1 = Mth::floor(xx + halfR); + int yt1 = Mth::floor(yy + halfHR); + int zt1 = Mth::floor(zz + halfR); // 4J Stu Added to stop ore features generating areas previously place by game rule generation if(collisionsExpected && levelGenOptions != NULL) @@ -87,36 +96,49 @@ bool OreFeature::place(Level *level, Random *random, int x, int y, int z) // A large % of ore placement is entirely into the air. Attempt to identify some of these early, by check the corners // of the area we are placing in to see if we are going to (very probably) be entirely above the height stored in the heightmap - bool earlyReject = true; - if ( level->getHeightmap(xt0, zt0) >= yt0 ) earlyReject = false; - else if( level->getHeightmap(xt1, zt0) >= yt0 ) earlyReject = false; - else if( level->getHeightmap(xt0, zt1) >= yt0 ) earlyReject = false; - else if( level->getHeightmap(xt1, zt1) >= yt0 ) earlyReject = false; + if( doEarlyRejectTest ) + { + bool earlyReject = true; + if ( level->getHeightmap(xt0, zt0) >= yt0 ) earlyReject = false; + else if( level->getHeightmap(xt1, zt0) >= yt0 ) earlyReject = false; + else if( level->getHeightmap(xt0, zt1) >= yt0 ) earlyReject = false; + else if( level->getHeightmap(xt1, zt1) >= yt0 ) earlyReject = false; + + if( earlyReject ) continue; + } + + double xdxd,ydyd; + + double xd0 = ((xt0 + 0.5) - xx); + double yd0 = ((yt0 + 0.5) - yy); + double zd0 = ((zt0 + 0.5) - zz); - if( earlyReject ) continue; + double halfRSq = halfR * halfR; - for (int x2 = xt0; x2 <= xt1; x2++) + double xd = xd0; + for (int x2 = xt0; x2 <= xt1; x2++, xd++) { - double xd = ((x2 + 0.5) - xx) / (r / 2); - if (xd * xd < 1) + xdxd = xd * xd; + if (xdxd < halfRSq) { - for (int y2 = yt0; y2 <= yt1; y2++) + double yd = yd0; + for (int y2 = yt0; y2 <= yt1; y2++, yd++) { - double yd = ((y2 + 0.5) - yy) / (hr / 2); - if (xd * xd + yd * yd < 1) + ydyd = yd * yd; + if (xdxd + ydyd < halfRSq) { - for (int z2 = zt0; z2 <= zt1; z2++) + double zd = zd0; + for (int z2 = zt0; z2 <= zt1; z2++, zd++) { - double zd = ((z2 + 0.5) - zz) / (r / 2); - if (xd * xd + yd * yd + zd * zd < 1) + if (xdxd + ydyd + zd * zd < halfRSq) { - if (level->getTile(x2, y2, z2) == targetTile) - { - level->setTileNoUpdateNoLightCheck(x2, y2, z2, tile); // 4J changed from setTileNoUpdate + if ( level->getTile(x2, y2, z2) == targetTile) + { + level->setTileAndData(x2, y2, z2, tile, 0, Tile::UPDATE_INVISIBLE_NO_LIGHT); } } } - } + } } } } diff --git a/Minecraft.World/OreRecipies.cpp b/Minecraft.World/OreRecipies.cpp index f18e985c..387d059b 100644 --- a/Minecraft.World/OreRecipies.cpp +++ b/Minecraft.World/OreRecipies.cpp @@ -1,10 +1,3 @@ -// package net.minecraft.world.item.crafting; -// -// import net.minecraft.world.item.DyePowderItem; -// import net.minecraft.world.item.Item; -// import net.minecraft.world.item.ItemInstance; -// import net.minecraft.world.level.tile.Tile; - #include "stdafx.h" #include "net.minecraft.world.item.h" #include "DyePowderItem.h" @@ -13,25 +6,8 @@ #include "Recipes.h" #include "OreRecipies.h" - -/* - private Object[][] map = { - { - Tile.goldBlock, new ItemInstance(Item.goldIngot, 9) - }, { - Tile.ironBlock, new ItemInstance(Item.ironIngot, 9) - }, { - Tile.diamondBlock, new ItemInstance(Item.diamond, 9) - }, { - Tile.lapisBlock, new ItemInstance(Item.dye_powder, 9, DyePowderItem.BLUE) - }, - }; -*/ - void OreRecipies::_init() { - map = new vector [MAX_ORE_RECIPES]; - ADD_OBJECT(map[0],Tile::goldBlock); ADD_OBJECT(map[0],new ItemInstance(Item::goldIngot, 9)); @@ -46,10 +22,18 @@ void OreRecipies::_init() ADD_OBJECT(map[4],Tile::lapisBlock); ADD_OBJECT(map[4],new ItemInstance(Item::dye_powder, 9, DyePowderItem::BLUE)); + + ADD_OBJECT(map[5],Tile::redstoneBlock); + ADD_OBJECT(map[5],new ItemInstance(Item::redStone, 9)); + + ADD_OBJECT(map[6],Tile::coalBlock); + ADD_OBJECT(map[6],new ItemInstance(Item::coal, 9, CoalItem::STONE_COAL)); + + ADD_OBJECT(map[7],Tile::hayBlock); + ADD_OBJECT(map[7],new ItemInstance(Item::wheat, 9)); } void OreRecipies::addRecipes(Recipes *r) { - for (int i = 0; i < MAX_ORE_RECIPES; i++) { Tile *from = (Tile*) map[i].at(0)->tile; diff --git a/Minecraft.World/OreRecipies.h b/Minecraft.World/OreRecipies.h index fa226a8a..f2bef1f7 100644 --- a/Minecraft.World/OreRecipies.h +++ b/Minecraft.World/OreRecipies.h @@ -1,6 +1,6 @@ #pragma once -#define MAX_ORE_RECIPES 5 +#define MAX_ORE_RECIPES 8 class OreRecipies { @@ -10,7 +10,7 @@ public: OreRecipies() {_init();} private: - vector *map; + vector map[MAX_ORE_RECIPES]; public: void addRecipes(Recipes *r); diff --git a/Minecraft.World/OwnableEntity.h b/Minecraft.World/OwnableEntity.h new file mode 100644 index 00000000..ae6e5383 --- /dev/null +++ b/Minecraft.World/OwnableEntity.h @@ -0,0 +1,8 @@ +#pragma once + +class OwnableEntity +{ +public: + virtual wstring getOwnerUUID() = 0; + virtual shared_ptr getOwner() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/OwnerHurtByTargetGoal.cpp b/Minecraft.World/OwnerHurtByTargetGoal.cpp index e576f575..8250dc18 100644 --- a/Minecraft.World/OwnerHurtByTargetGoal.cpp +++ b/Minecraft.World/OwnerHurtByTargetGoal.cpp @@ -6,20 +6,31 @@ OwnerHurtByTargetGoal::OwnerHurtByTargetGoal(TamableAnimal *tameAnimal) : TargetGoal(tameAnimal, 32, false) { this->tameAnimal = tameAnimal; + timestamp = 0; setRequiredControlFlags(TargetGoal::TargetFlag); } bool OwnerHurtByTargetGoal::canUse() { if (!tameAnimal->isTame()) return false; - shared_ptr owner = tameAnimal->getOwner(); + shared_ptr owner = dynamic_pointer_cast( tameAnimal->getOwner() ); if (owner == NULL) return false; - ownerLastHurtBy = weak_ptr(owner->getLastHurtByMob()); - return canAttack(ownerLastHurtBy.lock(), false); + ownerLastHurtBy = weak_ptr(owner->getLastHurtByMob()); + int ts = owner->getLastHurtByMobTimestamp(); + + shared_ptr locked = ownerLastHurtBy.lock(); + return ts != timestamp && canAttack(locked, false) && tameAnimal->wantsToAttack(locked, owner); } void OwnerHurtByTargetGoal::start() { mob->setTarget(ownerLastHurtBy.lock()); + + shared_ptr owner = dynamic_pointer_cast( tameAnimal->getOwner() ); + if (owner != NULL) + { + timestamp = owner->getLastHurtByMobTimestamp(); + } + TargetGoal::start(); } \ No newline at end of file diff --git a/Minecraft.World/OwnerHurtByTargetGoal.h b/Minecraft.World/OwnerHurtByTargetGoal.h index 48b30313..2cdc9378 100644 --- a/Minecraft.World/OwnerHurtByTargetGoal.h +++ b/Minecraft.World/OwnerHurtByTargetGoal.h @@ -8,7 +8,8 @@ class OwnerHurtByTargetGoal : public TargetGoal { private: TamableAnimal *tameAnimal; // Owner of this goal - weak_ptr ownerLastHurtBy; + weak_ptr ownerLastHurtBy; + int timestamp; public: OwnerHurtByTargetGoal(TamableAnimal *tameAnimal); diff --git a/Minecraft.World/OwnerHurtTargetGoal.cpp b/Minecraft.World/OwnerHurtTargetGoal.cpp index c6c367d7..b7e74505 100644 --- a/Minecraft.World/OwnerHurtTargetGoal.cpp +++ b/Minecraft.World/OwnerHurtTargetGoal.cpp @@ -7,19 +7,30 @@ OwnerHurtTargetGoal::OwnerHurtTargetGoal(TamableAnimal *tameAnimal) : TargetGoal { this->tameAnimal = tameAnimal; setRequiredControlFlags(TargetGoal::TargetFlag); + timestamp = 0; } bool OwnerHurtTargetGoal::canUse() { if (!tameAnimal->isTame()) return false; - shared_ptr owner = tameAnimal->getOwner(); + shared_ptr owner = dynamic_pointer_cast( tameAnimal->getOwner() ); if (owner == NULL) return false; - ownerLastHurt = weak_ptr(owner->getLastHurtMob()); - return canAttack(ownerLastHurt.lock(), false); + ownerLastHurt = weak_ptr(owner->getLastHurtMob()); + int ts = owner->getLastHurtMobTimestamp(); + shared_ptr locked = ownerLastHurt.lock(); + return ts != timestamp && canAttack(locked, false) && tameAnimal->wantsToAttack(locked, owner); } void OwnerHurtTargetGoal::start() { mob->setTarget(ownerLastHurt.lock()); - TargetGoal::start(); + + shared_ptr owner = dynamic_pointer_cast( tameAnimal->getOwner() ); + if (owner != NULL) + { + timestamp = owner->getLastHurtMobTimestamp(); + + + TargetGoal::start(); + } } \ No newline at end of file diff --git a/Minecraft.World/OwnerHurtTargetGoal.h b/Minecraft.World/OwnerHurtTargetGoal.h index 71079645..1eba5957 100644 --- a/Minecraft.World/OwnerHurtTargetGoal.h +++ b/Minecraft.World/OwnerHurtTargetGoal.h @@ -8,7 +8,8 @@ class OwnerHurtTargetGoal : public TargetGoal { private: TamableAnimal *tameAnimal; // Owner of this goal - weak_ptr ownerLastHurt; + weak_ptr ownerLastHurt; + int timestamp; public: OwnerHurtTargetGoal(TamableAnimal *tameAnimal); diff --git a/Minecraft.World/Packet.cpp b/Minecraft.World/Packet.cpp index 0a59204c..93f02399 100644 --- a/Minecraft.World/Packet.cpp +++ b/Minecraft.World/Packet.cpp @@ -37,7 +37,7 @@ void Packet::staticCtor() map(14, false, true, false, false, typeid(PlayerActionPacket), PlayerActionPacket::create); map(15, false, true, false, false, typeid(UseItemPacket), UseItemPacket::create); - map(16, false, true, false, false, typeid(SetCarriedItemPacket), SetCarriedItemPacket::create); + map(16, true, true, true, false, typeid(SetCarriedItemPacket), SetCarriedItemPacket::create); // 4J-PB - we need to send to any client for the sleep in bed //map(17, true, false, false, false, EntityActionAtPositionPacket)); map(17, true, false, true, false, typeid(EntityActionAtPositionPacket), EntityActionAtPositionPacket::create); @@ -52,7 +52,7 @@ void Packet::staticCtor() map(24, true, false, false, true, typeid(AddMobPacket), AddMobPacket::create); map(25, true, false, false, false, typeid(AddPaintingPacket), AddPaintingPacket::create); map(26, true, false, false, false, typeid(AddExperienceOrbPacket), AddExperienceOrbPacket::create); // TODO New for 1.8.2 - Needs sendToAny? - //map(27, false, true, false, false, PlayerInputPacket)); + map(27, false, true, false, false, typeid(PlayerInputPacket), PlayerInputPacket::create); // 4J-PB - needs to go to any player, due to the knockback effect when a played is hit map(28, true, false, true, true, typeid(SetEntityMotionPacket), SetEntityMotionPacket::create); map(29, true, false, false, true, typeid(RemoveEntitiesPacket), RemoveEntitiesPacket::create); @@ -66,11 +66,12 @@ void Packet::staticCtor() // 4J - needs to go to any player, to create sound effect when a player is hit map(38, true, false, true, true, typeid(EntityEventPacket), EntityEventPacket::create); - map(39, true, false, true, false, typeid(SetRidingPacket), SetRidingPacket::create); + map(39, true, false, true, false, typeid(SetEntityLinkPacket), SetEntityLinkPacket::create); map(40, true, false, true, true, typeid(SetEntityDataPacket), SetEntityDataPacket::create); map(41, true, false, true, false, typeid(UpdateMobEffectPacket), UpdateMobEffectPacket::create); map(42, true, false, true, false, typeid(RemoveMobEffectPacket), RemoveMobEffectPacket::create); map(43, true, false, true, false, typeid(SetExperiencePacket), SetExperiencePacket::create); + map(44, true, false, true, false, typeid(UpdateAttributesPacket), UpdateAttributesPacket::create); map(50, true, false, true, true, typeid(ChunkVisibilityPacket), ChunkVisibilityPacket::create); map(51, true, false, true, true, typeid(BlockRegionUpdatePacket), BlockRegionUpdatePacket::create); // Changed to LevelChunkPacket in Java but we aren't using that @@ -83,7 +84,7 @@ void Packet::staticCtor() map(61, true, false, true, false, typeid(LevelEventPacket), LevelEventPacket::create); // 4J-PB - don't see the need for this, we can use 61 map(62, true, false, true, false, typeid(LevelSoundPacket), LevelSoundPacket::create); - //map(62, true, false, true, false, typeid(LevelSoundPacket), LevelSoundPacket::create); + map(63, true, false, true, false, typeid(LevelParticlesPacket), LevelParticlesPacket::create); map(70, true, false, false, false, typeid(GameEventPacket), GameEventPacket::create); map(71, true, false, false, false, typeid(AddGlobalEntityPacket), AddGlobalEntityPacket::create); @@ -107,6 +108,7 @@ void Packet::staticCtor() map(130, true, true, true, false, typeid(SignUpdatePacket), SignUpdatePacket::create); map(131, true, false, true, false, typeid(ComplexItemDataPacket), ComplexItemDataPacket::create); map(132, true, false, false, false, typeid(TileEntityDataPacket), TileEntityDataPacket::create); + map(133, true, false, true, false, typeid(TileEditorOpenPacket), TileEditorOpenPacket::create); // 4J Added map(150, false, true, false, false, typeid(CraftItemPacket), CraftItemPacket::create); @@ -136,6 +138,12 @@ void Packet::staticCtor() //map(203, true, true, true, false, ChatAutoCompletePacket.class); //map(204, false, true, true, false, ClientInformationPacket.class); map(205, false, true, true, false, typeid(ClientCommandPacket), ClientCommandPacket::create); + + map(206, true, false, true, false, typeid(SetObjectivePacket), SetObjectivePacket::create); + map(207, true, false, true, false, typeid(SetScorePacket), SetScorePacket::create); + map(208, true, false, true, false, typeid(SetDisplayObjectivePacket), SetDisplayObjectivePacket::create); + map(209, true, false, true, false, typeid(SetPlayerTeamPacket), SetPlayerTeamPacket::create); + map(250, true, true, true, false, typeid(CustomPayloadPacket), CustomPayloadPacket::create); // 4J Stu - These added 1.3.2, but don't think we need them //map(252, true, true, SharedKeyPacket.class); @@ -207,16 +215,25 @@ void Packet::map(int id, bool receiveOnClient, bool receiveOnServer, bool sendTo } // 4J Added to record data for outgoing packets -void Packet::recordOutgoingPacket(shared_ptr packet) +void Packet::recordOutgoingPacket(shared_ptr packet, int playerIndex) { #ifndef _CONTENT_PACKAGE #if PACKET_ENABLE_STAT_TRACKING - AUTO_VAR(it, outgoingStatistics.find(packet->getId())); +#if 0 + int idx = packet->getId(); +#else + int idx = playerIndex; + if( packet->getId() != 51 ) + { + idx = 100; + } +#endif + AUTO_VAR(it, outgoingStatistics.find(idx)); if( it == outgoingStatistics.end() ) { - Packet::PacketStatistics *packetStatistics = new PacketStatistics(packet->getId()); - outgoingStatistics[packet->getId()] = packetStatistics; + Packet::PacketStatistics *packetStatistics = new PacketStatistics(idx); + outgoingStatistics[idx] = packetStatistics; packetStatistics->addPacket(packet->getEstimatedSize()); } else @@ -227,77 +244,31 @@ void Packet::recordOutgoingPacket(shared_ptr packet) #endif } -void Packet::renderPacketStats(int id) -{ - AUTO_VAR(it, outgoingStatistics.find(id)); - - if( it != outgoingStatistics.end() ) - { - it->second->renderStats(); - } -} - -void Packet::renderAllPacketStats() +void Packet::updatePacketStatsPIX() { #ifndef _CONTENT_PACKAGE #if PACKET_ENABLE_STAT_TRACKING - Minecraft *pMinecraft = Minecraft::GetInstance(); - pMinecraft->gui->renderStackedGraph(Packet::renderPos, 512, renderableStats.size(), &Packet::getIndexedStatValue ); - - renderAllPacketStatsKey(); - - Packet::renderPos++; - Packet::renderPos%=511; -#endif -#endif -} - -void Packet::renderAllPacketStatsKey() -{ -#ifndef _CONTENT_PACKAGE -#if PACKET_ENABLE_STAT_TRACKING - Minecraft *pMinecraft = Minecraft::GetInstance(); - int total = Packet::renderableStats.size(); - for(unsigned int i = 0; i < total; ++i) + + for( AUTO_VAR(it, outgoingStatistics.begin()); it != outgoingStatistics.end(); it++ ) { - Packet::PacketStatistics *stat = Packet::renderableStats[i]; - float vary = (float)i/total; - int fColour = floor(vary * 0xffffff); - - int colour = 0xff000000 + fColour; - pMinecraft->gui->drawString( pMinecraft->font, stat->getLegendString(), 900, 30 + (10 * i), colour); + Packet::PacketStatistics *stat = it->second; + __int64 count = stat->getRunningCount(); + wchar_t pixName[256]; + swprintf_s(pixName,L"Packet count %d",stat->id); +// PIXReportCounter(pixName,(float)count); + __int64 total = stat->getRunningTotal(); + swprintf_s(pixName,L"Packet bytes %d",stat->id); + PIXReportCounter(pixName,(float)total); + stat->IncrementPos(); } #endif #endif } -__int64 Packet::getIndexedStatValue(unsigned int samplePos, unsigned int renderableId) -{ - __int64 val = 0; - -#ifndef _CONTENT_PACKAGE -#if PACKET_ENABLE_STAT_TRACKING - val = renderableStats[renderableId]->getCountSample(samplePos); -#endif -#endif - - return val; -} - - shared_ptr Packet::getPacket(int id) { - // 4J - removed try/catch - // try - // { + // 4J: Removed try/catch return idToCreateMap[id](); - // } - // catch (exception e) - // { - // // TODO 4J JEV print stack trace, newInstance doesnt throw an exception in c++ yet. - // printf("Skipping packet with id %d" , id); - // return NULL; - // } } void Packet::writeBytes(DataOutputStream *dataoutputstream, byteArray bytes) @@ -320,7 +291,7 @@ byteArray Packet::readBytes(DataInputStream *datainputstream) } byteArray bytes(size); - datainputstream->read(bytes); + datainputstream->readFully(bytes); return bytes; } @@ -446,18 +417,19 @@ wstring Packet::readUtf(DataInputStream *dis, int maxLength) // throws IOExcepti return builder; } +Packet::PacketStatistics::PacketStatistics(int id) : id( id ), count( 0 ), totalSize( 0 ), samplesPos( 0 ) +{ + memset(countSamples, 0, sizeof(countSamples)); + memset(sizeSamples, 0, sizeof(sizeSamples)); +} + void Packet::PacketStatistics::addPacket(int bytes) { - if(count == 0) - { - firstSampleTime = System::currentTimeMillis(); - } - count++; + countSamples[samplesPos]++; + sizeSamples[samplesPos] += bytes; + timeSamples[samplesPos] = System::currentTimeMillis(); totalSize += bytes; - - // 4J Added - countSamples[samplesPos & (512 - 1)]++; - sizeSamples[samplesPos & (512 - 1)] += (unsigned int) bytes; + count++; } int Packet::PacketStatistics::getCount() @@ -474,44 +446,45 @@ double Packet::PacketStatistics::getAverageSize() return (double) totalSize / count; } -void Packet::PacketStatistics::renderStats( ) +int Packet::PacketStatistics::getTotalSize() { -#ifndef _CONTENT_PACKAGE -#if PACKET_ENABLE_STAT_TRACKING - samplesPos++; - - countSamples[samplesPos & (512 - 1)] = 0; - sizeSamples[samplesPos & (512 - 1)] = 0; - - Minecraft *pMinecraft = Minecraft::GetInstance(); - pMinecraft->gui->renderGraph(512, samplesPos, countSamples, 1, 10, sizeSamples, 1, 50); -#endif -#endif + return totalSize; } -__int64 Packet::PacketStatistics::getCountSample(int samplePos) +__int64 Packet::PacketStatistics::getRunningTotal() { - if(samplePos == 511) + __int64 total = 0; + __int64 currentTime = System::currentTimeMillis(); + for( int i = 0; i < TOTAL_TICKS; i++ ) { - samplesPos++; - countSamples[samplesPos & (512 - 1)] = 0; - sizeSamples[samplesPos & (512 - 1)] = 0; + if( currentTime - timeSamples[i] <= 1000 ) + { + total += sizeSamples[i]; + } } - - return countSamples[samplePos] * 10; + return total; } -wstring Packet::PacketStatistics::getLegendString() +__int64 Packet::PacketStatistics::getRunningCount() { - static wchar_t string[128]; - double bps = 0.0; - if(firstSampleTime > 0) + __int64 total = 0; + __int64 currentTime = System::currentTimeMillis(); + for( int i = 0; i < TOTAL_TICKS; i++ ) { - float timeDiff = ((System::currentTimeMillis() - firstSampleTime)/1000); - if(timeDiff > 0) bps = totalSize / timeDiff; + if( currentTime - timeSamples[i] <= 1000 ) + { + total += countSamples[i]; + } } - swprintf(string, 128, L"id: %d , packets: %d , total: %d , bytes: %d, total: %d, %f Bps", id, countSamples[(samplesPos - 1) & (512 - 1)], count, sizeSamples[(samplesPos - 1) & (512 - 1)], totalSize, bps ); - return string; + return total; +} + +void Packet::PacketStatistics::IncrementPos() +{ + samplesPos = ( samplesPos + 1 ) % TOTAL_TICKS; + countSamples[samplesPos] = 0; + sizeSamples[samplesPos] = 0; + timeSamples[samplesPos] = 0; } bool Packet::canBeInvalidated() diff --git a/Minecraft.World/Packet.h b/Minecraft.World/Packet.h index 60410df3..7c30f6aa 100644 --- a/Minecraft.World/Packet.h +++ b/Minecraft.World/Packet.h @@ -21,26 +21,26 @@ public: int count; int totalSize; + static const int TOTAL_TICKS = 100; + // 4J Added - __int64 countSamples[512]; - __int64 sizeSamples[512]; + __int64 countSamples[TOTAL_TICKS]; + __int64 sizeSamples[TOTAL_TICKS]; + __int64 timeSamples[TOTAL_TICKS]; int samplesPos; - __int64 firstSampleTime; - public: const int id; public: - PacketStatistics(int id) : id( id ), count( 0 ), totalSize( 0 ), samplesPos( 0 ), firstSampleTime( 0 ) { countSamples[0] = 0; sizeSamples[0] = 0; } + PacketStatistics(int id); void addPacket(int bytes); int getCount(); + int getTotalSize(); double getAverageSize(); - - // 4J Added - void renderStats(); - __int64 getCountSample(int samplePos); - wstring getLegendString(); + __int64 getRunningTotal(); + __int64 getRunningCount(); + void IncrementPos(); }; // 4J JEV, replaces the static blocks. @@ -80,12 +80,8 @@ private: static vector renderableStats; static int renderPos; public: - static void recordOutgoingPacket(shared_ptr packet); - static void renderPacketStats(int id); - static void renderAllPacketStats(); - static void renderAllPacketStatsKey(); - static __int64 getIndexedStatValue(unsigned int samplePos, unsigned int renderableId); - + static void recordOutgoingPacket(shared_ptr packet, int playerIndex); + static void updatePacketStatsPIX(); private : static unordered_map statistics; //static int nextPrint; diff --git a/Minecraft.World/PacketListener.cpp b/Minecraft.World/PacketListener.cpp index 2f051d7d..09fbb052 100644 --- a/Minecraft.World/PacketListener.cpp +++ b/Minecraft.World/PacketListener.cpp @@ -139,7 +139,7 @@ void PacketListener::handleSetEntityData(shared_ptr packet) onUnhandledPacket( (shared_ptr ) packet); } -void PacketListener::handleRidePacket(shared_ptr packet) +void PacketListener::handleEntityLinkPacket(shared_ptr packet) { onUnhandledPacket( (shared_ptr ) packet); } @@ -388,6 +388,48 @@ bool PacketListener::canHandleAsyncPackets() return false; } + + +// 1.6.4 +void PacketListener::handleAddObjective(shared_ptr packet) +{ + onUnhandledPacket(packet); +} + +void PacketListener::handleSetScore(shared_ptr packet) +{ + onUnhandledPacket(packet); +} + +void PacketListener::handleSetDisplayObjective(shared_ptr packet) +{ + onUnhandledPacket(packet); +} + +void PacketListener::handleSetPlayerTeamPacket(shared_ptr packet) +{ + onUnhandledPacket(packet); +} + +void PacketListener::handleParticleEvent(shared_ptr packet) +{ + onUnhandledPacket(packet); +} + +void PacketListener::handleUpdateAttributes(shared_ptr packet) +{ + onUnhandledPacket(packet); +} + +void PacketListener::handleTileEditorOpen(shared_ptr tileEditorOpenPacket) +{ +} + +bool PacketListener::isDisconnected() +{ + return false; +} + // 4J Added void PacketListener::handleCraftItem(shared_ptr packet) diff --git a/Minecraft.World/PacketListener.h b/Minecraft.World/PacketListener.h index 93b14603..f63b6bc7 100644 --- a/Minecraft.World/PacketListener.h +++ b/Minecraft.World/PacketListener.h @@ -45,7 +45,7 @@ class SetEntityDataPacket; class SetEntityMotionPacket; class SetEquippedItemPacket; class SetHealthPacket; -class SetRidingPacket; +class SetEntityLinkPacket; class SetSpawnPositionPacket; class SetTimePacket; class SignUpdatePacket; @@ -86,6 +86,15 @@ class TileDestructionPacket; class ClientCommandPacket; class LevelChunksPacket; +// 1.6.4 +class SetObjectivePacket; +class SetScorePacket; +class SetDisplayObjectivePacket; +class SetPlayerTeamPacket; +class LevelParticlesPacket; +class UpdateAttributesPacket; +class TileEditorOpenPacket; + // 4J Added class CraftItemPacket; class TradeItemPacket; @@ -135,7 +144,7 @@ public: virtual void handleSetSpawn(shared_ptr packet); virtual void handleSetEntityMotion(shared_ptr packet); virtual void handleSetEntityData(shared_ptr packet); - virtual void handleRidePacket(shared_ptr packet); + virtual void handleEntityLinkPacket(shared_ptr packet); virtual void handleInteract(shared_ptr packet); virtual void handleEntityEvent(shared_ptr packet); virtual void handleSetHealth(shared_ptr packet); @@ -193,6 +202,16 @@ public: //virtual void handleLevelChunks(shared_ptr packet); virtual bool canHandleAsyncPackets(); + // 1.6.4 + virtual void handleAddObjective(shared_ptr packet); + virtual void handleSetScore(shared_ptr packet); + virtual void handleSetDisplayObjective(shared_ptr packet); + virtual void handleSetPlayerTeamPacket(shared_ptr packet); + virtual void handleParticleEvent(shared_ptr packet); + virtual void handleUpdateAttributes(shared_ptr packet); + virtual void handleTileEditorOpen(shared_ptr tileEditorOpenPacket); + virtual bool isDisconnected(); + // 4J Added virtual void handleCraftItem(shared_ptr packet); virtual void handleTradeItem(shared_ptr packet); diff --git a/Minecraft.World/Painting.cpp b/Minecraft.World/Painting.cpp index 0d8f35fe..208beb77 100644 --- a/Minecraft.World/Painting.cpp +++ b/Minecraft.World/Painting.cpp @@ -74,23 +74,34 @@ Painting::Painting(Level *level, int xTile, int yTile, int zTile, int dir) : Han } // 4J Stu - Added this so that we can use some shared_ptr functions that were needed in the ctor -void Painting::PaintingPostConstructor(int dir) +// 4J Stu - Added motive param for debugging/artists only +void Painting::PaintingPostConstructor(int dir, int motive) { - vector *survivableMotives = new vector(); - for (int i = 0 ; i < LAST_VALUE; i++) +#ifndef _CONTENT_PACKAGE + if (app.DebugArtToolsOn() && motive >= 0) { - this->motive = (Motive *)Motive::values[i]; + this->motive = (Motive *)Motive::values[motive]; setDir(dir); - if (survives()) - { - survivableMotives->push_back(this->motive); - } } - if (!survivableMotives->empty()) + else +#endif { - this->motive = survivableMotives->at(random->nextInt((int)survivableMotives->size())); + vector *survivableMotives = new vector(); + for (int i = 0 ; i < LAST_VALUE; i++) + { + this->motive = (Motive *)Motive::values[i]; + setDir(dir); + if (survives()) + { + survivableMotives->push_back(this->motive); + } + } + if (!survivableMotives->empty()) + { + this->motive = survivableMotives->at(random->nextInt((int)survivableMotives->size())); + } + setDir(dir); } - setDir(dir); } Painting::Painting(Level *level, int x, int y, int z, int dir, wstring motiveName) : HangingEntity( level , x, y, z, dir ) @@ -142,7 +153,16 @@ int Painting::getHeight() return motive->h; } -void Painting::dropItem() +void Painting::dropItem(shared_ptr causedBy) { + if ( (causedBy != NULL) && causedBy->instanceof(eTYPE_PLAYER) ) + { + shared_ptr player = dynamic_pointer_cast(causedBy); + if (player->abilities.instabuild) + { + return; + } + } + spawnAtLocation(shared_ptr(new ItemInstance(Item::painting)), 0.0f); } \ No newline at end of file diff --git a/Minecraft.World/Painting.h b/Minecraft.World/Painting.h index 7866b662..b47a012b 100644 --- a/Minecraft.World/Painting.h +++ b/Minecraft.World/Painting.h @@ -72,10 +72,6 @@ public: }; public: -// int dir; -// -// int xTile, yTile, zTile; - Motive *motive; private: @@ -88,7 +84,8 @@ public: Painting(Level *level, int x, int y, int z, int dir, wstring motiveName); // 4J Stu - Added this so that we can use some shared_ptr functions that were needed in the ctor - void PaintingPostConstructor(int dir); + // 4J Stu - Added motive param for debugging/artists only + void PaintingPostConstructor(int dir, int motive = -1); protected: //void defineSynchedData(); @@ -113,5 +110,5 @@ public: virtual int getWidth(); virtual int getHeight(); - virtual void dropItem(); + virtual void dropItem(shared_ptr causedBy); }; diff --git a/Minecraft.World/PanicGoal.cpp b/Minecraft.World/PanicGoal.cpp index da951ca2..564fa59d 100644 --- a/Minecraft.World/PanicGoal.cpp +++ b/Minecraft.World/PanicGoal.cpp @@ -6,16 +6,16 @@ #include "net.minecraft.world.phys.h" #include "PanicGoal.h" -PanicGoal::PanicGoal(PathfinderMob *mob, float speed) +PanicGoal::PanicGoal(PathfinderMob *mob, double speedModifier) { this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag); } bool PanicGoal::canUse() { - if (mob->getLastHurtByMob() == NULL) return false; + if (mob->getLastHurtByMob() == NULL && !mob->isOnFire()) return false; Vec3 *pos = RandomPos::getPos(dynamic_pointer_cast(mob->shared_from_this()), 5, 4); if (pos == NULL) return false; posX = pos->x; @@ -26,7 +26,7 @@ bool PanicGoal::canUse() void PanicGoal::start() { - mob->getNavigation()->moveTo(posX, posY, posZ, speed); + mob->getNavigation()->moveTo(posX, posY, posZ, speedModifier); } bool PanicGoal::canContinueToUse() diff --git a/Minecraft.World/PanicGoal.h b/Minecraft.World/PanicGoal.h index 03d82782..2db64a75 100644 --- a/Minecraft.World/PanicGoal.h +++ b/Minecraft.World/PanicGoal.h @@ -8,11 +8,11 @@ class PanicGoal : public Goal { private: PathfinderMob *mob; - float speed; + double speedModifier; double posX, posY, posZ; public: - PanicGoal(PathfinderMob *mob, float speed); + PanicGoal(PathfinderMob *mob, double speedModifier); virtual bool canUse(); virtual void start(); diff --git a/Minecraft.World/ParticleTypes.h b/Minecraft.World/ParticleTypes.h index d822008e..ecc2ab96 100644 --- a/Minecraft.World/ParticleTypes.h +++ b/Minecraft.World/ParticleTypes.h @@ -26,7 +26,9 @@ enum ePARTICLE_TYPE eParticleType_largeexplode, eParticleType_townaura, eParticleType_spell, + eParticleType_witchMagic, eParticleType_mobSpell, + eParticleType_mobSpellAmbient, eParticleType_instantSpell, eParticleType_magicCrit, eParticleType_dripWater, @@ -36,6 +38,7 @@ enum ePARTICLE_TYPE eParticleType_ender, // 4J Added - These are things that used the "portal" particle but are actually end related entities eParticleType_angryVillager, eParticleType_happyVillager, + eParticleType_fireworksspark, // 4J-JEV: In the java, the particle name was used to sneak parameters in for the Terrain and IconCrack particle constructors. diff --git a/Minecraft.World/PathFinder.cpp b/Minecraft.World/PathFinder.cpp index 878c74f1..029cf582 100644 --- a/Minecraft.World/PathFinder.cpp +++ b/Minecraft.World/PathFinder.cpp @@ -17,7 +17,7 @@ PathFinder::PathFinder(LevelSource *level, bool canPassDoors, bool canOpenDoors, this->canOpenDoors = canOpenDoors; this->avoidWater = avoidWater; this->canFloat = canFloat; - this->level = level; + this->level = level; } PathFinder::~PathFinder() @@ -35,17 +35,17 @@ PathFinder::~PathFinder() Path *PathFinder::findPath(Entity *from, Entity *to, float maxDist) { - return findPath(from, to->x, to->bb->y0, to->z, maxDist); + return findPath(from, to->x, to->bb->y0, to->z, maxDist); } Path *PathFinder::findPath(Entity *from, int x, int y, int z, float maxDist) { - return findPath(from, x + 0.5f, y + 0.5f, z + 0.5f, maxDist); + return findPath(from, x + 0.5f, y + 0.5f, z + 0.5f, maxDist); } Path *PathFinder::findPath(Entity *e, double xt, double yt, double zt, float maxDist) { - openSet.clear(); + openSet.clear(); nodes.clear(); bool resetAvoidWater = avoidWater; @@ -63,143 +63,144 @@ Path *PathFinder::findPath(Entity *e, double xt, double yt, double zt, float max avoidWater = false; } else startY = Mth::floor(e->bb->y0 + 0.5f); - Node *from = getNode((int) floor(e->bb->x0), startY, (int) floor(e->bb->z0)); - Node *to = getNode((int) floor(xt - e->bbWidth / 2), (int) floor(yt), (int) floor(zt - e->bbWidth / 2)); + Node *from = getNode((int) floor(e->bb->x0), startY, (int) floor(e->bb->z0)); + Node *to = getNode((int) floor(xt - e->bbWidth / 2), (int) floor(yt), (int) floor(zt - e->bbWidth / 2)); - Node *size = new Node((int) floor(e->bbWidth + 1), (int) floor(e->bbHeight + 1), (int) floor(e->bbWidth + 1)); - Path *path = findPath(e, from, to, size, maxDist); + Node *size = new Node((int) floor(e->bbWidth + 1), (int) floor(e->bbHeight + 1), (int) floor(e->bbWidth + 1)); + Path *path = findPath(e, from, to, size, maxDist); delete size; avoidWater = resetAvoidWater; - return path; + return path; } // function A*(start,goal) Path *PathFinder::findPath(Entity *e, Node *from, Node *to, Node *size, float maxDist) { - from->g = 0; - from->h = from->distanceToSqr(to); - from->f = from->h; + from->g = 0; + from->h = from->distanceToSqr(to); + from->f = from->h; - openSet.clear(); - openSet.insert(from); + openSet.clear(); + openSet.insert(from); - Node *closest = from; + Node *closest = from; - while (!openSet.isEmpty()) + while (!openSet.isEmpty()) { - Node *x = openSet.pop(); + Node *x = openSet.pop(); if (x->equals(to)) { - return reconstruct_path(from, to); - } + return reconstruct_path(from, to); + } - if (x->distanceToSqr(to) < closest->distanceToSqr(to)) + if (x->distanceToSqr(to) < closest->distanceToSqr(to)) { - closest = x; - } - x->closed = true; + closest = x; + } + x->closed = true; - int neighborCount = getNeighbors(e, x, size, to, maxDist); - for (int i = 0; i < neighborCount; i++) + int neighborCount = getNeighbors(e, x, size, to, maxDist); + for (int i = 0; i < neighborCount; i++) { - Node *y = neighbors->data[i]; + Node *y = neighbors->data[i]; - float tentative_g_score = x->g + x->distanceToSqr(y); - if (!y->inOpenSet() || tentative_g_score < y->g) + float tentative_g_score = x->g + x->distanceToSqr(y); + if (!y->inOpenSet() || tentative_g_score < y->g) { - y->cameFrom = x; - y->g = tentative_g_score; - y->h = y->distanceToSqr(to); - if (y->inOpenSet()) + y->cameFrom = x; + y->g = tentative_g_score; + y->h = y->distanceToSqr(to); + if (y->inOpenSet()) { - openSet.changeCost(y, y->g + y->h); - } + openSet.changeCost(y, y->g + y->h); + } else { - y->f = y->g + y->h; - openSet.insert(y); - } - } - } - } - - if (closest == from) return NULL; - return reconstruct_path(from, closest); + y->f = y->g + y->h; + openSet.insert(y); + } + } + } + } + + if (closest == from) return NULL; + return reconstruct_path(from, closest); } int PathFinder::getNeighbors(Entity *entity, Node *pos, Node *size, Node *target, float maxDist) { - int p = 0; + int p = 0; - int jumpSize = 0; - if (isFree(entity, pos->x, pos->y + 1, pos->z, size) == TYPE_OPEN) jumpSize = 1; + int jumpSize = 0; + if (isFree(entity, pos->x, pos->y + 1, pos->z, size) == TYPE_OPEN) jumpSize = 1; - Node *n = getNode(entity, pos->x, pos->y, pos->z + 1, size, jumpSize); - Node *w = getNode(entity, pos->x - 1, pos->y, pos->z, size, jumpSize); - Node *e = getNode(entity, pos->x + 1, pos->y, pos->z, size, jumpSize); - Node *s = getNode(entity, pos->x, pos->y, pos->z - 1, size, jumpSize); + Node *n = getNode(entity, pos->x, pos->y, pos->z + 1, size, jumpSize); + Node *w = getNode(entity, pos->x - 1, pos->y, pos->z, size, jumpSize); + Node *e = getNode(entity, pos->x + 1, pos->y, pos->z, size, jumpSize); + Node *s = getNode(entity, pos->x, pos->y, pos->z - 1, size, jumpSize); - if (n != NULL && !n->closed && n->distanceTo(target) < maxDist) neighbors->data[p++] = n; - if (w != NULL && !w->closed && w->distanceTo(target) < maxDist) neighbors->data[p++] = w; - if (e != NULL && !e->closed && e->distanceTo(target) < maxDist) neighbors->data[p++] = e; - if (s != NULL && !s->closed && s->distanceTo(target) < maxDist) neighbors->data[p++] = s; + if (n != NULL && !n->closed && n->distanceTo(target) < maxDist) neighbors->data[p++] = n; + if (w != NULL && !w->closed && w->distanceTo(target) < maxDist) neighbors->data[p++] = w; + if (e != NULL && !e->closed && e->distanceTo(target) < maxDist) neighbors->data[p++] = e; + if (s != NULL && !s->closed && s->distanceTo(target) < maxDist) neighbors->data[p++] = s; - return p; + return p; } Node *PathFinder::getNode(Entity *entity, int x, int y, int z, Node *size, int jumpSize) { - Node *best = NULL; + Node *best = NULL; int pathType = isFree(entity, x, y, z, size); if (pathType == TYPE_WALKABLE) return getNode(x, y, z); - if (pathType == TYPE_OPEN) best = getNode(x, y, z); - if (best == NULL && jumpSize > 0 && pathType != TYPE_FENCE && pathType != TYPE_TRAP && isFree(entity, x, y + jumpSize, z, size) == TYPE_OPEN) + if (pathType == TYPE_OPEN) best = getNode(x, y, z); + if (best == NULL && jumpSize > 0 && pathType != TYPE_FENCE && pathType != TYPE_TRAP && isFree(entity, x, y + jumpSize, z, size) == TYPE_OPEN) { - best = getNode(x, y + jumpSize, z); - y += jumpSize; - } + best = getNode(x, y + jumpSize, z); + y += jumpSize; + } - if (best != NULL) + if (best != NULL) { - int drop = 0; - int cost = 0; - while (y > 0) + int drop = 0; + int cost = 0; + while (y > 0) { cost = isFree(entity, x, y - 1, z, size); if (avoidWater && cost == TYPE_WATER) return NULL; if (cost != TYPE_OPEN) break; - // fell too far? - if (++drop >= 4) return NULL; - y--; + // fell too far? + if (++drop >= 4) return NULL; // 4J - rolling this back to pre-java 1.6.4 version as we're suspicious of the performance implications of this +// if (drop++ >= entity->getMaxFallDistance()) return NULL; + y--; - if (y > 0) best = getNode(x, y, z); - } - // fell into lava? - if (cost == TYPE_LAVA) return NULL; - } + if (y > 0) best = getNode(x, y, z); + } + // fell into lava? + if (cost == TYPE_LAVA) return NULL; + } - return best; + return best; } /*final*/ Node *PathFinder::getNode(int x, int y, int z) { - int i = Node::createHash(x, y, z); - Node *node; + int i = Node::createHash(x, y, z); + Node *node; AUTO_VAR(it, nodes.find(i)); - if ( it == nodes.end() ) + if ( it == nodes.end() ) { MemSect(54); - node = new Node(x, y, z); + node = new Node(x, y, z); MemSect(0); - nodes.insert( unordered_map::value_type(i, node) ); - } + nodes.insert( unordered_map::value_type(i, node) ); + } else { node = (*it).second; } - return node; + return node; } int PathFinder::isFree(Entity *entity, int x, int y, int z, Node *size) @@ -228,6 +229,24 @@ int PathFinder::isFree(Entity *entity, int x, int y, int z, Node *size, bool avo } Tile *tile = Tile::tiles[tileId]; + + // 4J Stu - Use new getTileRenderShape passing in the tileId we have already got + if (entity->level->getTileRenderShape(tileId) == Tile::SHAPE_RAIL) + { + int xt = Mth::floor(entity->x); + int yt = Mth::floor(entity->y); + int zt = Mth::floor(entity->z); + if (entity->level->getTileRenderShape(xt, yt, zt) == Tile::SHAPE_RAIL + || entity->level->getTileRenderShape(xt, yt - 1, zt) == Tile::SHAPE_RAIL) + { + continue; + } + else + { + return TYPE_FENCE; + } + } + if (tile->isPathfindable(entity->level, xx, yy, zz)) continue; if (canOpenDoors && tileId == Tile::door_wood_Id) continue; @@ -243,29 +262,29 @@ int PathFinder::isFree(Entity *entity, int x, int y, int z, Node *size, bool avo return TYPE_BLOCKED; } - return walkable ? TYPE_WALKABLE : TYPE_OPEN; + return walkable ? TYPE_WALKABLE : TYPE_OPEN; } // function reconstruct_path(came_from,current_node) Path *PathFinder::reconstruct_path(Node *from, Node *to) { - int count = 1; - Node *n = to; - while (n->cameFrom != NULL) + int count = 1; + Node *n = to; + while (n->cameFrom != NULL) { - count++; - n = n->cameFrom; - } - - NodeArray nodes = NodeArray(count); - n = to; - nodes.data[--count] = n; - while (n->cameFrom != NULL) + count++; + n = n->cameFrom; + } + + NodeArray nodes = NodeArray(count); + n = to; + nodes.data[--count] = n; + while (n->cameFrom != NULL) { - n = n->cameFrom; - nodes.data[--count] = n; - } + n = n->cameFrom; + nodes.data[--count] = n; + } Path *ret = new Path(nodes); delete [] nodes.data; - return ret; + return ret; } \ No newline at end of file diff --git a/Minecraft.World/PathFinder.h b/Minecraft.World/PathFinder.h index 87321264..1e35ccb5 100644 --- a/Minecraft.World/PathFinder.h +++ b/Minecraft.World/PathFinder.h @@ -9,12 +9,12 @@ class PathFinder private: LevelSource *level; - BinaryHeap openSet; + BinaryHeap openSet; // 4J Jev, was a IntHashMap, thought this was close enough. - unordered_map nodes; + unordered_map nodes; - NodeArray *neighbors; + NodeArray *neighbors; bool canPassDoors; bool canOpenDoors; @@ -25,30 +25,30 @@ public: PathFinder(LevelSource *level, bool canPassDoors, bool canOpenDoors, bool avoidWater, bool canFloat); ~PathFinder(); - Path *findPath(Entity *from, Entity *to, float maxDist); - Path *findPath(Entity *from, int x, int y, int z, float maxDist); + Path *findPath(Entity *from, Entity *to, float maxDist); + Path *findPath(Entity *from, int x, int y, int z, float maxDist); private: Path *findPath(Entity *e, double xt, double yt, double zt, float maxDist); - // function A*(start,goal) - Path *findPath(Entity *e, Node *from, Node *to, Node *size, float maxDist); - int getNeighbors(Entity *entity, Node *pos, Node *size, Node *target, float maxDist); - Node *getNode(Entity *entity, int x, int y, int z, Node *size, int jumpSize); - /*final*/ Node *getNode(int x, int y, int z); + // function A*(start,goal) + Path *findPath(Entity *e, Node *from, Node *to, Node *size, float maxDist); + int getNeighbors(Entity *entity, Node *pos, Node *size, Node *target, float maxDist); + Node *getNode(Entity *entity, int x, int y, int z, Node *size, int jumpSize); + /*final*/ Node *getNode(int x, int y, int z); public: static const int TYPE_TRAP = -4; static const int TYPE_FENCE = -3; static const int TYPE_LAVA = -2; - static const int TYPE_WATER = -1; - static const int TYPE_BLOCKED = 0; - static const int TYPE_OPEN = 1; + static const int TYPE_WATER = -1; + static const int TYPE_BLOCKED = 0; + static const int TYPE_OPEN = 1; static const int TYPE_WALKABLE = 2; int isFree(Entity *entity, int x, int y, int z, Node *size); static int isFree(Entity *entity, int x, int y, int z, Node *size, bool avoidWater, bool canOpenDoors, bool canPassDoors); - // function reconstruct_path(came_from,current_node) - Path *reconstruct_path(Node *from, Node *to); + // function reconstruct_path(came_from,current_node) + Path *reconstruct_path(Node *from, Node *to); }; \ No newline at end of file diff --git a/Minecraft.World/PathNavigation.cpp b/Minecraft.World/PathNavigation.cpp index 2bf01672..7cac052e 100644 --- a/Minecraft.World/PathNavigation.cpp +++ b/Minecraft.World/PathNavigation.cpp @@ -2,20 +2,22 @@ #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.pathfinder.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.control.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" #include "PathNavigation.h" -PathNavigation::PathNavigation(Mob *mob, Level *level, float maxDist) +PathNavigation::PathNavigation(Mob *mob, Level *level) { this->mob = mob; this->level = level; - this->maxDist = maxDist; + dist = mob->getAttribute(SharedMonsterAttributes::FOLLOW_RANGE); path = NULL; - speed = 0.0f; + speedModifier = 0.0; avoidSun = false; _tick = 0; lastStuckCheck = 0; @@ -67,9 +69,9 @@ void PathNavigation::setAvoidSun(bool avoidSun) this->avoidSun = avoidSun; } -void PathNavigation::setSpeed(float speed) +void PathNavigation::setSpeedModifier(double speedModifier) { - this->speed = speed; + this->speedModifier = speedModifier; } void PathNavigation::setCanFloat(bool canFloat) @@ -77,38 +79,43 @@ void PathNavigation::setCanFloat(bool canFloat) this->canFloat = canFloat; } +float PathNavigation::getMaxDist() +{ + return (float) dist->getValue(); +} + Path *PathNavigation::createPath(double x, double y, double z) { if (!canUpdatePath()) return NULL; - return level->findPath(mob->shared_from_this(), Mth::floor(x), (int) y, Mth::floor(z), maxDist, _canPassDoors, _canOpenDoors, avoidWater, canFloat); + return level->findPath(mob->shared_from_this(), Mth::floor(x), (int) y, Mth::floor(z), getMaxDist(), _canPassDoors, _canOpenDoors, avoidWater, canFloat); } -bool PathNavigation::moveTo(double x, double y, double z, float speed) +bool PathNavigation::moveTo(double x, double y, double z, double speedModifier) { MemSect(52); Path *newPath = createPath(Mth::floor(x), (int) y, Mth::floor(z)); MemSect(0); // No need to delete newPath here as this will be copied into the member variable path and the class can assume responsibility for it - return moveTo(newPath, speed); + return moveTo(newPath, speedModifier); } -Path *PathNavigation::createPath(shared_ptr target) +Path *PathNavigation::createPath(shared_ptr target) { if (!canUpdatePath()) return NULL; - return level->findPath(mob->shared_from_this(), target, maxDist, _canPassDoors, _canOpenDoors, avoidWater, canFloat); + return level->findPath(mob->shared_from_this(), target, getMaxDist(), _canPassDoors, _canOpenDoors, avoidWater, canFloat); } -bool PathNavigation::moveTo(shared_ptr target, float speed) +bool PathNavigation::moveTo(shared_ptr target, double speedModifier) { MemSect(53); Path *newPath = createPath(target); MemSect(0); // No need to delete newPath here as this will be copied into the member variable path and the class can assume responsibility for it - if (newPath != NULL) return moveTo(newPath, speed); + if (newPath != NULL) return moveTo(newPath, speedModifier); else return false; } -bool PathNavigation::moveTo(Path *newPath, float speed) +bool PathNavigation::moveTo(Path *newPath, double speedModifier) { if(newPath == NULL) { @@ -128,7 +135,7 @@ bool PathNavigation::moveTo(Path *newPath, float speed) if (avoidSun) trimPathFromSun(); if (path->getSize() == 0) return false; - this->speed = speed; + this->speedModifier = speedModifier; Vec3 *mobPos = getTempMobPos(); lastStuckCheck = _tick; lastStuckCheckPos->x = mobPos->x; @@ -153,7 +160,7 @@ void PathNavigation::tick() Vec3 *target = path->currentPos(mob->shared_from_this()); if (target == NULL) return; - mob->getMoveControl()->setWantedPosition(target->x, target->y, target->z, speed); + mob->getMoveControl()->setWantedPosition(target->x, target->y, target->z, speedModifier); } void PathNavigation::updatePath() diff --git a/Minecraft.World/PathNavigation.h b/Minecraft.World/PathNavigation.h index b8a8cfd6..9b68637a 100644 --- a/Minecraft.World/PathNavigation.h +++ b/Minecraft.World/PathNavigation.h @@ -10,8 +10,8 @@ private: Mob *mob; Level *level; Path *path; - float speed; - float maxDist; + double speedModifier; + AttributeInstance *dist; bool avoidSun; int _tick; int lastStuckCheck; @@ -23,7 +23,7 @@ private: bool canFloat; public: - PathNavigation(Mob *mob, Level *level, float maxDist); + PathNavigation(Mob *mob, Level *level); ~PathNavigation(); void setAvoidWater(bool avoidWater); @@ -33,13 +33,14 @@ public: void setCanPassDoors(bool canPass); bool canOpenDoors(); void setAvoidSun(bool avoidSun); - void setSpeed(float speed); + void setSpeedModifier(double speedModifier); void setCanFloat(bool canFloat); + float getMaxDist(); Path *createPath(double x, double y, double z); - bool moveTo(double x, double y, double z, float speed); - Path *createPath(shared_ptr target); - bool moveTo(shared_ptr target, float speed); - bool moveTo(Path *newPath, float speed); + bool moveTo(double x, double y, double z, double speedModifier); + Path *createPath(shared_ptr target); + bool moveTo(shared_ptr target, double speedModifier); + bool moveTo(Path *newPath, double speedModifier); Path *getPath(); void tick(); diff --git a/Minecraft.World/PathfinderMob.cpp b/Minecraft.World/PathfinderMob.cpp index b72e064f..c01790e7 100644 --- a/Minecraft.World/PathfinderMob.cpp +++ b/Minecraft.World/PathfinderMob.cpp @@ -1,12 +1,17 @@ #include "stdafx.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.animal.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.ai.goal.h" +#include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.pathfinder.h" #include "net.minecraft.world.phys.h" #include "SharedConstants.h" #include "PathfinderMob.h" - +AttributeModifier *PathfinderMob::SPEED_MODIFIER_FLEEING = (new AttributeModifier(eModifierId_MOB_FLEEING, 2.0f, AttributeModifier::OPERATION_MULTIPLY_TOTAL))->setSerialize(false); PathfinderMob::PathfinderMob(Level *level) : Mob( level ) { @@ -14,6 +19,11 @@ PathfinderMob::PathfinderMob(Level *level) : Mob( level ) attackTarget = nullptr; holdGround = false; fleeTime = 0; + + restrictRadius = -1; + restrictCenter = new Pos(0, 0, 0); + addedLeashRestrictionGoal = false; + leashRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0f); } bool PathfinderMob::shouldHoldGround() @@ -24,11 +34,20 @@ bool PathfinderMob::shouldHoldGround() PathfinderMob::~PathfinderMob() { delete path; + delete restrictCenter; + delete leashRestrictionGoal; } void PathfinderMob::serverAiStep() { - if (fleeTime > 0) fleeTime--; + if (fleeTime > 0) + { + if (--fleeTime == 0) + { + AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + speed->removeModifier(SPEED_MODIFIER_FLEEING); + } + } holdGround = shouldHoldGround(); float maxDist = 16; @@ -124,7 +143,7 @@ void PathfinderMob::serverAiStep() double yd = target->y - yFloor; float yRotD = (float) (atan2(zd, xd) * 180 / PI) - 90; float rotDiff = Mth::wrapDegrees(yRotD - yRot); - yya = runSpeed; + yya = (float) getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue(); if (rotDiff > MAX_TURN) { rotDiff = MAX_TURN; @@ -161,7 +180,7 @@ void PathfinderMob::serverAiStep() lookAt(attackTarget, 30, 30); } - if (this->horizontalCollision && !isPathFinding()) jumping = true; + if (horizontalCollision && !isPathFinding()) jumping = true; if (random->nextFloat() < 0.8f && (inWater || inLava)) jumping = true; } @@ -250,12 +269,108 @@ void PathfinderMob::setAttackTarget(shared_ptr attacker) attackTarget = attacker; } -float PathfinderMob::getWalkingSpeedModifier() +// might move to navigation, might make area +bool PathfinderMob::isWithinRestriction() +{ + return isWithinRestriction(Mth::floor(x), Mth::floor(y), Mth::floor(z)); +} + +bool PathfinderMob::isWithinRestriction(int x, int y, int z) +{ + if (restrictRadius == -1) return true; + return restrictCenter->distSqr(x, y, z) < restrictRadius * restrictRadius; +} + +void PathfinderMob::restrictTo(int x, int y, int z, int radius) +{ + restrictCenter->set(x, y, z); + restrictRadius = radius; +} + +Pos *PathfinderMob::getRestrictCenter() +{ + return restrictCenter; +} + +float PathfinderMob::getRestrictRadius() +{ + return restrictRadius; +} + +void PathfinderMob::clearRestriction() +{ + restrictRadius = -1; +} + +bool PathfinderMob::hasRestriction() +{ + return restrictRadius != -1; +} + +void PathfinderMob::tickLeash() +{ + Mob::tickLeash(); + + if (isLeashed() && getLeashHolder() != NULL && getLeashHolder()->level == this->level) + { + // soft restriction + shared_ptr leashHolder = getLeashHolder(); + restrictTo((int) leashHolder->x, (int) leashHolder->y, (int) leashHolder->z, 5); + + float _distanceTo = distanceTo(leashHolder); + + shared_ptr tamabaleAnimal = shared_from_this()->instanceof(eTYPE_TAMABLE_ANIMAL) ? dynamic_pointer_cast(shared_from_this()) : nullptr; + if ( (tamabaleAnimal != NULL) && tamabaleAnimal->isSitting() ) + { + if (_distanceTo > 10) + { + dropLeash(true, true); + } + return; + } + + if (!addedLeashRestrictionGoal) + { + goalSelector.addGoal(2, leashRestrictionGoal, false); + getNavigation()->setAvoidWater(false); + addedLeashRestrictionGoal = true; + } + + onLeashDistance(_distanceTo); + + if (_distanceTo > 4) + { + // harder restriction + getNavigation()->moveTo(leashHolder, 1.0); + } + if (_distanceTo > 6) + { + // hardest restriction + double dx = (leashHolder->x - x) / _distanceTo; + double dy = (leashHolder->y - y) / _distanceTo; + double dz = (leashHolder->z - z) / _distanceTo; + + xd += dx * abs(dx) * .4; + yd += dy * abs(dy) * .4; + zd += dz * abs(dz) * .4; + } + if (_distanceTo > 10) + { + dropLeash(true, true); + } + + } + else if (!isLeashed() && addedLeashRestrictionGoal) + { + addedLeashRestrictionGoal = false; + goalSelector.removeGoal(leashRestrictionGoal); + getNavigation()->setAvoidWater(true); + clearRestriction(); + } +} + +void PathfinderMob::onLeashDistance(float distanceToLeashHolder) { - if (useNewAi()) return 1.0f; - float speed = Mob::getWalkingSpeedModifier(); - if (fleeTime > 0) speed *= 2; - return speed; } bool PathfinderMob::couldWander() diff --git a/Minecraft.World/PathfinderMob.h b/Minecraft.World/PathfinderMob.h index fdbadf8c..1f2b86c7 100644 --- a/Minecraft.World/PathfinderMob.h +++ b/Minecraft.World/PathfinderMob.h @@ -7,6 +7,9 @@ class Path; class PathfinderMob : public Mob { +public: + static AttributeModifier *SPEED_MODIFIER_FLEEING; + private: static const int MAX_TURN = 30; @@ -22,6 +25,13 @@ protected: bool holdGround; int fleeTime; +private: + Pos *restrictCenter; + float restrictRadius; + Goal *leashRestrictionGoal; + bool addedLeashRestrictionGoal; + +protected: virtual bool shouldHoldGround(); virtual void serverAiStep(); virtual void findRandomStrollLocation(int quadrant = -1); @@ -35,13 +45,23 @@ protected: public: virtual bool canSpawn(); - bool isPathFinding(); - void setPath(Path *path); - shared_ptr getAttackTarget(); - void setAttackTarget(shared_ptr attacker); + virtual bool isPathFinding(); + virtual void setPath(Path *path); + virtual shared_ptr getAttackTarget(); + virtual void setAttackTarget(shared_ptr attacker); + + // might move to navigation, might make area + virtual bool isWithinRestriction(); + virtual bool isWithinRestriction(int x, int y, int z); + virtual void restrictTo(int x, int y, int z, int radius); + virtual Pos *getRestrictCenter(); + virtual float getRestrictRadius(); + virtual void clearRestriction(); + virtual bool hasRestriction(); protected: - float getWalkingSpeedModifier(); + void tickLeash(); + void onLeashDistance(float distanceToLeashHolder); // 4J added public: diff --git a/Minecraft.World/PickaxeItem.cpp b/Minecraft.World/PickaxeItem.cpp index 5876b9bb..05177e7b 100644 --- a/Minecraft.World/PickaxeItem.cpp +++ b/Minecraft.World/PickaxeItem.cpp @@ -2,37 +2,37 @@ #include "net.minecraft.world.level.tile.h" #include "PickaxeItem.h" -TileArray *PickaxeItem::diggables = NULL; +TileArray PickaxeItem::diggables; void PickaxeItem::staticCtor() { - PickaxeItem::diggables = new TileArray( PICKAXE_DIGGABLES); - diggables->data[0] = Tile::stoneBrick; - diggables->data[1] = Tile::stoneSlab; - diggables->data[2] = Tile::stoneSlabHalf; - diggables->data[3] = Tile::rock; - diggables->data[4] = Tile::sandStone; - diggables->data[5] = Tile::mossStone; - diggables->data[6] = Tile::ironOre; - diggables->data[7] = Tile::ironBlock; - diggables->data[8] = Tile::coalOre; - diggables->data[9] = Tile::goldBlock; - diggables->data[10] = Tile::goldOre; - diggables->data[11] = Tile::diamondOre; - diggables->data[12] = Tile::diamondBlock; - diggables->data[13] = Tile::ice; - diggables->data[14] = Tile::hellRock; - diggables->data[15] = Tile::lapisOre; - diggables->data[16] = Tile::lapisBlock; - // 4J - brought forward from 1.2.3 - diggables->data[17] = Tile::redStoneOre; - diggables->data[18] = Tile::redStoneOre_lit; - diggables->data[19] = Tile::rail; - diggables->data[20] = Tile::detectorRail; - diggables->data[21] = Tile::goldenRail; + PickaxeItem::diggables = TileArray( PICKAXE_DIGGABLES); + diggables.data[0] = Tile::cobblestone; + diggables.data[1] = Tile::stoneSlab; + diggables.data[2] = Tile::stoneSlabHalf; + diggables.data[3] = Tile::stone; + diggables.data[4] = Tile::sandStone; + diggables.data[5] = Tile::mossyCobblestone; + diggables.data[6] = Tile::ironOre; + diggables.data[7] = Tile::ironBlock; + diggables.data[8] = Tile::coalOre; + diggables.data[9] = Tile::goldBlock; + diggables.data[10] = Tile::goldOre; + diggables.data[11] = Tile::diamondOre; + diggables.data[12] = Tile::diamondBlock; + diggables.data[13] = Tile::ice; + diggables.data[14] = Tile::netherRack; + diggables.data[15] = Tile::lapisOre; + diggables.data[16] = Tile::lapisBlock; + diggables.data[17] = Tile::redStoneOre; + diggables.data[18] = Tile::redStoneOre_lit; + diggables.data[19] = Tile::rail; + diggables.data[20] = Tile::detectorRail; + diggables.data[21] = Tile::goldenRail; + diggables.data[21] = Tile::activatorRail; } -PickaxeItem::PickaxeItem(int id, const Tier *tier) : DiggerItem(id, 2, tier, diggables) +PickaxeItem::PickaxeItem(int id, const Tier *tier) : DiggerItem(id, 2, tier, &diggables) { } @@ -54,9 +54,9 @@ bool PickaxeItem::canDestroySpecial(Tile *tile) // 4J - brought forward from 1.2.3 float PickaxeItem::getDestroySpeed(shared_ptr itemInstance, Tile *tile) { - if (tile != NULL && (tile->material == Material::metal || tile->material == Material::heavyMetal || tile->material == Material::stone)) + if (tile != NULL && (tile->material == Material::metal || tile->material == Material::heavyMetal || tile->material == Material::stone)) { - return speed; - } - return DiggerItem::getDestroySpeed(itemInstance, tile); + return speed; + } + return DiggerItem::getDestroySpeed(itemInstance, tile); } diff --git a/Minecraft.World/PickaxeItem.h b/Minecraft.World/PickaxeItem.h index 52dac510..36caf49a 100644 --- a/Minecraft.World/PickaxeItem.h +++ b/Minecraft.World/PickaxeItem.h @@ -2,12 +2,12 @@ #include "DiggerItem.h" -#define PICKAXE_DIGGABLES 22 +#define PICKAXE_DIGGABLES 23 class PickaxeItem : public DiggerItem { private: - static TileArray *diggables; + static TileArray diggables; public: // static void staticCtor(); diff --git a/Minecraft.World/Pig.cpp b/Minecraft.World/Pig.cpp index b556a936..cc042f58 100644 --- a/Minecraft.World/Pig.cpp +++ b/Minecraft.World/Pig.cpp @@ -6,6 +6,7 @@ #include "net.minecraft.world.level.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.entity.ai.navigation.h" #include "net.minecraft.world.entity.item.h" @@ -23,23 +24,20 @@ Pig::Pig(Level *level) : Animal( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_PIG; // 4J - was L"/mob/pig.png"; - this->setSize(0.9f, 0.9f); + setSize(0.9f, 0.9f); getNavigation()->setAvoidWater(true); - float walkSpeed = 0.25f; goalSelector.addGoal(0, new FloatGoal(this)); - goalSelector.addGoal(1, new PanicGoal(this, 0.38f)); - goalSelector.addGoal(2, controlGoal = new ControlledByPlayerGoal(this, 0.34f, walkSpeed)); - goalSelector.addGoal(3, new BreedGoal(this, walkSpeed)); - goalSelector.addGoal(4, new TemptGoal(this, 0.3f, Item::carrotOnAStick_Id, false)); - goalSelector.addGoal(4, new TemptGoal(this, 0.25f, Item::carrots_Id, false)); - goalSelector.addGoal(5, new FollowParentGoal(this, 0.28f)); - goalSelector.addGoal(6, new RandomStrollGoal(this, walkSpeed)); + goalSelector.addGoal(1, new PanicGoal(this, 1.25)); + goalSelector.addGoal(2, controlGoal = new ControlledByPlayerGoal(this, 0.3f, 0.25f)); + goalSelector.addGoal(3, new BreedGoal(this, 1.0)); + goalSelector.addGoal(4, new TemptGoal(this, 1.2, Item::carrotOnAStick_Id, false)); + goalSelector.addGoal(4, new TemptGoal(this, 1.2, Item::carrots_Id, false)); + goalSelector.addGoal(5, new FollowParentGoal(this, 1.1)); + goalSelector.addGoal(6, new RandomStrollGoal(this, 1.0)); goalSelector.addGoal(7, new LookAtPlayerGoal(this, typeid(Player), 6)); goalSelector.addGoal(8, new RandomLookAroundGoal(this)); } @@ -49,9 +47,17 @@ bool Pig::useNewAi() return true; } -int Pig::getMaxHealth() +void Pig::registerAttributes() +{ + Animal::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(10); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f); +} + +void Pig::newServerAiStep() { - return 10; + Animal::newServerAiStep(); } bool Pig::canBeControlledByRider() @@ -94,9 +100,14 @@ int Pig::getDeathSound() return eSoundType_MOB_PIG_DEATH; } -bool Pig::interact(shared_ptr player) +void Pig::playStepSound(int xt, int yt, int zt, int t) +{ + playSound(eSoundType_MOB_PIG_STEP, 0.15f, 1); +} + +bool Pig::mobInteract(shared_ptr player) { - if(!Animal::interact(player)) + if(!Animal::mobInteract(player)) { if (hasSaddle() && !level->isClientSide && (rider.lock() == NULL || rider.lock() == player)) { @@ -162,7 +173,7 @@ void Pig::thunderHit(const LightningBolt *lightningBolt) void Pig::causeFallDamage(float distance) { Animal::causeFallDamage(distance); - if (distance > 5 && dynamic_pointer_cast( rider.lock() ) != NULL) + if ( (distance > 5) && rider.lock() != NULL && rider.lock()->instanceof(eTYPE_PLAYER) ) { (dynamic_pointer_cast(rider.lock()))->awardStat(GenericStats::flyPig(),GenericStats::param_flyPig()); } diff --git a/Minecraft.World/Pig.h b/Minecraft.World/Pig.h index adcfbf4e..9b7183da 100644 --- a/Minecraft.World/Pig.h +++ b/Minecraft.World/Pig.h @@ -21,7 +21,12 @@ public: Pig(Level *level); virtual bool useNewAi(); - virtual int getMaxHealth(); + +protected: + virtual void registerAttributes(); + virtual void newServerAiStep(); + +public: virtual bool canBeControlledByRider(); protected: @@ -35,9 +40,10 @@ protected: virtual int getAmbientSound(); virtual int getHurtSound(); virtual int getDeathSound(); + virtual void playStepSound(int xt, int yt, int zt, int t); public: - virtual bool interact(shared_ptr player); + virtual bool mobInteract(shared_ptr player); protected: virtual int getDeathLoot(); diff --git a/Minecraft.World/PigZombie.cpp b/Minecraft.World/PigZombie.cpp index cc060484..7a736c9a 100644 --- a/Minecraft.World/PigZombie.cpp +++ b/Minecraft.World/PigZombie.cpp @@ -3,7 +3,9 @@ #include "net.minecraft.world.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.phys.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.item.enchantment.h" #include "net.minecraft.world.entity.item.h" @@ -12,38 +14,31 @@ #include "..\Minecraft.Client\Textures.h" #include "SoundTypes.h" - - -shared_ptr PigZombie::sword; - -void PigZombie::staticCtor() -{ - PigZombie::sword = shared_ptr( new ItemInstance(Item::sword_gold, 1) ); -} +AttributeModifier *PigZombie::SPEED_MODIFIER_ATTACKING = (new AttributeModifier(eModifierId_MOB_PIG_ATTACKSPEED, 0.45, AttributeModifier::OPERATION_ADDITION))->setSerialize(false); void PigZombie::_init() { + registerAttributes(); + angerTime = 0; playAngrySoundIn = 0; + lastAttackTarget = nullptr; } PigZombie::PigZombie(Level *level) : Zombie( level ) { - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that - // the derived version of the function is called - - // 4J Stu - Zombie has already called this, and we don't override it so the Zombie one is the most derived version anyway - //this->defineSynchedData(); + _init(); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + fireImmune = true; +} - _init(); +void PigZombie::registerAttributes() +{ + Zombie::registerAttributes(); - this->textureIdx = TN_MOB_PIGZOMBIE; // 4J was L"/mob/pigzombie.png"; - runSpeed = 0.5f; - attackDamage = 5; - this->fireImmune = true; + getAttribute(SPAWN_REINFORCEMENTS_CHANCE)->setBaseValue(0); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.5f); + getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(5); } bool PigZombie::useNewAi() @@ -51,39 +46,45 @@ bool PigZombie::useNewAi() return false; } -int PigZombie::getTexture() -{ - return textureIdx; -} - void PigZombie::tick() { - runSpeed = attackTarget != NULL ? 0.95f : 0.5f; - if (playAngrySoundIn > 0) + if (lastAttackTarget != attackTarget && !level->isClientSide) + { + AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + speed->removeModifier(SPEED_MODIFIER_ATTACKING); + + if (attackTarget != NULL) + { + speed->addModifier(new AttributeModifier(*SPEED_MODIFIER_ATTACKING)); + } + } + lastAttackTarget = attackTarget; + + if (playAngrySoundIn > 0) { - if (--playAngrySoundIn == 0) + if (--playAngrySoundIn == 0) { - level->playSound(shared_from_this(), eSoundType_MOB_ZOMBIEPIG_ZPIGANGRY, getSoundVolume() * 2, ((random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f) * 1.8f); - } - } - Zombie::tick(); + playSound(eSoundType_MOB_ZOMBIEPIG_ZPIGANGRY, getSoundVolume() * 2, ((random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f) * 1.8f); + } + } + Zombie::tick(); } bool PigZombie::canSpawn() { - return level->difficulty > Difficulty::PEACEFUL && level->isUnobstructed(bb) && level->getCubes(shared_from_this(), bb)->empty() && !level->containsAnyLiquid(bb); + return level->difficulty > Difficulty::PEACEFUL && level->isUnobstructed(bb) && level->getCubes(shared_from_this(), bb)->empty() && !level->containsAnyLiquid(bb); } void PigZombie::addAdditonalSaveData(CompoundTag *tag) { - Zombie::addAdditonalSaveData(tag); - tag->putShort(L"Anger", (short) angerTime); + Zombie::addAdditonalSaveData(tag); + tag->putShort(L"Anger", (short) angerTime); } void PigZombie::readAdditionalSaveData(CompoundTag *tag) { - Zombie::readAdditionalSaveData(tag); - angerTime = tag->getShort(L"Anger"); + Zombie::readAdditionalSaveData(tag); + angerTime = tag->getShort(L"Anger"); } shared_ptr PigZombie::findAttackTarget() @@ -97,51 +98,51 @@ shared_ptr PigZombie::findAttackTarget() #endif #endif - if (angerTime == 0) return nullptr; - return Zombie::findAttackTarget(); + if (angerTime == 0) return nullptr; + return Zombie::findAttackTarget(); } -bool PigZombie::hurt(DamageSource *source, int dmg) +bool PigZombie::hurt(DamageSource *source, float dmg) { shared_ptr sourceEntity = source->getEntity(); - if (dynamic_pointer_cast(sourceEntity) != NULL) + if ( sourceEntity != NULL && sourceEntity->instanceof(eTYPE_PLAYER) ) { - vector > *nearby = level->getEntities( shared_from_this(), bb->grow(32, 32, 32)); + vector > *nearby = level->getEntities( shared_from_this(), bb->grow(32, 32, 32)); AUTO_VAR(itEnd, nearby->end()); for (AUTO_VAR(it, nearby->begin()); it != itEnd; it++) { - shared_ptr e = *it; //nearby->at(i); - if (dynamic_pointer_cast(e) != NULL) + shared_ptr e = *it; //nearby->at(i); + if ( e->instanceof(eTYPE_PIGZOMBIE) ) { - shared_ptr pigZombie = dynamic_pointer_cast(e); - pigZombie->alert(sourceEntity); - } - } - alert(sourceEntity); - } - return Zombie::hurt(source, dmg); + shared_ptr pigZombie = dynamic_pointer_cast(e); + pigZombie->alert(sourceEntity); + } + } + alert(sourceEntity); + } + return Zombie::hurt(source, dmg); } void PigZombie::alert(shared_ptr target) { - this->attackTarget = target; - angerTime = 20 * 20 + random->nextInt(20 * 20); - playAngrySoundIn = random->nextInt(20 * 2); + attackTarget = target; + angerTime = 20 * 20 + random->nextInt(20 * 20); + playAngrySoundIn = random->nextInt(20 * 2); } int PigZombie::getAmbientSound() { - return eSoundType_MOB_ZOMBIEPIG_AMBIENT; + return eSoundType_MOB_ZOMBIEPIG_AMBIENT; } int PigZombie::getHurtSound() { - return eSoundType_MOB_ZOMBIEPIG_HURT; + return eSoundType_MOB_ZOMBIEPIG_HURT; } int PigZombie::getDeathSound() { - return eSoundType_MOB_ZOMBIEPIG_DEATH; + return eSoundType_MOB_ZOMBIEPIG_DEATH; } void PigZombie::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) @@ -158,45 +159,29 @@ void PigZombie::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) } } +bool PigZombie::mobInteract(shared_ptr player) +{ + return false; +} + void PigZombie::dropRareDeathLoot(int rareLootLevel) { - if (rareLootLevel > 0) - { - shared_ptr sword = shared_ptr( new ItemInstance(Item::sword_gold) ); - EnchantmentHelper::enchantItem(random, sword, 5); - spawnAtLocation(sword, 0); - } - else - { - int select = random->nextInt(3); - if (select == 0) - { - spawnAtLocation(Item::goldIngot_Id, 1); - } - else if (select == 1) - { - spawnAtLocation(Item::sword_gold_Id, 1); - } - else if (select == 2) - { - spawnAtLocation(Item::helmet_gold_Id, 1); - } - } + spawnAtLocation(Item::goldIngot_Id, 1); } int PigZombie::getDeathLoot() { - return Item::rotten_flesh_Id; + return Item::rotten_flesh_Id; } -void PigZombie::finalizeMobSpawn() +void PigZombie::populateDefaultEquipmentSlots() { - Zombie::finalizeMobSpawn(); - setVillager(false); + setEquippedSlot(SLOT_WEAPON, shared_ptr( new ItemInstance(Item::sword_gold)) ); } -shared_ptr PigZombie::getCarriedItem() +MobGroupData *PigZombie::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param { - // TODO 4J - could be of const shared_ptr type. - return (shared_ptr ) sword; -} + Zombie::finalizeMobSpawn(groupData); + setVillager(false); + return groupData; +} \ No newline at end of file diff --git a/Minecraft.World/PigZombie.h b/Minecraft.World/PigZombie.h index b47efacb..21ccd49e 100644 --- a/Minecraft.World/PigZombie.h +++ b/Minecraft.World/PigZombie.h @@ -13,8 +13,11 @@ public: static Entity *create(Level *level) { return new PigZombie(level); } private: + static AttributeModifier *SPEED_MODIFIER_ATTACKING; + int angerTime; - int playAngrySoundIn; + int playAngrySoundIn; + shared_ptr lastAttackTarget; void _init(); @@ -22,20 +25,20 @@ public: PigZombie(Level *level); protected: - bool useNewAi(); + virtual void registerAttributes(); + virtual bool useNewAi(); public: - virtual int getTexture(); - virtual void tick(); - virtual bool canSpawn(); - virtual void addAdditonalSaveData(CompoundTag *tag); - virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void tick(); + virtual bool canSpawn(); + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditionalSaveData(CompoundTag *tag); protected: virtual shared_ptr findAttackTarget(); public: - virtual bool hurt(DamageSource *source, int dmg); + virtual bool hurt(DamageSource *source, float dmg); private: void alert(shared_ptr target); @@ -45,16 +48,16 @@ protected: virtual int getHurtSound(); virtual int getDeathSound(); virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); - virtual void dropRareDeathLoot(int rareLootLevel); - virtual int getDeathLoot(); - -private: - static shared_ptr sword; public: - virtual void finalizeMobSpawn(); + virtual bool mobInteract(shared_ptr player); - shared_ptr getCarriedItem(); +protected: + virtual void dropRareDeathLoot(int rareLootLevel); + virtual int getDeathLoot(); + virtual void populateDefaultEquipmentSlots(); - static void staticCtor(); + +public: + virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param }; diff --git a/Minecraft.World/PistonBaseTile.cpp b/Minecraft.World/PistonBaseTile.cpp index cbad5cec..c71bbf95 100644 --- a/Minecraft.World/PistonBaseTile.cpp +++ b/Minecraft.World/PistonBaseTile.cpp @@ -41,9 +41,9 @@ PistonBaseTile::PistonBaseTile(int id, bool isSticky) : Tile(id, Material::pisto // 4J - added initialiser ignoreUpdate(false); - this->isSticky = isSticky; - setSoundType(SOUND_STONE); - setDestroyTime(0.5f); + this->isSticky = isSticky; + setSoundType(SOUND_STONE); + setDestroyTime(0.5f); iconInside = NULL; iconBack = NULL; @@ -52,7 +52,7 @@ PistonBaseTile::PistonBaseTile(int id, bool isSticky) : Tile(id, Material::pisto Icon *PistonBaseTile::getPlatformTexture() { - return iconPlatform; + return iconPlatform; } void PistonBaseTile::updateShape(float x0, float y0, float z0, float x1, float y1, float z1) @@ -62,32 +62,32 @@ void PistonBaseTile::updateShape(float x0, float y0, float z0, float x1, float y Icon *PistonBaseTile::getTexture(int face, int data) { - int facing = getFacing(data); + int facing = getFacing(data); - if (facing > 5) + if (facing > 5) { - return iconPlatform; - } + return iconPlatform; + } - if (face == facing) + if (face == facing) { - // sorry about this mess... - // when the piston is extended, either normally - // or because a piston arm animation, the top - // texture is the furnace bottom + // sorry about this mess... + // when the piston is extended, either normally + // or because a piston arm animation, the top + // texture is the furnace bottom ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); - if (isExtended(data) || tls->xx0 > 0 || tls->yy0 > 0 || tls->zz0 > 0 || tls->xx1 < 1 || tls->yy1 < 1 || tls->zz1 < 1) + if (isExtended(data) || tls->xx0 > 0 || tls->yy0 > 0 || tls->zz0 > 0 || tls->xx1 < 1 || tls->yy1 < 1 || tls->zz1 < 1) { - return iconInside; - } - return iconPlatform; - } - if (face == Facing::OPPOSITE_FACING[facing]) + return iconInside; + } + return iconPlatform; + } + if (face == Facing::OPPOSITE_FACING[facing]) { - return iconBack; - } + return iconBack; + } - return icon; + return icon; } Icon *PistonBaseTile::getTexture(const wstring &name) @@ -124,107 +124,112 @@ bool PistonBaseTile::use(Level *level, int x, int y, int z, shared_ptr p return false; } -void PistonBaseTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void PistonBaseTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { - int targetData = getNewFacing(level, x, y, z, dynamic_pointer_cast(by) ); - level->setData(x, y, z, targetData); - if (!level->isClientSide && !ignoreUpdate()) + int targetData = getNewFacing(level, x, y, z, dynamic_pointer_cast(by) ); + level->setData(x, y, z, targetData, Tile::UPDATE_CLIENTS); + if (!level->isClientSide && !ignoreUpdate()) { - checkIfExtend(level, x, y, z); - } + checkIfExtend(level, x, y, z); + } } void PistonBaseTile::neighborChanged(Level *level, int x, int y, int z, int type) { - if (!level->isClientSide && !ignoreUpdate()) + if (!level->isClientSide && !ignoreUpdate()) { - checkIfExtend(level, x, y, z); - } + checkIfExtend(level, x, y, z); + } } void PistonBaseTile::onPlace(Level *level, int x, int y, int z) { - if (!level->isClientSide && level->getTileEntity(x, y, z) == NULL && !ignoreUpdate()) + if (!level->isClientSide && level->getTileEntity(x, y, z) == NULL && !ignoreUpdate()) { - checkIfExtend(level, x, y, z); - } + checkIfExtend(level, x, y, z); + } } void PistonBaseTile::checkIfExtend(Level *level, int x, int y, int z) { - int data = level->getData(x, y, z); - int facing = getFacing(data); + int data = level->getData(x, y, z); + int facing = getFacing(data); - if (facing == UNDEFINED_FACING) + if (facing == UNDEFINED_FACING) { - return; - } - bool extend = getNeighborSignal(level, x, y, z, facing); + return; + } + bool extend = getNeighborSignal(level, x, y, z, facing); - if (extend && !isExtended(data)) + if (extend && !isExtended(data)) { - if (canPush(level, x, y, z, facing)) + if (canPush(level, x, y, z, facing)) { - //level->setDataNoUpdate(x, y, z, facing | EXTENDED_BIT); - level->tileEvent(x, y, z, id, TRIGGER_EXTEND, facing); - } - } + level->tileEvent(x, y, z, id, TRIGGER_EXTEND, facing); + } + } else if (!extend && isExtended(data)) { - //level->setDataNoUpdate(x, y, z, facing); - level->tileEvent(x, y, z, id, TRIGGER_CONTRACT, facing); - } + level->setData(x, y, z, facing, UPDATE_CLIENTS); + level->tileEvent(x, y, z, id, TRIGGER_CONTRACT, facing); + } } /** - * This method checks neighbor signals for this block and the block above, - * and directly beneath. However, it avoids checking blocks that would be - * pushed by this block. - * - * @param level - * @param x - * @param y - * @param z - * @return - */ +* This method checks neighbor signals for this block and the block above, +* and directly beneath. However, it avoids checking blocks that would be +* pushed by this block. +* +* @param level +* @param x +* @param y +* @param z +* @return +*/ bool PistonBaseTile::getNeighborSignal(Level *level, int x, int y, int z, int facing) { - // check adjacent neighbors, but not in push direction - if (facing != Facing::DOWN && level->getSignal(x, y - 1, z, Facing::DOWN)) return true; - if (facing != Facing::UP && level->getSignal(x, y + 1, z, Facing::UP)) return true; - if (facing != Facing::NORTH && level->getSignal(x, y, z - 1, Facing::NORTH)) return true; - if (facing != Facing::SOUTH && level->getSignal(x, y, z + 1, Facing::SOUTH)) return true; - if (facing != Facing::EAST && level->getSignal(x + 1, y, z, Facing::EAST)) return true; - if (facing != Facing::WEST && level->getSignal(x - 1, y, z, Facing::WEST)) return true; - - // check signals above - if (level->getSignal(x, y, z, 0)) return true; - if (level->getSignal(x, y + 2, z, 1)) return true; - if (level->getSignal(x, y + 1, z - 1, 2)) return true; - if (level->getSignal(x, y + 1, z + 1, 3)) return true; - if (level->getSignal(x - 1, y + 1, z, 4)) return true; - if (level->getSignal(x + 1, y + 1, z, 5)) return true; - - return false; + // check adjacent neighbors, but not in push direction + if (facing != Facing::DOWN && level->hasSignal(x, y - 1, z, Facing::DOWN)) return true; + if (facing != Facing::UP && level->hasSignal(x, y + 1, z, Facing::UP)) return true; + if (facing != Facing::NORTH && level->hasSignal(x, y, z - 1, Facing::NORTH)) return true; + if (facing != Facing::SOUTH && level->hasSignal(x, y, z + 1, Facing::SOUTH)) return true; + if (facing != Facing::EAST && level->hasSignal(x + 1, y, z, Facing::EAST)) return true; + if (facing != Facing::WEST && level->hasSignal(x - 1, y, z, Facing::WEST)) return true; + + // check signals above + if (level->hasSignal(x, y, z, 0)) return true; + if (level->hasSignal(x, y + 2, z, 1)) return true; + if (level->hasSignal(x, y + 1, z - 1, 2)) return true; + if (level->hasSignal(x, y + 1, z + 1, 3)) return true; + if (level->hasSignal(x - 1, y + 1, z, 4)) return true; + if (level->hasSignal(x + 1, y + 1, z, 5)) return true; + + return false; } -void PistonBaseTile::triggerEvent(Level *level, int x, int y, int z, int param1, int facing) +bool PistonBaseTile::triggerEvent(Level *level, int x, int y, int z, int param1, int facing) { ignoreUpdate(true); - if (param1 == TRIGGER_EXTEND) - { - level->setDataNoUpdate(x, y, z, facing | EXTENDED_BIT); - } - else + if (!level->isClientSide) { - level->setDataNoUpdate(x, y, z, facing); + bool extend = getNeighborSignal(level, x, y, z, facing); + + if (extend && param1 == TRIGGER_CONTRACT) + { + level->setData(x, y, z, facing | EXTENDED_BIT, UPDATE_CLIENTS); + return false; + } + else if (!extend && param1 == TRIGGER_EXTEND) + { + return false; + } } - if (param1 == TRIGGER_EXTEND) + if (param1 == TRIGGER_EXTEND) { PIXBeginNamedEvent(0,"Create push\n"); - if (createPush(level, x, y, z, facing)) + if (createPush(level, x, y, z, facing)) { // 4J - it is (currently) critical that this setData sends data to the client, so have added a bool to the method so that it sends data even if the data was already set to the same value // as before, which was actually its behaviour until a change in 1.0.1 meant that setData only conditionally sent updates to listeners. If the data update Isn't sent, then what @@ -237,139 +242,140 @@ void PistonBaseTile::triggerEvent(Level *level, int x, int y, int z, int param1, // We really need to spend some time investigating a better way for pistons to work as it all seems a bit scary how the host/client interact, but forcing this to send should at least // restore the behaviour of the pistons to something closer to what they were before the 1.0.1 update. By sending this data update, then (4) in the list above doesn't happen // because the client does actually receive an update for this tile from the host after the event has been processed on the cient. - level->setData(x, y, z, facing | EXTENDED_BIT, true); - level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_TILE_PISTON_OUT, 0.5f, level->random->nextFloat() * 0.25f + 0.6f); - } + level->setData(x, y, z, facing | EXTENDED_BIT, Tile::UPDATE_CLIENTS, true); + level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_TILE_PISTON_OUT, 0.5f, level->random->nextFloat() * 0.25f + 0.6f); + } else { - level->setDataNoUpdate(x, y, z, facing); + return false; } PIXEndNamedEvent(); - } + } else if (param1 == TRIGGER_CONTRACT) { PIXBeginNamedEvent(0,"Contract phase A\n"); - shared_ptr prevTileEntity = level->getTileEntity(x + Facing::STEP_X[facing], y + Facing::STEP_Y[facing], z + Facing::STEP_Z[facing]); - if (prevTileEntity != NULL && dynamic_pointer_cast(prevTileEntity) != NULL) + shared_ptr prevTileEntity = level->getTileEntity(x + Facing::STEP_X[facing], y + Facing::STEP_Y[facing], z + Facing::STEP_Z[facing]); + if (prevTileEntity != NULL && dynamic_pointer_cast(prevTileEntity) != NULL) { - dynamic_pointer_cast(prevTileEntity)->finalTick(); - } + dynamic_pointer_cast(prevTileEntity)->finalTick(); + } stopSharingIfServer(level, x, y, z); // 4J added - level->setTileAndDataNoUpdate(x, y, z, Tile::pistonMovingPiece_Id, facing); - level->setTileEntity(x, y, z, PistonMovingPiece::newMovingPieceEntity(id, facing, facing, false, true)); + level->setTileAndData(x, y, z, Tile::pistonMovingPiece_Id, facing, Tile::UPDATE_ALL); + level->setTileEntity(x, y, z, PistonMovingPiece::newMovingPieceEntity(id, facing, facing, false, true)); PIXEndNamedEvent(); - // sticky movement - if (isSticky) + // sticky movement + if (isSticky) { PIXBeginNamedEvent(0,"Contract sticky phase A\n"); - int twoX = x + Facing::STEP_X[facing] * 2; - int twoY = y + Facing::STEP_Y[facing] * 2; - int twoZ = z + Facing::STEP_Z[facing] * 2; - int block = level->getTile(twoX, twoY, twoZ); - int blockData = level->getData(twoX, twoY, twoZ); - bool pistonPiece = false; + int twoX = x + Facing::STEP_X[facing] * 2; + int twoY = y + Facing::STEP_Y[facing] * 2; + int twoZ = z + Facing::STEP_Z[facing] * 2; + int block = level->getTile(twoX, twoY, twoZ); + int blockData = level->getData(twoX, twoY, twoZ); + bool pistonPiece = false; PIXEndNamedEvent(); - if (block == Tile::pistonMovingPiece_Id) + if (block == Tile::pistonMovingPiece_Id) { PIXBeginNamedEvent(0,"Contract sticky phase B\n"); - // the block two steps away is a moving piston block piece, - // so replace it with the real data, since it's probably - // this piston which is changing too fast - shared_ptr tileEntity = level->getTileEntity(twoX, twoY, twoZ); - if (tileEntity != NULL && dynamic_pointer_cast(tileEntity) != NULL ) + // the block two steps away is a moving piston block piece, so replace it with the real data, + // since it's probably this piston which is changing too fast + shared_ptr tileEntity = level->getTileEntity(twoX, twoY, twoZ); + if (tileEntity != NULL && dynamic_pointer_cast(tileEntity) != NULL ) { - shared_ptr ppe = dynamic_pointer_cast(tileEntity); + shared_ptr ppe = dynamic_pointer_cast(tileEntity); - if (ppe->getFacing() == facing && ppe->isExtending()) + if (ppe->getFacing() == facing && ppe->isExtending()) { - // force the tile to air before pushing - ppe->finalTick(); - block = ppe->getId(); - blockData = ppe->getData(); - pistonPiece = true; - } - } + // force the tile to air before pushing + ppe->finalTick(); + block = ppe->getId(); + blockData = ppe->getData(); + pistonPiece = true; + } + } PIXEndNamedEvent(); - } + } PIXBeginNamedEvent(0,"Contract sticky phase C\n"); - if (!pistonPiece && block > 0 && (isPushable(block, level, twoX, twoY, twoZ, false)) - && (Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_NORMAL || block == Tile::pistonBase_Id || block == Tile::pistonStickyBase_Id)) + if (!pistonPiece && block > 0 && (isPushable(block, level, twoX, twoY, twoZ, false)) + && (Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_NORMAL || block == Tile::pistonBase_Id || block == Tile::pistonStickyBase_Id)) { stopSharingIfServer(level, twoX, twoY, twoZ); // 4J added - x += Facing::STEP_X[facing]; - y += Facing::STEP_Y[facing]; - z += Facing::STEP_Z[facing]; + x += Facing::STEP_X[facing]; + y += Facing::STEP_Y[facing]; + z += Facing::STEP_Z[facing]; - level->setTileAndDataNoUpdate(x, y, z, Tile::pistonMovingPiece_Id, blockData); - level->setTileEntity(x, y, z, PistonMovingPiece::newMovingPieceEntity(block, blockData, facing, false, false)); + level->setTileAndData(x, y, z, Tile::pistonMovingPiece_Id, blockData, Tile::UPDATE_ALL); + level->setTileEntity(x, y, z, PistonMovingPiece::newMovingPieceEntity(block, blockData, facing, false, false)); ignoreUpdate(false); - level->setTile(twoX, twoY, twoZ, 0); + level->removeTile(twoX, twoY, twoZ); ignoreUpdate(true); } else if (!pistonPiece) { stopSharingIfServer(level, x + Facing::STEP_X[facing], y + Facing::STEP_Y[facing], z + Facing::STEP_Z[facing]); // 4J added ignoreUpdate(false); - level->setTile(x + Facing::STEP_X[facing], y + Facing::STEP_Y[facing], z + Facing::STEP_Z[facing], 0); + level->removeTile(x + Facing::STEP_X[facing], y + Facing::STEP_Y[facing], z + Facing::STEP_Z[facing]); ignoreUpdate(true); - } + } PIXEndNamedEvent(); - } + } else { stopSharingIfServer(level, x + Facing::STEP_X[facing], y + Facing::STEP_Y[facing], z + Facing::STEP_Z[facing]); // 4J added ignoreUpdate(false); - level->setTile(x + Facing::STEP_X[facing], y + Facing::STEP_Y[facing], z + Facing::STEP_Z[facing], 0); + level->removeTile(x + Facing::STEP_X[facing], y + Facing::STEP_Y[facing], z + Facing::STEP_Z[facing]); ignoreUpdate(true); - } + } - level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_TILE_PISTON_IN, 0.5f, level->random->nextFloat() * 0.15f + 0.6f); - } + level->playSound(x + 0.5, y + 0.5, z + 0.5, eSoundType_TILE_PISTON_IN, 0.5f, level->random->nextFloat() * 0.15f + 0.6f); + } ignoreUpdate(false); + + return true; } void PistonBaseTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { - int data = (forceData == -1 ) ? level->getData(x, y, z) : forceData; + int data = (forceData == -1 ) ? level->getData(x, y, z) : forceData; - if (isExtended(data)) + if (isExtended(data)) { - const float thickness = PLATFORM_THICKNESS / 16.0f; - switch (getFacing(data)) + const float thickness = PLATFORM_THICKNESS / 16.0f; + switch (getFacing(data)) { case Facing::DOWN: - setShape(0, thickness, 0, 1, 1, 1); - break; + setShape(0, thickness, 0, 1, 1, 1); + break; case Facing::UP: - setShape(0, 0, 0, 1, 1 - thickness, 1); - break; + setShape(0, 0, 0, 1, 1 - thickness, 1); + break; case Facing::NORTH: - setShape(0, 0, thickness, 1, 1, 1); - break; + setShape(0, 0, thickness, 1, 1, 1); + break; case Facing::SOUTH: - setShape(0, 0, 0, 1, 1, 1 - thickness); - break; + setShape(0, 0, 0, 1, 1, 1 - thickness); + break; case Facing::WEST: - setShape(thickness, 0, 0, 1, 1, 1); - break; + setShape(thickness, 0, 0, 1, 1, 1); + break; case Facing::EAST: - setShape(0, 0, 0, 1 - thickness, 1, 1); - break; - } - } + setShape(0, 0, 0, 1 - thickness, 1, 1); + break; + } + } else { - setShape(0, 0, 0, 1, 1, 1); - } + setShape(0, 0, 0, 1, 1, 1); + } } void PistonBaseTile::updateDefaultShape() @@ -379,8 +385,8 @@ void PistonBaseTile::updateDefaultShape() void PistonBaseTile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source) { - setShape(0, 0, 0, 1, 1, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(0, 0, 0, 1, 1, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); } AABB *PistonBaseTile::getAABB(Level *level, int x, int y, int z) @@ -404,64 +410,68 @@ bool PistonBaseTile::isExtended(int data) return (data & EXTENDED_BIT) != 0; } -int PistonBaseTile::getNewFacing(Level *level, int x, int y, int z, shared_ptr player) +int PistonBaseTile::getNewFacing(Level *level, int x, int y, int z, shared_ptr player) { - if (Mth::abs((float) player->x - x) < 2 && Mth::abs((float) player->z - z) < 2) + if (Mth::abs((float) player->x - x) < 2 && Mth::abs((float) player->z - z) < 2) { - // If the player is above the block, the slot is on the top - double py = player->y + 1.82 - player->heightOffset; - if (py - y > 2) + // If the player is above the block, the slot is on the top + double py = player->y + 1.82 - player->heightOffset; + if (py - y > 2) { - return Facing::UP; - } - // If the player is below the block, the slot is on the bottom - if (y - py > 0) + return Facing::UP; + } + // If the player is below the block, the slot is on the bottom + if (y - py > 0) { - return Facing::DOWN; - } - } - // The slot is on the side - int i = Mth::floor(player->yRot * 4.0f / 360.0f + 0.5) & 0x3; - if (i == 0) return Facing::NORTH; - if (i == 1) return Facing::EAST; - if (i == 2) return Facing::SOUTH; - if (i == 3) return Facing::WEST; - return 0; + return Facing::DOWN; + } + } + // The slot is on the side + int i = Mth::floor(player->yRot * 4.0f / 360.0f + 0.5) & 0x3; + if (i == 0) return Facing::NORTH; + if (i == 1) return Facing::EAST; + if (i == 2) return Facing::SOUTH; + if (i == 3) return Facing::WEST; + return 0; } bool PistonBaseTile::isPushable(int block, Level *level, int cx, int cy, int cz, bool allowDestroyable) { - // special case for obsidian - if (block == Tile::obsidian_Id) + // special case for obsidian + if (block == Tile::obsidian_Id) { - return false; - } + return false; + } - if (block == Tile::pistonBase_Id || block == Tile::pistonStickyBase_Id) + if (block == Tile::pistonBase_Id || block == Tile::pistonStickyBase_Id) { - // special case for piston bases - if (isExtended(level->getData(cx, cy, cz))) + // special case for piston bases + if (isExtended(level->getData(cx, cy, cz))) { - return false; - } - } + return false; + } + } else { - if (Tile::tiles[block]->getDestroySpeed(level, cx, cy, cz) == Tile::INDESTRUCTIBLE_DESTROY_TIME) + if (Tile::tiles[block]->getDestroySpeed(level, cx, cy, cz) == Tile::INDESTRUCTIBLE_DESTROY_TIME) { - return false; - } + return false; + } - if (Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_BLOCK) + if (Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_BLOCK) { - return false; - } - - if (!allowDestroyable && Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_DESTROY) + return false; + } + + if (Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_DESTROY) { - return false; - } - } + if(!allowDestroyable) + { + return false; + } + return true; + } + } if( Tile::tiles[block]->isEntityTile() ) // 4J - java uses instanceof EntityTile here { @@ -474,19 +484,19 @@ bool PistonBaseTile::isPushable(int block, Level *level, int cx, int cy, int cz, bool PistonBaseTile::canPush(Level *level, int sx, int sy, int sz, int facing) { - int cx = sx + Facing::STEP_X[facing]; - int cy = sy + Facing::STEP_Y[facing]; - int cz = sz + Facing::STEP_Z[facing]; + int cx = sx + Facing::STEP_X[facing]; + int cy = sy + Facing::STEP_Y[facing]; + int cz = sz + Facing::STEP_Z[facing]; - for (int i = 0; i < MAX_PUSH_DEPTH + 1; i++) + for (int i = 0; i < MAX_PUSH_DEPTH + 1; i++) { if (cy <= 0 || cy >= (Level::maxBuildHeight - 1)) { - // out of bounds - return false; - } - + // out of bounds + return false; + } + // 4J - added to also check for out of bounds in x/z for our finite world int minXZ = - (level->dimension->getXZSize() * 16 ) / 2; int maxXZ = (level->dimension->getXZSize() * 16 ) / 2 - 1; @@ -494,35 +504,35 @@ bool PistonBaseTile::canPush(Level *level, int sx, int sy, int sz, int facing) { return false; } - int block = level->getTile(cx, cy, cz); - if (block == 0) + int block = level->getTile(cx, cy, cz); + if (block == 0) { - break; - } + break; + } - if (!isPushable(block, level, cx, cy, cz, true)) + if (!isPushable(block, level, cx, cy, cz, true)) { - return false; - } + return false; + } - if (Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_DESTROY) + if (Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_DESTROY) { - break; - } + break; + } - if (i == MAX_PUSH_DEPTH) + if (i == MAX_PUSH_DEPTH) { - // we've reached the maximum push depth - // without finding air or a breakable block - return false; - } + // we've reached the maximum push depth + // without finding air or a breakable block + return false; + } - cx += Facing::STEP_X[facing]; - cy += Facing::STEP_Y[facing]; - cz += Facing::STEP_Z[facing]; - } + cx += Facing::STEP_X[facing]; + cy += Facing::STEP_Y[facing]; + cz += Facing::STEP_Z[facing]; + } - return true; + return true; } @@ -541,18 +551,18 @@ void PistonBaseTile::stopSharingIfServer(Level *level, int x, int y, int z) bool PistonBaseTile::createPush(Level *level, int sx, int sy, int sz, int facing) { - int cx = sx + Facing::STEP_X[facing]; - int cy = sy + Facing::STEP_Y[facing]; - int cz = sz + Facing::STEP_Z[facing]; + int cx = sx + Facing::STEP_X[facing]; + int cy = sy + Facing::STEP_Y[facing]; + int cz = sz + Facing::STEP_Z[facing]; - for (int i = 0; i < MAX_PUSH_DEPTH + 1; i++) + for (int i = 0; i < MAX_PUSH_DEPTH + 1; i++) { if (cy <= 0 || cy >= (Level::maxBuildHeight - 1)) { - // out of bounds - return false; - } - + // out of bounds + return false; + } + // 4J - added to also check for out of bounds in x/z for our finite world int minXZ = - (level->dimension->getXZSize() * 16 ) / 2; int maxXZ = (level->dimension->getXZSize() * 16 ) / 2 - 1; @@ -561,68 +571,91 @@ bool PistonBaseTile::createPush(Level *level, int sx, int sy, int sz, int facing return false; } - int block = level->getTile(cx, cy, cz); - if (block == 0) + int block = level->getTile(cx, cy, cz); + if (block == 0) { - break; - } + break; + } - if (!isPushable(block, level, cx, cy, cz, true)) + if (!isPushable(block, level, cx, cy, cz, true)) { - return false; - } + return false; + } - if (Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_DESTROY) + if (Tile::tiles[block]->getPistonPushReaction() == Material::PUSH_DESTROY) { - // this block is destroyed when pushed - Tile::tiles[block]->spawnResources(level, cx, cy, cz, level->getData(cx, cy, cz), 0); - // setting the tile to air is actually superflous, but - // helps vs multiplayer problems + // this block is destroyed when pushed + Tile::tiles[block]->spawnResources(level, cx, cy, cz, level->getData(cx, cy, cz), 0); + // setting the tile to air is actually superflous, but helps vs multiplayer problems stopSharingIfServer(level, cx, cy, cz); // 4J added - level->setTile(cx, cy, cz, 0); - break; - } + level->removeTile(cx, cy, cz); + break; + } - if (i == MAX_PUSH_DEPTH) + if (i == MAX_PUSH_DEPTH) { - // we've reached the maximum push depth - // without finding air or a breakable block - return false; - } + // we've reached the maximum push depth without finding air or a breakable block + return false; + } + + cx += Facing::STEP_X[facing]; + cy += Facing::STEP_Y[facing]; + cz += Facing::STEP_Z[facing]; + } - cx += Facing::STEP_X[facing]; - cy += Facing::STEP_Y[facing]; - cz += Facing::STEP_Z[facing]; - } + int ex = cx; + int ey = cy; + int ez = cz; + int count = 0; + int tiles[MAX_PUSH_DEPTH + 1]; - while (cx != sx || cy != sy || cz != sz) + while (cx != sx || cy != sy || cz != sz) { - int nx = cx - Facing::STEP_X[facing]; - int ny = cy - Facing::STEP_Y[facing]; - int nz = cz - Facing::STEP_Z[facing]; + int nx = cx - Facing::STEP_X[facing]; + int ny = cy - Facing::STEP_Y[facing]; + int nz = cz - Facing::STEP_Z[facing]; - int block = level->getTile(nx, ny, nz); - int data = level->getData(nx, ny, nz); + int block = level->getTile(nx, ny, nz); + int data = level->getData(nx, ny, nz); stopSharingIfServer(level, cx, cy, cz); // 4J added - if (block == id && nx == sx && ny == sy && nz == sz) + if (block == id && nx == sx && ny == sy && nz == sz) { - level->setTileAndDataNoUpdate(cx, cy, cz, Tile::pistonMovingPiece_Id, facing | (isSticky ? PistonExtensionTile::STICKY_BIT : 0), false); - level->setTileEntity(cx, cy, cz, PistonMovingPiece::newMovingPieceEntity(Tile::pistonExtensionPiece_Id, facing | (isSticky ? PistonExtensionTile::STICKY_BIT : 0), facing, true, false)); - } + level->setTileAndData(cx, cy, cz, Tile::pistonMovingPiece_Id, facing | (isSticky ? PistonExtensionTile::STICKY_BIT : 0), Tile::UPDATE_NONE); + level->setTileEntity(cx, cy, cz, PistonMovingPiece::newMovingPieceEntity(Tile::pistonExtensionPiece_Id, facing | (isSticky ? PistonExtensionTile::STICKY_BIT : 0), facing, true, false)); + } else { - level->setTileAndDataNoUpdate(cx, cy, cz, Tile::pistonMovingPiece_Id, data, false); - level->setTileEntity(cx, cy, cz, PistonMovingPiece::newMovingPieceEntity(block, data, facing, true, false)); - } + level->setTileAndData(cx, cy, cz, Tile::pistonMovingPiece_Id, data, Tile::UPDATE_NONE); + level->setTileEntity(cx, cy, cz, PistonMovingPiece::newMovingPieceEntity(block, data, facing, true, false)); + } + tiles[count++] = block; - cx = nx; - cy = ny; - cz = nz; - } + cx = nx; + cy = ny; + cz = nz; + } + + cx = ex; + cy = ey; + cz = ez; + count = 0; - return true; + while (cx != sx || cy != sy || cz != sz) + { + int nx = cx - Facing::STEP_X[facing]; + int ny = cy - Facing::STEP_Y[facing]; + int nz = cz - Facing::STEP_Z[facing]; + + level->updateNeighborsAt(nx, ny, nz, tiles[count++]); + + cx = nx; + cy = ny; + cz = nz; + } + + return true; } diff --git a/Minecraft.World/PistonBaseTile.h b/Minecraft.World/PistonBaseTile.h index 0fda1391..59c2e833 100644 --- a/Minecraft.World/PistonBaseTile.h +++ b/Minecraft.World/PistonBaseTile.h @@ -27,45 +27,45 @@ private: static DWORD tlsIdx; // 4J - was just a static but implemented with TLS for our version - static bool ignoreUpdate(); + static bool ignoreUpdate(); static void ignoreUpdate(bool set); public: PistonBaseTile(int id, bool isSticky); - Icon *getPlatformTexture(); + Icon *getPlatformTexture(); virtual void updateShape(float x0, float y0, float z0, float x1, float y1, float z1); - virtual Icon *getTexture(int face, int data); + virtual Icon *getTexture(int face, int data); static Icon *getTexture(const wstring &name); void registerIcons(IconRegister *iconRegister); - virtual int getRenderShape(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); - virtual void onPlace(Level *level, int x, int y, int z); + virtual int getRenderShape(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual void onPlace(Level *level, int x, int y, int z); private: - void checkIfExtend(Level *level, int x, int y, int z); - bool getNeighborSignal(Level *level, int x, int y, int z, int facing); + void checkIfExtend(Level *level, int x, int y, int z); + bool getNeighborSignal(Level *level, int x, int y, int z, int facing); public: - virtual void triggerEvent(Level *level, int x, int y, int z, int param1, int facing); - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param - virtual void updateDefaultShape(); - virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); + virtual bool triggerEvent(Level *level, int x, int y, int z, int param1, int facing); + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param + virtual void updateDefaultShape(); + virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual bool isCubeShaped(); + virtual bool isCubeShaped(); - static int getFacing(int data); - static bool isExtended(int data); - static int getNewFacing(Level *level, int x, int y, int z, shared_ptr player); + static int getFacing(int data); + static bool isExtended(int data); + static int getNewFacing(Level *level, int x, int y, int z, shared_ptr player); private: - static bool isPushable(int block, Level *level, int cx, int cy, int cz, bool allowDestroyable); - static bool canPush(Level *level, int sx, int sy, int sz, int facing); + static bool isPushable(int block, Level *level, int cx, int cy, int cz, bool allowDestroyable); + static bool canPush(Level *level, int sx, int sy, int sz, int facing); static void stopSharingIfServer(Level *level, int x, int y, int z); // 4J added - bool createPush(Level *level, int sx, int sy, int sz, int facing); + bool createPush(Level *level, int sx, int sy, int sz, int facing); }; \ No newline at end of file diff --git a/Minecraft.World/PistonExtensionTile.cpp b/Minecraft.World/PistonExtensionTile.cpp index 1827ddde..25c5adb9 100644 --- a/Minecraft.World/PistonExtensionTile.cpp +++ b/Minecraft.World/PistonExtensionTile.cpp @@ -9,8 +9,8 @@ PistonExtensionTile::PistonExtensionTile(int id) : Tile(id, Material::piston,isS // 4J added initialiser overrideTopTexture = NULL; - setSoundType(SOUND_STONE); - setDestroyTime(0.5f); + setSoundType(SOUND_STONE); + setDestroyTime(0.5f); } void PistonExtensionTile::setOverrideTopTexture(Icon *overrideTopTexture) @@ -23,49 +23,63 @@ void PistonExtensionTile::clearOverrideTopTexture() this->overrideTopTexture = NULL; } +void PistonExtensionTile::playerWillDestroy(Level *level, int x, int y, int z, int data, shared_ptr player) +{ + if (player->abilities.instabuild) + { + int facing = getFacing(data); + int tile = level->getTile(x - Facing::STEP_X[facing], y - Facing::STEP_Y[facing], z - Facing::STEP_Z[facing]); + if (tile == Tile::pistonBase_Id || tile == Tile::pistonStickyBase_Id) + { + level->removeTile(x - Facing::STEP_X[facing], y - Facing::STEP_Y[facing], z - Facing::STEP_Z[facing]); + } + } + Tile::playerWillDestroy(level, x, y, z, data, player); +} + void PistonExtensionTile::onRemove(Level *level, int x, int y, int z, int id, int data) { - Tile::onRemove(level, x, y, z, id, data); - int facing = Facing::OPPOSITE_FACING[getFacing(data)]; - x += Facing::STEP_X[facing]; - y += Facing::STEP_Y[facing]; - z += Facing::STEP_Z[facing]; + Tile::onRemove(level, x, y, z, id, data); + int facing = Facing::OPPOSITE_FACING[getFacing(data)]; + x += Facing::STEP_X[facing]; + y += Facing::STEP_Y[facing]; + z += Facing::STEP_Z[facing]; - int t = level->getTile(x, y, z); + int t = level->getTile(x, y, z); - if (t == Tile::pistonBase_Id || t == Tile::pistonStickyBase_Id) + if (t == Tile::pistonBase_Id || t == Tile::pistonStickyBase_Id) { - data = level->getData(x, y, z); - if (PistonBaseTile::isExtended(data)) + data = level->getData(x, y, z); + if (PistonBaseTile::isExtended(data)) { - Tile::tiles[t]->spawnResources(level, x, y, z, data, 0); - level->setTile(x, y, z, 0); + Tile::tiles[t]->spawnResources(level, x, y, z, data, 0); + level->removeTile(x, y, z); - } - } + } + } } Icon *PistonExtensionTile::getTexture(int face, int data) { - int facing = getFacing(data); + int facing = getFacing(data); - if (face == facing) + if (face == facing) { - if (overrideTopTexture != NULL) + if (overrideTopTexture != NULL) { - return overrideTopTexture; - } - if ((data & STICKY_BIT) != 0) + return overrideTopTexture; + } + if ((data & STICKY_BIT) != 0) { return PistonBaseTile::getTexture(PistonBaseTile::PLATFORM_STICKY_TEX); - } - return PistonBaseTile::getTexture(PistonBaseTile::PLATFORM_TEX); - } - if (facing < 6 && face == Facing::OPPOSITE_FACING[facing]) + } + return PistonBaseTile::getTexture(PistonBaseTile::PLATFORM_TEX); + } + if (facing < 6 && face == Facing::OPPOSITE_FACING[facing]) { - return PistonBaseTile::getTexture(PistonBaseTile::PLATFORM_TEX); - } - return PistonBaseTile::getTexture(PistonBaseTile::EDGE_TEX); // edge and arms + return PistonBaseTile::getTexture(PistonBaseTile::PLATFORM_TEX); + } + return PistonBaseTile::getTexture(PistonBaseTile::EDGE_TEX); // edge and arms } void PistonExtensionTile::registerIcons(IconRegister *iconRegister) @@ -105,98 +119,98 @@ int PistonExtensionTile::getResourceCount(Random *random) void PistonExtensionTile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source) { - int data = level->getData(x, y, z); + int data = level->getData(x, y, z); - const float thickness = PistonBaseTile::PLATFORM_THICKNESS / 16.0f; - const float smallEdge1 = (8.0f - (PistonBaseTile::PLATFORM_THICKNESS / 2.0f)) / 16.0f; - const float smallEdge2 = (8.0f + (PistonBaseTile::PLATFORM_THICKNESS / 2.0f)) / 16.0f; - const float largeEdge1 = (8.0f - PistonBaseTile::PLATFORM_THICKNESS) / 16.0f; - const float largeEdge2 = (8.0f + PistonBaseTile::PLATFORM_THICKNESS) / 16.0f; + const float thickness = PistonBaseTile::PLATFORM_THICKNESS / 16.0f; + const float smallEdge1 = (8.0f - (PistonBaseTile::PLATFORM_THICKNESS / 2.0f)) / 16.0f; + const float smallEdge2 = (8.0f + (PistonBaseTile::PLATFORM_THICKNESS / 2.0f)) / 16.0f; + const float largeEdge1 = (8.0f - PistonBaseTile::PLATFORM_THICKNESS) / 16.0f; + const float largeEdge2 = (8.0f + PistonBaseTile::PLATFORM_THICKNESS) / 16.0f; - switch (getFacing(data)) + switch (getFacing(data)) { - case Facing::DOWN: - setShape(0, 0, 0, 1, thickness, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - setShape(smallEdge1, thickness, smallEdge1, smallEdge2, 1, smallEdge2); - Tile::addAABBs(level, x, y, z, box, boxes, source); - break; - case Facing::UP: - setShape(0, 1 - thickness, 0, 1, 1, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - setShape(smallEdge1, 0, smallEdge1, smallEdge2, 1 - thickness, smallEdge2); - Tile::addAABBs(level, x, y, z, box, boxes, source); - break; - case Facing::NORTH: - setShape(0, 0, 0, 1, 1, thickness); - Tile::addAABBs(level, x, y, z, box, boxes, source); - setShape(largeEdge1, smallEdge1, thickness, largeEdge2, smallEdge2, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - break; - case Facing::SOUTH: - setShape(0, 0, 1 - thickness, 1, 1, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - setShape(largeEdge1, smallEdge1, 0, largeEdge2, smallEdge2, 1 - thickness); - Tile::addAABBs(level, x, y, z, box, boxes, source); - break; - case Facing::WEST: - setShape(0, 0, 0, thickness, 1, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - setShape(smallEdge1, largeEdge1, thickness, smallEdge2, largeEdge2, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - break; - case Facing::EAST: - setShape(1 - thickness, 0, 0, 1, 1, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); - setShape(0, smallEdge1, largeEdge1, 1 - thickness, smallEdge2, largeEdge2); - Tile::addAABBs(level, x, y, z, box, boxes, source); - break; - } - setShape(0, 0, 0, 1, 1, 1); + case Facing::DOWN: + setShape(0, 0, 0, 1, thickness, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(smallEdge1, thickness, smallEdge1, smallEdge2, 1, smallEdge2); + Tile::addAABBs(level, x, y, z, box, boxes, source); + break; + case Facing::UP: + setShape(0, 1 - thickness, 0, 1, 1, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(smallEdge1, 0, smallEdge1, smallEdge2, 1 - thickness, smallEdge2); + Tile::addAABBs(level, x, y, z, box, boxes, source); + break; + case Facing::NORTH: + setShape(0, 0, 0, 1, 1, thickness); + Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(largeEdge1, smallEdge1, thickness, largeEdge2, smallEdge2, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + break; + case Facing::SOUTH: + setShape(0, 0, 1 - thickness, 1, 1, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(largeEdge1, smallEdge1, 0, largeEdge2, smallEdge2, 1 - thickness); + Tile::addAABBs(level, x, y, z, box, boxes, source); + break; + case Facing::WEST: + setShape(0, 0, 0, thickness, 1, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(smallEdge1, largeEdge1, thickness, smallEdge2, largeEdge2, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + break; + case Facing::EAST: + setShape(1 - thickness, 0, 0, 1, 1, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(0, smallEdge1, largeEdge1, 1 - thickness, smallEdge2, largeEdge2); + Tile::addAABBs(level, x, y, z, box, boxes, source); + break; + } + setShape(0, 0, 0, 1, 1, 1); } void PistonExtensionTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { - int data = (forceData == -1 ) ? level->getData(x, y, z) : forceData; + int data = (forceData == -1 ) ? level->getData(x, y, z) : forceData; - const float thickness = PistonBaseTile::PLATFORM_THICKNESS / 16.0f; + const float thickness = PistonBaseTile::PLATFORM_THICKNESS / 16.0f; - switch (getFacing(data)) + switch (getFacing(data)) { - case Facing::DOWN: - setShape(0, 0, 0, 1, thickness, 1); - break; - case Facing::UP: - setShape(0, 1 - thickness, 0, 1, 1, 1); - break; - case Facing::NORTH: - setShape(0, 0, 0, 1, 1, thickness); - break; - case Facing::SOUTH: - setShape(0, 0, 1 - thickness, 1, 1, 1); - break; - case Facing::WEST: - setShape(0, 0, 0, thickness, 1, 1); - break; - case Facing::EAST: - setShape(1 - thickness, 0, 0, 1, 1, 1); - break; - } + case Facing::DOWN: + setShape(0, 0, 0, 1, thickness, 1); + break; + case Facing::UP: + setShape(0, 1 - thickness, 0, 1, 1, 1); + break; + case Facing::NORTH: + setShape(0, 0, 0, 1, 1, thickness); + break; + case Facing::SOUTH: + setShape(0, 0, 1 - thickness, 1, 1, 1); + break; + case Facing::WEST: + setShape(0, 0, 0, thickness, 1, 1); + break; + case Facing::EAST: + setShape(1 - thickness, 0, 0, 1, 1, 1); + break; + } } void PistonExtensionTile::neighborChanged(Level *level, int x, int y, int z, int type) { - int facing = getFacing(level->getData(x, y, z)); - int tile = level->getTile(x - Facing::STEP_X[facing], y - Facing::STEP_Y[facing], z - Facing::STEP_Z[facing]); - if (tile != Tile::pistonBase_Id && tile != Tile::pistonStickyBase_Id) + int facing = getFacing(level->getData(x, y, z)); + int tile = level->getTile(x - Facing::STEP_X[facing], y - Facing::STEP_Y[facing], z - Facing::STEP_Z[facing]); + if (tile != Tile::pistonBase_Id && tile != Tile::pistonStickyBase_Id) { - level->setTile(x, y, z, 0); - } - else + level->removeTile(x, y, z); + } + else { - Tile::tiles[tile]->neighborChanged(level, x - Facing::STEP_X[facing], y - Facing::STEP_Y[facing], z - Facing::STEP_Z[facing], type); - } + Tile::tiles[tile]->neighborChanged(level, x - Facing::STEP_X[facing], y - Facing::STEP_Y[facing], z - Facing::STEP_Z[facing], type); + } } int PistonExtensionTile::getFacing(int data) @@ -206,5 +220,11 @@ int PistonExtensionTile::getFacing(int data) int PistonExtensionTile::cloneTileId(Level *level, int x, int y, int z) { + int data = level->getData(x, y, z); + if ((data & STICKY_BIT) != 0) + { + return Tile::pistonStickyBase_Id; + } + return Tile::pistonBase_Id; return 0; } \ No newline at end of file diff --git a/Minecraft.World/PistonExtensionTile.h b/Minecraft.World/PistonExtensionTile.h index a0b08729..bd00b8e2 100644 --- a/Minecraft.World/PistonExtensionTile.h +++ b/Minecraft.World/PistonExtensionTile.h @@ -4,28 +4,29 @@ class PistonExtensionTile : public Tile { public: - // i'm reusing this block for the sticky pistons - static const int STICKY_BIT = 8; + // i'm reusing this block for the sticky pistons + static const int STICKY_BIT = 8; private: Icon *overrideTopTexture; public: PistonExtensionTile(int id); - void setOverrideTopTexture(Icon *overrideTopTexture); - void clearOverrideTopTexture(); - void onRemove(Level *level, int x, int y, int z, int id, int data); - virtual Icon *getTexture(int face, int data); - void registerIcons(IconRegister *iconRegister); - virtual int getRenderShape(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual bool mayPlace(Level *level, int x, int y, int z, int face); - virtual int getResourceCount(Random *random); - virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param - virtual void neighborChanged(Level *level, int x, int y, int z, int type); - static int getFacing(int data); + virtual void setOverrideTopTexture(Icon *overrideTopTexture); + virtual void clearOverrideTopTexture(); + virtual void playerWillDestroy(Level *level, int x, int y, int z, int data, shared_ptr player); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual Icon *getTexture(int face, int data); + virtual void registerIcons(IconRegister *iconRegister); + virtual int getRenderShape(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual bool mayPlace(Level *level, int x, int y, int z, int face); + virtual int getResourceCount(Random *random); + virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + static int getFacing(int data); virtual int cloneTileId(Level *level, int x, int y, int z); }; \ No newline at end of file diff --git a/Minecraft.World/PistonMovingPiece.cpp b/Minecraft.World/PistonMovingPiece.cpp index e141cebe..5fa9a475 100644 --- a/Minecraft.World/PistonMovingPiece.cpp +++ b/Minecraft.World/PistonMovingPiece.cpp @@ -6,7 +6,7 @@ #include "Facing.h" #include "AABB.h" -PistonMovingPiece::PistonMovingPiece(int id) : EntityTile(id, Material::piston, isSolidRender() ) +PistonMovingPiece::PistonMovingPiece(int id) : BaseEntityTile(id, Material::piston, isSolidRender() ) { setDestroyTime(INDESTRUCTIBLE_DESTROY_TIME); } @@ -22,15 +22,15 @@ void PistonMovingPiece::onPlace(Level *level, int x, int y, int z) void PistonMovingPiece::onRemove(Level *level, int x, int y, int z, int id, int data) { - shared_ptr tileEntity = level->getTileEntity(x, y, z); - if (tileEntity != NULL && dynamic_pointer_cast(tileEntity) != NULL) + shared_ptr tileEntity = level->getTileEntity(x, y, z); + if (tileEntity != NULL && dynamic_pointer_cast(tileEntity) != NULL) { - dynamic_pointer_cast(tileEntity)->finalTick(); - } + dynamic_pointer_cast(tileEntity)->finalTick(); + } else { - EntityTile::onRemove(level, x, y, z, id, data); - } + BaseEntityTile::onRemove(level, x, y, z, id, data); + } } bool PistonMovingPiece::mayPlace(Level *level, int x, int y, int z) @@ -61,14 +61,14 @@ bool PistonMovingPiece::isCubeShaped() bool PistonMovingPiece::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param { if( soundOnly) return false; - // this is a special case in order to help removing invisible, unbreakable, blocks in the world - if (!level->isClientSide && level->getTileEntity(x, y, z) == NULL) + // this is a special case in order to help removing invisible, unbreakable, blocks in the world + if (!level->isClientSide && level->getTileEntity(x, y, z) == NULL) { - // this block is no longer valid - level->setTile(x, y, z, 0); - return true; - } - return false; + // this block is no longer valid + level->removeTile(x, y, z); + return true; + } + return false; } int PistonMovingPiece::getResource(int data, Random *random, int playerBonusLevel) @@ -78,22 +78,23 @@ int PistonMovingPiece::getResource(int data, Random *random, int playerBonusLeve void PistonMovingPiece::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus) { - if (level->isClientSide) return; + if (level->isClientSide) return; - shared_ptr entity = getEntity(level, x, y, z); - if (entity == NULL) + shared_ptr entity = getEntity(level, x, y, z); + if (entity == NULL) { - return; - } + return; + } - Tile::tiles[entity->getId()]->spawnResources(level, x, y, z, entity->getData(), 0); + Tile::tiles[entity->getId()]->spawnResources(level, x, y, z, entity->getData(), 0); } void PistonMovingPiece::neighborChanged(Level *level, int x, int y, int z, int type) { - if (!level->isClientSide && level->getTileEntity(x, y, z) == NULL) + if (!level->isClientSide) { - } + level->getTileEntity(x, y, z) == NULL; + } } shared_ptr PistonMovingPiece::newMovingPieceEntity(int block, int data, int facing, bool extending, bool isSourcePiston) @@ -103,64 +104,64 @@ shared_ptr PistonMovingPiece::newMovingPieceEntity(int block, int da AABB *PistonMovingPiece::getAABB(Level *level, int x, int y, int z) { - shared_ptr entity = getEntity(level, x, y, z); - if (entity == NULL) + shared_ptr entity = getEntity(level, x, y, z); + if (entity == NULL) { - return NULL; - } + return NULL; + } - // move the aabb depending on the animation - float progress = entity->getProgress(0); - if (entity->isExtending()) + // move the aabb depending on the animation + float progress = entity->getProgress(0); + if (entity->isExtending()) { - progress = 1.0f - progress; - } - return getAABB(level, x, y, z, entity->getId(), progress, entity->getFacing()); + progress = 1.0f - progress; + } + return getAABB(level, x, y, z, entity->getId(), progress, entity->getFacing()); } void PistonMovingPiece::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { - shared_ptr entity = dynamic_pointer_cast(forceEntity); + shared_ptr entity = dynamic_pointer_cast(forceEntity); if( entity == NULL ) entity = getEntity(level, x, y, z); - if (entity != NULL) + if (entity != NULL) { - Tile *tile = Tile::tiles[entity->getId()]; - if (tile == NULL || tile == this) + Tile *tile = Tile::tiles[entity->getId()]; + if (tile == NULL || tile == this) { - return; - } - tile->updateShape(level, x, y, z); + return; + } + tile->updateShape(level, x, y, z); - float progress = entity->getProgress(0); - if (entity->isExtending()) + float progress = entity->getProgress(0); + if (entity->isExtending()) { - progress = 1.0f - progress; - } - int facing = entity->getFacing(); + progress = 1.0f - progress; + } + int facing = entity->getFacing(); ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); - tls->xx0 = tile->getShapeX0() - Facing::STEP_X[facing] * progress; - tls->yy0 = tile->getShapeY0() - Facing::STEP_Y[facing] * progress; - tls->zz0 = tile->getShapeZ0() - Facing::STEP_Z[facing] * progress; - tls->xx1 = tile->getShapeX1() - Facing::STEP_X[facing] * progress; - tls->yy1 = tile->getShapeY1() - Facing::STEP_Y[facing] * progress; - tls->zz1 = tile->getShapeZ1() - Facing::STEP_Z[facing] * progress; - } + tls->xx0 = tile->getShapeX0() - Facing::STEP_X[facing] * progress; + tls->yy0 = tile->getShapeY0() - Facing::STEP_Y[facing] * progress; + tls->zz0 = tile->getShapeZ0() - Facing::STEP_Z[facing] * progress; + tls->xx1 = tile->getShapeX1() - Facing::STEP_X[facing] * progress; + tls->yy1 = tile->getShapeY1() - Facing::STEP_Y[facing] * progress; + tls->zz1 = tile->getShapeZ1() - Facing::STEP_Z[facing] * progress; + } } AABB *PistonMovingPiece::getAABB(Level *level, int x, int y, int z, int tile, float progress, int facing) { - if (tile == 0 || tile == id) + if (tile == 0 || tile == id) { - return NULL; - } - AABB *aabb = Tile::tiles[tile]->getAABB(level, x, y, z); + return NULL; + } + AABB *aabb = Tile::tiles[tile]->getAABB(level, x, y, z); - if (aabb == NULL) + if (aabb == NULL) { - return NULL; - } + return NULL; + } - // move the aabb depending on the animation + // move the aabb depending on the animation if (Facing::STEP_X[facing] < 0) { aabb->x0 -= Facing::STEP_X[facing] * progress; @@ -185,17 +186,17 @@ AABB *PistonMovingPiece::getAABB(Level *level, int x, int y, int z, int tile, fl { aabb->z1 -= Facing::STEP_Z[facing] * progress; } - return aabb; + return aabb; } shared_ptr PistonMovingPiece::getEntity(LevelSource *level, int x, int y, int z) { - shared_ptr tileEntity = level->getTileEntity(x, y, z); - if (tileEntity != NULL && dynamic_pointer_cast(tileEntity) != NULL) + shared_ptr tileEntity = level->getTileEntity(x, y, z); + if (tileEntity != NULL && dynamic_pointer_cast(tileEntity) != NULL) { - return dynamic_pointer_cast(tileEntity); - } - return nullptr; + return dynamic_pointer_cast(tileEntity); + } + return nullptr; } void PistonMovingPiece::registerIcons(IconRegister *iconRegister) diff --git a/Minecraft.World/PistonMovingPiece.h b/Minecraft.World/PistonMovingPiece.h index 1b1a61dc..cf64cabf 100644 --- a/Minecraft.World/PistonMovingPiece.h +++ b/Minecraft.World/PistonMovingPiece.h @@ -1,8 +1,8 @@ -#include "EntityTile.h" +#include "BaseEntityTile.h" class PistonPieceEntity; -class PistonMovingPiece : public EntityTile +class PistonMovingPiece : public BaseEntityTile { public: PistonMovingPiece(int id); @@ -12,21 +12,21 @@ protected: public: virtual void onPlace(Level *level, int x, int y, int z); - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual bool mayPlace(Level *level, int x, int y, int z, int face); - virtual int getRenderShape(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param; - virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); - static shared_ptr newMovingPieceEntity(int block, int data, int facing, bool extending, bool isSourcePiston); - virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual bool mayPlace(Level *level, int x, int y, int z, int face); + virtual int getRenderShape(); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param; + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + static shared_ptr newMovingPieceEntity(int block, int data, int facing, bool extending, bool isSourcePiston); + virtual AABB *getAABB(Level *level, int x, int y, int z); + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param - AABB *getAABB(Level *level, int x, int y, int z, int tile, float progress, int facing); + AABB *getAABB(Level *level, int x, int y, int z, int tile, float progress, int facing); private: shared_ptr getEntity(LevelSource *level, int x, int y, int z); diff --git a/Minecraft.World/PistonPieceEntity.cpp b/Minecraft.World/PistonPieceEntity.cpp index 3498cec0..0d0a86d0 100644 --- a/Minecraft.World/PistonPieceEntity.cpp +++ b/Minecraft.World/PistonPieceEntity.cpp @@ -146,7 +146,10 @@ void PistonPieceEntity::finalTick() level->removeTileEntity(x, y, z); setRemoved(); if (level->getTile(x, y, z) == Tile::pistonMovingPiece_Id) - level->setTileAndData(x, y, z, id, data); + { + level->setTileAndData(x, y, z, id, data, Tile::UPDATE_ALL); + level->neighborChanged(x, y, z, id); + } } } @@ -160,7 +163,10 @@ void PistonPieceEntity::tick() level->removeTileEntity(x, y, z); setRemoved(); if (level->getTile(x, y, z) == Tile::pistonMovingPiece_Id) - level->setTileAndData(x, y, z, id, data); + { + level->setTileAndData(x, y, z, id, data, Tile::UPDATE_ALL); + level->neighborChanged(x, y, z, id); + } return; } diff --git a/Minecraft.World/PlainsBiome.cpp b/Minecraft.World/PlainsBiome.cpp index e26c664b..df6f4785 100644 --- a/Minecraft.World/PlainsBiome.cpp +++ b/Minecraft.World/PlainsBiome.cpp @@ -3,6 +3,8 @@ PlainsBiome::PlainsBiome(int id) : Biome(id) { + friendlies.push_back(new MobSpawnerData(eTYPE_HORSE, 5, 2, 6)); + decorator->treeCount = -999; decorator->flowerCount = 4; decorator->grassCount = 10; diff --git a/Minecraft.World/PlayGoal.cpp b/Minecraft.World/PlayGoal.cpp index 304e7758..a3760862 100644 --- a/Minecraft.World/PlayGoal.cpp +++ b/Minecraft.World/PlayGoal.cpp @@ -9,14 +9,14 @@ #include "BasicTypeContainers.h" #include "PlayGoal.h" -PlayGoal::PlayGoal(Villager *mob, float speed) +PlayGoal::PlayGoal(Villager *mob, double speedModifier) { - followFriend = weak_ptr(); + followFriend = weak_ptr(); wantedX = wantedY = wantedZ = 0.0; playTime = 0; this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag); } @@ -38,7 +38,7 @@ bool PlayGoal::canUse() double distSqr = friendV->distanceToSqr(mob->shared_from_this()); if (distSqr > closestDistSqr) continue; closestDistSqr = distSqr; - followFriend = weak_ptr(friendV); + followFriend = weak_ptr(friendV); } delete children; @@ -64,7 +64,7 @@ void PlayGoal::start() void PlayGoal::stop() { mob->setChasing(false); - followFriend = weak_ptr(); + followFriend = weak_ptr(); } void PlayGoal::tick() @@ -72,7 +72,7 @@ void PlayGoal::tick() --playTime; if (followFriend.lock() != NULL) { - if (mob->distanceToSqr(followFriend.lock()) > 2 * 2) mob->getNavigation()->moveTo(followFriend.lock(), speed); + if (mob->distanceToSqr(followFriend.lock()) > 2 * 2) mob->getNavigation()->moveTo(followFriend.lock(), speedModifier); } else { @@ -80,7 +80,7 @@ void PlayGoal::tick() { Vec3 *pos = RandomPos::getPos(dynamic_pointer_cast(mob->shared_from_this()), 16, 3); if (pos == NULL) return; - mob->getNavigation()->moveTo(pos->x, pos->y, pos->z, speed); + mob->getNavigation()->moveTo(pos->x, pos->y, pos->z, speedModifier); } } } \ No newline at end of file diff --git a/Minecraft.World/PlayGoal.h b/Minecraft.World/PlayGoal.h index a1b1a291..0c927d76 100644 --- a/Minecraft.World/PlayGoal.h +++ b/Minecraft.World/PlayGoal.h @@ -6,13 +6,13 @@ class PlayGoal : public Goal { private: Villager *mob; - weak_ptr followFriend; - float speed; + weak_ptr followFriend; + double speedModifier; double wantedX, wantedY, wantedZ; int playTime; public: - PlayGoal(Villager *mob, float speed); + PlayGoal(Villager *mob, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/PlaySoundCommand.h b/Minecraft.World/PlaySoundCommand.h new file mode 100644 index 00000000..1f43143b --- /dev/null +++ b/Minecraft.World/PlaySoundCommand.h @@ -0,0 +1,88 @@ +/* +package net.minecraft.commands.common; + +import net.minecraft.commands.BaseCommand; +import net.minecraft.commands.CommandSender; +import net.minecraft.commands.exceptions.CommandException; +import net.minecraft.commands.exceptions.UsageException; +import net.minecraft.network.packet.LevelSoundPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; + +public class PlaySoundCommand extends BaseCommand { + @Override + public String getName() { + return "playsound"; + } + + @Override + public int getPermissionLevel() { + return LEVEL_GAMEMASTERS; + } + + @Override + public String getUsage(CommandSender source) { + return "commands.playsound.usage"; + } + + @Override + public void execute(CommandSender source, String[] args) { + if (args.length < 2) { + throw new UsageException(getUsage(source)); + } + + int index = 0; + String sound = args[index++]; + ServerPlayer player = convertToPlayer(source, args[index++]); + double x = player.getCommandSenderWorldPosition().x; + double y = player.getCommandSenderWorldPosition().y; + double z = player.getCommandSenderWorldPosition().z; + double volume = 1; + double pitch = 1; + double minVolume = 0; + + if (args.length > index) x = convertArgToCoordinate(source, x, args[index++]); + if (args.length > index) y = convertArgToCoordinate(source, y, args[index++], 0, 0); + if (args.length > index) z = convertArgToCoordinate(source, z, args[index++]); + + if (args.length > index) volume = convertArgToDouble(source, args[index++], 0, Float.MAX_VALUE); + if (args.length > index) pitch = convertArgToDouble(source, args[index++], 0, 2); + if (args.length > index) minVolume = convertArgToDouble(source, args[index++], 0, 1); + + double maxDist = volume > 1 ? volume * 16 : 16; + double dist = player.distanceTo(x, y, z); + + if (dist > maxDist) { + if (minVolume > 0) { + double deltaX = x - player.x; + double deltaY = y - player.y; + double deltaZ = z - player.z; + double length = Math.sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ); + double soundX = player.x; + double soundY = player.y; + double soundZ = player.z; + + if (length > 0) { + soundX += deltaX / length * 2; + soundY += deltaY / length * 2; + soundZ += deltaZ / length * 2; + } + + player.connection.send(new LevelSoundPacket(sound, soundX, soundY, soundZ, (float) minVolume, (float) pitch)); + } else { + throw new CommandException("commands.playsound.playerTooFar", player.getAName()); + } + } else { + player.connection.send(new LevelSoundPacket(sound, x, y, z, (float) volume, (float) pitch)); + } + + logAdminAction(source, "commands.playsound.success", sound, player.getAName()); + } + + @Override + public boolean isValidWildcardPlayerArgument(String[] args, int argumentIndex) { + return argumentIndex == 1; + } +} + +*/ \ No newline at end of file diff --git a/Minecraft.World/Player.cpp b/Minecraft.World/Player.cpp index d4832e40..700935f6 100644 --- a/Minecraft.World/Player.cpp +++ b/Minecraft.World/Player.cpp @@ -15,7 +15,9 @@ #include "net.minecraft.world.level.chunk.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.animal.h" +#include "net.minecraft.world.entity.boss.h" #include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.item.h" @@ -24,6 +26,8 @@ #include "net.minecraft.world.level.material.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.world.scores.h" +#include "net.minecraft.world.scores.criteria.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.inventory.h" #include "net.minecraft.world.damagesource.h" @@ -43,52 +47,35 @@ void Player::_init() { + registerAttributes(); + setHealth(getMaxHealth()); inventory = shared_ptr( new Inventory( this ) ); userType = 0; - score = 0; oBob = bob = 0.0f; - swinging = false; - swingTime = 0; - - //string name; - dimension = 0; - //string cloakTexture; xCloakO = yCloakO = zCloakO = 0.0; xCloak = yCloak = zCloak = 0.0; m_isSleeping = false; + customTextureUrl = L""; + customTextureUrl2 = L""; m_uiPlayerCurrentSkin=0; bedPosition = NULL; - sleepCounter = 0; deathFadeCounter=0; - bedOffsetX = bedOffsetY = bedOffsetZ = 0.0f; stats = NULL; - respawnPosition = NULL; + respawnForced = false; minecartAchievementPos = NULL; - - changingDimensionDelay = 20; - - - isInsidePortal = false; - - - portalTime = oPortalTime = 0.0f; - - dmgSpill = 0; - - fishing = nullptr; distanceWalk = distanceSwim = distanceFall = distanceClimb = distanceMinecart = distanceBoat = distancePig = 0; @@ -106,6 +93,8 @@ void Player::_init() defaultWalkSpeed = 0.1f; defaultFlySpeed = 0.02f; + lastLevelUpTime = 0; + m_uiGamePrivileges = 0; m_ppAdditionalModelParts=NULL; @@ -121,14 +110,13 @@ void Player::_init() m_bAwardedOnARail=false; } -Player::Player(Level *level) : Mob( level ) +Player::Player(Level *level, const wstring &name) : LivingEntity( level ) { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + this->name = name; _init(); MemSect(11); @@ -139,14 +127,12 @@ Player::Player(Level *level) : Mob( level ) heightOffset = 1.62f; Pos *spawnPos = level->getSharedSpawnPos(); - this->moveTo(spawnPos->x + 0.5, spawnPos->y + 1, spawnPos->z + 0.5, 0, 0); + moveTo(spawnPos->x + 0.5, spawnPos->y + 1, spawnPos->z + 0.5, 0, 0); delete spawnPos; - modelName = L"humanoid"; rotOffs = 180; flameTime = 20; - textureIdx = TN_MOB_CHAR; // 4J - was L"/mob/char.png"; m_skinIndex = eDefaultSkins_Skin0; m_playerIndex = 0; m_dwSkinId = 0; @@ -158,7 +144,12 @@ Player::Player(Level *level) : Mob( level ) //m_bShownOnMaps = true; setShowOnMaps(app.GetGameHostOption(eGameHostOption_Gamertags)!=0?true:false); m_bIsGuest = false; - m_UUID = L""; + +#ifndef _XBOX_ONE + // 4J: Set UUID to name on none-XB1 consoles, may change in future but for now + // ownership of animals on these consoles is done by name + setUUID(name); +#endif } Player::~Player() @@ -173,17 +164,20 @@ Player::~Player() //if( containerMenu != inventoryMenu ) delete containerMenu; } -int Player::getMaxHealth() +void Player::registerAttributes() { - return MAX_HEALTH; + LivingEntity::registerAttributes(); + + getAttributes()->registerAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(1); } void Player::defineSynchedData() { - this->Mob::defineSynchedData(); + LivingEntity::defineSynchedData(); entityData->define(DATA_PLAYER_FLAGS_ID, (byte) 0); - entityData->define(DATA_PLAYER_RUNNING_ID, (byte) 0); + entityData->define(DATA_PLAYER_ABSORPTION_ID, (float) 0); + entityData->define(DATA_SCORE_ID, (int) 0); } shared_ptr Player::getUseItem() @@ -240,8 +234,8 @@ bool Player::isBlocking() return isUsingItem() && Item::items[useItem->id]->getUseAnimation(useItem) == UseAnim_block; } - -void Player::tick() +// 4J Stu - Added for things that should only be ticked once per simulation frame +void Player::updateFrameTick() { if (useItem != NULL) { @@ -308,7 +302,17 @@ void Player::tick() deathFadeCounter = DEATHFADE_DURATION; } } - this->Mob::tick(); +} + +void Player::tick() +{ + if(level->isClientSide) + { + // 4J Stu - Server player calls this differently so that it only happens once per simulation tick + updateFrameTick(); + } + + LivingEntity::tick(); if (!level->isClientSide) { @@ -459,62 +463,61 @@ void Player::tick() this->drop( shared_ptr( new ItemInstance( Tile::goldenRail, 10 ) ) ); this->drop( shared_ptr( new ItemInstance( Tile::lever, 10 ) ) ); - level->setTime( 0 ); int poweredCount = 0; for(int i = 10; i < 2800; ++i) { - level->setTile(x+i,y-1,z-2,Tile::quartzBlock_Id); - level->setTile(x+i,y,z-2,Tile::quartzBlock_Id); - level->setTile(x+i,y+1,z-2,Tile::quartzBlock_Id); - level->setTile(x+i,y+2,z-2,Tile::lightGem_Id); - level->setTile(x+i,y+3,z-2,Tile::quartzBlock_Id); + level->setTileAndData(x+i,y-1,z-2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y,z-2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+1,z-2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z-2,Tile::glowstone_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z-2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); - level->setTile(x+i,y-1,z-1,Tile::stoneBrick_Id); + level->setTileAndData(x+i,y-1,z-1,Tile::stoneBrick_Id,0,Tile::UPDATE_CLIENTS); if(i%20 == 0) { - level->setTile(x+i,y,z-1,Tile::notGate_on_Id); + level->setTileAndData(x+i,y,z-1,Tile::redstoneTorch_on_Id,0,Tile::UPDATE_CLIENTS); poweredCount = 4; } else { - level->setTile(x+i,y,z-1,0); + level->setTileAndData(x+i,y,z-1,0,0,Tile::UPDATE_CLIENTS); } - level->setTile(x+i,y+1,z-1,0); - level->setTile(x+i,y+2,z-1,0); - level->setTile(x+i,y+3,z-1,0); + level->setTileAndData(x+i,y+1,z-1,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z-1,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z-1,0,0,Tile::UPDATE_CLIENTS); - level->setTile(x+i,y-1,z,Tile::stoneBrick_Id); + level->setTileAndData(x+i,y-1,z,Tile::stoneBrick_Id,0,Tile::UPDATE_CLIENTS); if(poweredCount>0) { - level->setTile(x+i,y,z,Tile::goldenRail_Id); + level->setTileAndData(x+i,y,z,Tile::goldenRail_Id,0,Tile::UPDATE_CLIENTS); --poweredCount; } else { - level->setTile(x+i,y,z,Tile::rail_Id); + level->setTileAndData(x+i,y,z,Tile::rail_Id,0,Tile::UPDATE_CLIENTS); } - level->setTile(x+i,y+1,z,0); - level->setTile(x+i,y+2,z,0); - level->setTile(x+i,y+3,z,0); + level->setTileAndData(x+i,y+1,z,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z,0,0,Tile::UPDATE_CLIENTS); - level->setTile(x+i,y-1,z+1,Tile::stoneBrick_Id); + level->setTileAndData(x+i,y-1,z+1,Tile::stoneBrick_Id,0,Tile::UPDATE_CLIENTS); if((i+5)%20 == 0) { - level->setTile(x+i,y,z+1,Tile::torch_Id); + level->setTileAndData(x+i,y,z+1,Tile::torch_Id,0,Tile::UPDATE_CLIENTS); } else { - level->setTile(x+i,y,z+1,0); + level->setTileAndData(x+i,y,z+1,0,0,Tile::UPDATE_CLIENTS); } - level->setTile(x+i,y+1,z+1,0); - level->setTile(x+i,y+2,z+1,0); - level->setTile(x+i,y+3,z+1,0); - - level->setTile(x+i,y-1,z+2,Tile::quartzBlock_Id); - level->setTile(x+i,y,z+2,Tile::quartzBlock_Id); - level->setTile(x+i,y+1,z+2,Tile::quartzBlock_Id); - level->setTile(x+i,y+2,z+2,Tile::lightGem_Id); - level->setTile(x+i,y+3,z+2,Tile::quartzBlock_Id); + level->setTileAndData(x+i,y+1,z+1,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z+1,0,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z+1,0,0,Tile::UPDATE_CLIENTS); + + level->setTileAndData(x+i,y-1,z+2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y,z+2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+1,z+2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+2,z+2,Tile::glowstone_Id,0,Tile::UPDATE_CLIENTS); + level->setTileAndData(x+i,y+3,z+2,Tile::quartzBlock_Id,0,Tile::UPDATE_CLIENTS); } madeTrack = true; } @@ -523,11 +526,28 @@ void Player::tick() //End 4J sTU } +int Player::getPortalWaitTime() +{ + return abilities.invulnerable ? 0 : SharedConstants::TICKS_PER_SECOND * 4; +} + +int Player::getDimensionChangingDelay() +{ + return SharedConstants::TICKS_PER_SECOND / 2; +} + +void Player::playSound(int iSound, float volume, float pitch) +{ + // this sound method will play locally for the local player, and + // broadcast to remote players + level->playPlayerSound(dynamic_pointer_cast(shared_from_this()), iSound, volume, pitch); +} + void Player::spawnEatParticles(shared_ptr useItem, int count) { if (useItem->getUseAnimation() == UseAnim_drink) { - level->playSound(shared_from_this(), eSoundType_RANDOM_DRINK, 0.5f, level->random->nextFloat() * 0.1f + 0.9f); + playSound(eSoundType_RANDOM_DRINK, 0.5f, level->random->nextFloat() * 0.1f + 0.9f); } if (useItem->getUseAnimation() == UseAnim_eat) { @@ -547,7 +567,7 @@ void Player::spawnEatParticles(shared_ptr useItem, int count) } // 4J Stu - Was L"mob.eat" which doesnt exist - level->playSound(shared_from_this(), eSoundType_RANDOM_EAT, 0.5f + 0.5f * random->nextInt(2), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); + playSound(eSoundType_RANDOM_EAT, 0.5f + 0.5f * random->nextInt(2), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); } } @@ -579,7 +599,7 @@ void Player::handleEntityEvent(byte id) } else { - Mob::handleEntityEvent(id); + LivingEntity::handleEntityEvent(id); } } @@ -588,7 +608,6 @@ bool Player::isImmobile() return getHealth() <= 0 || isSleeping(); } - void Player::closeContainer() { containerMenu = inventoryMenu; @@ -608,7 +627,7 @@ void Player::ride(shared_ptr e) return; } - Mob::ride(e); + LivingEntity::ride(e); } void Player::setPlayerDefaultSkin(EDefaultSkins skin) @@ -927,10 +946,17 @@ void Player::prepareCustomTextures() void Player::rideTick() { + if (!level->isClientSide && isSneaking()) + { + ride(nullptr); + setSneaking(false); + return; + } + double preX = x, preY = y, preZ = z; float preYRot = yRot, preXRot = xRot; - this->Mob::rideTick(); + LivingEntity::rideTick(); oBob = bob; bob = 0; @@ -958,42 +984,15 @@ void Player::resetPos() { heightOffset = 1.62f; setSize(0.6f, 1.8f); - this->Mob::resetPos(); + LivingEntity::resetPos(); setHealth(getMaxHealth()); deathTime = 0; } -int Player::getCurrentSwingDuration() -{ - if (hasEffect(MobEffect::digSpeed)) - { - return SWING_DURATION - (1 + getEffect(MobEffect::digSpeed)->getAmplifier()) * 1; - } - if (hasEffect(MobEffect::digSlowdown)) - { - return SWING_DURATION + (1 + getEffect(MobEffect::digSlowdown)->getAmplifier()) * 2; - } - return SWING_DURATION; -} - void Player::serverAiStep() { - int currentSwingDuration = getCurrentSwingDuration(); - if (swinging) - { - swingTime++; - if (swingTime >= currentSwingDuration) - { - swingTime = 0; - swinging = false; - } - } - else - { - swingTime = 0; - } - - attackAnim = swingTime / (float) currentSwingDuration; + LivingEntity::serverAiStep(); + updateSwingTime(); } @@ -1001,23 +1000,25 @@ void Player::aiStep() { if (jumpTriggerTime > 0) jumpTriggerTime--; - if (level->difficulty == Difficulty::PEACEFUL && getHealth() < getMaxHealth()) + if (level->difficulty == Difficulty::PEACEFUL && getHealth() < getMaxHealth() && level->getGameRules()->getBoolean(GameRules::RULE_NATURAL_REGENERATION)) { if (tickCount % 20 * 12 == 0) heal(1); } inventory->tick(); oBob = bob; - this->Mob::aiStep(); + LivingEntity::aiStep(); - this->walkingSpeed = abilities.getWalkingSpeed(); - this->flyingSpeed = defaultFlySpeed; + AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + if (!level->isClientSide) speed->setBaseValue(abilities.getWalkingSpeed()); + flyingSpeed = defaultFlySpeed; if (isSprinting()) { - walkingSpeed += abilities.getWalkingSpeed() * 0.3f; flyingSpeed += defaultFlySpeed * 0.3f; } + setSpeed((float) speed->getValue()); + float tBob = (float) sqrt(xd * xd + zd * zd); // 4J added - we were getting a NaN with zero xd & zd @@ -1037,7 +1038,19 @@ void Player::aiStep() if (getHealth() > 0) { - vector > *entities = level->getEntities(shared_from_this(), bb->grow(1, 0, 1)); + AABB *pickupArea = NULL; + if (riding != NULL && !riding->removed) + { + // if the player is riding, also touch entities under the + // pig/horse + pickupArea = bb->minmax(riding->bb)->grow(1, 0, 1); + } + else + { + pickupArea = bb->grow(1, .5, 1); + } + + vector > *entities = level->getEntities(shared_from_this(), pickupArea); if (entities != NULL) { AUTO_VAR(itEnd, entities->end()); @@ -1059,21 +1072,26 @@ void Player::touch(shared_ptr entity) entity->playerTouch( dynamic_pointer_cast( shared_from_this() ) ); } -// 4J - Removed 1.0.1 -//bool Player::addResource(int resource) -//{ -// return inventory->add(shared_ptr( new ItemInstance(resource, 1, 0) ) ); -//} - int Player::getScore() { - return score; + return entityData->getInteger(DATA_SCORE_ID); +} + +void Player::setScore(int value) +{ + entityData->set(DATA_SCORE_ID, value); +} + +void Player::increaseScore(int amount) +{ + int score = getScore(); + entityData->set(DATA_SCORE_ID, score + amount); } void Player::die(DamageSource *source) { - this->Mob::die(source); - this->setSize(0.2f, 0.2f); + LivingEntity::die(source); + setSize(0.2f, 0.2f); setPos(x, y, z); yd = 0.1f; @@ -1082,7 +1100,10 @@ void Player::die(DamageSource *source) { drop(shared_ptr( new ItemInstance(Item::apple, 1) ), true); } - inventory->dropAll(); + if (!level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) + { + inventory->dropAll(); + } if (source != NULL) { @@ -1093,26 +1114,33 @@ void Player::die(DamageSource *source) { xd = zd = 0; } - this->heightOffset = 0.1f; + heightOffset = 0.1f; } -void Player::awardKillScore(shared_ptr victim, int score) +void Player::awardKillScore(shared_ptr victim, int awardPoints) { - this->score += score; -} + increaseScore(awardPoints); + vector *objectives = getScoreboard()->findObjectiveFor(ObjectiveCriteria::KILL_COUNT_ALL); -int Player::decreaseAirSupply(int currentSupply) -{ - int oxygenBonus = EnchantmentHelper::getOxygenBonus(inventory); - if (oxygenBonus > 0) + //if (victim instanceof Player) + //{ + // awardStat(Stats::playerKills, 1); + // objectives.addAll(getScoreboard().findObjectiveFor(ObjectiveCriteria::KILL_COUNT_PLAYERS)); + //} + //else + //{ + // awardStat(Stats::mobKills, 1); + //} + + if(objectives) { - if (random->nextInt(oxygenBonus + 1) > 0) + for (AUTO_VAR(it,objectives->begin()); it != objectives->end(); ++it) { - // the oxygen bonus prevents us from drowning - return currentSupply; + Objective *objective = *it; + Score *score = getScoreboard()->getPlayerScore(getAName(), objective); + score->increment(); } } - return Mob::decreaseAirSupply(currentSupply); } bool Player::isShootable() @@ -1125,9 +1153,9 @@ bool Player::isCreativeModeAllowed() return true; } -shared_ptr Player::drop() +shared_ptr Player::drop(bool all) { - return drop(inventory->removeItem(inventory->selected, 1), false); + return drop(inventory->removeItem(inventory->selected, all && inventory->getSelected() != NULL ? inventory->getSelected()->count : 1), false); } shared_ptr Player::drop(shared_ptr item) @@ -1138,6 +1166,7 @@ shared_ptr Player::drop(shared_ptr item) shared_ptr Player::drop(shared_ptr item, bool randomly) { if (item == NULL) return nullptr; + if (item->count == 0) return nullptr; shared_ptr thrownItem = shared_ptr( new ItemEntity(level, x, y - 0.3f + getHeadHeight(), z, item) ); thrownItem->throwTime = 20 * 2; @@ -1181,14 +1210,28 @@ void Player::reallyDrop(shared_ptr thrownItem) } -float Player::getDestroySpeed(Tile *tile) +float Player::getDestroySpeed(Tile *tile, bool hasProperTool) { float speed = inventory->getDestroySpeed(tile); - int efficiency = EnchantmentHelper::getDiggingBonus(inventory); - if (efficiency > 0 && inventory->canDestroy(tile)) + if (speed > 1) { - speed += (efficiency * efficiency + 1); + int efficiency = EnchantmentHelper::getDiggingBonus(dynamic_pointer_cast(shared_from_this())); + shared_ptr item = inventory->getSelected(); + + if (efficiency > 0 && item != NULL) + { + float boost = efficiency * efficiency + 1; + + if (item->canDestroySpecial(tile) || speed > 1) + { + speed += boost; + } + else + { + speed += boost * 0.08f; + } + } } if (hasEffect(MobEffect::digSpeed)) @@ -1200,7 +1243,7 @@ float Player::getDestroySpeed(Tile *tile) speed *= 1.0f - (getEffect(MobEffect::digSlowdown)->getAmplifier() + 1) * .2f; } - if (isUnderLiquid(Material::water) && !EnchantmentHelper::hasWaterWorkerBonus(inventory)) speed /= 5; + if (isUnderLiquid(Material::water) && !EnchantmentHelper::hasWaterWorkerBonus(dynamic_pointer_cast(shared_from_this()))) speed /= 5; // 4J Stu - onGround is set to true on the client when we are flying, which means // the dig speed is out of sync with the server. Removing this speed change when @@ -1217,16 +1260,17 @@ bool Player::canDestroy(Tile *tile) void Player::readAdditionalSaveData(CompoundTag *entityTag) { - Mob::readAdditionalSaveData(entityTag); + LivingEntity::readAdditionalSaveData(entityTag); ListTag *inventoryList = (ListTag *) entityTag->getList(L"Inventory"); inventory->load(inventoryList); - dimension = entityTag->getInt(L"Dimension"); + inventory->selected = entityTag->getInt(L"SelectedItemSlot"); m_isSleeping = entityTag->getBoolean(L"Sleeping"); sleepCounter = entityTag->getShort(L"SleepTimer"); experienceProgress = entityTag->getFloat(L"XpP"); experienceLevel = entityTag->getInt(L"XpLevel"); totalExperience = entityTag->getInt(L"XpTotal"); + setScore(entityTag->getInt(L"Score")); if (m_isSleeping) { @@ -1237,6 +1281,7 @@ void Player::readAdditionalSaveData(CompoundTag *entityTag) if (entityTag->contains(L"SpawnX") && entityTag->contains(L"SpawnY") && entityTag->contains(L"SpawnZ")) { respawnPosition = new Pos(entityTag->getInt(L"SpawnX"), entityTag->getInt(L"SpawnY"), entityTag->getInt(L"SpawnZ")); + respawnForced = entityTag->getBoolean(L"SpawnForced"); } foodData.readAdditionalSaveData(entityTag); @@ -1254,21 +1299,23 @@ void Player::readAdditionalSaveData(CompoundTag *entityTag) void Player::addAdditonalSaveData(CompoundTag *entityTag) { - Mob::addAdditonalSaveData(entityTag); + LivingEntity::addAdditonalSaveData(entityTag); entityTag->put(L"Inventory", inventory->save(new ListTag())); - entityTag->putInt(L"Dimension", dimension); + entityTag->putInt(L"SelectedItemSlot", inventory->selected); entityTag->putBoolean(L"Sleeping", m_isSleeping); entityTag->putShort(L"SleepTimer", (short) sleepCounter); entityTag->putFloat(L"XpP", experienceProgress); entityTag->putInt(L"XpLevel", experienceLevel); entityTag->putInt(L"XpTotal", totalExperience); + entityTag->putInt(L"Score", getScore()); if (respawnPosition != NULL) { entityTag->putInt(L"SpawnX", respawnPosition->x); entityTag->putInt(L"SpawnY", respawnPosition->y); entityTag->putInt(L"SpawnZ", respawnPosition->z); + entityTag->putBoolean(L"SpawnForced", respawnForced); } foodData.addAdditonalSaveData(entityTag); @@ -1281,21 +1328,27 @@ void Player::addAdditonalSaveData(CompoundTag *entityTag) } -Pos *Player::getRespawnPosition(Level *level, CompoundTag *entityTag) +bool Player::openContainer(shared_ptr container) { - if (entityTag->contains(L"SpawnX") && entityTag->contains(L"SpawnY") && entityTag->contains(L"SpawnZ")) - { - return new Pos(entityTag->getInt(L"SpawnX"), entityTag->getInt(L"SpawnY"), entityTag->getInt(L"SpawnZ")); - } - return level->getSharedSpawnPos(); + return true; } -bool Player::openContainer(shared_ptr container) +bool Player::openHopper(shared_ptr container) +{ + return true; +} + +bool Player::openHopper(shared_ptr container) +{ + return true; +} + +bool Player::openHorseInventory(shared_ptr horse, shared_ptr container) { return true; } -bool Player::startEnchanting(int x, int y, int z) +bool Player::startEnchanting(int x, int y, int z, const wstring &name) { return true; } @@ -1310,8 +1363,9 @@ bool Player::startCrafting(int x, int y, int z) return true; } -void Player::take(shared_ptr e, int orgCount) +bool Player::openFireworks(int x, int y, int z) { + return true; } float Player::getHeadHeight() @@ -1325,8 +1379,9 @@ void Player::setDefaultHeadHeight() heightOffset = 1.62f; } -bool Player::hurt(DamageSource *source, int dmg) +bool Player::hurt(DamageSource *source, float dmg) { + if (isInvulnerable()) return false; if ( hasInvulnerablePrivilege() || (abilities.invulnerable && !source->isBypassInvul()) ) return false; // 4J-JEV: Fix for PSVita: #3987 - [IN GAME] The user can take damage/die, when attempting to re-enter fly mode when falling from a height. @@ -1350,95 +1405,40 @@ bool Player::hurt(DamageSource *source, int dmg) if (dmg == 0) return false; shared_ptr attacker = source->getEntity(); - if ( dynamic_pointer_cast( attacker ) != NULL ) + if ( attacker != NULL && attacker->instanceof(eTYPE_ARROW) ) { - if ((dynamic_pointer_cast(attacker))->owner != NULL) + shared_ptr arrow = dynamic_pointer_cast(attacker); + if ( arrow->owner != NULL) { - attacker = (dynamic_pointer_cast(attacker))->owner; + attacker = arrow->owner; } } - if ( dynamic_pointer_cast( attacker ) != NULL ) - { - // aggreviate all pet wolves nearby - directAllTameWolvesOnTarget(dynamic_pointer_cast(attacker), false); - } - return this->Mob::hurt(source, dmg); + return LivingEntity::hurt(source, dmg); } -int Player::getDamageAfterMagicAbsorb(DamageSource *damageSource, int damage) +bool Player::canHarmPlayer(shared_ptr target) { - int remainingDamage = Mob::getDamageAfterMagicAbsorb(damageSource, damage); - if (remainingDamage <= 0) - { - return 0; - } + Team *team = getTeam(); + Team *otherTeam = target->getTeam(); - int enchantmentArmor = EnchantmentHelper::getDamageProtection(inventory, damageSource); - if (enchantmentArmor > 20) + if (team == NULL) { - enchantmentArmor = 20; + return true; } - if (enchantmentArmor > 0 && enchantmentArmor <= 20) + if (!team->isAlliedTo(otherTeam)) { - int absorb = 25 - enchantmentArmor; - int v = remainingDamage * absorb + dmgSpill; - remainingDamage = v / 25; - dmgSpill = v % 25; + return true; } - - return remainingDamage; + return team->isAllowFriendlyFire(); } -bool Player::isPlayerVersusPlayer() +bool Player::canHarmPlayer(wstring targetName) { - return false; -} - -void Player::directAllTameWolvesOnTarget(shared_ptr target, bool skipSitting) -{ - - // filter un-attackable mobs - if ((dynamic_pointer_cast( target ) != NULL) || (dynamic_pointer_cast( target) != NULL)) - { - return; - } - // never target wolves that has this player as owner - if (dynamic_pointer_cast(target) != NULL) - { - shared_ptr wolfTarget = dynamic_pointer_cast(target); - if (wolfTarget->isTame() && m_UUID.compare( wolfTarget->getOwnerUUID() ) == 0 ) - { - return; - } - } - if ((dynamic_pointer_cast( target ) != NULL) && !isPlayerVersusPlayer()) - { - // pvp is off - return; - } - - - // TODO: Optimize this? Most of the time players wont have pets: - vector > *nearbyWolves = level->getEntitiesOfClass(typeid(Wolf), AABB::newTemp(x, y, z, x + 1, y + 1, z + 1)->grow(16, 4, 16)); - AUTO_VAR(itEnd, nearbyWolves->end()); - for (AUTO_VAR(it, nearbyWolves->begin()); it != itEnd; it++) - { - shared_ptr wolf = dynamic_pointer_cast(*it);; - if (wolf->isTame() && wolf->getAttackTarget() == NULL && m_UUID.compare( wolf->getOwnerUUID() ) == 0) - { - if (!skipSitting || !wolf->isSitting()) - { - wolf->setSitting(false); - wolf->setAttackTarget(target); - } - } - } - delete nearbyWolves; - + return true; } -void Player::hurtArmor(int damage) +void Player::hurtArmor(float damage) { inventory->hurtArmor(damage); } @@ -1450,30 +1450,37 @@ int Player::getArmorValue() float Player::getArmorCoverPercentage() { - int count = 0; + int count = 0; for (int i = 0; i < inventory->armor.length; i++) { - if (inventory->armor[i] != NULL) { - count++; - } - } - return (float) count / (float) inventory->armor.length; + if (inventory->armor[i] != NULL) { + count++; + } + } + return (float) count / (float) inventory->armor.length; } -void Player::actuallyHurt(DamageSource *source, int dmg) +void Player::actuallyHurt(DamageSource *source, float dmg) { - if (!source->isBypassArmor() && isBlocking()) + if (isInvulnerable()) return; + if (!source->isBypassArmor() && isBlocking() && dmg > 0) { - dmg = (1 + dmg) >> 1; + dmg = (1 + dmg) * .5f; } dmg = getDamageAfterArmorAbsorb(source, dmg); dmg = getDamageAfterMagicAbsorb(source, dmg); + + float originalDamage = dmg; + dmg = max(dmg - getAbsorptionAmount(), 0.0f); + setAbsorptionAmount(getAbsorptionAmount() - (originalDamage - dmg)); + if (dmg == 0) return; + causeFoodExhaustion(source->getFoodExhaustion()); - //this->Mob::actuallyHurt(source, dmg); - health -= dmg; + float oldHealth = getHealth(); + setHealth(getHealth() - dmg); + getCombatTracker()->recordDamage(source, oldHealth, dmg); } - bool Player::openFurnace(shared_ptr container) { return true; @@ -1484,7 +1491,7 @@ bool Player::openTrap(shared_ptr container) return true; } -void Player::openTextEdit(shared_ptr sign) +void Player::openTextEdit(shared_ptr sign) { } @@ -1493,7 +1500,12 @@ bool Player::openBrewingStand(shared_ptr brewingStand) return true; } -bool Player::openTrading(shared_ptr traderTarget) +bool Player::openBeacon(shared_ptr beacon) +{ + return true; +} + +bool Player::openTrading(shared_ptr traderTarget, const wstring &name) { return true; } @@ -1509,21 +1521,41 @@ void Player::openItemInstanceGui(shared_ptr itemInstance) bool Player::interact(shared_ptr entity) { - if (entity->interact( dynamic_pointer_cast( shared_from_this() ) )) return true; + shared_ptr thisPlayer = dynamic_pointer_cast(shared_from_this()); + shared_ptr item = getSelectedItem(); - if (item != NULL && dynamic_pointer_cast( entity ) != NULL) + shared_ptr itemClone = (item != NULL) ? item->copy() : nullptr; + if ( entity->interact(thisPlayer) ) + { + // [EB]: Added rude check to see if we're still talking about the + // same item; this code caused bucket->milkbucket to be deleted because + // the milkbuckets' stack got decremented to 0. + if (item != NULL && item == getSelectedItem()) + { + if (item->count <= 0 && !abilities.instabuild) + { + removeSelectedItem(); + } + else if (item->count < itemClone->count && abilities.instabuild) + { + item->count = itemClone->count; + } + } + return true; + } + + if ( (item != NULL) && entity->instanceof(eTYPE_LIVINGENTITY) ) { // 4J - PC Comments // Hack to prevent item stacks from decrementing if the player has // the ability to instabuild - if(this->abilities.instabuild) item = item->copy(); - if(item->interactEnemy(dynamic_pointer_cast(entity))) + if(this->abilities.instabuild) item = itemClone; + if(item->interactEnemy(thisPlayer, dynamic_pointer_cast(entity))) { // 4J - PC Comments // Don't remove the item in hand if the player has the ability - // to - // instabuild - if (item->count <= 0 && !this->abilities.instabuild) + // to instabuild + if ( (item->count <= 0) && !abilities.instabuild) { removeSelectedItem(); } @@ -1548,15 +1580,6 @@ double Player::getRidingHeight() return heightOffset - 0.5f; } -void Player::swing() -{ - if (!swinging || swingTime >= getCurrentSwingDuration() / 2 || swingTime < 0) - { - swingTime = -1; - swinging = true; - } -} - void Player::attack(shared_ptr entity) { if (!entity->isAttackable()) @@ -1564,24 +1587,22 @@ void Player::attack(shared_ptr entity) return; } - int dmg = inventory->getAttackDamage(entity); - - if (hasEffect(MobEffect::damageBoost)) - { - dmg += (3 << getEffect(MobEffect::damageBoost)->getAmplifier()); - } - if (hasEffect(MobEffect::weakness)) + if (entity->skipAttackInteraction(shared_from_this())) { - dmg -= (2 << getEffect(MobEffect::weakness)->getAmplifier()); + return; } + float dmg = (float) getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->getValue(); + int knockback = 0; - int magicBoost = 0; - shared_ptr mob = dynamic_pointer_cast(entity); - if (mob != NULL) + float magicBoost = 0; + + if ( entity->instanceof(eTYPE_LIVINGENTITY) ) { - magicBoost = EnchantmentHelper::getDamageBonus(inventory, mob); - knockback += EnchantmentHelper::getKnockbackBonus(inventory, mob); + shared_ptr thisPlayer = dynamic_pointer_cast(shared_from_this()); + shared_ptr mob = dynamic_pointer_cast(entity); + magicBoost = EnchantmentHelper::getDamageBonus(thisPlayer, mob); + knockback += EnchantmentHelper::getKnockbackBonus(thisPlayer, mob); } if (isSprinting()) { @@ -1590,18 +1611,18 @@ void Player::attack(shared_ptr entity) if (dmg > 0 || magicBoost > 0) { - bool bCrit = fallDistance > 0 && !onGround && !onLadder() && !isInWater() && !hasEffect(MobEffect::blindness) && riding == NULL && mob != NULL; - if (bCrit) + bool bCrit = fallDistance > 0 && !onGround && !onLadder() && !isInWater() && !hasEffect(MobEffect::blindness) && (riding == NULL) && entity->instanceof(eTYPE_LIVINGENTITY); + if (bCrit && dmg > 0) { - dmg += random->nextInt(dmg / 2 + 2); + dmg *= 1.5f; } dmg += magicBoost; - + // Ensure we put the entity on fire if we're hitting with a // fire-enchanted weapon bool setOnFireTemporatily = false; - int fireAspect = EnchantmentHelper::getFireAspect(dynamic_pointer_cast(shared_from_this())); - if (dynamic_pointer_cast(entity) && fireAspect > 0 && !entity->isOnFire()) + int fireAspect = EnchantmentHelper::getFireAspect(dynamic_pointer_cast(shared_from_this())); + if ( entity->instanceof(eTYPE_MOB) && fireAspect > 0 && !entity->isOnFire()) { setOnFireTemporatily = true; entity->setOnFire(1); @@ -1635,29 +1656,36 @@ void Player::attack(shared_ptr entity) } setLastHurtMob(entity); - shared_ptr mob = dynamic_pointer_cast(entity); - if (mob) + + if ( entity->instanceof(eTYPE_LIVINGENTITY) ) { + shared_ptr mob = dynamic_pointer_cast(entity); ThornsEnchantment::doThornsAfterAttack(shared_from_this(), mob, random); } } shared_ptr item = getSelectedItem(); - if (item != NULL && dynamic_pointer_cast( entity ) != NULL) + shared_ptr hurtTarget = entity; + if ( entity->instanceof(eTYPE_MULTIENTITY_MOB_PART) ) { - item->hurtEnemy(dynamic_pointer_cast(entity), dynamic_pointer_cast( shared_from_this() ) ); - if (item->count <= 0) + shared_ptr multiMob = dynamic_pointer_cast((dynamic_pointer_cast(entity))->parentMob.lock()); + if ( (multiMob != NULL) && multiMob->instanceof(eTYPE_LIVINGENTITY) ) { - removeSelectedItem(); + hurtTarget = dynamic_pointer_cast( multiMob ); } } - if (dynamic_pointer_cast( entity ) != NULL) + if ( (item != NULL) && hurtTarget->instanceof(eTYPE_LIVINGENTITY) ) { - if (entity->isAlive()) + item->hurtEnemy(dynamic_pointer_cast(hurtTarget), dynamic_pointer_cast( shared_from_this() ) ); + if (item->count <= 0) { - directAllTameWolvesOnTarget(dynamic_pointer_cast(entity), true); + removeSelectedItem(); } - // 4J Stu - Brought forward wasHurt check to Fix 66140 - Bug: Fire Aspect bypasses "Player v Player" being Disabled + } + if ( entity->instanceof(eTYPE_LIVINGENTITY) ) + { + //awardStat(Stats.damageDealt, (int) Math.round(dmg * 10)); + if (fireAspect > 0 && wasHurt) { entity->setOnFire(fireAspect * 4); @@ -1670,6 +1698,11 @@ void Player::attack(shared_ptr entity) causeFoodExhaustion(FoodConstants::EXHAUSTION_ATTACK); } + + // if (SharedConstants::INGAME_DEBUG_OUTPUT) + // { + // //sendMessage(ChatMessageComponent.forPlainText("DMG " + dmg + ", " + magicBoost + ", " + knockback)); + // } } void Player::crit(shared_ptr entity) @@ -1707,7 +1740,7 @@ Slot *Player::getInventorySlot(int slotId) void Player::remove() { - this->Mob::remove(); + LivingEntity::remove(); inventoryMenu->removed( dynamic_pointer_cast( shared_from_this() ) ); if (containerMenu != NULL) { @@ -1717,7 +1750,7 @@ void Player::remove() bool Player::isInWall() { - return !m_isSleeping && this->Mob::isInWall(); + return !m_isSleeping && LivingEntity::isInWall(); } bool Player::isLocalPlayer() @@ -1759,6 +1792,7 @@ Player::BedSleepingResult Player::startSleepInBed(int x, int y, int z, bool bTes vector > *monsters = level->getEntitiesOfClass(typeid(Monster), AABB::newTemp(x - hRange, y - vRange, z - hRange, x + hRange, y + vRange, z + hRange)); if (!monsters->empty()) { + delete monsters; return NOT_SAFE; } delete monsters; @@ -1778,8 +1812,10 @@ Player::BedSleepingResult Player::startSleepInBed(int x, int y, int z, bool bTes return OK; } - // 4J Stu - You can use a bed from within a minecart, and this causes all sorts of problems. - ride(nullptr); + if (isRiding()) + { + ride(nullptr); + } setSize(0.2f, 0.2f); heightOffset = .2f; @@ -1898,7 +1934,7 @@ void Player::stopSleepInBed(bool forcefulWakeUp, bool updateLevelList, bool save } if (saveRespawnPoint) { - setRespawnPosition(bedPosition); + setRespawnPosition(bedPosition, false); } } @@ -1909,7 +1945,7 @@ bool Player::checkBed() } -Pos *Player::checkBedValidRespawnPosition(Level *level, Pos *pos) +Pos *Player::checkBedValidRespawnPosition(Level *level, Pos *pos, bool forced) { // make sure the chunks around the bed exist ChunkSource *chunkSource = level->getChunkSource(); @@ -1921,6 +1957,15 @@ Pos *Player::checkBedValidRespawnPosition(Level *level, Pos *pos) // make sure the bed is still standing if (level->getTile(pos->x, pos->y, pos->z) != Tile::bed_Id) { + Material *bottomMaterial = level->getMaterial(pos->x, pos->y, pos->z); + Material *topMaterial = level->getMaterial(pos->x, pos->y + 1, pos->z); + bool freeFeet = !bottomMaterial->isSolid() && !bottomMaterial->isLiquid(); + bool freeHead = !topMaterial->isSolid() && !topMaterial->isLiquid(); + + if (forced && freeFeet && freeHead) + { + return pos; + } return NULL; } // make sure the bed still has a stand-up position @@ -2005,15 +2050,22 @@ Pos *Player::getRespawnPosition() return respawnPosition; } -void Player::setRespawnPosition(Pos *respawnPosition) +bool Player::isRespawnForced() +{ + return respawnForced; +} + +void Player::setRespawnPosition(Pos *respawnPosition, bool forced) { if (respawnPosition != NULL) { this->respawnPosition = new Pos(*respawnPosition); + respawnForced = forced; } else { this->respawnPosition = NULL; + respawnForced = false; } } @@ -2028,7 +2080,7 @@ void Player::awardStat(Stat *stat, byteArray paramBlob) void Player::jumpFromGround() { - this->Mob::jumpFromGround(); + LivingEntity::jumpFromGround(); // 4J Stu - This seems to have been missed from 1.7.3, but do we care? //awardStat(Stats::jump, 1); @@ -2050,21 +2102,25 @@ void Player::travel(float xa, float ya) if (abilities.flying && riding == NULL) { - double ydo = this->yd; + double ydo = yd; float ofs = flyingSpeed; flyingSpeed = abilities.getFlyingSpeed(); - this->Mob::travel(xa, ya); - this->yd = ydo * 0.6; + LivingEntity::travel(xa, ya); + yd = ydo * 0.6; flyingSpeed = ofs; } else { - this->Mob::travel(xa, ya); + LivingEntity::travel(xa, ya); } checkMovementStatistiscs(x - preX, y - preY, z - preZ); } +float Player::getSpeed() +{ + return (float) getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->getValue(); +} void Player::checkMovementStatistiscs(double dx, double dy, double dz) { @@ -2142,7 +2198,7 @@ void Player::checkRidingStatistiscs(double dx, double dy, double dz) int distance = (int) Math::round(sqrt(dx * dx + dy * dy + dz * dz) * 100.0f); if (distance > 0) { - if ( dynamic_pointer_cast( riding ) ) + if ( riding->instanceof(eTYPE_MINECART) ) { distanceMinecart += distance; if( distanceMinecart >= 100 ) @@ -2189,7 +2245,7 @@ void Player::checkRidingStatistiscs(double dx, double dy, double dz) } } - else if (dynamic_pointer_cast( riding ) != NULL) + else if ( riding->instanceof(eTYPE_BOAT) ) { distanceBoat += distance; if( distanceBoat >= 100 ) @@ -2199,7 +2255,7 @@ void Player::checkRidingStatistiscs(double dx, double dy, double dz) awardStat(GenericStats::boatOneM(), GenericStats::param_boat(newDistance/100) ); } } - else if (dynamic_pointer_cast( riding ) != NULL) + else if ( riding->instanceof(eTYPE_PIG) ) { distancePig += distance; if( distancePig >= 100 ) @@ -2228,14 +2284,14 @@ void Player::causeFallDamage(float distance) awardStat(GenericStats::fallOneM(), GenericStats::param_fall(newDistance/100) ); } } - this->Mob::causeFallDamage(distance); + LivingEntity::causeFallDamage(distance); } -void Player::killed(shared_ptr mob) +void Player::killed(shared_ptr mob) { // 4J-PB - added the lavaslime enemy - fix for #64007 - TU7: Code: Achievements: TCR#073: Killing Magma Cubes doesn't unlock "Monster Hunter" Achievement. - if( dynamic_pointer_cast( mob ) != NULL || mob->GetType() == eTYPE_GHAST || mob->GetType() == eTYPE_SLIME || mob->GetType() == eTYPE_LAVASLIME || mob->GetType() == eTYPE_ENDERDRAGON) + if( mob->instanceof(eTYPE_ENEMY) || mob->GetType() == eTYPE_GHAST || mob->GetType() == eTYPE_SLIME || mob->GetType() == eTYPE_LAVASLIME || mob->GetType() == eTYPE_ENDERDRAGON) { awardStat(GenericStats::killEnemy(), GenericStats::param_noArgs()); @@ -2282,9 +2338,14 @@ void Player::killed(shared_ptr mob) } } +void Player::makeStuckInWeb() +{ + if (!abilities.flying) LivingEntity::makeStuckInWeb(); +} + Icon *Player::getItemInHandIcon(shared_ptr item, int layer) { - Icon *icon = Mob::getItemInHandIcon(item, layer); + Icon *icon = LivingEntity::getItemInHandIcon(item, layer); if (item->id == Item::fishingRod->id && fishing != NULL) { icon = Item::fishingRod->getEmptyIcon(); @@ -2317,21 +2378,9 @@ shared_ptr Player::getArmor(int pos) return inventory->getArmor(pos); } -void Player::handleInsidePortal() -{ - if (changingDimensionDelay > 0) - { - changingDimensionDelay = 10; - return; - } - - isInsidePortal = true; -} - void Player::increaseXp(int i) { - // Update xp calculations from 1.3 - score += i; + increaseScore(i); int max = INT_MAX - totalExperience; if (i > max) { @@ -2342,17 +2391,26 @@ void Player::increaseXp(int i) while (experienceProgress >= 1) { experienceProgress = (experienceProgress - 1) * getXpNeededForNextLevel(); - levelUp(); + giveExperienceLevels(1); experienceProgress /= getXpNeededForNextLevel(); } } -void Player::withdrawExperienceLevels(int amount) +void Player::giveExperienceLevels(int amount) { - experienceLevel -= amount; + experienceLevel += amount; if (experienceLevel < 0) { experienceLevel = 0; + experienceProgress = 0; + totalExperience = 0; + } + + if (amount > 0 && experienceLevel % 5 == 0 && lastLevelUpTime < tickCount - SharedConstants::TICKS_PER_SECOND * 5.0f) + { + float vol = experienceLevel > 30 ? 1 : experienceLevel / 30.0f; + level->playEntitySound(shared_from_this(), eSoundType_RANDOM_LEVELUP, vol * 0.75f, 1); + lastLevelUpTime = tickCount; } } @@ -2370,11 +2428,6 @@ int Player::getXpNeededForNextLevel() return 17; } -void Player::levelUp() -{ - experienceLevel++; -} - /** * This method adds on to the player's exhaustion, which may decrease the * player's food level. @@ -2433,13 +2486,49 @@ void Player::startUsingItem(shared_ptr instance, int duration) #endif } -bool Player::mayBuild(int x, int y, int z) +bool Player::mayDestroyBlockAt(int x, int y, int z) { - return abilities.mayBuild; + if (abilities.mayBuild) + { + return true; + } + int t = level->getTile(x, y, z); + if (t > 0) { + Tile *tile = Tile::tiles[t]; + + if (tile->material->isDestroyedByHand()) + { + return true; + } + else if (getSelectedItem() != NULL) + { + shared_ptr carried = getSelectedItem(); + + if (carried->canDestroySpecial(tile) || carried->getDestroySpeed(tile) > 1) + { + return true; + } + } + } + return false; +} + +bool Player::mayUseItemAt(int x, int y, int z, int face, shared_ptr item) +{ + if (abilities.mayBuild) + { + return true; + } + if (item != NULL) + { + return item->mayBePlacedInAdventureMode(); + } + return false; } int Player::getExperienceReward(shared_ptr killedBy) { + if (level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) return 0; int reward = experienceLevel * 7; if (reward > 100) { @@ -2459,8 +2548,9 @@ wstring Player::getAName() return name; } -void Player::changeDimension(int i) +bool Player::shouldShowName() { + return true; } void Player::restoreFrom(shared_ptr oldPlayer, bool restoreAll) @@ -2469,21 +2559,24 @@ void Player::restoreFrom(shared_ptr oldPlayer, bool restoreAll) { inventory->replaceWith(oldPlayer->inventory); - health = oldPlayer->health; + setHealth(oldPlayer->getHealth()); foodData = oldPlayer->foodData; experienceLevel = oldPlayer->experienceLevel; totalExperience = oldPlayer->totalExperience; experienceProgress = oldPlayer->experienceProgress; - score = oldPlayer->score; + setScore(oldPlayer->getScore()); + portalEntranceDir = oldPlayer->portalEntranceDir; + } + else if (level->getGameRules()->getBoolean(GameRules::RULE_KEEPINVENTORY)) + { + inventory->replaceWith(oldPlayer->inventory); - for(AUTO_VAR(it, oldPlayer->activeEffects.begin()); it != oldPlayer->activeEffects.end(); ++it) - { - MobEffectInstance *instance = it->second; - addEffectNoUpdate( instance ); - } - oldPlayer->activeEffects.clear(); + experienceLevel = oldPlayer->experienceLevel; + totalExperience = oldPlayer->totalExperience; + experienceProgress = oldPlayer->experienceProgress; + setScore(oldPlayer->getScore()); } enderChestInventory = oldPlayer->enderChestInventory; } @@ -2508,25 +2601,83 @@ wstring Player::getName() wstring Player::getDisplayName() { - return displayName; + //PlayerTeam.formatNameForTeam(getTeam(), name); + + // If player display name is not set, return name + return m_displayName.size() > 0 ? m_displayName : name; } -//Language getLanguage() { return Language.getInstance(); } -//String localize(String key, Object... args) { return getLanguage().getElement(key, args); } +wstring Player::getNetworkName() +{ + // 4J: We can only transmit gamertag in network packets + return name; +} + +Level *Player::getCommandSenderWorld() +{ + return level; +} shared_ptr Player::getEnderChestInventory() { return enderChestInventory; } +shared_ptr Player::getCarried(int slot) +{ + if (slot == 0) return inventory->getSelected(); + return inventory->armor[slot - 1]; +} + shared_ptr Player::getCarriedItem() { return inventory->getSelected(); } +void Player::setEquippedSlot(int slot, shared_ptr item) +{ + inventory->armor[slot] = item; +} + bool Player::isInvisibleTo(shared_ptr player) { - return isInvisible(); + return isInvisible(); +} + +ItemInstanceArray Player::getEquipmentSlots() +{ + return inventory->armor; +} + +bool Player::isCapeHidden() +{ + return getPlayerFlag(FLAG_HIDE_CAPE); +} + +bool Player::isPushedByWater() +{ + return !abilities.flying; +} + +Scoreboard *Player::getScoreboard() +{ + return level->getScoreboard(); +} + +Team *Player::getTeam() +{ + return getScoreboard()->getPlayersTeam(name); +} + +void Player::setAbsorptionAmount(float absorptionAmount) +{ + if (absorptionAmount < 0) absorptionAmount = 0; + getEntityData()->set(DATA_PLAYER_ABSORPTION_ID, absorptionAmount); +} + +float Player::getAbsorptionAmount() +{ + return getEntityData()->getFloat(DATA_PLAYER_ABSORPTION_ID); } int Player::getTexture() @@ -2561,7 +2712,7 @@ int Player::hash_fnct(const shared_ptr k) #ifdef __PS3__ return (int)boost::hash_value( k->name ); // 4J Stu - Names are completely unique? #else - return (int)std::hash{}( k->name ); // 4J Stu - Names are completely unique? + return (int)std::hash{}(k->name); // 4J Stu - Names are completely unique? #endif //__PS3__ } @@ -2770,12 +2921,12 @@ bool Player::isAllowedToInteract(shared_ptr target) bool allowed = true; if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) { - if (target->GetType() == eTYPE_MINECART) + if (target->instanceof(eTYPE_MINECART)) { if (getPlayerGamePrivilege(Player::ePlayerGamePrivilege_CanUseContainers) == 0) { shared_ptr minecart = dynamic_pointer_cast( target ); - if (minecart->type == Minecart::CHEST) + if (minecart->getType() == Minecart::TYPE_CHEST) allowed = false; } diff --git a/Minecraft.World/Player.h b/Minecraft.World/Player.h index 185a70a7..2e223a1e 100644 --- a/Minecraft.World/Player.h +++ b/Minecraft.World/Player.h @@ -1,25 +1,29 @@ #pragma once using namespace std; -#include "Mob.h" +#include "LivingEntity.h" #include "Definitions.h" #include "Abilities.h" #include "FoodData.h" #include "PlayerEnderChestContainer.h" #include "CommandSender.h" +#include "ScoreHolder.h" class AbstractContainerMenu; class Stats; class FishingHook; - +class EntityHorse; class ItemEntity; class Slot; class Pos; - +class TileEntity; +class BeaconTileEntity; class FurnaceTileEntity; class DispenserTileEntity; class SignTileEntity; class BrewingStandTileEntity; +class HopperTileEntity; +class MinecartHopper; class Inventory; class Container; class FoodData; @@ -27,13 +31,13 @@ class DamageSource; class Merchant; class PlayerEnderChestContainer; class GameType; +class Scoreboard; -class Player : public Mob, public CommandSender +class Player : public LivingEntity, public CommandSender, public ScoreHolder { public: static const int MAX_NAME_LENGTH = 16 + 4; static const int MAX_HEALTH = 20; - static const int SWING_DURATION = 6; static const int SLEEP_DURATION = 100; static const int WAKE_UP_DURATION = 10; @@ -47,7 +51,11 @@ private: static const int FLY_ACHIEVEMENT_SPEED = 25; static const int DATA_PLAYER_FLAGS_ID = 16; - static const int DATA_PLAYER_RUNNING_ID = 17; + static const int DATA_PLAYER_ABSORPTION_ID = 17; + static const int DATA_SCORE_ID = 18; + +protected: + static const int FLAG_HIDE_CAPE = 1; public: shared_ptr inventory; @@ -65,16 +73,14 @@ protected: public: BYTE userType; - int score; float oBob, bob; - bool swinging; - int swingTime; wstring name; - int dimension; int takeXpDelay; // 4J-PB - track custom skin + wstring customTextureUrl; + wstring customTextureUrl2; unsigned int m_uiPlayerCurrentSkin; void ChangePlayerSkin(); @@ -83,8 +89,8 @@ public: double xCloakO, yCloakO, zCloakO; double xCloak, yCloak, zCloak; - // 4J-HEG - store display name, added for Xbox One - wstring displayName; + // 4J-HG: store display name, added for Xbox One "game display name" + wstring m_displayName; protected: // player sleeping in bed? @@ -103,20 +109,13 @@ public: private: Pos *respawnPosition; + bool respawnForced; Pos *minecartAchievementPos; //4J Gordon: These are in cms, every time they go > 1m they are entered into the stats int distanceWalk, distanceSwim, distanceFall, distanceClimb, distanceMinecart, distanceBoat, distancePig; public: - int changingDimensionDelay; - -protected: - bool isInsidePortal; - -public: - float portalTime, oPortalTime; - Abilities abilities; int experienceLevel, totalExperience; @@ -131,6 +130,9 @@ protected: float defaultWalkSpeed; float defaultFlySpeed; +private: + int lastLevelUpTime; + public: eINSTANCEOF GetType() { return eTYPE_PLAYER; } @@ -138,11 +140,11 @@ public: // 4J Added to default init void _init(); - Player(Level *level); + Player(Level *level, const wstring &name); virtual ~Player(); - virtual int getMaxHealth(); protected: + virtual void registerAttributes(); virtual void defineSynchedData(); public: @@ -153,7 +155,13 @@ public: void stopUsingItem(); virtual bool isBlocking(); + // 4J Stu - Added for things that should only be ticked once per simulation frame + virtual void updateFrameTick(); + virtual void tick(); + virtual int getPortalWaitTime(); + virtual int getDimensionChangingDelay(); + virtual void playSound(int iSound, float volume, float pitch); protected: void spawnEatParticles(shared_ptr useItem, int count); @@ -172,9 +180,6 @@ public: virtual void rideTick(); virtual void resetPos(); -private: - int getCurrentSwingDuration(); - protected: virtual void serverAiStep(); @@ -185,18 +190,14 @@ private: virtual void touch(shared_ptr entity); public: - //bool addResource(int resource); // 4J - Removed 1.0.1 - int getScore(); + virtual int getScore(); + virtual void setScore(int value); + virtual void increaseScore(int amount); virtual void die(DamageSource *source); - void awardKillScore(shared_ptr victim, int score); - -protected: - virtual int decreaseAirSupply(int currentSupply); - -public: + virtual void awardKillScore(shared_ptr victim, int awardPoints); virtual bool isShootable(); bool isCreativeModeAllowed(); - virtual shared_ptr drop(); + virtual shared_ptr drop(bool all); shared_ptr drop(shared_ptr item); shared_ptr drop(shared_ptr item, bool randomly); @@ -204,16 +205,18 @@ protected: virtual void reallyDrop(shared_ptr thrownItem); public: - float getDestroySpeed(Tile *tile); + float getDestroySpeed(Tile *tile, bool hasProperTool); bool canDestroy(Tile *tile); virtual void readAdditionalSaveData(CompoundTag *entityTag); virtual void addAdditonalSaveData(CompoundTag *entityTag); - static Pos *getRespawnPosition(Level *level, CompoundTag *entityTag); virtual bool openContainer(shared_ptr container); // 4J - added bool return - virtual bool startEnchanting(int x, int y, int z); // 4J - added bool return + virtual bool openHopper(shared_ptr container); + virtual bool openHopper(shared_ptr container); + virtual bool openHorseInventory(shared_ptr horse, shared_ptr container); + virtual bool startEnchanting(int x, int y, int z, const wstring &name); // 4J - added bool return virtual bool startRepairing(int x, int y, int z); // 4J - added bool return - virtual bool startCrafting(int x, int y, int z); // 4J - added boo return - virtual void take(shared_ptr e, int orgCount); + virtual bool startCrafting(int x, int y, int z); // 4J - added bool return + virtual bool openFireworks(int x, int y, int z); // 4J - added virtual float getHeadHeight(); // 4J-PB - added to keep the code happy with the change to make the third person view per player @@ -226,35 +229,34 @@ protected: public: shared_ptr fishing; - virtual bool hurt(DamageSource *source, int dmg); + virtual bool hurt(DamageSource *source, float dmg); + virtual bool canHarmPlayer(shared_ptr target); + virtual bool canHarmPlayer(wstring targetName); // 4J: Added for ServerPlayer when only player name is provided protected: - virtual int getDamageAfterMagicAbsorb(DamageSource *damageSource, int damage); - virtual bool isPlayerVersusPlayer(); - void directAllTameWolvesOnTarget(shared_ptr target, bool skipSitting); - virtual void hurtArmor(int damage); + virtual void hurtArmor(float damage); public: virtual int getArmorValue(); - float getArmorCoverPercentage(); + virtual float getArmorCoverPercentage(); protected: - virtual void actuallyHurt(DamageSource *source, int dmg); + virtual void actuallyHurt(DamageSource *source, float dmg); public: using Entity::interact; virtual bool openFurnace(shared_ptr container); // 4J - added bool return virtual bool openTrap(shared_ptr container); // 4J - added bool return - virtual void openTextEdit(shared_ptr sign); + virtual void openTextEdit(shared_ptr sign); virtual bool openBrewingStand(shared_ptr brewingStand); // 4J - added bool return - virtual bool openTrading(shared_ptr traderTarget); // 4J - added bool return + virtual bool openBeacon(shared_ptr beacon); + virtual bool openTrading(shared_ptr traderTarget, const wstring &name); // 4J - added bool return virtual void openItemInstanceGui(shared_ptr itemInstance); virtual bool interact(shared_ptr entity); virtual shared_ptr getSelectedItem(); void removeSelectedItem(); virtual double getRidingHeight(); - virtual void swing(); virtual void attack(shared_ptr entity); virtual void crit(shared_ptr entity); virtual void magicCrit(shared_ptr entity); @@ -298,7 +300,7 @@ private: bool checkBed(); public: - static Pos *checkBedValidRespawnPosition(Level *level, Pos *pos); + static Pos *checkBedValidRespawnPosition(Level *level, Pos *pos, bool forced); float getSleepRotation(); bool isSleeping(); bool isSleepingLongEnough(); @@ -316,16 +318,18 @@ public: * client. */ virtual void displayClientMessage(int messageId); - Pos *getRespawnPosition(); - void setRespawnPosition(Pos *respawnPosition); + virtual Pos *getRespawnPosition(); + virtual bool isRespawnForced(); + virtual void setRespawnPosition(Pos *respawnPosition, bool forced); virtual void awardStat(Stat *stat, byteArray param); protected: void jumpFromGround(); public: - void travel(float xa, float ya); - void checkMovementStatistiscs(double dx, double dy, double dz); + virtual void travel(float xa, float ya); + virtual float getSpeed(); + virtual void checkMovementStatistiscs(double dx, double dy, double dz); private: void checkRidingStatistiscs(double dx, double dy, double dz); @@ -336,25 +340,20 @@ protected: virtual void causeFallDamage(float distance); public: - virtual void killed(shared_ptr mob); + virtual void killed(shared_ptr mob); + virtual void makeStuckInWeb(); virtual Icon *getItemInHandIcon(shared_ptr item, int layer); virtual shared_ptr getArmor(int pos); - virtual void handleInsidePortal(); - - void increaseXp(int i); - virtual void withdrawExperienceLevels(int amount); + virtual void increaseXp(int i); + virtual void giveExperienceLevels(int amount); int getXpNeededForNextLevel(); - -private: - void levelUp(); - -public: void causeFoodExhaustion(float amount); FoodData *getFoodData(); bool canEat(bool magicalItem); bool isHurt(); virtual void startUsingItem(shared_ptr instance, int duration); - bool mayBuild(int x, int y, int z); + virtual bool mayDestroyBlockAt(int x, int y, int z); + virtual bool mayUseItemAt(int x, int y, int z, int face, shared_ptr item); protected: virtual int getExperienceReward(shared_ptr killedBy); @@ -362,8 +361,7 @@ protected: public: virtual wstring getAName(); - - virtual void changeDimension(int i); + virtual bool shouldShowName(); virtual void restoreFrom(shared_ptr oldPlayer, bool restoreAll); protected: @@ -373,17 +371,26 @@ public: void onUpdateAbilities(); void setGameMode(GameType *mode); wstring getName(); - wstring getDisplayName(); // 4J added + virtual wstring getDisplayName(); + virtual wstring getNetworkName(); // 4J: Added - //Language getLanguage() { return Language.getInstance(); } - //String localize(String key, Object... args) { return getLanguage().getElement(key, args); } + virtual Level *getCommandSenderWorld(); shared_ptr getEnderChestInventory(); -public: + virtual shared_ptr getCarried(int slot); virtual shared_ptr getCarriedItem(); - + virtual void setEquippedSlot(int slot, shared_ptr item); virtual bool isInvisibleTo(shared_ptr player); + virtual ItemInstanceArray getEquipmentSlots(); + virtual bool isCapeHidden(); + virtual bool isPushedByWater(); + virtual Scoreboard *getScoreboard(); + virtual Team *getTeam(); + virtual void setAbsorptionAmount(float absorptionAmount); + virtual float getAbsorptionAmount(); + + //////// 4J ///////////////// static int hash_fnct(const shared_ptr k); static bool eq_test(const shared_ptr x, const shared_ptr y); @@ -410,8 +417,6 @@ public: PlayerUID getXuid() { return m_xuid; } void setOnlineXuid(PlayerUID xuid) { m_OnlineXuid = xuid; } PlayerUID getOnlineXuid() { return m_OnlineXuid; } - void setUUID(const wstring &UUID) { m_UUID = UUID; } - wstring getUUID() { return m_UUID; } void setPlayerIndex(DWORD dwIndex) { m_playerIndex = dwIndex; } DWORD getPlayerIndex() { return m_playerIndex; } @@ -421,15 +426,13 @@ public: void setShowOnMaps(bool bVal) { m_bShownOnMaps = bVal; } bool canShowOnMaps() { return m_bShownOnMaps && !getPlayerGamePrivilege(ePlayerGamePrivilege_Invisible); } - + virtual void sendMessage(const wstring& message, ChatPacket::EChatPacketMessage type = ChatPacket::e_ChatCustom, int customData = -1, const wstring& additionalMessage = L"") { } private: PlayerUID m_xuid; PlayerUID m_OnlineXuid; protected: - wstring m_UUID; // 4J Added - bool m_bShownOnMaps; bool m_bIsGuest; diff --git a/Minecraft.World/PlayerAbilitiesPacket.cpp b/Minecraft.World/PlayerAbilitiesPacket.cpp index b1b854a5..d02f164c 100644 --- a/Minecraft.World/PlayerAbilitiesPacket.cpp +++ b/Minecraft.World/PlayerAbilitiesPacket.cpp @@ -3,8 +3,6 @@ #include "net.minecraft.network.packet.h" #include "PlayerAbilitiesPacket.h" -const float PlayerAbilitiesPacket::SPEED_ACCURACY = 255.0f; - PlayerAbilitiesPacket::PlayerAbilitiesPacket() { invulnerable = false; @@ -17,24 +15,24 @@ PlayerAbilitiesPacket::PlayerAbilitiesPacket() PlayerAbilitiesPacket::PlayerAbilitiesPacket(Abilities *abilities) { - this->setInvulnerable(abilities->invulnerable); - this->setFlying(abilities->flying); - this->setCanFly(abilities->mayfly); - this->setInstabuild(abilities->instabuild); - this->setFlyingSpeed(abilities->getFlyingSpeed()); - this->setWalkingSpeed(abilities->getWalkingSpeed()); + setInvulnerable(abilities->invulnerable); + setFlying(abilities->flying); + setCanFly(abilities->mayfly); + setInstabuild(abilities->instabuild); + setFlyingSpeed(abilities->getFlyingSpeed()); + setWalkingSpeed(abilities->getWalkingSpeed()); } void PlayerAbilitiesPacket::read(DataInputStream *dis) { byte bitfield = dis->readByte(); - this->setInvulnerable((bitfield & FLAG_INVULNERABLE) > 0); - this->setFlying((bitfield & FLAG_FLYING) > 0); - this->setCanFly((bitfield & FLAG_CAN_FLY) > 0); - this->setInstabuild((bitfield & FLAG_INSTABUILD) > 0); - this->setFlyingSpeed(dis->readByte() / SPEED_ACCURACY); - this->setWalkingSpeed(dis->readByte() / SPEED_ACCURACY); + setInvulnerable((bitfield & FLAG_INVULNERABLE) > 0); + setFlying((bitfield & FLAG_FLYING) > 0); + setCanFly((bitfield & FLAG_CAN_FLY) > 0); + setInstabuild((bitfield & FLAG_INSTABUILD) > 0); + setFlyingSpeed(dis->readFloat()); + setWalkingSpeed(dis->readFloat()); } void PlayerAbilitiesPacket::write(DataOutputStream *dos) @@ -47,8 +45,8 @@ void PlayerAbilitiesPacket::write(DataOutputStream *dos) if (canInstabuild()) bitfield |= FLAG_INSTABUILD; dos->writeByte(bitfield); - dos->writeByte((int) (flyingSpeed * SPEED_ACCURACY)); - dos->writeByte((int) (walkingSpeed * SPEED_ACCURACY)); + dos->writeFloat(flyingSpeed); + dos->writeFloat(walkingSpeed); } void PlayerAbilitiesPacket::handle(PacketListener *listener) @@ -113,7 +111,7 @@ float PlayerAbilitiesPacket::getFlyingSpeed() void PlayerAbilitiesPacket::setFlyingSpeed(float flySpeed) { - this->flyingSpeed = flySpeed; + flyingSpeed = flySpeed; } float PlayerAbilitiesPacket::getWalkingSpeed() diff --git a/Minecraft.World/PlayerAbilitiesPacket.h b/Minecraft.World/PlayerAbilitiesPacket.h index 21c1fdc2..8cd82bf5 100644 --- a/Minecraft.World/PlayerAbilitiesPacket.h +++ b/Minecraft.World/PlayerAbilitiesPacket.h @@ -11,7 +11,6 @@ private: static const int FLAG_FLYING = 1 << 1; static const int FLAG_CAN_FLY = 1 << 2; static const int FLAG_INSTABUILD = 1 << 3; - static const float SPEED_ACCURACY; bool invulnerable; bool _isFlying; diff --git a/Minecraft.World/PlayerActionPacket.cpp b/Minecraft.World/PlayerActionPacket.cpp index ce438cb6..aaa3e37e 100644 --- a/Minecraft.World/PlayerActionPacket.cpp +++ b/Minecraft.World/PlayerActionPacket.cpp @@ -7,7 +7,7 @@ const int PlayerActionPacket::START_DESTROY_BLOCK = 0; const int PlayerActionPacket::ABORT_DESTROY_BLOCK = 1; const int PlayerActionPacket::STOP_DESTROY_BLOCK = 2; -const int PlayerActionPacket::GET_UPDATED_BLOCK = 3; +const int PlayerActionPacket::DROP_ALL_ITEMS = 3; const int PlayerActionPacket::DROP_ITEM = 4; const int PlayerActionPacket::RELEASE_USE_ITEM = 5; @@ -31,11 +31,11 @@ PlayerActionPacket::PlayerActionPacket(int action, int x, int y, int z, int face void PlayerActionPacket::read(DataInputStream *dis) //throws IOException { - action = dis->read(); + action = dis->readUnsignedByte(); x = dis->readInt(); - y = dis->read(); + y = dis->readUnsignedByte(); z = dis->readInt(); - face = dis->read(); + face = dis->readUnsignedByte(); } void PlayerActionPacket::write(DataOutputStream *dos) //throws IOException diff --git a/Minecraft.World/PlayerActionPacket.h b/Minecraft.World/PlayerActionPacket.h index 0228ebb4..45c077d2 100644 --- a/Minecraft.World/PlayerActionPacket.h +++ b/Minecraft.World/PlayerActionPacket.h @@ -9,7 +9,7 @@ public: static const int START_DESTROY_BLOCK; static const int ABORT_DESTROY_BLOCK; static const int STOP_DESTROY_BLOCK; - static const int GET_UPDATED_BLOCK; + static const int DROP_ALL_ITEMS; static const int DROP_ITEM; static const int RELEASE_USE_ITEM; diff --git a/Minecraft.World/PlayerCommandPacket.cpp b/Minecraft.World/PlayerCommandPacket.cpp index 6aecc0e6..72e34c80 100644 --- a/Minecraft.World/PlayerCommandPacket.cpp +++ b/Minecraft.World/PlayerCommandPacket.cpp @@ -14,30 +14,43 @@ const int PlayerCommandPacket::START_SPRINTING = 4; const int PlayerCommandPacket::STOP_SPRINTING = 5; const int PlayerCommandPacket::START_IDLEANIM = 6; const int PlayerCommandPacket::STOP_IDLEANIM = 7; +const int PlayerCommandPacket::RIDING_JUMP = 8; +const int PlayerCommandPacket::OPEN_INVENTORY = 9; PlayerCommandPacket::PlayerCommandPacket() { id = -1; action = 0; + data = 0; } PlayerCommandPacket::PlayerCommandPacket(shared_ptr e, int action) { id = e->entityId; this->action = action; + this->data = 0; +} + +PlayerCommandPacket::PlayerCommandPacket(shared_ptr e, int action, int data) +{ + id = e->entityId; + this->action = action; + this->data = data; } void PlayerCommandPacket::read(DataInputStream *dis) //throws IOException { id = dis->readInt(); action = dis->readByte(); + data = dis->readInt(); } void PlayerCommandPacket::write(DataOutputStream *dos) //throws IOException { dos->writeInt(id); dos->writeByte(action); + dos->writeInt(data); } void PlayerCommandPacket::handle(PacketListener *listener) @@ -47,5 +60,5 @@ void PlayerCommandPacket::handle(PacketListener *listener) int PlayerCommandPacket::getEstimatedSize() { - return 5; + return 9; } diff --git a/Minecraft.World/PlayerCommandPacket.h b/Minecraft.World/PlayerCommandPacket.h index dd6c8cb1..92ee57eb 100644 --- a/Minecraft.World/PlayerCommandPacket.h +++ b/Minecraft.World/PlayerCommandPacket.h @@ -7,12 +7,14 @@ class PlayerCommandPacket : public Packet, public enable_shared_from_this e, int action); + PlayerCommandPacket(shared_ptr e, int action, int data); virtual void read(DataInputStream *dis); virtual void write(DataOutputStream *dos); diff --git a/Minecraft.World/PlayerEnderChestContainer.cpp b/Minecraft.World/PlayerEnderChestContainer.cpp index 466d9710..f0a1aaa3 100644 --- a/Minecraft.World/PlayerEnderChestContainer.cpp +++ b/Minecraft.World/PlayerEnderChestContainer.cpp @@ -1,12 +1,18 @@ #include "stdafx.h" #include "net.minecraft.world.level.tile.entity.h" +#include "ContainerOpenPacket.h" #include "PlayerEnderChestContainer.h" -PlayerEnderChestContainer::PlayerEnderChestContainer() : SimpleContainer(IDS_TILE_ENDERCHEST, 9 * 3) +PlayerEnderChestContainer::PlayerEnderChestContainer() : SimpleContainer(IDS_TILE_ENDERCHEST, L"", false, 9 * 3) { activeChest = nullptr; } +int PlayerEnderChestContainer::getContainerType() +{ + return ContainerOpenPacket::ENDER_CHEST; +} + void PlayerEnderChestContainer::setActiveChest(shared_ptr activeChest) { this->activeChest = activeChest; @@ -69,4 +75,9 @@ void PlayerEnderChestContainer::stopOpen() } SimpleContainer::stopOpen(); activeChest = nullptr; +} + +bool PlayerEnderChestContainer::canPlaceItem(int slot, shared_ptr item) +{ + return true; } \ No newline at end of file diff --git a/Minecraft.World/PlayerEnderChestContainer.h b/Minecraft.World/PlayerEnderChestContainer.h index 523417aa..67522244 100644 --- a/Minecraft.World/PlayerEnderChestContainer.h +++ b/Minecraft.World/PlayerEnderChestContainer.h @@ -12,10 +12,13 @@ private: public: PlayerEnderChestContainer(); + virtual int getContainerType(); + void setActiveChest(shared_ptr activeChest); void setItemsByTag(ListTag *enderItemsList); ListTag *createTag(); bool stillValid(shared_ptr player); void startOpen(); void stopOpen(); + bool canPlaceItem(int slot, shared_ptr item); }; \ No newline at end of file diff --git a/Minecraft.World/PlayerIO.h b/Minecraft.World/PlayerIO.h index 559ab2ee..153c55e3 100644 --- a/Minecraft.World/PlayerIO.h +++ b/Minecraft.World/PlayerIO.h @@ -11,7 +11,7 @@ class PlayerIO { public: virtual void save(shared_ptr player) = 0; - virtual bool load(shared_ptr player) = 0; // 4J Changed return val to bool to check if new player or loaded player + virtual CompoundTag *load(shared_ptr player) = 0; virtual CompoundTag *loadPlayerDataTag(PlayerUID xuid) = 0; // 4J Changed from string name to xuid // 4J Added diff --git a/Minecraft.World/PlayerInputPacket.cpp b/Minecraft.World/PlayerInputPacket.cpp index 6dd6fcae..04aebf0f 100644 --- a/Minecraft.World/PlayerInputPacket.cpp +++ b/Minecraft.World/PlayerInputPacket.cpp @@ -8,40 +8,32 @@ PlayerInputPacket::PlayerInputPacket() { - xa = 0.0f; - ya = 0.0f; + xxa = 0.0f; + yya = 0.0f; isJumpingVar = false; isSneakingVar = false; - xRot = 0.0f; - yRot = 0.0f; } -PlayerInputPacket::PlayerInputPacket(float xa, float ya, bool isJumpingVar, bool isSneakingVar, float xRot, float yRot) +PlayerInputPacket::PlayerInputPacket(float xxa, float yya, bool isJumpingVar, bool isSneakingVar) { - this->xa = xa; - this->ya = ya; + this->xxa = xxa; + this->yya = yya; this->isJumpingVar = isJumpingVar; this->isSneakingVar = isSneakingVar; - this->xRot = xRot; - this->yRot = yRot; } void PlayerInputPacket::read(DataInputStream *dis) //throws IOException { - xa = dis->readFloat(); - ya = dis->readFloat(); - xRot = dis->readFloat(); - yRot = dis->readFloat(); + xxa = dis->readFloat(); + yya = dis->readFloat(); isJumpingVar = dis->readBoolean(); isSneakingVar = dis->readBoolean(); } void PlayerInputPacket::write(DataOutputStream *dos) //throws IOException { - dos->writeFloat(xa); - dos->writeFloat(ya); - dos->writeFloat(xRot); - dos->writeFloat(yRot); + dos->writeFloat(xxa); + dos->writeFloat(yya); dos->writeBoolean(isJumpingVar); dos->writeBoolean(isSneakingVar); } @@ -53,27 +45,17 @@ void PlayerInputPacket::handle(PacketListener *listener) int PlayerInputPacket::getEstimatedSize() { - return 18; + return 10; } -float PlayerInputPacket::getXa() +float PlayerInputPacket::getXxa() { - return xa; + return xxa; } -float PlayerInputPacket::getXRot() +float PlayerInputPacket::getYya() { - return xRot; -} - -float PlayerInputPacket::getYa() -{ - return ya; -} - -float PlayerInputPacket::getYRot() -{ - return yRot; + return yya; } bool PlayerInputPacket::isJumping() diff --git a/Minecraft.World/PlayerInputPacket.h b/Minecraft.World/PlayerInputPacket.h index 8bc11d3e..bc2d3985 100644 --- a/Minecraft.World/PlayerInputPacket.h +++ b/Minecraft.World/PlayerInputPacket.h @@ -7,26 +7,22 @@ class PlayerInputPacket : public Packet, public enable_shared_from_this args = getArguments(matcher.group(TARGETS_GROUP_ARGS)); + String type = matcher.group(TARGETS_GROUP_TYPE); + int rangeMin = getDefaultRangeMin(type); + int rangeMax = getDefaultRangeMax(type); + int levelMin = getDefaultLevelMin(type); + int levelMax = getDefaultLevelMax(type); + int count = getDefaultCount(type); + int mode = LevelSettings.GameType.NOT_SET.getId(); + Pos pos = source.getCommandSenderWorldPosition(); + Map scores = getScores(args); + String name = null; + String team = null; + boolean requireLevel = false; + + if (args.containsKey(ARGUMENT_RANGE_MIN)) { + rangeMin = Mth.getInt(args.get(ARGUMENT_RANGE_MIN), rangeMin); + requireLevel = true; + } + if (args.containsKey(ARGUMENT_RANGE_MAX)) { + rangeMax = Mth.getInt(args.get(ARGUMENT_RANGE_MAX), rangeMax); + requireLevel = true; + } + if (args.containsKey(ARGUMENT_LEVEL_MIN)) { + levelMin = Mth.getInt(args.get(ARGUMENT_LEVEL_MIN), levelMin); + } + if (args.containsKey(ARGUMENT_LEVEL_MAX)) { + levelMax = Mth.getInt(args.get(ARGUMENT_LEVEL_MAX), levelMax); + } + if (args.containsKey(ARGUMENT_COORDINATE_X)) { + pos.x = Mth.getInt(args.get(ARGUMENT_COORDINATE_X), pos.x); + requireLevel = true; + } + if (args.containsKey(ARGUMENT_COORDINATE_Y)) { + pos.y = Mth.getInt(args.get(ARGUMENT_COORDINATE_Y), pos.y); + requireLevel = true; + } + if (args.containsKey(ARGUMENT_COORDINATE_Z)) { + pos.z = Mth.getInt(args.get(ARGUMENT_COORDINATE_Z), pos.z); + requireLevel = true; + } + if (args.containsKey(ARGUMENT_MODE)) { + mode = Mth.getInt(args.get(ARGUMENT_MODE), mode); + } + if (args.containsKey(ARGUMENT_COUNT)) { + count = Mth.getInt(args.get(ARGUMENT_COUNT), count); + } + if (args.containsKey(ARGUMENT_TEAM_NAME)) { + team = args.get(ARGUMENT_TEAM_NAME); + } + if (args.containsKey(ARGUMENT_PLAYER_NAME)) { + name = args.get(ARGUMENT_PLAYER_NAME); + } + + Level level = requireLevel ? source.getCommandSenderWorld() : null; + + if (type.equals(TARGET_NEAREST) || type.equals(TARGET_ALL)) { + List players = MinecraftServer.getInstance().getPlayers().getPlayers(pos, rangeMin, rangeMax, count, mode, levelMin, levelMax, scores, name, team, level); + return players == null || players.isEmpty() ? new ServerPlayer[0] : players.toArray(new ServerPlayer[0]); + } else if (type.equals(TARGET_RANDOM)) { + List players = MinecraftServer.getInstance().getPlayers().getPlayers(pos, rangeMin, rangeMax, 0, mode, levelMin, levelMax, scores, name, team, level); + Collections.shuffle(players); + players = players.subList(0, Math.min(count, players.size())); + return players == null || players.isEmpty() ? new ServerPlayer[0] : players.toArray(new ServerPlayer[0]); + } else { + return null; + } + } else { + return null; + } + } + + public static Map getScores(Map input) { + Map result = new HashMap(); + + for (String key : input.keySet()) { + if (key.startsWith(ARGUMENT_SCORE_PREFIX) && key.length() > ARGUMENT_SCORE_PREFIX.length()) { + String name = key.substring(ARGUMENT_SCORE_PREFIX.length()); + result.put(name, Mth.getInt(input.get(key), 1)); + } + } + + return result; + } + + public static boolean isList(String input) { + Matcher matcher = PATTERN_TARGETS.matcher(input); + + if (matcher.matches()) { + Map args = getArguments(matcher.group(TARGETS_GROUP_ARGS)); + String type = matcher.group(TARGETS_GROUP_TYPE); + int count = getDefaultCount(type); + if (args.containsKey(ARGUMENT_COUNT)) count = Mth.getInt(args.get(ARGUMENT_COUNT), count); + return count != 1; + } + + return false; + } + + public static boolean isPattern(String input, String onlyType) { + Matcher matcher = PATTERN_TARGETS.matcher(input); + + if (matcher.matches()) { + String type = matcher.group(TARGETS_GROUP_TYPE); + if (onlyType != null && !onlyType.equals(type)) return false; + + return true; + } + + return false; + } + + public static boolean isPattern(String input) { + return isPattern(input, null); + } + + private static final int getDefaultRangeMin(String type) { + return 0; + } + + private static final int getDefaultRangeMax(String type) { + return 0; + } + + private static final int getDefaultLevelMax(String type) { + return Integer.MAX_VALUE; + } + + private static final int getDefaultLevelMin(String type) { + return 0; + } + + private static final int getDefaultCount(String type) { + if (type.equals(TARGET_ALL)) { + return 0; + } else { + return 1; + } + } + + private static Map getArguments(String input) { + HashMap result = new HashMap(); + if (input == null) return result; + Matcher matcher = PATTERN_SHORT_ARGUMENT.matcher(input); + int count = 0; + int last = -1; + + while (matcher.find()) { + String name = null; + + switch (count++) { + case 0: + name = ARGUMENT_COORDINATE_X; + break; + case 1: + name = ARGUMENT_COORDINATE_Y; + break; + case 2: + name = ARGUMENT_COORDINATE_Z; + break; + case 3: + name = ARGUMENT_RANGE_MAX; + break; + } + + if (name != null && matcher.group(1).length() > 0) result.put(name, matcher.group(1)); + last = matcher.end(); + } + + if (last < input.length()) { + matcher = PATTERN_LONG_ARGUMENT.matcher(last == -1 ? input : input.substring(last)); + + while (matcher.find()) { + result.put(matcher.group(1), matcher.group(2)); + } + } + + return result; + } +} + +*/ \ No newline at end of file diff --git a/Minecraft.World/PlayerTeam.cpp b/Minecraft.World/PlayerTeam.cpp new file mode 100644 index 00000000..3e159af4 --- /dev/null +++ b/Minecraft.World/PlayerTeam.cpp @@ -0,0 +1,120 @@ +#include "stdafx.h" +#include "net.minecraft.world.scores.h" +#include "PlayerTeam.h" + +PlayerTeam::PlayerTeam(Scoreboard *scoreboard, const wstring &name) +{ + this->scoreboard = scoreboard; + this->name = name; + displayName = name; + + prefix = L""; + suffix = L""; + allowFriendlyFire = true; + seeFriendlyInvisibles = true; +} + +Scoreboard *PlayerTeam::getScoreboard() +{ + return scoreboard; +} + +wstring PlayerTeam::getName() +{ + return name; +} + +wstring PlayerTeam::getDisplayName() +{ + return displayName; +} + +void PlayerTeam::setDisplayName(const wstring &displayName) +{ + //if (displayName == null) throw new IllegalArgumentException("Name cannot be null"); + this->displayName = displayName; + scoreboard->onTeamChanged(this); +} + +unordered_set *PlayerTeam::getPlayers() +{ + return &players; +} + +wstring PlayerTeam::getPrefix() +{ + return prefix; +} + +void PlayerTeam::setPrefix(const wstring &prefix) +{ + //if (prefix == null) throw new IllegalArgumentException("Prefix cannot be null"); + this->prefix = prefix; + scoreboard->onTeamChanged(this); +} + +wstring PlayerTeam::getSuffix() +{ + return suffix; +} + +void PlayerTeam::setSuffix(const wstring &suffix) +{ + //if (suffix == null) throw new IllegalArgumentException("Suffix cannot be null"); + this->suffix = suffix; + scoreboard->onTeamChanged(this); +} + +wstring PlayerTeam::getFormattedName(const wstring &teamMemberName) +{ + return getPrefix() + teamMemberName + getSuffix(); +} + +wstring PlayerTeam::formatNameForTeam(PlayerTeam *team) +{ + return formatNameForTeam(team, team->getDisplayName()); +} + +wstring PlayerTeam::formatNameForTeam(Team *team, const wstring &name) +{ + if (team == NULL) return name; + return team->getFormattedName(name); +} + +bool PlayerTeam::isAllowFriendlyFire() +{ + return allowFriendlyFire; +} + +void PlayerTeam::setAllowFriendlyFire(bool allowFriendlyFire) +{ + this->allowFriendlyFire = allowFriendlyFire; + scoreboard->onTeamChanged(this); +} + +bool PlayerTeam::canSeeFriendlyInvisibles() +{ + return seeFriendlyInvisibles; +} + +void PlayerTeam::setSeeFriendlyInvisibles(bool seeFriendlyInvisibles) +{ + this->seeFriendlyInvisibles = seeFriendlyInvisibles; + scoreboard->onTeamChanged(this); +} + +int PlayerTeam::packOptions() +{ + int result = 0; + + if (isAllowFriendlyFire()) result |= 1 << BIT_FRIENDLY_FIRE; + if (canSeeFriendlyInvisibles()) result |= 1 << BIT_SEE_INVISIBLES; + + return result; +} + +void PlayerTeam::unpackOptions(int options) +{ + setAllowFriendlyFire((options & (1 << BIT_FRIENDLY_FIRE)) > 0); + setSeeFriendlyInvisibles((options & (1 << BIT_SEE_INVISIBLES)) > 0); +} \ No newline at end of file diff --git a/Minecraft.World/PlayerTeam.h b/Minecraft.World/PlayerTeam.h new file mode 100644 index 00000000..bf91309a --- /dev/null +++ b/Minecraft.World/PlayerTeam.h @@ -0,0 +1,49 @@ +#pragma once + +#include "Team.h" + +class Scoreboard; + +class PlayerTeam : public Team +{ +public: + static const int MAX_NAME_LENGTH = 16; + static const int MAX_DISPLAY_NAME_LENGTH = 32; + static const int MAX_PREFIX_LENGTH = 16; + static const int MAX_SUFFIX_LENGTH = 16; + +private: + static const int BIT_FRIENDLY_FIRE = 0; + static const int BIT_SEE_INVISIBLES = 1; + + Scoreboard *scoreboard; + wstring name; + unordered_set players; + wstring displayName; + wstring prefix; + wstring suffix; + bool allowFriendlyFire; + bool seeFriendlyInvisibles; + +public: + PlayerTeam(Scoreboard *scoreboard, const wstring &name); + + Scoreboard *getScoreboard(); + wstring getName(); + wstring getDisplayName(); + void setDisplayName(const wstring &displayName); + unordered_set *getPlayers(); + wstring getPrefix(); + void setPrefix(const wstring &prefix); + wstring getSuffix(); + void setSuffix(const wstring &suffix); + wstring getFormattedName(const wstring &teamMemberName); + static wstring formatNameForTeam(PlayerTeam *team); + static wstring formatNameForTeam(Team *team, const wstring &name); + bool isAllowFriendlyFire(); + void setAllowFriendlyFire(bool allowFriendlyFire); + bool canSeeFriendlyInvisibles(); + void setSeeFriendlyInvisibles(bool seeFriendlyInvisibles); + int packOptions(); + void unpackOptions(int options); +}; \ No newline at end of file diff --git a/Minecraft.World/PortalForcer.cpp b/Minecraft.World/PortalForcer.cpp index 7c9b7a86..8880399e 100644 --- a/Minecraft.World/PortalForcer.cpp +++ b/Minecraft.World/PortalForcer.cpp @@ -3,58 +3,72 @@ #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.dimension.h" +#include "..\Minecraft.Client\ServerLevel.h" #include "PortalForcer.h" -PortalForcer::PortalForcer() +PortalForcer::PortalPosition::PortalPosition(int x, int y, int z, __int64 time) : Pos(x, y, z) { - random = new Random(); + lastUsed = time; } +PortalForcer::PortalForcer(ServerLevel *level) +{ + this->level = level; + random = new Random(level->getSeed()); +} + +PortalForcer::~PortalForcer() +{ + for(AUTO_VAR(it,cachedPortals.begin()); it != cachedPortals.end(); ++it) + { + delete it->second; + } +} -void PortalForcer::force(Level *level, shared_ptr e) +void PortalForcer::force(shared_ptr e, double xOriginal, double yOriginal, double zOriginal, float yRotOriginal) { - if (level->dimension->id == 1) + if (level->dimension->id == 1) { - int x = Mth::floor(e->x); - int y = Mth::floor(e->y) - 1; - int z = Mth::floor(e->z); + int x = Mth::floor(e->x); + int y = Mth::floor(e->y) - 1; + int z = Mth::floor(e->z); - int xa = 1; - int za = 0; - for (int b = -2; b <= 2; b++) + int xa = 1; + int za = 0; + for (int b = -2; b <= 2; b++) { - for (int s = -2; s <= 2; s++) + for (int s = -2; s <= 2; s++) { - for (int h = -1; h < 3; h++) + for (int h = -1; h < 3; h++) { - int xt = x + s * xa + b * za; - int yt = y + h; - int zt = z + s * za - b * xa; + int xt = x + s * xa + b * za; + int yt = y + h; + int zt = z + s * za - b * xa; - bool border = h < 0; + bool border = h < 0; - level->setTile(xt, yt, zt, border ? Tile::obsidian_Id : 0); - } - } - } + level->setTileAndUpdate(xt, yt, zt, border ? Tile::obsidian_Id : 0); + } + } + } - e->moveTo(x, y, z, e->yRot, 0); - e->xd = e->yd = e->zd = 0; + e->moveTo(x, y, z, e->yRot, 0); + e->xd = e->yd = e->zd = 0; - return; - } + return; + } - if (findPortal(level, e)) + if (findPortal(e, xOriginal, yOriginal, zOriginal, yRotOriginal)) { return; } - createPortal(level, e); - findPortal(level, e); + createPortal(e); + findPortal(e, xOriginal, yOriginal, zOriginal, yRotOriginal); } -bool PortalForcer::findPortal(Level *level, shared_ptr e) +bool PortalForcer::findPortal(shared_ptr e, double xOriginal, double yOriginal, double zOriginal, float yRotOriginal) { // 4J Stu - Decrease the range at which we search for a portal in the nether given our smaller nether int r = 16;//* 8; @@ -79,29 +93,47 @@ bool PortalForcer::findPortal(Level *level, shared_ptr e) int xc = Mth::floor(e->x); int zc = Mth::floor(e->z); - for (int x = xc - r; x <= xc + r; x++) + long hash = ChunkPos::hashCode(xc, zc); + bool updateCache = true; + + AUTO_VAR(it, cachedPortals.find(hash)); + if (it != cachedPortals.end()) + { + PortalPosition *pos = it->second; + + closest = 0; + xTarget = pos->x; + yTarget = pos->y; + zTarget = pos->z; + pos->lastUsed = level->getGameTime(); + updateCache = false; + } + else { - double xd = (x + 0.5) - e->x; - for (int z = zc - r; z <= zc + r; z++) + for (int x = xc - r; x <= xc + r; x++) { - double zd = (z + 0.5) - e->z; - for (int y = level->getHeight() - 1; y >= 0; y--) + double xd = (x + 0.5) - e->x; + for (int z = zc - r; z <= zc + r; z++) { - if (level->getTile(x, y, z) == Tile::portalTile_Id) + double zd = (z + 0.5) - e->z; + for (int y = level->getHeight() - 1; y >= 0; y--) { - while (level->getTile(x, y - 1, z) == Tile::portalTile_Id) + if (level->getTile(x, y, z) == Tile::portalTile_Id) { - y--; - } + while (level->getTile(x, y - 1, z) == Tile::portalTile_Id) + { + y--; + } - double yd = (y + 0.5) - e->y; - double dist = xd * xd + yd * yd + zd * zd; - if (closest < 0 || dist < closest) - { - closest = dist; - xTarget = x; - yTarget = y; - zTarget = z; + double yd = (y + 0.5) - e->y; + double dist = xd * xd + yd * yd + zd * zd; + if (closest < 0 || dist < closest) + { + closest = dist; + xTarget = x; + yTarget = y; + zTarget = z; + } } } } @@ -114,18 +146,110 @@ bool PortalForcer::findPortal(Level *level, shared_ptr e) int y = yTarget; int z = zTarget; + if (updateCache) + { + cachedPortals[hash] = new PortalPosition(x, y, z, level->getGameTime()); + cachedPortalKeys.push_back(hash); + } + double xt = x + 0.5; double yt = y + 0.5; double zt = z + 0.5; + int dir = Direction::UNDEFINED; - if (level->getTile(x - 1, y, z) == Tile::portalTile_Id) xt -= 0.5; - if (level->getTile(x + 1, y, z) == Tile::portalTile_Id) xt += 0.5; + if (level->getTile(x - 1, y, z) == Tile::portalTile_Id) dir = Direction::NORTH; + if (level->getTile(x + 1, y, z) == Tile::portalTile_Id) dir = Direction::SOUTH; + if (level->getTile(x, y, z - 1) == Tile::portalTile_Id) dir = Direction::EAST; + if (level->getTile(x, y, z + 1) == Tile::portalTile_Id) dir = Direction::WEST; - if (level->getTile(x, y, z - 1) == Tile::portalTile_Id) zt -= 0.5; - if (level->getTile(x, y, z + 1) == Tile::portalTile_Id) zt += 0.5; + int originalDir = e->getPortalEntranceDir(); - e->moveTo(xt, yt, zt, e->yRot, 0); - e->xd = e->yd = e->zd = 0; + if (dir > Direction::UNDEFINED) + { + int leftDir = Direction::DIRECTION_COUNTER_CLOCKWISE[dir]; + int forwardsx = Direction::STEP_X[dir]; + int forwardsz = Direction::STEP_Z[dir]; + int leftx = Direction::STEP_X[leftDir]; + int leftz = Direction::STEP_Z[leftDir]; + + bool leftBlocked = !level->isEmptyTile(x + forwardsx + leftx, y, z + forwardsz + leftz) || !level->isEmptyTile(x + forwardsx + leftx, y + 1, z + forwardsz + leftz); + bool rightBlocked = !level->isEmptyTile(x + forwardsx, y, z + forwardsz) || !level->isEmptyTile(x + forwardsx, y + 1, z + forwardsz); + + if (leftBlocked && rightBlocked) + { + dir = Direction::DIRECTION_OPPOSITE[dir]; + leftDir = Direction::DIRECTION_OPPOSITE[leftDir]; + forwardsx = Direction::STEP_X[dir]; + forwardsz = Direction::STEP_Z[dir]; + leftx = Direction::STEP_X[leftDir]; + leftz = Direction::STEP_Z[leftDir]; + + x -= leftx; + xt -= leftx; + z -= leftz; + zt -= leftz; + leftBlocked = !level->isEmptyTile(x + forwardsx + leftx, y, z + forwardsz + leftz) || !level->isEmptyTile(x + forwardsx + leftx, y + 1, z + forwardsz + leftz); + rightBlocked = !level->isEmptyTile(x + forwardsx, y, z + forwardsz) || !level->isEmptyTile(x + forwardsx, y + 1, z + forwardsz); + } + + float offsetLeft = 0.5f; + float offsetForwards = 0.5f; + + if (!leftBlocked && rightBlocked) + { + offsetLeft = 1; + } + else if (leftBlocked && !rightBlocked) + { + offsetLeft = 0; + } + else if (leftBlocked && rightBlocked) + { + offsetForwards = 0; + } + + // Center them in the frame and push them out forwards + xt += (leftx * offsetLeft) + (offsetForwards * forwardsx); + zt += (leftz * offsetLeft) + (offsetForwards * forwardsz); + + float xx = 0; + float zz = 0; + float xz = 0; + float zx = 0; + + if (dir == originalDir) + { + xx = 1; + zz = 1; + } + else if (dir == Direction::DIRECTION_OPPOSITE[originalDir]) + { + xx = -1; + zz = -1; + } + else if (dir == Direction::DIRECTION_CLOCKWISE[originalDir]) + { + xz = 1; + zx = -1; + } + else + { + xz = -1; + zx = 1; + } + + double xd = e->xd; + double zd = e->zd; + e->xd = xd * xx + zd * zx; + e->zd = xd * xz + zd * zz; + e->yRot = (yRotOriginal - originalDir * 90) + (dir * 90); + } + else + { + e->xd = e->yd = e->zd = 0; + } + + e->moveTo(xt, yt, zt, e->yRot, e->xRot); return true; } @@ -133,7 +257,7 @@ bool PortalForcer::findPortal(Level *level, shared_ptr e) } -bool PortalForcer::createPortal(Level *level, shared_ptr e) +bool PortalForcer::createPortal(shared_ptr e) { // 4J Stu - Increase the range at which we try and create a portal to stop creating them floating in mid air over lava int r = 16 * 3; @@ -240,7 +364,7 @@ bool PortalForcer::createPortal(Level *level, shared_ptr e) } } } - next_first: continue; +next_first: continue; } } } @@ -299,7 +423,7 @@ bool PortalForcer::createPortal(Level *level, shared_ptr e) } } } - next_second: continue; +next_second: continue; } } } @@ -341,7 +465,7 @@ bool PortalForcer::createPortal(Level *level, shared_ptr e) bool border = h < 0; - level->setTile(xt, yt, zt, border ? Tile::obsidian_Id : 0); + level->setTileAndUpdate(xt, yt, zt, border ? Tile::obsidian_Id : 0); } } } @@ -349,7 +473,6 @@ bool PortalForcer::createPortal(Level *level, shared_ptr e) for (int pass = 0; pass < 4; pass++) { - level->noNeighborUpdate = true; for (int s = 0; s < 4; s++) { for (int h = -1; h < 4; h++) @@ -359,10 +482,9 @@ bool PortalForcer::createPortal(Level *level, shared_ptr e) int zt = z + (s - 1) * za; bool border = s == 0 || s == 3 || h == -1 || h == 3; - level->setTile(xt, yt, zt, border ? Tile::obsidian_Id : Tile::portalTile_Id); + level->setTileAndData(xt, yt, zt, border ? Tile::obsidian_Id : Tile::portalTile_Id, 0, Tile::UPDATE_CLIENTS); } } - level->noNeighborUpdate = false; for (int s = 0; s < 4; s++) { @@ -379,3 +501,28 @@ bool PortalForcer::createPortal(Level *level, shared_ptr e) return true; } + +void PortalForcer::tick(__int64 time) +{ + if (time % (SharedConstants::TICKS_PER_SECOND * 5) == 0) + { + __int64 cutoff = time - SharedConstants::TICKS_PER_SECOND * 30; + + for(AUTO_VAR(it,cachedPortalKeys.begin()); it != cachedPortalKeys.end();) + { + __int64 key = *it; + PortalPosition *pos = cachedPortals[key]; + + if (pos == NULL || pos->lastUsed < cutoff) + { + delete pos; + it = cachedPortalKeys.erase(it); + cachedPortals.erase(key); + } + else + { + ++it; + } + } + } +} \ No newline at end of file diff --git a/Minecraft.World/PortalForcer.h b/Minecraft.World/PortalForcer.h index feb2f129..a589d9b3 100644 --- a/Minecraft.World/PortalForcer.h +++ b/Minecraft.World/PortalForcer.h @@ -4,18 +4,27 @@ class Random; class PortalForcer { -private: - Random *random; - public: - // 4J Stu Added - Java has no ctor, but we need to initialise random - PortalForcer(); + class PortalPosition : public Pos + { + public: + __int64 lastUsed; - void force(Level *level, shared_ptr e); + PortalPosition(int x, int y, int z, __int64 time); + }; -public: - bool findPortal(Level *level, shared_ptr e); +private: + ServerLevel *level; + Random *random; + unordered_map<__int64, PortalPosition *> cachedPortals; + vector<__int64> cachedPortalKeys; public: - bool createPortal(Level *level, shared_ptr e); + PortalForcer(ServerLevel *level); + ~PortalForcer(); + + void force(shared_ptr e, double xOriginal, double yOriginal, double zOriginal, float yRotOriginal); + bool findPortal(shared_ptr e, double xOriginal, double yOriginal, double zOriginal, float yRotOriginal); + bool createPortal(shared_ptr e); + void tick(__int64 time); }; \ No newline at end of file diff --git a/Minecraft.World/PortalTile.cpp b/Minecraft.World/PortalTile.cpp index 1b500a36..5e891e53 100644 --- a/Minecraft.World/PortalTile.cpp +++ b/Minecraft.World/PortalTile.cpp @@ -26,8 +26,12 @@ void PortalTile::tick(Level *level, int x, int y, int z, Random *random) if (y0 > 0 && !level->isSolidBlockingTile(x, y0 + 1, z)) { // spawn a pig man here - int result = 0; - bool spawned = MonsterPlacerItem::spawnMobAt(level, 57, x + .5, y0 + 1.1, z + .5, &result) != NULL; + int iResult = 0; + shared_ptr entity = SpawnEggItem::spawnMobAt(level, 57, x + .5, y0 + 1.1, z + .5, &iResult); + if (entity != NULL) + { + entity->changingDimensionDelay = entity->getDimensionChangingDelay(); + } } } } @@ -39,18 +43,18 @@ AABB *PortalTile::getAABB(Level *level, int x, int y, int z) void PortalTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { - if (level->getTile(x - 1, y, z) == id || level->getTile(x + 1, y, z) == id) + if (level->getTile(x - 1, y, z) == id || level->getTile(x + 1, y, z) == id) { - float xr = 8 / 16.0f; - float yr = 2 / 16.0f; - this->setShape(0.5f - xr, 0, 0.5f - yr, 0.5f + xr, 1, 0.5f + yr); - } + float xr = 8 / 16.0f; + float yr = 2 / 16.0f; + setShape(0.5f - xr, 0, 0.5f - yr, 0.5f + xr, 1, 0.5f + yr); + } else { - float xr = 2 / 16.0f; - float yr = 8 / 16.0f; - this->setShape(0.5f - xr, 0, 0.5f - yr, 0.5f + xr, 1, 0.5f + yr); - } + float xr = 2 / 16.0f; + float yr = 8 / 16.0f; + setShape(0.5f - xr, 0, 0.5f - yr, 0.5f + xr, 1, 0.5f + yr); + } } bool PortalTile::isSolidRender(bool isServerLevel) @@ -65,124 +69,122 @@ bool PortalTile::isCubeShaped() bool PortalTile::trySpawnPortal(Level *level, int x, int y, int z, bool actuallySpawn) { - int xd = 0; - int zd = 0; - if (level->getTile(x - 1, y, z) == Tile::obsidian_Id || level->getTile(x + 1, y, z) == Tile::obsidian_Id) xd = 1; - if (level->getTile(x, y, z - 1) == Tile::obsidian_Id || level->getTile(x, y, z + 1) == Tile::obsidian_Id) zd = 1; + int xd = 0; + int zd = 0; + if (level->getTile(x - 1, y, z) == Tile::obsidian_Id || level->getTile(x + 1, y, z) == Tile::obsidian_Id) xd = 1; + if (level->getTile(x, y, z - 1) == Tile::obsidian_Id || level->getTile(x, y, z + 1) == Tile::obsidian_Id) zd = 1; - if (xd == zd) return false; + if (xd == zd) return false; - if (level->getTile(x - xd, y, z - zd) == 0) + if (level->getTile(x - xd, y, z - zd) == 0) { - x -= xd; - z -= zd; - } + x -= xd; + z -= zd; + } - for (int xx = -1; xx <= 2; xx++) + for (int xx = -1; xx <= 2; xx++) { - for (int yy = -1; yy <= 3; yy++) + for (int yy = -1; yy <= 3; yy++) { - bool edge = (xx == -1) || (xx == 2) || (yy == -1) || (yy == 3); - if ((xx == -1 || xx == 2) && (yy == -1 || yy == 3)) continue; + bool edge = (xx == -1) || (xx == 2) || (yy == -1) || (yy == 3); + if ((xx == -1 || xx == 2) && (yy == -1 || yy == 3)) continue; - int t = level->getTile(x + xd * xx, y + yy, z + zd * xx); + int t = level->getTile(x + xd * xx, y + yy, z + zd * xx); - if (edge) + if (edge) { - if (t != Tile::obsidian_Id) return false; - } + if (t != Tile::obsidian_Id) return false; + } else { - if (t != 0 && t != Tile::fire_Id) return false; - } - } - } + if (t != 0 && t != Tile::fire_Id) return false; + } + } + } if( !actuallySpawn ) return true; - level->noNeighborUpdate = true; - for (int xx = 0; xx < 2; xx++) + for (int xx = 0; xx < 2; xx++) { - for (int yy = 0; yy < 3; yy++) + for (int yy = 0; yy < 3; yy++) { - level->setTile(x + xd * xx, y + yy, z + zd * xx, Tile::portalTile_Id); - } - } - level->noNeighborUpdate = false; + level->setTileAndData(x + xd * xx, y + yy, z + zd * xx, Tile::portalTile_Id, 0, Tile::UPDATE_CLIENTS); + } + } - return true; + return true; } void PortalTile::neighborChanged(Level *level, int x, int y, int z, int type) { - int xd = 0; - int zd = 1; - if (level->getTile(x - 1, y, z) == id || level->getTile(x + 1, y, z) == id) + int xd = 0; + int zd = 1; + if (level->getTile(x - 1, y, z) == id || level->getTile(x + 1, y, z) == id) { - xd = 1; - zd = 0; - } + xd = 1; + zd = 0; + } - int yBottom = y; - while (level->getTile(x, yBottom - 1, z) == id) - yBottom--; + int yBottom = y; + while (level->getTile(x, yBottom - 1, z) == id) + yBottom--; - if (level->getTile(x, yBottom - 1, z) != Tile::obsidian_Id) + if (level->getTile(x, yBottom - 1, z) != Tile::obsidian_Id) { - level->setTile(x, y, z, 0); - return; - } + level->removeTile(x, y, z); + return; + } - int height = 1; - while (height < 4 && level->getTile(x, yBottom + height, z) == id) - height++; + int height = 1; + while (height < 4 && level->getTile(x, yBottom + height, z) == id) + height++; - if (height != 3 || level->getTile(x, yBottom + height, z) != Tile::obsidian_Id) + if (height != 3 || level->getTile(x, yBottom + height, z) != Tile::obsidian_Id) { - level->setTile(x, y, z, 0); - return; - } + level->removeTile(x, y, z); + return; + } - bool we = level->getTile(x - 1, y, z) == id || level->getTile(x + 1, y, z) == id; - bool ns = level->getTile(x, y, z - 1) == id || level->getTile(x, y, z + 1) == id; - if (we && ns) + bool we = level->getTile(x - 1, y, z) == id || level->getTile(x + 1, y, z) == id; + bool ns = level->getTile(x, y, z - 1) == id || level->getTile(x, y, z + 1) == id; + if (we && ns) { - level->setTile(x, y, z, 0); - return; - } - - if (!(// - (level->getTile(x + xd, y, z + zd) == Tile::obsidian_Id && level->getTile(x - xd, y, z - zd) == id) || // - (level->getTile(x - xd, y, z - zd) == Tile::obsidian_Id && level->getTile(x + xd, y, z + zd) == id)// - )) + level->removeTile(x, y, z); + return; + } + + if (!(// + (level->getTile(x + xd, y, z + zd) == Tile::obsidian_Id && level->getTile(x - xd, y, z - zd) == id) || // + (level->getTile(x - xd, y, z - zd) == Tile::obsidian_Id && level->getTile(x + xd, y, z + zd) == id)// + )) { - level->setTile(x, y, z, 0); - return; - } + level->removeTile(x, y, z); + return; + } } bool PortalTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { - if (level->getTile(x, y, z) == id) return false; + if (level->getTile(x, y, z) == id) return false; - bool w = level->getTile(x - 1, y, z) == id && level->getTile(x - 2, y, z) != id; - bool e = level->getTile(x + 1, y, z) == id && level->getTile(x + 2, y, z) != id; + bool w = level->getTile(x - 1, y, z) == id && level->getTile(x - 2, y, z) != id; + bool e = level->getTile(x + 1, y, z) == id && level->getTile(x + 2, y, z) != id; - bool n = level->getTile(x, y, z - 1) == id && level->getTile(x, y, z - 2) != id; - bool s = level->getTile(x, y, z + 1) == id && level->getTile(x, y, z + 2) != id; + bool n = level->getTile(x, y, z - 1) == id && level->getTile(x, y, z - 2) != id; + bool s = level->getTile(x, y, z + 1) == id && level->getTile(x, y, z + 2) != id; - bool we = w || e; - bool ns = n || s; + bool we = w || e; + bool ns = n || s; - if (we && face == 4) return true; - if (we && face == 5) return true; - if (ns && face == 2) return true; - if (ns && face == 3) return true; + if (we && face == 4) return true; + if (we && face == 5) return true; + if (ns && face == 2) return true; + if (ns && face == 3) return true; - return false; + return false; } int PortalTile::getResourceCount(Random *random) @@ -197,40 +199,42 @@ int PortalTile::getRenderLayer() void PortalTile::entityInside(Level *level, int x, int y, int z, shared_ptr entity) { + if (entity->GetType() == eTYPE_EXPERIENCEORB ) return; // 4J added + if (entity->riding == NULL && entity->rider.lock() == NULL) entity->handleInsidePortal(); } void PortalTile::animateTick(Level *level, int xt, int yt, int zt, Random *random) { - if (random->nextInt(100) == 0) + if (random->nextInt(100) == 0) { - level->playLocalSound(xt + 0.5, yt + 0.5, zt + 0.5, eSoundType_PORTAL_PORTAL, 0.5f, random->nextFloat() * 0.4f + 0.8f); - } - for (int i = 0; i < 4; i++) + level->playLocalSound(xt + 0.5, yt + 0.5, zt + 0.5, eSoundType_PORTAL_PORTAL, 0.5f, random->nextFloat() * 0.4f + 0.8f, false); + } + for (int i = 0; i < 4; i++) { - double x = xt + random->nextFloat(); - double y = yt + random->nextFloat(); - double z = zt + random->nextFloat(); - double xa = 0; - double ya = 0; - double za = 0; - int flip = random->nextInt(2) * 2 - 1; - xa = (random->nextFloat() - 0.5) * 0.5; - ya = (random->nextFloat() - 0.5) * 0.5; - za = (random->nextFloat() - 0.5) * 0.5; - if (level->getTile(xt - 1, yt, zt) == id || level->getTile(xt + 1, yt, zt) == id) + double x = xt + random->nextFloat(); + double y = yt + random->nextFloat(); + double z = zt + random->nextFloat(); + double xa = 0; + double ya = 0; + double za = 0; + int flip = random->nextInt(2) * 2 - 1; + xa = (random->nextFloat() - 0.5) * 0.5; + ya = (random->nextFloat() - 0.5) * 0.5; + za = (random->nextFloat() - 0.5) * 0.5; + if (level->getTile(xt - 1, yt, zt) == id || level->getTile(xt + 1, yt, zt) == id) { - z = zt + 0.5 + (0.25) * flip; - za = (random->nextFloat() * 2) * flip; - } + z = zt + 0.5 + (0.25) * flip; + za = (random->nextFloat() * 2) * flip; + } else { - x = xt + 0.5 + (0.25) * flip; - xa = (random->nextFloat() * 2) * flip; - } + x = xt + 0.5 + (0.25) * flip; + xa = (random->nextFloat() * 2) * flip; + } - level->addParticle(eParticleType_netherportal, x, y, z, xa, ya, za); - } + level->addParticle(eParticleType_netherportal, x, y, z, xa, ya, za); + } } int PortalTile::cloneTileId(Level *level, int x, int y, int z) diff --git a/Minecraft.World/Pos.cpp b/Minecraft.World/Pos.cpp index 3fad76e8..e673ecc3 100644 --- a/Minecraft.World/Pos.cpp +++ b/Minecraft.World/Pos.cpp @@ -18,9 +18,9 @@ Pos::Pos(int x, int y, int z) Pos::Pos(Pos *position) { - this->x = position->x; - this->y = position->y; - this->z = position->z; + x = position->x; + y = position->y; + z = position->z; } //@Override @@ -71,9 +71,9 @@ void Pos::set(int x, int y, int z) void Pos::set(Pos *pos) { - this->x = pos->x; - this->y = pos->y; - this->z = pos->z; + x = pos->x; + y = pos->y; + z = pos->z; } Pos *Pos::above() @@ -145,93 +145,93 @@ void Pos::move(int x, int y, int z) void Pos::move(Pos pos) { - this->x += pos.x; - this->y += pos.y; - this->z += pos.z; + x += pos.x; + y += pos.y; + z += pos.z; } void Pos::moveX(int steps) { - this->x += steps; + x += steps; } void Pos::moveY(int steps) { - this->y += steps; + y += steps; } void Pos::moveZ(int steps) { - this->z += steps; + z += steps; } void Pos::moveUp(int steps) { - this->y += steps; + y += steps; } void Pos::moveUp() { - this->y++; + y++; } void Pos::moveDown(int steps) { - this->y -= steps; + y -= steps; } void Pos::moveDown() { - this->y--; + y--; } void Pos::moveEast(int steps) { - this->x += steps; + x += steps; } void Pos::moveEast() { - this->x++; + x++; } void Pos::moveWest(int steps) { - this->x -= steps; + x -= steps; } void Pos::moveWest() { - this->x--; + x--; } void Pos::moveNorth(int steps) { - this->z -= steps; + z -= steps; } void Pos::moveNorth() { - this->z--; + z--; } void Pos::moveSouth(int steps) { - this->z += steps; + z += steps; } void Pos::moveSouth() { - this->z++; + z++; } double Pos::dist(int x, int y, int z) { - int dx = this->x - x; - int dy = this->y - y; - int dz = this->z - z; + double dx = this->x - x; + double dy = this->y - y; + double dz = this->z - z; - return sqrt( (double) dx * dx + dy * dy + dz * dz); + return sqrt( dx * dx + dy * dy + dz * dz); } double Pos::dist(Pos *pos) @@ -241,8 +241,13 @@ double Pos::dist(Pos *pos) float Pos::distSqr(int x, int y, int z) { - int dx = this->x - x; - int dy = this->y - y; - int dz = this->z - z; + float dx = this->x - x; + float dy = this->y - y; + float dz = this->z - z; return dx * dx + dy * dy + dz * dz; +} + +float Pos::distSqr(Pos *pos) +{ + return distSqr(pos->x, pos->y, pos->z); } \ No newline at end of file diff --git a/Minecraft.World/Pos.h b/Minecraft.World/Pos.h index a07c7fe3..c2130441 100644 --- a/Minecraft.World/Pos.h +++ b/Minecraft.World/Pos.h @@ -23,75 +23,44 @@ public: bool equals(void *other); int hashCode(); - int compareTo(Pos *pos); - Pos *offset(int x, int y, int z); - void set(int x, int y, int z); - void set(Pos *pos); Pos *above(); - Pos *above(int steps); - Pos *below(); - Pos *below(int steps); - Pos *north(); - Pos *north(int steps); - Pos *south(); - Pos *south(int steps); - Pos *west(); - Pos *west(int steps); - Pos *east(); - Pos *east(int steps); void move(int x, int y, int z); - void move(Pos pos); - void moveX(int steps); - void moveY(int steps); - void moveZ(int steps); - void moveUp(int steps); - void moveUp(); - void moveDown(int steps); - void moveDown(); - void moveEast(int steps); - void moveEast(); - void moveWest(int steps); - void moveWest(); - void moveNorth(int steps); - void moveNorth(); - void moveSouth(int steps); - void moveSouth(); double dist(int x, int y, int z); - double dist(Pos *pos); float distSqr(int x, int y, int z); + float distSqr(Pos *pos); }; \ No newline at end of file diff --git a/Minecraft.World/Position.h b/Minecraft.World/Position.h new file mode 100644 index 00000000..ca2596bc --- /dev/null +++ b/Minecraft.World/Position.h @@ -0,0 +1,9 @@ +#pragma once + +class Position +{ +public: + virtual double getX() = 0; + virtual double getY() = 0; + virtual double getZ() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/PositionImpl.h b/Minecraft.World/PositionImpl.h new file mode 100644 index 00000000..e194bc54 --- /dev/null +++ b/Minecraft.World/PositionImpl.h @@ -0,0 +1,34 @@ +#pragma once + +#include "Position.h" + +class PositionImpl : public Position +{ +protected: + double x; + double y; + double z; + +public: + PositionImpl(double x, double y, double z) + { + this->x = x; + this->y = y; + this->z = z; + } + + double getX() + { + return x; + } + + double getY() + { + return y; + } + + double getZ() + { + return z; + } +}; \ No newline at end of file diff --git a/Minecraft.World/PotatoTile.cpp b/Minecraft.World/PotatoTile.cpp index 27ca1984..64a696ec 100644 --- a/Minecraft.World/PotatoTile.cpp +++ b/Minecraft.World/PotatoTile.cpp @@ -55,6 +55,6 @@ void PotatoTile::registerIcons(IconRegister *iconRegister) { for (int i = 0; i < 4; i++) { - icons[i] = iconRegister->registerIcon(L"potatoes_" + _toString(i)); + icons[i] = iconRegister->registerIcon(getIconName() + L"_stage_" + _toString(i) ); } } \ No newline at end of file diff --git a/Minecraft.World/PotionBrewing.cpp b/Minecraft.World/PotionBrewing.cpp index eb973655..5c454fd4 100644 --- a/Minecraft.World/PotionBrewing.cpp +++ b/Minecraft.World/PotionBrewing.cpp @@ -218,6 +218,17 @@ int PotionBrewing::getColorValue(vector *effects) return ((int) red) << 16 | ((int) green) << 8 | ((int) blue); } +bool PotionBrewing::areAllEffectsAmbient(vector *effects) +{ + for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it) + { + MobEffectInstance *effect = *it; + if (!effect->isAmbient()) return false; + } + + return true; +} + int PotionBrewing::getColorValue(int brew, bool includeDisabledEffects) { if (!includeDisabledEffects) @@ -598,7 +609,9 @@ vector *PotionBrewing::getEffects(int brew, bool includeDis { list = new vector(); } - list->push_back(new MobEffectInstance(effect->getId(), duration, amplifier)); + MobEffectInstance *instance = new MobEffectInstance(effect->getId(), duration, amplifier); + if ((brew & THROWABLE_MASK) != 0) instance->setSplash(true); + list->push_back(instance); } } diff --git a/Minecraft.World/PotionBrewing.h b/Minecraft.World/PotionBrewing.h index 68679293..8f110c93 100644 --- a/Minecraft.World/PotionBrewing.h +++ b/Minecraft.World/PotionBrewing.h @@ -5,6 +5,14 @@ class MobEffectInstance; class PotionBrewing { public: + static const int POTION_ID_SPLASH_DAMAGE = 32732; + static const int POTION_ID_SPLASH_WEAKNESS = 32696; + static const int POTION_ID_SPLASH_SLOWNESS = 32698; + static const int POTION_ID_SPLASH_POISON = 32660; + static const int POTION_ID_HEAL = 16341; + static const int POTION_ID_SWIFTNESS = 16274; + static const int POTION_ID_FIRE_RESISTANCE = 16307; + static const bool SIMPLIFIED_BREWING = true; // 4J Stu - Made #define so we can use it to select const initialisation #define _SIMPLIFIED_BREWING 1 @@ -28,6 +36,12 @@ public: static const wstring MOD_GUNPOWDER; static const wstring MOD_GOLDENCARROT; + static const int BITS_FOR_MAX_NORMAL_EFFECT = 0xF; + static const int BITS_FOR_DURATION = (1 << 5); + static const int BITS_FOR_EXTENDED = (1 << 6); + static const int BITS_FOR_NORMAL = (1 << 13); + static const int BITS_FOR_SPLASH = (1 << 14); + private: typedef unordered_map intStringMap; static intStringMap potionEffectDuration; @@ -55,6 +69,7 @@ private: public: static int getAppearanceValue(int brew); static int getColorValue(vector *effects); + static bool areAllEffectsAmbient(vector *effects); private: static unordered_map cachedColors; diff --git a/Minecraft.World/PotionItem.cpp b/Minecraft.World/PotionItem.cpp index 643e9661..e302b8f9 100644 --- a/Minecraft.World/PotionItem.cpp +++ b/Minecraft.World/PotionItem.cpp @@ -3,6 +3,7 @@ #include "net.minecraft.world.item.alchemy.h" #include "net.minecraft.world.effect.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.h" @@ -32,7 +33,33 @@ PotionItem::PotionItem(int id) : Item(id) vector *PotionItem::getMobEffects(shared_ptr potion) { - return getMobEffects(potion->getAuxValue()); + if (!potion->hasTag() || !potion->getTag()->contains(L"CustomPotionEffects")) + { + vector *effects = NULL; + AUTO_VAR(it, cachedMobEffects.find(potion->getAuxValue())); + if(it != cachedMobEffects.end()) effects = it->second; + if (effects == NULL) + { + effects = PotionBrewing::getEffects(potion->getAuxValue(), false); + cachedMobEffects[potion->getAuxValue()] = effects; + } + + // Result should be a new (unmanaged) vector, so create a new one + return effects == NULL ? NULL : new vector(*effects); + } + else + { + vector *effects = new vector(); + ListTag *customList = (ListTag *) potion->getTag()->getList(L"CustomPotionEffects"); + + for (int i = 0; i < customList->size(); i++) + { + CompoundTag *tag = customList->get(i); + effects->push_back(MobEffectInstance::load(tag)); + } + + return effects; + } } vector *PotionItem::getMobEffects(int auxValue) @@ -89,7 +116,7 @@ UseAnim PotionItem::getUseAnimation(shared_ptr itemInstance) return UseAnim_drink; } -bool PotionItem::TestUse(Level *level, shared_ptr player) +bool PotionItem::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { return true; } @@ -99,7 +126,7 @@ shared_ptr PotionItem::use(shared_ptr instance, Leve if (isThrowable(instance->getAuxValue())) { if (!player->abilities.instabuild) instance->count--; - level->playSound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); + level->playEntitySound(player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); if (!level->isClientSide) level->addEntity(shared_ptr( new ThrownPotion(level, player, instance->getAuxValue()) )); return instance; } @@ -212,20 +239,39 @@ wstring PotionItem::getHoverName(shared_ptr itemInstance) return elementName; } -void PotionItem::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced, vector &unformattedStrings) +void PotionItem::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced) { if (itemInstance->getAuxValue() == 0) { return; } vector *effects = ((PotionItem *) Item::potion)->getMobEffects(itemInstance); + attrAttrModMap modifiers; if (effects != NULL && !effects->empty()) { //for (MobEffectInstance effect : effects) for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it) { MobEffectInstance *effect = *it; - wstring effectString = app.GetString( effect->getDescriptionId() );//I18n.get(effect.getDescriptionId()).trim(); + wstring effectString = app.GetString( effect->getDescriptionId() ); + + MobEffect *mobEffect = MobEffect::effects[effect->getId()]; + unordered_map *effectModifiers = mobEffect->getAttributeModifiers(); + + if (effectModifiers != NULL && effectModifiers->size() > 0) + { + for(AUTO_VAR(it, effectModifiers->begin()); it != effectModifiers->end(); ++it) + { + // 4J - anonymous modifiers added here are destroyed shortly? + AttributeModifier *original = it->second; + AttributeModifier *modifier = new AttributeModifier(mobEffect->getAttributeModifierValue(effect->getAmplifier(), original), original->getOperation()); + modifiers.insert( std::pair( it->first->getId(), modifier) ); + } + } + + // Don't want to delete this (that's a pointer to mobEffects internal vector of modifiers) + // delete effectModifiers; + if (effect->getAmplifier() > 0) { wstring potencyString = L""; @@ -247,37 +293,46 @@ void PotionItem::appendHoverText(shared_ptr itemInstance, shared_p potencyString = app.GetString( IDS_POTION_POTENCY_0 ); break; } - effectString += potencyString;// + I18n.get("potion.potency." + effect.getAmplifier()).trim(); + effectString += potencyString; // + I18n.get("potion.potency." + effect.getAmplifier()).trim(); } if (effect->getDuration() > SharedConstants::TICKS_PER_SECOND) { effectString += L" (" + MobEffect::formatDuration(effect) + L")"; } - unformattedStrings.push_back(effectString); - wchar_t formatted[256]; - ZeroMemory(formatted, 256 * sizeof(wchar_t)); - eMinecraftColour colour = eMinecraftColour_NOT_SET; - if (MobEffect::effects[effect->getId()]->isHarmful()) + + eMinecraftColour color = eMinecraftColour_NOT_SET; + + if (mobEffect->isHarmful()) { - colour = eHTMLColor_c; - //lines->push_back(L"§c + effectString); //"§c" + color = eHTMLColor_c; } else { - colour = eHTMLColor_7; - //lines->push_back(L"§7" + effectString); //"§7" + color = eHTMLColor_7; } - swprintf(formatted, 256, L"%ls",app.GetHTMLColour(colour),effectString.c_str()); - lines->push_back(formatted); + + lines->push_back(HtmlString(effectString, color)); } } else { wstring effectString = app.GetString(IDS_POTION_EMPTY); //I18n.get("potion.empty").trim(); - //eHTMLColor_7 - wchar_t formatted[256]; - swprintf(formatted,256,L"%ls",app.GetHTMLColour(eHTMLColor_7),effectString.c_str()); - lines->push_back(formatted); //"§7" + + lines->push_back(HtmlString(effectString, eHTMLColor_7)); //"§7" + } + + if (!modifiers.empty()) + { + // Add new line + lines->push_back(HtmlString(L"")); + lines->push_back(HtmlString(app.GetString(IDS_POTION_EFFECTS_WHENDRANK), eHTMLColor_5)); + + // Add modifier descriptions + for (AUTO_VAR(it, modifiers.begin()); it != modifiers.end(); ++it) + { + // 4J: Moved modifier string building to AttributeModifier + lines->push_back(it->second->getHoverText(it->first)); + } } } @@ -290,11 +345,6 @@ bool PotionItem::isFoil(shared_ptr itemInstance) unsigned int PotionItem::getUseDescriptionId(shared_ptr instance) { int brew = instance->getAuxValue(); - - -#define MACRO_POTION_IS_NIGHTVISION(aux) ((aux & 0x200F) == MASK_NIGHTVISION) -#define MACRO_POTION_IS_INVISIBILITY(aux) ((aux & 0x200F) == MASK_INVISIBILITY) - if(brew == 0) return IDS_POTION_DESC_WATER_BOTTLE; else if( MACRO_POTION_IS_REGENERATION(brew)) return IDS_POTION_DESC_REGENERATION; else if( MACRO_POTION_IS_SPEED(brew) ) return IDS_POTION_DESC_MOVESPEED; diff --git a/Minecraft.World/PotionItem.h b/Minecraft.World/PotionItem.h index d03d3308..9fa158c2 100644 --- a/Minecraft.World/PotionItem.h +++ b/Minecraft.World/PotionItem.h @@ -30,7 +30,7 @@ public: virtual int getUseDuration(shared_ptr itemInstance); virtual UseAnim getUseAnimation(shared_ptr itemInstance); virtual shared_ptr use(shared_ptr instance, Level *level, shared_ptr player); - virtual bool TestUse(Level *level, shared_ptr player); + virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); virtual bool useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); virtual Icon *getIcon(int auxValue); virtual Icon *getLayerIcon(int auxValue, int spriteLayer); @@ -40,7 +40,7 @@ public: virtual bool hasMultipleSpriteLayers(); virtual bool hasInstantenousEffects(int itemAuxValue); virtual wstring getHoverName(shared_ptr itemInstance); - virtual void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced, vector &unformattedStrings); + virtual void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced); virtual bool isFoil(shared_ptr itemInstance); virtual unsigned int getUseDescriptionId(shared_ptr instance); diff --git a/Minecraft.World/PoweredMetalTile.cpp b/Minecraft.World/PoweredMetalTile.cpp new file mode 100644 index 00000000..71938975 --- /dev/null +++ b/Minecraft.World/PoweredMetalTile.cpp @@ -0,0 +1,17 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.redstone.h" +#include "PoweredMetalTile.h" + +PoweredMetalTile::PoweredMetalTile(int id) : MetalTile(id) +{ +} + +bool PoweredMetalTile::isSignalSource() +{ + return true; +} + +int PoweredMetalTile::getSignal(LevelSource *level, int x, int y, int z, int dir) +{ + return Redstone::SIGNAL_MAX; +} \ No newline at end of file diff --git a/Minecraft.World/PoweredMetalTile.h b/Minecraft.World/PoweredMetalTile.h new file mode 100644 index 00000000..1ee573de --- /dev/null +++ b/Minecraft.World/PoweredMetalTile.h @@ -0,0 +1,12 @@ +#pragma once + +#include "MetalTile.h" + +class PoweredMetalTile : public MetalTile +{ +public: + PoweredMetalTile(int id); + + virtual bool isSignalSource(); + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); +}; \ No newline at end of file diff --git a/Minecraft.World/PoweredRailTile.cpp b/Minecraft.World/PoweredRailTile.cpp new file mode 100644 index 00000000..9ebf6291 --- /dev/null +++ b/Minecraft.World/PoweredRailTile.cpp @@ -0,0 +1,187 @@ +#include "stdafx.h" +#include "net.minecraft.world.h" +#include "net.minecraft.world.level.h" +#include "PoweredRailTile.h" + +PoweredRailTile::PoweredRailTile(int id) : BaseRailTile(id, true) +{ +} + +Icon *PoweredRailTile::getTexture(int face, int data) +{ + if ((data & RAIL_DATA_BIT) == 0) + { + return icon; + } + else + { + return iconPowered; + } +} + +void PoweredRailTile::registerIcons(IconRegister *iconRegister) +{ + BaseRailTile::registerIcons(iconRegister); + iconPowered = iconRegister->registerIcon(getIconName() + L"_powered"); +} + +bool PoweredRailTile::findPoweredRailSignal(Level *level, int x, int y, int z, int data, bool forward, int searchDepth) +{ + if (searchDepth >= 8) + { + return false; + } + + int dir = data & RAIL_DIRECTION_MASK; + + bool checkBelow = true; + switch (dir) + { + case DIR_FLAT_Z: + if (forward) + { + z++; + } + else + { + z--; + } + break; + case DIR_FLAT_X: + if (forward) + { + x--; + } + else + { + x++; + } + break; + case 2: + if (forward) + { + x--; + } + else + { + x++; + y++; + checkBelow = false; + } + dir = DIR_FLAT_X; + break; + case 3: + if (forward) + { + x--; + y++; + checkBelow = false; + } + else + { + x++; + } + dir = DIR_FLAT_X; + break; + case 4: + if (forward) + { + z++; + } + else + { + z--; + y++; + checkBelow = false; + } + dir = DIR_FLAT_Z; + break; + case 5: + if (forward) + { + z++; + y++; + checkBelow = false; + } + else + { + z--; + } + dir = DIR_FLAT_Z; + break; + } + + if (isSameRailWithPower(level, x, y, z, forward, searchDepth, dir)) + { + return true; + } + if (checkBelow && isSameRailWithPower(level, x, y - 1, z, forward, searchDepth, dir)) + { + return true; + } + return false; +} + +bool PoweredRailTile::isSameRailWithPower(Level *level, int x, int y, int z, bool forward, int searchDepth, int dir) +{ + int tile = level->getTile(x, y, z); + + if (tile == id) + { + int tileData = level->getData(x, y, z); + int myDir = tileData & RAIL_DIRECTION_MASK; + + if (dir == DIR_FLAT_X && (myDir == DIR_FLAT_Z || myDir == 4 || myDir == 5)) + { + return false; + } + if (dir == DIR_FLAT_Z && (myDir == DIR_FLAT_X || myDir == 2 || myDir == 3)) + { + return false; + } + + if ((tileData & RAIL_DATA_BIT) != 0) + { + if (level->hasNeighborSignal(x, y, z)) + { + return true; + } + else + { + return findPoweredRailSignal(level, x, y, z, tileData, forward, searchDepth + 1); + } + } + } + + return false; +} + +void PoweredRailTile::updateState(Level *level, int x, int y, int z, int data, int dir, int type) +{ + bool signal = level->hasNeighborSignal(x, y, z); + signal = signal || findPoweredRailSignal(level, x, y, z, data, true, 0) || findPoweredRailSignal(level, x, y, z, data, false, 0); + + bool changed = false; + if (signal && (data & RAIL_DATA_BIT) == 0) + { + level->setData(x, y, z, dir | RAIL_DATA_BIT, Tile::UPDATE_ALL); + changed = true; + } + else if (!signal && (data & RAIL_DATA_BIT) != 0) + { + level->setData(x, y, z, dir, Tile::UPDATE_ALL); + changed = true; + } + + // usually the level only updates neighbors that are in the same + // y plane as the current tile, but sloped rails may need to + // update tiles above or below it as well + if (changed) + { + level->updateNeighborsAt(x, y - 1, z, id); + if (dir == 2 || dir == 3 || dir == 4 || dir == 5) + { + level->updateNeighborsAt(x, y + 1, z, id); + } + } +} \ No newline at end of file diff --git a/Minecraft.World/PoweredRailTile.h b/Minecraft.World/PoweredRailTile.h new file mode 100644 index 00000000..42b330cc --- /dev/null +++ b/Minecraft.World/PoweredRailTile.h @@ -0,0 +1,21 @@ +#pragma once + +#include "BaseRailTile.h" + +class PoweredRailTile : public BaseRailTile +{ + friend class ChunkRebuildData; +protected: + Icon *iconPowered; + +public: + PoweredRailTile(int id); + + virtual Icon *getTexture(int face, int data); + virtual void registerIcons(IconRegister *iconRegister); + +protected: + virtual bool findPoweredRailSignal(Level *level, int x, int y, int z, int data, bool forward, int searchDepth); + virtual bool isSameRailWithPower(Level *level, int x, int y, int z, bool forward, int searchDepth, int dir); + virtual void updateState(Level *level, int x, int y, int z, int data, int dir, int type); +}; \ No newline at end of file diff --git a/Minecraft.World/PressurePlateTile.cpp b/Minecraft.World/PressurePlateTile.cpp index eacdeb07..6a30819d 100644 --- a/Minecraft.World/PressurePlateTile.cpp +++ b/Minecraft.World/PressurePlateTile.cpp @@ -1,211 +1,48 @@ #include "stdafx.h" -#include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.level.h" -#include "net.minecraft.world.level.tile.h" -#include "net.minecraft.world.phys.h" -#include "net.minecraft.world.h" +#include "net.minecraft.world.level.redstone.h" #include "PressurePlateTile.h" -#include "SoundTypes.h" -PressurePlateTile::PressurePlateTile(int id, const wstring &tex, Material *material, Sensitivity sensitivity) : Tile(id, material, isSolidRender()) +PressurePlateTile::PressurePlateTile(int id, const wstring &tex, Material *material, Sensitivity sensitivity) : BasePressurePlateTile(id, tex, material) { this->sensitivity = sensitivity; - this->setTicking(true); - this->texture = tex; - float o = 1 / 16.0f; - setShape(o, 0, o, 1 - o, 0.5f / 16.0f, 1 - o); + // 4J Stu - Move this from base class to use virtual function + updateShape(getDataForSignal(Redstone::SIGNAL_MAX)); } -int PressurePlateTile::getTickDelay() +int PressurePlateTile::getDataForSignal(int signal) { - return 20; + return signal > 0 ? 1 : 0; } -AABB *PressurePlateTile::getAABB(Level *level, int x, int y, int z) +int PressurePlateTile::getSignalForData(int data) { - return NULL; + return data == 1 ? Redstone::SIGNAL_MAX : 0; } -bool PressurePlateTile::isSolidRender(bool isServerLevel) +int PressurePlateTile::getSignalStrength(Level *level, int x, int y, int z) { - return false; -} - -bool PressurePlateTile::blocksLight() -{ - return false; -} - -bool PressurePlateTile::isCubeShaped() -{ - return false; -} - -bool PressurePlateTile::isPathfindable(LevelSource *level, int x, int y, int z) -{ - return true; -} - -bool PressurePlateTile::mayPlace(Level *level, int x, int y, int z) -{ - return level->isTopSolidBlocking(x, y - 1, z) || FenceTile::isFence(level->getTile(x, y - 1, z)); -} - -void PressurePlateTile::neighborChanged(Level *level, int x, int y, int z, int type) -{ - bool replace = false; - - if (!level->isTopSolidBlocking(x, y - 1, z) && !FenceTile::isFence(level->getTile(x, y - 1, z))) replace = true; - - if (replace) - { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); - } -} - -void PressurePlateTile::tick(Level *level, int x, int y, int z, Random *random) -{ - if (level->isClientSide) return; - if (level->getData(x, y, z) == 0) - { - return; - } - - checkPressed(level, x, y, z); -} - -void PressurePlateTile::entityInside(Level *level, int x, int y, int z, shared_ptr entity) -{ - if (level->isClientSide) return; - - if (level->getData(x, y, z) == 1) - { - return; - } - - checkPressed(level, x, y, z); -} - -void PressurePlateTile::checkPressed(Level *level, int x, int y, int z) -{ - bool wasPressed = level->getData(x, y, z) == 1; - bool shouldBePressed = false; - - float b = 2 / 16.0f; - vector > *entities = NULL; - - bool entitiesToBeFreed = false; - if (sensitivity == PressurePlateTile::everything) entities = level->getEntities(nullptr, AABB::newTemp(x + b, y, z + b, x + 1 - b, y + 0.25, z + 1 - b)); - - if (sensitivity == PressurePlateTile::mobs) - { - entities = level->getEntitiesOfClass(typeid(Mob), AABB::newTemp(x + b, y, z + b, x + 1 - b, y + 0.25, z + 1 - b)); - entitiesToBeFreed = true; - } - if (sensitivity == PressurePlateTile::players) - { - entities = level->getEntitiesOfClass(typeid(Player), AABB::newTemp(x + b, y, z + b, x + 1 - b, y + 0.25, z + 1 - b)); - entitiesToBeFreed = true; - } + vector< shared_ptr > *entities = NULL; - if (!entities->empty()) - { - shouldBePressed = true; - } - - if (shouldBePressed && !wasPressed) - { - level->setData(x, y, z, 1); - level->updateNeighborsAt(x, y, z, id); - level->updateNeighborsAt(x, y - 1, z, id); - level->setTilesDirty(x, y, z, x, y, z); - - level->playSound(x + 0.5, y + 0.1, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, 0.6f); - } - if (!shouldBePressed && wasPressed) - { - level->setData(x, y, z, 0); - level->updateNeighborsAt(x, y, z, id); - level->updateNeighborsAt(x, y - 1, z, id); - level->setTilesDirty(x, y, z, x, y, z); + if (sensitivity == everything) entities = level->getEntities(nullptr, getSensitiveAABB(x, y, z)); + else if (sensitivity == mobs) entities = level->getEntitiesOfClass(typeid(LivingEntity), getSensitiveAABB(x, y, z)); + else if (sensitivity == players) entities = level->getEntitiesOfClass(typeid(Player), getSensitiveAABB(x, y, z)); + else __debugbreak(); // 4J-JEV: We're going to delete something at a random location. - level->playSound(x + 0.5, y + 0.1, z + 0.5, eSoundType_RANDOM_CLICK, 0.3f, 0.5f); - } - - if (shouldBePressed) - { - level->addToTickNextTick(x, y, z, id, getTickDelay()); - } - - if( entitiesToBeFreed ) + if (entities != NULL && !entities->empty()) { - delete entities; + for (AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) + { + shared_ptr e = *it; + if (!e->isIgnoringTileTriggers()) + { + if (sensitivity != everything) delete entities; + return Redstone::SIGNAL_MAX; + } + } } -} - -void PressurePlateTile::onRemove(Level *level, int x, int y, int z, int id, int data) -{ - if (data > 0) - { - level->updateNeighborsAt(x, y, z, this->id); - level->updateNeighborsAt(x, y - 1, z, this->id); - } - Tile::onRemove(level, x, y, z, id, data); -} - -void PressurePlateTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param -{ - bool pressed = level->getData(x, y, z) == 1; - float o = 1 / 16.0f; - if (pressed) - { - this->setShape(o, 0, o, 1 - o, 0.5f / 16.0f, 1 - o); - } - else - { - setShape(o, 0, o, 1 - o, 1 / 16.0f, 1 - o); - } -} - -bool PressurePlateTile::getSignal(LevelSource *level, int x, int y, int z, int dir) -{ - return (level->getData(x, y, z)) > 0; -} - -bool PressurePlateTile::getDirectSignal(Level *level, int x, int y, int z, int dir) -{ - if (level->getData(x, y, z) == 0) return false; - return (dir == 1); -} - -bool PressurePlateTile::isSignalSource() -{ - return true; -} - -void PressurePlateTile::updateDefaultShape() -{ - float x = 8 / 16.0f; - float y = 2 / 16.0f; - float z = 8 / 16.0f; - setShape(0.5f - x, 0.5f - y, 0.5f - z, 0.5f + x, 0.5f + y, 0.5f + z); - -} - -bool PressurePlateTile::shouldTileTick(Level *level, int x,int y,int z) -{ - return level->getData(x, y, z) != 0; -} - -int PressurePlateTile::getPistonPushReaction() -{ - return Material::PUSH_DESTROY; -} - -void PressurePlateTile::registerIcons(IconRegister *iconRegister) -{ - icon = iconRegister->registerIcon(texture); + if (sensitivity != everything) delete entities; + return Redstone::SIGNAL_NONE; } \ No newline at end of file diff --git a/Minecraft.World/PressurePlateTile.h b/Minecraft.World/PressurePlateTile.h index 0b70fca9..ca3e6b0b 100644 --- a/Minecraft.World/PressurePlateTile.h +++ b/Minecraft.World/PressurePlateTile.h @@ -1,49 +1,22 @@ #pragma once -#include "Tile.h" -#include "Definitions.h" +#include "BasePressurePlateTile.h" -class Random; - -class PressurePlateTile : public Tile +class PressurePlateTile : public BasePressurePlateTile { - friend class Tile; -private: - wstring texture; public: - enum Sensitivity + enum Sensitivity { - everything, - mobs, - players - }; + everything, mobs, players + }; private: Sensitivity sensitivity; -protected: - PressurePlateTile(int id, const wstring &tex, Material *material, Sensitivity sensitivity); -public: - virtual int getTickDelay(); - virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool blocksLight(); - virtual bool isCubeShaped(); - virtual bool isPathfindable(LevelSource *level, int x, int y, int z); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); - virtual void tick(Level *level, int x, int y, int z, Random *random); - virtual void entityInside(Level *level, int x, int y, int z, shared_ptr entity); -private: - virtual void checkPressed(Level *level, int x, int y, int z); + public: - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param - virtual bool getSignal(LevelSource *level, int x, int y, int z, int dir); - virtual bool getDirectSignal(Level *level, int x, int y, int z, int dir); - virtual bool isSignalSource(); - virtual void updateDefaultShape(); - virtual int getPistonPushReaction(); - void registerIcons(IconRegister *iconRegister); - - // 4J Added so we can check before we try to add a tile to the tick list if it's actually going to do seomthing - virtual bool shouldTileTick(Level *level, int x,int y,int z); -}; + PressurePlateTile(int id, const wstring &tex, Material *material, Sensitivity sensitivity); + +protected: + virtual int getDataForSignal(int signal); + virtual int getSignalForData(int data); + virtual int getSignalStrength(Level *level, int x, int y, int z); +}; \ No newline at end of file diff --git a/Minecraft.World/PrimedTnt.cpp b/Minecraft.World/PrimedTnt.cpp index 09926d50..79fd760f 100644 --- a/Minecraft.World/PrimedTnt.cpp +++ b/Minecraft.World/PrimedTnt.cpp @@ -14,6 +14,8 @@ void PrimedTnt::_init() blocksBuilding = true; setSize(0.98f, 0.98f); heightOffset = bbHeight / 2.0f; + + owner = weak_ptr(); } PrimedTnt::PrimedTnt(Level *level) : Entity( level ) @@ -25,7 +27,7 @@ PrimedTnt::PrimedTnt(Level *level) : Entity( level ) _init(); } -PrimedTnt::PrimedTnt(Level *level, double x, double y, double z) : Entity( level ) +PrimedTnt::PrimedTnt(Level *level, double x, double y, double z, shared_ptr owner) : Entity( level ) { _init(); @@ -41,6 +43,8 @@ PrimedTnt::PrimedTnt(Level *level, double x, double y, double z) : Entity( level xo = x; yo = y; zo = z; + + this->owner = weak_ptr(owner); } void PrimedTnt::defineSynchedData() @@ -95,7 +99,7 @@ void PrimedTnt::tick() void PrimedTnt::explode() { float r = 4.0f; - level->explode(nullptr, x, y, z, r, true); + level->explode(shared_from_this(), x, y, z, r, true); } @@ -109,8 +113,12 @@ void PrimedTnt::readAdditionalSaveData(CompoundTag *tag) life = tag->getByte(L"Fuse"); } - float PrimedTnt::getShadowHeightOffs() { return 0; +} + +shared_ptr PrimedTnt::getOwner() +{ + return owner.lock(); } \ No newline at end of file diff --git a/Minecraft.World/PrimedTnt.h b/Minecraft.World/PrimedTnt.h index 8f1b11dd..0b65a5ca 100644 --- a/Minecraft.World/PrimedTnt.h +++ b/Minecraft.World/PrimedTnt.h @@ -11,11 +11,12 @@ public: static const int serialVersionUID = 0; int life; + weak_ptr owner; void _init(); PrimedTnt(Level *level); - PrimedTnt(Level *level, double x, double y, double z); + PrimedTnt(Level *level, double x, double y, double z, shared_ptr owner); protected: virtual void defineSynchedData(); @@ -34,4 +35,5 @@ protected: public: virtual float getShadowHeightOffs(); + virtual shared_ptr getOwner(); }; diff --git a/Minecraft.World/Projectile.h b/Minecraft.World/Projectile.h new file mode 100644 index 00000000..ab6b0b05 --- /dev/null +++ b/Minecraft.World/Projectile.h @@ -0,0 +1,7 @@ +#pragma once + +class Projectile +{ +public: + virtual void shoot(double xd, double yd, double zd, float pow, float uncertainty) = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/ProtectionEnchantment.cpp b/Minecraft.World/ProtectionEnchantment.cpp index 39e3eca1..8304529b 100644 --- a/Minecraft.World/ProtectionEnchantment.cpp +++ b/Minecraft.World/ProtectionEnchantment.cpp @@ -41,7 +41,7 @@ int ProtectionEnchantment::getDamageProtection(int level, DamageSource *source) if (type == ALL) return Mth::floor(protect * 0.75f); if (type == FIRE && source->isFire()) return Mth::floor(protect * 1.25f); if (type == FALL && source == DamageSource::fall) return Mth::floor(protect * 2.5f); - if (type == EXPLOSION && source == DamageSource::explosion) return Mth::floor(protect * 1.5f); + if (type == EXPLOSION && source->isExplosion() ) return Mth::floor(protect * 1.5f); if (type == PROJECTILE && source->isProjectile()) return Mth::floor(protect * 1.5f); return 0; } @@ -56,11 +56,11 @@ bool ProtectionEnchantment::isCompatibleWith(Enchantment *other) const ProtectionEnchantment *pe = dynamic_cast( other ); if (pe != NULL) { - if (pe->type == this->type) + if (pe->type == type) { return false; } - if (this->type == FALL || pe->type == FALL) + if (type == FALL || pe->type == FALL) { return true; } diff --git a/Minecraft.World/PumpkinFeature.cpp b/Minecraft.World/PumpkinFeature.cpp index 6af6a9a1..95f306b3 100644 --- a/Minecraft.World/PumpkinFeature.cpp +++ b/Minecraft.World/PumpkinFeature.cpp @@ -5,19 +5,19 @@ bool PumpkinFeature::place(Level *level, Random *random, int x, int y, int z) { - for (int i = 0; i < 64; i++) + for (int i = 0; i < 64; i++) { - int x2 = x + random->nextInt(8) - random->nextInt(8); - int y2 = y + random->nextInt(4) - random->nextInt(4); - int z2 = z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(x2, y2, z2) && level->getTile(x2, y2 - 1, z2) == Tile::grass_Id) + int x2 = x + random->nextInt(8) - random->nextInt(8); + int y2 = y + random->nextInt(4) - random->nextInt(4); + int z2 = z + random->nextInt(8) - random->nextInt(8); + if (level->isEmptyTile(x2, y2, z2) && level->getTile(x2, y2 - 1, z2) == Tile::grass_Id) { - if (Tile::pumpkin->mayPlace(level, x2, y2, z2)) + if (Tile::pumpkin->mayPlace(level, x2, y2, z2)) { - level->setTileAndDataNoUpdate(x2, y2, z2, Tile::pumpkin_Id, random->nextInt(4)); - } - } - } + level->setTileAndData(x2, y2, z2, Tile::pumpkin_Id, random->nextInt(4), Tile::UPDATE_CLIENTS); + } + } + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/PumpkinTile.cpp b/Minecraft.World/PumpkinTile.cpp index 577b9a17..2bc36972 100644 --- a/Minecraft.World/PumpkinTile.cpp +++ b/Minecraft.World/PumpkinTile.cpp @@ -11,47 +11,47 @@ const wstring PumpkinTile::TEXTURE_FACE = L"pumpkin_face"; const wstring PumpkinTile::TEXTURE_LANTERN = L"pumpkin_jack"; -PumpkinTile::PumpkinTile(int id, bool lit) : DirectionalTile(id, Material::vegetable) +PumpkinTile::PumpkinTile(int id, bool lit) : DirectionalTile(id, Material::vegetable, isSolidRender() ) { - iconTop = NULL; + iconTop = NULL; iconFace = NULL; - setTicking(true); - this->lit = lit; + setTicking(true); + this->lit = lit; } Icon *PumpkinTile::getTexture(int face, int data) { - if (face == Facing::UP) return iconTop; - if (face == Facing::DOWN) return iconTop; + if (face == Facing::UP) return iconTop; + if (face == Facing::DOWN) return iconTop; - if (data == DIR_NORTH && face == Facing::NORTH) return iconFace; - if (data == DIR_EAST && face == Facing::EAST) return iconFace; - if (data == DIR_SOUTH && face == Facing::SOUTH) return iconFace; - if (data == DIR_WEST && face == Facing::WEST) return iconFace; + if (data == DIR_NORTH && face == Facing::NORTH) return iconFace; + if (data == DIR_EAST && face == Facing::EAST) return iconFace; + if (data == DIR_SOUTH && face == Facing::SOUTH) return iconFace; + if (data == DIR_WEST && face == Facing::WEST) return iconFace; - else return icon; + else return icon; } void PumpkinTile::onPlace(Level *level, int x, int y, int z) { Tile::onPlace(level, x, y, z); - if (level->getTile(x, y - 1, z) == Tile::snow_Id && level->getTile(x, y - 2, z) == Tile::snow_Id) + if (level->getTile(x, y - 1, z) == Tile::snow_Id && level->getTile(x, y - 2, z) == Tile::snow_Id) { - if (!level->isClientSide) + if (!level->isClientSide) { // 4J - added limit of number of snowmen that can be spawned if( level->canCreateMore( eTYPE_SNOWMAN, Level::eSpawnType_Egg) ) { - level->setTileNoUpdate(x, y, z, 0); - level->setTileNoUpdate(x, y - 1, z, 0); - level->setTileNoUpdate(x, y - 2, z, 0); + level->setTileAndData(x, y, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 2, z, 0, 0, Tile::UPDATE_CLIENTS); shared_ptr snowMan = shared_ptr(new SnowMan(level)); snowMan->moveTo(x + 0.5, y - 1.95, z + 0.5, 0, 0); level->addEntity(snowMan); - level->tileUpdated(x, y, z, 0); - level->tileUpdated(x, y - 1, z, 0); - level->tileUpdated(x, y - 2, z, 0); + level->tileUpdated(x, y, z, 0); + level->tileUpdated(x, y - 1, z, 0); + level->tileUpdated(x, y - 2, z, 0); } else { @@ -59,15 +59,15 @@ void PumpkinTile::onPlace(Level *level, int x, int y, int z) Tile::spawnResources(level, x, y, z, level->getData(x, y, z), 0); Tile::tiles[Tile::snow_Id]->spawnResources(level, x, y - 1, z, level->getData(x, y - 1, z), 0); Tile::tiles[Tile::snow_Id]->spawnResources(level, x, y - 2, z, level->getData(x, y - 2, z), 0); - level->setTile(x, y, z, 0); - level->setTile(x, y - 1, z, 0); - level->setTile(x, y - 2, z, 0); + level->setTileAndData(x, y, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 2, z, 0, 0, Tile::UPDATE_CLIENTS); } - } - for (int i = 0; i < 120; i++) + } + for (int i = 0; i < 120; i++) { - level->addParticle(eParticleType_snowshovel, x + level->random->nextDouble(), y - 2 + level->random->nextDouble() * 2.5, z + level->random->nextDouble(), 0, 0, 0); - } + level->addParticle(eParticleType_snowshovel, x + level->random->nextDouble(), y - 2 + level->random->nextDouble() * 2.5, z + level->random->nextDouble(), 0, 0, 0); + } } else if (level->getTile(x, y - 1, z) == Tile::ironBlock_Id && level->getTile(x, y - 2, z) == Tile::ironBlock_Id) { @@ -80,18 +80,18 @@ void PumpkinTile::onPlace(Level *level, int x, int y, int z) // 4J - added limit of number of golems that can be spawned if( level->canCreateMore( eTYPE_VILLAGERGOLEM, Level::eSpawnType_Egg) ) { - level->setTileNoUpdate(x, y, z, 0); - level->setTileNoUpdate(x, y - 1, z, 0); - level->setTileNoUpdate(x, y - 2, z, 0); + level->setTileAndData(x, y, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 2, z, 0, 0, Tile::UPDATE_CLIENTS); if (xArms) { - level->setTileNoUpdate(x - 1, y - 1, z, 0); - level->setTileNoUpdate(x + 1, y - 1, z, 0); + level->setTileAndData(x - 1, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + 1, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); } else { - level->setTileNoUpdate(x, y - 1, z - 1, 0); - level->setTileNoUpdate(x, y - 1, z + 1, 0); + level->setTileAndData(x, y - 1, z - 1, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z + 1, 0, 0, Tile::UPDATE_CLIENTS); } shared_ptr villagerGolem = shared_ptr(new VillagerGolem(level)); @@ -124,23 +124,23 @@ void PumpkinTile::onPlace(Level *level, int x, int y, int z) Tile::spawnResources(level, x, y, z, level->getData(x, y, z), 0); Tile::tiles[Tile::ironBlock_Id]->spawnResources(level, x, y - 1, z, level->getData(x, y - 1, z), 0); Tile::tiles[Tile::ironBlock_Id]->spawnResources(level, x, y - 2, z, level->getData(x, y - 2, z), 0); - level->setTile(x, y, z, 0); - level->setTile(x, y - 1, z, 0); - level->setTile(x, y - 2, z, 0); + level->setTileAndData(x, y, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 2, z, 0, 0, Tile::UPDATE_CLIENTS); if(xArms) { Tile::tiles[Tile::ironBlock_Id]->spawnResources(level, x - 1, y - 1, z, level->getData(x - 1, y - 1, z), 0); Tile::tiles[Tile::ironBlock_Id]->spawnResources(level, x + 1, y - 1, z, level->getData(x + 1, y - 1, z), 0); - level->setTile(x - 1, y - 1, z, 0); - level->setTile(x + 1, y - 1, z, 0); + level->setTileAndData(x - 1, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + 1, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); } else { Tile::tiles[Tile::ironBlock_Id]->spawnResources(level, x, y - 1, z - 1, level->getData(x, y - 1, z - 1), 0); Tile::tiles[Tile::ironBlock_Id]->spawnResources(level, x, y - 1, z + 1, level->getData(x, y - 1, z + 1), 0); - level->setTile(x, y - 1, z - 1, 0); - level->setTile(x, y - 1, z + 1, 0); + level->setTileAndData(x, y - 1, z - 1, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z + 1, 0, 0, Tile::UPDATE_CLIENTS); } } } @@ -150,20 +150,20 @@ void PumpkinTile::onPlace(Level *level, int x, int y, int z) bool PumpkinTile::mayPlace(Level *level, int x, int y, int z) { - int t = level->getTile(x, y, z); - return (t == 0 || Tile::tiles[t]->material->isReplaceable()) && level->isTopSolidBlocking(x, y - 1, z); + int t = level->getTile(x, y, z); + return (t == 0 || Tile::tiles[t]->material->isReplaceable()) && level->isTopSolidBlocking(x, y - 1, z); } -void PumpkinTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void PumpkinTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { - int dir = Mth::floor(by->yRot * 4 / (360) + 2.5) & 3; - level->setData(x, y, z, dir); + int dir = Mth::floor(by->yRot * 4 / (360) + 2.5) & 3; + level->setData(x, y, z, dir, Tile::UPDATE_CLIENTS); } void PumpkinTile::registerIcons(IconRegister *iconRegister) { - iconFace = iconRegister->registerIcon(lit ? TEXTURE_LANTERN : TEXTURE_FACE); - iconTop = iconRegister->registerIcon(L"pumpkin_top"); - icon = iconRegister->registerIcon(L"pumpkin_side"); + iconFace = iconRegister->registerIcon(getIconName() + L"_face_" + (lit ? L"on" : L"off")); + iconTop = iconRegister->registerIcon(getIconName() + L"_top"); + icon = iconRegister->registerIcon(getIconName() + L"_side"); } diff --git a/Minecraft.World/PumpkinTile.h b/Minecraft.World/PumpkinTile.h index 1c808b54..59b4d819 100644 --- a/Minecraft.World/PumpkinTile.h +++ b/Minecraft.World/PumpkinTile.h @@ -23,9 +23,9 @@ private: protected: PumpkinTile(int id, bool lit); public: - virtual Icon *getTexture(int face, int data); - virtual void onPlace(Level *level, int x, int y, int z); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); + virtual Icon *getTexture(int face, int data); + virtual void onPlace(Level *level, int x, int y, int z); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); void registerIcons(IconRegister *iconRegister); }; \ No newline at end of file diff --git a/Minecraft.World/QuartzBlockTile.cpp b/Minecraft.World/QuartzBlockTile.cpp index a7beeb21..709e0c1e 100644 --- a/Minecraft.World/QuartzBlockTile.cpp +++ b/Minecraft.World/QuartzBlockTile.cpp @@ -12,11 +12,11 @@ int QuartzBlockTile::BLOCK_NAMES[QUARTZ_BLOCK_NAMES] = { IDS_TILE_QUARTZ_BLOCK, IDS_TILE_QUARTZ_BLOCK_CHISELED, IDS_TILE_QUARTZ_BLOCK_LINES, IDS_TILE_QUARTZ_BLOCK_LINES, IDS_TILE_QUARTZ_BLOCK_LINES }; -const wstring QuartzBlockTile::TEXTURE_TOP = L"quartzblock_top"; -const wstring QuartzBlockTile::TEXTURE_CHISELED_TOP = L"quartzblock_chiseled_top"; -const wstring QuartzBlockTile::TEXTURE_LINES_TOP = L"quartzblock_lines_top"; -const wstring QuartzBlockTile::TEXTURE_BOTTOM = L"quartzblock_bottom"; -const wstring QuartzBlockTile::TEXTURE_NAMES[QUARTZ_BLOCK_TEXTURES] = { L"quartzblock_side", L"quartzblock_chiseled", L"quartzblock_lines", L"", L""}; +const wstring QuartzBlockTile::TEXTURE_TOP = L"top"; +const wstring QuartzBlockTile::TEXTURE_CHISELED_TOP = L"chiseled_top"; +const wstring QuartzBlockTile::TEXTURE_LINES_TOP = L"lines_top"; +const wstring QuartzBlockTile::TEXTURE_BOTTOM = L"bottom"; +const wstring QuartzBlockTile::TEXTURE_NAMES[QUARTZ_BLOCK_TEXTURES] = { L"side", L"chiseled", L"lines", L"", L""}; QuartzBlockTile::QuartzBlockTile(int id) : Tile(id, Material::stone) { @@ -111,12 +111,12 @@ void QuartzBlockTile::registerIcons(IconRegister *iconRegister) } else { - icons[i] = iconRegister->registerIcon(TEXTURE_NAMES[i]); + icons[i] = iconRegister->registerIcon(getIconName() + L"_" + TEXTURE_NAMES[i]); } } - iconTop = iconRegister->registerIcon(TEXTURE_TOP); - iconChiseledTop = iconRegister->registerIcon(TEXTURE_CHISELED_TOP); - iconLinesTop = iconRegister->registerIcon(TEXTURE_LINES_TOP); - iconBottom = iconRegister->registerIcon(TEXTURE_BOTTOM); + iconTop = iconRegister->registerIcon(getIconName() + L"_" + TEXTURE_TOP); + iconChiseledTop = iconRegister->registerIcon(getIconName() + L"_" + TEXTURE_CHISELED_TOP); + iconLinesTop = iconRegister->registerIcon(getIconName() + L"_" + TEXTURE_LINES_TOP); + iconBottom = iconRegister->registerIcon(getIconName() + L"_" + TEXTURE_BOTTOM); } \ No newline at end of file diff --git a/Minecraft.World/RailTile.cpp b/Minecraft.World/RailTile.cpp index 4ece48ca..798d248c 100644 --- a/Minecraft.World/RailTile.cpp +++ b/Minecraft.World/RailTile.cpp @@ -1,676 +1,36 @@ #include "stdafx.h" -#include "net.minecraft.world.phys.h" -#include "net.minecraft.world.level.h" #include "net.minecraft.world.h" #include "RailTile.h" -RailTile::Rail::Rail(Level *level, int x, int y, int z) +RailTile::RailTile(int id) : BaseRailTile(id, false) { - this->level = level; - this->x = x; - this->y = y; - this->z = z; - - int id = level->getTile(x, y, z); - - // 4J Stu - We saw a random crash near the end of development on XboxOne orignal version where the id here isn't a tile any more - // Adding this check in to avoid that crash - m_bValidRail = isRail(id); - if(m_bValidRail) - { - int direction = level->getData(x, y, z); - if (((RailTile *) Tile::tiles[id])->usesDataBit) - { - usesDataBit = true; - direction = direction & ~RAIL_DATA_BIT; - } - else - { - usesDataBit = false; - } - updateConnections(direction); - } -} - -RailTile::Rail::~Rail() -{ - for( int i = 0; i < connections.size(); i++ ) - { - delete connections[i]; - } -} - -void RailTile::Rail::updateConnections(int direction) -{ - if(m_bValidRail) - { - for( int i = 0; i < connections.size(); i++ ) - { - delete connections[i]; - } - connections.clear(); - MemSect(50); - if (direction == DIR_FLAT_Z) - { - connections.push_back(new TilePos(x, y, z - 1)); - connections.push_back(new TilePos(x, y, z + 1)); - } else if (direction == DIR_FLAT_X) - { - connections.push_back(new TilePos(x - 1, y, z)); - connections.push_back(new TilePos(x + 1, y, z)); - } else if (direction == 2) - { - connections.push_back(new TilePos(x - 1, y, z)); - connections.push_back(new TilePos(x + 1, y + 1, z)); - } else if (direction == 3) - { - connections.push_back(new TilePos(x - 1, y + 1, z)); - connections.push_back(new TilePos(x + 1, y, z)); - } else if (direction == 4) - { - connections.push_back(new TilePos(x, y + 1, z - 1)); - connections.push_back(new TilePos(x, y, z + 1)); - } else if (direction == 5) - { - connections.push_back(new TilePos(x, y, z - 1)); - connections.push_back(new TilePos(x, y + 1, z + 1)); - } else if (direction == 6) - { - connections.push_back(new TilePos(x + 1, y, z)); - connections.push_back(new TilePos(x, y, z + 1)); - } else if (direction == 7) - { - connections.push_back(new TilePos(x - 1, y, z)); - connections.push_back(new TilePos(x, y, z + 1)); - } else if (direction == 8) - { - connections.push_back(new TilePos(x - 1, y, z)); - connections.push_back(new TilePos(x, y, z - 1)); - } else if (direction == 9) - { - connections.push_back(new TilePos(x + 1, y, z)); - connections.push_back(new TilePos(x, y, z - 1)); - } - MemSect(0); - } -} - -void RailTile::Rail::removeSoftConnections() -{ - if(m_bValidRail) - { - for (unsigned int i = 0; i < connections.size(); i++) - { - Rail *rail = getRail(connections[i]); - if (rail == NULL || !rail->connectsTo(this)) - { - delete connections[i]; - connections.erase(connections.begin()+i); - i--; - } else - { - delete connections[i]; - MemSect(50); - connections[i] =new TilePos(rail->x, rail->y, rail->z); - MemSect(0); - } - delete rail; - } - } -} - -bool RailTile::Rail::hasRail(int x, int y, int z) -{ - if(!m_bValidRail) return false; - if (isRail(level, x, y, z)) return true; - if (isRail(level, x, y + 1, z)) return true; - if (isRail(level, x, y - 1, z)) return true; - return false; -} - -RailTile::Rail *RailTile::Rail::getRail(TilePos *p) -{ - if(!m_bValidRail) return NULL; - if (isRail(level, p->x, p->y, p->z)) return new Rail(level, p->x, p->y, p->z); - if (isRail(level, p->x, p->y + 1, p->z)) return new Rail(level, p->x, p->y + 1, p->z); - if (isRail(level, p->x, p->y - 1, p->z)) return new Rail(level, p->x, p->y - 1, p->z); - return NULL; -} - - -bool RailTile::Rail::connectsTo(Rail *rail) -{ - if(m_bValidRail) - { - AUTO_VAR(itEnd, connections.end()); - for (AUTO_VAR(it, connections.begin()); it != itEnd; it++) - { - TilePos *p = *it; //connections[i]; - if (p->x == rail->x && p->z == rail->z) - { - return true; - } - } - } - return false; -} - -bool RailTile::Rail::hasConnection(int x, int y, int z) -{ - if(m_bValidRail) - { - AUTO_VAR(itEnd, connections.end()); - for (AUTO_VAR(it, connections.begin()); it != itEnd; it++) - { - TilePos *p = *it; //connections[i]; - if (p->x == x && p->z == z) - { - return true; - } - } - } - return false; -} - - -int RailTile::Rail::countPotentialConnections() -{ - int count = 0; - - if(m_bValidRail) - { - if (hasRail(x, y, z - 1)) count++; - if (hasRail(x, y, z + 1)) count++; - if (hasRail(x - 1, y, z)) count++; - if (hasRail(x + 1, y, z)) count++; - } - - return count; -} - -bool RailTile::Rail::canConnectTo(Rail *rail) -{ - if(!m_bValidRail) return false; - if (connectsTo(rail)) return true; - if (connections.size() == 2) - { - return false; - } - if (connections.empty()) - { - return true; - } - - TilePos *c = connections[0]; - - return true; -} - -void RailTile::Rail::connectTo(Rail *rail) -{ - if(m_bValidRail) - { - MemSect(50); - connections.push_back(new TilePos(rail->x, rail->y, rail->z)); - MemSect(0); - - bool n = hasConnection(x, y, z - 1); - bool s = hasConnection(x, y, z + 1); - bool w = hasConnection(x - 1, y, z); - bool e = hasConnection(x + 1, y, z); - - int dir = -1; - - if (n || s) dir = DIR_FLAT_Z; - if (w || e) dir = DIR_FLAT_X; - - if (!usesDataBit) - { - if (s && e && !n && !w) dir = 6; - if (s && w && !n && !e) dir = 7; - if (n && w && !s && !e) dir = 8; - if (n && e && !s && !w) dir = 9; - } - if (dir == DIR_FLAT_Z) - { - if (isRail(level, x, y + 1, z - 1)) dir = 4; - if (isRail(level, x, y + 1, z + 1)) dir = 5; - } - if (dir == DIR_FLAT_X) - { - if (isRail(level, x + 1, y + 1, z)) dir = 2; - if (isRail(level, x - 1, y + 1, z)) dir = 3; - } - - if (dir < 0) dir = DIR_FLAT_Z; - - int data = dir; - if (usesDataBit) - { - data = (level->getData(x, y, z) & RAIL_DATA_BIT) | dir; - } - - level->setData(x, y, z, data); - } -} - -bool RailTile::Rail::hasNeighborRail(int x, int y, int z) -{ - if(!m_bValidRail) return false; - TilePos tp(x,y,z); - Rail *neighbor = getRail( &tp ); - if (neighbor == NULL) return false; - neighbor->removeSoftConnections(); - bool retval = neighbor->canConnectTo(this); - delete neighbor; - return retval; -} - -void RailTile::Rail::place(bool hasSignal, bool first) -{ - if(m_bValidRail) - { - bool n = hasNeighborRail(x, y, z - 1); - bool s = hasNeighborRail(x, y, z + 1); - bool w = hasNeighborRail(x - 1, y, z); - bool e = hasNeighborRail(x + 1, y, z); - - int dir = -1; - - if ((n || s) && !w && !e) dir = DIR_FLAT_Z; - if ((w || e) && !n && !s) dir = DIR_FLAT_X; - - if (!usesDataBit) - { - if (s && e && !n && !w) dir = 6; - if (s && w && !n && !e) dir = 7; - if (n && w && !s && !e) dir = 8; - if (n && e && !s && !w) dir = 9; - } - if (dir == -1) - { - if (n || s) dir = DIR_FLAT_Z; - if (w || e) dir = DIR_FLAT_X; - - if (!usesDataBit) - { - if (hasSignal) - { - if (s && e) dir = 6; - if (w && s) dir = 7; - if (e && n) dir = 9; - if (n && w) dir = 8; - } else { - if (n && w) dir = 8; - if (e && n) dir = 9; - if (w && s) dir = 7; - if (s && e) dir = 6; - } - } - } - - if (dir == DIR_FLAT_Z) - { - if (isRail(level, x, y + 1, z - 1)) dir = 4; - if (isRail(level, x, y + 1, z + 1)) dir = 5; - } - if (dir == DIR_FLAT_X) - { - if (isRail(level, x + 1, y + 1, z)) dir = 2; - if (isRail(level, x - 1, y + 1, z)) dir = 3; - } - - if (dir < 0) dir = DIR_FLAT_Z; - - updateConnections(dir); - - int data = dir; - if (usesDataBit) - { - data = (level->getData(x, y, z) & RAIL_DATA_BIT) | dir; - } - - if (first || level->getData(x, y, z) != data) - { - level->setData(x, y, z, data); - - AUTO_VAR(itEnd, connections.end()); - for (AUTO_VAR(it, connections.begin()); it != itEnd; it++) - { - Rail *neighbor = getRail(*it); - if (neighbor == NULL) continue; - neighbor->removeSoftConnections(); - - if (neighbor->canConnectTo(this)) - { - neighbor->connectTo(this); - } - delete neighbor; - } - } - } -} - -bool RailTile::isRail(Level *level, int x, int y, int z) -{ - int tile = level->getTile(x, y, z); - return tile == Tile::rail_Id || tile == Tile::goldenRail_Id || tile == Tile::detectorRail_Id; - -} - -bool RailTile::isRail(int id) -{ - return id == Tile::rail_Id || id == Tile::goldenRail_Id || id == Tile::detectorRail_Id; -} - -RailTile::RailTile(int id, bool usesDataBit) : Tile(id, Material::decoration, isSolidRender()) -{ - this->usesDataBit = usesDataBit; - this->setShape(0, 0, 0, 1, 2 / 16.0f, 1); - - iconTurn = NULL; -} - -bool RailTile::isUsesDataBit() -{ - return usesDataBit; -} - -AABB *RailTile::getAABB(Level *level, int x, int y, int z) -{ - return NULL; -} - -bool RailTile::blocksLight() -{ - return false; -} - -bool RailTile::isSolidRender(bool isServerLevel) -{ - return false; -} - -HitResult *RailTile::clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b) -{ - updateShape(level, xt, yt, zt); - return Tile::clip(level, xt, yt, zt, a, b); -} - -void RailTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param -{ - int data = level->getData(x, y, z); - if (data >= 2 && data <= 5) - { - setShape(0, 0, 0, 1, 2 / 16.0f + 0.5f, 1); - } else - { - setShape(0, 0, 0, 1, 2 / 16.0f, 1); - } } Icon *RailTile::getTexture(int face, int data) { - if (usesDataBit) + if (data >= 6) { - if (id == Tile::goldenRail_Id) - { - if ((data & RAIL_DATA_BIT) == 0) - { - return icon; - } - else - { - return iconTurn; // Actually the powered rail on version - } - } - } else if (data >= 6) return iconTurn; - return icon; -} - -bool RailTile::isCubeShaped() -{ - return false; -} - -int RailTile::getRenderShape() -{ - return Tile::SHAPE_RAIL; -} - -int RailTile::getResourceCount(Random random) -{ - return 1; -} - -bool RailTile::mayPlace(Level *level, int x, int y, int z) -{ - if (level->isTopSolidBlocking(x, y - 1, z)) - { - return true; - } - return false; -} - -void RailTile::onPlace(Level *level, int x, int y, int z) -{ - if (!level->isClientSide) - { - updateDir(level, x, y, z, true); - - if (id == Tile::goldenRail_Id) - { - neighborChanged(level, x, y, z, id); - } - } -} - -void RailTile::neighborChanged(Level *level, int x, int y, int z, int type) -{ - if (level->isClientSide) return; - - int data = level->getData(x, y, z); - int dir = data; - if (usesDataBit) { - dir = dir & RAIL_DIRECTION_MASK; - } - bool remove = false; - - if (!level->isTopSolidBlocking(x, y - 1, z)) remove = true; - if (dir == 2 && !level->isTopSolidBlocking(x + 1, y, z)) remove = true; - if (dir == 3 && !level->isTopSolidBlocking(x - 1, y, z)) remove = true; - if (dir == 4 && !level->isTopSolidBlocking(x, y, z - 1)) remove = true; - if (dir == 5 && !level->isTopSolidBlocking(x, y, z + 1)) remove = true; - - if (remove) - { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + return iconTurn; } else { - if (id == Tile::goldenRail_Id) - { - bool signal = level->hasNeighborSignal(x, y, z); - signal = signal || findGoldenRailSignal(level, x, y, z, data, true, 0) || findGoldenRailSignal(level, x, y, z, data, false, 0); - - bool changed = false; - if (signal && (data & RAIL_DATA_BIT) == 0) - { - level->setData(x, y, z, dir | RAIL_DATA_BIT); - changed = true; - } else if (!signal && (data & RAIL_DATA_BIT) != 0) - { - level->setData(x, y, z, dir); - changed = true; - } - - // usually the level only updates neighbors that are in the same - // y plane as the current tile, but sloped rails may need to - // update tiles above or below it as well - if (changed) { - level->updateNeighborsAt(x, y - 1, z, id); - if (dir == 2 || dir == 3 || dir == 4 || dir == 5) - { - level->updateNeighborsAt(x, y + 1, z, id); - } - } - } - else if (type > 0 && Tile::tiles[type]->isSignalSource() && !usesDataBit) - { - Rail *rail = new Rail(level, x, y, z); - if (rail->countPotentialConnections() == 3) - { - updateDir(level, x, y, z, false); - } - delete rail; - } + return icon; } - } -void RailTile::updateDir(Level *level, int x, int y, int z, bool first) +void RailTile::registerIcons(IconRegister *iconRegister) { - if (level->isClientSide) return; - Rail *rail = new Rail(level, x, y, z); - rail->place(level->hasNeighborSignal(x, y, z), first); - delete rail; + BaseRailTile::registerIcons(iconRegister); + iconTurn = iconRegister->registerIcon(getIconName() + L"_turned"); } -bool RailTile::findGoldenRailSignal(Level *level, int x, int y, int z, int data, bool forward, int searchDepth) +void RailTile::updateState(Level *level, int x, int y, int z, int data, int dir, int type) { - if (searchDepth >= 8) + if (type > 0 && Tile::tiles[type]->isSignalSource()) { - return false; - } - - int dir = data & RAIL_DIRECTION_MASK; - - bool checkBelow = true; - switch (dir) - { - case DIR_FLAT_Z: - if (forward) - { - z++; - } else { - z--; - } - break; - case DIR_FLAT_X: - if (forward) + if (Rail(level, x, y, z).countPotentialConnections() == 3) { - x--; - } else { - x++; + updateDir(level, x, y, z, false); } - break; - case 2: - if (forward) - { - x--; - } else - { - x++; - y++; - checkBelow = false; - } - dir = DIR_FLAT_X; - break; - case 3: - if (forward) - { - x--; - y++; - checkBelow = false; - } else { - x++; - } - dir = DIR_FLAT_X; - break; - case 4: - if (forward) - { - z++; - } else { - z--; - y++; - checkBelow = false; - } - dir = DIR_FLAT_Z; - break; - case 5: - if (forward) - { - z++; - y++; - checkBelow = false; - } else - { - z--; - } - dir = DIR_FLAT_Z; - break; - } - - if (isGoldenRailWithPower(level, x, y, z, forward, searchDepth, dir)) - { - return true; - } - if (checkBelow && isGoldenRailWithPower(level, x, y - 1, z, forward, searchDepth, dir)) - { - return true; - } - return false; - -} - -bool RailTile::isGoldenRailWithPower(Level *level, int x, int y, int z, bool forward, int searchDepth, int dir) -{ - int tile = level->getTile(x, y, z); - if (tile == Tile::goldenRail_Id) - { - int tileData = level->getData(x, y, z); - int myDir = tileData & RAIL_DIRECTION_MASK; - - if (dir == DIR_FLAT_X && (myDir == DIR_FLAT_Z || myDir == 4 || myDir == 5)) - { - return false; - } - if (dir == DIR_FLAT_Z && (myDir == DIR_FLAT_X || myDir == 2 || myDir == 3)) - { - return false; - } - - if ((tileData & RAIL_DATA_BIT) != 0) - { - if (level->hasNeighborSignal(x, y, z)) - { - return true; - } - else - { - return findGoldenRailSignal(level, x, y, z, tileData, forward, searchDepth + 1); - } - } - } - return false; -} - -int RailTile::getPistonPushReaction() -{ - return Material::PUSH_NORMAL; -} - -void RailTile::registerIcons(IconRegister *iconRegister) -{ - Tile::registerIcons(iconRegister); - if(id == Tile::goldenRail_Id) - { - iconTurn = iconRegister->registerIcon(L"goldenRail_powered"); - } - else - { - iconTurn = iconRegister->registerIcon(L"rail_turn"); } } \ No newline at end of file diff --git a/Minecraft.World/RailTile.h b/Minecraft.World/RailTile.h index 776d8454..eacbf05b 100644 --- a/Minecraft.World/RailTile.h +++ b/Minecraft.World/RailTile.h @@ -1,84 +1,20 @@ #pragma once -#include "Tile.h" -#include "TilePos.h" -#include "Definitions.h" -class Random; -class HitResult; -class ChunkRebuildData; +#include "BaseRailTile.h" -using namespace std; - -class RailTile : public Tile +class RailTile : public BaseRailTile { - friend class Tile; friend class ChunkRebuildData; -public: - static const int DIR_FLAT_Z = 0; - static const int DIR_FLAT_X = 1; - // the data bit is used by boosters and detectors, so they can't turn - static const int RAIL_DATA_BIT = 8; - static const int RAIL_DIRECTION_MASK = 7; private: Icon *iconTurn; - - bool usesDataBit; - - class Rail - { - friend class RailTile; - private: - Level *level; - int x, y, z; - bool usesDataBit; - vector connections; - bool m_bValidRail; // 4J added - - public: - Rail(Level *level, int x, int y, int z); - ~Rail(); - private: - void updateConnections(int direction); - void removeSoftConnections(); - bool hasRail(int x, int y, int z); - Rail *getRail(TilePos *p); - bool connectsTo(Rail *rail); - bool hasConnection(int x, int y, int z); - int countPotentialConnections(); - bool canConnectTo(Rail *rail); - private: - void connectTo(Rail *rail); - bool hasNeighborRail(int x, int y, int z); - public: - void place(bool hasSignal, bool first); - }; + public: - static bool isRail(Level *level, int x, int y, int z); - static bool isRail(int id); -protected: - RailTile(int id, bool usesDataBit); -public: - using Tile::getResourceCount; + RailTile(int id); - bool isUsesDataBit(); - virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual bool blocksLight(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual HitResult *clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b); - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param - virtual Icon *getTexture(int face, int data); - virtual bool isCubeShaped(); - virtual int getRenderShape(); - virtual int getResourceCount(Random random); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual void onPlace(Level *level, int x, int y, int z); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); -private: - void updateDir(Level *level, int x, int y, int z, bool first); - bool findGoldenRailSignal(Level *level, int x, int y, int z, int data, bool forward, int searchDepth); - bool isGoldenRailWithPower(Level *level, int x, int y, int z, bool forward, int searchDepth, int dir); -public: - virtual int getPistonPushReaction(); + Icon *getTexture(int face, int data); void registerIcons(IconRegister *iconRegister); -}; + +protected: + void updateState(Level *level, int x, int y, int z, int data, int dir, int type); +}; \ No newline at end of file diff --git a/Minecraft.World/RandomLevelSource.cpp b/Minecraft.World/RandomLevelSource.cpp index 4e26134a..2b93578a 100644 --- a/Minecraft.World/RandomLevelSource.cpp +++ b/Minecraft.World/RandomLevelSource.cpp @@ -7,6 +7,7 @@ #include "net.minecraft.world.level.levelgen.synth.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.storage.h" +#include "net.minecraft.world.entity.h" #include "RandomLevelSource.h" #ifdef __PS3__ @@ -17,6 +18,8 @@ static PerlinNoise_DataIn g_lperlinNoise2_SPU __attribute__((__aligned__(16))); static PerlinNoise_DataIn g_perlinNoise1_SPU __attribute__((__aligned__(16))); static PerlinNoise_DataIn g_scaleNoise_SPU __attribute__((__aligned__(16))); static PerlinNoise_DataIn g_depthNoise_SPU __attribute__((__aligned__(16))); +//#define DISABLE_SPU_CODE + #endif @@ -26,38 +29,40 @@ const double RandomLevelSource::SNOW_CUTOFF = 0.5; RandomLevelSource::RandomLevelSource(Level *level, __int64 seed, bool generateStructures) : generateStructures( generateStructures ) { m_XZSize = level->getLevelData()->getXZSize(); - +#ifdef _LARGE_WORLDS + level->getLevelData()->getMoatFlags(&m_classicEdgeMoat, &m_smallEdgeMoat, &m_mediumEdgeMoat); +#endif caveFeature = new LargeCaveFeature(); strongholdFeature = new StrongholdFeature(); - villageFeature = new VillageFeature(0,m_XZSize); - mineShaftFeature = new MineShaftFeature(); + villageFeature = new VillageFeature(m_XZSize); + mineShaftFeature = new MineShaftFeature(); scatteredFeature = new RandomScatteredLargeFeature(); canyonFeature = new CanyonFeature(); - this->level = level; + this->level = level; - random = new Random(seed); + random = new Random(seed); pprandom = new Random(seed); // 4J - added, so that we can have a separate random for doing post-processing in parallel with creation - lperlinNoise1 = new PerlinNoise(random, 16); - lperlinNoise2 = new PerlinNoise(random, 16); - perlinNoise1 = new PerlinNoise(random, 8); - perlinNoise3 = new PerlinNoise(random, 4); + lperlinNoise1 = new PerlinNoise(random, 16); + lperlinNoise2 = new PerlinNoise(random, 16); + perlinNoise1 = new PerlinNoise(random, 8); + perlinNoise3 = new PerlinNoise(random, 4); - scaleNoise = new PerlinNoise(random, 10); - depthNoise = new PerlinNoise(random, 16); + scaleNoise = new PerlinNoise(random, 10); + depthNoise = new PerlinNoise(random, 16); - if (FLOATING_ISLANDS) + if (FLOATING_ISLANDS) { - floatingIslandScale = new PerlinNoise(random, 10); - floatingIslandNoise = new PerlinNoise(random, 16); - } + floatingIslandScale = new PerlinNoise(random, 10); + floatingIslandNoise = new PerlinNoise(random, 16); + } else { floatingIslandScale = NULL; floatingIslandNoise = NULL; } - forestNoise = new PerlinNoise(random, 8); + forestNoise = new PerlinNoise(random, 8); } RandomLevelSource::~RandomLevelSource() @@ -69,24 +74,24 @@ RandomLevelSource::~RandomLevelSource() delete scatteredFeature; delete canyonFeature; - this->level = level; + this->level = level; - delete random;; - delete lperlinNoise1; - delete lperlinNoise2; - delete perlinNoise1; - delete perlinNoise3; + delete random;; + delete lperlinNoise1; + delete lperlinNoise2; + delete perlinNoise1; + delete perlinNoise3; - delete scaleNoise; - delete depthNoise; + delete scaleNoise; + delete depthNoise; - if (FLOATING_ISLANDS) + if (FLOATING_ISLANDS) { - delete floatingIslandScale; - delete floatingIslandNoise; - } + delete floatingIslandScale; + delete floatingIslandNoise; + } - delete forestNoise; + delete forestNoise; if( pows.data != NULL ) delete [] pows.data; } @@ -97,115 +102,225 @@ LARGE_INTEGER g_totalPrepareHeightsTime = {0,0}; LARGE_INTEGER g_averagePrepareHeightsTime = {0, 0}; + + + + +#ifdef _LARGE_WORLDS + +int RandomLevelSource::getMinDistanceToEdge(int xxx, int zzz, int worldSize, float falloffStart) +{ + // Get distance to edges of world in x + // we have to do a proper line dist check here + int min = -worldSize/2; + int max = (worldSize/2)-1; + + // // only check if either x or z values are within the falloff + // if(xxx > (min - falloffStart) + + Vec3* topLeft = Vec3::newTemp(min, 0, min); + Vec3* topRight = Vec3::newTemp(max, 0, min); + Vec3* bottomLeft = Vec3::newTemp(min, 0, max); + Vec3* bottomRight = Vec3::newTemp(max, 0, max); + + float closest = falloffStart; + float dist; + // make sure we're in range of the edges before we do a full distance check + if( (xxx > (min-falloffStart) && xxx < (min+falloffStart)) || + (xxx > (max-falloffStart) && xxx < (max+falloffStart)) ) + { + Vec3* point = Vec3::newTemp(xxx, 0, zzz); + if(xxx>0) + dist = point->distanceFromLine(topRight, bottomRight); + else + dist = point->distanceFromLine(topLeft, bottomLeft); + closest = dist; + } + + // make sure we're in range of the edges before we do a full distance check + if( (zzz > (min-falloffStart) && zzz < (min+falloffStart)) || + (zzz > (max-falloffStart) && zzz < (max+falloffStart)) ) + { + Vec3* point = Vec3::newTemp(xxx, 0, zzz); + if(zzz>0) + dist = point->distanceFromLine(bottomLeft, bottomRight); + else + dist = point->distanceFromLine(topLeft, topRight); + if(dist expandedWorldSizes[i])) + { + // this world has been expanded, with moat settings, so we need fallofs at this edges too + int eminMoat = getMinDistanceToEdge(xxx, zzz, expandedWorldSizes[i], falloffStart); + if(eminMoat < emin) + { + emin = eminMoat; + } + } + } + + // Calculate how much we want the world to fall away, if we're in the defined region to do so + if( emin < falloffStart ) + { + int falloff = falloffStart - emin; + comp = ((float)falloff / (float)falloffStart ) * falloffMax; + } + *pEMin = emin; + return comp; + // 4J - end of extra code + /////////////////////////////////////////////////////////////////// +} + +#else + + +// MGH - go back to using the simpler version for PS3/vita/360, as it was causing a lot of slow down on the tuturial generation +float RandomLevelSource::getHeightFalloff(int xxx, int zzz, int* pEMin) +{ + /////////////////////////////////////////////////////////////////// + // 4J - add this chunk of code to make land "fall-off" at the edges of + // a finite world - size of that world is currently hard-coded in here + const int worldSize = m_XZSize * 16; + const int falloffStart = 32; // chunks away from edge were we start doing fall-off + const float falloffMax = 128.0f; // max value we need to get to falloff by the edge of the map + + // Get distance to edges of world in x + int xxx0 = xxx + ( worldSize / 2 ); + if( xxx0 < 0 ) xxx0 = 0; + int xxx1 = ( ( worldSize / 2 ) - 1 ) - xxx; + if( xxx1 < 0 ) xxx1 = 0; + + // Get distance to edges of world in z + int zzz0 = zzz + ( worldSize / 2 ); + if( zzz0 < 0 ) zzz0 = 0; + int zzz1 = ( ( worldSize / 2 ) - 1 ) - zzz; + if( zzz1 < 0 ) zzz1 = 0; + + // Get min distance to any edge + int emin = xxx0; + if (xxx1 < emin ) emin = xxx1; + if (zzz0 < emin ) emin = zzz0; + if (zzz1 < emin ) emin = zzz1; + + float comp = 0.0f; + + // Calculate how much we want the world to fall away, if we're in the defined region to do so + if( emin < falloffStart ) + { + int falloff = falloffStart - emin; + comp = ((float)falloff / (float)falloffStart ) * falloffMax; + } + // 4J - end of extra code + /////////////////////////////////////////////////////////////////// + *pEMin = emin; + return comp; +} + +#endif // _LARGE_WORLDS + void RandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) { LARGE_INTEGER startTime; - int xChunks = 16 / CHUNK_WIDTH; + int xChunks = 16 / CHUNK_WIDTH; int yChunks = Level::genDepth / CHUNK_HEIGHT; int waterHeight = level->seaLevel; - int xSize = xChunks + 1; - int ySize = Level::genDepth / CHUNK_HEIGHT + 1; - int zSize = xChunks + 1; + int xSize = xChunks + 1; + int ySize = Level::genDepth / CHUNK_HEIGHT + 1; + int zSize = xChunks + 1; BiomeArray biomes; // 4J created locally here for thread safety, java has this as a class member level->getBiomeSource()->getRawBiomeBlock(biomes, xOffs * CHUNK_WIDTH - 2, zOffs * CHUNK_WIDTH - 2, xSize + 5, zSize + 5); doubleArray buffer; // 4J - used to be declared with class level scope but tidying up for thread safety reasons - buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize, biomes); + buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize, biomes); QueryPerformanceCounter(&startTime); - for (int xc = 0; xc < xChunks; xc++) + for (int xc = 0; xc < xChunks; xc++) { - for (int zc = 0; zc < xChunks; zc++) + for (int zc = 0; zc < xChunks; zc++) { - for (int yc = 0; yc < yChunks; yc++) + for (int yc = 0; yc < yChunks; yc++) { - double yStep = 1 / (double) CHUNK_HEIGHT; - double s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; - double s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; - double s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; - double s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; - - double s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; - double s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; - double s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; - double s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; - - for (int y = 0; y < CHUNK_HEIGHT; y++) + double yStep = 1 / (double) CHUNK_HEIGHT; + double s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; + double s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; + double s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; + double s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; + + double s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; + double s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; + double s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; + double s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; + + for (int y = 0; y < CHUNK_HEIGHT; y++) { - double xStep = 1 / (double) CHUNK_WIDTH; + double xStep = 1 / (double) CHUNK_WIDTH; - double _s0 = s0; - double _s1 = s1; - double _s0a = (s2 - s0) * xStep; - double _s1a = (s3 - s1) * xStep; + double _s0 = s0; + double _s1 = s1; + double _s0a = (s2 - s0) * xStep; + double _s1a = (s3 - s1) * xStep; - for (int x = 0; x < CHUNK_WIDTH; x++) + for (int x = 0; x < CHUNK_WIDTH; x++) { - int offs = (x + xc * CHUNK_WIDTH) << Level::genDepthBitsPlusFour | (0 + zc * CHUNK_WIDTH) << Level::genDepthBits | (yc * CHUNK_HEIGHT + y); - int step = 1 << Level::genDepthBits; + int offs = (x + xc * CHUNK_WIDTH) << Level::genDepthBitsPlusFour | (0 + zc * CHUNK_WIDTH) << Level::genDepthBits | (yc * CHUNK_HEIGHT + y); + int step = 1 << Level::genDepthBits; offs -= step; - double zStep = 1 / (double) CHUNK_WIDTH; + double zStep = 1 / (double) CHUNK_WIDTH; - double val = _s0; - double vala = (_s1 - _s0) * zStep; + double val = _s0; + double vala = (_s1 - _s0) * zStep; val -= vala; - for (int z = 0; z < CHUNK_WIDTH; z++) + for (int z = 0; z < CHUNK_WIDTH; z++) { - /////////////////////////////////////////////////////////////////// - // 4J - add this chunk of code to make land "fall-off" at the edges of - // a finite world - size of that world is currently hard-coded in here - const int worldSize = m_XZSize * 16; - const int falloffStart = 32; // chunks away from edge were we start doing fall-off - const float falloffMax = 128.0f; // max value we need to get to falloff by the edge of the map - +// 4J Stu - I have removed all uses of the new getHeightFalloff function for now as we had some problems with PS3/PSVita world generation +// I have fixed the non large worlds method, however we will be happier if the current builds go out with completely old code +// We can put the new code back in mid-november 2014 once those PS3/Vita builds are gone (and the PS4 doesn't have world enlarging in these either anyway) int xxx = ( ( xOffs * 16 ) + x + ( xc * CHUNK_WIDTH ) ); int zzz = ( ( zOffs * 16 ) + z + ( zc * CHUNK_WIDTH ) ); + int emin; + float comp = getHeightFalloff(xxx, zzz, &emin); - // Get distance to edges of world in x - int xxx0 = xxx + ( worldSize / 2 ); - if( xxx0 < 0 ) xxx0 = 0; - int xxx1 = ( ( worldSize / 2 ) - 1 ) - xxx; - if( xxx1 < 0 ) xxx1 = 0; - - // Get distance to edges of world in z - int zzz0 = zzz + ( worldSize / 2 ); - if( zzz0 < 0 ) zzz0 = 0; - int zzz1 = ( ( worldSize / 2 ) - 1 ) - zzz; - if( zzz1 < 0 ) zzz1 = 0; - - // Get min distance to any edge - int emin = xxx0; - if (xxx1 < emin ) emin = xxx1; - if (zzz0 < emin ) emin = zzz0; - if (zzz1 < emin ) emin = zzz1; - - float comp = 0.0f; - - // Calculate how much we want the world to fall away, if we're in the defined region to do so - if( emin < falloffStart ) - { - int falloff = falloffStart - emin; - comp = ((float)falloff / (float)falloffStart ) * falloffMax; - } - // 4J - end of extra code - /////////////////////////////////////////////////////////////////// // 4J - slightly rearranged this code (as of java 1.0.1 merge) to better fit with // changes we've made edge-of-world things - original sets blocks[offs += step] directly // here rather than setting a tileId int tileId = 0; // 4J - this comparison used to just be with 0.0f but is now varied by block above - if ((val += vala) > comp) + if ((val += vala) > comp) { - tileId = (byte) Tile::rock_Id; - } + tileId = (byte) Tile::stone_Id; + } else if (yc * CHUNK_HEIGHT + y < waterHeight) { - tileId = (byte) Tile::calmWater_Id; - } + tileId = (byte) Tile::calmWater_Id; + } // 4J - more extra code to make sure that the column at the edge of the world is just water & rock, to match the infinite sea that // continues on after the edge of the world. @@ -213,24 +328,24 @@ void RandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) if( emin == 0 ) { // This matches code in MultiPlayerChunkCache that makes the geometry which continues at the edge of the world - if( yc * CHUNK_HEIGHT + y <= ( level->getSeaLevel() - 10 ) ) tileId = Tile::rock_Id; + if( yc * CHUNK_HEIGHT + y <= ( level->getSeaLevel() - 10 ) ) tileId = Tile::stone_Id; else if( yc * CHUNK_HEIGHT + y < level->getSeaLevel() ) tileId = Tile::calmWater_Id; } blocks[offs += step] = tileId; - } - _s0 += _s0a; - _s1 += _s1a; - } - - s0 += s0a; - s1 += s1a; - s2 += s2a; - s3 += s3a; - } - } - } - } + } + _s0 += _s0a; + _s1 += _s1a; + } + + s0 += s0a; + s1 += s1a; + s2 += s2a; + s3 += s3a; + } + } + } + } LARGE_INTEGER endTime; QueryPerformanceCounter(&endTime); LARGE_INTEGER timeInFunc; @@ -248,26 +363,26 @@ void RandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArray blocks) void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes) { - int waterHeight = level->seaLevel; + int waterHeight = level->seaLevel; - double s = 1 / 32.0; + double s = 1 / 32.0; doubleArray depthBuffer(16*16); // 4J - used to be declared with class level scope but moved here for thread safety - depthBuffer = perlinNoise3->getRegion(depthBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s * 2, s * 2, s * 2); + depthBuffer = perlinNoise3->getRegion(depthBuffer, xOffs * 16, zOffs * 16, 0, 16, 16, 1, s * 2, s * 2, s * 2); - for (int x = 0; x < 16; x++) + for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) + for (int z = 0; z < 16; z++) { - Biome *b = biomes[z + x * 16]; + Biome *b = biomes[z + x * 16]; float temp = b->getTemperature(); - int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random->nextDouble() * 0.25); + int runDepth = (int) (depthBuffer[x + z * 16] / 3 + 3 + random->nextDouble() * 0.25); - int run = -1; + int run = -1; - byte top = b->topMaterial; - byte material = b->material; + byte top = b->topMaterial; + byte material = b->material; LevelGenerationOptions *lgo = app.getLevelGenerationOptions(); if(lgo != NULL) @@ -275,70 +390,69 @@ void RandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, Bi lgo->getBiomeOverride(b->id,material,top); } - for (int y = Level::genDepthMinusOne; y >= 0; y--) + for (int y = Level::genDepthMinusOne; y >= 0; y--) { - int offs = (z * 16 + x) * Level::genDepth + y; + int offs = (z * 16 + x) * Level::genDepth + y; if (y <= 1 + random->nextInt(2)) // 4J - changed to make the bedrock not have bits you can get stuck in -// if (y <= 0 + random->nextInt(5)) + // if (y <= 0 + random->nextInt(5)) { - blocks[offs] = (byte) Tile::unbreakable_Id; - } + blocks[offs] = (byte) Tile::unbreakable_Id; + } else { - int old = blocks[offs]; + int old = blocks[offs]; - if (old == 0) + if (old == 0) { - run = -1; - } - else if (old == Tile::rock_Id) + run = -1; + } + else if (old == Tile::stone_Id) { - if (run == -1) + if (run == -1) { - if (runDepth <= 0) + if (runDepth <= 0) { - top = 0; - material = (byte) Tile::rock_Id; - } + top = 0; + material = (byte) Tile::stone_Id; + } else if (y >= waterHeight - 4 && y <= waterHeight + 1) { - top = b->topMaterial; + top = b->topMaterial; material = b->material; if(lgo != NULL) { lgo->getBiomeOverride(b->id,material,top); } - } + } - if (y < waterHeight && top == 0) + if (y < waterHeight && top == 0) { - if (temp < 0.15f) top = (byte) Tile::ice_Id; - else top = (byte) Tile::calmWater_Id; - } - - run = runDepth; - if (y >= waterHeight - 1) blocks[offs] = top; - else blocks[offs] = material; - } + if (temp < 0.15f) top = (byte) Tile::ice_Id; + else top = (byte) Tile::calmWater_Id; + } + + run = runDepth; + if (y >= waterHeight - 1) blocks[offs] = top; + else blocks[offs] = material; + } else if (run > 0) { - run--; - blocks[offs] = material; + run--; + blocks[offs] = material; - // place a few sandstone blocks beneath sand - // runs - if (run == 0 && material == Tile::sand_Id) + // place a few sandstone blocks beneath sand runs + if (run == 0 && material == Tile::sand_Id) { - run = random->nextInt(4); - material = (byte) Tile::sandStone_Id; - } - } - } - } - } - } - } + run = random->nextInt(4); + material = (byte) Tile::sandStone_Id; + } + } + } + } + } + } + } delete [] depthBuffer.data; @@ -351,28 +465,28 @@ LevelChunk *RandomLevelSource::create(int x, int z) LevelChunk *RandomLevelSource::getChunk(int xOffs, int zOffs) { - random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); + random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); // 4J - now allocating this with a physical alloc & bypassing general memory management so that it will get cleanly freed int blocksSize = Level::genDepth * 16 * 16; byte *tileData = (byte *)XPhysicalAlloc(blocksSize, MAXULONG_PTR, 4096, PAGE_READWRITE); XMemSet128(tileData,0,blocksSize); byteArray blocks = byteArray(tileData,blocksSize); -// byteArray blocks = byteArray(16 * level->depth * 16); + // byteArray blocks = byteArray(16 * level->depth * 16); - // LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); // 4J - moved to below + // LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); // 4J - moved to below prepareHeights(xOffs, zOffs, blocks); // 4J - Some changes made here to how biomes, temperatures and downfalls are passed around for thread safety BiomeArray biomes; - level->getBiomeSource()->getBiomeBlock(biomes, xOffs * 16, zOffs * 16, 16, 16, true); + level->getBiomeSource()->getBiomeBlock(biomes, xOffs * 16, zOffs * 16, 16, 16, true); - buildSurfaces(xOffs, zOffs, blocks, biomes); + buildSurfaces(xOffs, zOffs, blocks, biomes); delete [] biomes.data; - caveFeature->apply(this, level, xOffs, zOffs, blocks); + caveFeature->apply(this, level, xOffs, zOffs, blocks); // 4J Stu Design Change - 1.8 gen goes stronghold, mineshaft, village, canyon // this changed in 1.2 to canyon, mineshaft, village, stronghold // This change makes sense as it stops canyons running through other structures @@ -384,19 +498,19 @@ LevelChunk *RandomLevelSource::getChunk(int xOffs, int zOffs) strongholdFeature->apply(this, level, xOffs, zOffs, blocks); scatteredFeature->apply(this, level, xOffs, zOffs, blocks); } -// canyonFeature.apply(this, level, xOffs, zOffs, blocks); - // townFeature.apply(this, level, xOffs, zOffs, blocks); - // addCaves(xOffs, zOffs, blocks); - // addTowns(xOffs, zOffs, blocks); + // canyonFeature.apply(this, level, xOffs, zOffs, blocks); + // townFeature.apply(this, level, xOffs, zOffs, blocks); + // addCaves(xOffs, zOffs, blocks); + // addTowns(xOffs, zOffs, blocks); -// levelChunk->recalcHeightmap(); // 4J - removed & moved into its own method + // levelChunk->recalcHeightmap(); // 4J - removed & moved into its own method // 4J - this now creates compressed block data from the blocks array passed in, so moved it until after the blocks are actually finalised. We also // now need to free the passed in blocks as the LevelChunk doesn't use the passed in allocation anymore. LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); XPhysicalFree(tileData); - return levelChunk; + return levelChunk; } // 4J - removed & moved into its own method from getChunk, so we can call recalcHeightmap after the chunk is added into the cache. Without @@ -411,10 +525,10 @@ void RandomLevelSource::lightChunk(LevelChunk *lc) doubleArray RandomLevelSource::getHeights(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize, BiomeArray& biomes) { - if (buffer.data == NULL) + if (buffer.data == NULL) { - buffer = doubleArray(xSize * ySize * zSize); - } + buffer = doubleArray(xSize * ySize * zSize); + } if (pows.data == NULL) { pows = floatArray(5 * 5); @@ -428,16 +542,16 @@ doubleArray RandomLevelSource::getHeights(doubleArray buffer, int x, int y, int } } - double s = 1 * 684.412; - double hs = 1 * 684.412; + double s = 1 * 684.412; + double hs = 1 * 684.412; doubleArray pnr, ar, br, sr, dr, fi, fis; // 4J - used to be declared with class level scope but moved here for thread safety - if (FLOATING_ISLANDS) + if (FLOATING_ISLANDS) { - fis = floatingIslandScale->getRegion(fis, x, y, z, xSize, 1, zSize, 1.0, 0, 1.0); - fi = floatingIslandNoise->getRegion(fi, x, y, z, xSize, 1, zSize, 500.0, 0, 500.0); - } + fis = floatingIslandScale->getRegion(fis, x, y, z, xSize, 1, zSize, 1.0, 0, 1.0); + fi = floatingIslandNoise->getRegion(fi, x, y, z, xSize, 1, zSize, 500.0, 0, 500.0); + } #if defined __PS3__ && !defined DISABLE_SPU_CODE C4JSpursJobQueue::Port port("C4JSpursJob_PerlinNoise"); @@ -459,23 +573,23 @@ doubleArray RandomLevelSource::getHeights(doubleArray buffer, int x, int y, int port.submitJob(&perlinJob4); port.submitJob(&perlinJob5); port.waitForCompletion(); - #else - sr = scaleNoise->getRegion(sr, x, z, xSize, zSize, 1.121, 1.121, 0.5); - dr = depthNoise->getRegion(dr, x, z, xSize, zSize, 200.0, 200.0, 0.5); - pnr = perlinNoise1->getRegion(pnr, x, y, z, xSize, ySize, zSize, s / 80.0, hs / 160.0, s / 80.0); - ar = lperlinNoise1->getRegion(ar, x, y, z, xSize, ySize, zSize, s, hs, s); - br = lperlinNoise2->getRegion(br, x, y, z, xSize, ySize, zSize, s, hs, s); +#else + sr = scaleNoise->getRegion(sr, x, z, xSize, zSize, 1.121, 1.121, 0.5); + dr = depthNoise->getRegion(dr, x, z, xSize, zSize, 200.0, 200.0, 0.5); + pnr = perlinNoise1->getRegion(pnr, x, y, z, xSize, ySize, zSize, s / 80.0, hs / 160.0, s / 80.0); + ar = lperlinNoise1->getRegion(ar, x, y, z, xSize, ySize, zSize, s, hs, s); + br = lperlinNoise2->getRegion(br, x, y, z, xSize, ySize, zSize, s, hs, s); #endif x = z = 0; - int p = 0; - int pp = 0; + int p = 0; + int pp = 0; - for (int xx = 0; xx < xSize; xx++) + for (int xx = 0; xx < xSize; xx++) { - for (int zz = 0; zz < zSize; zz++) + for (int zz = 0; zz < zSize; zz++) { float sss = 0; float ddd = 0; @@ -504,27 +618,27 @@ doubleArray RandomLevelSource::getHeights(doubleArray buffer, int x, int y, int sss = sss * 0.9f + 0.1f; ddd = (ddd * 4 - 1) / 8.0f; - - double rdepth = (dr[pp] / 8000.0); - if (rdepth < 0) rdepth = -rdepth * 0.3; - rdepth = rdepth * 3.0 - 2.0; - if (rdepth < 0) + double rdepth = (dr[pp] / 8000.0); + if (rdepth < 0) rdepth = -rdepth * 0.3; + rdepth = rdepth * 3.0 - 2.0; + + if (rdepth < 0) { rdepth = rdepth / 2; - if (rdepth < -1) rdepth = -1; - rdepth = rdepth / 1.4; - rdepth /= 2; - } + if (rdepth < -1) rdepth = -1; + rdepth = rdepth / 1.4; + rdepth /= 2; + } else { - if (rdepth > 1) rdepth = 1; - rdepth = rdepth / 8; - } + if (rdepth > 1) rdepth = 1; + rdepth = rdepth / 8; + } - pp++; + pp++; - for (int yy = 0; yy < ySize; yy++) + for (int yy = 0; yy < ySize; yy++) { double depth = ddd; double scale = sss; @@ -534,32 +648,32 @@ doubleArray RandomLevelSource::getHeights(doubleArray buffer, int x, int y, int double yCenter = ySize / 2.0 + depth * 4; - double val = 0; + double val = 0; double yOffs = (yy - (yCenter)) * 12 * 128 / Level::genDepth / scale; - if (yOffs < 0) yOffs *= 4; + if (yOffs < 0) yOffs *= 4; - double bb = ar[p] / 512; - double cc = br[p] / 512; + double bb = ar[p] / 512; + double cc = br[p] / 512; - double v = (pnr[p] / 10 + 1) / 2; - if (v < 0) val = bb; - else if (v > 1) val = cc; - else val = bb + (cc - bb) * v; - val -= yOffs; + double v = (pnr[p] / 10 + 1) / 2; + if (v < 0) val = bb; + else if (v > 1) val = cc; + else val = bb + (cc - bb) * v; + val -= yOffs; - if (yy > ySize - 4) + if (yy > ySize - 4) { - double slide = (yy - (ySize - 4)) / (4 - 1.0f); - val = val * (1 - slide) + -10 * slide; - } + double slide = (yy - (ySize - 4)) / (4 - 1.0f); + val = val * (1 - slide) + -10 * slide; + } - buffer[p] = val; - p++; - } - } - } + buffer[p] = val; + p++; + } + } + } delete [] pnr.data; delete [] ar.data; @@ -569,7 +683,7 @@ doubleArray RandomLevelSource::getHeights(doubleArray buffer, int x, int y, int delete [] fi.data; delete [] fis.data; - return buffer; + return buffer; } @@ -580,76 +694,76 @@ bool RandomLevelSource::hasChunk(int x, int y) void RandomLevelSource::calcWaterDepths(ChunkSource *parent, int xt, int zt) { - int xo = xt * 16; - int zo = zt * 16; - for (int x = 0; x < 16; x++) + int xo = xt * 16; + int zo = zt * 16; + for (int x = 0; x < 16; x++) { - int y = level->getSeaLevel(); - for (int z = 0; z < 16; z++) + int y = level->getSeaLevel(); + for (int z = 0; z < 16; z++) { - int xp = xo + x + 7; - int zp = zo + z + 7; - int h = level->getHeightmap(xp, zp); - if (h <= 0) + int xp = xo + x + 7; + int zp = zo + z + 7; + int h = level->getHeightmap(xp, zp); + if (h <= 0) { - if (level->getHeightmap(xp - 1, zp) > 0 || level->getHeightmap(xp + 1, zp) > 0 || level->getHeightmap(xp, zp - 1) > 0 || level->getHeightmap(xp, zp + 1) > 0) + if (level->getHeightmap(xp - 1, zp) > 0 || level->getHeightmap(xp + 1, zp) > 0 || level->getHeightmap(xp, zp - 1) > 0 || level->getHeightmap(xp, zp + 1) > 0) { - bool hadWater = false; - if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater_Id && level->getData(xp - 1, y, zp) < 7)) hadWater = true; - if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater_Id && level->getData(xp + 1, y, zp) < 7)) hadWater = true; - if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater_Id && level->getData(xp, y, zp - 1) < 7)) hadWater = true; - if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater_Id && level->getData(xp, y, zp + 1) < 7)) hadWater = true; - if (hadWater) + bool hadWater = false; + if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater_Id && level->getData(xp - 1, y, zp) < 7)) hadWater = true; + if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater_Id && level->getData(xp + 1, y, zp) < 7)) hadWater = true; + if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater_Id && level->getData(xp, y, zp - 1) < 7)) hadWater = true; + if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater_Id && level->getData(xp, y, zp + 1) < 7)) hadWater = true; + if (hadWater) { - for (int x2 = -5; x2 <= 5; x2++) + for (int x2 = -5; x2 <= 5; x2++) { - for (int z2 = -5; z2 <= 5; z2++) + for (int z2 = -5; z2 <= 5; z2++) { - int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2); + int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2); - if (d <= 5) + if (d <= 5) { - d = 6 - d; - if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater_Id) + d = 6 - d; + if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater_Id) { - int od = level->getData(xp + x2, y, zp + z2); - if (od < 7 && od < d) + int od = level->getData(xp + x2, y, zp + z2); + if (od < 7 && od < d) { - level->setData(xp + x2, y, zp + z2, d); - } - } - } - } - } - if (hadWater) + level->setData(xp + x2, y, zp + z2, d, Tile::UPDATE_ALL); + } + } + } + } + } + if (hadWater) { - level->setTileAndDataNoUpdate(xp, y, zp, Tile::calmWater_Id, 7); - for (int y2 = 0; y2 < y; y2++) + level->setTileAndData(xp, y, zp, Tile::calmWater_Id, 7, Tile::UPDATE_CLIENTS); + for (int y2 = 0; y2 < y; y2++) { - level->setTileAndDataNoUpdate(xp, y2, zp, Tile::calmWater_Id, 8); - } - } - } - } - } - } - } + level->setTileAndData(xp, y2, zp, Tile::calmWater_Id, 8, Tile::UPDATE_CLIENTS); + } + } + } + } + } + } + } } // 4J - changed this to used pprandom rather than random, so that we can run it concurrently with getChunk void RandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) { - HeavyTile::instaFall = true; - int xo = xt * 16; - int zo = zt * 16; + HeavyTile::instaFall = true; + int xo = xt * 16; + int zo = zt * 16; - Biome *biome = level->getBiome(xo + 16, zo + 16); + Biome *biome = level->getBiome(xo + 16, zo + 16); - if (RandomLevelSource::FLOATING_ISLANDS) + if (FLOATING_ISLANDS) { - calcWaterDepths(parent, xt, zt); - } + calcWaterDepths(parent, xt, zt); + } pprandom->setSeed(level->getSeed()); __int64 xScale = pprandom->nextLong() / 2 * 2 + 1; @@ -669,15 +783,17 @@ void RandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Lakes"); - if (!hasVillage && pprandom->nextInt(4) == 0) + if (biome != Biome::desert && biome != Biome::desertHills) { - int x = xo + pprandom->nextInt(16) + 8; - int y = pprandom->nextInt(Level::genDepth); - int z = zo + pprandom->nextInt(16) + 8; + if (!hasVillage && pprandom->nextInt(4) == 0) + { + int x = xo + pprandom->nextInt(16) + 8; + int y = pprandom->nextInt(Level::genDepth); + int z = zo + pprandom->nextInt(16) + 8; - LakeFeature *calmWater = new LakeFeature(Tile::calmWater_Id); - calmWater->place(level, pprandom, x, y, z); - delete calmWater; + LakeFeature calmWater(Tile::calmWater_Id); + calmWater.place(level, pprandom, x, y, z); + } } PIXEndNamedEvent(); @@ -689,55 +805,58 @@ void RandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) int z = zo + pprandom->nextInt(16) + 8; if (y < level->seaLevel || pprandom->nextInt(10) == 0) { - LakeFeature *calmLava = new LakeFeature(Tile::calmLava_Id); - calmLava->place(level, pprandom, x, y, z); - delete calmLava; + LakeFeature calmLava(Tile::calmLava_Id); + calmLava.place(level, pprandom, x, y, z); } } PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Monster rooms"); - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 8; i++) + { int x = xo + pprandom->nextInt(16) + 8; int y = pprandom->nextInt(Level::genDepth); int z = zo + pprandom->nextInt(16) + 8; - MonsterRoomFeature *mrf = new MonsterRoomFeature(); - if (mrf->place(level, pprandom, x, y, z)) - { - } - delete mrf; + MonsterRoomFeature mrf; + mrf.place(level, pprandom, x, y, z); } PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Biome decorate"); biome->decorate(level, pprandom, xo, zo); PIXEndNamedEvent(); - + + PIXBeginNamedEvent(0,"Process Schematics"); app.processSchematics(parent->getChunk(xt,zt)); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Post process mobs"); MobSpawner::postProcessSpawnMobs(level, biome, xo + 8, zo + 8, 16, 16, pprandom); + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Update ice and snow"); // 4J - brought forward from 1.2.3 to get snow back in taiga biomes - xo += 8; - zo += 8; - for (int x = 0; x < 16; x++) + xo += 8; + zo += 8; + for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) + for (int z = 0; z < 16; z++) { - int y = level->getTopRainBlock(xo + x, zo + z); + int y = level->getTopRainBlock(xo + x, zo + z); - if (level->shouldFreezeIgnoreNeighbors(x + xo, y - 1, z + zo)) + if (level->shouldFreezeIgnoreNeighbors(x + xo, y - 1, z + zo)) { - level->setTileNoUpdate(x + xo, y - 1, z + zo, Tile::ice_Id); // 4J - changed from setTile, otherwise we end up creating a *lot* of dynamic water tiles as these ice tiles are set - } - if (level->shouldSnow(x + xo, y, z + zo)) + level->setTileAndData(x + xo, y - 1, z + zo, Tile::ice_Id, 0, Tile::UPDATE_CLIENTS); + } + if (level->shouldSnow(x + xo, y, z + zo)) { - level->setTile(x + xo, y, z + zo, Tile::topSnow_Id); - } - } - } + level->setTileAndData(x + xo, y, z + zo, Tile::topSnow_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } + PIXEndNamedEvent(); - HeavyTile::instaFall = false; + HeavyTile::instaFall = false; } bool RandomLevelSource::save(bool force, ProgressListener *progressListener) @@ -762,19 +881,34 @@ wstring RandomLevelSource::gatherStats() vector *RandomLevelSource::getMobsAt(MobCategory *mobCategory, int x, int y, int z) { - Biome *biome = level->getBiome(x, z); - if (biome == NULL) + Biome *biome = level->getBiome(x, z); + if (biome == NULL) { - return NULL; - } - return biome->getMobs(mobCategory); + return NULL; + } + if (mobCategory == MobCategory::monster && scatteredFeature->isSwamphut(x, y, z)) + { + return scatteredFeature->getSwamphutEnemies(); + } + return biome->getMobs(mobCategory); } TilePos *RandomLevelSource::findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z) { - if (LargeFeature::STRONGHOLD == featureName && strongholdFeature != NULL) + if (LargeFeature::STRONGHOLD == featureName && strongholdFeature != NULL) { - return strongholdFeature->getNearestGeneratedFeature(level, x, y, z); - } - return NULL; + return strongholdFeature->getNearestGeneratedFeature(level, x, y, z); + } + return NULL; } + +void RandomLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ) +{ + if (generateStructures) + { + mineShaftFeature->apply(this, level, chunkX, chunkZ, NULL); + villageFeature->apply(this, level, chunkX, chunkZ, NULL); + strongholdFeature->apply(this, level, chunkX, chunkZ, NULL); + scatteredFeature->apply(this, level, chunkX, chunkZ, NULL); + } +} \ No newline at end of file diff --git a/Minecraft.World/RandomLevelSource.h b/Minecraft.World/RandomLevelSource.h index d71028b1..740a9db2 100644 --- a/Minecraft.World/RandomLevelSource.h +++ b/Minecraft.World/RandomLevelSource.h @@ -14,31 +14,31 @@ class RandomScatteredLargeFeature; class RandomLevelSource : public ChunkSource { public: - static const double SNOW_CUTOFF; - static const double SNOW_SCALE; - static const bool FLOATING_ISLANDS = false; - static const int CHUNK_HEIGHT = 8; - static const int CHUNK_WIDTH = 4; + static const double SNOW_CUTOFF; + static const double SNOW_SCALE; + static const bool FLOATING_ISLANDS = false; + static const int CHUNK_HEIGHT = 8; + static const int CHUNK_WIDTH = 4; private: - Random *random; + Random *random; Random *pprandom; // 4J - added - PerlinNoise *lperlinNoise1; - PerlinNoise *lperlinNoise2; - PerlinNoise *perlinNoise1; - PerlinNoise *perlinNoise3; + PerlinNoise *lperlinNoise1; + PerlinNoise *lperlinNoise2; + PerlinNoise *perlinNoise1; + PerlinNoise *perlinNoise3; public: - PerlinNoise *scaleNoise; - PerlinNoise *depthNoise; + PerlinNoise *scaleNoise; + PerlinNoise *depthNoise; private: - PerlinNoise *floatingIslandScale; - PerlinNoise *floatingIslandNoise; + PerlinNoise *floatingIslandScale; + PerlinNoise *floatingIslandNoise; public: - PerlinNoise *forestNoise; + PerlinNoise *forestNoise; private: Level *level; @@ -51,10 +51,15 @@ public: ~RandomLevelSource(); public: +#ifdef _LARGE_WORLDS + int getMinDistanceToEdge(int xxx, int zzz, int worldSize, float falloffStart); + +#endif + float getHeightFalloff(int xxx, int zzz, int* pEMin); void prepareHeights(int xOffs, int zOffs, byteArray blocks); public: - void buildSurfaces(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes); + void buildSurfaces(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes); private: LargeFeature *caveFeature; @@ -64,10 +69,10 @@ private: RandomScatteredLargeFeature *scatteredFeature; LargeFeature *canyonFeature; private: - virtual LevelChunk *create(int x, int z); + virtual LevelChunk *create(int x, int z); public: - virtual LevelChunk *getChunk(int xOffs, int zOffs); + virtual LevelChunk *getChunk(int xOffs, int zOffs); virtual void lightChunk(LevelChunk *lc); // 4J added private: @@ -80,13 +85,14 @@ private: void calcWaterDepths(ChunkSource *parent, int xt, int zt); public: - virtual void postProcess(ChunkSource *parent, int xt, int zt); - virtual bool save(bool force, ProgressListener *progressListener); - virtual bool tick(); - virtual bool shouldSave(); - virtual wstring gatherStats(); + virtual void postProcess(ChunkSource *parent, int xt, int zt); + virtual bool save(bool force, ProgressListener *progressListener); + virtual bool tick(); + virtual bool shouldSave(); + virtual wstring gatherStats(); public: virtual vector *getMobsAt(MobCategory *mobCategory, int x, int y, int z); - virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ); }; diff --git a/Minecraft.World/RandomScatteredLargeFeature.cpp b/Minecraft.World/RandomScatteredLargeFeature.cpp index d460dc14..2a2290e3 100644 --- a/Minecraft.World/RandomScatteredLargeFeature.cpp +++ b/Minecraft.World/RandomScatteredLargeFeature.cpp @@ -1,9 +1,11 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.biome.h" +#include "net.minecraft.world.level.levelgen.structure.h" #include "ScatteredFeaturePieces.h" #include "RandomScatteredLargeFeature.h" +const wstring RandomScatteredLargeFeature::OPTION_SPACING = L"distance"; vector RandomScatteredLargeFeature::allowedBiomes; void RandomScatteredLargeFeature::staticCtor() @@ -11,29 +13,55 @@ void RandomScatteredLargeFeature::staticCtor() allowedBiomes.push_back( Biome::desert ); allowedBiomes.push_back( Biome::desertHills ); allowedBiomes.push_back( Biome::jungle ); + allowedBiomes.push_back( Biome::jungleHills ); + allowedBiomes.push_back( Biome::swampland ); +} + +void RandomScatteredLargeFeature::_init() +{ + spacing = 32; + minSeparation = 8; + + swamphutEnemies.push_back(new Biome::MobSpawnerData(eTYPE_WITCH, 1, 1, 1)); } RandomScatteredLargeFeature::RandomScatteredLargeFeature() { + _init(); } -bool RandomScatteredLargeFeature::isFeatureChunk(int x, int z, bool bIsSuperflat) +RandomScatteredLargeFeature::RandomScatteredLargeFeature(unordered_map options) { - int featureSpacing = 32; - int minFeatureSeparation = 8; + _init(); + for(AUTO_VAR(it, options.begin()); it != options.end(); ++it) + { + if (it->first.compare(OPTION_SPACING) == 0) + { + spacing = Mth::getInt(it->second, spacing, minSeparation + 1); + } + } +} + +wstring RandomScatteredLargeFeature::getFeatureName() +{ + return L"Temple"; +} + +bool RandomScatteredLargeFeature::isFeatureChunk(int x, int z, bool bIsSuperflat) +{ int xx = x; int zz = z; - if (x < 0) x -= featureSpacing - 1; - if (z < 0) z -= featureSpacing - 1; + if (x < 0) x -= spacing - 1; + if (z < 0) z -= spacing - 1; - int xCenterFeatureChunk = x / featureSpacing; - int zCenterFeatureChunk = z / featureSpacing; + int xCenterFeatureChunk = x / spacing; + int zCenterFeatureChunk = z / spacing; Random *r = level->getRandomFor(xCenterFeatureChunk, zCenterFeatureChunk, 14357617); - xCenterFeatureChunk *= featureSpacing; - zCenterFeatureChunk *= featureSpacing; - xCenterFeatureChunk += r->nextInt(featureSpacing - minFeatureSeparation); - zCenterFeatureChunk += r->nextInt(featureSpacing - minFeatureSeparation); + xCenterFeatureChunk *= spacing; + zCenterFeatureChunk *= spacing; + xCenterFeatureChunk += r->nextInt(spacing - minSeparation); + zCenterFeatureChunk += r->nextInt(spacing - minSeparation); x = xx; z = zz; @@ -46,11 +74,14 @@ bool RandomScatteredLargeFeature::isFeatureChunk(int x, int z, bool bIsSuperflat if (forcePlacement || (x == xCenterFeatureChunk && z == zCenterFeatureChunk)) { - bool biomeOk = level->getBiomeSource()->containsOnly(x * 16 + 8, z * 16 + 8, 0, allowedBiomes); - if (biomeOk) + Biome *biome = level->getBiomeSource()->getBiome(x * 16 + 8, z * 16 + 8); + for (AUTO_VAR(it,allowedBiomes.begin()); it != allowedBiomes.end(); ++it) { - // System.out.println("feature at " + (x * 16) + " " + (z * 16)); - return true; + Biome *a = *it; + if (biome == a) + { + return true; + } } } @@ -60,25 +91,50 @@ bool RandomScatteredLargeFeature::isFeatureChunk(int x, int z, bool bIsSuperflat StructureStart *RandomScatteredLargeFeature::createStructureStart(int x, int z) { - // System.out.println("feature at " + (x * 16) + " " + (z * 16)); return new ScatteredFeatureStart(level, random, x, z); } +RandomScatteredLargeFeature::ScatteredFeatureStart::ScatteredFeatureStart() +{ + // for reflection +} -RandomScatteredLargeFeature::ScatteredFeatureStart::ScatteredFeatureStart(Level *level, Random *random, int chunkX, int chunkZ) +RandomScatteredLargeFeature::ScatteredFeatureStart::ScatteredFeatureStart(Level *level, Random *random, int chunkX, int chunkZ) : StructureStart(chunkX, chunkZ) { - if (level->getBiome(chunkX * 16 + 8, chunkZ * 16 + 8) == Biome::jungle) + Biome *biome = level->getBiome(chunkX * 16 + 8, chunkZ * 16 + 8); + if (biome == Biome::jungle || biome == Biome::jungleHills) { ScatteredFeaturePieces::JunglePyramidPiece *startRoom = new ScatteredFeaturePieces::JunglePyramidPiece(random, chunkX * 16, chunkZ * 16); pieces.push_back(startRoom); - // System.out.println("jungle feature at " + (chunkX * 16) + " " + (chunkZ * 16)); + } + else if (biome == Biome::swampland) + { + ScatteredFeaturePieces::SwamplandHut *startRoom = new ScatteredFeaturePieces::SwamplandHut(random, chunkX * 16, chunkZ * 16); + pieces.push_back(startRoom); } else { ScatteredFeaturePieces::DesertPyramidPiece *startRoom = new ScatteredFeaturePieces::DesertPyramidPiece(random, chunkX * 16, chunkZ * 16); pieces.push_back(startRoom); - // System.out.println("desert feature at " + (chunkX * 16) + " " + (chunkZ * 16)); } calculateBoundingBox(); +} + +bool RandomScatteredLargeFeature::isSwamphut(int cellX, int cellY, int cellZ) +{ + StructureStart *structureAt = getStructureAt(cellX, cellY, cellZ); + if (structureAt == NULL || !( dynamic_cast( structureAt ) ) || structureAt->pieces.empty()) + { + return false; + } + StructurePiece *first = NULL; + AUTO_VAR(it, structureAt->pieces.begin()); + if(it != structureAt->pieces.end() ) first = *it; + return dynamic_cast(first) != NULL; +} + +vector *RandomScatteredLargeFeature::getSwamphutEnemies() +{ + return &swamphutEnemies; } \ No newline at end of file diff --git a/Minecraft.World/RandomScatteredLargeFeature.h b/Minecraft.World/RandomScatteredLargeFeature.h index b7d9fc06..b5d46ce8 100644 --- a/Minecraft.World/RandomScatteredLargeFeature.h +++ b/Minecraft.World/RandomScatteredLargeFeature.h @@ -6,17 +6,41 @@ class RandomScatteredLargeFeature : public StructureFeature { public: + static const wstring OPTION_SPACING; + static void staticCtor(); static vector allowedBiomes; + +private: + vector swamphutEnemies; + int spacing; + int minSeparation; + + void _init(); + +public: RandomScatteredLargeFeature(); + RandomScatteredLargeFeature(unordered_map options); + + wstring getFeatureName(); protected: virtual bool isFeatureChunk(int x, int z, bool bIsSuperflat=false); StructureStart *createStructureStart(int x, int z); +public: class ScatteredFeatureStart : public StructureStart { public: + static StructureStart *Create() { return new ScatteredFeatureStart(); } + virtual EStructureStart GetType() { return eStructureStart_ScatteredFeatureStart; } + + public: + ScatteredFeatureStart(); ScatteredFeatureStart(Level *level, Random *random, int chunkX, int chunkZ); }; + +public: + bool isSwamphut(int cellX, int cellY, int cellZ); + vector *getSwamphutEnemies(); }; \ No newline at end of file diff --git a/Minecraft.World/RandomStrollGoal.cpp b/Minecraft.World/RandomStrollGoal.cpp index 21f3adb1..15957ab3 100644 --- a/Minecraft.World/RandomStrollGoal.cpp +++ b/Minecraft.World/RandomStrollGoal.cpp @@ -7,10 +7,10 @@ #include "SharedConstants.h" #include "RandomStrollGoal.h" -RandomStrollGoal::RandomStrollGoal(PathfinderMob *mob, float speed) +RandomStrollGoal::RandomStrollGoal(PathfinderMob *mob, double speedModifier) { this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); } @@ -56,5 +56,5 @@ bool RandomStrollGoal::canContinueToUse() void RandomStrollGoal::start() { - mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speed); + mob->getNavigation()->moveTo(wantedX, wantedY, wantedZ, speedModifier); } \ No newline at end of file diff --git a/Minecraft.World/RandomStrollGoal.h b/Minecraft.World/RandomStrollGoal.h index e46a9c95..0cde8334 100644 --- a/Minecraft.World/RandomStrollGoal.h +++ b/Minecraft.World/RandomStrollGoal.h @@ -9,10 +9,10 @@ class RandomStrollGoal : public Goal private: PathfinderMob *mob; double wantedX, wantedY, wantedZ; - float speed; + double speedModifier; public: - RandomStrollGoal(PathfinderMob *mob, float speed); + RandomStrollGoal(PathfinderMob *mob, double speedModifier); virtual bool canUse(); virtual bool canContinueToUse(); diff --git a/Minecraft.World/RangedAttackGoal.cpp b/Minecraft.World/RangedAttackGoal.cpp new file mode 100644 index 00000000..2923e011 --- /dev/null +++ b/Minecraft.World/RangedAttackGoal.cpp @@ -0,0 +1,105 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.ai.control.h" +#include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.ai.sensing.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.phys.h" +#include "RangedAttackGoal.h" + +void RangedAttackGoal::_init(RangedAttackMob *rangedMob, Mob *mob, double speedModifier, int attackIntervalMin, int attackIntervalMax, float attackRadius) +{ + //if (!(mob instanceof LivingEntity)) + //{ + //throw new IllegalArgumentException("ArrowAttackGoal requires Mob implements RangedAttackMob"); + //} + rangedAttackMob = rangedMob; + this->mob = mob; + this->speedModifier = speedModifier; + this->attackIntervalMin = attackIntervalMin; + this->attackIntervalMax = attackIntervalMax; + this->attackRadius = attackRadius; + attackRadiusSqr = attackRadius * attackRadius; + setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); + + target = weak_ptr(); + attackTime = -1; + seeTime = 0; +} + +RangedAttackGoal::RangedAttackGoal(RangedAttackMob *rangedMob, Mob *mob, double speedModifier, int attackInterval, float attackRadius) +{ + _init(rangedMob, mob, speedModifier, attackInterval, attackInterval, attackRadius); +} + +RangedAttackGoal::RangedAttackGoal(RangedAttackMob *rangedMob, Mob *mob, double speedModifier, int attackIntervalMin, int attackIntervalMax, float attackRadius) +{ + _init(rangedMob, mob, speedModifier, attackIntervalMin, attackIntervalMax, attackRadius); +} + +bool RangedAttackGoal::canUse() +{ + shared_ptr bestTarget = mob->getTarget(); + if (bestTarget == NULL) return false; + target = weak_ptr(bestTarget); + return true; +} + +bool RangedAttackGoal::canContinueToUse() +{ + return canUse() || !mob->getNavigation()->isDone(); +} + +void RangedAttackGoal::stop() +{ + target = weak_ptr(); + seeTime = 0; + attackTime = -1; +} + +void RangedAttackGoal::tick() +{ + // 4J: It's possible the target has gone since canUse selected it, don't do tick if target is null + if (target.lock() == NULL) return; + + double targetDistSqr = mob->distanceToSqr(target.lock()->x, target.lock()->bb->y0, target.lock()->z); + bool canSee = mob->getSensing()->canSee(target.lock()); + + if (canSee) + { + seeTime++; + } + else + { + seeTime = 0; + } + + if (targetDistSqr > attackRadiusSqr || seeTime < 20) + { + mob->getNavigation()->moveTo(target.lock(), speedModifier); + } + else + { + mob->getNavigation()->stop(); + } + + mob->getLookControl()->setLookAt(target.lock(), 30, 30); + + if (--attackTime == 0) + { + if (targetDistSqr > attackRadiusSqr || !canSee) return; + + float dist = Mth::sqrt(targetDistSqr) / attackRadius; + float power = dist; + if (power < 0.1f) power = 0.1f; + if (power > 1) power = 1; + + rangedAttackMob->performRangedAttack(target.lock(), power); + attackTime = Mth::floor(dist * (attackIntervalMax - attackIntervalMin) + attackIntervalMin); + } + else if (attackTime < 0) + { + float dist = Mth::sqrt(targetDistSqr) / attackRadius; + attackTime = Mth::floor(dist * (attackIntervalMax - attackIntervalMin) + attackIntervalMin); + } +} \ No newline at end of file diff --git a/Minecraft.World/RangedAttackGoal.h b/Minecraft.World/RangedAttackGoal.h new file mode 100644 index 00000000..7667707b --- /dev/null +++ b/Minecraft.World/RangedAttackGoal.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Goal.h" + +class RangedAttackMob; + +class RangedAttackGoal : public Goal +{ +private: + Mob *mob; // Owner + RangedAttackMob *rangedAttackMob; // owner + weak_ptr target; + int attackTime; + double speedModifier; + int seeTime; + int attackIntervalMin; + int attackIntervalMax; + float attackRadius; + float attackRadiusSqr; + + void _init(RangedAttackMob *rangedMob, Mob *mob, double speedModifier, int attackIntervalMin, int attackIntervalMax, float attackRadius); + +public: + // 4J Added extra Mob param to avoid weird type conversion problems + RangedAttackGoal(RangedAttackMob *rangedMob, Mob *mob, double speedModifier, int attackInterval, float attackRadius); + RangedAttackGoal(RangedAttackMob *rangedMob, Mob *mob, double speedModifier, int attackIntervalMin, int attackIntervalMax, float attackRadius); + + bool canUse(); + bool canContinueToUse(); + void stop(); + void tick(); +}; \ No newline at end of file diff --git a/Minecraft.World/RangedAttackMob.h b/Minecraft.World/RangedAttackMob.h new file mode 100644 index 00000000..8a9f67ef --- /dev/null +++ b/Minecraft.World/RangedAttackMob.h @@ -0,0 +1,7 @@ +#pragma once + +class RangedAttackMob +{ +public: + virtual void performRangedAttack(shared_ptr target, float power) = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/RangedAttribute.cpp b/Minecraft.World/RangedAttribute.cpp new file mode 100644 index 00000000..d61d77ce --- /dev/null +++ b/Minecraft.World/RangedAttribute.cpp @@ -0,0 +1,31 @@ +#include "stdafx.h" + +#include "RangedAttribute.h" + +RangedAttribute::RangedAttribute(eATTRIBUTE_ID id, double defaultValue, double minValue, double maxValue) : BaseAttribute(id, defaultValue) +{ + this->minValue = minValue; + this->maxValue = maxValue; + + //if (minValue > maxValue) throw new IllegalArgumentException("Minimum value cannot be bigger than maximum value!"); + //if (defaultValue < minValue) throw new IllegalArgumentException("Default value cannot be lower than minimum value!"); + //if (defaultValue > maxValue) throw new IllegalArgumentException("Default value cannot be bigger than maximum value!"); +} + +double RangedAttribute::getMinValue() +{ + return minValue; +} + +double RangedAttribute::getMaxValue() +{ + return maxValue; +} + +double RangedAttribute::sanitizeValue(double value) +{ + if (value < minValue) value = minValue; + if (value > maxValue) value = maxValue; + + return value; +} \ No newline at end of file diff --git a/Minecraft.World/RangedAttribute.h b/Minecraft.World/RangedAttribute.h new file mode 100644 index 00000000..f2c59324 --- /dev/null +++ b/Minecraft.World/RangedAttribute.h @@ -0,0 +1,21 @@ +#pragma once + +#include "BaseAttribute.h" + +class RangedAttribute : public BaseAttribute +{ +private: + double minValue; + double maxValue; + +public: + RangedAttribute(eATTRIBUTE_ID id, double defaultValue, double minValue, double maxValue); + + double getMinValue(); + double getMaxValue(); + double sanitizeValue(double value); + + // 4J: Removed legacy name + //RangedAttribute *importLegacyName(const wstring &name); + //wstring getImportLegacyName(); +}; \ No newline at end of file diff --git a/Minecraft.World/Recipes.cpp b/Minecraft.World/Recipes.cpp index 93be1dfb..dbb1dbde 100644 --- a/Minecraft.World/Recipes.cpp +++ b/Minecraft.World/Recipes.cpp @@ -1,19 +1,3 @@ -/*package net.minecraft.world.Item::crafting; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import net.minecraft.world.inventory.CraftingContainer; -import net.minecraft.world.Item::CoalItem; -import net.minecraft.world.Item::Item; -import net.minecraft.world.Item::ItemInstance; -import net.minecraft.world.level.Tile::StoneSlabTile; -import net.minecraft.world.level.Tile::Tile;*/ - #include "stdafx.h" #include "Container.h" #include "AbstractContainerMenu.h" @@ -32,6 +16,7 @@ OreRecipies *Recipes::pOreRecipies=NULL; StructureRecipies *Recipes::pStructureRecipies=NULL; ToolRecipies *Recipes::pToolRecipies=NULL; WeaponRecipies *Recipes::pWeaponRecipies=NULL; +FireworksRecipe *Recipes::pFireworksRecipes=NULL; void Recipes::staticCtor() { @@ -60,6 +45,11 @@ Recipes::Recipes() // 4J Stu - These just don't work with our crafting menu //recipies->push_back(new ArmorDyeRecipe()); + //recipies->add(new MapCloningRecipe()); + //recipies->add(new MapExtendingRecipe()); + //recipies->add(new FireworksRecipe()); + pFireworksRecipes = new FireworksRecipe(); + addShapedRecipy(new ItemInstance(Tile::wood, 4, 0), // L"sczg", @@ -109,7 +99,7 @@ Recipes::Recipes() L"ssctctg", L"###", // L"XXX", // - L'#', Tile::cloth, L'X', Tile::wood, + L'#', Tile::wool, L'X', Tile::wood, L'S'); addShapedRecipy(new ItemInstance(Tile::enchantTable, 1), // @@ -177,7 +167,7 @@ Recipes::Recipes() L"###", // L"###", // - L'#', Tile::stoneBrick, + L'#', Tile::cobblestone, L'S'); addShapedRecipy(new ItemInstance(Tile::cobbleWall, 6, WallTile::TYPE_MOSSY), // @@ -185,7 +175,7 @@ Recipes::Recipes() L"###", // L"###", // - L'#', Tile::mossStone, + L'#', Tile::mossyCobblestone, L'S'); addShapedRecipy(new ItemInstance(Item::door_wood, 1), // @@ -228,7 +218,7 @@ Recipes::Recipes() L"## ", // L"###", // - L'#', Tile::stoneBrick, + L'#', Tile::cobblestone, L'S'); addShapedRecipy(new ItemInstance(Tile::stairs_bricks, 4), // @@ -246,7 +236,7 @@ Recipes::Recipes() L"## ", // L"###", // - L'#', Tile::stoneBrickSmooth, + L'#', Tile::cobblestone, L'S'); addShapedRecipy(new ItemInstance(Tile::stairs_netherBricks, 4), // @@ -317,6 +307,13 @@ Recipes::Recipes() L'#', Item::snowBall, L'S'); + addShapedRecipy(new ItemInstance(Tile::topSnow, 6), // + L"sctg", + L"###", // + + L'#', Tile::snow, + L'S'); + addShapedRecipy(new ItemInstance(Tile::clay, 1), // L"sscig", L"##", // @@ -333,7 +330,7 @@ Recipes::Recipes() L'#', Item::brick, L'S'); - addShapedRecipy(new ItemInstance(Tile::cloth, 1), // + addShapedRecipy(new ItemInstance(Tile::wool, 1), // L"sscig", L"##", // L"##", // @@ -347,7 +344,7 @@ Recipes::Recipes() L"#X#", // L"X#X", // - L'X', Item::sulphur,// + L'X', Item::gunpowder,// L'#', Tile::sand, L'T'); @@ -362,13 +359,13 @@ Recipes::Recipes() L"sctg", L"###", // - L'#', Tile::rock, + L'#', Tile::stone, L'S'); addShapedRecipy(new ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::COBBLESTONE_SLAB), // L"sctg", L"###", // - L'#', Tile::stoneBrick, + L'#', Tile::cobblestone, L'S'); addShapedRecipy(new ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::BRICK_SLAB), // @@ -382,7 +379,7 @@ Recipes::Recipes() L"sctg", L"###", // - L'#', Tile::stoneBrickSmooth, + L'#', Tile::stoneBrick, L'S'); addShapedRecipy(new ItemInstance(Tile::stoneSlabHalf, 6, StoneSlabTile::NETHERBRICK_SLAB), // @@ -441,7 +438,7 @@ Recipes::Recipes() L"BEB", // L"CCC", // - L'A', Item::milk,// + L'A', Item::bucket_milk,// L'B', Item::sugar,// L'C', Item::wheat, L'E', Item::egg, L'F'); @@ -474,6 +471,17 @@ Recipes::Recipes() L'#', Item::stick, L'V'); + addShapedRecipy(new ItemInstance(Tile::activatorRail, 6), // + L"ssscictcig", + L"XSX", // + L"X#X", // + L"XSX", // + + L'X', Item::ironIngot,// + L'#', Tile::redstoneTorch_on,// + L'S', Item::stick, + L'V'); + addShapedRecipy(new ItemInstance(Tile::detectorRail, 6), // L"ssscicictg", L"X X", // @@ -509,6 +517,22 @@ Recipes::Recipes() L'A', Tile::furnace, L'B', Item::minecart, L'V'); + addShapedRecipy(new ItemInstance(Item::minecart_tnt, 1), // + L"ssctcig", + L"A", // + L"B", // + + L'A', Tile::tnt, L'B', Item::minecart, + L'V'); + + addShapedRecipy(new ItemInstance(Item::minecart_hopper, 1), // + L"ssctcig", + L"A", // + L"B", // + + L'A', Tile::hopper, L'B', Item::minecart, + L'V'); + addShapedRecipy(new ItemInstance(Item::boat, 1), // L"ssctg", L"# #", // @@ -616,14 +640,14 @@ Recipes::Recipes() L'T'); addShapedRecipy(new ItemInstance(Tile::torch, 4), // - L"sscicig", + L"ssczcig", L"X", // L"#", // - L'X', Item::coal,// + L'X', new ItemInstance(Item::coal, 1, CoalItem::STONE_COAL),// L'#', Item::stick, L'T'); - addShapedRecipy(new ItemInstance(Tile::lightGem, 1), // + addShapedRecipy(new ItemInstance(Tile::glowstone, 1), // L"sscig", L"##", // L"##", // @@ -644,7 +668,7 @@ Recipes::Recipes() L"X", // L"#", // - L'#', Tile::stoneBrick, L'X', Item::stick, + L'#', Tile::cobblestone, L'X', Item::stick, L'M'); addShapedRecipy(new ItemInstance(Tile::tripWireSource, 2), // @@ -656,7 +680,7 @@ Recipes::Recipes() L'#', Tile::wood, L'S', Item::stick, L'I', Item::ironIngot, L'M'); - addShapedRecipy(new ItemInstance(Tile::notGate_on, 1), // + addShapedRecipy(new ItemInstance(Tile::redstoneTorch_on, 1), // L"sscicig", L"X", // L"#", // @@ -664,14 +688,40 @@ Recipes::Recipes() L'#', Item::stick, L'X', Item::redStone, L'M'); - addShapedRecipy(new ItemInstance(Item::diode, 1), // + addShapedRecipy(new ItemInstance(Item::repeater, 1), // L"ssctcictg", L"#X#", // L"III", // - L'#', Tile::notGate_on, L'X', Item::redStone, L'I', Tile::rock, + L'#', Tile::redstoneTorch_on, L'X', Item::redStone, L'I', Tile::stone, L'M'); + addShapedRecipy(new ItemInstance(Item::comparator, 1), // + L"sssctcictg", + L" # ", // + L"#X#", // + L"III", // + + L'#', Tile::redstoneTorch_on, L'X', Item::netherQuartz, L'I', Tile::stone, + L'M'); + + addShapedRecipy(new ItemInstance(Tile::daylightDetector), + L"sssctcictg", + L"GGG", + L"QQQ", + L"WWW", + + L'G', Tile::glass, L'Q', Item::netherQuartz, L'W', Tile::woodSlabHalf, + L'M'); + + addShapedRecipy(new ItemInstance(Tile::hopper), + L"ssscictg", + L"I I", // + L"ICI", // + L" I ", // + + L'I', Item::ironIngot, L'C', Tile::chest, + L'M'); addShapedRecipy(new ItemInstance(Item::clock, 1), // L"ssscicig", @@ -688,12 +738,21 @@ Recipes::Recipes() addShapelessRecipy(new ItemInstance(Item::fireball, 3), // L"iiig", - Item::sulphur, Item::blazePowder,Item::coal, + Item::gunpowder, Item::blazePowder,Item::coal, L'T'); addShapelessRecipy(new ItemInstance(Item::fireball, 3), // L"iizg", - Item::sulphur, Item::blazePowder,new ItemInstance(Item::coal, 1, CoalItem::CHAR_COAL), + Item::gunpowder, Item::blazePowder,new ItemInstance(Item::coal, 1, CoalItem::CHAR_COAL), + L'T'); + + addShapedRecipy(new ItemInstance(Item::lead, 2), // + L"ssscicig", + L"~~ ", // + L"~O ", // + L" ~", // + + L'~', Item::string, L'O', Item::slimeBall, L'T'); @@ -706,7 +765,6 @@ Recipes::Recipes() L'#', Item::ironIngot, L'X', Item::redStone, L'T'); - // 4J-PB Added a MapItem init addShapedRecipy(new ItemInstance(Item::map, 1), // L"ssscicig", L"###", // @@ -719,14 +777,14 @@ Recipes::Recipes() addShapedRecipy(new ItemInstance(Tile::button, 1), // L"sctg", L"#", // - //L"#", // - L'#', Tile::rock, + + L'#', Tile::stone, L'M'); addShapedRecipy(new ItemInstance(Tile::button_wood, 1), // L"sctg", L"#", // - //L"#", // + L'#', Tile::wood, L'M'); @@ -739,16 +797,38 @@ Recipes::Recipes() addShapedRecipy(new ItemInstance(Tile::pressurePlate_stone, 1), // L"sctg", L"##", // - L'#', Tile::rock, + L'#', Tile::stone, L'M'); + addShapedRecipy(new ItemInstance(Tile::weightedPlate_heavy, 1), // + L"scig", + L"##", // + + L'#', Item::ironIngot, + L'M'); + + addShapedRecipy(new ItemInstance(Tile::weightedPlate_light, 1), // + L"scig", + L"##", // + + L'#', Item::goldIngot, + L'M'); addShapedRecipy(new ItemInstance(Tile::dispenser, 1), // L"sssctcicig", L"###", // L"#X#", // L"#R#", // - L'#', Tile::stoneBrick, L'X', Item::bow, L'R', Item::redStone, + L'#', Tile::cobblestone, L'X', Item::bow, L'R', Item::redStone, + L'M'); + + addShapedRecipy(new ItemInstance(Tile::dropper, 1), // + L"sssctcig", + L"###", // + L"# #", // + L"#R#", // + + L'#', Tile::cobblestone, L'R', Item::redStone, L'M'); addShapedRecipy(new ItemInstance(Item::cauldron, 1), // @@ -765,7 +845,7 @@ Recipes::Recipes() L" B ", // L"###", // - L'#', Tile::stoneBrick, L'B', Item::blazeRod, + L'#', Tile::cobblestone, L'B', Item::blazeRod, L'S'); @@ -778,7 +858,7 @@ Recipes::Recipes() L'T'); - addShapedRecipy(new ItemInstance(Tile::recordPlayer, 1), // + addShapedRecipy(new ItemInstance(Tile::jukebox, 1), // L"sssctcig", L"###", // L"#X#", // @@ -787,8 +867,6 @@ Recipes::Recipes() L'#', Tile::wood, L'X', Item::diamond, 'D'); - - addShapedRecipy(new ItemInstance(Item::paper, 3), // L"scig", L"###", // @@ -807,7 +885,7 @@ Recipes::Recipes() //addShapelessRecipy(new ItemInstance(Item.writingBook, 1), // // Item.book, new ItemInstance(Item.dye_powder, 1, DyePowderItem.BLACK), Item.feather); - addShapedRecipy(new ItemInstance(Tile::musicBlock, 1), // + addShapedRecipy(new ItemInstance(Tile::noteblock, 1), // L"sssctcig", L"###", // L"#X#", // @@ -831,7 +909,7 @@ Recipes::Recipes() L"#X#", // L"###", // - L'#', Item::stick, L'X', Tile::cloth, + L'#', Item::stick, L'X', Tile::wool, L'D'); @@ -878,7 +956,7 @@ Recipes::Recipes() L"#X#", // L"#R#", // - L'#', Tile::stoneBrick, L'X', Item::ironIngot, L'R', Item::redStone, L'T', Tile::wood, + L'#', Tile::cobblestone, L'X', Item::ironIngot, L'R', Item::redStone, L'T', Tile::wood, L'M'); addShapedRecipy(new ItemInstance((Tile *)Tile::pistonStickyBase, 1), // @@ -890,6 +968,30 @@ Recipes::Recipes() L'M'); + // 4J Stu - Added some dummy firework recipes to allow us to navigate forward to the fireworks scene + addShapedRecipy(new ItemInstance(Item::fireworks, 1), // + L"sscicig", + L" P ", // + L" G ", // + + L'P', Item::paper, L'G', Item::gunpowder, + L'D'); + + addShapedRecipy(new ItemInstance(Item::fireworksCharge,1), // + L"sscicig", + L" D ", // + L" G ", // + + L'D', Item::dye_powder, L'G', Item::gunpowder, + L'D'); + + addShapedRecipy(new ItemInstance(Item::fireworksCharge,1), // + L"sscicig", + L" D ", // + L" C ", // + + L'D', Item::dye_powder, L'C', Item::fireworksCharge, + L'D'); // Sort so the largest recipes get checked first! @@ -1005,7 +1107,7 @@ ShapedRecipy *Recipes::addShapedRecipy(ItemInstance *result, ...) break; case L'i': pItem=va_arg(vl,Item *); - pItemInstance= new ItemInstance(pItem); + pItemInstance= new ItemInstance(pItem,1,ANY_AUX_VALUE); mappings->insert(myMap::value_type(wchFrom,pItemInstance)); break; case L't': @@ -1146,7 +1248,7 @@ void Recipes::addShapelessRecipy(ItemInstance *result,... ) recipies->push_back(new ShapelessRecipy(result, ingredients, group)); } -shared_ptr Recipes::getItemFor(shared_ptr craftSlots, Level *level) +shared_ptr Recipes::getItemFor(shared_ptr craftSlots, Level *level, Recipy *recipesClass /*= NULL*/) { int count = 0; shared_ptr first = nullptr; @@ -1173,11 +1275,18 @@ shared_ptr Recipes::getItemFor(shared_ptr craft return shared_ptr( new ItemInstance(first->id, 1, resultDamage) ); } - AUTO_VAR(itEnd, recipies->end()); - for (AUTO_VAR(it, recipies->begin()); it != itEnd; it++) + if(recipesClass != NULL) + { + if (recipesClass->matches(craftSlots, level)) return recipesClass->assemble(craftSlots); + } + else { - Recipy *r = *it; //recipies->at(i); - if (r->matches(craftSlots, level)) return r->assemble(craftSlots); + AUTO_VAR(itEnd, recipies->end()); + for (AUTO_VAR(it, recipies->begin()); it != itEnd; it++) + { + Recipy *r = *it; //recipies->at(i); + if (r->matches(craftSlots, level)) return r->assemble(craftSlots); + } } return nullptr; } diff --git a/Minecraft.World/Recipes.h b/Minecraft.World/Recipes.h index c5d091e1..aacdac30 100644 --- a/Minecraft.World/Recipes.h +++ b/Minecraft.World/Recipes.h @@ -31,6 +31,7 @@ class StructureRecipies; class ToolRecipies; class WeaponRecipies; class ShapedRecipy; +class FireworksRecipe; typedef unordered_map myMap; @@ -89,7 +90,7 @@ public: ShapedRecipy *addShapedRecipy(ItemInstance *, ... ); void addShapelessRecipy(ItemInstance *result,... ); - shared_ptr getItemFor(shared_ptr craftSlots, Level *level); + shared_ptr getItemFor(shared_ptr craftSlots, Level *level, Recipy *recipesClass = NULL); // 4J Added recipesClass param vector *getRecipies(); // 4J-PB - Added all below for new Xbox 'crafting' @@ -100,7 +101,7 @@ private: void buildRecipeIngredientsArray(); Recipy::INGREDIENTS_REQUIRED *m_pRecipeIngredientsRequired; - +public: static ToolRecipies *pToolRecipies; static WeaponRecipies *pWeaponRecipies; static StructureRecipies *pStructureRecipies; @@ -108,4 +109,5 @@ private: static FoodRecipies *pFoodRecipies; static ClothDyeRecipes *pClothDyeRecipes; static ArmorRecipes *pArmorRecipes; + static FireworksRecipe *pFireworksRecipes; }; diff --git a/Minecraft.World/RecordingItem.cpp b/Minecraft.World/RecordingItem.cpp index 24be1190..3b501899 100644 --- a/Minecraft.World/RecordingItem.cpp +++ b/Minecraft.World/RecordingItem.cpp @@ -2,14 +2,18 @@ #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.item.h" #include "net.minecraft.world.h" #include "ItemInstance.h" #include "RecordingItem.h" #include "GenericStats.h" +unordered_map RecordingItem::BY_NAME; + RecordingItem::RecordingItem(int id, const wstring& recording) : Item(id), recording( recording ) { this->maxStackSize = 1; + BY_NAME[recording] = this; } Icon *RecordingItem::getIcon(int auxValue) @@ -20,13 +24,13 @@ Icon *RecordingItem::getIcon(int auxValue) bool RecordingItem::useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { // 4J-PB - Adding a test only version to allow tooltips to be displayed - if (level->getTile(x, y, z) == Tile::recordPlayer_Id && level->getData(x, y, z) == 0) + if (level->getTile(x, y, z) == Tile::jukebox_Id && level->getData(x, y, z) == 0) { if(!bTestUseOnOnly) { if (level->isClientSide) return true; - ((RecordPlayerTile *) Tile::recordPlayer)->setRecord(level, x, y, z, id); + ((JukeboxTile *) Tile::jukebox)->setRecord(level, x, y, z, itemInstance); level->levelEvent(nullptr, LevelEvent::SOUND_PLAY_RECORDING, x, y, z, id); itemInstance->count--; @@ -40,17 +44,14 @@ bool RecordingItem::useOn(shared_ptr itemInstance, shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced, vector &unformattedStrings) +void RecordingItem::appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced) { - eMinecraftColour rarityColour = getRarity(shared_ptr())->color; - int colour = app.GetHTMLColour(rarityColour); - wchar_t formatted[256]; - - swprintf(formatted, 256, L"%ls",colour,L"C418 - ", recording.c_str()); + eMinecraftColour color = getRarity(shared_ptr())->color; - lines->push_back(formatted); + wchar_t text[256]; + swprintf(text, 256, L"%ls %ls", L"C418 -", recording.c_str()); - unformattedStrings.push_back(recording); + lines->push_back(HtmlString(text, color)); } const Rarity *RecordingItem::getRarity(shared_ptr itemInstance) @@ -62,3 +63,16 @@ void RecordingItem::registerIcons(IconRegister *iconRegister) { icon = iconRegister->registerIcon(L"record_" + recording); } + +RecordingItem *RecordingItem::getByName(const wstring &name) +{ + AUTO_VAR(it,BY_NAME.find(name)); + if(it != BY_NAME.end()) + { + return it->second; + } + else + { + return NULL; + } +} \ No newline at end of file diff --git a/Minecraft.World/RecordingItem.h b/Minecraft.World/RecordingItem.h index 9b184c6a..3a30eee5 100644 --- a/Minecraft.World/RecordingItem.h +++ b/Minecraft.World/RecordingItem.h @@ -5,19 +5,21 @@ using namespace std; class RecordingItem : public Item { +private: + static unordered_map BY_NAME; + public: const std::wstring recording; public: // 4J Stu - Was protected in Java, but the can't access it where we need RecordingItem(int id, const wstring& recording); - //@Override Icon *getIcon(int auxValue); virtual bool useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); - virtual void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced, vector &unformattedStrings); + virtual void appendHoverText(shared_ptr itemInstance, shared_ptr player, vector *lines, bool advanced); virtual const Rarity *getRarity(shared_ptr itemInstance); - //@Override void registerIcons(IconRegister *iconRegister); + static RecordingItem *getByName(const wstring &name); }; \ No newline at end of file diff --git a/Minecraft.World/RedStoneDustTile.cpp b/Minecraft.World/RedStoneDustTile.cpp index 699cad95..0107b667 100644 --- a/Minecraft.World/RedStoneDustTile.cpp +++ b/Minecraft.World/RedStoneDustTile.cpp @@ -3,7 +3,10 @@ #include "RedStoneDustTile.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" +#include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.h" +#include "net.minecraft.h" #include "Direction.h" #include "DiodeTile.h" @@ -11,10 +14,10 @@ #include "IntBuffer.h" #include "..\Minecraft.Client\Tesselator.h" -const wstring RedStoneDustTile::TEXTURE_CROSS = L"redstoneDust_cross"; -const wstring RedStoneDustTile::TEXTURE_LINE = L"redstoneDust_line"; -const wstring RedStoneDustTile::TEXTURE_CROSS_OVERLAY = L"redstoneDust_cross_overlay"; -const wstring RedStoneDustTile::TEXTURE_LINE_OVERLAY = L"redstoneDust_line_overlay"; +const wstring RedStoneDustTile::TEXTURE_CROSS = L"_cross"; +const wstring RedStoneDustTile::TEXTURE_LINE = L"_line"; +const wstring RedStoneDustTile::TEXTURE_CROSS_OVERLAY = L"_cross_overlay"; +const wstring RedStoneDustTile::TEXTURE_LINE_OVERLAY = L"_line_overlay"; RedStoneDustTile::RedStoneDustTile(int id) : Tile(id, Material::decoration,isSolidRender()) { @@ -71,13 +74,13 @@ int RedStoneDustTile::getColor(LevelSource *level, int x, int y, int z, int data bool RedStoneDustTile::mayPlace(Level *level, int x, int y, int z) { - return level->isTopSolidBlocking(x, y - 1, z) || level->getTile(x, y - 1, z) == Tile::lightGem_Id; + return level->isTopSolidBlocking(x, y - 1, z) || level->getTile(x, y - 1, z) == Tile::glowstone_Id; } void RedStoneDustTile::updatePowerStrength(Level *level, int x, int y, int z) { updatePowerStrength(level, x, y, z, x, y, z); - + vector updates = vector(toUpdate.begin(), toUpdate.end()); toUpdate.clear(); @@ -94,16 +97,19 @@ void RedStoneDustTile::updatePowerStrength(Level *level, int x, int y, int z, in int old = level->getData(x, y, z); int target = 0; - this->shouldSignal = false; - bool neighborSignal = level->hasNeighborSignal(x, y, z); - this->shouldSignal = true; + target = checkTarget(level, xFrom, yFrom, zFrom, target); + + shouldSignal = false; + int neighborSignal = level->getBestNeighborSignal(x, y, z); + shouldSignal = true; - if (neighborSignal) + if (neighborSignal > Redstone::SIGNAL_NONE && neighborSignal > target - 1) { - target = 15; + target = neighborSignal; } - else + { + int newTarget = 0; for (int i = 0; i < 4; i++) { int xt = x; @@ -113,57 +119,32 @@ void RedStoneDustTile::updatePowerStrength(Level *level, int x, int y, int z, in if (i == 2) zt--; if (i == 3) zt++; - if (xt != xFrom || y != yFrom || zt != zFrom) target = checkTarget(level, xt, y, zt, target); + if (xt != xFrom || zt != zFrom) newTarget = checkTarget(level, xt, y, zt, newTarget); if (level->isSolidBlockingTile(xt, y, zt) && !level->isSolidBlockingTile(x, y + 1, z)) { - if (xt != xFrom || y + 1 != yFrom || zt != zFrom) target = checkTarget(level, xt, y + 1, zt, target); + if ((xt != xFrom || zt != zFrom) && y >= yFrom) + newTarget = checkTarget(level, xt, y + 1, zt, newTarget); } else if (!level->isSolidBlockingTile(xt, y, zt)) { - if (xt != xFrom || y - 1 != yFrom || zt != zFrom) target = checkTarget(level, xt, y - 1, zt, target); + if ((xt != xFrom || zt != zFrom) && y <= yFrom) + newTarget = checkTarget(level, xt, y - 1, zt, newTarget); } } - if (target > 0) target--; + if (newTarget > target) target = newTarget - 1; + else if (target > 0) target--; else target = 0; + + if (neighborSignal > target - 1) + { + target = neighborSignal; + } } if (old != target) { - level->noNeighborUpdate = true; - level->setData(x, y, z, target); - level->setTilesDirty(x, y, z, x, y, z); - level->noNeighborUpdate = false; - - for (int i = 0; i < 4; i++) - { - int xt = x; - int zt = z; - int yt = y - 1; - if (i == 0) xt--; - if (i == 1) xt++; - if (i == 2) zt--; - if (i == 3) zt++; + level->setData(x, y, z, target, Tile::UPDATE_CLIENTS); - if (level->isSolidBlockingTile(xt, y, zt)) yt += 2; - - int current = 0; - current = checkTarget(level, xt, y, zt, -1); - target = level->getData(x, y, z); - if (target > 0) target--; - if (current >= 0 && current != target) - { - updatePowerStrength(level, xt, y, zt, x, y, z); - } - current = checkTarget(level, xt, yt, zt, -1); - target = level->getData(x, y, z); - if (target > 0) target--; - if (current >= 0 && current != target) - { - updatePowerStrength(level, xt, yt, zt, x, y, z); - } - } - - if (old < target || target == 0) { toUpdate.insert(TilePos(x, y, z)); toUpdate.insert(TilePos(x - 1, y, z)); @@ -185,7 +166,7 @@ void RedStoneDustTile::checkCornerChangeAt(Level *level, int x, int y, int z) level->updateNeighborsAt(x + 1, y, z, id); level->updateNeighborsAt(x, y, z - 1, id); level->updateNeighborsAt(x, y, z + 1, id); - + level->updateNeighborsAt(x, y - 1, z, id); level->updateNeighborsAt(x, y + 1, z, id); } @@ -254,7 +235,6 @@ int RedStoneDustTile::checkTarget(Level *level, int x, int y, int z, int target) void RedStoneDustTile::neighborChanged(Level *level, int x, int y, int z, int type) { if (level->isClientSide) return; - int face = level->getData(x, y, z); bool ok = mayPlace(level, x, y, z); @@ -264,8 +244,8 @@ void RedStoneDustTile::neighborChanged(Level *level, int x, int y, int z, int ty } else { - spawnResources(level, x, y, z, face, 0); - level->setTile(x, y, z, 0); + spawnResources(level, x, y, z, 0, 0); + level->removeTile(x, y, z); } Tile::neighborChanged(level, x, y, z, type); @@ -276,44 +256,48 @@ int RedStoneDustTile::getResource(int data, Random *random, int playerBonusLevel return Item::redStone->id; } -bool RedStoneDustTile::getDirectSignal(Level *level, int x, int y, int z, int dir) +int RedStoneDustTile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir) { - if (!shouldSignal) return false; + if (!shouldSignal) return Redstone::SIGNAL_NONE; return getSignal(level, x, y, z, dir); } -bool RedStoneDustTile::getSignal(LevelSource *level, int x, int y, int z, int dir) +int RedStoneDustTile::getSignal(LevelSource *level, int x, int y, int z, int dir) { - if (!shouldSignal) return false; - if (level->getData(x, y, z) == 0) return false; + if (!shouldSignal) return Redstone::SIGNAL_NONE; + int data = level->getData(x, y, z); + if (data == Facing::DOWN) + { + return Redstone::SIGNAL_NONE; + } - if (dir == 1) return true; + if (dir == Facing::UP) return data; - bool w = RedStoneDustTile::shouldReceivePowerFrom(level, x - 1, y, z, Direction::WEST) - || (!level->isSolidBlockingTile(x - 1, y, z) && RedStoneDustTile::shouldReceivePowerFrom(level, x - 1, y - 1, z, Direction::UNDEFINED)); - bool e = RedStoneDustTile::shouldReceivePowerFrom(level, x + 1, y, z, Direction::EAST) - || (!level->isSolidBlockingTile(x + 1, y, z) && RedStoneDustTile::shouldReceivePowerFrom(level, x + 1, y - 1, z, Direction::UNDEFINED)); - bool n = RedStoneDustTile::shouldReceivePowerFrom(level, x, y, z - 1, Direction::NORTH) - || (!level->isSolidBlockingTile(x, y, z - 1) && RedStoneDustTile::shouldReceivePowerFrom(level, x, y - 1, z - 1, Direction::UNDEFINED)); - bool s = RedStoneDustTile::shouldReceivePowerFrom(level, x, y, z + 1, Direction::SOUTH) - || (!level->isSolidBlockingTile(x, y, z + 1) && RedStoneDustTile::shouldReceivePowerFrom(level, x, y - 1, z + 1, Direction::UNDEFINED)); + bool w = shouldReceivePowerFrom(level, x - 1, y, z, Direction::WEST) + || (!level->isSolidBlockingTile(x - 1, y, z) && shouldReceivePowerFrom(level, x - 1, y - 1, z, Direction::UNDEFINED)); + bool e = shouldReceivePowerFrom(level, x + 1, y, z, Direction::EAST) + || (!level->isSolidBlockingTile(x + 1, y, z) && shouldReceivePowerFrom(level, x + 1, y - 1, z, Direction::UNDEFINED)); + bool n = shouldReceivePowerFrom(level, x, y, z - 1, Direction::NORTH) + || (!level->isSolidBlockingTile(x, y, z - 1) && shouldReceivePowerFrom(level, x, y - 1, z - 1, Direction::UNDEFINED)); + bool s = shouldReceivePowerFrom(level, x, y, z + 1, Direction::SOUTH) + || (!level->isSolidBlockingTile(x, y, z + 1) && shouldReceivePowerFrom(level, x, y - 1, z + 1, Direction::UNDEFINED)); if (!level->isSolidBlockingTile(x, y + 1, z)) { - if (level->isSolidBlockingTile(x - 1, y, z) && RedStoneDustTile::shouldReceivePowerFrom(level, x - 1, y + 1, z, Direction::UNDEFINED)) w = true; - if (level->isSolidBlockingTile(x + 1, y, z) && RedStoneDustTile::shouldReceivePowerFrom(level, x + 1, y + 1, z, Direction::UNDEFINED)) e = true; - if (level->isSolidBlockingTile(x, y, z - 1) && RedStoneDustTile::shouldReceivePowerFrom(level, x, y + 1, z - 1, Direction::UNDEFINED)) n = true; - if (level->isSolidBlockingTile(x, y, z + 1) && RedStoneDustTile::shouldReceivePowerFrom(level, x, y + 1, z + 1, Direction::UNDEFINED)) s = true; + if (level->isSolidBlockingTile(x - 1, y, z) && shouldReceivePowerFrom(level, x - 1, y + 1, z, Direction::UNDEFINED)) w = true; + if (level->isSolidBlockingTile(x + 1, y, z) && shouldReceivePowerFrom(level, x + 1, y + 1, z, Direction::UNDEFINED)) e = true; + if (level->isSolidBlockingTile(x, y, z - 1) && shouldReceivePowerFrom(level, x, y + 1, z - 1, Direction::UNDEFINED)) n = true; + if (level->isSolidBlockingTile(x, y, z + 1) && shouldReceivePowerFrom(level, x, y + 1, z + 1, Direction::UNDEFINED)) s = true; } - if (!n && !e && !w && !s && (dir >= 2 && dir <= 5)) return true; + if (!n && !e && !w && !s && (dir >= 2 && dir <= 5)) return data; - if (dir == 2 && n && (!w && !e)) return true; - if (dir == 3 && s && (!w && !e)) return true; - if (dir == 4 && w && (!n && !s)) return true; - if (dir == 5 && e && (!n && !s)) return true; + if (dir == 2 && n && (!w && !e)) return data; + if (dir == 3 && s && (!w && !e)) return data; + if (dir == 4 && w && (!n && !s)) return data; + if (dir == 5 && e && (!n && !s)) return data; - return false; + return Redstone::SIGNAL_NONE; } @@ -374,11 +358,11 @@ bool RedStoneDustTile::shouldConnectTo(LevelSource *level, int x, int y, int z, int t = level->getTile(x, y, z); if (t == Tile::redStoneDust_Id) return true; if (t == 0) return false; - if (t == Tile::diode_off_Id || t == Tile::diode_on_Id) + if (Tile::diode_off->isSameDiode(t)) { - int data = level->getData(x, y, z); - return direction == (data & DiodeTile::DIRECTION_MASK) || direction == Direction::DIRECTION_OPPOSITE[data & DiodeTile::DIRECTION_MASK]; - } + int data = level->getData(x, y, z); + return direction == (data & DiodeTile::DIRECTION_MASK) || direction == Direction::DIRECTION_OPPOSITE[data & DiodeTile::DIRECTION_MASK]; + } else if (Tile::tiles[t]->isSignalSource() && direction != Direction::UNDEFINED) return true; return false; @@ -386,18 +370,18 @@ bool RedStoneDustTile::shouldConnectTo(LevelSource *level, int x, int y, int z, bool RedStoneDustTile::shouldReceivePowerFrom(LevelSource *level, int x, int y, int z, int direction) { - if (shouldConnectTo(level, x, y, z, direction)) + if (shouldConnectTo(level, x, y, z, direction)) { - return true; - } + return true; + } - int t = level->getTile(x, y, z); - if (t == Tile::diode_on_Id) + int t = level->getTile(x, y, z); + if (t == Tile::diode_on_Id) { - int data = level->getData(x, y, z); - return direction == (data & DiodeTile::DIRECTION_MASK); - } - return false; + int data = level->getData(x, y, z); + return direction == (data & DiodeTile::DIRECTION_MASK); + } + return false; } int RedStoneDustTile::cloneTileId(Level *level, int x, int y, int z) @@ -407,10 +391,10 @@ int RedStoneDustTile::cloneTileId(Level *level, int x, int y, int z) void RedStoneDustTile::registerIcons(IconRegister *iconRegister) { - iconCross = iconRegister->registerIcon(TEXTURE_CROSS); - iconLine = iconRegister->registerIcon(TEXTURE_LINE); - iconCrossOver = iconRegister->registerIcon(TEXTURE_CROSS_OVERLAY); - iconLineOver = iconRegister->registerIcon(TEXTURE_LINE_OVERLAY); + iconCross = iconRegister->registerIcon(getIconName() + TEXTURE_CROSS); + iconLine = iconRegister->registerIcon(getIconName() + TEXTURE_LINE); + iconCrossOver = iconRegister->registerIcon(getIconName() + TEXTURE_CROSS_OVERLAY); + iconLineOver = iconRegister->registerIcon(getIconName() + TEXTURE_LINE_OVERLAY); icon = iconCross; } diff --git a/Minecraft.World/RedStoneDustTile.h b/Minecraft.World/RedStoneDustTile.h index edb18e6d..2a647658 100644 --- a/Minecraft.World/RedStoneDustTile.h +++ b/Minecraft.World/RedStoneDustTile.h @@ -17,7 +17,7 @@ public: static const wstring TEXTURE_LINE_OVERLAY; private: bool shouldSignal; - unordered_set toUpdate; + unordered_set toUpdate; Icon *iconCross; Icon *iconLine; Icon *iconCrossOver; @@ -25,34 +25,34 @@ private: public: RedStoneDustTile(int id); - virtual void updateDefaultShape(); // 4J Added override - virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); - virtual int getRenderShape(); + virtual void updateDefaultShape(); // 4J Added override + virtual AABB *getAABB(Level *level, int x, int y, int z); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); + virtual int getRenderShape(); virtual int getColor() const; // 4J Added - virtual int getColor(LevelSource *level, int x, int y, int z); + virtual int getColor(LevelSource *level, int x, int y, int z); virtual int getColor(LevelSource *level, int x, int y, int z, int data); // 4J added - virtual bool mayPlace(Level *level, int x, int y, int z); + virtual bool mayPlace(Level *level, int x, int y, int z); private: void updatePowerStrength(Level *level, int x, int y, int z); - void updatePowerStrength(Level *level, int x, int y, int z, int xFrom, int yFrom, int zFrom); - void checkCornerChangeAt(Level *level, int x, int y, int z); + void updatePowerStrength(Level *level, int x, int y, int z, int xFrom, int yFrom, int zFrom); + void checkCornerChangeAt(Level *level, int x, int y, int z); public: virtual void onPlace(Level *level, int x, int y, int z); - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); private: int checkTarget(Level *level, int x, int y, int z, int target); public: virtual void neighborChanged(Level *level, int x, int y, int z, int type); - virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual bool getDirectSignal(Level *level, int x, int y, int z, int dir) ; - virtual bool getSignal(LevelSource *level, int x, int y, int z, int dir); + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir); + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); - virtual bool isSignalSource(); - virtual void animateTick(Level *level, int x, int y, int z, Random *random); + virtual bool isSignalSource(); + virtual void animateTick(Level *level, int x, int y, int z, Random *random); - static bool shouldConnectTo(LevelSource *level, int x, int y, int z, int direction); + static bool shouldConnectTo(LevelSource *level, int x, int y, int z, int direction); static bool shouldReceivePowerFrom(LevelSource *level, int x, int y, int z, int direction); virtual int cloneTileId(Level *level, int x, int y, int z); diff --git a/Minecraft.World/RedStoneItem.cpp b/Minecraft.World/RedStoneItem.cpp index 64201caa..3d8ee453 100644 --- a/Minecraft.World/RedStoneItem.cpp +++ b/Minecraft.World/RedStoneItem.cpp @@ -23,7 +23,7 @@ bool RedStoneItem::useOn(shared_ptr itemInstance, shared_ptrisEmptyTile(x, y, z)) return false; } - if (!player->mayBuild(x, y, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, itemInstance)) return false; if (Tile::redStoneDust->mayPlace(level, x, y, z)) { if(!bTestUseOnOnly) @@ -32,7 +32,7 @@ bool RedStoneItem::useOn(shared_ptr itemInstance, shared_ptrawardStat(GenericStats::blocksPlaced(Tile::redStoneDust_Id), GenericStats::param_blocksPlaced(Tile::redStoneDust_Id,itemInstance->getAuxValue(),1)); itemInstance->count--; - level->setTile(x, y, z, Tile::redStoneDust_Id); + level->setTileAndUpdate(x, y, z, Tile::redStoneDust_Id); } } diff --git a/Minecraft.World/RedStoneOreTile.cpp b/Minecraft.World/RedStoneOreTile.cpp index 9317ffdd..b7551932 100644 --- a/Minecraft.World/RedStoneOreTile.cpp +++ b/Minecraft.World/RedStoneOreTile.cpp @@ -12,7 +12,7 @@ RedStoneOreTile::RedStoneOreTile(int id, bool lit) : Tile(id, Material::stone) this->lit = lit; } -int RedStoneOreTile::getTickDelay() +int RedStoneOreTile::getTickDelay(Level *level) { return 30; } @@ -32,7 +32,7 @@ void RedStoneOreTile::stepOn(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly/*=false*/) // 4J added soundOnly param @@ -48,7 +48,7 @@ void RedStoneOreTile::interact(Level *level, int x, int y, int z) if (level->isClientSide) return; // 4J added if (id == Tile::redStoneOre_Id) { - level->setTile(x, y, z, Tile::redStoneOre_lit_Id); + level->setTileAndUpdate(x, y, z, Tile::redStoneOre_lit_Id); } } @@ -56,7 +56,7 @@ void RedStoneOreTile::tick(Level *level, int x, int y, int z, Random* random) { if (id == Tile::redStoneOre_lit_Id) { - level->setTile(x, y, z, Tile::redStoneOre_Id); + level->setTileAndUpdate(x, y, z, Tile::redStoneOre_Id); } } @@ -119,7 +119,7 @@ void RedStoneOreTile::poofParticles(Level *level, int x, int y, int z) bool RedStoneOreTile::shouldTileTick(Level *level, int x,int y,int z) { - return id == Tile::redStoneOre_lit_Id; + return id == Tile::redStoneOre_lit_Id; } shared_ptr RedStoneOreTile::getSilkTouchItemInstance(int data) diff --git a/Minecraft.World/RedStoneOreTile.h b/Minecraft.World/RedStoneOreTile.h index bc1d48d7..2ff80ed5 100644 --- a/Minecraft.World/RedStoneOreTile.h +++ b/Minecraft.World/RedStoneOreTile.h @@ -10,21 +10,21 @@ private: bool lit; public: RedStoneOreTile(int id, bool lit); - virtual int getTickDelay(); - virtual void attack(Level *level, int x, int y, int z, shared_ptr player); - virtual void stepOn(Level *level, int x, int y, int z, shared_ptr entity); + virtual int getTickDelay(Level *level); + virtual void attack(Level *level, int x, int y, int z, shared_ptr player); + virtual void stepOn(Level *level, int x, int y, int z, shared_ptr entity); virtual bool TestUse(); - virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param private: virtual void interact(Level *level, int x, int y, int z); public: virtual void tick(Level *level, int x, int y, int z, Random* random); - virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual int getResource(int data, Random *random, int playerBonusLevel); virtual int getResourceCountForLootBonus(int bonusLevel, Random *random); - virtual int getResourceCount(Random *random); + virtual int getResourceCount(Random *random); virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonusLevel); - virtual void animateTick(Level *level, int x, int y, int z, Random *random); - + virtual void animateTick(Level *level, int x, int y, int z, Random *random); + // 4J Added so we can check before we try to add a tile to the tick list if it's actually going to do seomthing virtual bool shouldTileTick(Level *level, int x,int y,int z); private: diff --git a/Minecraft.World/RedlightTile.cpp b/Minecraft.World/RedlightTile.cpp index 2a529c84..bf4cc01f 100644 --- a/Minecraft.World/RedlightTile.cpp +++ b/Minecraft.World/RedlightTile.cpp @@ -36,7 +36,7 @@ void RedlightTile::onPlace(Level *level, int x, int y, int z) } else if (!isLit && level->hasNeighborSignal(x, y, z)) { - level->setTile(x, y, z, Tile::redstoneLight_lit_Id); + level->setTileAndData(x, y, z, Tile::redstoneLight_lit_Id, 0, UPDATE_CLIENTS); } } } @@ -51,7 +51,7 @@ void RedlightTile::neighborChanged(Level *level, int x, int y, int z, int type) } else if (!isLit && level->hasNeighborSignal(x, y, z)) { - level->setTile(x, y, z, Tile::redstoneLight_lit_Id); + level->setTileAndData(x, y, z, Tile::redstoneLight_lit_Id, 0, UPDATE_CLIENTS); } } } @@ -62,7 +62,7 @@ void RedlightTile::tick(Level *level, int x, int y, int z, Random *random) { if (isLit && !level->hasNeighborSignal(x, y, z)) { - level->setTile(x, y, z, Tile::redstoneLight_Id); + level->setTileAndData(x, y, z, Tile::redstoneLight_Id, 0, UPDATE_CLIENTS); } } } diff --git a/Minecraft.World/Redstone.cpp b/Minecraft.World/Redstone.cpp new file mode 100644 index 00000000..62e0d8f2 --- /dev/null +++ b/Minecraft.World/Redstone.cpp @@ -0,0 +1,8 @@ +#include "stdafx.h" + +#include "Redstone.h" + +// 4J-JEV: Because whiny Ps4 compiler. +const int Redstone::SIGNAL_NONE; +const int Redstone::SIGNAL_MIN; +const int Redstone::SIGNAL_MAX; \ No newline at end of file diff --git a/Minecraft.World/Redstone.h b/Minecraft.World/Redstone.h new file mode 100644 index 00000000..0b25e8b7 --- /dev/null +++ b/Minecraft.World/Redstone.h @@ -0,0 +1,9 @@ +#pragma once + +class Redstone +{ +public: + static const int SIGNAL_NONE = 0; + static const int SIGNAL_MIN = 0; + static const int SIGNAL_MAX = 15; +}; \ No newline at end of file diff --git a/Minecraft.World/ReedTile.cpp b/Minecraft.World/ReedTile.cpp index 69596e83..c01eb764 100644 --- a/Minecraft.World/ReedTile.cpp +++ b/Minecraft.World/ReedTile.cpp @@ -33,12 +33,12 @@ void ReedTile::tick(Level *level, int x, int y, int z, Random* random) int age = level->getData(x, y, z); if (age == 15) { - level->setTile(x, y + 1, z, id); - level->setData(x, y, z, 0); + level->setTileAndUpdate(x, y + 1, z, id); + level->setData(x, y, z, 0, Tile::UPDATE_NONE); } else { - level->setData(x, y, z, age + 1); + level->setData(x, y, z, age + 1, Tile::UPDATE_NONE); } } } @@ -66,8 +66,8 @@ const void ReedTile::checkAlive(Level *level, int x, int y, int z) { if (!canSurvive(level, x, y, z)) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); } } @@ -113,5 +113,5 @@ int ReedTile::cloneTileId(Level *level, int x, int y, int z) bool ReedTile::shouldTileTick(Level *level, int x,int y,int z) { - return level->isEmptyTile(x, y + 1, z); + return level->isEmptyTile(x, y + 1, z); } diff --git a/Minecraft.World/ReedsFeature.cpp b/Minecraft.World/ReedsFeature.cpp index 6d4f3e97..2792b21b 100644 --- a/Minecraft.World/ReedsFeature.cpp +++ b/Minecraft.World/ReedsFeature.cpp @@ -5,11 +5,11 @@ bool ReedsFeature::place(Level *level, Random *random, int x, int y, int z) { - for (int i = 0; i < 20; i++) + for (int i = 0; i < 20; i++) { - int x2 = x + random->nextInt(4) - random->nextInt(4); - int y2 = y; - int z2 = z + random->nextInt(4) - random->nextInt(4); + int x2 = x + random->nextInt(4) - random->nextInt(4); + int y2 = y; + int z2 = z + random->nextInt(4) - random->nextInt(4); // 4J Stu Added to stop reed features generating areas previously place by game rule generation if(app.getLevelGenerationOptions() != NULL) @@ -22,25 +22,25 @@ bool ReedsFeature::place(Level *level, Random *random, int x, int y, int z) continue; } } - if (level->isEmptyTile(x2, y2, z2)) + if (level->isEmptyTile(x2, y2, z2)) { - if (level->getMaterial(x2-1, y2-1, z2) == Material::water || - level->getMaterial(x2+1, y2-1, z2) == Material::water || - level->getMaterial(x2, y2-1, z2-1) == Material::water || - level->getMaterial(x2, y2-1, z2+1) == Material::water) + if (level->getMaterial(x2-1, y2-1, z2) == Material::water || + level->getMaterial(x2+1, y2-1, z2) == Material::water || + level->getMaterial(x2, y2-1, z2-1) == Material::water || + level->getMaterial(x2, y2-1, z2+1) == Material::water) { - int h = 2 + random->nextInt(random->nextInt(3) + 1); - for (int yy = 0; yy < h; yy++) + int h = 2 + random->nextInt(random->nextInt(3) + 1); + for (int yy = 0; yy < h; yy++) { - if ( Tile::reeds->canSurvive(level, x2, y2 + yy, z2) ) + if ( Tile::reeds->canSurvive(level, x2, y2 + yy, z2) ) { - level->setTileNoUpdate(x2, y2 + yy, z2, Tile::reeds_Id); - } - } - } - } - } + level->setTileAndData(x2, y2 + yy, z2, Tile::reeds_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } + } + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/Region.cpp b/Minecraft.World/Region.cpp index 4c3a454d..e3e91bf0 100644 --- a/Minecraft.World/Region.cpp +++ b/Minecraft.World/Region.cpp @@ -3,6 +3,7 @@ #include "net.minecraft.world.level.chunk.h" #include "net.minecraft.world.level.dimension.h" #include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.redstone.h" #include "Material.h" #include "Level.h" @@ -27,14 +28,14 @@ Region::~Region() } } -Region::Region(Level *level, int x1, int y1, int z1, int x2, int y2, int z2) +Region::Region(Level *level, int x1, int y1, int z1, int x2, int y2, int z2, int r) { this->level = level; - xc1 = x1 >> 4; - zc1 = z1 >> 4; - int xc2 = x2 >> 4; - int zc2 = z2 >> 4; + xc1 = (x1 - r) >> 4; + zc1 = (z1 - r) >> 4; + int xc2 = (x2 + r) >> 4; + int zc2 = (z2 + r) >> 4; chunks = new LevelChunk2DArray(xc2 - xc1 + 1, zc2 - zc1 + 1); @@ -48,7 +49,17 @@ Region::Region(Level *level, int x1, int y1, int z1, int x2, int y2, int z2) { LevelChunkArray *lca = (*chunks)[xc - xc1]; lca->data[zc - zc1] = chunk; - //(*chunks)[xc - xc1].data[zc - zc1] = level->getChunk(xc, zc); + } + } + } + for (int xc = (x1 >> 4); xc <= (x2 >> 4); xc++) + { + for (int zc = (z1 >> 4); zc <= (z2 >> 4); zc++) + { + LevelChunkArray *lca = (*chunks)[xc - xc1]; + LevelChunk *chunk = lca->data[zc - zc1]; + if (chunk != NULL) + { if (!chunk->isYSpaceEmpty(y1, y2)) { allEmpty = false; @@ -147,10 +158,10 @@ shared_ptr Region::getTileEntity(int x, int y, int z) int Region::getLightColor(int x, int y, int z, int emitt, int tileId/*=-1*/) { - int s = getBrightnessPropagate(LightLayer::Sky, x, y, z, tileId); - int b = getBrightnessPropagate(LightLayer::Block, x, y, z, tileId); - if (b < emitt) b = emitt; - return s << 20 | b << 4; + int s = getBrightnessPropagate(LightLayer::Sky, x, y, z, tileId); + int b = getBrightnessPropagate(LightLayer::Block, x, y, z, tileId); + if (b < emitt) b = emitt; + return s << 20 | b << 4; } float Region::getBrightness(int x, int y, int z, int emitt) @@ -289,14 +300,8 @@ bool Region::isSolidBlockingTile(int x, int y, int z) bool Region::isTopSolidBlocking(int x, int y, int z) { - // Temporary workaround until tahgs per-face solidity is finished Tile *tile = Tile::tiles[getTile(x, y, z)]; - if (tile == NULL) return false; - - if (tile->material->isSolidBlocking() && tile->isCubeShaped()) return true; - if (dynamic_cast(tile)) return (getData(x, y, z) & StairTile::UPSIDEDOWN_BIT) == StairTile::UPSIDEDOWN_BIT; - if (dynamic_cast(tile)) return (getData(x, y, z) & HalfSlabTile::TOP_SLOT_BIT) == HalfSlabTile::TOP_SLOT_BIT; - return false; + return level->isTopSolidBlocking(tile, getData(x, y, z)); } bool Region::isEmptyTile(int x, int y, int z) @@ -309,15 +314,19 @@ bool Region::isEmptyTile(int x, int y, int z) // 4J - brought forward from 1.8.2 int Region::getBrightnessPropagate(LightLayer::variety layer, int x, int y, int z, int tileId) { - if (y < 0) y = 0; + if (y < 0) y = 0; if (y >= Level::maxBuildHeight) y = Level::maxBuildHeight - 1; - if (y < 0 || y >= Level::maxBuildHeight || x < -Level::MAX_LEVEL_SIZE || z < -Level::MAX_LEVEL_SIZE || x >= Level::MAX_LEVEL_SIZE || z > Level::MAX_LEVEL_SIZE) + if (y < 0 || y >= Level::maxBuildHeight || x < -Level::MAX_LEVEL_SIZE || z < -Level::MAX_LEVEL_SIZE || x >= Level::MAX_LEVEL_SIZE || z > Level::MAX_LEVEL_SIZE) { // 4J Stu - The java LightLayer was an enum class type with a member "surrounding" which is what we // were returning here. Surrounding has the same value as the enum value in our C++ code, so just cast // it to an int return (int)layer; - } + } + if (layer == LightLayer::Sky && level->dimension->hasCeiling) + { + return 0; + } int id = tileId > -1 ? tileId : getTile(x, y, z); if (Tile::propagate[id]) @@ -334,31 +343,38 @@ int Region::getBrightnessPropagate(LightLayer::variety layer, int x, int y, int return br; } - int xc = (x >> 4) - xc1; - int zc = (z >> 4) - zc1; + int xc = (x >> 4) - xc1; + int zc = (z >> 4) - zc1; - return (*chunks)[xc]->data[zc]->getBrightness(layer, x & 15, y, z & 15); + return (*chunks)[xc]->data[zc]->getBrightness(layer, x & 15, y, z & 15); } // 4J - brought forward from 1.8.2 int Region::getBrightness(LightLayer::variety layer, int x, int y, int z) { - if (y < 0) y = 0; - if (y >= Level::maxBuildHeight) y = Level::maxBuildHeight - 1; - if (y < 0 || y >= Level::maxBuildHeight || x < -Level::MAX_LEVEL_SIZE || z < -Level::MAX_LEVEL_SIZE || x >= Level::MAX_LEVEL_SIZE || z > Level::MAX_LEVEL_SIZE) + if (y < 0) y = 0; + if (y >= Level::maxBuildHeight) y = Level::maxBuildHeight - 1; + if (y < 0 || y >= Level::maxBuildHeight || x < -Level::MAX_LEVEL_SIZE || z < -Level::MAX_LEVEL_SIZE || x >= Level::MAX_LEVEL_SIZE || z > Level::MAX_LEVEL_SIZE) { // 4J Stu - The java LightLayer was an enum class type with a member "surrounding" which is what we // were returning here. Surrounding has the same value as the enum value in our C++ code, so just cast // it to an int return (int)layer; - } - int xc = (x >> 4) - xc1; - int zc = (z >> 4) - zc1; + } + int xc = (x >> 4) - xc1; + int zc = (z >> 4) - zc1; - return (*chunks)[xc]->data[zc]->getBrightness(layer, x & 15, y, z & 15); + return (*chunks)[xc]->data[zc]->getBrightness(layer, x & 15, y, z & 15); } int Region::getMaxBuildHeight() { return Level::maxBuildHeight; +} + +int Region::getDirectSignal(int x, int y, int z, int dir) +{ + int t = getTile(x, y, z); + if (t == 0) return Redstone::SIGNAL_NONE; + return Tile::tiles[t]->getDirectSignal(this, x, y, z, dir); } \ No newline at end of file diff --git a/Minecraft.World/Region.h b/Minecraft.World/Region.h index 0d200a35..7d6cdc11 100644 --- a/Minecraft.World/Region.h +++ b/Minecraft.World/Region.h @@ -19,7 +19,7 @@ private: unsigned char *CachedTiles; public: - Region(Level *level, int x1, int y1, int z1, int x2, int y2, int z2); + Region(Level *level, int x1, int y1, int z1, int x2, int y2, int z2, int r); virtual ~Region(); bool isAllEmpty(); int getTile(int x, int y, int z); @@ -43,6 +43,7 @@ public: int getBrightness(LightLayer::variety layer, int x, int y, int z); int getMaxBuildHeight(); + int getDirectSignal(int x, int y, int z, int dir); LevelChunk* getLevelChunk(int x, int y, int z); diff --git a/Minecraft.World/RegionFileCache.cpp b/Minecraft.World/RegionFileCache.cpp index c21a6250..23c87118 100644 --- a/Minecraft.World/RegionFileCache.cpp +++ b/Minecraft.World/RegionFileCache.cpp @@ -120,3 +120,9 @@ DataOutputStream *RegionFileCache::_getChunkDataOutputStream(ConsoleSaveFile *sa return r->getChunkDataOutputStream(chunkX & 31, chunkZ & 31); } } + + +RegionFileCache::~RegionFileCache() +{ + _clear(); +} diff --git a/Minecraft.World/RegionFileCache.h b/Minecraft.World/RegionFileCache.h index 03e576cc..cef71d90 100644 --- a/Minecraft.World/RegionFileCache.h +++ b/Minecraft.World/RegionFileCache.h @@ -16,6 +16,7 @@ private: public: // Made public and non-static so we can have a cache for input and output files RegionFileCache() {} + ~RegionFileCache(); RegionFile *_getRegionFile(ConsoleSaveFile *saveFile, const wstring &prefix, int chunkX, int chunkZ); // 4J - TODO was synchronized void _clear(); // 4J - TODO was synchronized diff --git a/Minecraft.World/RepairContainer.cpp b/Minecraft.World/RepairContainer.cpp index 7b2a51bc..2ada97a6 100644 --- a/Minecraft.World/RepairContainer.cpp +++ b/Minecraft.World/RepairContainer.cpp @@ -1,8 +1,8 @@ #include "stdafx.h" -#include "RepairMenu.h" +#include "AnvilMenu.h" #include "RepairContainer.h" -RepairContainer::RepairContainer(RepairMenu *menu, int name, int size) : SimpleContainer(name, size) +RepairContainer::RepairContainer(AnvilMenu *menu, int name, bool customName, int size) : SimpleContainer(name, L"", customName, size) { m_menu = menu; } @@ -11,4 +11,9 @@ void RepairContainer::setChanged() { SimpleContainer::setChanged(); m_menu->slotsChanged(shared_from_this()); +} + +bool RepairContainer::canPlaceItem(int slot, shared_ptr item) +{ + return true; } \ No newline at end of file diff --git a/Minecraft.World/RepairContainer.h b/Minecraft.World/RepairContainer.h index 758132c0..a4311c52 100644 --- a/Minecraft.World/RepairContainer.h +++ b/Minecraft.World/RepairContainer.h @@ -2,14 +2,15 @@ #include "SimpleContainer.h" -class RepairMenu; +class AnvilMenu; class RepairContainer : public SimpleContainer, public enable_shared_from_this { private: - RepairMenu *m_menu; + AnvilMenu *m_menu; public: - RepairContainer(RepairMenu *menu, int name, int size); + RepairContainer(AnvilMenu *menu, int name, bool customName, int size); void setChanged(); + bool canPlaceItem(int slot, shared_ptr item); }; \ No newline at end of file diff --git a/Minecraft.World/RepairResultSlot.cpp b/Minecraft.World/RepairResultSlot.cpp index 041a64a7..51e95b42 100644 --- a/Minecraft.World/RepairResultSlot.cpp +++ b/Minecraft.World/RepairResultSlot.cpp @@ -5,7 +5,7 @@ #include "net.minecraft.world.entity.player.h" #include "RepairResultSlot.h" -RepairResultSlot::RepairResultSlot(RepairMenu *menu, int xt, int yt, int zt, shared_ptr container, int slot, int x, int y) : Slot(container, slot, x, y) +RepairResultSlot::RepairResultSlot(AnvilMenu *menu, int xt, int yt, int zt, shared_ptr container, int slot, int x, int y) : Slot(container, slot, x, y) { m_menu = menu; this->xt = xt; @@ -25,24 +25,24 @@ bool RepairResultSlot::mayPickup(shared_ptr player) void RepairResultSlot::onTake(shared_ptr player, shared_ptr carried) { - if (!player->abilities.instabuild) player->withdrawExperienceLevels(m_menu->cost); - m_menu->repairSlots->setItem(RepairMenu::INPUT_SLOT, nullptr); + if (!player->abilities.instabuild) player->giveExperienceLevels(-m_menu->cost); + m_menu->repairSlots->setItem(AnvilMenu::INPUT_SLOT, nullptr); if (m_menu->repairItemCountCost > 0) { - shared_ptr addition = m_menu->repairSlots->getItem(RepairMenu::ADDITIONAL_SLOT); + shared_ptr addition = m_menu->repairSlots->getItem(AnvilMenu::ADDITIONAL_SLOT); if (addition != NULL && addition->count > m_menu->repairItemCountCost) { addition->count -= m_menu->repairItemCountCost; - m_menu->repairSlots->setItem(RepairMenu::ADDITIONAL_SLOT, addition); + m_menu->repairSlots->setItem(AnvilMenu::ADDITIONAL_SLOT, addition); } else { - m_menu->repairSlots->setItem(RepairMenu::ADDITIONAL_SLOT, nullptr); + m_menu->repairSlots->setItem(AnvilMenu::ADDITIONAL_SLOT, nullptr); } } else { - m_menu->repairSlots->setItem(RepairMenu::ADDITIONAL_SLOT, nullptr); + m_menu->repairSlots->setItem(AnvilMenu::ADDITIONAL_SLOT, nullptr); } m_menu->cost = 0; @@ -54,12 +54,12 @@ void RepairResultSlot::onTake(shared_ptr player, shared_ptr 2) { - m_menu->level->setTile(xt, yt, zt, 0); + m_menu->level->removeTile(xt, yt, zt); m_menu->level->levelEvent(LevelEvent::SOUND_ANVIL_BROKEN, xt, yt, zt, 0); } else { - m_menu->level->setData(xt, yt, zt, dir | (dmg << 2)); + m_menu->level->setData(xt, yt, zt, dir | (dmg << 2), Tile::UPDATE_CLIENTS); m_menu->level->levelEvent(LevelEvent::SOUND_ANVIL_USED, xt, yt, zt, 0); } } diff --git a/Minecraft.World/RepairResultSlot.h b/Minecraft.World/RepairResultSlot.h index 1895ca30..b7583569 100644 --- a/Minecraft.World/RepairResultSlot.h +++ b/Minecraft.World/RepairResultSlot.h @@ -2,16 +2,16 @@ #include "Slot.h" -class RepairMenu; +class AnvilMenu; class RepairResultSlot : public Slot { private: - RepairMenu *m_menu; + AnvilMenu *m_menu; int xt, yt, zt; public: - RepairResultSlot(RepairMenu *menu, int xt, int yt, int zt, shared_ptr container, int slot, int x, int y); + RepairResultSlot(AnvilMenu *menu, int xt, int yt, int zt, shared_ptr container, int slot, int x, int y); bool mayPlace(shared_ptr item); bool mayPickup(shared_ptr player); diff --git a/Minecraft.World/RepeaterTile.cpp b/Minecraft.World/RepeaterTile.cpp new file mode 100644 index 00000000..23a9e12f --- /dev/null +++ b/Minecraft.World/RepeaterTile.cpp @@ -0,0 +1,132 @@ +#include "stdafx.h" +#include "net.minecraft.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" +#include "RepeaterTile.h" + +const double RepeaterTile::DELAY_RENDER_OFFSETS[4] = {-1.0f / 16.0f, 1.0f / 16.0f, 3.0f / 16.0f, 5.0f / 16.0f}; +const int RepeaterTile::DELAYS[4]= {1, 2, 3, 4}; + +RepeaterTile::RepeaterTile(int id, bool on) : DiodeTile(id, on) +{ +} + +bool RepeaterTile::use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly) +{ + if (soundOnly) return false; + + int data = level->getData(x, y, z); + int delay = (data & DELAY_MASK) >> DELAY_SHIFT; + delay = ((delay + 1) << DELAY_SHIFT) & DELAY_MASK; + + level->setData(x, y, z, delay | (data & DIRECTION_MASK), Tile::UPDATE_ALL); + return true; +} + +int RepeaterTile::getTurnOnDelay(int data) +{ + return DELAYS[(data & DELAY_MASK) >> DELAY_SHIFT] * 2; +} + +DiodeTile *RepeaterTile::getOnTile() +{ + return Tile::diode_on; +} + +DiodeTile *RepeaterTile::getOffTile() +{ + return Tile::diode_off; +} + +int RepeaterTile::getResource(int data, Random *random, int playerBonusLevel) +{ + return Item::repeater_Id; +} + +int RepeaterTile::cloneTileId(Level *level, int x, int y, int z) +{ + return Item::repeater_Id; +} + +int RepeaterTile::getRenderShape() +{ + return SHAPE_REPEATER; +} + +bool RepeaterTile::isLocked(LevelSource *level, int x, int y, int z, int data) +{ + return getAlternateSignal(level, x, y, z, data) > Redstone::SIGNAL_NONE; +} + +bool RepeaterTile::isAlternateInput(int tile) +{ + return isDiode(tile); +} + +void RepeaterTile::animateTick(Level *level, int xt, int yt, int zt, Random *random) +{ + if (!on) return; + int data = level->getData(xt, yt, zt); + int dir = getDirection(data); + + double x = xt + 0.5f + (random->nextFloat() - 0.5f) * 0.2; + double y = yt + 0.4f + (random->nextFloat() - 0.5f) * 0.2; + double z = zt + 0.5f + (random->nextFloat() - 0.5f) * 0.2; + + double xo = 0; + double zo = 0; + + if (random->nextInt(2) == 0) + { + // spawn on receiver + switch (dir) + { + case Direction::SOUTH: + zo = -5.0f / 16.0f; + break; + case Direction::NORTH: + zo = 5.0f / 16.0f; + break; + case Direction::EAST: + xo = -5.0f / 16.0f; + break; + case Direction::WEST: + xo = 5.0f / 16.0f; + break; + } + } + else + { + // spawn on transmitter + int delay = (data & DELAY_MASK) >> DELAY_SHIFT; + switch (dir) + { + case Direction::SOUTH: + zo = DELAY_RENDER_OFFSETS[delay]; + break; + case Direction::NORTH: + zo = -DELAY_RENDER_OFFSETS[delay]; + break; + case Direction::EAST: + xo = DELAY_RENDER_OFFSETS[delay]; + break; + case Direction::WEST: + xo = -DELAY_RENDER_OFFSETS[delay]; + break; + } + } + + level->addParticle(eParticleType_reddust, x + xo, y, z + zo, 0, 0, 0); +} + +void RepeaterTile::onRemove(Level *level, int x, int y, int z, int id, int data) +{ + DiodeTile::onRemove(level, x, y, z, id, data); + updateNeighborsInFront(level, x, y, z); +} + +bool RepeaterTile::TestUse() +{ + return true; +} \ No newline at end of file diff --git a/Minecraft.World/RepeaterTile.h b/Minecraft.World/RepeaterTile.h new file mode 100644 index 00000000..048e4de0 --- /dev/null +++ b/Minecraft.World/RepeaterTile.h @@ -0,0 +1,40 @@ +#pragma once + +#include "DiodeTile.h" + +class RepeaterTile : public DiodeTile +{ +public: + static const int DELAY_MASK = DIRECTION_INV_MASK; + static const int DELAY_SHIFT = 2; + + static const double DELAY_RENDER_OFFSETS[4]; + +private: + static const int DELAYS[4]; + +public: + RepeaterTile(int id, bool on); + + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); + +protected: + virtual int getTurnOnDelay(int data); + virtual DiodeTile *getOnTile(); + virtual DiodeTile *getOffTile(); + +public: + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual int cloneTileId(Level *level, int x, int y, int z); + virtual int getRenderShape(); + virtual bool isLocked(LevelSource *level, int x, int y, int z, int data); + +protected: + virtual bool isAlternateInput(int tile); + +public: + void animateTick(Level *level, int xt, int yt, int zt, Random *random); + void onRemove(Level *level, int x, int y, int z, int id, int data); + + virtual bool TestUse(); +}; \ No newline at end of file diff --git a/Minecraft.World/ResultContainer.cpp b/Minecraft.World/ResultContainer.cpp index c28b3cf3..f2f273c2 100644 --- a/Minecraft.World/ResultContainer.cpp +++ b/Minecraft.World/ResultContainer.cpp @@ -4,7 +4,6 @@ ResultContainer::ResultContainer() : Container() { - items = new ItemInstanceArray(1); } unsigned int ResultContainer::getContainerSize() @@ -14,20 +13,30 @@ unsigned int ResultContainer::getContainerSize() shared_ptr ResultContainer::getItem(unsigned int slot) { - return (*items)[0]; + return items[0]; } -int ResultContainer::getName() +wstring ResultContainer::getName() { - return 0; + return L""; +} + +wstring ResultContainer::getCustomName() +{ + return L""; +} + +bool ResultContainer::hasCustomName() +{ + return false; } shared_ptr ResultContainer::removeItem(unsigned int slot, int count) { - if ((*items)[0] != NULL) + if (items[0] != NULL) { - shared_ptr item = (*items)[0]; - (*items)[0] = nullptr; + shared_ptr item = items[0]; + items[0] = nullptr; return item; } return nullptr; @@ -35,10 +44,10 @@ shared_ptr ResultContainer::removeItem(unsigned int slot, int coun shared_ptr ResultContainer::removeItemNoUpdate(int slot) { - if ((*items)[0] != NULL) + if (items[0] != NULL) { - shared_ptr item = (*items)[0]; - (*items)[0] = nullptr; + shared_ptr item = items[0]; + items[0] = nullptr; return item; } return nullptr; @@ -46,7 +55,7 @@ shared_ptr ResultContainer::removeItemNoUpdate(int slot) void ResultContainer::setItem(unsigned int slot, shared_ptr item) { - (*items)[0] = item; + items[0] = item; } int ResultContainer::getMaxStackSize() @@ -59,6 +68,11 @@ void ResultContainer::setChanged() } bool ResultContainer::stillValid(shared_ptr player) +{ + return true; +} + +bool ResultContainer::canPlaceItem(int slot, shared_ptr item) { return true; } \ No newline at end of file diff --git a/Minecraft.World/ResultContainer.h b/Minecraft.World/ResultContainer.h index 62df65d8..f99cf806 100644 --- a/Minecraft.World/ResultContainer.h +++ b/Minecraft.World/ResultContainer.h @@ -5,7 +5,7 @@ class ResultContainer : public Container { private: - ItemInstanceArray *items; + shared_ptr items[1]; public: // 4J Stu Added a ctor to init items @@ -13,14 +13,16 @@ public: virtual unsigned int getContainerSize(); virtual shared_ptr getItem(unsigned int slot); - virtual int getName(); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual bool hasCustomName(); virtual shared_ptr removeItem(unsigned int slot, int count); virtual shared_ptr removeItemNoUpdate(int slot); virtual void setItem(unsigned int slot, shared_ptr item); virtual int getMaxStackSize(); virtual void setChanged(); virtual bool stillValid(shared_ptr player); - - void startOpen() { } // TODO Auto-generated method stub - void stopOpen() { } // TODO Auto-generated method stub + virtual void startOpen() { } // TODO Auto-generated method stub + virtual void stopOpen() { } // TODO Auto-generated method stub + virtual bool canPlaceItem(int slot, shared_ptr item); }; \ No newline at end of file diff --git a/Minecraft.World/ResultSlot.cpp b/Minecraft.World/ResultSlot.cpp index b79329af..08ffe714 100644 --- a/Minecraft.World/ResultSlot.cpp +++ b/Minecraft.World/ResultSlot.cpp @@ -66,21 +66,17 @@ void ResultSlot::onTake(shared_ptr player, shared_ptr carr if (item->getItem()->hasCraftingRemainingItem()) { - - // (TheApathetic) shared_ptr craftResult = shared_ptr(new ItemInstance(item->getItem()->getCraftingRemainingItem())); /* - * Try to place this in the player's inventory (See we.java - * for new method) + * Try to place this in the player's inventory (See we.java for new method) */ - if (item->getItem()->shouldMoveCraftingResultToInventory(item) && this->player->inventory->add(craftResult)) + if (item->getItem()->shouldMoveCraftingResultToInventory(item) && player->inventory->add(craftResult)) { continue; } - // If this slot is now empty, place it there (current - // behavior) + // If this slot is now empty, place it there (current behavior) if (craftSlots->getItem(i) == NULL) { craftSlots->setItem(i, craftResult); @@ -88,7 +84,7 @@ void ResultSlot::onTake(shared_ptr player, shared_ptr carr else { // Finally, if nothing else, just drop the item - this->player->drop(craftResult); + player->drop(craftResult); } } diff --git a/Minecraft.World/RotatedPillarTile.cpp b/Minecraft.World/RotatedPillarTile.cpp new file mode 100644 index 00000000..a4b7d931 --- /dev/null +++ b/Minecraft.World/RotatedPillarTile.cpp @@ -0,0 +1,77 @@ +#include "stdafx.h" +#include "net.minecraft.h" +#include "RotatedPillarTile.h" + +RotatedPillarTile::RotatedPillarTile(int id, Material *material) : Tile(id, material) +{ +} + +int RotatedPillarTile::getRenderShape() +{ + return Tile::SHAPE_TREE; +} + +int RotatedPillarTile::getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) +{ + int type = itemValue & MASK_TYPE; + int facing = 0; + + switch (face) + { + case Facing::NORTH: + case Facing::SOUTH: + facing = FACING_Z; + break; + case Facing::EAST: + case Facing::WEST: + facing = FACING_X; + break; + case Facing::UP: + case Facing::DOWN: + facing = FACING_Y; + break; + } + + return type | facing; +} + +Icon *RotatedPillarTile::getTexture(int face, int data) +{ + int dir = data & MASK_FACING; + int type = data & MASK_TYPE; + + if (dir == FACING_Y && (face == Facing::UP || face == Facing::DOWN)) + { + return getTopTexture(type); + } + else if (dir == FACING_X && (face == Facing::EAST || face == Facing::WEST)) + { + return getTopTexture(type); + } + else if (dir == FACING_Z && (face == Facing::NORTH || face == Facing::SOUTH)) + { + return getTopTexture(type); + } + + return getTypeTexture(type); +} + +Icon *RotatedPillarTile::getTopTexture(int type) +{ + return iconTop; +} + +int RotatedPillarTile::getSpawnResourcesAuxValue(int data) +{ + return data & MASK_TYPE; +} + +int RotatedPillarTile::getType(int data) +{ + return data & MASK_TYPE; +} + +shared_ptr RotatedPillarTile::getSilkTouchItemInstance(int data) +{ + return shared_ptr( new ItemInstance(id, 1, getType(data)) ); +} \ No newline at end of file diff --git a/Minecraft.World/RotatedPillarTile.h b/Minecraft.World/RotatedPillarTile.h new file mode 100644 index 00000000..76e52997 --- /dev/null +++ b/Minecraft.World/RotatedPillarTile.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Tile.h" + +class RotatedPillarTile : public Tile +{ +public: + static const int MASK_TYPE = 0x3; + static const int MASK_FACING = 0xC; + static const int FACING_Y = 0 << 2; + static const int FACING_X = 1 << 2; + static const int FACING_Z = 2 << 2; + +protected: + Icon *iconTop; + + RotatedPillarTile(int id, Material *material); + +public: + virtual int getRenderShape(); + virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); + virtual Icon *getTexture(int face, int data); + +protected: + virtual Icon *getTypeTexture(int type) = 0; + + virtual Icon *getTopTexture(int type); + +public: + virtual int getSpawnResourcesAuxValue(int data); + virtual int getType(int data); + +protected: + virtual shared_ptr getSilkTouchItemInstance(int data); +}; \ No newline at end of file diff --git a/Minecraft.World/RunAroundLikeCrazyGoal.cpp b/Minecraft.World/RunAroundLikeCrazyGoal.cpp new file mode 100644 index 00000000..118b09f9 --- /dev/null +++ b/Minecraft.World/RunAroundLikeCrazyGoal.cpp @@ -0,0 +1,62 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.control.h" +#include "net.minecraft.world.entity.animal.h" +#include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.h" +#include "RandomPos.h" +#include "RunAroundLikeCrazyGoal.h" + +RunAroundLikeCrazyGoal::RunAroundLikeCrazyGoal(EntityHorse *mob, double speedModifier) +{ + horse = mob; + this->speedModifier = speedModifier; + setRequiredControlFlags(Control::MoveControlFlag); +} + +bool RunAroundLikeCrazyGoal::canUse() +{ + if (horse->isTamed() || horse->rider.lock() == NULL) return false; + Vec3 *pos = RandomPos::getPos(dynamic_pointer_cast(horse->shared_from_this()), 5, 4); + if (pos == NULL) return false; + posX = pos->x; + posY = pos->y; + posZ = pos->z; + return true; +} + +void RunAroundLikeCrazyGoal::start() +{ + horse->getNavigation()->moveTo(posX, posY, posZ, speedModifier); +} + +bool RunAroundLikeCrazyGoal::canContinueToUse() +{ + return !horse->getNavigation()->isDone() && horse->rider.lock() != NULL; +} + +void RunAroundLikeCrazyGoal::tick() +{ + if (horse->getRandom()->nextInt(50) == 0) + { + + if ( horse->rider.lock()->instanceof(eTYPE_PLAYER) ) + { + int temper = horse->getTemper(); + int maxTemper = horse->getMaxTemper(); + if (maxTemper > 0 && horse->getRandom()->nextInt(maxTemper) < temper) + { + horse->tameWithName(dynamic_pointer_cast(horse->rider.lock())); + horse->level->broadcastEntityEvent(horse->shared_from_this(), EntityEvent::TAMING_SUCCEEDED); + return; + } + horse->modifyTemper(5); + } + + horse->rider.lock()->ride(nullptr); + horse->rider = weak_ptr(); + horse->makeMad(); + horse->level->broadcastEntityEvent(horse->shared_from_this(), EntityEvent::TAMING_FAILED); + } +} \ No newline at end of file diff --git a/Minecraft.World/RunAroundLikeCrazyGoal.h b/Minecraft.World/RunAroundLikeCrazyGoal.h new file mode 100644 index 00000000..f895186a --- /dev/null +++ b/Minecraft.World/RunAroundLikeCrazyGoal.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Goal.h" + +class EntityHorse; + +class RunAroundLikeCrazyGoal : public Goal +{ +private: + EntityHorse *horse; // Owner + double speedModifier; + double posX, posY, posZ; + +public: + RunAroundLikeCrazyGoal(EntityHorse *mob, double speedModifier); + + bool canUse(); + void start(); + bool canContinueToUse(); + void tick(); +}; \ No newline at end of file diff --git a/Minecraft.World/SaddleItem.cpp b/Minecraft.World/SaddleItem.cpp index 0effeb53..f982b751 100644 --- a/Minecraft.World/SaddleItem.cpp +++ b/Minecraft.World/SaddleItem.cpp @@ -6,26 +6,26 @@ SaddleItem::SaddleItem(int id) : Item(id) { - maxStackSize = 1; + maxStackSize = 1; } -bool SaddleItem::interactEnemy(shared_ptr itemInstance, shared_ptr mob) +bool SaddleItem::interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr mob) { - if ( dynamic_pointer_cast(mob) ) + if ( (mob != NULL) && mob->instanceof(eTYPE_PIG) ) { - shared_ptr pig = dynamic_pointer_cast(mob); - if (!pig->hasSaddle() && !pig->isBaby()) + shared_ptr pig = dynamic_pointer_cast(mob); + if (!pig->hasSaddle() && !pig->isBaby()) { - pig->setSaddle(true); - itemInstance->count--; - } + pig->setSaddle(true); + itemInstance->count--; + } return true; - } + } return false; } -bool SaddleItem::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) +bool SaddleItem::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) { - interactEnemy(itemInstance, mob); - return true; + interactEnemy(itemInstance, nullptr, mob); + return true; } \ No newline at end of file diff --git a/Minecraft.World/SaddleItem.h b/Minecraft.World/SaddleItem.h index 129922db..424eecd5 100644 --- a/Minecraft.World/SaddleItem.h +++ b/Minecraft.World/SaddleItem.h @@ -8,6 +8,6 @@ class SaddleItem : public Item public: SaddleItem(int id); - virtual bool interactEnemy(shared_ptr itemInstance, shared_ptr mob); - virtual bool hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker); + virtual bool interactEnemy(shared_ptr itemInstance, shared_ptr player, shared_ptr mob); + virtual bool hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker); }; \ No newline at end of file diff --git a/Minecraft.World/SandFeature.cpp b/Minecraft.World/SandFeature.cpp index b678e290..122264ff 100644 --- a/Minecraft.World/SandFeature.cpp +++ b/Minecraft.World/SandFeature.cpp @@ -5,21 +5,21 @@ SandFeature::SandFeature(int radius, int tile) { - this->tile = tile; - this->radius = radius; + this->tile = tile; + this->radius = radius; } bool SandFeature::place(Level *level, Random *random, int x, int y, int z) { - if (level->getMaterial(x, y, z) != Material::water) return false; + if (level->getMaterial(x, y, z) != Material::water) return false; // 4J - optimisation. Without this, we can end up creating a huge number of HeavyTiles to be ticked // a few frames away. I think instatick ought to be fine here - we're only turning rock into gravel, // so should instantly know if we've made a rock with nothing underneath and that should fall. level->setInstaTick(true); - int r = random->nextInt(radius-2)+2; - int yr = 2; + int r = random->nextInt(radius-2)+2; + int yr = 2; // 4J Stu Added to stop tree features generating areas previously place by game rule generation if(app.getLevelGenerationOptions() != NULL) @@ -34,25 +34,25 @@ bool SandFeature::place(Level *level, Random *random, int x, int y, int z) } } - for (int xx = x - r; xx <= x + r; xx++) + for (int xx = x - r; xx <= x + r; xx++) { - for (int zz = z - r; zz <= z + r; zz++) + for (int zz = z - r; zz <= z + r; zz++) { - int xd = xx - x; - int zd = zz - z; - if (xd * xd + zd * zd > r * r) continue; - for (int yy = y - yr; yy <= y + yr; yy++) + int xd = xx - x; + int zd = zz - z; + if (xd * xd + zd * zd > r * r) continue; + for (int yy = y - yr; yy <= y + yr; yy++) { - int t = level->getTile(xx, yy, zz); - if (t == Tile::dirt_Id || t == Tile::grass_Id) + int t = level->getTile(xx, yy, zz); + if (t == Tile::dirt_Id || t == Tile::grass_Id) { - level->setTileNoUpdate(xx, yy, zz, tile); - } - } - } - } + level->setTileAndData(xx, yy, zz, tile, 0, Tile::UPDATE_CLIENTS); + } + } + } + } level->setInstaTick(false); - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/Sapling.cpp b/Minecraft.World/Sapling.cpp index 42bd53ee..85fcea98 100644 --- a/Minecraft.World/Sapling.cpp +++ b/Minecraft.World/Sapling.cpp @@ -6,11 +6,11 @@ #include "Sapling.h" -const unsigned int Sapling::SAPLING_NAMES[SAPLING_NAMES_SIZE] = { IDS_TILE_SAPLING_OAK, - IDS_TILE_SAPLING_SPRUCE, - IDS_TILE_SAPLING_BIRCH, - IDS_TILE_SAPLING_JUNGLE - }; +int Sapling::SAPLING_NAMES[SAPLING_NAMES_SIZE] = { IDS_TILE_SAPLING_OAK, + IDS_TILE_SAPLING_SPRUCE, + IDS_TILE_SAPLING_BIRCH, + IDS_TILE_SAPLING_JUNGLE +}; const wstring Sapling::TEXTURE_NAMES[] = {L"sapling", L"sapling_spruce", L"sapling_birch", L"sapling_jungle"}; @@ -37,15 +37,7 @@ void Sapling::tick(Level *level, int x, int y, int z, Random *random) { if (random->nextInt(7) == 0) { - int data = level->getData(x, y, z); - if ((data & AGE_BIT) == 0) - { - level->setData(x, y, z, data | AGE_BIT); - } - else - { - growTree(level, x, y, z, random); - } + advanceTree(level, x, y, z, random); } } } @@ -56,6 +48,19 @@ Icon *Sapling::getTexture(int face, int data) return icons[data]; } +void Sapling::advanceTree(Level *level, int x, int y, int z, Random *random) +{ + int data = level->getData(x, y, z); + if ((data & AGE_BIT) == 0) + { + level->setData(x, y, z, data | AGE_BIT, Tile::UPDATE_NONE); + } + else + { + growTree(level, x, y, z, random); + } +} + void Sapling::growTree(Level *level, int x, int y, int z, Random *random) { int data = level->getData(x, y, z) & TYPE_MASK; @@ -80,14 +85,12 @@ void Sapling::growTree(Level *level, int x, int y, int z, Random *random) { for (oz = 0; oz >= -1; oz--) { - if (isSapling(level, x + ox, y, z + oz, TYPE_JUNGLE) && - isSapling(level, x + ox + 1, y, z + oz, TYPE_JUNGLE) && - isSapling(level, x + ox, y, z + oz + 1, TYPE_JUNGLE) && - isSapling(level, x + ox + 1, y, z + oz + 1, TYPE_JUNGLE)) + if (isSapling(level, x + ox, y, z + oz, TYPE_JUNGLE) && isSapling(level, x + ox + 1, y, z + oz, TYPE_JUNGLE) && isSapling(level, x + ox, y, z + oz + 1, TYPE_JUNGLE) + && isSapling(level, x + ox + 1, y, z + oz + 1, TYPE_JUNGLE)) { - f = new MegaTreeFeature(true, 10 + random->nextInt(20), TreeTile::JUNGLE_TRUNK, LeafTile::JUNGLE_LEAF); - multiblock = true; - break; + f = new MegaTreeFeature(true, 10 + random->nextInt(20), TreeTile::JUNGLE_TRUNK, LeafTile::JUNGLE_LEAF); + multiblock = true; + break; } } if (f != NULL) @@ -112,27 +115,27 @@ void Sapling::growTree(Level *level, int x, int y, int z, Random *random) } if (multiblock) { - level->setTileNoUpdate(x + ox, y, z + oz, 0); - level->setTileNoUpdate(x + ox + 1, y, z + oz, 0); - level->setTileNoUpdate(x + ox, y, z + oz + 1, 0); - level->setTileNoUpdate(x + ox + 1, y, z + oz + 1, 0); + level->setTileAndData(x + ox, y, z + oz, 0, 0, Tile::UPDATE_NONE); + level->setTileAndData(x + ox + 1, y, z + oz, 0, 0, Tile::UPDATE_NONE); + level->setTileAndData(x + ox, y, z + oz + 1, 0, 0, Tile::UPDATE_NONE); + level->setTileAndData(x + ox + 1, y, z + oz + 1, 0, 0, Tile::UPDATE_NONE); } else { - level->setTileNoUpdate(x, y, z, 0); + level->setTileAndData(x, y, z, 0, 0, Tile::UPDATE_NONE); } if (!f->place(level, random, x + ox, y, z + oz)) { if (multiblock) { - level->setTileAndDataNoUpdate(x + ox, y, z + oz, this->id, data); - level->setTileAndDataNoUpdate(x + ox + 1, y, z + oz, this->id, data); - level->setTileAndDataNoUpdate(x + ox, y, z + oz + 1, this->id, data); - level->setTileAndDataNoUpdate(x + ox + 1, y, z + oz + 1, this->id, data); + level->setTileAndData(x + ox, y, z + oz, id, data, Tile::UPDATE_NONE); + level->setTileAndData(x + ox + 1, y, z + oz, id, data, Tile::UPDATE_NONE); + level->setTileAndData(x + ox, y, z + oz + 1, id, data, Tile::UPDATE_NONE); + level->setTileAndData(x + ox + 1, y, z + oz + 1, id, data, Tile::UPDATE_NONE); } else { - level->setTileAndDataNoUpdate(x, y, z, this->id, data); + level->setTileAndData(x, y, z, id, data, Tile::UPDATE_NONE); } } if( f != NULL ) diff --git a/Minecraft.World/Sapling.h b/Minecraft.World/Sapling.h index f44888af..57135f33 100644 --- a/Minecraft.World/Sapling.h +++ b/Minecraft.World/Sapling.h @@ -18,7 +18,7 @@ public: static const int SAPLING_NAMES_SIZE = 4; - static const unsigned int SAPLING_NAMES[SAPLING_NAMES_SIZE]; + static int SAPLING_NAMES[SAPLING_NAMES_SIZE]; private: static const wstring TEXTURE_NAMES[]; @@ -32,11 +32,11 @@ protected: Sapling(int id); public: - virtual void updateDefaultShape(); // 4J Added override - void tick(Level *level, int x, int y, int z, Random *random); - - Icon *getTexture(int face, int data); + virtual void updateDefaultShape(); // 4J Added override + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual Icon *getTexture(int face, int data); + virtual void advanceTree(Level *level, int x, int y, int z, Random *random); void growTree(Level *level, int x, int y, int z, Random *random); virtual unsigned int getDescriptionId(int iData = -1); diff --git a/Minecraft.World/SavedDataStorage.cpp b/Minecraft.World/SavedDataStorage.cpp index cacfa688..3dbd6400 100644 --- a/Minecraft.World/SavedDataStorage.cpp +++ b/Minecraft.World/SavedDataStorage.cpp @@ -43,6 +43,10 @@ shared_ptr SavedDataStorage::get(const type_info& clazz, const wstrin { data = dynamic_pointer_cast( shared_ptr(new Villages(id) ) ); } + else if( clazz == typeid(StructureFeatureSavedData) ) + { + data = dynamic_pointer_cast( shared_ptr( new StructureFeatureSavedData(id) ) ); + } else { // Handling of new SavedData class required diff --git a/Minecraft.World/ScatteredFeaturePieces.cpp b/Minecraft.World/ScatteredFeaturePieces.cpp index 07c2e7e6..317d6d9e 100644 --- a/Minecraft.World/ScatteredFeaturePieces.cpp +++ b/Minecraft.World/ScatteredFeaturePieces.cpp @@ -1,12 +1,30 @@ #include "stdafx.h" #include "net.minecraft.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.level.dimension.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.levelgen.structure.h" #include "WeighedTreasure.h" #include "ScatteredFeaturePieces.h" +void ScatteredFeaturePieces::loadStatic() +{ + StructureFeatureIO::setPieceId(eStructurePiece_DesertPyramidPiece, DesertPyramidPiece::Create, L"TeDP"); + StructureFeatureIO::setPieceId(eStructurePiece_JunglePyramidPiece, DesertPyramidPiece::Create, L"TeJP"); + StructureFeatureIO::setPieceId(eStructurePiece_SwamplandHut, DesertPyramidPiece::Create, L"TeSH"); +} + +ScatteredFeaturePieces::ScatteredFeaturePiece::ScatteredFeaturePiece() +{ + width = 0; + height = 0; + depth = 0; + heightPosition = 0; + // for reflection +} + ScatteredFeaturePieces::ScatteredFeaturePiece::ScatteredFeaturePiece(Random *random, int west, int floor, int north, int width, int height, int depth) : StructurePiece(0) { heightPosition = -1; @@ -16,6 +34,16 @@ ScatteredFeaturePieces::ScatteredFeaturePiece::ScatteredFeaturePiece(Random *ran orientation = random->nextInt(4); + LevelGenerationOptions *levelGenOptions = app.getLevelGenerationOptions(); + if( levelGenOptions != NULL ) + { + int tempOrientation = 0; + if(levelGenOptions->isFeatureChunk(west>>4,north>>4,StructureFeature::eFeature_Temples, &tempOrientation) ) + { + orientation = tempOrientation; + } + } + switch (orientation) { case Direction::NORTH: @@ -28,6 +56,22 @@ ScatteredFeaturePieces::ScatteredFeaturePiece::ScatteredFeaturePiece(Random *ran } } +void ScatteredFeaturePieces::ScatteredFeaturePiece::addAdditonalSaveData(CompoundTag *tag) +{ + tag->putInt(L"Width", width); + tag->putInt(L"Height", height); + tag->putInt(L"Depth", depth); + tag->putInt(L"HPos", heightPosition); +} + +void ScatteredFeaturePieces::ScatteredFeaturePiece::readAdditonalSaveData(CompoundTag *tag) +{ + width = tag->getInt(L"Width"); + height = tag->getInt(L"Height"); + depth = tag->getInt(L"Depth"); + heightPosition = tag->getInt(L"HPos"); +} + bool ScatteredFeaturePieces::ScatteredFeaturePiece::updateAverageGroundHeight(Level *level, BoundingBox *chunkBB, int offset) { if (heightPosition >= 0) @@ -66,8 +110,23 @@ WeighedTreasure *ScatteredFeaturePieces::DesertPyramidPiece::treasureItems[Scatt new WeighedTreasure(Item::emerald_Id, 0, 1, 3, 2), new WeighedTreasure(Item::bone_Id, 0, 4, 6, 20), new WeighedTreasure(Item::rotten_flesh_Id, 0, 3, 7, 16), + // very rare for pyramids ... + new WeighedTreasure(Item::saddle_Id, 0, 1, 1, 3), + new WeighedTreasure(Item::horseArmorMetal_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::horseArmorGold_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::horseArmorDiamond_Id, 0, 1, 1, 1), + // ... }; +ScatteredFeaturePieces::DesertPyramidPiece::DesertPyramidPiece() +{ + hasPlacedChest[0] = false; + hasPlacedChest[1] = false; + hasPlacedChest[2] = false; + hasPlacedChest[3] = false; + // for reflection +} + ScatteredFeaturePieces::DesertPyramidPiece::DesertPyramidPiece(Random *random, int west, int north) : ScatteredFeaturePiece(random, west, 64, north, 21, 15, 21) { hasPlacedChest[0] = false; @@ -76,6 +135,24 @@ ScatteredFeaturePieces::DesertPyramidPiece::DesertPyramidPiece(Random *random, i hasPlacedChest[3] = false; } +void ScatteredFeaturePieces::DesertPyramidPiece::addAdditonalSaveData(CompoundTag *tag) +{ + ScatteredFeaturePiece::addAdditonalSaveData(tag); + tag->putBoolean(L"hasPlacedChest0", hasPlacedChest[0]); + tag->putBoolean(L"hasPlacedChest1", hasPlacedChest[1]); + tag->putBoolean(L"hasPlacedChest2", hasPlacedChest[2]); + tag->putBoolean(L"hasPlacedChest3", hasPlacedChest[3]); +} + +void ScatteredFeaturePieces::DesertPyramidPiece::readAdditonalSaveData(CompoundTag *tag) +{ + ScatteredFeaturePiece::readAdditonalSaveData(tag); + hasPlacedChest[0] = tag->getBoolean(L"hasPlacedChest0"); + hasPlacedChest[1] = tag->getBoolean(L"hasPlacedChest1"); + hasPlacedChest[2] = tag->getBoolean(L"hasPlacedChest2"); + hasPlacedChest[3] = tag->getBoolean(L"hasPlacedChest3"); +} + bool ScatteredFeaturePieces::DesertPyramidPiece::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { // pyramid @@ -181,41 +258,41 @@ bool ScatteredFeaturePieces::DesertPyramidPiece::postProcess(Level *level, Rando placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, width - 5, 1, z, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_HEIROGLYPHS, width - 5, 2, z, chunkBB); } - placeBlock(level, Tile::cloth_Id, baseDecoColor, 10, 0, 7, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 10, 0, 8, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 9, 0, 9, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 11, 0, 9, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 8, 0, 10, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 12, 0, 10, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 7, 0, 10, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 13, 0, 10, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 9, 0, 11, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 11, 0, 11, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 10, 0, 12, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 10, 0, 13, chunkBB); - placeBlock(level, Tile::cloth_Id, blue, 10, 0, 10, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 10, 0, 7, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 10, 0, 8, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 9, 0, 9, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 11, 0, 9, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 8, 0, 10, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 12, 0, 10, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 7, 0, 10, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 13, 0, 10, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 9, 0, 11, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 11, 0, 11, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 10, 0, 12, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 10, 0, 13, chunkBB); + placeBlock(level, Tile::wool_Id, blue, 10, 0, 10, chunkBB); // outdoor decoration for (int x = 0; x <= width - 1; x += width - 1) { placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 2, 1, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 2, 2, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 2, 2, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 2, 3, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 3, 1, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 3, 2, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 3, 2, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 3, 3, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 4, 1, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 4, 1, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_HEIROGLYPHS, x, 4, 2, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 4, 3, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 4, 3, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 5, 1, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 5, 2, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 5, 2, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 5, 3, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 6, 1, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 6, 1, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_HEIROGLYPHS, x, 6, 2, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 6, 3, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 7, 1, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 7, 2, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 7, 3, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 6, 3, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 7, 1, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 7, 2, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 7, 3, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 8, 1, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 8, 2, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 8, 3, chunkBB); @@ -223,23 +300,23 @@ bool ScatteredFeaturePieces::DesertPyramidPiece::postProcess(Level *level, Rando for (int x = 2; x <= width - 3; x += width - 3 - 2) { placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x - 1, 2, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 2, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 2, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x + 1, 2, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x - 1, 3, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 3, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 3, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x + 1, 3, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x - 1, 4, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x - 1, 4, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_HEIROGLYPHS, x, 4, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x + 1, 4, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x + 1, 4, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x - 1, 5, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 5, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 5, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x + 1, 5, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x - 1, 6, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x - 1, 6, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_HEIROGLYPHS, x, 6, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x + 1, 6, 00, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x - 1, 7, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x, 7, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, x + 1, 7, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x + 1, 6, 00, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x - 1, 7, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x, 7, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, x + 1, 7, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x - 1, 8, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x, 8, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, x + 1, 8, 0, chunkBB); @@ -247,9 +324,9 @@ bool ScatteredFeaturePieces::DesertPyramidPiece::postProcess(Level *level, Rando generateBox(level, chunkBB, 8, 4, 0, 12, 6, 0, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, false); placeBlock(level, 0, 0, 8, 6, 0, chunkBB); placeBlock(level, 0, 0, 12, 6, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 9, 5, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 9, 5, 0, chunkBB); placeBlock(level, Tile::sandStone_Id, SandStoneTile::TYPE_HEIROGLYPHS, 10, 5, 0, chunkBB); - placeBlock(level, Tile::cloth_Id, baseDecoColor, 11, 5, 0, chunkBB); + placeBlock(level, Tile::wool_Id, baseDecoColor, 11, 5, 0, chunkBB); // tombs generateBox(level, chunkBB, 8, -14, 8, 12, -11, 12, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, Tile::sandStone_Id, SandStoneTile::TYPE_SMOOTHSIDE, false); @@ -289,7 +366,7 @@ bool ScatteredFeaturePieces::DesertPyramidPiece::postProcess(Level *level, Rando return true; } - + WeighedTreasure *ScatteredFeaturePieces::JunglePyramidPiece::treasureItems[ScatteredFeaturePieces::JunglePyramidPiece::TREASURE_ITEMS_COUNT] = { new WeighedTreasure(Item::diamond_Id, 0, 1, 3, 3), @@ -298,6 +375,12 @@ WeighedTreasure *ScatteredFeaturePieces::JunglePyramidPiece::treasureItems[Scatt new WeighedTreasure(Item::emerald_Id, 0, 1, 3, 2), new WeighedTreasure(Item::bone_Id, 0, 4, 6, 20), new WeighedTreasure(Item::rotten_flesh_Id, 0, 3, 7, 16), + // very rare for pyramids ... + new WeighedTreasure(Item::saddle_Id, 0, 1, 1, 3), + new WeighedTreasure(Item::horseArmorMetal_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::horseArmorGold_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::horseArmorDiamond_Id, 0, 1, 1, 1), + // ... }; @@ -307,6 +390,11 @@ WeighedTreasure *ScatteredFeaturePieces::JunglePyramidPiece::dispenserItems[Scat // new WeighedTreasure(Item.fireball.id, 0, 1, 1, 10), }; +ScatteredFeaturePieces::JunglePyramidPiece::JunglePyramidPiece() +{ + // for reflection +} + ScatteredFeaturePieces::JunglePyramidPiece::JunglePyramidPiece(Random *random, int west, int north) : ScatteredFeaturePiece(random, west, 64, north, 12, 10, 15) { placedMainChest = false; @@ -315,6 +403,24 @@ ScatteredFeaturePieces::JunglePyramidPiece::JunglePyramidPiece(Random *random, i placedTrap2 = false; } +void ScatteredFeaturePieces::JunglePyramidPiece::addAdditonalSaveData(CompoundTag *tag) +{ + ScatteredFeaturePiece::addAdditonalSaveData(tag); + tag->putBoolean(L"placedMainChest", placedMainChest); + tag->putBoolean(L"placedHiddenChest", placedHiddenChest); + tag->putBoolean(L"placedTrap1", placedTrap1); + tag->putBoolean(L"placedTrap2", placedTrap2); +} + +void ScatteredFeaturePieces::JunglePyramidPiece::readAdditonalSaveData(CompoundTag *tag) +{ + ScatteredFeaturePiece::readAdditonalSaveData(tag); + placedMainChest = tag->getBoolean(L"placedMainChest"); + placedHiddenChest = tag->getBoolean(L"placedHiddenChest"); + placedTrap1 = tag->getBoolean(L"placedTrap1"); + placedTrap2 = tag->getBoolean(L"placedTrap2"); +} + bool ScatteredFeaturePieces::JunglePyramidPiece::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (!updateAverageGroundHeight(level, chunkBB, 0)) @@ -457,7 +563,7 @@ bool ScatteredFeaturePieces::JunglePyramidPiece::postProcess(Level *level, Rando placeBlock(level, Tile::redStoneDust_Id, 0, 5, -3, 2, chunkBB); placeBlock(level, Tile::redStoneDust_Id, 0, 5, -3, 1, chunkBB); placeBlock(level, Tile::redStoneDust_Id, 0, 4, -3, 1, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 3, -3, 1, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 3, -3, 1, chunkBB); if (!placedTrap1) { placedTrap1 = createDispenser(level, chunkBB, random, 3, -2, 1, Facing::NORTH, WeighedTreasureArray(dispenserItems,DISPENSER_ITEMS_COUNT), 2); @@ -473,7 +579,7 @@ bool ScatteredFeaturePieces::JunglePyramidPiece::postProcess(Level *level, Rando placeBlock(level, Tile::redStoneDust_Id, 0, 8, -3, 6, chunkBB); placeBlock(level, Tile::redStoneDust_Id, 0, 9, -3, 6, chunkBB); placeBlock(level, Tile::redStoneDust_Id, 0, 9, -3, 5, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 9, -3, 4, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 9, -3, 4, chunkBB); placeBlock(level, Tile::redStoneDust_Id, 0, 9, -2, 4, chunkBB); if (!placedTrap2) { @@ -485,28 +591,28 @@ bool ScatteredFeaturePieces::JunglePyramidPiece::postProcess(Level *level, Rando { placedMainChest = createChest(level, chunkBB, random, 8, -3, 3, WeighedTreasure::addToTreasure(WeighedTreasureArray(treasureItems,TREASURE_ITEMS_COUNT), Item::enchantedBook->createForRandomTreasure(random)), 2 + random->nextInt(5)); } - placeBlock(level, Tile::mossStone_Id, 0, 9, -3, 2, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 8, -3, 1, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 4, -3, 5, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 5, -2, 5, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 5, -1, 5, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 6, -3, 5, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 7, -2, 5, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 7, -1, 5, chunkBB); - placeBlock(level, Tile::mossStone_Id, 0, 8, -3, 5, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 9, -3, 2, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 8, -3, 1, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 4, -3, 5, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 5, -2, 5, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 5, -1, 5, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 6, -3, 5, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 7, -2, 5, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 7, -1, 5, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 8, -3, 5, chunkBB); generateBox(level, chunkBB, 9, -1, 1, 9, -1, 5, false, random, &stoneSelector); // hidden room generateAirBox(level, chunkBB, 8, -3, 8, 10, -1, 10); - placeBlock(level, Tile::stoneBrickSmooth_Id, SmoothStoneBrickTile::TYPE_DETAIL, 8, -2, 11, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, SmoothStoneBrickTile::TYPE_DETAIL, 9, -2, 11, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, SmoothStoneBrickTile::TYPE_DETAIL, 10, -2, 11, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, SmoothStoneBrickTile::TYPE_DETAIL, 8, -2, 11, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, SmoothStoneBrickTile::TYPE_DETAIL, 9, -2, 11, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, SmoothStoneBrickTile::TYPE_DETAIL, 10, -2, 11, chunkBB); placeBlock(level, Tile::lever_Id, LeverTile::getLeverFacing(getOrientationData(Tile::lever_Id, Facing::NORTH)), 8, -2, 12, chunkBB); placeBlock(level, Tile::lever_Id, LeverTile::getLeverFacing(getOrientationData(Tile::lever_Id, Facing::NORTH)), 9, -2, 12, chunkBB); placeBlock(level, Tile::lever_Id, LeverTile::getLeverFacing(getOrientationData(Tile::lever_Id, Facing::NORTH)), 10, -2, 12, chunkBB); generateBox(level, chunkBB, 8, -3, 8, 8, -3, 10, false, random, &stoneSelector); generateBox(level, chunkBB, 10, -3, 8, 10, -3, 10, false, random, &stoneSelector); - placeBlock(level, Tile::mossStone_Id, 0, 10, -2, 9, chunkBB); + placeBlock(level, Tile::mossyCobblestone_Id, 0, 10, -2, 9, chunkBB); placeBlock(level, Tile::redStoneDust_Id, 0, 8, -2, 9, chunkBB); placeBlock(level, Tile::redStoneDust_Id, 0, 8, -2, 10, chunkBB); placeBlock(level, Tile::redStoneDust_Id, 0, 10, -1, 9, chunkBB); @@ -526,12 +632,117 @@ void ScatteredFeaturePieces::JunglePyramidPiece::MossStoneSelector::next(Random { if (random->nextFloat() < .4f) { - nextId = Tile::stoneBrick_Id; + nextId = Tile::cobblestone_Id; } else { - nextId = Tile::mossStone_Id; + nextId = Tile::mossyCobblestone_Id; } } -ScatteredFeaturePieces::JunglePyramidPiece::MossStoneSelector ScatteredFeaturePieces::JunglePyramidPiece::stoneSelector; \ No newline at end of file +ScatteredFeaturePieces::JunglePyramidPiece::MossStoneSelector ScatteredFeaturePieces::JunglePyramidPiece::stoneSelector; + +ScatteredFeaturePieces::SwamplandHut::SwamplandHut() +{ + spawnedWitch = false; + // for reflection +} + +ScatteredFeaturePieces::SwamplandHut::SwamplandHut(Random *random, int west, int north) : ScatteredFeaturePiece(random, west, 64, north, 7, 5, 9) +{ + spawnedWitch = false; +} + +void ScatteredFeaturePieces::SwamplandHut::addAdditonalSaveData(CompoundTag *tag) +{ + ScatteredFeaturePiece::addAdditonalSaveData(tag); + tag->putBoolean(L"Witch", spawnedWitch); +} + +void ScatteredFeaturePieces::SwamplandHut::readAdditonalSaveData(CompoundTag *tag) +{ + ScatteredFeaturePiece::readAdditonalSaveData(tag); + spawnedWitch = tag->getBoolean(L"Witch"); +} + +bool ScatteredFeaturePieces::SwamplandHut::postProcess(Level *level, Random *random, BoundingBox *chunkBB) +{ + if (!updateAverageGroundHeight(level, chunkBB, 0)) + { + return false; + } + + // floor and ceiling + generateBox(level, chunkBB, 1, 1, 1, 5, 1, 7, Tile::wood_Id, TreeTile::DARK_TRUNK, Tile::wood_Id, TreeTile::DARK_TRUNK, false); + generateBox(level, chunkBB, 1, 4, 2, 5, 4, 7, Tile::wood_Id, TreeTile::DARK_TRUNK, Tile::wood_Id, TreeTile::DARK_TRUNK, false); + generateBox(level, chunkBB, 2, 1, 0, 4, 1, 0, Tile::wood_Id, TreeTile::DARK_TRUNK, Tile::wood_Id, TreeTile::DARK_TRUNK, false); + + // walls + generateBox(level, chunkBB, 2, 2, 2, 3, 3, 2, Tile::wood_Id, TreeTile::DARK_TRUNK, Tile::wood_Id, TreeTile::DARK_TRUNK, false); + generateBox(level, chunkBB, 1, 2, 3, 1, 3, 6, Tile::wood_Id, TreeTile::DARK_TRUNK, Tile::wood_Id, TreeTile::DARK_TRUNK, false); + generateBox(level, chunkBB, 5, 2, 3, 5, 3, 6, Tile::wood_Id, TreeTile::DARK_TRUNK, Tile::wood_Id, TreeTile::DARK_TRUNK, false); + generateBox(level, chunkBB, 2, 2, 7, 4, 3, 7, Tile::wood_Id, TreeTile::DARK_TRUNK, Tile::wood_Id, TreeTile::DARK_TRUNK, false); + + // pillars + generateBox(level, chunkBB, 1, 0, 2, 1, 3, 2, Tile::treeTrunk_Id, Tile::treeTrunk_Id, false); + generateBox(level, chunkBB, 5, 0, 2, 5, 3, 2, Tile::treeTrunk_Id, Tile::treeTrunk_Id, false); + generateBox(level, chunkBB, 1, 0, 7, 1, 3, 7, Tile::treeTrunk_Id, Tile::treeTrunk_Id, false); + generateBox(level, chunkBB, 5, 0, 7, 5, 3, 7, Tile::treeTrunk_Id, Tile::treeTrunk_Id, false); + + // windows + placeBlock(level, Tile::fence_Id, 0, 2, 3, 2, chunkBB); + placeBlock(level, Tile::fence_Id, 0, 3, 3, 7, chunkBB); + placeBlock(level, 0, 0, 1, 3, 4, chunkBB); + placeBlock(level, 0, 0, 5, 3, 4, chunkBB); + placeBlock(level, 0, 0, 5, 3, 5, chunkBB); + placeBlock(level, Tile::flowerPot_Id, FlowerPotTile::TYPE_MUSHROOM_RED, 1, 3, 5, chunkBB); + + // decoration + placeBlock(level, Tile::workBench_Id, 0, 3, 2, 6, chunkBB); + placeBlock(level, Tile::cauldron_Id, 0, 4, 2, 6, chunkBB); + + // front railings + placeBlock(level, Tile::fence_Id, 0, 1, 2, 1, chunkBB); + placeBlock(level, Tile::fence_Id, 0, 5, 2, 1, chunkBB); + // placeBlock(level, Tile.torch.id, 0, 1, 3, 1, chunkBB); + // placeBlock(level, Tile.torch.id, 0, 5, 3, 1, chunkBB); + + // ceiling edges + int south = getOrientationData(Tile::stairs_wood_Id, StairTile::DIR_NORTH); + int east = getOrientationData(Tile::stairs_wood_Id, StairTile::DIR_WEST); + int west = getOrientationData(Tile::stairs_wood_Id, StairTile::DIR_EAST); + int north = getOrientationData(Tile::stairs_wood_Id, StairTile::DIR_SOUTH); + + generateBox(level, chunkBB, 0, 4, 1, 6, 4, 1, Tile::stairs_sprucewood_Id, south, Tile::stairs_sprucewood_Id, south, false); + generateBox(level, chunkBB, 0, 4, 2, 0, 4, 7, Tile::stairs_sprucewood_Id, west, Tile::stairs_sprucewood_Id, west, false); + generateBox(level, chunkBB, 6, 4, 2, 6, 4, 7, Tile::stairs_sprucewood_Id, east, Tile::stairs_sprucewood_Id, east, false); + generateBox(level, chunkBB, 0, 4, 8, 6, 4, 8, Tile::stairs_sprucewood_Id, north, Tile::stairs_sprucewood_Id, north, false); + + // fill pillars down to solid ground + for (int z = 2; z <= 7; z += 5) + { + for (int x = 1; x <= 5; x += 4) + { + fillColumnDown(level, Tile::treeTrunk_Id, 0, x, -1, z, chunkBB); + } + } + + if (!spawnedWitch) + { + int wx = getWorldX(2, 5); + int wy = getWorldY(2); + int wz = getWorldZ(2, 5); + + if (chunkBB->isInside(wx, wy, wz)) + { + spawnedWitch = true; + + shared_ptr witch = shared_ptr( new Witch(level) ); + witch->moveTo(wx + .5, wy, wz + .5, 0, 0); + witch->finalizeMobSpawn(NULL); + level->addEntity(witch); + } + } + + return true; +} \ No newline at end of file diff --git a/Minecraft.World/ScatteredFeaturePieces.h b/Minecraft.World/ScatteredFeaturePieces.h index 08ab92ba..5fb334df 100644 --- a/Minecraft.World/ScatteredFeaturePieces.h +++ b/Minecraft.World/ScatteredFeaturePieces.h @@ -4,6 +4,9 @@ class ScatteredFeaturePieces { +public: + static void loadStatic(); + private: class ScatteredFeaturePiece : public StructurePiece { @@ -14,8 +17,11 @@ private: int heightPosition; + ScatteredFeaturePiece(); ScatteredFeaturePiece(Random *random, int west, int floor, int north, int width, int height, int depth); + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); bool updateAverageGroundHeight(Level *level, BoundingBox *chunkBB, int offset); }; @@ -23,14 +29,23 @@ public: class DesertPyramidPiece : public ScatteredFeaturePiece { public: - static const int TREASURE_ITEMS_COUNT = 6; + static StructurePiece *Create() { return new DesertPyramidPiece(); } + virtual EStructurePiece GetType() { return eStructurePiece_DesertPyramidPiece; } + + public: + static const int TREASURE_ITEMS_COUNT = 10; private: bool hasPlacedChest[4]; static WeighedTreasure *treasureItems[TREASURE_ITEMS_COUNT]; public: + DesertPyramidPiece(); DesertPyramidPiece(Random *random, int west, int north); + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); }; @@ -38,7 +53,11 @@ public: class JunglePyramidPiece : public ScatteredFeaturePiece { public: - static const int TREASURE_ITEMS_COUNT = 6; + static StructurePiece *Create() { return new JunglePyramidPiece(); } + virtual EStructurePiece GetType() { return eStructurePiece_JunglePyramidPiece; } + + public: + static const int TREASURE_ITEMS_COUNT = 10; static const int DISPENSER_ITEMS_COUNT = 1; private: bool placedMainChest; @@ -50,8 +69,14 @@ public: static WeighedTreasure *dispenserItems[DISPENSER_ITEMS_COUNT]; public: + JunglePyramidPiece(); JunglePyramidPiece(Random *random, int west, int north); + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); private: @@ -64,4 +89,25 @@ public: static MossStoneSelector stoneSelector; }; + + class SwamplandHut : public ScatteredFeaturePiece + { + public: + static StructurePiece *Create() { return new SwamplandHut(); } + virtual EStructurePiece GetType() { return eStructurePiece_SwamplandHut; } + + private: + bool spawnedWitch; + + public: + SwamplandHut(); + SwamplandHut(Random *random, int west, int north); + + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; }; \ No newline at end of file diff --git a/Minecraft.World/Score.cpp b/Minecraft.World/Score.cpp new file mode 100644 index 00000000..039939b1 --- /dev/null +++ b/Minecraft.World/Score.cpp @@ -0,0 +1,68 @@ +#include "stdafx.h" +#include "net.minecraft.world.scores.h" +#include "net.minecraft.world.scores.criteria.h" +#include "Score.h" + +Score::Score(Scoreboard *scoreboard, Objective *objective, const wstring &owner) +{ + this->scoreboard = scoreboard; + this->objective = objective; + this->owner = owner; + count = 0; +} + +void Score::add(int count) +{ + //if (objective.getCriteria().isReadOnly()) throw new IllegalStateException("Cannot modify read-only score"); + setScore(getScore() + count); +} + +void Score::remove(int count) +{ + //if (objective.getCriteria().isReadOnly()) throw new IllegalStateException("Cannot modify read-only score"); + setScore(getScore() - count); +} + +void Score::increment() +{ + //if (objective.getCriteria().isReadOnly()) throw new IllegalStateException("Cannot modify read-only score"); + add(1); +} + +void Score::decrement() +{ + //if (objective.getCriteria().isReadOnly()) throw new IllegalStateException("Cannot modify read-only score"); + remove(1); +} + +int Score::getScore() +{ + return count; +} + +void Score::setScore(int score) +{ + int old = count; + count = score; + if (old != score) getScoreboard()->onScoreChanged(this); +} + +Objective *Score::getObjective() +{ + return objective; +} + +wstring Score::getOwner() +{ + return owner; +} + +Scoreboard *Score::getScoreboard() +{ + return scoreboard; +} + +void Score::updateFor(vector > *players) +{ + setScore(objective->getCriteria()->getScoreModifier(players)); +} \ No newline at end of file diff --git a/Minecraft.World/Score.h b/Minecraft.World/Score.h new file mode 100644 index 00000000..2a32f138 --- /dev/null +++ b/Minecraft.World/Score.h @@ -0,0 +1,44 @@ +#pragma once + +class Scoreboard; +class Objective; + +class Score +{ +public: + // 4J Not converted +#if 0 + static final Comparator SCORE_COMPARATOR = new Comparator() { + @Override + public int compare(Score o1, Score o2) { + if (o1.getScore() > o2.getScore()) { + return 1; + } else if (o1.getScore() < o2.getScore()) { + return -1; + } else { + return 0; + } + } + }; +#endif + +private: + Scoreboard *scoreboard; + Objective *objective; + wstring owner; + int count; + +public: + Score(Scoreboard *scoreboard, Objective *objective, const wstring &owner); + + void add(int count); + void remove(int count); + void increment(); + void decrement(); + int getScore(); + void setScore(int score); + Objective *getObjective(); + wstring getOwner(); + Scoreboard *getScoreboard(); + void updateFor(vector > *players); +}; \ No newline at end of file diff --git a/Minecraft.World/ScoreHolder.h b/Minecraft.World/ScoreHolder.h new file mode 100644 index 00000000..72a43de3 --- /dev/null +++ b/Minecraft.World/ScoreHolder.h @@ -0,0 +1,9 @@ +#pragma once + +class Scoreboard; + +class ScoreHolder +{ +public: + virtual Scoreboard *getScoreboard() = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/Scoreboard.cpp b/Minecraft.World/Scoreboard.cpp new file mode 100644 index 00000000..5c6f2ebd --- /dev/null +++ b/Minecraft.World/Scoreboard.cpp @@ -0,0 +1,328 @@ +#include "stdafx.h" + +#include "Scoreboard.h" + +Objective *Scoreboard::getObjective(const wstring &name) +{ + return NULL; + //return objectivesByName.find(name)->second; +} + +Objective *Scoreboard::addObjective(const wstring &name, ObjectiveCriteria *criteria) +{ + return NULL; +// Objective *objective = getObjective(name); +// if (objective != NULL) +// { +//#indef _CONTENT_PACKAGE +// __debugbreak(); +//#endif +// //throw new IllegalArgumentException("An objective with the name '" + name + "' already exists!"); +// } +// +// objective = new Objective(this, name, criteria); +// +// vector *criteriaList = objectivesByCriteria.find(criteria)->second; +// +// if (criteriaList == NULL) +// { +// criteriaList = new vector(); +// objectivesByCriteria[criteria] = criteriaList; +// } +// +// criteriaList->push_back(objective); +// objectivesByName[name] = objective; +// onObjectiveAdded(objective); +// +// return objective; +} + +vector *Scoreboard::findObjectiveFor(ObjectiveCriteria *criteria) +{ + return NULL; + //vector *objectives = objectivesByCriteria.find(criteria)->second; + + //return objectives == NULL ? new vector() : new vector(objectives); +} + +Score *Scoreboard::getPlayerScore(const wstring &name, Objective *objective) +{ + return NULL; + //unordered_map *scores = playerScores.find(name)->it; + + //if (scores == NULL) + //{ + // scores = new unordered_map(); + // playerScores.put(name, scores); + //} + + //Score *score = scores->get(objective); + + //if (score == NULL) + //{ + // score = new Score(this, objective, name); + // scores->put(objective, score); + //} + + //return score; +} + +vector *Scoreboard::getPlayerScores(Objective *objective) +{ + return NULL; + //vector *result = new vector(); + + //for (Map scores : playerScores.values()) + //{ + // Score score = scores.get(objective); + // if (score != null) result.add(score); + //} + + //Collections.sort(result, Score.SCORE_COMPARATOR); + + //return result; +} + +vector *Scoreboard::getObjectives() +{ + return NULL; + //return objectivesByName.values(); +} + +vector *Scoreboard::getTrackedPlayers() +{ + return NULL; + //return playerScores.keySet(); +} + +void Scoreboard::resetPlayerScore(const wstring &player) +{ + //unordered_map *removed = playerScores.remove(player); + + //if (removed != NULL) + //{ + // onPlayerRemoved(player); + //} +} + +vector *Scoreboard::getScores() +{ + return NULL; + //Collection> values = playerScores.values(); + //List result = new ArrayList(); + + //for (Map map : values) + //{ + // result.addAll(map.values()); + //} + + //return result; +} + +vector *Scoreboard::getScores(Objective *objective) +{ + return NULL; + //Collection> values = playerScores.values(); + //List result = new ArrayList(); + + //for (Map map : values) { + // Score score = map.get(objective); + // if (score != null) result.add(score); + //} + + //return result; +} + +unordered_map *Scoreboard::getPlayerScores(const wstring &player) +{ + return NULL; + //Map result = playerScores.get(player); + //if (result == null) result = new HashMap(); + //return result; +} + +void Scoreboard::removeObjective(Objective *objective) +{ + //objectivesByName.remove(objective.getName()); + + //for (int i = 0; i < DISPLAY_SLOTS; i++) { + // if (getDisplayObjective(i) == objective) setDisplayObjective(i, null); + //} + + //List objectives = objectivesByCriteria.get(objective.getCriteria()); + //if (objectives != null) objectives.remove(objective); + + //for (Map objectiveScoreMap : playerScores.values()) { + // objectiveScoreMap.remove(objective); + //} + + //onObjectiveRemoved(objective); +} + +void Scoreboard::setDisplayObjective(int slot, Objective *objective) +{ + //displayObjectives[slot] = objective; +} + +Objective *Scoreboard::getDisplayObjective(int slot) +{ + return NULL; + //return displayObjectives[slot]; +} + +PlayerTeam *Scoreboard::getPlayerTeam(const wstring &name) +{ + return NULL; + //return teamsByName.get(name); +} + +PlayerTeam *Scoreboard::addPlayerTeam(const wstring &name) +{ + return NULL; + //PlayerTeam team = getPlayerTeam(name); + //if (team != null) throw new IllegalArgumentException("An objective with the name '" + name + "' already exists!"); + + //team = new PlayerTeam(this, name); + //teamsByName.put(name, team); + //onTeamAdded(team); + + //return team; +} + +void Scoreboard::removePlayerTeam(PlayerTeam *team) +{ + //teamsByName.remove(team.getName()); + + //// [TODO]: Loop through scores, remove. + + //for (String player : team.getPlayers()) { + // teamsByPlayer.remove(player); + //} + + //onTeamRemoved(team); +} + +void Scoreboard::addPlayerToTeam(const wstring &player, PlayerTeam *team) +{ + //if (getPlayersTeam(player) != null) { + // removePlayerFromTeam(player); + //} + + //teamsByPlayer.put(player, team); + //team.getPlayers().add(player); +} + +bool Scoreboard::removePlayerFromTeam(const wstring &player) +{ + return false; + //PlayerTeam team = getPlayersTeam(player); + + //if (team != null) { + // removePlayerFromTeam(player, team); + // return true; + //} else { + // return false; + //} +} + +void Scoreboard::removePlayerFromTeam(const wstring &player, PlayerTeam *team) +{ + //if (getPlayersTeam(player) != team) { + // throw new IllegalStateException("Player is either on another team or not on any team. Cannot remove from team '" + team.getName() + "'."); + //} + + //teamsByPlayer.remove(player); + //team.getPlayers().remove(player); +} + +vector *Scoreboard::getTeamNames() +{ + return NULL; + //return teamsByName.keySet(); +} + +vector *Scoreboard::getPlayerTeams() +{ + return NULL; + //return teamsByName.values(); +} + +shared_ptr Scoreboard::getPlayer(const wstring &name) +{ + return nullptr; + //return MinecraftServer.getInstance().getPlayers().getPlayer(name); +} + +PlayerTeam *Scoreboard::getPlayersTeam(const wstring &name) +{ + return NULL; + //return teamsByPlayer.get(name); +} + +void Scoreboard::onObjectiveAdded(Objective *objective) +{ +} + +void Scoreboard::onObjectiveChanged(Objective *objective) +{ +} + +void Scoreboard::onObjectiveRemoved(Objective *objective) +{ +} + +void Scoreboard::onScoreChanged(Score *score) +{ +} + +void Scoreboard::onPlayerRemoved(const wstring &player) +{ +} + +void Scoreboard::onTeamAdded(PlayerTeam *team) +{ +} + +void Scoreboard::onTeamChanged(PlayerTeam *team) +{ +} + +void Scoreboard::onTeamRemoved(PlayerTeam *team) +{ +} + +wstring Scoreboard::getDisplaySlotName(int slot) +{ + switch (slot) + { + case DISPLAY_SLOT_LIST: + return L"list"; + case DISPLAY_SLOT_SIDEBAR: + return L"sidebar"; + case DISPLAY_SLOT_BELOW_NAME: + return L"belowName"; + default: + return L""; + } +} + +int Scoreboard::getDisplaySlotByName(const wstring &name) +{ + return -1; + //if (name.equalsIgnoreCase("list")) + //{ + // return DISPLAY_SLOT_LIST; + //} + //else if (name.equalsIgnoreCase("sidebar")) + //{ + // return DISPLAY_SLOT_SIDEBAR; + //} + //else if (name.equalsIgnoreCase("belowName")) + //{ + // return DISPLAY_SLOT_BELOW_NAME; + //} + //else + //{ + // return -1; + //} +} \ No newline at end of file diff --git a/Minecraft.World/Scoreboard.h b/Minecraft.World/Scoreboard.h new file mode 100644 index 00000000..13168f0b --- /dev/null +++ b/Minecraft.World/Scoreboard.h @@ -0,0 +1,59 @@ +#pragma once + +class Objective; +class ObjectiveCriteria; +class PlayerTeam; +class Score; + +class Scoreboard +{ +public: + static const int DISPLAY_SLOT_LIST = 0; + static const int DISPLAY_SLOT_SIDEBAR = 1; + static const int DISPLAY_SLOT_BELOW_NAME = 2; + static const int DISPLAY_SLOTS = 3; + +private: + unordered_map objectivesByName; + unordered_map *> objectivesByCriteria; + unordered_map > playerScores; + Objective *displayObjectives[DISPLAY_SLOTS]; + unordered_map teamsByName; + unordered_map teamsByPlayer; + +public: + Objective *getObjective(const wstring &name); + Objective *addObjective(const wstring &name, ObjectiveCriteria *criteria); + vector *findObjectiveFor(ObjectiveCriteria *criteria); + Score *getPlayerScore(const wstring &name, Objective *objective); + vector *getPlayerScores(Objective *objective); + vector *getObjectives(); + vector *getTrackedPlayers(); + void resetPlayerScore(const wstring &player); + vector *getScores(); + vector *getScores(Objective *objective); + unordered_map *getPlayerScores(const wstring &player); + void removeObjective(Objective *objective); + void setDisplayObjective(int slot, Objective *objective); + Objective *getDisplayObjective(int slot); + PlayerTeam *getPlayerTeam(const wstring &name); + PlayerTeam *addPlayerTeam(const wstring &name); + void removePlayerTeam(PlayerTeam *team); + void addPlayerToTeam(const wstring &player, PlayerTeam *team); + bool removePlayerFromTeam(const wstring &player); + void removePlayerFromTeam(const wstring &player, PlayerTeam *team); + vector *getTeamNames(); + vector *getPlayerTeams(); + shared_ptr getPlayer(const wstring &name); + PlayerTeam *getPlayersTeam(const wstring &name); + void onObjectiveAdded(Objective *objective); + void onObjectiveChanged(Objective *objective); + void onObjectiveRemoved(Objective *objective); + void onScoreChanged(Score *score); + void onPlayerRemoved(const wstring &player); + void onTeamAdded(PlayerTeam *team); + void onTeamChanged(PlayerTeam *team); + void onTeamRemoved(PlayerTeam *team); + static wstring getDisplaySlotName(int slot); + static int getDisplaySlotByName(const wstring &name); +}; \ No newline at end of file diff --git a/Minecraft.World/ScoreboardSaveData.h b/Minecraft.World/ScoreboardSaveData.h new file mode 100644 index 00000000..4a59b45e --- /dev/null +++ b/Minecraft.World/ScoreboardSaveData.h @@ -0,0 +1,189 @@ +#pragma once + +// 4J Not converted +#if 0 +class ScoreboardSaveData extends SavedData { + public static final String FILE_ID = "scoreboard"; + + private Scoreboard scoreboard; + private CompoundTag delayLoad; + + public ScoreboardSaveData() { + this(FILE_ID); + } + + public ScoreboardSaveData(String id) { + super(id); + } + + public void setScoreboard(Scoreboard scoreboard) { + this.scoreboard = scoreboard; + + if (delayLoad != null) { + load(delayLoad); + } + } + + @Override + public void load(CompoundTag tag) { + if (scoreboard == null) { + delayLoad = tag; + return; + } + + loadObjectives((ListTag) tag.getList("Objectives")); + loadPlayerScores((ListTag) tag.getList("PlayerScores")); + + if (tag.contains("DisplaySlots")) { + loadDisplaySlots(tag.getCompound("DisplaySlots")); + } + + if (tag.contains("Teams")) { + loadTeams((ListTag) tag.getList("Teams")); + } + } + + protected void loadTeams(ListTag list) { + for (int i = 0; i < list.size(); i++) { + CompoundTag tag = list.get(i); + + PlayerTeam team = scoreboard.addPlayerTeam(tag.getString("Name")); + team.setDisplayName(tag.getString("DisplayName")); + team.setPrefix(tag.getString("Prefix")); + team.setSuffix(tag.getString("Suffix")); + if (tag.contains("AllowFriendlyFire")) team.setAllowFriendlyFire(tag.getBoolean("AllowFriendlyFire")); + if (tag.contains("SeeFriendlyInvisibles")) team.setSeeFriendlyInvisibles(tag.getBoolean("SeeFriendlyInvisibles")); + + loadTeamPlayers(team, (ListTag) tag.getList("Players")); + } + } + + protected void loadTeamPlayers(PlayerTeam team, ListTag list) { + for (int i = 0; i < list.size(); i++) { + scoreboard.addPlayerToTeam(list.get(i).data, team); + } + } + + protected void loadDisplaySlots(CompoundTag tag) { + for (int i = 0; i < Scoreboard.DISPLAY_SLOTS; i++) { + if (tag.contains("slot_" + i)) { + String name = tag.getString("slot_" + i); + Objective objective = scoreboard.getObjective(name); + scoreboard.setDisplayObjective(i, objective); + } + } + } + + protected void loadObjectives(ListTag list) { + for (int i = 0; i < list.size(); i++) { + CompoundTag tag = list.get(i); + + ObjectiveCriteria criteria = ObjectiveCriteria.CRITERIA_BY_NAME.get(tag.getString("CriteriaName")); + Objective objective = scoreboard.addObjective(tag.getString("Name"), criteria); + objective.setDisplayName(tag.getString("DisplayName")); + } + } + + protected void loadPlayerScores(ListTag list) { + for (int i = 0; i < list.size(); i++) { + CompoundTag tag = list.get(i); + + Objective objective = scoreboard.getObjective(tag.getString("Objective")); + Score score = scoreboard.getPlayerScore(tag.getString("Name"), objective); + score.setScore(tag.getInt("Score")); + } + } + + @Override + public void save(CompoundTag tag) { + if (scoreboard == null) { + MinecraftServer.getInstance().getLogger().warning("Tried to save scoreboard without having a scoreboard..."); + return; + } + + tag.put("Objectives", saveObjectives()); + tag.put("PlayerScores", savePlayerScores()); + tag.put("Teams", saveTeams()); + + saveDisplaySlots(tag); + } + + protected ListTag saveTeams() { + ListTag list = new ListTag(); + Collection teams = scoreboard.getPlayerTeams(); + + for (PlayerTeam team : teams) { + CompoundTag tag = new CompoundTag(); + + tag.putString("Name", team.getName()); + tag.putString("DisplayName", team.getDisplayName()); + tag.putString("Prefix", team.getPrefix()); + tag.putString("Suffix", team.getSuffix()); + tag.putBoolean("AllowFriendlyFire", team.isAllowFriendlyFire()); + tag.putBoolean("SeeFriendlyInvisibles", team.canSeeFriendlyInvisibles()); + + ListTag playerList = new ListTag(); + + for (String player : team.getPlayers()) { + playerList.add(new StringTag("", player)); + } + + tag.put("Players", playerList); + + list.add(tag); + } + + return list; + } + + protected void saveDisplaySlots(CompoundTag tag) { + CompoundTag slots = new CompoundTag(); + boolean hasDisplaySlot = false; + + for (int i = 0; i < Scoreboard.DISPLAY_SLOTS; i++) { + Objective objective = scoreboard.getDisplayObjective(i); + + if (objective != null) { + slots.putString("slot_" + i, objective.getName()); + hasDisplaySlot = true; + } + } + + if (hasDisplaySlot) tag.putCompound("DisplaySlots", slots); + } + + protected ListTag saveObjectives() { + ListTag list = new ListTag(); + Collection objectives = scoreboard.getObjectives(); + + for (Objective objective : objectives) { + CompoundTag tag = new CompoundTag(); + + tag.putString("Name", objective.getName()); + tag.putString("CriteriaName", objective.getCriteria().getName()); + tag.putString("DisplayName", objective.getDisplayName()); + + list.add(tag); + } + + return list; + } + + protected ListTag savePlayerScores() { + ListTag list = new ListTag(); + Collection scores = scoreboard.getScores(); + + for (Score score : scores) { + CompoundTag tag = new CompoundTag(); + + tag.putString("Name", score.getOwner()); + tag.putString("Objective", score.getObjective().getName()); + tag.putInt("Score", score.getScore()); + + list.add(tag); + } + + return list; + } +}; +#endif \ No newline at end of file diff --git a/Minecraft.World/SeedFoodItem.cpp b/Minecraft.World/SeedFoodItem.cpp index 4ba9a14a..8f5bfa92 100644 --- a/Minecraft.World/SeedFoodItem.cpp +++ b/Minecraft.World/SeedFoodItem.cpp @@ -15,14 +15,14 @@ bool SeedFoodItem::useOn(shared_ptr instance, shared_ptr p { if (face != Facing::UP) return false; - if (!player->mayBuild(x, y, z) || !player->mayBuild(x, y + 1, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, instance) || !player->mayUseItemAt(x, y + 1, z, face, instance)) return false; int targetType = level->getTile(x, y, z); if (targetType == targetLand && level->isEmptyTile(x, y + 1, z)) { if(!bTestUseOnOnly) { - level->setTile(x, y + 1, z, resultId); + level->setTileAndUpdate(x, y + 1, z, resultId); instance->count--; } return true; diff --git a/Minecraft.World/SeedItem.cpp b/Minecraft.World/SeedItem.cpp index 7a5ac1b8..87211d8b 100644 --- a/Minecraft.World/SeedItem.cpp +++ b/Minecraft.World/SeedItem.cpp @@ -10,27 +10,27 @@ using namespace std; SeedItem::SeedItem(int id, int resultId, int targetLand) : Item(id) { - this->resultId = resultId; + this->resultId = resultId; this->targetLand = targetLand; } bool SeedItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { // 4J-PB - Adding a test only version to allow tooltips to be displayed - if (face != 1) return false; + if (face != 1) return false; - if (!player->mayBuild(x, y, z) || !player->mayBuild(x, y + 1, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, instance) || !player->mayUseItemAt(x, y + 1, z, face, instance)) return false; - int targetType = level->getTile(x, y, z); + int targetType = level->getTile(x, y, z); - if (targetType == targetLand && level->isEmptyTile(x, y + 1, z)) + if (targetType == targetLand && level->isEmptyTile(x, y + 1, z)) { if(!bTestUseOnOnly) { - level->setTile(x, y + 1, z, resultId); + level->setTileAndUpdate(x, y + 1, z, resultId); instance->count--; } - return true; - } - return false; + return true; + } + return false; } \ No newline at end of file diff --git a/Minecraft.World/ServersideAttributeMap.cpp b/Minecraft.World/ServersideAttributeMap.cpp new file mode 100644 index 00000000..ec75aa22 --- /dev/null +++ b/Minecraft.World/ServersideAttributeMap.cpp @@ -0,0 +1,83 @@ +#include "stdafx.h" + +#include "Attribute.h" +#include "RangedAttribute.h" +#include "AttributeInstance.h" +#include "ModifiableAttributeInstance.h" +#include "ServersideAttributeMap.h" + +AttributeInstance *ServersideAttributeMap::getInstance(Attribute *attribute) +{ + return BaseAttributeMap::getInstance(attribute); +} + +AttributeInstance *ServersideAttributeMap::getInstance(eATTRIBUTE_ID id) +{ + AttributeInstance *result = BaseAttributeMap::getInstance(id); + + // 4J: Removed legacy name + // If we didn't find it, search by legacy name + /*if (result == NULL) + { + AUTO_VAR(it, attributesByLegacy.find(name)); + if(it != attributesByLegacy.end()) + { + result = it->second; + } + }*/ + + return result; +} + +AttributeInstance *ServersideAttributeMap::registerAttribute(Attribute *attribute) +{ + AUTO_VAR(it,attributesById.find(attribute->getId())); + if (it != attributesById.end()) + { + return it->second; + } + + AttributeInstance *instance = new ModifiableAttributeInstance(this, attribute); + attributesById.insert(std::pair(attribute->getId(), instance)); + + // 4J: Removed legacy name + // If this is a ranged attribute also add to legacy name map + /*RangedAttribute *rangedAttribute = dynamic_cast(attribute); + if (rangedAttribute != NULL && rangedAttribute->getImportLegacyName() != L"") + { + attributesByLegacy.insert(std::pair(rangedAttribute->getImportLegacyName(), instance)); + }*/ + + return instance; +} + +void ServersideAttributeMap::onAttributeModified(ModifiableAttributeInstance *attributeInstance) +{ + if (attributeInstance->getAttribute()->isClientSyncable()) + { + dirtyAttributes.insert(attributeInstance); + } +} + +unordered_set *ServersideAttributeMap::getDirtyAttributes() +{ + return &dirtyAttributes; +} + +unordered_set *ServersideAttributeMap::getSyncableAttributes() +{ + unordered_set *result = new unordered_set(); + vector atts; + getAttributes(atts); + for (int i = 0; i < atts.size(); i++) + { + AttributeInstance *instance = atts.at(i); + + if (instance->getAttribute()->isClientSyncable()) + { + result->insert(instance); + } + } + + return result; +} \ No newline at end of file diff --git a/Minecraft.World/ServersideAttributeMap.h b/Minecraft.World/ServersideAttributeMap.h new file mode 100644 index 00000000..b404eb9e --- /dev/null +++ b/Minecraft.World/ServersideAttributeMap.h @@ -0,0 +1,24 @@ +#pragma once + +#include "BaseAttributeMap.h" + +class ServersideAttributeMap : public BaseAttributeMap +{ +private: + unordered_set dirtyAttributes; + +protected: + // 4J: Remove legacy name + //unordered_map attributesByLegacy; + +public: + + // 4J-JEV: Changed from ModifiableAttributeInstance to AttributeInstance as they are not 'covariant' on PS4. + virtual AttributeInstance *getInstance(Attribute *attribute); + virtual AttributeInstance *getInstance(eATTRIBUTE_ID id); + + virtual AttributeInstance *registerAttribute(Attribute *attribute); + virtual void onAttributeModified(ModifiableAttributeInstance *attributeInstance); + virtual unordered_set *getDirtyAttributes(); + virtual unordered_set *getSyncableAttributes(); +}; \ No newline at end of file diff --git a/Minecraft.World/SetDisplayObjectivePacket.cpp b/Minecraft.World/SetDisplayObjectivePacket.cpp new file mode 100644 index 00000000..f1cffa4b --- /dev/null +++ b/Minecraft.World/SetDisplayObjectivePacket.cpp @@ -0,0 +1,46 @@ +#include "stdafx.h" +#include "PacketListener.h" +#include "net.minecraft.world.scores.h" +#include "SetDisplayObjectivePacket.h" + +SetDisplayObjectivePacket::SetDisplayObjectivePacket() +{ + slot = 0; + objectiveName = L""; +} + +SetDisplayObjectivePacket::SetDisplayObjectivePacket(int slot, Objective *objective) +{ + this->slot = slot; + + if (objective == NULL) + { + objectiveName = L""; + } + else + { + objectiveName = objective->getName(); + } +} + +void SetDisplayObjectivePacket::read(DataInputStream *dis) +{ + slot = dis->readByte(); + objectiveName = readUtf(dis, Objective::MAX_NAME_LENGTH); +} + +void SetDisplayObjectivePacket::write(DataOutputStream *dos) +{ + dos->writeByte(slot); + writeUtf(objectiveName, dos); +} + +void SetDisplayObjectivePacket::handle(PacketListener *listener) +{ + listener->handleSetDisplayObjective(shared_from_this()); +} + +int SetDisplayObjectivePacket::getEstimatedSize() +{ + return 1 + 2 + objectiveName.length(); +} \ No newline at end of file diff --git a/Minecraft.World/SetDisplayObjectivePacket.h b/Minecraft.World/SetDisplayObjectivePacket.h new file mode 100644 index 00000000..f32f6386 --- /dev/null +++ b/Minecraft.World/SetDisplayObjectivePacket.h @@ -0,0 +1,24 @@ +#pragma once + +#include "Packet.h" + +class Objective; + +class SetDisplayObjectivePacket : public Packet, public enable_shared_from_this +{ +public: + int slot; + wstring objectiveName; + + SetDisplayObjectivePacket(); + SetDisplayObjectivePacket(int slot, Objective *objective); + + void read(DataInputStream *dis); + void write(DataOutputStream *dos); + void handle(PacketListener *listener); + int getEstimatedSize(); + +public: + static shared_ptr create() { return shared_ptr(new SetDisplayObjectivePacket()); } + virtual int getId() { return 208; } +}; \ No newline at end of file diff --git a/Minecraft.World/SetEntityDataPacket.cpp b/Minecraft.World/SetEntityDataPacket.cpp index 1538c152..9947c163 100644 --- a/Minecraft.World/SetEntityDataPacket.cpp +++ b/Minecraft.World/SetEntityDataPacket.cpp @@ -53,11 +53,6 @@ int SetEntityDataPacket::getEstimatedSize() return 5; } -bool SetEntityDataPacket::isAync() -{ - return true; -} - vector > *SetEntityDataPacket::getUnpackedData() { return packedItems; diff --git a/Minecraft.World/SetEntityDataPacket.h b/Minecraft.World/SetEntityDataPacket.h index 1b31aa4c..a3bb0860 100644 --- a/Minecraft.World/SetEntityDataPacket.h +++ b/Minecraft.World/SetEntityDataPacket.h @@ -21,7 +21,6 @@ public: virtual void write(DataOutputStream *dos); virtual void handle(PacketListener *listener); virtual int getEstimatedSize(); - virtual bool isAync(); vector > *getUnpackedData(); diff --git a/Minecraft.World/SetEntityLinkPacket.cpp b/Minecraft.World/SetEntityLinkPacket.cpp new file mode 100644 index 00000000..cae35e48 --- /dev/null +++ b/Minecraft.World/SetEntityLinkPacket.cpp @@ -0,0 +1,57 @@ +#include "stdafx.h" +#include +#include "InputOutputStream.h" +#include "PacketListener.h" +#include "net.minecraft.world.entity.h" +#include "SetEntityLinkPacket.h" + + + +SetEntityLinkPacket::SetEntityLinkPacket() +{ + sourceId = -1; + destId = -1; + type = -1; +} + +SetEntityLinkPacket::SetEntityLinkPacket(int linkType, shared_ptr sourceEntity, shared_ptr destEntity) +{ + type = linkType; + this->sourceId = sourceEntity->entityId; + this->destId = destEntity != NULL ? destEntity->entityId : -1; +} + +int SetEntityLinkPacket::getEstimatedSize() +{ + return 8; +} + +void SetEntityLinkPacket::read(DataInputStream *dis) //throws IOException +{ + sourceId = dis->readInt(); + destId = dis->readInt(); + type = dis->readUnsignedByte(); +} + +void SetEntityLinkPacket::write(DataOutputStream *dos) //throws IOException +{ + dos->writeInt(sourceId); + dos->writeInt(destId); + dos->writeByte(type); +} + +void SetEntityLinkPacket::handle(PacketListener *listener) +{ + listener->handleEntityLinkPacket(shared_from_this()); +} + +bool SetEntityLinkPacket::canBeInvalidated() +{ + return true; +} + +bool SetEntityLinkPacket::isInvalidatedBy(shared_ptr packet) +{ + shared_ptr target = dynamic_pointer_cast(packet); + return target->sourceId == sourceId; +} diff --git a/Minecraft.World/SetEntityLinkPacket.h b/Minecraft.World/SetEntityLinkPacket.h new file mode 100644 index 00000000..aa92206d --- /dev/null +++ b/Minecraft.World/SetEntityLinkPacket.h @@ -0,0 +1,29 @@ +#pragma once +using namespace std; + +#include "Packet.h" + +class SetEntityLinkPacket : public Packet, public enable_shared_from_this +{ +public: + static const int RIDING = 0; + static const int LEASH = 1; + + int type; + int sourceId, destId; + + SetEntityLinkPacket(); + SetEntityLinkPacket(int linkType, shared_ptr sourceEntity, shared_ptr destEntity); + + virtual int getEstimatedSize(); + virtual void read(DataInputStream *dis); + virtual void write(DataOutputStream *dos); + virtual void handle(PacketListener *listener); + virtual bool canBeInvalidated(); + virtual bool isInvalidatedBy(shared_ptr packet); + +public: + static shared_ptr create() { return shared_ptr(new SetEntityLinkPacket()); } + virtual int getId() { return 39; } + +}; \ No newline at end of file diff --git a/Minecraft.World/SetExperiencePacket.cpp b/Minecraft.World/SetExperiencePacket.cpp index ffe90a67..c5d84b21 100644 --- a/Minecraft.World/SetExperiencePacket.cpp +++ b/Minecraft.World/SetExperiencePacket.cpp @@ -49,11 +49,6 @@ bool SetExperiencePacket::canBeInvalidated() } bool SetExperiencePacket::isInvalidatedBy(shared_ptr packet) -{ - return true; -} - -bool SetExperiencePacket::isAync() { return true; } \ No newline at end of file diff --git a/Minecraft.World/SetExperiencePacket.h b/Minecraft.World/SetExperiencePacket.h index 499b7efd..01c0ed46 100644 --- a/Minecraft.World/SetExperiencePacket.h +++ b/Minecraft.World/SetExperiencePacket.h @@ -18,7 +18,6 @@ public: virtual int getEstimatedSize(); virtual bool canBeInvalidated(); virtual bool isInvalidatedBy(shared_ptr packet); - virtual bool isAync(); public: static shared_ptr create() { return shared_ptr(new SetExperiencePacket()); } diff --git a/Minecraft.World/SetHealthPacket.cpp b/Minecraft.World/SetHealthPacket.cpp index 55d7ccc3..639cacd8 100644 --- a/Minecraft.World/SetHealthPacket.cpp +++ b/Minecraft.World/SetHealthPacket.cpp @@ -8,14 +8,14 @@ SetHealthPacket::SetHealthPacket() { - this->health = 0; + this->health = 0.0f; this->food = 0; this->saturation = 0; this->damageSource = eTelemetryChallenges_Unknown; } -SetHealthPacket::SetHealthPacket(int health, int food, float saturation, ETelemetryChallenges damageSource) +SetHealthPacket::SetHealthPacket(float health, int food, float saturation, ETelemetryChallenges damageSource) { this->health = health; this->food = food; @@ -27,7 +27,7 @@ SetHealthPacket::SetHealthPacket(int health, int food, float saturation, ETeleme void SetHealthPacket::read(DataInputStream *dis) //throws IOException { - health = dis->readShort(); + health = dis->readFloat(); food = dis->readShort(); saturation = dis->readFloat(); // exhaustion = dis.readFloat(); @@ -37,7 +37,7 @@ void SetHealthPacket::read(DataInputStream *dis) //throws IOException void SetHealthPacket::write(DataOutputStream *dos) //throws IOException { - dos->writeShort(health); + dos->writeFloat(health); dos->writeShort(food); dos->writeFloat(saturation); // dos.writeFloat(exhaustion); @@ -52,7 +52,7 @@ void SetHealthPacket::handle(PacketListener *listener) int SetHealthPacket::getEstimatedSize() { - return 9; + return 11; } bool SetHealthPacket::canBeInvalidated() diff --git a/Minecraft.World/SetHealthPacket.h b/Minecraft.World/SetHealthPacket.h index de8f4cb9..4704f220 100644 --- a/Minecraft.World/SetHealthPacket.h +++ b/Minecraft.World/SetHealthPacket.h @@ -6,15 +6,14 @@ using namespace std; class SetHealthPacket : public Packet, public enable_shared_from_this { public: - int health; + float health; int food; float saturation; - // public float exhaustion; // 4J - Original comment ETelemetryChallenges damageSource; // 4J Added SetHealthPacket(); - SetHealthPacket(int health, int food, float saturation, ETelemetryChallenges damageSource); + SetHealthPacket(float health, int food, float saturation, ETelemetryChallenges damageSource); virtual void read(DataInputStream *dis); virtual void write(DataOutputStream *dos); diff --git a/Minecraft.World/SetObjectivePacket.cpp b/Minecraft.World/SetObjectivePacket.cpp new file mode 100644 index 00000000..7e656967 --- /dev/null +++ b/Minecraft.World/SetObjectivePacket.cpp @@ -0,0 +1,42 @@ +#include "stdafx.h" +#include "net.minecraft.world.scores.h" +#include "PacketListener.h" +#include "SetObjectivePacket.h" + +SetObjectivePacket::SetObjectivePacket() +{ + objectiveName = L""; + displayName = L""; + method = 0; +} + +SetObjectivePacket::SetObjectivePacket(Objective *objective, int method) +{ + objectiveName = objective->getName(); + displayName = objective->getDisplayName(); + this->method = method; +} + +void SetObjectivePacket::read(DataInputStream *dis) +{ + objectiveName = readUtf(dis, Objective::MAX_NAME_LENGTH); + displayName = readUtf(dis, Objective::MAX_DISPLAY_NAME_LENGTH); + method = dis->readByte(); +} + +void SetObjectivePacket::write(DataOutputStream *dos) +{ + writeUtf(objectiveName, dos); + writeUtf(displayName, dos); + dos->writeByte(method); +} + +void SetObjectivePacket::handle(PacketListener *listener) +{ + listener->handleAddObjective(shared_from_this()); +} + +int SetObjectivePacket::getEstimatedSize() +{ + return 2 + objectiveName.length() + 2 + displayName.length() + 1; +} \ No newline at end of file diff --git a/Minecraft.World/SetObjectivePacket.h b/Minecraft.World/SetObjectivePacket.h new file mode 100644 index 00000000..5b5dfc6f --- /dev/null +++ b/Minecraft.World/SetObjectivePacket.h @@ -0,0 +1,28 @@ +#pragma once + +#include "Packet.h" + +class Objective; + +class SetObjectivePacket : public Packet, public enable_shared_from_this +{ +public: + static const int METHOD_ADD = 0; + static const int METHOD_REMOVE = 1; + static const int METHOD_CHANGE = 2; + + wstring objectiveName; + wstring displayName; + int method; + + SetObjectivePacket(); + SetObjectivePacket(Objective *objective, int method); + void read(DataInputStream *dis); + void write(DataOutputStream *dos); + void handle(PacketListener *listener); + int getEstimatedSize(); + +public: + static shared_ptr create() { return shared_ptr(new SetObjectivePacket()); } + virtual int getId() { return 206; } +}; \ No newline at end of file diff --git a/Minecraft.World/SetPlayerTeamPacket.cpp b/Minecraft.World/SetPlayerTeamPacket.cpp new file mode 100644 index 00000000..8c605784 --- /dev/null +++ b/Minecraft.World/SetPlayerTeamPacket.cpp @@ -0,0 +1,114 @@ +#include "stdafx.h" +#include "net.minecraft.world.scores.h" +#include "net.minecraft.world.entity.player.h" +#include "PacketListener.h" +#include "SetPlayerTeamPacket.h" + +SetPlayerTeamPacket::SetPlayerTeamPacket() +{ + name = L""; + displayName = L""; + prefix = L""; + suffix = L""; + method = 0; + options = 0; +} + +SetPlayerTeamPacket::SetPlayerTeamPacket(PlayerTeam *team, int method) +{ + name = team->getName(); + this->method = method; + + if (method == METHOD_ADD || method == METHOD_CHANGE) + { + displayName = team->getDisplayName(); + prefix = team->getPrefix(); + suffix = team->getSuffix(); + options = team->packOptions(); + } + if (method == METHOD_ADD) + { + unordered_set *playerNames = team->getPlayers(); + players.insert(players.end(), playerNames->begin(), playerNames->end()); + } +} + +SetPlayerTeamPacket::SetPlayerTeamPacket(PlayerTeam *team, vector *playerNames, int method) +{ + if (method != METHOD_JOIN && method != METHOD_LEAVE) + { + app.DebugPrintf("Method must be join or leave for player constructor"); +#ifndef _CONTENT_PACKAGE + __debugbreak(); +#endif + } + if (playerNames == NULL || playerNames->empty()) + { + app.DebugPrintf("Players cannot be null/empty"); +#ifndef _CONTENT_PACKAGE + __debugbreak(); +#endif + } + + this->method = method; + name = team->getName(); + this->players.insert(players.end(), playerNames->begin(), playerNames->end()); +} + +void SetPlayerTeamPacket::read(DataInputStream *dis) +{ + name = readUtf(dis, Objective::MAX_NAME_LENGTH); + method = dis->readByte(); + + if (method == METHOD_ADD || method == METHOD_CHANGE) + { + displayName = readUtf(dis, PlayerTeam::MAX_DISPLAY_NAME_LENGTH); + prefix = readUtf(dis, PlayerTeam::MAX_PREFIX_LENGTH); + suffix = readUtf(dis, PlayerTeam::MAX_SUFFIX_LENGTH); + options = dis->readByte(); + } + + if (method == METHOD_ADD || method == METHOD_JOIN || method == METHOD_LEAVE) + { + int count = dis->readShort(); + + for (int i = 0; i < count; i++) + { + players.push_back(readUtf(dis, Player::MAX_NAME_LENGTH)); + } + } +} + +void SetPlayerTeamPacket::write(DataOutputStream *dos) +{ + writeUtf(name, dos); + dos->writeByte(method); + + if (method == METHOD_ADD || method == METHOD_CHANGE) + { + writeUtf(displayName, dos); + writeUtf(prefix, dos); + writeUtf(suffix, dos); + dos->writeByte(options); + } + + if (method == METHOD_ADD || method == METHOD_JOIN || method == METHOD_LEAVE) + { + dos->writeShort(players.size()); + + for (AUTO_VAR(it,players.begin()); it != players.end(); ++it) + { + writeUtf(*it, dos); + } + } +} + +void SetPlayerTeamPacket::handle(PacketListener *listener) +{ + listener->handleSetPlayerTeamPacket(shared_from_this()); +} + +int SetPlayerTeamPacket::getEstimatedSize() +{ + return 1 + 2 + name.length(); +} \ No newline at end of file diff --git a/Minecraft.World/SetPlayerTeamPacket.h b/Minecraft.World/SetPlayerTeamPacket.h new file mode 100644 index 00000000..f6df9da2 --- /dev/null +++ b/Minecraft.World/SetPlayerTeamPacket.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Packet.h" + +class PlayerTeam; + +class SetPlayerTeamPacket : public Packet , public enable_shared_from_this +{ +public: + static const int METHOD_ADD = 0; + static const int METHOD_REMOVE = 1; + static const int METHOD_CHANGE = 2; + static const int METHOD_JOIN = 3; + static const int METHOD_LEAVE = 4; + + wstring name; + wstring displayName; + wstring prefix; + wstring suffix; + vector players; + int method; + int options; + + SetPlayerTeamPacket(); + SetPlayerTeamPacket(PlayerTeam *team, int method); + SetPlayerTeamPacket(PlayerTeam *team, vector *players, int method); + void read(DataInputStream *dis); + void write(DataOutputStream *dos); + void handle(PacketListener *listener); + int getEstimatedSize(); + +public: + static shared_ptr create() { return shared_ptr(new SetPlayerTeamPacket()); } + virtual int getId() { return 209; } +}; \ No newline at end of file diff --git a/Minecraft.World/SetPlayerTimeoutCommand.h b/Minecraft.World/SetPlayerTimeoutCommand.h new file mode 100644 index 00000000..4bc83e66 --- /dev/null +++ b/Minecraft.World/SetPlayerTimeoutCommand.h @@ -0,0 +1,36 @@ +/* +package net.minecraft.commands.common; + +import net.minecraft.commands.BaseCommand; +import net.minecraft.commands.CommandSender; +import net.minecraft.commands.exceptions.UsageException; +import net.minecraft.server.MinecraftServer; + +public class SetPlayerTimeoutCommand extends BaseCommand { + public String getName() { + return "setidletimeout"; + } + + @Override + public int getPermissionLevel() { + return LEVEL_ADMINS; + } + + @Override + public String getUsage(CommandSender source) { + return "commands.setidletimeout.usage"; + } + + public void execute(CommandSender source, String[] args) { + if (args.length == 1) { + int timeout = convertArgToInt(source, args[0], 0); + MinecraftServer.getInstance().setPlayerIdleTimeout(timeout); + logAdminAction(source, "commands.setidletimeout.success", timeout); + return; + } + + throw new UsageException("commands.setidletimeout.usage"); + } +} + +*/ \ No newline at end of file diff --git a/Minecraft.World/SetScorePacket.cpp b/Minecraft.World/SetScorePacket.cpp new file mode 100644 index 00000000..75887eb5 --- /dev/null +++ b/Minecraft.World/SetScorePacket.cpp @@ -0,0 +1,63 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.scores.h" +#include "PacketListener.h" +#include "SetScorePacket.h" + +SetScorePacket::SetScorePacket() +{ + owner = L""; + objectiveName = L""; + score = 0; + method = 0; +} + +SetScorePacket::SetScorePacket(Score *score, int method) +{ + owner = score->getOwner(); + objectiveName = score->getObjective()->getName(); + this->score = score->getScore(); + this->method = method; +} + +SetScorePacket::SetScorePacket(const wstring &owner) +{ + this->owner = owner; + objectiveName = L""; + score = 0; + method = METHOD_REMOVE; +} + +void SetScorePacket::read(DataInputStream *dis) +{ + owner = readUtf(dis, Player::MAX_NAME_LENGTH); + method = dis->readByte(); + + if (method != METHOD_REMOVE) + { + objectiveName = readUtf(dis, Objective::MAX_NAME_LENGTH); + score = dis->readInt(); + } +} + +void SetScorePacket::write(DataOutputStream *dos) +{ + writeUtf(owner, dos); + dos->writeByte(method); + + if (method != METHOD_REMOVE) + { + writeUtf(objectiveName, dos); + dos->writeInt(score); + } +} + +void SetScorePacket::handle(PacketListener *listener) +{ + listener->handleSetScore(shared_from_this()); +} + +int SetScorePacket::getEstimatedSize() +{ + return 2 + (owner.empty() ? 0 : owner.length()) + 2 + (objectiveName.empty() ? 0 : objectiveName.length()) + 4 + 1; +} \ No newline at end of file diff --git a/Minecraft.World/SetScorePacket.h b/Minecraft.World/SetScorePacket.h new file mode 100644 index 00000000..5f800be6 --- /dev/null +++ b/Minecraft.World/SetScorePacket.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Packet.h" + +class Score; + +class SetScorePacket : public Packet , public enable_shared_from_this +{ +public: + static const int METHOD_CHANGE = 0; + static const int METHOD_REMOVE = 1; + + wstring owner; + wstring objectiveName; + int score; + int method; + + SetScorePacket(); + SetScorePacket(Score *score, int method); + SetScorePacket(const wstring &owner); + + void read(DataInputStream *dis); + void write(DataOutputStream *dos); + void handle(PacketListener *listener); + int getEstimatedSize(); + +public: + static shared_ptr create() { return shared_ptr(new SetScorePacket()); } + virtual int getId() { return 207; } +}; \ No newline at end of file diff --git a/Minecraft.World/SetTimePacket.cpp b/Minecraft.World/SetTimePacket.cpp index 2f707970..5936255c 100644 --- a/Minecraft.World/SetTimePacket.cpp +++ b/Minecraft.World/SetTimePacket.cpp @@ -4,26 +4,38 @@ #include "PacketListener.h" #include "SetTimePacket.h" - - SetTimePacket::SetTimePacket() { - time = 0; + gameTime = 0; + dayTime = 0; } -SetTimePacket::SetTimePacket(__int64 time) +SetTimePacket::SetTimePacket(__int64 gameTime, __int64 dayTime, bool tickDayTime) { - this->time = time; + this->gameTime = gameTime; + this->dayTime = dayTime; + + // 4J: We send daylight cycle rule with host options so don't need this + /*if (!tickDayTime) + { + this->dayTime = -this->dayTime; + if (this->dayTime == 0) + { + this->dayTime = -1; + } + }*/ } void SetTimePacket::read(DataInputStream *dis) //throws IOException { - time = dis->readLong(); + gameTime = dis->readLong(); + dayTime = dis->readLong(); } void SetTimePacket::write(DataOutputStream *dos) //throws IOException { - dos->writeLong(time); + dos->writeLong(gameTime); + dos->writeLong(dayTime); } void SetTimePacket::handle(PacketListener *listener) @@ -33,7 +45,7 @@ void SetTimePacket::handle(PacketListener *listener) int SetTimePacket::getEstimatedSize() { - return 8; + return 16; } bool SetTimePacket::canBeInvalidated() diff --git a/Minecraft.World/SetTimePacket.h b/Minecraft.World/SetTimePacket.h index 5b658a0b..7ded9ce1 100644 --- a/Minecraft.World/SetTimePacket.h +++ b/Minecraft.World/SetTimePacket.h @@ -6,10 +6,11 @@ using namespace std; class SetTimePacket : public Packet, public enable_shared_from_this { public: - __int64 time; + __int64 gameTime; + __int64 dayTime; SetTimePacket(); - SetTimePacket(__int64 time); + SetTimePacket(__int64 gameTime, __int64 dayTime, bool tickDayTime); virtual void read(DataInputStream *dis); virtual void write(DataOutputStream *dos); diff --git a/Minecraft.World/SharedConstants.cpp b/Minecraft.World/SharedConstants.cpp index 497822bc..00ff3a05 100644 --- a/Minecraft.World/SharedConstants.cpp +++ b/Minecraft.World/SharedConstants.cpp @@ -3,7 +3,7 @@ #include "InputOutputStream.h" #include "SharedConstants.h" -const wstring SharedConstants::VERSION_STRING = L"1.2.3"; +const wstring SharedConstants::VERSION_STRING = L"1.6.4"; const bool SharedConstants::TEXTURE_LIGHTING = true; wstring SharedConstants::readAcceptableChars() diff --git a/Minecraft.World/SharedConstants.h b/Minecraft.World/SharedConstants.h index bd6dae89..a8924e47 100644 --- a/Minecraft.World/SharedConstants.h +++ b/Minecraft.World/SharedConstants.h @@ -7,7 +7,8 @@ class SharedConstants public: static void staticCtor(); static const wstring VERSION_STRING; - static const int NETWORK_PROTOCOL_VERSION = 39; + static const int NETWORK_PROTOCOL_VERSION = 78; + static const bool INGAME_DEBUG_OUTPUT = false; // NOT texture resolution. How many sub-blocks each block face is made up of. // 4J Added for texture packs diff --git a/Minecraft.World/SharedMonsterAttributes.cpp b/Minecraft.World/SharedMonsterAttributes.cpp new file mode 100644 index 00000000..f434f1e7 --- /dev/null +++ b/Minecraft.World/SharedMonsterAttributes.cpp @@ -0,0 +1,108 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "BasicTypeContainers.h" +#include "SharedMonsterAttributes.h" + +Attribute *SharedMonsterAttributes::MAX_HEALTH = (new RangedAttribute(eAttributeId_GENERIC_MAXHEALTH, 20, 0, Double::MAX_VALUE))->setSyncable(true); +Attribute *SharedMonsterAttributes::FOLLOW_RANGE = (new RangedAttribute(eAttributeId_GENERIC_FOLLOWRANGE, 32, 0, 2048)); +Attribute *SharedMonsterAttributes::KNOCKBACK_RESISTANCE = (new RangedAttribute(eAttributeId_GENERIC_KNOCKBACKRESISTANCE, 0, 0, 1)); +Attribute *SharedMonsterAttributes::MOVEMENT_SPEED = (new RangedAttribute(eAttributeId_GENERIC_MOVEMENTSPEED, 0.7f, 0, Double::MAX_VALUE))->setSyncable(true); +Attribute *SharedMonsterAttributes::ATTACK_DAMAGE = new RangedAttribute(eAttributeId_GENERIC_ATTACKDAMAGE, 2, 0, Double::MAX_VALUE); + +ListTag *SharedMonsterAttributes::saveAttributes(BaseAttributeMap *attributes) +{ + ListTag *list = new ListTag(); + + vector atts; + attributes->getAttributes(atts); + for (AUTO_VAR(it, atts.begin()); it != atts.end(); ++it) + { + AttributeInstance *attribute = *it; + list->add(saveAttribute(attribute)); + } + + return list; +} + +CompoundTag *SharedMonsterAttributes::saveAttribute(AttributeInstance *instance) +{ + CompoundTag *tag = new CompoundTag(); + Attribute *attribute = instance->getAttribute(); + + tag->putInt(L"ID", attribute->getId()); + tag->putDouble(L"Base", instance->getBaseValue()); + + unordered_set modifiers; + instance->getModifiers(modifiers); + + if (!modifiers.empty()) + { + ListTag *list = new ListTag(); + + for (AUTO_VAR(it,modifiers.begin()); it != modifiers.end(); ++it) + { + AttributeModifier* modifier = *it; + if (modifier->isSerializable()) + { + list->add(saveAttributeModifier(modifier)); + } + } + + tag->put(L"Modifiers", list); + } + + return tag; +} + +CompoundTag *SharedMonsterAttributes::saveAttributeModifier(AttributeModifier *modifier) +{ + CompoundTag *tag = new CompoundTag(); + + tag->putDouble(L"Amount", modifier->getAmount()); + tag->putInt(L"Operation", modifier->getOperation()); + tag->putInt(L"UUID", modifier->getId()); + + return tag; +} + +void SharedMonsterAttributes::loadAttributes(BaseAttributeMap *attributes, ListTag *list) +{ + for (int i = 0; i < list->size(); i++) + { + CompoundTag *tag = list->get(i); + AttributeInstance *instance = attributes->getInstance(static_cast(tag->getInt(L"ID"))); + + if (instance != NULL) + { + loadAttribute(instance, tag); + } + else + { + app.DebugPrintf("Ignoring unknown attribute '%d'", tag->getInt(L"ID") ); + } + } +} + +void SharedMonsterAttributes::loadAttribute(AttributeInstance *instance, CompoundTag *tag) +{ + instance->setBaseValue(tag->getDouble(L"Base")); + + if (tag->contains(L"Modifiers")) + { + ListTag *list = (ListTag *) tag->getList(L"Modifiers"); + + for (int i = 0; i < list->size(); i++) + { + AttributeModifier *modifier = loadAttributeModifier(list->get(i)); + AttributeModifier *old = instance->getModifier(modifier->getId()); + if (old != NULL) instance->removeModifier(old); + instance->addModifier(modifier); + } + } +} + +AttributeModifier *SharedMonsterAttributes::loadAttributeModifier(CompoundTag *tag) +{ + eMODIFIER_ID id = (eMODIFIER_ID)tag->getInt(L"UUID"); + return new AttributeModifier(id, tag->getDouble(L"Amount"), tag->getInt(L"Operation")); +} \ No newline at end of file diff --git a/Minecraft.World/SharedMonsterAttributes.h b/Minecraft.World/SharedMonsterAttributes.h new file mode 100644 index 00000000..7195462e --- /dev/null +++ b/Minecraft.World/SharedMonsterAttributes.h @@ -0,0 +1,26 @@ +#pragma once + +class SharedMonsterAttributes +{ +public: + static Attribute *MAX_HEALTH; + static Attribute *FOLLOW_RANGE; + static Attribute *KNOCKBACK_RESISTANCE; + static Attribute *MOVEMENT_SPEED; + static Attribute *ATTACK_DAMAGE; + + static ListTag *saveAttributes(BaseAttributeMap *attributes); + +private: + static CompoundTag *saveAttribute(AttributeInstance *instance); + static CompoundTag *saveAttributeModifier(AttributeModifier *modifier); + +public: + static void loadAttributes(BaseAttributeMap *attributes, ListTag *list); + +private: + static void loadAttribute(AttributeInstance *instance, CompoundTag *tag); + +public: + static AttributeModifier *loadAttributeModifier(CompoundTag *tag); +}; \ No newline at end of file diff --git a/Minecraft.World/ShearsItem.cpp b/Minecraft.World/ShearsItem.cpp index 7f4d8d51..dd0c2ac7 100644 --- a/Minecraft.World/ShearsItem.cpp +++ b/Minecraft.World/ShearsItem.cpp @@ -9,14 +9,14 @@ ShearsItem::ShearsItem(int itemId) : Item(itemId) setMaxDamage(238); } -bool ShearsItem::mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner) +bool ShearsItem::mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner) { - if (tile == Tile::leaves_Id || tile == Tile::web_Id || tile == Tile::tallgrass_Id || tile == Tile::vine_Id || tile == Tile::tripWire_Id) + if (tile == Tile::leaves_Id || tile == Tile::web_Id || tile == Tile::tallgrass_Id || tile == Tile::vine_Id || tile == Tile::tripWire_Id) { - itemInstance->hurt(1, owner); + itemInstance->hurtAndBreak(1, owner); return true; - } - return Item::mineBlock(itemInstance, level, tile, x, y, z, owner); + } + return Item::mineBlock(itemInstance, level, tile, x, y, z, owner); } bool ShearsItem::canDestroySpecial(Tile *tile) @@ -26,13 +26,13 @@ bool ShearsItem::canDestroySpecial(Tile *tile) float ShearsItem::getDestroySpeed(shared_ptr itemInstance, Tile *tile) { - if (tile->id == Tile::web_Id || tile->id == Tile::leaves_Id) + if (tile->id == Tile::web_Id || tile->id == Tile::leaves_Id) { - return 15; - } - if (tile->id == Tile::cloth_Id) + return 15; + } + if (tile->id == Tile::wool_Id) { - return 5; - } - return Item::getDestroySpeed(itemInstance, tile); + return 5; + } + return Item::getDestroySpeed(itemInstance, tile); } \ No newline at end of file diff --git a/Minecraft.World/ShearsItem.h b/Minecraft.World/ShearsItem.h index 06078645..3bf0c46f 100644 --- a/Minecraft.World/ShearsItem.h +++ b/Minecraft.World/ShearsItem.h @@ -7,7 +7,7 @@ class ShearsItem : public Item { public: ShearsItem(int itemId); - virtual bool mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner); + virtual bool mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner); virtual bool canDestroySpecial(Tile *tile); virtual float getDestroySpeed(shared_ptr itemInstance, Tile *tile); }; \ No newline at end of file diff --git a/Minecraft.World/Sheep.cpp b/Minecraft.World/Sheep.cpp index 30eeefcd..32379c2a 100644 --- a/Minecraft.World/Sheep.cpp +++ b/Minecraft.World/Sheep.cpp @@ -1,5 +1,3 @@ -using namespace std; - #include "stdafx.h" #include "com.mojang.nbt.h" #include "net.minecraft.world.level.tile.h" @@ -8,6 +6,7 @@ using namespace std; #include "net.minecraft.world.item.h" #include "net.minecraft.world.item.crafting.h" #include "net.minecraft.world.inventory.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.entity.ai.navigation.h" #include "net.minecraft.world.entity.h" @@ -15,12 +14,13 @@ using namespace std; #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.entity.global.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "Sheep.h" #include "..\Minecraft.Client\Textures.h" #include "MobCategory.h" #include "GenericStats.h" -const float Sheep::COLOR[][3] = +const float Sheep::COLOR[Sheep::COLOR_LENGTH][3] = { { 1.0f, 1.0f, 1.0f }, // white { 0.85f, 0.5f, 0.2f }, // orange @@ -45,26 +45,23 @@ Sheep::Sheep(Level *level) : Animal( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_SHEEP; // 4J - was L"/mob/sheep.png"; - this->setSize(0.9f, 1.3f); + setSize(0.9f, 1.3f); eatAnimationTick = 0; eatTileGoal = new EatTileGoal(this); - float walkSpeed = 0.23f; getNavigation()->setAvoidWater(true); goalSelector.addGoal(0, new FloatGoal(this)); - goalSelector.addGoal(1, new PanicGoal(this, 0.38f)); - goalSelector.addGoal(2, new BreedGoal(this, walkSpeed)); - goalSelector.addGoal(3, new TemptGoal(this, 0.25f, Item::wheat_Id, false)); - goalSelector.addGoal(4, new FollowParentGoal(this, 0.25f)); + goalSelector.addGoal(1, new PanicGoal(this, 1.25)); + goalSelector.addGoal(2, new BreedGoal(this, 1.0)); + goalSelector.addGoal(3, new TemptGoal(this, 1.1, Item::wheat_Id, false)); + goalSelector.addGoal(4, new FollowParentGoal(this, 1.1)); goalSelector.addGoal(5, eatTileGoal, false); - goalSelector.addGoal(6, new RandomStrollGoal(this, walkSpeed)); + goalSelector.addGoal(6, new RandomStrollGoal(this, 1.0)); goalSelector.addGoal(7, new LookAtPlayerGoal(this, typeid(Player), 6)); goalSelector.addGoal(8, new RandomLookAroundGoal(this)); @@ -90,9 +87,12 @@ void Sheep::aiStep() Animal::aiStep(); } -int Sheep::getMaxHealth() +void Sheep::registerAttributes() { - return 8; + Animal::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(8); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.23f); } void Sheep::defineSynchedData() @@ -108,13 +108,13 @@ void Sheep::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) if(!isSheared()) { // killing a non-sheared sheep will drop a single block of cloth - spawnAtLocation(shared_ptr( new ItemInstance(Tile::cloth_Id, 1, getColor()) ), 0.0f); + spawnAtLocation(shared_ptr( new ItemInstance(Tile::wool_Id, 1, getColor()) ), 0.0f); } } int Sheep::getDeathLoot() { - return Tile::cloth_Id; + return Tile::wool_Id; } void Sheep::handleEntityEvent(byte id) @@ -160,35 +160,36 @@ float Sheep::getHeadEatAngleScale(float a) return ((xRot / (180.0f / PI))); } -bool Sheep::interact(shared_ptr player) +bool Sheep::mobInteract(shared_ptr player) { - shared_ptr item = player->inventory->getSelected(); + shared_ptr item = player->inventory->getSelected(); // 4J-JEV: Fix for #88212, // Untrusted players shouldn't be able to sheer sheep. if (!player->isAllowedToInteract( shared_from_this() )) return false; //Animal::interact(player); - if (item != NULL && item->id == Item::shears->id && !isSheared() && !isBaby()) + if (item != NULL && item->id == Item::shears->id && !isSheared() && !isBaby()) { - if (!level->isClientSide) + if (!level->isClientSide) { - setSheared(true); - int count = 1 + random->nextInt(3); - for (int i = 0; i < count; i++) + setSheared(true); + int count = 1 + random->nextInt(3); + for (int i = 0; i < count; i++) { - shared_ptr ie = spawnAtLocation(shared_ptr( new ItemInstance(Tile::cloth_Id, 1, getColor()) ), 1.0f); - ie->yd += random->nextFloat() * 0.05f; - ie->xd += (random->nextFloat() - random->nextFloat()) * 0.1f; - ie->zd += (random->nextFloat() - random->nextFloat()) * 0.1f; - } + shared_ptr ie = spawnAtLocation(shared_ptr( new ItemInstance(Tile::wool_Id, 1, getColor()) ), 1.0f); + ie->yd += random->nextFloat() * 0.05f; + ie->xd += (random->nextFloat() - random->nextFloat()) * 0.1f; + ie->zd += (random->nextFloat() - random->nextFloat()) * 0.1f; + } player->awardStat( GenericStats::shearedEntity(eTYPE_SHEEP), GenericStats::param_shearedEntity(eTYPE_SHEEP) ); - } - item->hurt(1, player); - } + } + item->hurtAndBreak(1, player); + playSound(eSoundType_MOB_SHEEP_SHEAR, 1, 1); + } - return Animal::interact(player); + return Animal::mobInteract(player); } void Sheep::addAdditonalSaveData(CompoundTag *tag) @@ -220,6 +221,11 @@ int Sheep::getDeathSound() return eSoundType_MOB_SHEEP_AMBIENT; } +void Sheep::playStepSound(int xt, int yt, int zt, int t) +{ + playSound(eSoundType_MOB_SHEEP_STEP, 0.15f, 1); +} + int Sheep::getColor() { return (entityData->getByte(DATA_WOOL_ID) & 0x0f); @@ -295,18 +301,16 @@ void Sheep::ate() if (isBaby()) { // remove a minute from aging - int age = getAge() + SharedConstants::TICKS_PER_SECOND * 60; - if (age > 0) - { - age = 0; - } - setAge(age); + ageUp(60); } } -void Sheep::finalizeMobSpawn() +MobGroupData *Sheep::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param { - setColor(Sheep::getSheepColor(level->random)); + groupData = Animal::finalizeMobSpawn(groupData); + + setColor(getSheepColor(level->random)); + return groupData; } int Sheep::getOffspringColor(shared_ptr animal, shared_ptr partner) diff --git a/Minecraft.World/Sheep.h b/Minecraft.World/Sheep.h index 666e1d57..16ecfb4c 100644 --- a/Minecraft.World/Sheep.h +++ b/Minecraft.World/Sheep.h @@ -31,7 +31,8 @@ private: EatTileGoal *eatTileGoal; public: - static const float COLOR[][3]; + static const int COLOR_LENGTH = 16; + static const float COLOR[COLOR_LENGTH][3]; public: Sheep(Level *level); @@ -42,9 +43,9 @@ protected: public: void aiStep(); - virtual int getMaxHealth(); protected: + virtual void registerAttributes(); virtual void defineSynchedData(); public: @@ -58,7 +59,7 @@ public: float getHeadEatPositionScale(float a); float getHeadEatAngleScale(float a); - virtual bool interact(shared_ptr player); + virtual bool mobInteract(shared_ptr player); virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); @@ -66,6 +67,7 @@ protected: virtual int getAmbientSound(); virtual int getHurtSound(); virtual int getDeathSound(); + virtual void playStepSound(int xt, int yt, int zt, int t); public: int getColor(); @@ -78,7 +80,7 @@ public: virtual void ate(); - void finalizeMobSpawn(); + MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param private: int getOffspringColor(shared_ptr animal, shared_ptr partner); diff --git a/Minecraft.World/ShortTag.h b/Minecraft.World/ShortTag.h index bfd7511b..989e1fb1 100644 --- a/Minecraft.World/ShortTag.h +++ b/Minecraft.World/ShortTag.h @@ -9,7 +9,7 @@ public: ShortTag(const wstring &name, int data) : Tag(name) {this->data = data; } void write(DataOutput *dos) { dos->writeShort(data); } - void load(DataInput *dis) { data = dis->readShort(); } + void load(DataInput *dis, int tagDepth) { data = dis->readShort(); } byte getId() { return TAG_Short; } wstring toString() diff --git a/Minecraft.World/ShovelItem.cpp b/Minecraft.World/ShovelItem.cpp index 79981bd1..8064cbe3 100644 --- a/Minecraft.World/ShovelItem.cpp +++ b/Minecraft.World/ShovelItem.cpp @@ -16,8 +16,7 @@ void ShovelItem::staticCtor() diggables->data[5] = Tile::snow; diggables->data[6] = Tile::clay; diggables->data[7] = Tile::farmland; - // 4J - brought forward from 1.2.3 - diggables->data[8] = Tile::hellSand; + diggables->data[8] = Tile::soulsand; diggables->data[9] = Tile::mycel; } diff --git a/Minecraft.World/ShowSeedCommand.h b/Minecraft.World/ShowSeedCommand.h new file mode 100644 index 00000000..fa7b3078 --- /dev/null +++ b/Minecraft.World/ShowSeedCommand.h @@ -0,0 +1,38 @@ +/* +package net.minecraft.commands.common; + +import net.minecraft.commands.*; +import net.minecraft.network.chat.ChatMessageComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; + +public class ShowSeedCommand extends BaseCommand { + @Override + public boolean canExecute(CommandSender source) { + return MinecraftServer.getInstance().isSingleplayer() || super.canExecute(source); + } + + @Override + public String getName() { + return "seed"; + } + + @Override + public int getPermissionLevel() { + return LEVEL_GAMEMASTERS; + } + + @Override + public String getUsage(CommandSender source) { + return "commands.seed.usage"; + } + + @Override + public void execute(CommandSender source, String[] args) { + Level level = source instanceof Player ? ((Player) source).level : MinecraftServer.getInstance().getLevel(0); + source.sendMessage(ChatMessageComponent.forTranslation("commands.seed.success", level.getSeed())); + } +} + +*/ \ No newline at end of file diff --git a/Minecraft.World/SignItem.cpp b/Minecraft.World/SignItem.cpp index 02ccf83d..c9cb627e 100644 --- a/Minecraft.World/SignItem.cpp +++ b/Minecraft.World/SignItem.cpp @@ -26,20 +26,25 @@ bool SignItem::useOn(shared_ptr instance, shared_ptr playe if (face == 4) x--; if (face == 5) x++; - if (!player->mayBuild(x, y, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, instance)) return false; if (!Tile::sign->mayPlace(level, x, y, z)) return false; + if (level->isClientSide) + { + return true; + } + if(!bTestUseOnOnly) { if (face == 1) { int rot = Mth::floor(((player->yRot + 180) * 16) / 360 + 0.5) & 15; - level->setTileAndData(x, y, z, Tile::sign_Id, rot); + level->setTileAndData(x, y, z, Tile::sign_Id, rot, Tile::UPDATE_ALL); } else { - level->setTileAndData(x, y, z, Tile::wallSign_Id, face); + level->setTileAndData(x, y, z, Tile::wallSign_Id, face, Tile::UPDATE_ALL); } instance->count--; diff --git a/Minecraft.World/SignTile.cpp b/Minecraft.World/SignTile.cpp index 52dc1260..52d62a60 100644 --- a/Minecraft.World/SignTile.cpp +++ b/Minecraft.World/SignTile.cpp @@ -5,7 +5,7 @@ #include "SignTileEntity.h" #include "SignTile.h" -SignTile::SignTile(int id, eINSTANCEOF clas, bool onGround) : EntityTile(id, Material::wood, isSolidRender()) +SignTile::SignTile(int id, eINSTANCEOF clas, bool onGround) : BaseEntityTile(id, Material::wood, isSolidRender()) { this->onGround = onGround; this->clas = clas; @@ -32,7 +32,7 @@ AABB *SignTile::getAABB(Level *level, int x, int y, int z) AABB *SignTile::getTileAABB(Level *level, int x, int y, int z) { updateShape(level, x, y, z); - return EntityTile::getTileAABB(level, x, y, z); + return BaseEntityTile::getTileAABB(level, x, y, z); } void SignTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param @@ -112,10 +112,10 @@ void SignTile::neighborChanged(Level *level, int x, int y, int z, int type) if (remove) { spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); } - EntityTile::neighborChanged(level, x, y, z, type); + BaseEntityTile::neighborChanged(level, x, y, z, type); } int SignTile::cloneTileId(Level *level, int x, int y, int z) diff --git a/Minecraft.World/SignTile.h b/Minecraft.World/SignTile.h index 92163973..4d9dce62 100644 --- a/Minecraft.World/SignTile.h +++ b/Minecraft.World/SignTile.h @@ -1,12 +1,12 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" #include "TileEntity.h" #include "stdafx.h" #include "Material.h" -class SignTile : public EntityTile +class SignTile : public BaseEntityTile { friend class Tile; private: diff --git a/Minecraft.World/SignTileEntity.cpp b/Minecraft.World/SignTileEntity.cpp index 09b8e022..74adc8cc 100644 --- a/Minecraft.World/SignTileEntity.cpp +++ b/Minecraft.World/SignTileEntity.cpp @@ -30,6 +30,8 @@ SignTileEntity::SignTileEntity() : TileEntity() m_iSelectedLine = -1; _isEditable = true; + + playerWhoMayEdit = nullptr; } SignTileEntity::~SignTileEntity() @@ -102,6 +104,20 @@ bool SignTileEntity::isEditable() void SignTileEntity::setEditable(bool isEditable) { this->_isEditable = isEditable; + if (!isEditable) + { + playerWhoMayEdit = nullptr; + } +} + +void SignTileEntity::setAllowedPlayerEditor(shared_ptr player) +{ + playerWhoMayEdit = player; +} + +shared_ptr SignTileEntity::getPlayerWhoMayEdit() +{ + return playerWhoMayEdit; } void SignTileEntity::setChanged() diff --git a/Minecraft.World/SignTileEntity.h b/Minecraft.World/SignTileEntity.h index b963f12f..9b06aaab 100644 --- a/Minecraft.World/SignTileEntity.h +++ b/Minecraft.World/SignTileEntity.h @@ -28,6 +28,7 @@ public: public: private: + shared_ptr playerWhoMayEdit; bool _isEditable; bool m_bVerified; bool m_bCensored; @@ -41,6 +42,8 @@ public: virtual shared_ptr getUpdatePacket(); bool isEditable(); void setEditable(bool isEditable); + void setAllowedPlayerEditor(shared_ptr player); + shared_ptr getPlayerWhoMayEdit(); virtual void setChanged(); static int StringVerifyCallback(LPVOID lpParam,STRING_VERIFY_RESPONSE *pResults); diff --git a/Minecraft.World/Silverfish.cpp b/Minecraft.World/Silverfish.cpp index 117dc41b..5cd4c77e 100644 --- a/Minecraft.World/Silverfish.cpp +++ b/Minecraft.World/Silverfish.cpp @@ -3,6 +3,8 @@ #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.h" #include "..\Minecraft.Client\Textures.h" #include "Silverfish.h" @@ -15,21 +17,19 @@ Silverfish::Silverfish(Level *level) : Monster( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_SILVERFISH;// 4J was "/mob/silverfish.png"; - this->setSize(0.3f, 0.7f); - runSpeed = 0.6f; - - // 4J - Brought forward damage from 1.2.3 - attackDamage = 1; + setSize(0.3f, 0.7f); } -int Silverfish::getMaxHealth() +void Silverfish::registerAttributes() { - return 8; + Monster::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(8); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.6f); + getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(1); } bool Silverfish::makeStepSound() @@ -69,8 +69,9 @@ int Silverfish::getDeathSound() } -bool Silverfish::hurt(DamageSource *source, int dmg) +bool Silverfish::hurt(DamageSource *source, float dmg) { + if (isInvulnerable()) return false; if (lookForFriends <= 0 && (dynamic_cast(source) != NULL || source == DamageSource::magic)) { // look for friends @@ -86,16 +87,14 @@ void Silverfish::checkHurtTarget(shared_ptr target, float d) if (attackTime <= 0 && d < 1.2f && target->bb->y1 > bb->y0 && target->bb->y0 < bb->y1) { attackTime = 20; - DamageSource *damageSource = DamageSource::mobAttack( dynamic_pointer_cast( shared_from_this() ) ); - target->hurt(damageSource, attackDamage); - delete damageSource; + doHurtTarget(target); } } void Silverfish::playStepSound(int xt, int yt, int zt, int t) { - level->playSound(shared_from_this(), eSoundType_MOB_SILVERFISH_STEP, 1, 1); + playSound(eSoundType_MOB_SILVERFISH_STEP, 0.15f, 1); } int Silverfish::getDeathLoot() @@ -140,9 +139,26 @@ void Silverfish::serverAiStep() int tile = level->getTile(baseX + xOff, baseY + yOff, baseZ + zOff); if (tile == Tile::monsterStoneEgg_Id) { - level->levelEvent(LevelEvent::PARTICLES_DESTROY_BLOCK, baseX + xOff, baseY + yOff, baseZ + zOff, - Tile::monsterStoneEgg_Id + (level->getData(baseX + xOff, baseY + yOff, baseZ + zOff) << Tile::TILE_NUM_SHIFT)); - level->setTile(baseX + xOff, baseY + yOff, baseZ + zOff, 0); + if (!level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) + { + int data = level->getData(baseX + xOff, baseY + yOff, baseZ + zOff); + + Tile *restoreTile = Tile::stone; + if (data == StoneMonsterTile::HOST_COBBLE) + { + restoreTile = Tile::cobblestone; + } + if (data == StoneMonsterTile::HOST_STONEBRICK) + { + restoreTile = Tile::stoneBrick; + } + + level->setTileAndData(baseX + xOff, baseY + yOff, baseZ + zOff, restoreTile->id, 0, Tile::UPDATE_ALL); + } + else + { + level->destroyTile(baseX + xOff, baseY + yOff, baseZ + zOff, false); + } Tile::monsterStoneEgg->destroy(level, baseX + xOff, baseY + yOff, baseZ + zOff, 0); if (random->nextBoolean()) @@ -167,7 +183,7 @@ void Silverfish::serverAiStep() int tile = level->getTile(tileX + Facing::STEP_X[facing], tileY + Facing::STEP_Y[facing], tileZ + Facing::STEP_Z[facing]); if (StoneMonsterTile::isCompatibleHostBlock(tile)) { - level->setTileAndData(tileX + Facing::STEP_X[facing], tileY + Facing::STEP_Y[facing], tileZ + Facing::STEP_Z[facing], Tile::monsterStoneEgg_Id, StoneMonsterTile::getDataForHostBlock(tile)); + level->setTileAndData(tileX + Facing::STEP_X[facing], tileY + Facing::STEP_Y[facing], tileZ + Facing::STEP_Z[facing], Tile::monsterStoneEgg_Id, StoneMonsterTile::getDataForHostBlock(tile), Tile::UPDATE_ALL); spawnAnim(); remove(); } @@ -186,7 +202,7 @@ void Silverfish::serverAiStep() float Silverfish::getWalkTargetValue(int x, int y, int z) { // silverfish LOVES stone =) - if (level->getTile(x, y - 1, z) == Tile::rock_Id) return 10; + if (level->getTile(x, y - 1, z) == Tile::stone_Id) return 10; return Monster::getWalkTargetValue(x, y, z); } diff --git a/Minecraft.World/Silverfish.h b/Minecraft.World/Silverfish.h index 0fd0cc06..e954fff1 100644 --- a/Minecraft.World/Silverfish.h +++ b/Minecraft.World/Silverfish.h @@ -13,9 +13,8 @@ private: public: Silverfish(Level *level); - virtual int getMaxHealth(); - protected: + virtual void registerAttributes(); virtual bool makeStepSound(); virtual shared_ptr findAttackTarget(); @@ -24,7 +23,7 @@ protected: virtual int getDeathSound(); public: - virtual bool hurt(DamageSource *source, int dmg); + virtual bool hurt(DamageSource *source, float dmg); protected: virtual void checkHurtTarget(shared_ptr target, float d); diff --git a/Minecraft.World/SimpleContainer.cpp b/Minecraft.World/SimpleContainer.cpp index e29bc790..147bab0a 100644 --- a/Minecraft.World/SimpleContainer.cpp +++ b/Minecraft.World/SimpleContainer.cpp @@ -5,9 +5,11 @@ #include "SimpleContainer.h" -SimpleContainer::SimpleContainer(int name, int size) +SimpleContainer::SimpleContainer(int name, wstring stringName, bool customName, int size) { this->name = name; + this->stringName = stringName; + this->customName = customName; this->size = size; items = new ItemInstanceArray( size ); @@ -46,14 +48,14 @@ shared_ptr SimpleContainer::removeItem(unsigned int slot, int coun { shared_ptr item = (*items)[slot]; (*items)[slot] = nullptr; - this->setChanged(); + setChanged(); return item; } else { shared_ptr i = (*items)[slot]->remove(count); if ((*items)[slot]->count == 0) (*items)[slot] = nullptr; - this->setChanged(); + setChanged(); return i; } } @@ -75,7 +77,7 @@ void SimpleContainer::setItem(unsigned int slot, shared_ptr item) { (*items)[slot] = item; if (item != NULL && item->count > getMaxStackSize()) item->count = getMaxStackSize(); - this->setChanged(); + setChanged(); } unsigned int SimpleContainer::getContainerSize() @@ -83,9 +85,25 @@ unsigned int SimpleContainer::getContainerSize() return size; } -int SimpleContainer::getName() +wstring SimpleContainer::getName() { - return name; + return stringName.empty() ? app.GetString(name) : stringName; +} + +wstring SimpleContainer::getCustomName() +{ + return hasCustomName() ? stringName : L""; +} + +bool SimpleContainer::hasCustomName() +{ + return customName; +} + +void SimpleContainer::setCustomName(const wstring &name) +{ + customName = true; + this->stringName = name; } int SimpleContainer::getMaxStackSize() @@ -95,16 +113,18 @@ int SimpleContainer::getMaxStackSize() void SimpleContainer::setChanged() { - // 4J - removing this as we don't seem to have any implementation of a listener containerChanged function, and shared_from_this is proving tricky to add to containers -#if 0 if (listeners != NULL) for (unsigned int i = 0; i < listeners->size(); i++) { - listeners->at(i)->containerChanged(shared_from_this()); + listeners->at(i)->containerChanged();//shared_from_this()); } -#endif } bool SimpleContainer::stillValid(shared_ptr player) +{ + return true; +} + +bool SimpleContainer::canPlaceItem(int slot, shared_ptr item) { return true; } \ No newline at end of file diff --git a/Minecraft.World/SimpleContainer.h b/Minecraft.World/SimpleContainer.h index 98c193d3..b0baed70 100644 --- a/Minecraft.World/SimpleContainer.h +++ b/Minecraft.World/SimpleContainer.h @@ -8,35 +8,30 @@ class SimpleContainer : public Container { private: int name; + wstring stringName; int size; ItemInstanceArray *items; vector *listeners; + bool customName; public: - SimpleContainer(int name, int size); - - void addListener(net_minecraft_world::ContainerListener *listener); - - void removeListener(net_minecraft_world::ContainerListener *listener); - - shared_ptr getItem(unsigned int slot); - - shared_ptr removeItem(unsigned int slot, int count); - shared_ptr removeItemNoUpdate(int slot); - - void setItem(unsigned int slot, shared_ptr item); - - unsigned int getContainerSize(); - - int getName(); - - int getMaxStackSize(); - - void setChanged(); - - bool stillValid(shared_ptr player); - - void startOpen() { } // TODO Auto-generated method stub - void stopOpen() { } // TODO Auto-generated method stub - + SimpleContainer(int name, wstring stringName, bool customName, int size); + + virtual void addListener(net_minecraft_world::ContainerListener *listener); + virtual void removeListener(net_minecraft_world::ContainerListener *listener); + virtual shared_ptr getItem(unsigned int slot); + virtual shared_ptr removeItem(unsigned int slot, int count); + virtual shared_ptr removeItemNoUpdate(int slot); + virtual void setItem(unsigned int slot, shared_ptr item); + virtual unsigned int getContainerSize(); + virtual wstring getName(); + virtual wstring getCustomName(); + virtual bool hasCustomName(); + virtual void setCustomName(const wstring &name); + virtual int getMaxStackSize(); + virtual void setChanged(); + virtual bool stillValid(shared_ptr player); + virtual void startOpen() { } // TODO Auto-generated method stub + virtual void stopOpen() { } // TODO Auto-generated method stub + virtual bool canPlaceItem(int slot, shared_ptr item); }; \ No newline at end of file diff --git a/Minecraft.World/SimpleFoiledItem.cpp b/Minecraft.World/SimpleFoiledItem.cpp new file mode 100644 index 00000000..65894731 --- /dev/null +++ b/Minecraft.World/SimpleFoiledItem.cpp @@ -0,0 +1,12 @@ +#include "stdafx.h" + +#include "SimpleFoiledItem.h" + +SimpleFoiledItem::SimpleFoiledItem(int id) : Item(id) +{ +} + +bool SimpleFoiledItem::isFoil(shared_ptr itemInstance) +{ + return true; +} diff --git a/Minecraft.World/SimpleFoiledItem.h b/Minecraft.World/SimpleFoiledItem.h new file mode 100644 index 00000000..41bd884d --- /dev/null +++ b/Minecraft.World/SimpleFoiledItem.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Item.h" + +class SimpleFoiledItem : public Item +{ +public: + SimpleFoiledItem(int id); + + bool isFoil(shared_ptr itemInstance); +}; \ No newline at end of file diff --git a/Minecraft.World/SitGoal.cpp b/Minecraft.World/SitGoal.cpp index 90180201..b79b2df7 100644 --- a/Minecraft.World/SitGoal.cpp +++ b/Minecraft.World/SitGoal.cpp @@ -20,7 +20,7 @@ bool SitGoal::canUse() if (mob->isInWater()) return false; if (!mob->onGround) return false; - shared_ptr owner = mob->getOwner(); + shared_ptr owner = dynamic_pointer_cast( mob->getOwner() ); if (owner == NULL) return true; // owner not on level if (mob->distanceToSqr(owner) < FollowOwnerGoal::TeleportDistance * FollowOwnerGoal::TeleportDistance && owner->getLastHurtByMob() != NULL) return false; diff --git a/Minecraft.World/Skeleton.cpp b/Minecraft.World/Skeleton.cpp index b6dbab1f..9afb95c6 100644 --- a/Minecraft.World/Skeleton.cpp +++ b/Minecraft.World/Skeleton.cpp @@ -1,14 +1,20 @@ #include "stdafx.h" #include "net.minecraft.world.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.dimension.h" +#include "net.minecraft.world.level.tile.entity.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.item.enchantment.h" +#include "net.minecraft.world.effect.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.entity.ai.goal.target.h" #include "net.minecraft.world.entity.ai.navigation.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.stats.h" #include "net.minecraft.world.damagesource.h" #include "SharedConstants.h" @@ -16,63 +22,86 @@ #include "..\Minecraft.Client\Textures.h" #include "SoundTypes.h" - - Skeleton::Skeleton(Level *level) : Monster( level ) { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_SKELETON; // 4J was L"/mob/skeleton.png"; - - runSpeed = 0.25f; + bowGoal = new RangedAttackGoal(this, this, 1.0, SharedConstants::TICKS_PER_SECOND * 1, SharedConstants::TICKS_PER_SECOND * 3, 15); + meleeGoal = new MeleeAttackGoal(this, eTYPE_PLAYER, 1.2, false); goalSelector.addGoal(1, new FloatGoal(this)); goalSelector.addGoal(2, new RestrictSunGoal(this)); - goalSelector.addGoal(3, new FleeSunGoal(this, runSpeed)); - goalSelector.addGoal(4, new ArrowAttackGoal(this, runSpeed, ArrowAttackGoal::ArrowType, SharedConstants::TICKS_PER_SECOND * 3)); - goalSelector.addGoal(5, new RandomStrollGoal(this, runSpeed)); + goalSelector.addGoal(3, new FleeSunGoal(this, 1.0)); + goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 8)); goalSelector.addGoal(6, new RandomLookAroundGoal(this)); targetSelector.addGoal(1, new HurtByTargetGoal(this, false)); - targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Player), 16, 0, true)); + targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Player), 0, true)); + + if (level != NULL && !level->isClientSide) reassessWeaponGoal(); } -bool Skeleton::useNewAi() +Skeleton::~Skeleton() { - return true; + delete bowGoal; + delete meleeGoal; +} + +void Skeleton::registerAttributes() +{ + Monster::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f); +} + +void Skeleton::defineSynchedData() +{ + Monster::defineSynchedData(); + + entityData->define(DATA_TYPE_ID, (byte) TYPE_DEFAULT); } -int Skeleton::getMaxHealth() +bool Skeleton::useNewAi() { - return 20; + return true; } int Skeleton::getAmbientSound() { - return eSoundType_MOB_SKELETON_AMBIENT; + return eSoundType_MOB_SKELETON_AMBIENT; } int Skeleton::getHurtSound() { - return eSoundType_MOB_SKELETON_HURT; + return eSoundType_MOB_SKELETON_HURT; } int Skeleton::getDeathSound() { - return eSoundType_MOB_SKELETON_HURT; + return eSoundType_MOB_SKELETON_DEATH; } -shared_ptr Skeleton::bow; +void Skeleton::playStepSound(int xt, int yt, int zt, int t) +{ + playSound(eSoundType_MOB_SKELETON_STEP, 0.15f, 1); +} -shared_ptr Skeleton::getCarriedItem() +bool Skeleton::doHurtTarget(shared_ptr target) { - return bow; + if (Monster::doHurtTarget(target)) + { + if ( (getSkeletonType() == TYPE_WITHER) && target->instanceof(eTYPE_LIVINGENTITY) ) + { + dynamic_pointer_cast(target)->addEffect(new MobEffectInstance(MobEffect::wither->id, SharedConstants::TICKS_PER_SECOND * 10)); + } + return true; + } + return false; } MobType Skeleton::getMobType() @@ -82,28 +111,65 @@ MobType Skeleton::getMobType() void Skeleton::aiStep() { - // isClientSide check brought forward from 1.8 (I assume it's related to the lighting changes) - if (level->isDay() && !level->isClientSide) + if (level->isDay() && !level->isClientSide) { - float br = getBrightness(1); - if (br > 0.5f) + float br = getBrightness(1); + if (br > 0.5f && random->nextFloat() * 30 < (br - 0.4f) * 2 && level->canSeeSky(Mth::floor(x), (int)floor( y + 0.5 ), Mth::floor(z))) { - if (level->canSeeSky( Mth::floor(x), Mth::floor(y), Mth::floor(z)) && random->nextFloat() * 30 < (br - 0.4f) * 2) + bool burn = true; + + shared_ptr helmet = getCarried(SLOT_HELM); + if (helmet != NULL) { - setOnFire(8); - } - } - } + if (helmet->isDamageableItem()) + { + helmet->setAuxValue(helmet->getDamageValue() + random->nextInt(2)); + if (helmet->getDamageValue() >= helmet->getMaxDamage()) + { + breakItem(helmet); + setEquippedSlot(SLOT_HELM, nullptr); + } + } + + burn = false; + } + + if (burn) + { + setOnFire(8); + } + } + } + if (level->isClientSide) + { + if (getSkeletonType() == TYPE_WITHER) + { + setSize(0.6f * 1.2f, 1.8f * 1.3f); + } + } + + Monster::aiStep(); +} + +void Skeleton::rideTick() +{ + Monster::rideTick(); + + if ( riding != NULL && riding->instanceof(eTYPE_PATHFINDER_MOB) ) + { + yBodyRot = dynamic_pointer_cast(riding)->yBodyRot; + } - Monster::aiStep(); } void Skeleton::die(DamageSource *source) { Monster::die(source); - shared_ptr player = dynamic_pointer_cast( source->getEntity() ); - if ( dynamic_pointer_cast( source->getDirectEntity() ) != NULL && player != NULL) + + if ( source->getDirectEntity() != NULL && source->getDirectEntity()->instanceof(eTYPE_ARROW) && source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_PLAYER) ) { + shared_ptr player = dynamic_pointer_cast( source->getEntity() ); + double xd = player->x - x; double zd = player->z - z; if (xd * xd + zd * zd >= 50 * 50) @@ -115,40 +181,179 @@ void Skeleton::die(DamageSource *source) int Skeleton::getDeathLoot() { - return Item::arrow->id; + return Item::arrow->id; } void Skeleton::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) { - // drop some arrows - int count = random->nextInt(3 + playerBonusLevel); - for (int i = 0; i < count; i++) + if (getSkeletonType() == TYPE_WITHER) { - spawnAtLocation(Item::arrow->id, 1); - } - // and some bones - count = random->nextInt(3 + playerBonusLevel); - for (int i = 0; i < count; i++) + // drop some arrows + int count = random->nextInt(3 + playerBonusLevel) - 1; + for (int i = 0; i < count; i++) + { + spawnAtLocation(Item::coal_Id, 1); + } + } + else { - spawnAtLocation(Item::bone->id, 1); - } + // drop some arrows + int count = random->nextInt(3 + playerBonusLevel); + for (int i = 0; i < count; i++) + { + spawnAtLocation(Item::arrow_Id, 1); + } + } + + // and some bones + int count = random->nextInt(3 + playerBonusLevel); + for (int i = 0; i < count; i++) + { + spawnAtLocation(Item::bone->id, 1); + } } void Skeleton::dropRareDeathLoot(int rareLootLevel) { - if (rareLootLevel > 0) + if (getSkeletonType() == TYPE_WITHER) + { + spawnAtLocation( shared_ptr( new ItemInstance(Item::skull_Id, 1, SkullTileEntity::TYPE_WITHER) ), 0); + } +} + +void Skeleton::populateDefaultEquipmentSlots() +{ + Monster::populateDefaultEquipmentSlots(); + + setEquippedSlot(SLOT_WEAPON, shared_ptr( new ItemInstance(Item::bow))); +} + +MobGroupData *Skeleton::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param +{ + groupData = Monster::finalizeMobSpawn(groupData); + + if ( dynamic_cast(level->dimension) != NULL && getRandom()->nextInt(5) > 0) + { + goalSelector.addGoal(4, meleeGoal, false); + + setSkeletonType(TYPE_WITHER); + setEquippedSlot(SLOT_WEAPON, shared_ptr( new ItemInstance(Item::sword_stone))); + getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(4); + } + else + { + goalSelector.addGoal(4, bowGoal, false); + + populateDefaultEquipmentSlots(); + populateDefaultEquipmentEnchantments(); + } + + setCanPickUpLoot(random->nextFloat() < MAX_PICKUP_LOOT_CHANCE * level->getDifficulty(x, y, z)); + + if (getCarried(SLOT_HELM) == NULL) + { + if (Calendar::GetMonth() + 1 == 10 && Calendar::GetDayOfMonth() == 31 && random->nextFloat() < 0.25f) + { + // Halloween! OooOOo! 25% of all skeletons/zombies can wear pumpkins on their heads. + setEquippedSlot(SLOT_HELM, shared_ptr( new ItemInstance(random->nextFloat() < 0.1f ? Tile::litPumpkin : Tile::pumpkin))); + dropChances[SLOT_HELM] = 0; + } + } + return groupData; +} + +void Skeleton::reassessWeaponGoal() +{ + goalSelector.removeGoal(meleeGoal); + goalSelector.removeGoal(bowGoal); + + shared_ptr carried = getCarriedItem(); + + if (carried != NULL && carried->id == Item::bow_Id) { - shared_ptr bow = shared_ptr( new ItemInstance(Item::bow) ); - EnchantmentHelper::enchantItem(random, bow, 5); - spawnAtLocation(bow, 0); + goalSelector.addGoal(4, bowGoal, false); } else { - spawnAtLocation(Item::bow_Id, 1); + goalSelector.addGoal(4, meleeGoal, false); } } -void Skeleton::staticCtor() +void Skeleton::performRangedAttack(shared_ptr target, float power) { - Skeleton::bow = shared_ptr( new ItemInstance(Item::bow, 1) ); + shared_ptr arrow = shared_ptr( new Arrow(level, dynamic_pointer_cast(shared_from_this()), target, 1.60f, 14 - (level->difficulty * 4)) ); + int damageBonus = EnchantmentHelper::getEnchantmentLevel(Enchantment::arrowBonus->id, getCarriedItem()); + int knockbackBonus = EnchantmentHelper::getEnchantmentLevel(Enchantment::arrowKnockback->id, getCarriedItem()); + + arrow->setBaseDamage(power * 2.0f + (random->nextGaussian() * 0.25f + (level->difficulty * 0.11f))); + + if (damageBonus > 0) + { + arrow->setBaseDamage(arrow->getBaseDamage() + (double) damageBonus * .5 + .5); + } + if (knockbackBonus > 0) + { + arrow->setKnockback(knockbackBonus); + } + if (EnchantmentHelper::getEnchantmentLevel(Enchantment::arrowFire->id, getCarriedItem()) > 0 || getSkeletonType() == TYPE_WITHER) + { + arrow->setOnFire(100); + } + + playSound(eSoundType_RANDOM_BOW, 1.0f, 1 / (getRandom()->nextFloat() * 0.4f + 0.8f)); + level->addEntity(arrow); } + +int Skeleton::getSkeletonType() +{ + return (int) entityData->getByte(DATA_TYPE_ID); +} + +void Skeleton::setSkeletonType(int type) +{ + entityData->set(DATA_TYPE_ID, (byte) type); + + fireImmune = type == TYPE_WITHER; + if (type == TYPE_WITHER) + { + setSize(0.6f * 1.2f, 1.8f * 1.3f); + } + else + { + setSize(0.6f, 1.8f); + } +} + +void Skeleton::readAdditionalSaveData(CompoundTag *tag) +{ + Monster::readAdditionalSaveData(tag); + + if (tag->contains(L"SkeletonType")) + { + int value = tag->getByte(L"SkeletonType"); + setSkeletonType(value); + } + + reassessWeaponGoal(); +} + +void Skeleton::addAdditonalSaveData(CompoundTag *entityTag) +{ + Monster::addAdditonalSaveData(entityTag); + entityTag->putByte(L"SkeletonType", (byte) getSkeletonType()); +} + +void Skeleton::setEquippedSlot(int slot, shared_ptr item) +{ + Monster::setEquippedSlot(slot, item); + + if (!level->isClientSide && slot == SLOT_WEAPON) + { + reassessWeaponGoal(); + } +} + +double Skeleton::getRidingHeight() +{ + return Monster::getRidingHeight() - .5; +} \ No newline at end of file diff --git a/Minecraft.World/Skeleton.h b/Minecraft.World/Skeleton.h index b85d9afe..e2f6594c 100644 --- a/Minecraft.World/Skeleton.h +++ b/Minecraft.World/Skeleton.h @@ -2,38 +2,68 @@ using namespace std; #include "Monster.h" +#include "RangedAttackMob.h" -class Skeleton : public Monster +class RangedAttackGoal; +class MeleeAttackGoal; + +class Skeleton : public Monster, public RangedAttackMob { public: eINSTANCEOF GetType() { return eTYPE_SKELETON; } static Entity *create(Level *level) { return new Skeleton(level); } +private: + static const int DATA_TYPE_ID = 13; + +public: + static const int TYPE_DEFAULT = 0; + static const int TYPE_WITHER = 1; + +private: + RangedAttackGoal *bowGoal; + MeleeAttackGoal *meleeGoal; + +public: Skeleton(Level *level); + virtual ~Skeleton(); +protected: + virtual void registerAttributes(); + virtual void defineSynchedData(); + +public: virtual bool useNewAi(); - virtual int getMaxHealth(); protected: virtual int getAmbientSound(); virtual int getHurtSound(); virtual int getDeathSound(); + virtual void playStepSound(int xt, int yt, int zt, int t); + +public: + virtual bool doHurtTarget(shared_ptr target); public: - virtual shared_ptr getCarriedItem(); virtual MobType getMobType(); virtual void aiStep(); + virtual void rideTick(); virtual void die(DamageSource *source); protected: virtual int getDeathLoot(); - virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); + virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); virtual void dropRareDeathLoot(int rareLootLevel); - -private: - static shared_ptr bow; + virtual void populateDefaultEquipmentSlots(); public: - - static void staticCtor(); + virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param + virtual void reassessWeaponGoal(); + virtual void performRangedAttack(shared_ptr target, float power); + virtual int getSkeletonType(); + virtual void setSkeletonType(int type); + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual void addAdditonalSaveData(CompoundTag *entityTag); + virtual void setEquippedSlot(int slot, shared_ptr item); + virtual double getRidingHeight(); }; diff --git a/Minecraft.World/SkullItem.cpp b/Minecraft.World/SkullItem.cpp index 643021dc..8fabc3cd 100644 --- a/Minecraft.World/SkullItem.cpp +++ b/Minecraft.World/SkullItem.cpp @@ -9,7 +9,7 @@ const unsigned int SkullItem::NAMES[SKULL_COUNT] = {IDS_ITEM_SKULL_SKELETON, IDS_ITEM_SKULL_WITHER, IDS_ITEM_SKULL_ZOMBIE, IDS_ITEM_SKULL_CHARACTER, IDS_ITEM_SKULL_CREEPER}; -wstring SkullItem::ICON_NAMES[SKULL_COUNT] = {L"skull_skeleton", L"skull_wither", L"skull_zombie", L"skull_char", L"skull_creeper"}; +wstring SkullItem::ICON_NAMES[SKULL_COUNT] = {L"skeleton", L"wither", L"zombie", L"char", L"creeper"}; SkullItem::SkullItem(int id) : Item(id) { @@ -31,13 +31,13 @@ bool SkullItem::useOn(shared_ptr instance, shared_ptr play if (face == 5) x++; //if (!player->mayUseItemAt(x, y, z, face, instance)) return false; - if (!player->mayBuild(x, y, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, instance)) return false; if (!Tile::skull->mayPlace(level, x, y, z)) return false; if(!bTestUseOnOnly) { - level->setTileAndData(x, y, z, Tile::skull_Id, face) ;//, Tile.UPDATE_CLIENTS); + level->setTileAndData(x, y, z, Tile::skull_Id, face, Tile::UPDATE_CLIENTS); int rot = 0; if (face == Facing::UP) @@ -82,7 +82,7 @@ bool SkullItem::mayPlace(Level *level, int x, int y, int z, int face, shared_ptr if (face == 5) x++; } - return level->mayPlace(Tile::skull_Id, x, y, z, false, face, nullptr) ;//, item); + return level->mayPlace(Tile::skull_Id, x, y, z, false, face, nullptr, item); } Icon *SkullItem::getIcon(int itemAuxValue) @@ -136,6 +136,6 @@ void SkullItem::registerIcons(IconRegister *iconRegister) { for (int i = 0; i < SKULL_COUNT; i++) { - icons[i] = iconRegister->registerIcon(ICON_NAMES[i]); + icons[i] = iconRegister->registerIcon(getIconName() + L"_" + ICON_NAMES[i]); } } \ No newline at end of file diff --git a/Minecraft.World/SkullTile.cpp b/Minecraft.World/SkullTile.cpp index 73aef0e1..92ce7807 100644 --- a/Minecraft.World/SkullTile.cpp +++ b/Minecraft.World/SkullTile.cpp @@ -1,11 +1,14 @@ #include "stdafx.h" -#include "net.minecraft.world.level.h" +#include "net.minecraft.world.h" +#include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.entity.h" +#include "WitherBoss.h" #include "net.minecraft.h" #include "SkullTile.h" -SkullTile::SkullTile(int id) : EntityTile(id, Material::decoration, isSolidRender() ) +SkullTile::SkullTile(int id) : BaseEntityTile(id, Material::decoration, isSolidRender() ) { setShape(4.0f / 16.0f, 0, 4.0f / 16.0f, 12.0f / 16.0f, .5f, 12.0f / 16.0f); } @@ -53,13 +56,13 @@ void SkullTile::updateShape(LevelSource *level, int x, int y, int z, int forceDa AABB *SkullTile::getAABB(Level *level, int x, int y, int z) { updateShape(level, x, y, z); - return EntityTile::getAABB(level, x, y, z); + return BaseEntityTile::getAABB(level, x, y, z); } -void SkullTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void SkullTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) { int dir = Mth::floor(by->yRot * 4 / (360) + 2.5) & 3; - level->setData(x, y, z, dir); + level->setData(x, y, z, dir, Tile::UPDATE_CLIENTS); } shared_ptr SkullTile::newTileEntity(Level *level) @@ -80,9 +83,7 @@ int SkullTile::cloneTileData(Level *level, int x, int y, int z) { return skull->getSkullType(); } - return 0; - // 4J Stu - Not added yet - //return EntityTile::cloneTileData(level, x, y, z); + return BaseEntityTile::cloneTileData(level, x, y, z); } int SkullTile::getSpawnResourcesAuxValue(int data) @@ -98,22 +99,18 @@ void SkullTile::spawnResources(Level *level, int x, int y, int z, int data, floa void SkullTile::playerWillDestroy(Level *level, int x, int y, int z, int data, shared_ptr player) { - // 4J Stu - Not implemented -#if 0 if (player->abilities.instabuild) { // prevent resource drop data |= NO_DROP_BIT; - level.setData(x, y, z, data); + level->setData(x, y, z, data, Tile::UPDATE_NONE); } - EntityTile::playerWillDestroy(level, x, y, z, data, player); -#endif + BaseEntityTile::playerWillDestroy(level, x, y, z, data, player); } -void SkullTile::onRemove(Level *level, int x, int y, int z)//, int id, int data) +void SkullTile::onRemove(Level *level, int x, int y, int z, int id, int data) { if (level->isClientSide) return; - int data = level->getData(x, y, z); if ((data & NO_DROP_BIT) == 0) { shared_ptr item = shared_ptr(new ItemInstance(Item::skull_Id, 1, cloneTileData(level, x, y, z))); @@ -127,7 +124,7 @@ void SkullTile::onRemove(Level *level, int x, int y, int z)//, int id, int data) popResource(level, x, y, z, item); } - EntityTile::onRemove(level, x, y, z, id, data); + BaseEntityTile::onRemove(level, x, y, z, id, data); } int SkullTile::getResource(int data, Random *random, int playerBonusLevel) @@ -137,105 +134,136 @@ int SkullTile::getResource(int data, Random *random, int playerBonusLevel) void SkullTile::checkMobSpawn(Level *level, int x, int y, int z, shared_ptr placedSkull) { - // 4J Stu - Don't have Withers yet, so don't need this -#if 0 - if (placedSkull.getSkullType() == SkullTileEntity.TYPE_WITHER && y >= 2 && level.difficulty > Difficulty.PEACEFUL) { - - // check wither boss spawn - - final int ss = Tile.hellSand.id; + if (placedSkull->getSkullType() == SkullTileEntity::TYPE_WITHER && y >= 2 && level->difficulty > Difficulty::PEACEFUL && !level->isClientSide) + { + // Check wither boss spawn + int ss = Tile::soulsand_Id; - // north-south alignment - for (int zo = -2; zo <= 0; zo++) { + // North-south alignment + for (int zo = -2; zo <= 0; zo++) + { if ( // - level.getTile(x, y - 1, z + zo) == ss && // - level.getTile(x, y - 1, z + zo + 1) == ss && // - level.getTile(x, y - 2, z + zo + 1) == ss && // - level.getTile(x, y - 1, z + zo + 2) == ss && // - isSkullAt(level, x, y, z + zo, SkullTileEntity.TYPE_WITHER) && // - isSkullAt(level, x, y, z + zo + 1, SkullTileEntity.TYPE_WITHER) && // - isSkullAt(level, x, y, z + zo + 2, SkullTileEntity.TYPE_WITHER)) { - - level.setDataNoUpdate(x, y, z + zo, NO_DROP_BIT); - level.setDataNoUpdate(x, y, z + zo + 1, NO_DROP_BIT); - level.setDataNoUpdate(x, y, z + zo + 2, NO_DROP_BIT); - level.setTileNoUpdate(x, y, z + zo, 0); - level.setTileNoUpdate(x, y, z + zo + 1, 0); - level.setTileNoUpdate(x, y, z + zo + 2, 0); - level.setTileNoUpdate(x, y - 1, z + zo, 0); - level.setTileNoUpdate(x, y - 1, z + zo + 1, 0); - level.setTileNoUpdate(x, y - 1, z + zo + 2, 0); - level.setTileNoUpdate(x, y - 2, z + zo + 1, 0); - - if (!level.isClientSide) { - WitherBoss witherBoss = new WitherBoss(level); - witherBoss.moveTo(x + 0.5, y - 1.45, z + zo + 1.5, 90, 0); - witherBoss.yBodyRot = 90; - witherBoss.makeInvulnerable(); - level.addEntity(witherBoss); - } - - for (int i = 0; i < 120; i++) { - level.addParticle("snowballpoof", x + level.random.nextDouble(), y - 2 + level.random.nextDouble() * 3.9, z + zo + 1 + level.random.nextDouble(), 0, 0, 0); - } - - level.tileUpdated(x, y, z + zo, 0); - level.tileUpdated(x, y, z + zo + 1, 0); - level.tileUpdated(x, y, z + zo + 2, 0); - level.tileUpdated(x, y - 1, z + zo, 0); - level.tileUpdated(x, y - 1, z + zo + 1, 0); - level.tileUpdated(x, y - 1, z + zo + 2, 0); - level.tileUpdated(x, y - 2, z + zo + 1, 0); - - return; + level->getTile(x, y - 1, z + zo) == ss && // + level->getTile(x, y - 1, z + zo + 1) == ss && // + level->getTile(x, y - 2, z + zo + 1) == ss && // + level->getTile(x, y - 1, z + zo + 2) == ss && // + isSkullAt(level, x, y, z + zo, SkullTileEntity::TYPE_WITHER) && // + isSkullAt(level, x, y, z + zo + 1, SkullTileEntity::TYPE_WITHER) && // + isSkullAt(level, x, y, z + zo + 2, SkullTileEntity::TYPE_WITHER)) + { + level->setData(x, y, z + zo, NO_DROP_BIT, Tile::UPDATE_CLIENTS); + level->setData(x, y, z + zo + 1, NO_DROP_BIT, Tile::UPDATE_CLIENTS); + level->setData(x, y, z + zo + 2, NO_DROP_BIT, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y, z + zo, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y, z + zo + 1, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y, z + zo + 2, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z + zo, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z + zo + 1, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 1, z + zo + 2, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x, y - 2, z + zo + 1, 0, 0, Tile::UPDATE_CLIENTS); + + // 4J: Check that we can spawn a Wither + if (level->canCreateMore(eTYPE_WITHERBOSS, Level::eSpawnType_Egg)) + { + // 4J: Removed !isClientSide check because there's one earlier on + shared_ptr witherBoss = shared_ptr( new WitherBoss(level) ); + witherBoss->moveTo(x + 0.5, y - 1.45, z + zo + 1.5, 90, 0); + witherBoss->yBodyRot = 90; + witherBoss->makeInvulnerable(); + level->addEntity(witherBoss); + } + else + { + // 4J: Can't spawn, drop resource instead + Tile::tiles[Tile::soulsand_Id]->spawnResources(level, x, y - 1, z + zo, 0, 0); + Tile::tiles[Tile::soulsand_Id]->spawnResources(level, x, y - 1, z + zo + 1, 0, 0); + Tile::tiles[Tile::soulsand_Id]->spawnResources(level, x, y - 2, z + zo + 1, 0, 0); + Tile::tiles[Tile::soulsand_Id]->spawnResources(level, x, y - 1, z + zo + 2, 0, 0); + + shared_ptr itemInstance = shared_ptr(new ItemInstance(Item::skull_Id, 3, SkullTileEntity::TYPE_WITHER)); + shared_ptr itemEntity = shared_ptr(new ItemEntity(level, x, y, z + zo + 1, itemInstance) ); + level->addEntity(itemEntity); + } + + for (int i = 0; i < 120; i++) + { + level->addParticle(eParticleType_snowballpoof, x + level->random->nextDouble(), y - 2 + level->random->nextDouble() * 3.9, z + zo + 1 + level->random->nextDouble(), 0, 0, 0); + } + + level->tileUpdated(x, y, z + zo, 0); + level->tileUpdated(x, y, z + zo + 1, 0); + level->tileUpdated(x, y, z + zo + 2, 0); + level->tileUpdated(x, y - 1, z + zo, 0); + level->tileUpdated(x, y - 1, z + zo + 1, 0); + level->tileUpdated(x, y - 1, z + zo + 2, 0); + level->tileUpdated(x, y - 2, z + zo + 1, 0); + + return; } } - // west-east alignment - for (int xo = -2; xo <= 0; xo++) { + // West-east alignment + for (int xo = -2; xo <= 0; xo++) + { if ( // - level.getTile(x + xo, y - 1, z) == ss && // - level.getTile(x + xo + 1, y - 1, z) == ss && // - level.getTile(x + xo + 1, y - 2, z) == ss && // - level.getTile(x + xo + 2, y - 1, z) == ss && // - isSkullAt(level, x + xo, y, z, SkullTileEntity.TYPE_WITHER) && // - isSkullAt(level, x + xo + 1, y, z, SkullTileEntity.TYPE_WITHER) && // - isSkullAt(level, x + xo + 2, y, z, SkullTileEntity.TYPE_WITHER)) { - - level.setDataNoUpdate(x + xo, y, z, NO_DROP_BIT); - level.setDataNoUpdate(x + xo + 1, y, z, NO_DROP_BIT); - level.setDataNoUpdate(x + xo + 2, y, z, NO_DROP_BIT); - level.setTileNoUpdate(x + xo, y, z, 0); - level.setTileNoUpdate(x + xo + 1, y, z, 0); - level.setTileNoUpdate(x + xo + 2, y, z, 0); - level.setTileNoUpdate(x + xo, y - 1, z, 0); - level.setTileNoUpdate(x + xo + 1, y - 1, z, 0); - level.setTileNoUpdate(x + xo + 2, y - 1, z, 0); - level.setTileNoUpdate(x + xo + 1, y - 2, z, 0); - - if (!level.isClientSide) { - WitherBoss witherBoss = new WitherBoss(level); - witherBoss.moveTo(x + xo + 1.5, y - 1.45, z + .5, 0, 0); - witherBoss.makeInvulnerable(); - level.addEntity(witherBoss); - } - - for (int i = 0; i < 120; i++) { - level.addParticle("snowballpoof", x + xo + 1 + level.random.nextDouble(), y - 2 + level.random.nextDouble() * 3.9, z + level.random.nextDouble(), 0, 0, 0); - } - - level.tileUpdated(x + xo, y, z, 0); - level.tileUpdated(x + xo + 1, y, z, 0); - level.tileUpdated(x + xo + 2, y, z, 0); - level.tileUpdated(x + xo, y - 1, z, 0); - level.tileUpdated(x + xo + 1, y - 1, z, 0); - level.tileUpdated(x + xo + 2, y - 1, z, 0); - level.tileUpdated(x + xo + 1, y - 2, z, 0); - - return; + level->getTile(x + xo, y - 1, z) == ss && // + level->getTile(x + xo + 1, y - 1, z) == ss && // + level->getTile(x + xo + 1, y - 2, z) == ss && // + level->getTile(x + xo + 2, y - 1, z) == ss && // + isSkullAt(level, x + xo, y, z, SkullTileEntity::TYPE_WITHER) && // + isSkullAt(level, x + xo + 1, y, z, SkullTileEntity::TYPE_WITHER) && // + isSkullAt(level, x + xo + 2, y, z, SkullTileEntity::TYPE_WITHER)) + { + + level->setData(x + xo, y, z, NO_DROP_BIT, Tile::UPDATE_CLIENTS); + level->setData(x + xo + 1, y, z, NO_DROP_BIT, Tile::UPDATE_CLIENTS); + level->setData(x + xo + 2, y, z, NO_DROP_BIT, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + xo, y, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + xo + 1, y, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + xo + 2, y, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + xo, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + xo + 1, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + xo + 2, y - 1, z, 0, 0, Tile::UPDATE_CLIENTS); + level->setTileAndData(x + xo + 1, y - 2, z, 0, 0, Tile::UPDATE_CLIENTS); + + // 4J: Check that we can spawn a Wither + if (level->canCreateMore(eTYPE_WITHERBOSS, Level::eSpawnType_Egg)) + { + // 4J: Removed !isClientSide check because there's one earlier on + shared_ptr witherBoss = shared_ptr( new WitherBoss(level) ); + witherBoss->moveTo(x + xo + 1.5, y - 1.45, z + .5, 0, 0); + witherBoss->makeInvulnerable(); + level->addEntity(witherBoss); + } + else + { + // 4J: Can't spawn, drop resource instead + Tile::tiles[Tile::soulsand_Id]->spawnResources(level, x + xo, y - 1, z, 0, 0); + Tile::tiles[Tile::soulsand_Id]->spawnResources(level, x + xo + 1, y - 1, z, 0, 0); + Tile::tiles[Tile::soulsand_Id]->spawnResources(level, x + xo + 1, y - 2, z, 0, 0); + Tile::tiles[Tile::soulsand_Id]->spawnResources(level, x + xo + 2, y - 1, z, 0, 0); + + shared_ptr itemInstance = shared_ptr(new ItemInstance(Item::skull_Id, 3, SkullTileEntity::TYPE_WITHER)); + shared_ptr itemEntity = shared_ptr(new ItemEntity(level, x + xo + 1, y, z, itemInstance) ); + level->addEntity(itemEntity); + } + + for (int i = 0; i < 120; i++) + { + level->addParticle(eParticleType_snowballpoof, x + xo + 1 + level->random->nextDouble(), y - 2 + level->random->nextDouble() * 3.9, z + level->random->nextDouble(), 0, 0, 0); + } + + level->tileUpdated(x + xo, y, z, 0); + level->tileUpdated(x + xo + 1, y, z, 0); + level->tileUpdated(x + xo + 2, y, z, 0); + level->tileUpdated(x + xo, y - 1, z, 0); + level->tileUpdated(x + xo + 1, y - 1, z, 0); + level->tileUpdated(x + xo + 2, y - 1, z, 0); + level->tileUpdated(x + xo + 1, y - 2, z, 0); + + return; } } } -#endif } bool SkullTile::isSkullAt(Level *level, int x, int y, int z, int skullType) @@ -260,11 +288,10 @@ void SkullTile::registerIcons(IconRegister *iconRegister) Icon *SkullTile::getTexture(int face, int data) { - return Tile::hellSand->getTexture(face); + return Tile::soulsand->getTexture(face); } wstring SkullTile::getTileItemIconName() { - return L""; - //return SkullItem::ICON_NAMES[0]; + return getIconName() + L"_" + SkullItem::ICON_NAMES[0]; } \ No newline at end of file diff --git a/Minecraft.World/SkullTile.h b/Minecraft.World/SkullTile.h index 1d514acd..8370a807 100644 --- a/Minecraft.World/SkullTile.h +++ b/Minecraft.World/SkullTile.h @@ -1,10 +1,10 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" class SkullTileEntity; -class SkullTile : public EntityTile +class SkullTile : public BaseEntityTile { friend class Tile; public: @@ -16,21 +16,21 @@ public: SkullTile(int id); public: - using EntityTile::onRemove; + using BaseEntityTile::onRemove; int getRenderShape(); bool isSolidRender(bool isServerLevel = false); bool isCubeShaped(); void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); AABB *getAABB(Level *level, int x, int y, int z); - void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); + void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); shared_ptr newTileEntity(Level *level); int cloneTileId(Level *level, int x, int y, int z); int cloneTileData(Level *level, int x, int y, int z); int getSpawnResourcesAuxValue(int data); void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonusLevel); void playerWillDestroy(Level *level, int x, int y, int z, int data, shared_ptr player); - void onRemove(Level *level, int x, int y, int z); //, int id, int data); + void onRemove(Level *level, int x, int y, int z, int id, int data); int getResource(int data, Random *random, int playerBonusLevel); void checkMobSpawn(Level *level, int x, int y, int z, shared_ptr placedSkull); diff --git a/Minecraft.World/Slime.cpp b/Minecraft.World/Slime.cpp index 7941fbe0..eb80d09c 100644 --- a/Minecraft.World/Slime.cpp +++ b/Minecraft.World/Slime.cpp @@ -6,8 +6,10 @@ #include "net.minecraft.world.level.chunk.h" #include "net.minecraft.world.entity.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.damagesource.h" #include "com.mojang.nbt.h" #include "Slime.h" @@ -30,15 +32,13 @@ Slime::Slime(Level *level) : Mob( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); + setHealth(getMaxHealth()); _init(); - this->textureIdx = TN_MOB_SLIME; // 4J was L"/mob/slime.png"; int size = 1 << (random->nextInt(3)); - this->heightOffset = 0; + heightOffset = 0; jumpDelay = random->nextInt(20) + 10; setSize(size); } @@ -53,18 +53,13 @@ void Slime::defineSynchedData() void Slime::setSize(int size) { entityData->set(ID_SIZE, (byte) size); - Mob::setSize(0.6f * size, 0.6f * size); - this->setPos(x, y, z); + setSize(0.6f * size, 0.6f * size); + setPos(x, y, z); + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(size * size); setHealth(getMaxHealth()); xpReward = size; } -int Slime::getMaxHealth() -{ - int size = getSize(); - return size * size; -} - int Slime::getSize() { return entityData->getByte(ID_SIZE); @@ -89,7 +84,7 @@ ePARTICLE_TYPE Slime::getParticleName() int Slime::getSquishSound() { - return eSoundType_MOB_SLIME; + return getSize() > 1 ? eSoundType_MOB_SLIME_BIG : eSoundType_MOB_SLIME; } void Slime::tick() @@ -102,7 +97,7 @@ void Slime::tick() squish = squish + (targetSquish - squish) * .5f; oSquish = squish; - bool wasOnGround = this->onGround; + bool wasOnGround = onGround; Mob::tick(); if (onGround && !wasOnGround) { @@ -118,7 +113,7 @@ void Slime::tick() if (doPlayLandSound()) { - level->playSound(shared_from_this(), getSquishSound(), getSoundVolume(), ((random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f) / 0.8f); + playSound(getSquishSound(), getSoundVolume(), ((random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f) / 0.8f); } targetSquish = -0.5f; } @@ -128,6 +123,12 @@ void Slime::tick() targetSquish = 1; } decreaseSquish(); + + if (level->isClientSide) + { + int size = getSize(); + setSize(0.6f * size, 0.6f * size); + } } void Slime::serverAiStep() @@ -148,7 +149,7 @@ void Slime::serverAiStep() jumping = true; if (doPlayJumpSound()) { - level->playSound(shared_from_this(), getSquishSound(), getSoundVolume(), ((random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f) * 0.8f); + playSound(getSquishSound(), getSoundVolume(), ((random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f) * 0.8f); } // 4J Removed TU7 to bring forward change to fix lava slime render in MP @@ -211,12 +212,12 @@ void Slime::playerTouch(shared_ptr player) if (isDealsDamage()) { int size = getSize(); - if (canSee(player) && this->distanceToSqr(player) < (0.6 * size) * (0.6 * size)) + if (canSee(player) && distanceToSqr(player) < (0.6 * size) * (0.6 * size)) { DamageSource *damageSource = DamageSource::mobAttack( dynamic_pointer_cast( shared_from_this() ) ); if (player->hurt(damageSource, getAttackDamage())) { - level->playSound(shared_from_this(), eSoundType_MOB_SLIME_ATTACK, 1, (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); + playSound(eSoundType_MOB_SLIME_ATTACK, 1, (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); } delete damageSource; } @@ -235,12 +236,12 @@ int Slime::getAttackDamage() int Slime::getHurtSound() { - return eSoundType_MOB_SLIME; + return getSize() > 1 ? eSoundType_MOB_SLIME_BIG : eSoundType_MOB_SLIME; } int Slime::getDeathSound() { - return eSoundType_MOB_SLIME; + return getSize() > 1 ? eSoundType_MOB_SLIME_BIG : eSoundType_MOB_SLIME; } int Slime::getDeathLoot() @@ -257,11 +258,24 @@ bool Slime::canSpawn() return false; } Random *lcr = lc->getRandom(987234911l); // 4J - separated out so we can delete - if ((getSize() == 1 || level->difficulty > Difficulty::PEACEFUL) && random->nextInt(10) == 0 && lcr->nextInt(10) == 0 && y < 40) + if ((getSize() == 1 || level->difficulty > Difficulty::PEACEFUL)) { - delete lcr; - return Mob::canSpawn(); + // spawn slime in swamplands at night + Biome *biome = level->getBiome(Mth::floor(x), Mth::floor(z)); + + if (biome == Biome::swampland && y > 50 && y < 70 && random->nextFloat() < 0.5f) + { + if (random->nextFloat() < level->getMoonBrightness() && level->getRawBrightness(Mth::floor(x), Mth::floor(y), Mth::floor(z)) <= random->nextInt(8)) + { + return Mob::canSpawn(); + } + } + if (random->nextInt(10) == 0 && lcr->nextInt(10) == 0 && y < 40) + { + return Mob::canSpawn(); + } } + delete lcr; return false; } @@ -278,7 +292,7 @@ int Slime::getMaxHeadXRot() bool Slime::doPlayJumpSound() { - return getSize() > 1; + return getSize() > 0; } bool Slime::doPlayLandSound() diff --git a/Minecraft.World/Slime.h b/Minecraft.World/Slime.h index 6fa56056..95a1aef1 100644 --- a/Minecraft.World/Slime.h +++ b/Minecraft.World/Slime.h @@ -31,10 +31,9 @@ protected: virtual void defineSynchedData(); public: - using Entity::setSize; + using Mob::setSize; virtual void setSize(int size); - virtual int getMaxHealth(); virtual int getSize(); virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); diff --git a/Minecraft.World/Slot.cpp b/Minecraft.World/Slot.cpp index 30fd9125..c7d1a029 100644 --- a/Minecraft.World/Slot.cpp +++ b/Minecraft.World/Slot.cpp @@ -116,6 +116,11 @@ bool Slot::mayPickup(shared_ptr player) return true; } +bool Slot::isActive() +{ + return true; +} + bool Slot::mayCombine(shared_ptr second) { shared_ptr first = getItem(); diff --git a/Minecraft.World/Slot.h b/Minecraft.World/Slot.h index 6289ec0e..12399783 100644 --- a/Minecraft.World/Slot.h +++ b/Minecraft.World/Slot.h @@ -36,6 +36,7 @@ public: virtual shared_ptr remove(int c); virtual bool isAt(shared_ptr c, int s); virtual bool mayPickup(shared_ptr player); + virtual bool isActive(); virtual bool mayCombine(shared_ptr item); // 4J Added virtual shared_ptr combine(shared_ptr item); // 4J Added }; \ No newline at end of file diff --git a/Minecraft.World/SmallFireball.cpp b/Minecraft.World/SmallFireball.cpp index a1fa5cb1..30f7a0b2 100644 --- a/Minecraft.World/SmallFireball.cpp +++ b/Minecraft.World/SmallFireball.cpp @@ -11,7 +11,7 @@ SmallFireball::SmallFireball(Level *level) : Fireball(level) setSize(5 / 16.0f, 5 / 16.0f); } -SmallFireball::SmallFireball(Level *level, shared_ptr mob, double xa, double ya, double za) : Fireball(level, mob, xa, ya, za) +SmallFireball::SmallFireball(Level *level, shared_ptr mob, double xa, double ya, double za) : Fireball(level, mob, xa, ya, za) { setSize(5 / 16.0f, 5 / 16.0f); } @@ -62,7 +62,7 @@ void SmallFireball::onHit(HitResult *res) }; if (level->isEmptyTile(tileX, tileY, tileZ)) { - level->setTile(tileX, tileY, tileZ, Tile::fire_Id); + level->setTileAndUpdate(tileX, tileY, tileZ, Tile::fire_Id); } } remove(); @@ -74,7 +74,7 @@ bool SmallFireball::isPickable() return false; } -bool SmallFireball::hurt(DamageSource *source, int damage) +bool SmallFireball::hurt(DamageSource *source, float damage) { return false; } \ No newline at end of file diff --git a/Minecraft.World/SmallFireball.h b/Minecraft.World/SmallFireball.h index 38ad8efd..bb2e67ae 100644 --- a/Minecraft.World/SmallFireball.h +++ b/Minecraft.World/SmallFireball.h @@ -12,7 +12,7 @@ public: public: SmallFireball(Level *level); - SmallFireball(Level *level, shared_ptr mob, double xa, double ya, double za); + SmallFireball(Level *level, shared_ptr mob, double xa, double ya, double za); SmallFireball(Level *level, double x, double y, double z, double xa, double ya, double za); protected: @@ -20,5 +20,5 @@ protected: public: virtual bool isPickable(); - virtual bool hurt(DamageSource *source, int damage); + virtual bool hurt(DamageSource *source, float damage); }; \ No newline at end of file diff --git a/Minecraft.World/SmoothStoneBrickTile.cpp b/Minecraft.World/SmoothStoneBrickTile.cpp index 372901ec..22fb6df5 100644 --- a/Minecraft.World/SmoothStoneBrickTile.cpp +++ b/Minecraft.World/SmoothStoneBrickTile.cpp @@ -2,7 +2,7 @@ #include "SmoothStoneBrickTile.h" #include "net.minecraft.world.h" -const wstring SmoothStoneBrickTile::TEXTURE_NAMES[] = {L"stonebricksmooth", L"stonebricksmooth_mossy", L"stonebricksmooth_cracked", L"stonebricksmooth_carved"}; +const wstring SmoothStoneBrickTile::TEXTURE_NAMES[] = {L"", L"mossy", L"cracked", L"carved"}; const unsigned int SmoothStoneBrickTile::SMOOTH_STONE_BRICK_NAMES[SMOOTH_STONE_BRICK_NAMES_LENGTH] = { IDS_TILE_STONE_BRICK_SMOOTH, IDS_TILE_STONE_BRICK_SMOOTH_MOSSY, @@ -38,6 +38,8 @@ void SmoothStoneBrickTile::registerIcons(IconRegister *iconRegister) for (int i = 0; i < SMOOTH_STONE_BRICK_NAMES_LENGTH; i++) { - icons[i] = iconRegister->registerIcon(TEXTURE_NAMES[i]); + wstring name = getIconName(); + if (!TEXTURE_NAMES[i].empty() ) name += L"_" + TEXTURE_NAMES[i]; + icons[i] = iconRegister->registerIcon(name); } } \ No newline at end of file diff --git a/Minecraft.World/SnowItem.cpp b/Minecraft.World/SnowItem.cpp new file mode 100644 index 00000000..73cb57ad --- /dev/null +++ b/Minecraft.World/SnowItem.cpp @@ -0,0 +1,45 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.h" +#include "SnowItem.h" + +SnowItem::SnowItem(int id, Tile *parentTile) : AuxDataTileItem(id, parentTile) +{ +} + +bool SnowItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) +{ + if (instance->count == 0) return false; + if (!player->mayUseItemAt(x, y, z, face, instance)) return false; + + int currentTile = level->getTile(x, y, z); + + // Are we adding extra snow to an existing tile? + if (currentTile == Tile::topSnow_Id) + { + Tile *snowTile = Tile::tiles[getTileId()]; + int currentData = level->getData(x, y, z); + int currentHeight = currentData & TopSnowTile::HEIGHT_MASK; + + if (currentHeight <= TopSnowTile::MAX_HEIGHT && level->isUnobstructed(snowTile->getAABB(level, x, y, z))) + { + if (!bTestUseOnOnly) + { + // Increase snow tile height + if (level->setData(x, y, z, (currentHeight + 1) | (currentData & ~TopSnowTile::HEIGHT_MASK), Tile::UPDATE_CLIENTS)) + { + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, snowTile->soundType->getPlaceSound(), (snowTile->soundType->getVolume() + 1) / 2, snowTile->soundType->getPitch() * 0.8f); + instance->count--; + return true; + } + } + else + { + return true; + } + } + } + + return AuxDataTileItem::useOn(instance, player, level, x, y, z, face, clickX, clickY, clickZ, bTestUseOnOnly); +} \ No newline at end of file diff --git a/Minecraft.World/SnowItem.h b/Minecraft.World/SnowItem.h new file mode 100644 index 00000000..47b0049a --- /dev/null +++ b/Minecraft.World/SnowItem.h @@ -0,0 +1,11 @@ +#pragma once + +#include "AuxDataTileItem.h" + +class SnowItem : public AuxDataTileItem +{ +public: + SnowItem(int id, Tile *parentTile); + + bool useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); +}; \ No newline at end of file diff --git a/Minecraft.World/SnowMan.cpp b/Minecraft.World/SnowMan.cpp index 958b8126..6c78b56f 100644 --- a/Minecraft.World/SnowMan.cpp +++ b/Minecraft.World/SnowMan.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.entity.ai.goal.target.h" #include "net.minecraft.world.entity.ai.navigation.h" @@ -22,20 +23,18 @@ SnowMan::SnowMan(Level *level) : Golem(level) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_SNOWMAN;// 4J was "/mob/snowman.png"; this->setSize(0.4f, 1.8f); getNavigation()->setAvoidWater(true); - goalSelector.addGoal(1, new ArrowAttackGoal(this, 0.25f, ArrowAttackGoal::SnowballType, SharedConstants::TICKS_PER_SECOND * 1)); - goalSelector.addGoal(2, new RandomStrollGoal(this, 0.2f)); + goalSelector.addGoal(1, new RangedAttackGoal(this, this, 1.25, SharedConstants::TICKS_PER_SECOND * 1, 10)); + goalSelector.addGoal(2, new RandomStrollGoal(this, 1.0)); goalSelector.addGoal(3, new LookAtPlayerGoal(this, typeid(Player), 6)); goalSelector.addGoal(4, new RandomLookAroundGoal(this)); - targetSelector.addGoal(1, new NearestAttackableTargetGoal(this, typeid(Monster), 16, 0, true)); + targetSelector.addGoal(1, new NearestAttackableTargetGoal(this, typeid(Mob), 0, true, false, Enemy::ENEMY_SELECTOR)); } bool SnowMan::useNewAi() @@ -43,16 +42,19 @@ bool SnowMan::useNewAi() return true; } -int SnowMan::getMaxHealth() +void SnowMan::registerAttributes() { - return 4; + Golem::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(4); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.2f); } void SnowMan::aiStep() { Golem::aiStep(); - if (this->isInWaterOrRain()) hurt(DamageSource::drown, 1); + if (isInWaterOrRain()) hurt(DamageSource::drown, 1); { int xx = Mth::floor(x); @@ -74,7 +76,7 @@ void SnowMan::aiStep() { if (Tile::topSnow->mayPlace(level, xx, yy, zz)) { - level->setTile(xx, yy, zz, Tile::topSnow_Id); + level->setTileAndUpdate(xx, yy, zz, Tile::topSnow_Id); } } } @@ -94,4 +96,17 @@ void SnowMan::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) for (int i = 0; i < count; i++) { spawnAtLocation(Item::snowBall_Id, 1); } +} + +void SnowMan::performRangedAttack(shared_ptr target, float power) +{ + shared_ptr snowball = shared_ptr(new Snowball(level, dynamic_pointer_cast(shared_from_this()))); + double xd = target->x - x; + double yd = (target->y + target->getHeadHeight() - 1.1f) - snowball->y; + double zd = target->z - z; + float yo = Mth::sqrt(xd * xd + zd * zd) * 0.2f; + snowball->shoot(xd, yd + yo, zd, 1.60f, 12); + + playSound(eSoundType_RANDOM_BOW, 1.0f, 1 / (getRandom()->nextFloat() * 0.4f + 0.8f)); + level->addEntity(snowball); } \ No newline at end of file diff --git a/Minecraft.World/SnowMan.h b/Minecraft.World/SnowMan.h index cf6f094a..52dbb52f 100644 --- a/Minecraft.World/SnowMan.h +++ b/Minecraft.World/SnowMan.h @@ -1,8 +1,9 @@ #pragma once #include "Golem.h" +#include "RangedAttackMob.h" -class SnowMan : public Golem +class SnowMan : public Golem, public RangedAttackMob { public: eINSTANCEOF GetType() { return eTYPE_SNOWMAN; } @@ -12,10 +13,16 @@ public: SnowMan(Level *level); virtual bool useNewAi(); - virtual int getMaxHealth(); +protected: + virtual void registerAttributes(); + +public: virtual void aiStep(); protected: virtual int getDeathLoot(); virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); + +public: + virtual void performRangedAttack(shared_ptr target, float power); }; \ No newline at end of file diff --git a/Minecraft.World/SnowTile.cpp b/Minecraft.World/SnowTile.cpp index dde16379..e73f5ceb 100644 --- a/Minecraft.World/SnowTile.cpp +++ b/Minecraft.World/SnowTile.cpp @@ -25,11 +25,11 @@ void SnowTile::tick(Level *level, int x, int y, int z, Random *random) if (level->getBrightness(LightLayer::Block, x, y, z) > 11) { this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); } } bool SnowTile::shouldTileTick(Level *level, int x,int y,int z) { - return level->getBrightness(LightLayer::Block, x, y, z) > 11; + return level->getBrightness(LightLayer::Block, x, y, z) > 11; } \ No newline at end of file diff --git a/Minecraft.World/Snowball.cpp b/Minecraft.World/Snowball.cpp index cdcefb1b..6588ac96 100644 --- a/Minecraft.World/Snowball.cpp +++ b/Minecraft.World/Snowball.cpp @@ -19,7 +19,7 @@ Snowball::Snowball(Level *level) : Throwable(level) _init(); } -Snowball::Snowball(Level *level, shared_ptr mob) : Throwable(level,mob) +Snowball::Snowball(Level *level, shared_ptr mob) : Throwable(level,mob) { _init(); } @@ -34,12 +34,12 @@ void Snowball::onHit(HitResult *res) if (res->entity != NULL) { int damage = 0; - if (dynamic_pointer_cast(res->entity) != NULL) + if ( res->entity->instanceof(eTYPE_BLAZE) ) { damage = 3; } - DamageSource *damageSource = DamageSource::thrown(shared_from_this(), owner); + DamageSource *damageSource = DamageSource::thrown(shared_from_this(), getOwner()); res->entity->hurt(damageSource, damage); delete damageSource; } diff --git a/Minecraft.World/Snowball.h b/Minecraft.World/Snowball.h index 82971726..d78dfade 100644 --- a/Minecraft.World/Snowball.h +++ b/Minecraft.World/Snowball.h @@ -16,7 +16,7 @@ private: public: Snowball(Level *level); - Snowball(Level *level, shared_ptr mob); + Snowball(Level *level, shared_ptr mob); Snowball(Level *level, double x, double y, double z); protected: diff --git a/Minecraft.World/SnowballItem.cpp b/Minecraft.World/SnowballItem.cpp index 41dd2b7c..0149e68d 100644 --- a/Minecraft.World/SnowballItem.cpp +++ b/Minecraft.World/SnowballItem.cpp @@ -8,7 +8,7 @@ SnowballItem::SnowballItem(int id) : Item(id) { - this->maxStackSize = 16; + this->maxStackSize = 16; } shared_ptr SnowballItem::use(shared_ptr instance, Level *level, shared_ptr player) @@ -17,7 +17,7 @@ shared_ptr SnowballItem::use(shared_ptr instance, Le { instance->count--; } - level->playSound((shared_ptr ) player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); - if (!level->isClientSide) level->addEntity( shared_ptr( new Snowball(level, player) ) ); - return instance; + level->playEntitySound((shared_ptr ) player, eSoundType_RANDOM_BOW, 0.5f, 0.4f / (random->nextFloat() * 0.4f + 0.8f)); + if (!level->isClientSide) level->addEntity( shared_ptr( new Snowball(level, player) ) ); + return instance; } \ No newline at end of file diff --git a/Minecraft.World/Socket.cpp b/Minecraft.World/Socket.cpp index 4b703403..bd0c2032 100644 --- a/Minecraft.World/Socket.cpp +++ b/Minecraft.World/Socket.cpp @@ -500,6 +500,14 @@ void Socket::SocketOutputStreamNetwork::writeWithFlags(byteArray b, unsigned int return; } +#ifdef _XBOX + bool lowPriority = ( ( flags & QNET_SENDDATA_LOW_PRIORITY ) == QNET_SENDDATA_LOW_PRIORITY ); + bool requireAck = lowPriority; +#else + bool lowPriority = false; + bool requireAck = ( ( flags & NON_QNET_SENDDATA_ACK_REQUIRED ) == NON_QNET_SENDDATA_ACK_REQUIRED ); +#endif + if( m_queueIdx == SOCKET_SERVER_END ) { //printf( "Sent %u bytes of data from \"%ls\" to \"%ls\"\n", @@ -507,7 +515,7 @@ void Socket::SocketOutputStreamNetwork::writeWithFlags(byteArray b, unsigned int //hostPlayer->GetGamertag(), //m_socket->networkPlayer->GetGamertag()); - hostPlayer->SendData(socketPlayer, buffer.pbyData, buffer.dwDataSize, QNET_SENDDATA_RELIABLE | QNET_SENDDATA_SEQUENTIAL | flags); + hostPlayer->SendData(socketPlayer, buffer.pbyData, buffer.dwDataSize, lowPriority, requireAck); // DWORD queueSize = hostPlayer->GetSendQueueSize( NULL, QNET_GETSENDQUEUESIZE_BYTES ); // if( queueSize > 24000 ) @@ -523,7 +531,7 @@ void Socket::SocketOutputStreamNetwork::writeWithFlags(byteArray b, unsigned int //m_socket->networkPlayer->GetGamertag(), //hostPlayer->GetGamertag()); - socketPlayer->SendData(hostPlayer, buffer.pbyData, buffer.dwDataSize, QNET_SENDDATA_RELIABLE | QNET_SENDDATA_SEQUENTIAL | flags); + socketPlayer->SendData(hostPlayer, buffer.pbyData, buffer.dwDataSize, lowPriority, requireAck); } } } diff --git a/Minecraft.World/SoulSandTile.cpp b/Minecraft.World/SoulSandTile.cpp new file mode 100644 index 00000000..4ebcf5f6 --- /dev/null +++ b/Minecraft.World/SoulSandTile.cpp @@ -0,0 +1,21 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.phys.h" +#include "SoulSandTile.h" + + +SoulSandTile::SoulSandTile(int id) : Tile(id, Material::sand) +{ +} + +AABB *SoulSandTile::getAABB(Level *level, int x, int y, int z) +{ + float r = 2 / 16.0f; + return AABB::newTemp(x, y, z, x + 1, y + 1 - r, z + 1); +} + +void SoulSandTile::entityInside(Level *level, int x, int y, int z, shared_ptr entity) +{ + entity->xd*=0.4; + entity->zd*=0.4; +} \ No newline at end of file diff --git a/Minecraft.World/SoulSandTile.h b/Minecraft.World/SoulSandTile.h new file mode 100644 index 00000000..b461de84 --- /dev/null +++ b/Minecraft.World/SoulSandTile.h @@ -0,0 +1,11 @@ +#pragma once +#include "Tile.h" +#include "Definitions.h" + +class SoulSandTile : public Tile +{ +public: + SoulSandTile(int id); + virtual AABB *getAABB(Level *level, int x, int y, int z); + virtual void entityInside(Level *level, int x, int y, int z, shared_ptr entity); +}; \ No newline at end of file diff --git a/Minecraft.World/SoundTypes.h b/Minecraft.World/SoundTypes.h index acbe9167..81e81d79 100644 --- a/Minecraft.World/SoundTypes.h +++ b/Minecraft.World/SoundTypes.h @@ -57,7 +57,7 @@ enum eSOUND_TYPE eSoundType_MOB_CAT_PURR, eSoundType_MOB_CAT_PURREOW, eSoundType_MOB_CAT_MEOW, - eSoundType_MOB_CAT_HITT, + eSoundType_MOB_CAT_HIT, // eSoundType_MOB_IRONGOLEM_THROW, // eSoundType_MOB_IRONGOLEM_HIT, // eSoundType_MOB_IRONGOLEM_DEATH, @@ -147,6 +147,72 @@ enum eSOUND_TYPE eSoundType_DIG_STONE, eSoundType_DIG_WOOD, + // 1.6.4 + eSoundType_FIREWORKS_LAUNCH, + eSoundType_FIREWORKS_BLAST, + eSoundType_FIREWORKS_BLAST_FAR, + eSoundType_FIREWORKS_LARGE_BLAST, + eSoundType_FIREWORKS_LARGE_BLAST_FAR, + eSoundType_FIREWORKS_TWINKLE, + eSoundType_FIREWORKS_TWINKLE_FAR, + + eSoundType_MOB_BAT_IDLE, + eSoundType_MOB_BAT_HURT, + eSoundType_MOB_BAT_DEATH, + eSoundType_MOB_BAT_TAKEOFF, + + + eSoundType_MOB_WITHER_SPAWN, + eSoundType_MOB_WITHER_IDLE, //"mob.wither.idle"; + eSoundType_MOB_WITHER_HURT, //"mob.wither.hurt"; + eSoundType_MOB_WITHER_DEATH,//"mob.wither.death"; + eSoundType_MOB_WITHER_SHOOT,//"mob.wither.shoot"; + + eSoundType_MOB_COW_STEP, + eSoundType_MOB_CHICKEN_STEP, + eSoundType_MOB_PIG_STEP, + eSoundType_MOB_ENDERMAN_STARE, + eSoundType_MOB_ENDERMAN_SCREAM, + eSoundType_MOB_SHEEP_SHEAR, + eSoundType_MOB_SHEEP_STEP, + eSoundType_MOB_SKELETON_DEATH, + eSoundType_MOB_SKELETON_STEP, + eSoundType_MOB_SPIDER_STEP, + eSoundType_MOB_WOLF_STEP, + eSoundType_MOB_ZOMBIE_STEP, + eSoundType_LIQUID_SWIM, + eSoundType_MOB_HORSE_LAND, + eSoundType_MOB_HORSE_ARMOR, + eSoundType_MOB_HORSE_LEATHER, + eSoundType_MOB_HORSE_ZOMBIE_DEATH, + eSoundType_MOB_HORSE_SKELETON_DEATH, + eSoundType_MOB_HORSE_DONKEY_DEATH, + eSoundType_MOB_HORSE_DEATH, + eSoundType_MOB_HORSE_ZOMBIE_HIT, + eSoundType_MOB_HORSE_SKELETON_HIT, + eSoundType_MOB_HORSE_DONKEY_HIT, + eSoundType_MOB_HORSE_HIT, + eSoundType_MOB_HORSE_ZOMBIE_IDLE, + eSoundType_MOB_HORSE_SKELETON_IDLE, + eSoundType_MOB_HORSE_DONKEY_IDLE, + eSoundType_MOB_HORSE_IDLE, + eSoundType_MOB_HORSE_DONKEY_ANGRY, + eSoundType_MOB_HORSE_ANGRY, + eSoundType_MOB_HORSE_GALLOP, + eSoundType_MOB_HORSE_BREATHE, + eSoundType_MOB_HORSE_WOOD, + eSoundType_MOB_HORSE_SOFT, + eSoundType_MOB_HORSE_JUMP, + eSoundType_MOB_WITCH_IDLE, + eSoundType_MOB_WITCH_HURT, + eSoundType_MOB_WITCH_DEATH, + eSoundType_MOB_SLIME_BIG, + eSoundType_MOB_SLIME_SMALL, + eSoundType_EATING, + eSoundType_RANDOM_LEVELUP, + + eSoundType_FIRE_NEWIGNITE, + eSoundType_MAX }; diff --git a/Minecraft.World/Source.h b/Minecraft.World/Source.h new file mode 100644 index 00000000..aab5b83d --- /dev/null +++ b/Minecraft.World/Source.h @@ -0,0 +1,5 @@ +#pragma once + +class Source +{ +}; \ No newline at end of file diff --git a/Minecraft.World/SpawnEggItem.cpp b/Minecraft.World/SpawnEggItem.cpp new file mode 100644 index 00000000..ab082bfb --- /dev/null +++ b/Minecraft.World/SpawnEggItem.cpp @@ -0,0 +1,378 @@ +#include "stdafx.h" +#include "..\Minecraft.Client\Minecraft.h" +#include "net.minecraft.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.tile.entity.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.npc.h" +#include "net.minecraft.world.h" +#include "HitResult.h" +#include "SpawnEggItem.h" +#include "Difficulty.h" + + +SpawnEggItem::SpawnEggItem(int id) : Item(id) +{ + setMaxStackSize(16); // 4J-PB brought forward. It is 64 on PC, but we'll never be able to place that many + setStackedByData(true); + overlay = NULL; +} + +wstring SpawnEggItem::getHoverName(shared_ptr itemInstance) +{ + wstring elementName = getDescription(); + + int nameId = EntityIO::getNameId(itemInstance->getAuxValue()); + if (nameId >= 0) + { + elementName = replaceAll(elementName,L"{*CREATURE*}",app.GetString(nameId)); + //elementName += " " + I18n.get("entity." + encodeId + ".name"); + } + else + { + elementName = replaceAll(elementName,L"{*CREATURE*}",L""); + } + + return elementName; +} + +int SpawnEggItem::getColor(shared_ptr item, int spriteLayer) +{ + AUTO_VAR(it, EntityIO::idsSpawnableInCreative.find(item->getAuxValue())); + if (it != EntityIO::idsSpawnableInCreative.end()) + { + EntityIO::SpawnableMobInfo *spawnableMobInfo = it->second; + if (spriteLayer == 0) { + return Minecraft::GetInstance()->getColourTable()->getColor( spawnableMobInfo->eggColor1 ); + } + return Minecraft::GetInstance()->getColourTable()->getColor( spawnableMobInfo->eggColor2 ); + } + return 0xffffff; +} + +bool SpawnEggItem::hasMultipleSpriteLayers() +{ + return true; +} + +Icon *SpawnEggItem::getLayerIcon(int auxValue, int spriteLayer) +{ + if (spriteLayer > 0) + { + return overlay; + } + return Item::getLayerIcon(auxValue, spriteLayer); +} + +// 4J-PB - added for dispenser +shared_ptr SpawnEggItem::canSpawn(int iAuxVal, Level *level, int *piResult) +{ + shared_ptr newEntity = EntityIO::newById(iAuxVal, level); + if (newEntity != NULL) + { + bool canSpawn = false; + + switch(newEntity->GetType()) + { + case eTYPE_CHICKEN: + if(level->canCreateMore( eTYPE_CHICKEN, Level::eSpawnType_Egg) ) + { + canSpawn = true; + } + else + { + *piResult=eSpawnResult_FailTooManyChickens; + } + break; + case eTYPE_WOLF: + if(level->canCreateMore( eTYPE_WOLF, Level::eSpawnType_Egg) ) + { + canSpawn = true; + } + else + { + *piResult=eSpawnResult_FailTooManyWolves; + } + break; + case eTYPE_VILLAGER: + if(level->canCreateMore( eTYPE_VILLAGER, Level::eSpawnType_Egg) ) + { + canSpawn = true; + } + else + { + *piResult=eSpawnResult_FailTooManyVillagers; + } + break; + case eTYPE_MUSHROOMCOW: + if(level->canCreateMore(eTYPE_MUSHROOMCOW, Level::eSpawnType_Egg) ) + { + canSpawn = true; + } + else + { + *piResult=eSpawnResult_FailTooManyMooshrooms; + } + break; + case eTYPE_SQUID: + if(level->canCreateMore( eTYPE_SQUID, Level::eSpawnType_Egg) ) + { + canSpawn = true; + } + else + { + *piResult=eSpawnResult_FailTooManySquid; + } + break; + case eTYPE_BAT: + if(level->canCreateMore( eTYPE_BAT, Level::eSpawnType_Egg) ) + { + canSpawn = true; + } + else + { + *piResult=eSpawnResult_FailTooManyBats; + } + break; + default: + if ( eTYPE_FLAGSET(eTYPE_ANIMALS_SPAWN_LIMIT_CHECK, newEntity->GetType()) ) + { + if( level->canCreateMore( newEntity->GetType(), Level::eSpawnType_Egg ) ) + { + canSpawn = true; + } + else + { + // different message for each animal + + *piResult=eSpawnResult_FailTooManyPigsCowsSheepCats; + } + } + // 4J: Use eTYPE_ENEMY instead of monster (slimes and ghasts aren't monsters) + else if(newEntity->instanceof(eTYPE_ENEMY)) + { + // 4J-PB - check if the player is trying to spawn an enemy in peaceful mode + if(level->difficulty==Difficulty::PEACEFUL) + { + *piResult=eSpawnResult_FailCantSpawnInPeaceful; + } + else if(level->canCreateMore( newEntity->GetType(), Level::eSpawnType_Egg) ) + { + canSpawn = true; + } + else + { + *piResult=eSpawnResult_FailTooManyMonsters; + } + } +#ifndef _CONTENT_PACKAGE + else if(app.DebugArtToolsOn()) + { + canSpawn = true; + } +#endif + break; + } + + if(canSpawn) + { + return newEntity; + } + } + + return nullptr; +} + +bool SpawnEggItem::useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) +{ + if (level->isClientSide) + { + return true; + } + + int tile = level->getTile(x, y, z); + +#ifndef _CONTENT_PACKAGE + if(app.DebugArtToolsOn() && tile == Tile::mobSpawner_Id) + { + // 4J Stu - Force adding this as a tile update + level->removeTile(x,y,z); + level->setTileAndData(x,y,z,Tile::mobSpawner_Id, 0, Tile::UPDATE_ALL); + shared_ptr mste = dynamic_pointer_cast( level->getTileEntity(x,y,z) ); + if(mste != NULL) + { + mste->setEntityId( EntityIO::getEncodeId(itemInstance->getAuxValue()) ); + return true; + } + } +#endif + + x += Facing::STEP_X[face]; + y += Facing::STEP_Y[face]; + z += Facing::STEP_Z[face]; + + double yOff = 0; + if (face == Facing::UP && (Tile::tiles[tile] != NULL && Tile::tiles[tile]->getRenderShape() == Tile::SHAPE_FENCE)) + { + // special case + yOff = .5; + } + + int iResult=0; + shared_ptr result = spawnMobAt(level, itemInstance->getAuxValue(), x + .5, y + yOff, z + .5, &iResult); + + if(bTestUseOnOnly) + { + return result != NULL; + } + + if (result != NULL) + { + // 4J-JEV: SetCustomName is a method for Mob not LivingEntity; so change instanceof to check for Mobs. + if ( result->instanceof(eTYPE_MOB) && itemInstance->hasCustomHoverName() ) + { + dynamic_pointer_cast(result)->setCustomName(itemInstance->getHoverName()); + } + if ( !player->abilities.instabuild ) + { + itemInstance->count--; + } + } + else + { + DisplaySpawnError(player, iResult); + } + + return true; +} + +shared_ptr SpawnEggItem::use(shared_ptr itemInstance, Level *level, shared_ptr player) +{ + if (level->isClientSide) return itemInstance; + + HitResult *hr = getPlayerPOVHitResult(level, player, true); + if (hr == NULL) + { + delete hr; + return itemInstance; + } + + if (hr->type == HitResult::TILE) + { + int xt = hr->x; + int yt = hr->y; + int zt = hr->z; + + if (!level->mayInteract(player, xt, yt, zt,0)) + { + delete hr; + return itemInstance; + } + if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) return itemInstance; + + if (level->getMaterial(xt, yt, zt) == Material::water) + { + int iResult=0; + shared_ptr result = spawnMobAt(level, itemInstance->getAuxValue(), xt, yt, zt, &iResult); + if (result != NULL) + { + // 4J-JEV: SetCustomName is a method for Mob not LivingEntity; so change instanceof to check for Mobs. + if ( result->instanceof(eTYPE_MOB) && itemInstance->hasCustomHoverName() ) + { + dynamic_pointer_cast(result)->setCustomName(itemInstance->getHoverName()); + } + if (!player->abilities.instabuild) + { + itemInstance->count--; + } + } + else + { + SpawnEggItem::DisplaySpawnError(player, iResult); + } + } + } + return itemInstance; +} + +shared_ptr SpawnEggItem::spawnMobAt(Level *level, int auxVal, double x, double y, double z, int *piResult) +{ + int mobId = auxVal; + int extraData = 0; + + //4J Stu - Enable spawning specific entity sub-types + mobId = auxVal & 0xFFF; + extraData = auxVal >> 12; + + if (EntityIO::idsSpawnableInCreative.find(mobId) == EntityIO::idsSpawnableInCreative.end()) + { + return nullptr; + } + + shared_ptr newEntity = nullptr; + + for (int i = 0; i < SPAWN_COUNT; i++) + { + newEntity = canSpawn(mobId, level, piResult); + + // 4J-JEV: DynCasting to Mob not LivingEntity; so change instanceof to check for Mobs. + if ( newEntity != NULL && newEntity->instanceof(eTYPE_MOB) ) + { + shared_ptr mob = dynamic_pointer_cast(newEntity); + newEntity->moveTo(x, y, z, Mth::wrapDegrees(level->random->nextFloat() * 360), 0); + newEntity->setDespawnProtected(); // 4J added, default to being protected against despawning (has to be done after initial position is set) + mob->yHeadRot = mob->yRot; + mob->yBodyRot = mob->yRot; + + mob->finalizeMobSpawn(NULL, extraData); + level->addEntity(newEntity); + mob->playAmbientSound(); + } + } + + return newEntity; +} + +void SpawnEggItem::registerIcons(IconRegister *iconRegister) +{ + Item::registerIcons(iconRegister); + overlay = iconRegister->registerIcon(getIconName() + L"_overlay"); +} + +void SpawnEggItem::DisplaySpawnError(shared_ptr player, int result) +{ + // some negative sound effect? + //level->levelEvent(LevelEvent::SOUND_CLICK_FAIL, x, y, z, 0); + switch(result) + { + case eSpawnResult_FailTooManyPigsCowsSheepCats: + player->displayClientMessage(IDS_MAX_PIGS_SHEEP_COWS_CATS_SPAWNED ); + break; + case eSpawnResult_FailTooManyChickens: + player->displayClientMessage(IDS_MAX_CHICKENS_SPAWNED ); + break; + case eSpawnResult_FailTooManySquid: + player->displayClientMessage(IDS_MAX_SQUID_SPAWNED ); + break; + case eSpawnResult_FailTooManyBats: + player->displayClientMessage(IDS_MAX_BATS_SPAWNED); + break; + case eSpawnResult_FailTooManyWolves: + player->displayClientMessage(IDS_MAX_WOLVES_SPAWNED ); + break; + case eSpawnResult_FailTooManyMooshrooms: + player->displayClientMessage(IDS_MAX_MOOSHROOMS_SPAWNED ); + break; + case eSpawnResult_FailTooManyMonsters: + player->displayClientMessage(IDS_MAX_ENEMIES_SPAWNED ); + break; + case eSpawnResult_FailTooManyVillagers: + player->displayClientMessage(IDS_MAX_VILLAGERS_SPAWNED ); + break; + case eSpawnResult_FailCantSpawnInPeaceful: + player->displayClientMessage(IDS_CANT_SPAWN_IN_PEACEFUL ); + break; + + } +} \ No newline at end of file diff --git a/Minecraft.World/SpawnEggItem.h b/Minecraft.World/SpawnEggItem.h new file mode 100644 index 00000000..dec0e351 --- /dev/null +++ b/Minecraft.World/SpawnEggItem.h @@ -0,0 +1,48 @@ +#pragma once + +#include "Item.h" + +class SpawnEggItem : public Item +{ +private: + static const int SPAWN_COUNT = 1; + + Icon *overlay; + +public: + + enum _eSpawnResult + { + eSpawnResult_OK=0, + eSpawnResult_FailTooManyPigsCowsSheepCats, + eSpawnResult_FailTooManyChickens, + eSpawnResult_FailTooManySquid, + eSpawnResult_FailTooManyBats, + eSpawnResult_FailTooManyWolves, + eSpawnResult_FailTooManyMooshrooms, + eSpawnResult_FailTooManyAnimals, + eSpawnResult_FailTooManyMonsters, + eSpawnResult_FailTooManyVillagers, + eSpawnResult_FailCantSpawnInPeaceful, + }; + + SpawnEggItem(int id); + + virtual wstring getHoverName(shared_ptr itemInstance); + virtual int getColor(shared_ptr item, int spriteLayer); + virtual bool hasMultipleSpriteLayers(); + virtual Icon *getLayerIcon(int auxValue, int spriteLayer); + virtual bool useOn(shared_ptr itemInstance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly=false); + virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); + + static shared_ptr spawnMobAt(Level *level, int mobId, double x, double y, double z, int *piResult); // 4J Added piResult param + + // 4J-PB added for dispenser + static shared_ptr canSpawn(int iAuxVal, Level *level, int *piResult); + + // 4J: Added for neatness + static void DisplaySpawnError(shared_ptr player, int result); + + //@Override + void registerIcons(IconRegister *iconRegister); +}; \ No newline at end of file diff --git a/Minecraft.World/Spider.cpp b/Minecraft.World/Spider.cpp index ba58ce54..49997db3 100644 --- a/Minecraft.World/Spider.cpp +++ b/Minecraft.World/Spider.cpp @@ -2,11 +2,14 @@ #include "net.minecraft.world.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.item.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.effect.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.monster.h" #include "com.mojang.nbt.h" +#include "BasicTypeContainers.h" #include "Spider.h" #include "..\Minecraft.Client\Textures.h" #include "SoundTypes.h" @@ -18,13 +21,10 @@ Spider::Spider(Level *level) : Monster( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_SPIDER; // 4J was L"/mob/spider.png"; this->setSize(1.4f, 0.9f); - runSpeed = 0.8f; } void Spider::defineSynchedData() @@ -46,19 +46,12 @@ void Spider::tick() } } -int Spider::getMaxHealth() -{ - return 16; -} - -double Spider::getRideHeight() +void Spider::registerAttributes() { - return bbHeight * 0.75 - 0.5f; -} + Monster::registerAttributes(); -bool Spider::makeStepSound() -{ - return false; + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(16); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.8f); } shared_ptr Spider::findAttackTarget() @@ -96,12 +89,17 @@ int Spider::getDeathSound() return eSoundType_MOB_SPIDER_DEATH; } +void Spider::playStepSound(int xt, int yt, int zt, int t) +{ + playSound(eSoundType_MOB_SPIDER_STEP, 0.15f, 1); +} + void Spider::checkHurtTarget(shared_ptr target, float d) { float br = getBrightness(1); if (br > 0.5f && random->nextInt(100) == 0) { - this->attackTarget = nullptr; + attackTarget = nullptr; return; } @@ -139,25 +137,20 @@ void Spider::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) } /** - * The the spiders act as if they're always on a ladder, which enables them - * to climb walls. - */ +* The the spiders act as if they're always on a ladder, which enables them +* to climb walls. +*/ bool Spider::onLadder() { return isClimbing(); } - + void Spider::makeStuckInWeb() { // do nothing - spiders don't get stuck in web } -float Spider::getModelScale() -{ - return 1.0f; -} - MobType Spider::getMobType() { return ARTHROPOD; @@ -189,4 +182,71 @@ void Spider::setClimbing(bool value) flags &= ~0x1; } entityData->set(DATA_FLAGS_ID, flags); +} + +MobGroupData *Spider::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param +{ + groupData = Monster::finalizeMobSpawn(groupData); + +#ifndef _CONTENT_PACKAGE + // 4J-JEV: Added for spider-jockey spawn-egg. + if ( (level->random->nextInt(100) == 0) || (extraData != 0) ) +#else + if (level->random->nextInt(100) == 0) +#endif + { + shared_ptr skeleton = shared_ptr( new Skeleton(level) ); + skeleton->moveTo(x, y, z, yRot, 0); + skeleton->finalizeMobSpawn(NULL); + level->addEntity(skeleton); + skeleton->ride(shared_from_this()); + } + + if (groupData == NULL) + { + groupData = new SpiderEffectsGroupData(); + + if (level->difficulty > Difficulty::NORMAL && level->random->nextFloat() < SPIDER_SPECIAL_EFFECT_CHANCE * level->getDifficulty(x, y, z)) + { + ((SpiderEffectsGroupData *) groupData)->setRandomEffect(level->random); + } + } + if ( dynamic_cast( groupData ) != NULL) + { + int effect = ((SpiderEffectsGroupData *) groupData)->effectId; + if (effect > 0 && MobEffect::effects[effect] != NULL) + { + addEffect(new MobEffectInstance(effect, Integer::MAX_VALUE)); + } + } + + return groupData; +} + +const float Spider::SPIDER_SPECIAL_EFFECT_CHANCE = .1f; + +Spider::SpiderEffectsGroupData::SpiderEffectsGroupData() +{ + effectId = 0; +} + +void Spider::SpiderEffectsGroupData::setRandomEffect(Random *random) +{ + int selection = random->nextInt(5); + if (selection <= 1) + { + effectId = MobEffect::movementSpeed->id; + } + else if (selection <= 2) + { + effectId = MobEffect::damageBoost->id; + } + else if (selection <= 3) + { + effectId = MobEffect::regeneration->id; + } + else if (selection <= 4) + { + effectId = MobEffect::invisibility->id; + } } \ No newline at end of file diff --git a/Minecraft.World/Spider.h b/Minecraft.World/Spider.h index f0257d6c..941ac45a 100644 --- a/Minecraft.World/Spider.h +++ b/Minecraft.World/Spider.h @@ -2,6 +2,7 @@ using namespace std; #include "Monster.h" +#include "MobGroupData.h" class Spider : public Monster { @@ -13,33 +14,45 @@ private: static const int DATA_FLAGS_ID = 16; public: - Spider(Level *level); + Spider(Level *level); protected: virtual void defineSynchedData(); public: virtual void tick(); - virtual int getMaxHealth(); - virtual double getRideHeight(); protected: - virtual bool makeStepSound(); + virtual void registerAttributes(); virtual shared_ptr findAttackTarget(); virtual int getAmbientSound(); virtual int getHurtSound(); virtual int getDeathSound(); - virtual void checkHurtTarget(shared_ptr target, float d); + virtual void playStepSound(int xt, int yt, int zt, int t); + virtual void checkHurtTarget(shared_ptr target, float d); virtual int getDeathLoot(); virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); public: virtual bool onLadder(); - + virtual void makeStuckInWeb(); - virtual float getModelScale(); virtual MobType getMobType(); virtual bool canBeAffected(MobEffectInstance *newEffect); virtual bool isClimbing(); virtual void setClimbing(bool value); + virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param + +private: + static const float SPIDER_SPECIAL_EFFECT_CHANCE; + +public: + class SpiderEffectsGroupData : public MobGroupData + { + public: + int effectId; + + SpiderEffectsGroupData(); + void setRandomEffect(Random *random); + }; }; diff --git a/Minecraft.World/SpikeFeature.cpp b/Minecraft.World/SpikeFeature.cpp index e8886d00..629b3c83 100644 --- a/Minecraft.World/SpikeFeature.cpp +++ b/Minecraft.World/SpikeFeature.cpp @@ -12,67 +12,67 @@ SpikeFeature::SpikeFeature(int tile) bool SpikeFeature::place(Level *level, Random *random, int x, int y, int z) { - if (!(level->isEmptyTile(x, y, z) && level->getTile(x, y - 1, z) == tile)) + if (!(level->isEmptyTile(x, y, z) && level->getTile(x, y - 1, z) == tile)) { - return false; - } - int hh = random->nextInt(32) + 6; - int r = random->nextInt(4) + 1; + return false; + } + int hh = random->nextInt(32) + 6; + int r = random->nextInt(4) + 1; - for (int xx = x - r; xx <= x + r; xx++) - for (int zz = z - r; zz <= z + r; zz++) + for (int xx = x - r; xx <= x + r; xx++) + for (int zz = z - r; zz <= z + r; zz++) { - int xd = xx - x; - int zd = zz - z; - if (xd * xd + zd * zd <= r * r + 1) + int xd = xx - x; + int zd = zz - z; + if (xd * xd + zd * zd <= r * r + 1) { - if (level->getTile(xx, y - 1, zz) != tile) + if (level->getTile(xx, y - 1, zz) != tile) { return false; } - } - } + } + } - for (int yy = y; yy < y + hh; yy++) - { - if (yy < Level::genDepth) + for (int yy = y; yy < y + hh; yy++) { - for (int xx = x - r; xx <= x + r; xx++) - for (int zz = z - r; zz <= z + r; zz++) - { - int xd = xx - x; - int zd = zz - z; - if (xd * xd + zd * zd <= r * r + 1) + if (yy < Level::genDepth) + { + for (int xx = x - r; xx <= x + r; xx++) + for (int zz = z - r; zz <= z + r; zz++) { - level->setTile(xx, yy, zz, Tile::obsidian_Id); - } - } - } else break; - } - - shared_ptr enderCrystal = shared_ptr(new EnderCrystal(level)); - enderCrystal->moveTo(x + 0.5f, y + hh, z + 0.5f, random->nextFloat() * 360, 0); - level->addEntity(enderCrystal); - level->setTile(x, y + hh, z, Tile::unbreakable_Id); - - return true; + int xd = xx - x; + int zd = zz - z; + if (xd * xd + zd * zd <= r * r + 1) + { + level->setTileAndData(xx, yy, zz, Tile::obsidian_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } else break; + } + + shared_ptr enderCrystal = shared_ptr(new EnderCrystal(level)); + enderCrystal->moveTo(x + 0.5f, y + hh, z + 0.5f, random->nextFloat() * 360, 0); + level->addEntity(enderCrystal); + level->setTileAndData(x, y + hh, z, Tile::unbreakable_Id, 0, Tile::UPDATE_CLIENTS); + + return true; } bool SpikeFeature::placeWithIndex(Level *level, Random *random, int x, int y, int z,int iIndex, int iRadius) { app.DebugPrintf("Spike - %d,%d,%d - index %d\n",x,y,z,iIndex); - int hh = 12 + (iIndex*3); + int hh = 12 + (iIndex*3); // fill any tiles below the spike - for (int xx = x - iRadius; xx <= x + iRadius; xx++) + for (int xx = x - iRadius; xx <= x + iRadius; xx++) { - for (int zz = z - iRadius; zz <= z + iRadius; zz++) + for (int zz = z - iRadius; zz <= z + iRadius; zz++) { - int xd = xx - x; - int zd = zz - z; - if (xd * xd + zd * zd <= iRadius * iRadius + 1) + int xd = xx - x; + int zd = zz - z; + if (xd * xd + zd * zd <= iRadius * iRadius + 1) { int iTileBelow=1; @@ -81,43 +81,43 @@ bool SpikeFeature::placeWithIndex(Level *level, Random *random, int x, int y, in if(level->isEmptyTile(xx, y - iTileBelow, zz)) { // empty tile - level->setTileNoUpdate(xx, y - iTileBelow, zz, Tile::obsidian_Id); + level->setTileAndData(xx, y - iTileBelow, zz, Tile::obsidian_Id, 0, Tile::UPDATE_CLIENTS); } else { - level->setTile(xx, y - iTileBelow, zz, Tile::obsidian_Id); + level->setTileAndData(xx, y - iTileBelow, zz, Tile::obsidian_Id, 0, Tile::UPDATE_CLIENTS); } iTileBelow++; } - } - } + } + } } - for (int yy = y; yy < y + hh; yy++) + for (int yy = y; yy < y + hh; yy++) { - if (yy < Level::genDepth) + if (yy < Level::genDepth) { - for (int xx = x - iRadius; xx <= x + iRadius; xx++) + for (int xx = x - iRadius; xx <= x + iRadius; xx++) { - for (int zz = z - iRadius; zz <= z + iRadius; zz++) + for (int zz = z - iRadius; zz <= z + iRadius; zz++) { - int xd = xx - x; - int zd = zz - z; + int xd = xx - x; + int zd = zz - z; int iVal = xd * xd + zd * zd; - if ( iVal <= iRadius * iRadius + 1) + if ( iVal <= iRadius * iRadius + 1) { - //level->setTile(xx, yy, zz, Tile::obsidian_Id); + //level->setTile(xx, yy, zz, Tile::obsidian_Id); placeBlock(level, xx, yy, zz, Tile::obsidian_Id, 0); - } - } + } + } } - } + } else { app.DebugPrintf("Breaking out of spike feature\n"); break; } - } + } // cap the last spikes with a fence to stop lucky arrows hitting the crystal @@ -155,7 +155,7 @@ bool SpikeFeature::placeWithIndex(Level *level, Random *random, int x, int y, in // and cap off the top int yy = y + hh + 3; - + if (yy < Level::genDepth) { for (int xx = x - 2; xx <= x + 2; xx++) @@ -168,12 +168,12 @@ bool SpikeFeature::placeWithIndex(Level *level, Random *random, int x, int y, in } } - shared_ptr enderCrystal = shared_ptr(new EnderCrystal(level)); - enderCrystal->moveTo(x + 0.5f, y + hh, z + 0.5f, random->nextFloat() * 360, 0); - level->addEntity(enderCrystal); + shared_ptr enderCrystal = shared_ptr(new EnderCrystal(level)); + enderCrystal->moveTo(x + 0.5f, y + hh, z + 0.5f, random->nextFloat() * 360, 0); + level->addEntity(enderCrystal); placeBlock(level, x, y + hh, z, Tile::unbreakable_Id, 0); - //level->setTile(x, y + hh, z, Tile::unbreakable_Id); + //level->setTile(x, y + hh, z, Tile::unbreakable_Id); - return true; + return true; } diff --git a/Minecraft.World/SpreadPlayersCommand.h b/Minecraft.World/SpreadPlayersCommand.h new file mode 100644 index 00000000..b8b451d6 --- /dev/null +++ b/Minecraft.World/SpreadPlayersCommand.h @@ -0,0 +1,328 @@ +/* +package net.minecraft.commands.common; + +import java.util.*; + +import net.minecraft.commands.*; +import net.minecraft.commands.exceptions.*; +import net.minecraft.network.chat.ChatMessageComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.tile.Tile; +import net.minecraft.world.scores.Team; + +import com.google.common.collect.*; + +public class SpreadPlayersCommand extends BaseCommand { + private static final int MAX_ITERATION_COUNT = 10000; + + @Override + public String getName() { + return "spreadplayers"; + } + + @Override + public int getPermissionLevel() { + return LEVEL_GAMEMASTERS; + } + + @Override + public String getUsage(CommandSender source) { + return "commands.spreadplayers.usage"; + } + + @Override + public void execute(CommandSender source, String[] args) { + if (args.length < 6) throw new UsageException("commands.spreadplayers.usage"); + int index = 0; + double x = convertArgToCoordinate(source, Double.NaN, args[index++]); + double z = convertArgToCoordinate(source, Double.NaN, args[index++]); + double minDist = convertArgToDouble(source, args[index++], 0); + double maxDist = convertArgToDouble(source, args[index++], minDist + 1); + boolean respectTeams = convertArgToBoolean(source, args[index++]); + + List players = Lists.newArrayList(); + + while (index < args.length) { + String arg = args[index++]; + + if (PlayerSelector.isPattern(arg)) { + ServerPlayer[] result = PlayerSelector.getPlayers(source, arg); + + if (result != null && result.length != 0) { + Collections.addAll(players, result); + } else { + throw new PlayerNotFoundException(); + } + } else { + Player player = MinecraftServer.getInstance().getPlayers().getPlayer(arg); + + if (player != null) { + players.add(player); + } else { + throw new PlayerNotFoundException(); + } + } + } + + if (players.isEmpty()) { + throw new PlayerNotFoundException(); + } + + source.sendMessage(ChatMessageComponent.forTranslation("commands.spreadplayers.spreading." + (respectTeams ? "teams" : "players"), joinPlayerNames(players), x, z, minDist, maxDist)); + + spreadPlayers(source, players, new Position(x, z), minDist, maxDist, players.get(0).level, respectTeams); + } + + private void spreadPlayers(CommandSender source, List players, Position center, double spreadDist, double maxDistFromCenter, Level level, boolean respectTeams) { + Random random = new Random(); + double minX = center.x - maxDistFromCenter; + double minZ = center.z - maxDistFromCenter; + double maxX = center.x + maxDistFromCenter; + double maxZ = center.z + maxDistFromCenter; + + Position[] positions = createInitialPositions(random, respectTeams ? getNumberOfTeams(players) : players.size(), minX, minZ, maxX, maxZ); + int iterations = spreadPositions(center, spreadDist, level, random, minX, minZ, maxX, maxZ, positions, respectTeams); + double avgDistance = setPlayerPositions(players, level, positions, respectTeams); + + logAdminAction(source, "commands.spreadplayers.success." + (respectTeams ? "teams" : "players"), positions.length, center.x, center.z); + if (positions.length > 1) source.sendMessage(ChatMessageComponent.forTranslation("commands.spreadplayers.info." + (respectTeams ? "teams" : "players"), String.format("%.2f", avgDistance), + iterations)); + } + + private int getNumberOfTeams(List players) { + Set teams = Sets.newHashSet(); + + for (LivingEntity player : players) { + if (player instanceof Player) { + teams.add(((Player) player).getTeam()); + } else { + teams.add(null); + } + } + + return teams.size(); + } + + private int spreadPositions(Position center, double spreadDist, Level level, Random random, double minX, double minZ, double maxX, double maxZ, Position[] positions, boolean respectTeams) { + boolean hasCollisions = true; + int iteration; + double minDistance = Float.MAX_VALUE; + + for (iteration = 0; iteration < MAX_ITERATION_COUNT && hasCollisions; iteration++) { + hasCollisions = false; + minDistance = Float.MAX_VALUE; + + for (int i = 0; i < positions.length; i++) { + Position position = positions[i]; + int neighbourCount = 0; + Position averageNeighbourPos = new Position(); + + for (int j = 0; j < positions.length; j++) { + if (i == j) continue; + Position neighbour = positions[j]; + + double dist = position.dist(neighbour); + minDistance = Math.min(dist, minDistance); + if (dist < spreadDist) { + neighbourCount++; + averageNeighbourPos.x += neighbour.x - position.x; + averageNeighbourPos.z += neighbour.z - position.z; + } + } + + if (neighbourCount > 0) { + averageNeighbourPos.x /= neighbourCount; + averageNeighbourPos.z /= neighbourCount; + double length = averageNeighbourPos.getLength(); + + if (length > 0) { + averageNeighbourPos.normalize(); + + position.moveAway(averageNeighbourPos); + } else { + position.randomize(random, minX, minZ, maxX, maxZ); + } + + hasCollisions = true; + } + + if (position.clamp(minX, minZ, maxX, maxZ)) { + hasCollisions = true; + } + } + + if (!hasCollisions) { + for (Position position : positions) { + if (!position.isSafe(level)) { + position.randomize(random, minX, minZ, maxX, maxZ); + hasCollisions = true; + } + } + } + } + + if (iteration >= MAX_ITERATION_COUNT) { + throw new CommandException("commands.spreadplayers.failure." + (respectTeams ? "teams" : "players"), positions.length, center.x, center.z, String.format("%.2f", minDistance)); + } + + return iteration; + } + + private double setPlayerPositions(List players, Level level, Position[] positions, boolean respectTeams) { + double avgDistance = 0; + int positionIndex = 0; + Map teamPositions = Maps.newHashMap(); + + for (int i = 0; i < players.size(); i++) { + LivingEntity player = players.get(i); + Position position; + + if (respectTeams) { + Team team = player instanceof Player ? ((Player) player).getTeam() : null; + + if (!teamPositions.containsKey(team)) { + teamPositions.put(team, positions[positionIndex++]); + } + + position = teamPositions.get(team); + } else { + position = positions[positionIndex++]; + } + + player.teleportTo(Mth.floor(position.x) + 0.5f, position.getSpawnY(level), Mth.floor(position.z) + 0.5); + + double closest = Double.MAX_VALUE; + for (int j = 0; j < positions.length; j++) { + if (position == positions[j]) continue; + + double dist = position.dist(positions[j]); + closest = Math.min(dist, closest); + } + avgDistance += closest; + } + + avgDistance /= players.size(); + return avgDistance; + } + + private Position[] createInitialPositions(Random random, int count, double minX, double minZ, double maxX, double maxZ) { + Position[] result = new Position[count]; + + for (int i = 0; i < result.length; i++) { + Position position = new Position(); + + position.randomize(random, minX, minZ, maxX, maxZ); + + result[i] = position; + } + + return result; + } + + private static class Position { + double x; + double z; + + Position() { + } + + Position(double x, double z) { + this.x = x; + this.z = z; + } + + void set(double x, double z) { + this.x = x; + this.z = z; + } + + double dist(Position target) { + double dx = x - target.x; + double dz = z - target.z; + + return Math.sqrt(dx * dx + dz * dz); + } + + void normalize() { + double dist = (double) getLength(); + x /= dist; + z /= dist; + } + + float getLength() { + return Mth.sqrt(x * x + z * z); + } + + public void moveAway(Position pos) { + x -= pos.x; + z -= pos.z; + } + + public boolean clamp(double minX, double minZ, double maxX, double maxZ) { + boolean changed = false; + + if (x < minX) { + x = minX; + changed = true; + } else if (x > maxX) { + x = maxX; + changed = true; + } + + if (z < minZ) { + z = minZ; + changed = true; + } else if (z > maxZ) { + z = maxZ; + changed = true; + } + + return changed; + } + + public int getSpawnY(Level level) { + int xt = Mth.floor(x); + int zt = Mth.floor(z); + + for (int y = Level.maxBuildHeight; y > 0; y--) { + int tile = level.getTile(xt, y, zt); + + if (tile != 0) { + return y + 1; + } + } + + return Level.maxBuildHeight + 1; + } + + public boolean isSafe(Level level) { + int xt = Mth.floor(x); + int zt = Mth.floor(z); + + for (int y = Level.maxBuildHeight; y > 0; y--) { + int tile = level.getTile(xt, y, zt); + + if (tile != 0) { + Material material = Tile.tiles[tile].material; + + return !material.isLiquid() && material != Material.fire; + } + } + + return false; + } + + public void randomize(Random random, double minX, double minZ, double maxX, double maxZ) { + x = Mth.nextDouble(random, minX, maxX); + z = Mth.nextDouble(random, minZ, maxZ); + } + } +} + +*/ \ No newline at end of file diff --git a/Minecraft.World/SpringFeature.cpp b/Minecraft.World/SpringFeature.cpp index f26f0084..c6fa5e9f 100644 --- a/Minecraft.World/SpringFeature.cpp +++ b/Minecraft.World/SpringFeature.cpp @@ -22,30 +22,30 @@ bool SpringFeature::place(Level *level, Random *random, int x, int y, int z) } } - if (level->getTile(x, y + 1, z) != Tile::rock_Id) return false; - if (level->getTile(x, y - 1, z) != Tile::rock_Id) return false; + if (level->getTile(x, y + 1, z) != Tile::stone_Id) return false; + if (level->getTile(x, y - 1, z) != Tile::stone_Id) return false; - if (level->getTile(x, y, z) != 0 && level->getTile(x, y, z) != Tile::rock_Id) return false; + if (level->getTile(x, y, z) != 0 && level->getTile(x, y, z) != Tile::stone_Id) return false; - int rockCount = 0; - if (level->getTile(x - 1, y, z) == Tile::rock_Id) rockCount++; - if (level->getTile(x + 1, y, z) == Tile::rock_Id) rockCount++; - if (level->getTile(x, y, z - 1) == Tile::rock_Id) rockCount++; - if (level->getTile(x, y, z + 1) == Tile::rock_Id) rockCount++; + int rockCount = 0; + if (level->getTile(x - 1, y, z) == Tile::stone_Id) rockCount++; + if (level->getTile(x + 1, y, z) == Tile::stone_Id) rockCount++; + if (level->getTile(x, y, z - 1) == Tile::stone_Id) rockCount++; + if (level->getTile(x, y, z + 1) == Tile::stone_Id) rockCount++; - int holeCount = 0; - if (level->isEmptyTile(x - 1, y, z)) holeCount++; - if (level->isEmptyTile(x + 1, y, z)) holeCount++; - if (level->isEmptyTile(x, y, z - 1)) holeCount++; - if (level->isEmptyTile(x, y, z + 1)) holeCount++; + int holeCount = 0; + if (level->isEmptyTile(x - 1, y, z)) holeCount++; + if (level->isEmptyTile(x + 1, y, z)) holeCount++; + if (level->isEmptyTile(x, y, z - 1)) holeCount++; + if (level->isEmptyTile(x, y, z + 1)) holeCount++; - if (rockCount == 3 && holeCount == 1) + if (rockCount == 3 && holeCount == 1) { - level->setTile(x, y, z, tile); - level->setInstaTick(true); - Tile::tiles[tile]->tick(level, x, y, z, random); - level->setInstaTick(false); - } + level->setTileAndData(x, y, z, tile, 0, Tile::UPDATE_CLIENTS); + level->setInstaTick(true); + Tile::tiles[tile]->tick(level, x, y, z, random); + level->setInstaTick(false); + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/Squid.cpp b/Minecraft.World/Squid.cpp index 3e36777c..7aae3615 100644 --- a/Minecraft.World/Squid.cpp +++ b/Minecraft.World/Squid.cpp @@ -1,17 +1,16 @@ -using namespace std; - #include "stdafx.h" #include "com.mojang.nbt.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.monster.h" #include "SharedConstants.h" #include "Squid.h" #include "..\Minecraft.Client\Textures.h" - - void Squid::_init() { xBodyRot = xBodyRotO = 0.0f; @@ -32,19 +31,19 @@ Squid::Squid(Level *level) : WaterAnimal( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); + setHealth(getMaxHealth()); _init(); - this->textureIdx = TN_MOB_SQUID; // 4J - was L"/mob/squid.png"; this->setSize(0.95f, 0.95f); tentacleSpeed = 1 / (random->nextFloat() + 1) * 0.2f; } -int Squid::getMaxHealth() +void Squid::registerAttributes() { - return 10; + WaterAnimal::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(10); } int Squid::getAmbientSound() @@ -72,6 +71,11 @@ int Squid::getDeathLoot() return 0; } +bool Squid::makeStepSound() +{ + return false; +} + void Squid::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) { int count = random->nextInt(3 + playerBonusLevel) + 1; @@ -136,10 +140,10 @@ void Squid::aiStep() double horizontalMovement = sqrt(xd * xd + zd * zd); - yBodyRot += ((-(float) atan2(this->xd, this->zd) * 180 / PI) - yBodyRot) * 0.1f; + yBodyRot += ((-(float) atan2(xd, zd) * 180 / PI) - yBodyRot) * 0.1f; yRot = yBodyRot; zBodyRot = zBodyRot + (float) PI * rotateSpeed * 1.5f; - xBodyRot += ((-(float) atan2(horizontalMovement, this->yd) * 180 / PI) - xBodyRot) * 0.1f; + xBodyRot += ((-(float) atan2(horizontalMovement, yd) * 180 / PI) - xBodyRot) * 0.1f; } else { diff --git a/Minecraft.World/Squid.h b/Minecraft.World/Squid.h index d5dc584c..c645d9f8 100644 --- a/Minecraft.World/Squid.h +++ b/Minecraft.World/Squid.h @@ -29,14 +29,15 @@ private: public: Squid(Level *level); - virtual int getMaxHealth(); protected: + virtual void registerAttributes(); virtual int getAmbientSound(); virtual int getHurtSound(); virtual int getDeathSound(); virtual float getSoundVolume(); virtual int getDeathLoot(); + virtual bool makeStepSound(); virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); public: diff --git a/Minecraft.World/StainedGlassBlock.cpp b/Minecraft.World/StainedGlassBlock.cpp new file mode 100644 index 00000000..3fae3d46 --- /dev/null +++ b/Minecraft.World/StainedGlassBlock.cpp @@ -0,0 +1,54 @@ +#include "stdafx.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.h" +#include "StainedGlassBlock.h" + +Icon *StainedGlassBlock::ICONS[StainedGlassBlock::ICONS_LENGTH]; + +StainedGlassBlock::StainedGlassBlock(int id, Material *material) : HalfTransparentTile(id, L"glass", material, false) +{ +} + +Icon *StainedGlassBlock::getTexture(int face, int data) +{ + return ICONS[data % ICONS_LENGTH]; +} + +int StainedGlassBlock::getSpawnResourcesAuxValue(int data) +{ + return data; +} + +int StainedGlassBlock::getItemAuxValueForBlockData(int data) +{ + return (~data & 0xf); +} + + +int StainedGlassBlock::getRenderLayer() +{ + return 1; +} + +void StainedGlassBlock::registerIcons(IconRegister *iconRegister) +{ + for (int i = 0; i < ICONS_LENGTH; i++) + { + ICONS[i] = iconRegister->registerIcon(getIconName() + L"_" + DyePowderItem::COLOR_TEXTURES[getItemAuxValueForBlockData(i)]); + } +} + +int StainedGlassBlock::getResourceCount(Random *random) +{ + return 0; +} + +bool StainedGlassBlock::isSilkTouchable() +{ + return true; +} + +bool StainedGlassBlock::isCubeShaped() +{ + return false; +} diff --git a/Minecraft.World/StainedGlassBlock.h b/Minecraft.World/StainedGlassBlock.h new file mode 100644 index 00000000..4b90d1dc --- /dev/null +++ b/Minecraft.World/StainedGlassBlock.h @@ -0,0 +1,27 @@ +#pragma once + +#include "HalfTransparentTile.h" + +class StainedGlassBlock : public HalfTransparentTile +{ + friend class ChunkRebuildData; +private: + static const int ICONS_LENGTH = 16; + static Icon *ICONS[ICONS_LENGTH]; + +public: + StainedGlassBlock(int id, Material *material); + + Icon *getTexture(int face, int data); + int getSpawnResourcesAuxValue(int data); + static int getItemAuxValueForBlockData(int data); + int getRenderLayer(); + void registerIcons(IconRegister *iconRegister); + int getResourceCount(Random *random); + +protected: + bool isSilkTouchable(); + +public: + bool isCubeShaped(); +}; \ No newline at end of file diff --git a/Minecraft.World/StainedGlassPaneBlock.cpp b/Minecraft.World/StainedGlassPaneBlock.cpp new file mode 100644 index 00000000..086d8ae5 --- /dev/null +++ b/Minecraft.World/StainedGlassPaneBlock.cpp @@ -0,0 +1,52 @@ +#include "stdafx.h" +#include "net.minecraft.world.h" +#include "net.minecraft.world.item.h" +#include "StainedGlassPaneBlock.h" + +Icon *StainedGlassPaneBlock::ICONS[StainedGlassPaneBlock::ICONS_COUNT]; +Icon *StainedGlassPaneBlock::EDGE_ICONS[StainedGlassPaneBlock::ICONS_COUNT]; + +StainedGlassPaneBlock::StainedGlassPaneBlock(int id) : ThinFenceTile(id, L"glass", L"glass_pane_top", Material::glass, false) +{ +} + +Icon *StainedGlassPaneBlock::getIconTexture(int face, int data) +{ + return ICONS[data % ICONS_COUNT]; +} + +Icon *StainedGlassPaneBlock::getEdgeTexture(int data) +{ + return EDGE_ICONS[~data & 0xF]; +} + +Icon *StainedGlassPaneBlock::getTexture(int face, int data) +{ + return getIconTexture(face, ~data & 0xf); +} + +int StainedGlassPaneBlock::getSpawnResourcesAuxValue(int data) +{ + return data; +} + +int StainedGlassPaneBlock::getItemAuxValueForBlockData(int data) +{ + return (data & 0xf); +} + + +int StainedGlassPaneBlock::getRenderLayer() +{ + return 1; +} + +void StainedGlassPaneBlock::registerIcons(IconRegister *iconRegister) +{ + ThinFenceTile::registerIcons(iconRegister); + for (int i = 0; i < ICONS_COUNT; i++) + { + ICONS[i] = iconRegister->registerIcon(getIconName() + L"_" + DyePowderItem::COLOR_TEXTURES[getItemAuxValueForBlockData(i)]); + EDGE_ICONS[i] = iconRegister->registerIcon(getIconName() + L"_pane_top_" + DyePowderItem::COLOR_TEXTURES[getItemAuxValueForBlockData(i)]); + } +} \ No newline at end of file diff --git a/Minecraft.World/StainedGlassPaneBlock.h b/Minecraft.World/StainedGlassPaneBlock.h new file mode 100644 index 00000000..fa943f55 --- /dev/null +++ b/Minecraft.World/StainedGlassPaneBlock.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ThinFenceTile.h" + +class StainedGlassPaneBlock : public ThinFenceTile +{ + friend class ChunkRebuildData; +private: + static const int ICONS_COUNT = 16; + static Icon *ICONS[ICONS_COUNT]; + static Icon *EDGE_ICONS[ICONS_COUNT]; + +public: + StainedGlassPaneBlock(int id); + + Icon *getIconTexture(int face, int data); + Icon *getEdgeTexture(int data); + Icon *getTexture(int face, int data); + int getSpawnResourcesAuxValue(int data); + static int getItemAuxValueForBlockData(int data); + int getRenderLayer(); + void registerIcons(IconRegister *iconRegister); +}; \ No newline at end of file diff --git a/Minecraft.World/StairTile.cpp b/Minecraft.World/StairTile.cpp index 7a80e9ff..de2cc865 100644 --- a/Minecraft.World/StairTile.cpp +++ b/Minecraft.World/StairTile.cpp @@ -6,9 +6,9 @@ #include "StairTile.h" int StairTile::DEAD_SPACES[8][2] = { - {2, 6}, {3, 7}, {2, 3}, {6, 7}, - {0, 4}, {1, 5}, {0, 1}, {4, 5} - }; + {2, 6}, {3, 7}, {2, 3}, {6, 7}, + {0, 4}, {1, 5}, {0, 1}, {4, 5} +}; StairTile::StairTile(int id, Tile *base,int basedata) : Tile(id, base->material, isSolidRender()) { @@ -325,45 +325,6 @@ void StairTile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList } } - //int data = level->getData(x, y, z); - //int dir = data & 0x3; - //float lowerPieceY0 = 0; - //float lowerPieceY1 = 0.5f; - //float upperPieceY0 = 0.5f; - //float upperPieceY1 = 1; - - //if ((data & UPSIDEDOWN_BIT) != 0) - //{ - // lowerPieceY0 = .5f; - // lowerPieceY1 = 1; - // upperPieceY0 = 0; - // upperPieceY1 = .5f; - //} - - //setShape(0, lowerPieceY0, 0, 1, lowerPieceY1, 1); - //Tile::addAABBs(level, x, y, z, box, boxes); - - //if (dir == 0) - //{ - // setShape(0.5f, upperPieceY0, 0, 1, upperPieceY1, 1); - // Tile::addAABBs(level, x, y, z, box, boxes); - //} - //else if (dir == 1) - //{ - // setShape(0, upperPieceY0, 0, .5f, upperPieceY1, 1); - // Tile::addAABBs(level, x, y, z, box, boxes); - //} - //else if (dir == 2) - //{ - // setShape(0, upperPieceY0, 0.5f, 1, upperPieceY1, 1); - // Tile::addAABBs(level, x, y, z, box, boxes); - //} - //else if (dir == 3) - //{ - // setShape(0, upperPieceY0, 0, 1, upperPieceY1, .5f); - // Tile::addAABBs(level, x, y, z, box, boxes); - //} - setShape(0, 0, 0, 1, 1, 1); } @@ -416,9 +377,9 @@ Icon *StairTile::getTexture(int face, int data) return base->getTexture(face, basedata); } -int StairTile::getTickDelay() +int StairTile::getTickDelay(Level *level) { - return base->getTickDelay(); + return base->getTickDelay(level); } AABB *StairTile::getTileAABB(Level *level, int x, int y, int z) @@ -485,20 +446,20 @@ bool StairTile::use(Level *level, int x, int y, int z, shared_ptr player return base->use(level, x, y, z, player, 0, 0, 0, 0); } -void StairTile::wasExploded(Level *level, int x, int y, int z) +void StairTile::wasExploded(Level *level, int x, int y, int z, Explosion *explosion) { - base->wasExploded(level, x, y, z); + base->wasExploded(level, x, y, z, explosion); } -void StairTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void StairTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { int dir = ( Mth::floor(by->yRot * 4 / (360) + 0.5) ) & 3; int usd = level->getData(x, y, z) & UPSIDEDOWN_BIT; - if (dir == 0) level->setData(x, y, z, DIR_SOUTH | usd); - if (dir == 1) level->setData(x, y, z, DIR_WEST | usd); - if (dir == 2) level->setData(x, y, z, DIR_NORTH | usd); - if (dir == 3) level->setData(x, y, z, DIR_EAST | usd); + if (dir == 0) level->setData(x, y, z, DIR_SOUTH | usd, Tile::UPDATE_CLIENTS); + if (dir == 1) level->setData(x, y, z, DIR_WEST | usd, Tile::UPDATE_CLIENTS); + if (dir == 2) level->setData(x, y, z, DIR_NORTH | usd, Tile::UPDATE_CLIENTS); + if (dir == 3) level->setData(x, y, z, DIR_EAST | usd, Tile::UPDATE_CLIENTS); } int StairTile::getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue) diff --git a/Minecraft.World/StairTile.h b/Minecraft.World/StairTile.h index d4797f04..ff5d57ff 100644 --- a/Minecraft.World/StairTile.h +++ b/Minecraft.World/StairTile.h @@ -34,11 +34,8 @@ protected: public: void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param bool isSolidRender(bool isServerLevel = false); - bool isCubeShaped(); - int getRenderShape(); - void setBaseShape(LevelSource *level, int x, int y, int z); static bool isStairs(int id); @@ -48,59 +45,35 @@ private: public: bool setStepShape(LevelSource *level, int x, int y, int z); bool setInnerPieceShape(LevelSource *level, int x, int y, int z); - void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); /** DELEGATES: **/ public: - void addLights(Level *level, int x, int y, int z); - - void animateTick(Level *level, int x, int y, int z, Random *random); - - void attack(Level *level, int x, int y, int z, shared_ptr player); - - void destroy(Level *level, int x, int y, int z, int data); - - int getLightColor(LevelSource *level, int x, int y, int z, int tileId = -1); - float getBrightness(LevelSource *level, int x, int y, int z); - - float getExplosionResistance(shared_ptr source); - - int getRenderLayer(); - - Icon *getTexture(int face, int data); - - int getTickDelay(); - - AABB *getTileAABB(Level *level, int x, int y, int z); - - void handleEntityInside(Level *level, int x, int y, int z, shared_ptr e, Vec3 *current); - - bool mayPick(); - - bool mayPick(int data, bool liquid); - - bool mayPlace(Level *level, int x, int y, int z); - - void onPlace(Level *level, int x, int y, int z); - - void onRemove(Level *level, int x, int y, int z, int id, int data); - - void prepareRender(Level *level, int x, int y, int z); - - void stepOn(Level *level, int x, int y, int z, shared_ptr entity); - - void tick(Level *level, int x, int y, int z, Random *random); - - bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - - void wasExploded(Level *level, int x, int y, int z); - - void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); - int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); - - HitResult *clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b); - + virtual void addLights(Level *level, int x, int y, int z); + virtual void animateTick(Level *level, int x, int y, int z, Random *random); + virtual void attack(Level *level, int x, int y, int z, shared_ptr player); + virtual void destroy(Level *level, int x, int y, int z, int data); + virtual int getLightColor(LevelSource *level, int x, int y, int z, int tileId = -1); + virtual float getBrightness(LevelSource *level, int x, int y, int z); + virtual float getExplosionResistance(shared_ptr source); + virtual int getRenderLayer(); + virtual Icon *getTexture(int face, int data); + virtual int getTickDelay(Level *level); + virtual AABB *getTileAABB(Level *level, int x, int y, int z); + virtual void handleEntityInside(Level *level, int x, int y, int z, shared_ptr e, Vec3 *current); + virtual bool mayPick(); + virtual bool mayPick(int data, bool liquid); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual void onPlace(Level *level, int x, int y, int z); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual void prepareRender(Level *level, int x, int y, int z); + virtual void stepOn(Level *level, int x, int y, int z, shared_ptr entity); + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual void wasExploded(Level *level, int x, int y, int z, Explosion *explosion); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); + virtual HitResult *clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b); virtual void registerIcons(IconRegister *iconRegister); }; diff --git a/Minecraft.World/Stats.cpp b/Minecraft.World/Stats.cpp index ce9ed8a7..89da587b 100644 --- a/Minecraft.World/Stats.cpp +++ b/Minecraft.World/Stats.cpp @@ -125,9 +125,9 @@ void Stats::buildBlockStats() blocksMined[Tile::farmland->id] = newStat; newStat->postConstruct(); - newStat = new ItemStat(BLOCKS_MINED_OFFSET + 1, L"mineBlock.stone", Tile::stoneBrick->id); + newStat = new ItemStat(BLOCKS_MINED_OFFSET + 1, L"mineBlock.stone", Tile::cobblestone->id); blocksMinedStats->push_back(newStat); - blocksMined[Tile::stoneBrick->id] = newStat; + blocksMined[Tile::cobblestone->id] = newStat; newStat->postConstruct(); newStat = new ItemStat(BLOCKS_MINED_OFFSET + 2, L"mineBlock.sand", Tile::sand->id); @@ -135,9 +135,9 @@ void Stats::buildBlockStats() blocksMined[Tile::sand->id] = newStat; newStat->postConstruct(); - newStat = new ItemStat(BLOCKS_MINED_OFFSET + 3, L"mineBlock.cobblestone", Tile::rock->id); + newStat = new ItemStat(BLOCKS_MINED_OFFSET + 3, L"mineBlock.cobblestone", Tile::stone->id); blocksMinedStats->push_back(newStat); - blocksMined[Tile::rock->id] = newStat; + blocksMined[Tile::stone->id] = newStat; newStat->postConstruct(); newStat = new ItemStat(BLOCKS_MINED_OFFSET + 4, L"mineBlock.gravel", Tile::gravel->id); @@ -186,19 +186,19 @@ void Stats::buildBlockStats() blocksMined[Tile::lapisOre->id] = newStat; newStat->postConstruct(); - newStat = new ItemStat(BLOCKS_MINED_OFFSET + 13, L"mineBlock.netherrack", Tile::hellRock->id); + newStat = new ItemStat(BLOCKS_MINED_OFFSET + 13, L"mineBlock.netherrack", Tile::netherRack->id); blocksMinedStats->push_back(newStat); - blocksMined[Tile::hellRock->id] = newStat; + blocksMined[Tile::netherRack->id] = newStat; newStat->postConstruct(); - newStat = new ItemStat(BLOCKS_MINED_OFFSET + 14, L"mineBlock.soulSand", Tile::hellSand->id); + newStat = new ItemStat(BLOCKS_MINED_OFFSET + 14, L"mineBlock.soulSand", Tile::soulsand->id); blocksMinedStats->push_back(newStat); - blocksMined[Tile::hellSand->id] = newStat; + blocksMined[Tile::soulsand->id] = newStat; newStat->postConstruct(); - newStat = new ItemStat(BLOCKS_MINED_OFFSET + 15, L"mineBlock.glowstone", Tile::lightGem->id); + newStat = new ItemStat(BLOCKS_MINED_OFFSET + 15, L"mineBlock.glowstone", Tile::glowstone->id); blocksMinedStats->push_back(newStat); - blocksMined[Tile::lightGem->id] = newStat; + blocksMined[Tile::glowstone->id] = newStat; newStat->postConstruct(); newStat = new ItemStat(BLOCKS_MINED_OFFSET + 16, L"mineBlock.wood", Tile::treeTrunk->id); @@ -249,14 +249,14 @@ void Stats::buildCraftableStats() // 4J Stu - The following stats were added as it was too easy to cheat the leaderboards by dropping and picking up these items // They are now changed to mining the block which involves a tiny bit more effort - newStat = new ItemStat(BLOCKS_MINED_OFFSET + 18, L"mineBlock.wheat", Tile::crops_Id); + newStat = new ItemStat(BLOCKS_MINED_OFFSET + 18, L"mineBlock.wheat", Tile::wheat_Id); blocksMinedStats->push_back(newStat); - blocksMined[Tile::crops_Id] = newStat; + blocksMined[Tile::wheat_Id] = newStat; newStat->postConstruct(); - newStat = new ItemStat(BLOCKS_MINED_OFFSET + 19, L"mineBlock.mushroom1", Tile::mushroom1_Id); + newStat = new ItemStat(BLOCKS_MINED_OFFSET + 19, L"mineBlock.mushroom1", Tile::mushroom_brown_Id); blocksMinedStats->push_back(newStat); - blocksMined[Tile::mushroom1_Id] = newStat; + blocksMined[Tile::mushroom_brown_Id] = newStat; newStat->postConstruct(); newStat = new ItemStat(BLOCKS_MINED_OFFSET + 17, L"mineBlock.sugar", Tile::reeds_Id); @@ -407,9 +407,9 @@ void Stats::buildCraftableStats() itemsCrafted[Item::hoe_gold->id] = newStat; newStat->postConstruct(); - newStat = new ItemStat(ITEMS_CRAFTED_OFFSET + 23, L"craftItem.glowstone", Tile::lightGem_Id); + newStat = new ItemStat(ITEMS_CRAFTED_OFFSET + 23, L"craftItem.glowstone", Tile::glowstone_Id); itemsCraftedStats->push_back(newStat); - itemsCrafted[Tile::lightGem_Id] = newStat; + itemsCrafted[Tile::glowstone_Id] = newStat; newStat->postConstruct(); newStat = new ItemStat(ITEMS_CRAFTED_OFFSET + 24, L"craftItem.tnt", Tile::tnt_Id); diff --git a/Minecraft.World/StemTile.cpp b/Minecraft.World/StemTile.cpp index 15c412eb..bf9b058d 100644 --- a/Minecraft.World/StemTile.cpp +++ b/Minecraft.World/StemTile.cpp @@ -11,11 +11,11 @@ const wstring StemTile::TEXTURE_ANGLED = L"stem_bent"; StemTile::StemTile(int id, Tile *fruit) : Bush(id) { - this->fruit = fruit; + this->fruit = fruit; - setTicking(true); - float ss = 0.125f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); + setTicking(true); + float ss = 0.125f; + this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); iconAngled = NULL; } @@ -27,91 +27,93 @@ bool StemTile::mayPlaceOn(int tile) void StemTile::tick(Level *level, int x, int y, int z, Random *random) { - Tile::tick(level, x, y, z, random); - if (level->getRawBrightness(x, y + 1, z) >= Level::MAX_BRIGHTNESS - 6) + Tile::tick(level, x, y, z, random); + if (level->getRawBrightness(x, y + 1, z) >= Level::MAX_BRIGHTNESS - 6) { - float growthSpeed = getGrowthSpeed(level, x, y, z); + float growthSpeed = getGrowthSpeed(level, x, y, z); // 4J Stu - Brought forward change from 1.2.3 to make fruit more likely to grow - if (random->nextInt((int) (25 / growthSpeed) + 1) == 0) + if (random->nextInt((int) (25 / growthSpeed) + 1) == 0) { - int age = level->getData(x, y, z); - if (age < 7) + int age = level->getData(x, y, z); + if (age < 7) { - age++; - level->setData(x, y, z, age); - } + age++; + level->setData(x, y, z, age, Tile::UPDATE_CLIENTS); + } else { - if (level->getTile(x - 1, y, z) == fruit->id) return; - if (level->getTile(x + 1, y, z) == fruit->id) return; - if (level->getTile(x, y, z - 1) == fruit->id) return; - if (level->getTile(x, y, z + 1) == fruit->id) return; - - int dir = random->nextInt(4); - int xx = x; - int zz = z; - if (dir == 0) xx--; - if (dir == 1) xx++; - if (dir == 2) zz--; - if (dir == 3) zz++; + if (level->getTile(x - 1, y, z) == fruit->id) return; + if (level->getTile(x + 1, y, z) == fruit->id) return; + if (level->getTile(x, y, z - 1) == fruit->id) return; + if (level->getTile(x, y, z + 1) == fruit->id) return; + + int dir = random->nextInt(4); + int xx = x; + int zz = z; + if (dir == 0) xx--; + if (dir == 1) xx++; + if (dir == 2) zz--; + if (dir == 3) zz++; // 4J Stu - Brought forward change from 1.2.3 to not require farmland to grow fruits int below = level->getTile(xx, y - 1, zz); if (level->getTile(xx, y, zz) == 0 && (below == Tile::farmland_Id || below == Tile::dirt_Id || below == Tile::grass_Id)) { - level->setTile(xx, y, zz, fruit->id); - } + level->setTileAndUpdate(xx, y, zz, fruit->id); + } - } - } - } + } + } + } } -void StemTile::growCropsToMax(Level *level, int x, int y, int z) +void StemTile::growCrops(Level *level, int x, int y, int z) { - level->setData(x, y, z, 7); + int stage = level->getData(x, y, z) + Mth::nextInt(level->random, 2, 5); + if (stage > 7) stage = 7; + level->setData(x, y, z, stage, Tile::UPDATE_CLIENTS); } float StemTile::getGrowthSpeed(Level *level, int x, int y, int z) { - float speed = 1; + float speed = 1; - int n = level->getTile(x, y, z - 1); - int s = level->getTile(x, y, z + 1); - int w = level->getTile(x - 1, y, z); - int e = level->getTile(x + 1, y, z); + int n = level->getTile(x, y, z - 1); + int s = level->getTile(x, y, z + 1); + int w = level->getTile(x - 1, y, z); + int e = level->getTile(x + 1, y, z); - int d0 = level->getTile(x - 1, y, z - 1); - int d1 = level->getTile(x + 1, y, z - 1); - int d2 = level->getTile(x + 1, y, z + 1); - int d3 = level->getTile(x - 1, y, z + 1); + int d0 = level->getTile(x - 1, y, z - 1); + int d1 = level->getTile(x + 1, y, z - 1); + int d2 = level->getTile(x + 1, y, z + 1); + int d3 = level->getTile(x - 1, y, z + 1); - bool horizontal = w == this->id || e == this->id; - bool vertical = n == this->id || s == this->id; - bool diagonal = d0 == this->id || d1 == this->id || d2 == this->id || d3 == this->id; + bool horizontal = w == id || e == id; + bool vertical = n == id || s == id; + bool diagonal = d0 == id || d1 == id || d2 == id || d3 == id; - for (int xx = x - 1; xx <= x + 1; xx++) - for (int zz = z - 1; zz <= z + 1; zz++) + for (int xx = x - 1; xx <= x + 1; xx++) + for (int zz = z - 1; zz <= z + 1; zz++) { - int t = level->getTile(xx, y - 1, zz); + int t = level->getTile(xx, y - 1, zz); - float tileSpeed = 0; - if (t == Tile::farmland_Id) + float tileSpeed = 0; + if (t == Tile::farmland_Id) { - tileSpeed = 1; - if (level->getData(xx, y - 1, zz) > 0) tileSpeed = 3; - } + tileSpeed = 1; + if (level->getData(xx, y - 1, zz) > 0) tileSpeed = 3; + } - if (xx != x || zz != z) tileSpeed /= 4; + if (xx != x || zz != z) tileSpeed /= 4; - speed += tileSpeed; - } + speed += tileSpeed; + } - if (diagonal || (horizontal && vertical)) speed /= 2; + if (diagonal || (horizontal && vertical)) speed /= 2; - return speed; + return speed; } int StemTile::getColor(int data) @@ -141,16 +143,16 @@ int StemTile::getColor(LevelSource *level, int x, int y, int z) void StemTile::updateDefaultShape() { - float ss = 0.125f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); + float ss = 0.125f; + setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, 0.25f, 0.5f + ss); } void StemTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); - tls->yy1 = (level->getData(x, y, z) * 2 + 2) / 16.0f; - float ss = 0.125f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, (float) tls->yy1, 0.5f + ss); + tls->yy1 = (level->getData(x, y, z) * 2 + 2) / 16.0f; + float ss = 0.125f; + setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, (float) tls->yy1, 0.5f + ss); } int StemTile::getRenderShape() @@ -159,7 +161,7 @@ int StemTile::getRenderShape() } int StemTile::getConnectDir(LevelSource *level, int x, int y, int z) - { +{ int d = level->getData(x, y, z); if (d < 7) return -1; if (level->getTile(x - 1, y, z) == fruit->id) return 0; @@ -170,37 +172,30 @@ int StemTile::getConnectDir(LevelSource *level, int x, int y, int z) } /** - * Using this method instead of destroy() to determine if seeds should be - * dropped - */ +* Using this method instead of destroy() to determine if seeds should be +* dropped +*/ void StemTile::spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus) { - Tile::spawnResources(level, x, y, z, data, odds, playerBonus); + Tile::spawnResources(level, x, y, z, data, odds, playerBonus); - if (level->isClientSide) + if (level->isClientSide) { - return; - } + return; + } - Item *seed = NULL; - if (fruit == Tile::pumpkin) seed = Item::seeds_pumpkin; - if (fruit == Tile::melon) seed = Item::seeds_melon; - for (int i = 0; i < 3; i++) + Item *seed = NULL; + if (fruit == Tile::pumpkin) seed = Item::seeds_pumpkin; + if (fruit == Tile::melon) seed = Item::seeds_melon; + for (int i = 0; i < 3; i++) { - if (level->random->nextInt(5 * 3) > data) continue; - float s = 0.7f; - float xo = level->random->nextFloat() * s + (1 - s) * 0.5f; - float yo = level->random->nextFloat() * s + (1 - s) * 0.5f; - float zo = level->random->nextFloat() * s + (1 - s) * 0.5f; - shared_ptr item = shared_ptr(new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr(new ItemInstance(seed)))); - item->throwTime = 10; - level->addEntity(item); - } + popResource(level, x, y, z, shared_ptr(new ItemInstance(seed))); + } } int StemTile::getResource(int data, Random *random, int playerBonusLevel) { - return -1; + return -1; } int StemTile::getResourceCount(Random *random) diff --git a/Minecraft.World/StemTile.h b/Minecraft.World/StemTile.h index ac4fc40c..4685e0a5 100644 --- a/Minecraft.World/StemTile.h +++ b/Minecraft.World/StemTile.h @@ -16,10 +16,11 @@ private: public: StemTile(int id, Tile *fruit); - virtual bool mayPlaceOn(int tile); + virtual bool mayPlaceOn(int tile); public: virtual void tick(Level *level, int x, int y, int z, Random *random); - void growCropsToMax(Level *level, int x, int y, int z); + virtual void growCrops(Level *level, int x, int y, int z); + private: float getGrowthSpeed(Level *level, int x, int y, int z); @@ -27,21 +28,21 @@ public: using Tile::getColor; int getColor(int data); - virtual int getColor(LevelSource *level, int x, int y, int z); - virtual void updateDefaultShape(); - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param - virtual int getRenderShape(); + virtual int getColor(LevelSource *level, int x, int y, int z); + virtual void updateDefaultShape(); + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param + virtual int getRenderShape(); - int getConnectDir(LevelSource *level, int x, int y, int z); + int getConnectDir(LevelSource *level, int x, int y, int z); - /** - * Using this method instead of destroy() to determine if seeds should be - * dropped - */ - virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); + /** + * Using this method instead of destroy() to determine if seeds should be + * dropped + */ + virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonus); - virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual int getResourceCount(Random *random); + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual int getResourceCount(Random *random); virtual int cloneTileId(Level *level, int x, int y, int z); void registerIcons(IconRegister *iconRegister); Icon *getAngledTexture(); diff --git a/Minecraft.World/StoneButtonTile.cpp b/Minecraft.World/StoneButtonTile.cpp new file mode 100644 index 00000000..bc49409f --- /dev/null +++ b/Minecraft.World/StoneButtonTile.cpp @@ -0,0 +1,12 @@ +#include "stdafx.h" +#include "net.minecraft.h" +#include "StoneButtonTile.h" + +StoneButtonTile::StoneButtonTile(int id) : ButtonTile(id, false) +{ +} + +Icon *StoneButtonTile::getTexture(int face, int data) +{ + return Tile::stone->getTexture(Facing::UP); +} \ No newline at end of file diff --git a/Minecraft.World/StoneButtonTile.h b/Minecraft.World/StoneButtonTile.h new file mode 100644 index 00000000..a6d5f31b --- /dev/null +++ b/Minecraft.World/StoneButtonTile.h @@ -0,0 +1,11 @@ +#pragma once + +#include "ButtonTile.h" + +class StoneButtonTile : public ButtonTile +{ +public: + StoneButtonTile(int id); + + virtual Icon *getTexture(int face, int data); +}; \ No newline at end of file diff --git a/Minecraft.World/StoneMonsterTile.cpp b/Minecraft.World/StoneMonsterTile.cpp index d3d6a846..ec31992f 100644 --- a/Minecraft.World/StoneMonsterTile.cpp +++ b/Minecraft.World/StoneMonsterTile.cpp @@ -1,29 +1,36 @@ #include "stdafx.h" #include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" #include "StoneMonsterTile.h" const unsigned int StoneMonsterTile::STONE_MONSTER_NAMES[STONE_MONSTER_NAMES_LENGTH] = { IDS_TILE_STONE_SILVERFISH, - IDS_TILE_STONE_SILVERFISH_COBBLESTONE, - IDS_TILE_STONE_SILVERFISH_STONE_BRICK, - }; + IDS_TILE_STONE_SILVERFISH_COBBLESTONE, + IDS_TILE_STONE_SILVERFISH_STONE_BRICK, +}; StoneMonsterTile::StoneMonsterTile(int id) : Tile(id, Material::clay) { - setDestroyTime(0); + setDestroyTime(0); } Icon *StoneMonsterTile::getTexture(int face, int data) { - if (data == HOST_COBBLE) +#ifndef _CONTENT_PACKAGE + if(app.DebugArtToolsOn()) { - return Tile::stoneBrick->getTexture(face); - } - if (data == HOST_STONEBRICK) + return Tile::fire->getTexture(face, 0); + } +#endif + if (data == HOST_COBBLE) + { + return Tile::cobblestone->getTexture(face); + } + if (data == HOST_STONEBRICK) { - return Tile::stoneBrickSmooth->getTexture(face); - } - return Tile::rock->getTexture(face); + return Tile::stoneBrick->getTexture(face); + } + return Tile::stone->getTexture(face); } void StoneMonsterTile::registerIcons(IconRegister *iconRegister) @@ -33,7 +40,7 @@ void StoneMonsterTile::registerIcons(IconRegister *iconRegister) void StoneMonsterTile::destroy(Level *level, int x, int y, int z, int data) { - if (!level->isClientSide) + if (!level->isClientSide) { // 4J - limit total amount of monsters. The normal map spawning limits these to 50, and mobspawning tiles limit to 60, so give ourselves a bit of headroom here to also be able to make silverfish if(level->countInstanceOf( eTYPE_MONSTER, false) < 70 ) @@ -48,8 +55,8 @@ void StoneMonsterTile::destroy(Level *level, int x, int y, int z, int data) silverfish->spawnAnim(); } } - } - Tile::destroy(level, x, y, z, data); + } + Tile::destroy(level, x, y, z, data); } int StoneMonsterTile::getResourceCount(Random *random) @@ -59,20 +66,20 @@ int StoneMonsterTile::getResourceCount(Random *random) bool StoneMonsterTile::isCompatibleHostBlock(int block) { - return block == Tile::rock_Id || block == Tile::stoneBrick_Id || block == Tile::stoneBrickSmooth_Id; + return block == Tile::stone_Id || block == Tile::cobblestone_Id || block == Tile::stoneBrick_Id; } int StoneMonsterTile::getDataForHostBlock(int block) { - if (block == Tile::stoneBrick_Id) + if (block == Tile::cobblestone_Id) { - return HOST_COBBLE; - } - if (block == Tile::stoneBrickSmooth_Id) + return HOST_COBBLE; + } + if (block == Tile::stoneBrick_Id) { - return HOST_STONEBRICK; - } - return HOST_ROCK; + return HOST_STONEBRICK; + } + return HOST_ROCK; } Tile *StoneMonsterTile::getHostBlockForData(int data) @@ -80,26 +87,26 @@ Tile *StoneMonsterTile::getHostBlockForData(int data) switch (data) { case HOST_COBBLE: - return Tile::stoneBrick; + return Tile::cobblestone; case HOST_STONEBRICK: - return Tile::stoneBrickSmooth; + return Tile::stoneBrick; default: - return Tile::rock; + return Tile::stone; } } shared_ptr StoneMonsterTile::getSilkTouchItemInstance(int data) { - Tile *tile = Tile::rock; - if (data == HOST_COBBLE) + Tile *tile = Tile::stone; + if (data == HOST_COBBLE) { - tile = Tile::stoneBrick; - } - if (data == HOST_STONEBRICK) + tile = Tile::cobblestone; + } + if (data == HOST_STONEBRICK) { - tile = Tile::stoneBrickSmooth; - } - return shared_ptr(new ItemInstance(tile)); + tile = Tile::stoneBrick; + } + return shared_ptr(new ItemInstance(tile)); } int StoneMonsterTile::cloneTileData(Level *level, int x, int y, int z) diff --git a/Minecraft.World/StoneSlabTile.cpp b/Minecraft.World/StoneSlabTile.cpp index 5c8d8b07..e4de58da 100644 --- a/Minecraft.World/StoneSlabTile.cpp +++ b/Minecraft.World/StoneSlabTile.cpp @@ -38,11 +38,11 @@ Icon *StoneSlabTile::getTexture(int face, int data) case WOOD_SLAB: return Tile::wood->getTexture(face); case COBBLESTONE_SLAB: - return Tile::stoneBrick->getTexture(face); + return Tile::cobblestone->getTexture(face); case BRICK_SLAB: return Tile::redBrick->getTexture(face); case SMOOTHBRICK_SLAB: - return Tile::stoneBrickSmooth->getTexture(face, SmoothStoneBrickTile::TYPE_DEFAULT); + return Tile::stoneBrick->getTexture(face, SmoothStoneBrickTile::TYPE_DEFAULT); case NETHERBRICK_SLAB: return Tile::netherBrick->getTexture(Facing::UP); case QUARTZ_SLAB: diff --git a/Minecraft.World/StoneSlabTileItem.cpp b/Minecraft.World/StoneSlabTileItem.cpp index ea636f65..013ad03e 100644 --- a/Minecraft.World/StoneSlabTileItem.cpp +++ b/Minecraft.World/StoneSlabTileItem.cpp @@ -12,7 +12,7 @@ StoneSlabTileItem::StoneSlabTileItem(int id, HalfSlabTile *halfTile, HalfSlabTil this->halfTile = halfTile; this->fullTile = fullTile; - this->isFull = full; + isFull = full; setMaxDamage(0); setStackedByData(true); } @@ -40,7 +40,7 @@ bool StoneSlabTileItem::useOn(shared_ptr instance, shared_ptrcount == 0) return false; - if (!player->mayBuild(x, y, z)) return false; + if (!player->mayUseItemAt(x, y, z, face, instance)) return false; int currentTile = level->getTile(x, y, z); int currentData = level->getData(x, y, z); @@ -54,11 +54,9 @@ bool StoneSlabTileItem::useOn(shared_ptr instance, shared_ptrisUnobstructed(fullTile->getAABB(level, x, y, z)) && level->setTileAndData(x, y, z, fullTile->id, slabType)) + if (level->isUnobstructed(fullTile->getAABB(level, x, y, z)) && level->setTileAndData(x, y, z, fullTile->id, slabType, Tile::UPDATE_ALL)) { -// level.playSound(x + 0.5f, y + 0.5f, z + 0.5f, fullTile.soundType.getPlaceSound(), (fullTile.soundType.getVolume() + 1) / 2, fullTile.soundType.getPitch() * 0.8f); -// instance.count--; - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, fullTile->soundType->getStepSound(), (fullTile->soundType->getVolume() + 1) / 2, fullTile->soundType->getPitch() * 0.8f); + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, fullTile->soundType->getPlaceSound(), (fullTile->soundType->getVolume() + 1) / 2, fullTile->soundType->getPitch() * 0.8f); instance->count--; } return true; @@ -127,10 +125,9 @@ bool StoneSlabTileItem::tryConvertTargetTile(shared_ptr instance, { return true; } - if (level->isUnobstructed(fullTile->getAABB(level, x, y, z)) && level->setTileAndData(x, y, z, fullTile->id, slabType)) + if (level->isUnobstructed(fullTile->getAABB(level, x, y, z)) && level->setTileAndData(x, y, z, fullTile->id, slabType, Tile::UPDATE_ALL)) { - //level.playSound(x + 0.5f, y + 0.5f, z + 0.5f, fullTile.soundType.getPlaceSound(), (fullTile.soundType.getVolume() + 1) / 2, fullTile.soundType.getPitch() * 0.8f); - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, fullTile->soundType->getStepSound(), (fullTile->soundType->getVolume() + 1) / 2, fullTile->soundType->getPitch() * 0.8f); + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, fullTile->soundType->getPlaceSound(), (fullTile->soundType->getVolume() + 1) / 2, fullTile->soundType->getPitch() * 0.8f); instance->count--; } return true; diff --git a/Minecraft.World/StoneTile.cpp b/Minecraft.World/StoneTile.cpp index 330cc087..01330894 100644 --- a/Minecraft.World/StoneTile.cpp +++ b/Minecraft.World/StoneTile.cpp @@ -7,5 +7,5 @@ StoneTile::StoneTile(int id) : Tile(id, Material::stone) int StoneTile::getResource(int data, Random *random, int playerBonusLevel) { - return Tile::stoneBrick_Id; + return Tile::cobblestone_Id; } \ No newline at end of file diff --git a/Minecraft.World/StringHelpers.cpp b/Minecraft.World/StringHelpers.cpp index f305c185..6985c88f 100644 --- a/Minecraft.World/StringHelpers.cpp +++ b/Minecraft.World/StringHelpers.cpp @@ -68,6 +68,20 @@ const char *wstringtofilename(const wstring& name) return buf; } +const char *wstringtochararray(const wstring& name) +{ + static char buf[256]; + assert(name.length()<256); + for(unsigned int i = 0; i < name.length(); i++ ) + { + wchar_t c = name[i]; + assert(c<128); // Will we have to do any conversion of non-ASCII characters in filenames? + buf[i] = (char)c; + } + buf[name.length()] = 0; + return buf; +} + wstring filenametowstring(const char *name) { return convStringToWstring(name); diff --git a/Minecraft.World/StringHelpers.h b/Minecraft.World/StringHelpers.h index 609fdf5a..1b364118 100644 --- a/Minecraft.World/StringHelpers.h +++ b/Minecraft.World/StringHelpers.h @@ -13,23 +13,30 @@ template std::wstring _toString(T t) oss << std::dec << t; return oss.str(); } +template std::wstring _toHexString(T t) +{ + std::wostringstream oss; + oss << std::hex << t; + return oss.str(); +} template T _fromString(const std::wstring& s) { - std::wistringstream stream (s); - T t; - stream >> t; - return t; + std::wistringstream stream (s); + T t; + stream >> t; + return t; } template T _fromHEXString(const std::wstring& s) { - std::wistringstream stream (s); - T t; - stream >> std::hex >> t; - return t; + std::wistringstream stream (s); + T t; + stream >> std::hex >> t; + return t; } wstring convStringToWstring(const string& converting); const char *wstringtofilename(const wstring& name); +const char *wstringtochararray(const wstring& name); wstring filenametowstring(const char *name); std::vector &stringSplit(const std::wstring &s, wchar_t delim, std::vector &elems); diff --git a/Minecraft.World/StringTag.h b/Minecraft.World/StringTag.h index badd53e6..8eb0eb7f 100644 --- a/Minecraft.World/StringTag.h +++ b/Minecraft.World/StringTag.h @@ -13,7 +13,7 @@ public: dos->writeUTF(data); } - void load(DataInput *dis) + void load(DataInput *dis, int tagDepth) { data = dis->readUTF(); } diff --git a/Minecraft.World/StrongholdFeature.cpp b/Minecraft.World/StrongholdFeature.cpp index 5372f4f9..3aed0195 100644 --- a/Minecraft.World/StrongholdFeature.cpp +++ b/Minecraft.World/StrongholdFeature.cpp @@ -4,9 +4,14 @@ #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.biome.h" #include "net.minecraft.world.level.dimension.h" +#include "Mth.h" #include "FileHeader.h" #include "JavaMath.h" +const wstring StrongholdFeature::OPTION_DISTANCE = L"distance"; +const wstring StrongholdFeature::OPTION_COUNT = L"count"; +const wstring StrongholdFeature::OPTION_SPREAD = L"spread"; + vector StrongholdFeature::allowedBiomes; void StrongholdFeature::staticCtor() @@ -26,33 +31,69 @@ void StrongholdFeature::staticCtor() allowedBiomes.push_back(Biome::jungleHills); }; - -StrongholdFeature::StrongholdFeature() : StructureFeature() +void StrongholdFeature::_init() { + distance = 32; + spread = 3; + // 4J added initialisers - for (int i = 0; i < strongholdPos_length; i++) + for (int i = 0; i < strongholdPos_length; i++) { strongholdPos[i] = NULL; } isSpotSelected = false; } +StrongholdFeature::StrongholdFeature() : StructureFeature() +{ + _init(); +} + +StrongholdFeature::StrongholdFeature(unordered_map options) +{ + _init(); + + for (AUTO_VAR(it, options.begin()); it != options.end(); ++it) + { + if (it->first.compare(OPTION_DISTANCE) == 0) + { + distance = Mth::getDouble(it->second, distance, 1); + } + else if (it->first.compare(OPTION_COUNT) == 0) + { + // 4J-JEV: Removed, we only have the one stronghold. + //strongholdPos = new ChunkPos[ Mth::getInt(it->second, strongholdPos_length, 1) ]; + assert(false); + } + else if (it->first.compare(OPTION_SPREAD) == 0) + { + spread = Mth::getInt(it->second, spread, 1); + } + } +} + StrongholdFeature::~StrongholdFeature() { - for (int i = 0; i < strongholdPos_length; i++) + for (int i = 0; i < strongholdPos_length; i++) { delete strongholdPos[i]; } } +wstring StrongholdFeature::getFeatureName() +{ + return LargeFeature::STRONGHOLD; +} + bool StrongholdFeature::isFeatureChunk(int x, int z,bool bIsSuperflat) { - if (!isSpotSelected) + if (!isSpotSelected) { Random random; - random.setSeed(level->getSeed()); + random.setSeed(level->getSeed()); double angle = random.nextDouble() * PI * 2.0; + int circle = 1; // 4J Stu - Changed so that we keep trying more until we have found somewhere in the world to place a stronghold bool hasFoundValidPos = false; @@ -71,7 +112,7 @@ bool StrongholdFeature::isFeatureChunk(int x, int z,bool bIsSuperflat) else { // Original Java - dist = (1.25 + random.nextDouble()) * 32.0; + dist = (1.25 * circle + random.nextDouble()) * (distance * circle); } #else // 4J Stu - Design change: Original spawns at *32 chunks rather than *10 chunks from (0,0) but that is outside our world @@ -118,10 +159,6 @@ bool StrongholdFeature::isFeatureChunk(int x, int z,bool bIsSuperflat) // 4J Added hasFoundValidPos = true; delete position; - } - else - { - app.DebugPrintf("Placed stronghold in INVALID biome at (%d, %d)\n", selectedX, selectedZ); } delete strongholdPos[i]; @@ -135,7 +172,7 @@ bool StrongholdFeature::isFeatureChunk(int x, int z,bool bIsSuperflat) // 4J Stu - Randomise the angles for retries as well #ifdef _LARGE_WORLDS - angle = random.nextDouble() * PI * 2.0; + angle = random.nextDouble() * PI * 2.0 * circle / (double) spread; #endif } while(!hasFoundValidPos && findAttempts < MAX_STRONGHOLD_ATTEMPTS); @@ -148,8 +185,8 @@ bool StrongholdFeature::isFeatureChunk(int x, int z,bool bIsSuperflat) } isSpotSelected = true; - } - + } + for (int i = 0; i < strongholdPos_length; i++) { bool forcePlacement = false; @@ -160,65 +197,70 @@ bool StrongholdFeature::isFeatureChunk(int x, int z,bool bIsSuperflat) } ChunkPos *pos = strongholdPos[i]; - if (forcePlacement || (pos && x == pos->x && z == pos->z) ) + if (forcePlacement || (pos && x == pos->x && z == pos->z) ) { - return true; - } + return true; + } } - return false; + return false; } vector *StrongholdFeature::getGuesstimatedFeaturePositions() { - vector *positions = new vector(); + vector *positions = new vector(); for( int i = 0; i < strongholdPos_length; i++ ) { ChunkPos *chunkPos = strongholdPos[i]; - if (chunkPos != NULL) + if (chunkPos != NULL) { positions->push_back(chunkPos->getMiddleBlockPosition(64)); - } - } - return positions; + } + } + return positions; } StructureStart *StrongholdFeature::createStructureStart(int x, int z) { - StrongholdStart *start = new StrongholdStart(level, random, x, z); + StrongholdStart *start = new StrongholdStart(level, random, x, z); // 4J - front() was get(0) while (start->getPieces()->empty() || ((StrongholdPieces::StartPiece *) start->getPieces()->front())->portalRoomPiece == NULL) { delete start; - // regenerate stronghold without changing seed - start = new StrongholdStart(level, random, x, z); - } + // regenerate stronghold without changing seed + start = new StrongholdStart(level, random, x, z); + } - return start; + return start; - // System.out.println("Creating stronghold at (" + x + ", " + z + ")"); - // return new StrongholdStart(level, random, x, z); + // System.out.println("Creating stronghold at (" + x + ", " + z + ")"); + // return new StrongholdStart(level, random, x, z); } -StrongholdFeature::StrongholdStart::StrongholdStart(Level *level, Random *random, int chunkX, int chunkZ) : StructureStart() +StrongholdFeature::StrongholdStart::StrongholdStart() { - StrongholdPieces::resetPieces(); + // for reflection +} + +StrongholdFeature::StrongholdStart::StrongholdStart(Level *level, Random *random, int chunkX, int chunkZ) : StructureStart(chunkX, chunkZ) +{ + StrongholdPieces::resetPieces(); - StrongholdPieces::StartPiece *startRoom = new StrongholdPieces::StartPiece(0, random, (chunkX << 4) + 2, (chunkZ << 4) + 2, level); - pieces.push_back(startRoom); - startRoom->addChildren(startRoom, &pieces, random); + StrongholdPieces::StartPiece *startRoom = new StrongholdPieces::StartPiece(0, random, (chunkX << 4) + 2, (chunkZ << 4) + 2, level); + pieces.push_back(startRoom); + startRoom->addChildren(startRoom, &pieces, random); - vector *pendingChildren = &startRoom->pendingChildren; - while (!pendingChildren->empty()) + vector *pendingChildren = &startRoom->pendingChildren; + while (!pendingChildren->empty()) { - int pos = random->nextInt((int)pendingChildren->size()); + int pos = random->nextInt((int)pendingChildren->size()); AUTO_VAR(it, pendingChildren->begin() + pos); StructurePiece *structurePiece = *it; pendingChildren->erase(it); - structurePiece->addChildren(startRoom, &pieces, random); - } + structurePiece->addChildren(startRoom, &pieces, random); + } - calculateBoundingBox(); - moveBelowSeaLevel(level, random, 10); + calculateBoundingBox(); + moveBelowSeaLevel(level, random, 10); } \ No newline at end of file diff --git a/Minecraft.World/StrongholdFeature.h b/Minecraft.World/StrongholdFeature.h index c96e9933..57dc5e2d 100644 --- a/Minecraft.World/StrongholdFeature.h +++ b/Minecraft.World/StrongholdFeature.h @@ -18,28 +18,45 @@ class Biome; class StrongholdFeature : public StructureFeature { +public: + static const wstring OPTION_DISTANCE; + static const wstring OPTION_COUNT; + static const wstring OPTION_SPREAD; + public: static void staticCtor(); private: static vector allowedBiomes; - bool isSpotSelected; + bool isSpotSelected; static const int strongholdPos_length = 1;// Java game has 3, but xbox game only has 1 because of the world size; // 4J added - ChunkPos *strongholdPos[strongholdPos_length]; + ChunkPos *strongholdPos[strongholdPos_length]; + double distance; + int spread; + + void _init(); public: StrongholdFeature(); + StrongholdFeature(unordered_map options); ~StrongholdFeature(); + wstring getFeatureName(); + protected: virtual bool isFeatureChunk(int x, int z, bool bIsSuperflat=false); vector *getGuesstimatedFeaturePositions(); - virtual StructureStart *createStructureStart(int x, int z); + virtual StructureStart *createStructureStart(int x, int z); -private: +public: class StrongholdStart : public StructureStart { public: + static StructureStart *Create() { return new StrongholdStart(); } + virtual EStructureStart GetType() { return eStructureStart_StrongholdStart; } + + public: + StrongholdStart(); StrongholdStart(Level *level, Random *random, int chunkX, int chunkZ); - }; + }; }; diff --git a/Minecraft.World/StrongholdPieces.cpp b/Minecraft.World/StrongholdPieces.cpp index 0168b2ba..d736fb0e 100644 --- a/Minecraft.World/StrongholdPieces.cpp +++ b/Minecraft.World/StrongholdPieces.cpp @@ -5,6 +5,7 @@ #include "net.minecraft.world.level.tile.entity.h" #include "net.minecraft.world.level.storage.h" #include "net.minecraft.world.level.levelgen.h" +#include "net.minecraft.world.level.levelgen.structure.h" #include "net.minecraft.world.item.h" #include "WeighedTreasure.h" #include "FileHeader.h" @@ -15,6 +16,23 @@ list StrongholdPieces::currentPieces; StrongholdPieces::EPieceClass StrongholdPieces::imposedPiece; const bool StrongholdPieces::CHECK_AIR = true; +void StrongholdPieces::loadStatic() +{ + StructureFeatureIO::setPieceId(eStructurePiece_ChestCorridor, ChestCorridor::Create, L"SHCC"); + StructureFeatureIO::setPieceId(eStructurePiece_FillerCorridor, FillerCorridor::Create, L"SHFC"); + StructureFeatureIO::setPieceId(eStructurePiece_FiveCrossing, FiveCrossing::Create, L"SH5C"); + StructureFeatureIO::setPieceId(eStructurePiece_LeftTurn, LeftTurn::Create, L"SHLT"); + StructureFeatureIO::setPieceId(eStructurePiece_Library, Library::Create, L"SHLi"); + StructureFeatureIO::setPieceId(eStructurePiece_PortalRoom, PortalRoom::Create, L"SHPR"); + StructureFeatureIO::setPieceId(eStructurePiece_PrisonHall, PrisonHall::Create, L"SHPH"); + StructureFeatureIO::setPieceId(eStructurePiece_RightTurn, RightTurn::Create, L"SHRT"); + StructureFeatureIO::setPieceId(eStructurePiece_StrongholdRoomCrossing, RoomCrossing::Create, L"SHRC"); + StructureFeatureIO::setPieceId(eStructurePiece_StairsDown, StairsDown::Create, L"SHSD"); + StructureFeatureIO::setPieceId(eStructurePiece_StrongholdStartPiece, StartPiece::Create, L"SHStart"); + StructureFeatureIO::setPieceId(eStructurePiece_Straight, Straight::Create, L"SHS"); + StructureFeatureIO::setPieceId(eStructurePiece_StraightStairsDown, StraightStairsDown::Create, L"SHSSD"); +} + StrongholdPieces::PieceWeight::PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount) : weight(weight) { this->placeCount = 0; // 4J added initialiser @@ -40,16 +58,16 @@ void StrongholdPieces::resetPieces() } currentPieces.clear(); - currentPieces.push_back( new PieceWeight(EPieceClass_Straight, 40, 0) ); - currentPieces.push_back( new PieceWeight(EPieceClass_PrisonHall, 5, 5) ); - currentPieces.push_back( new PieceWeight(EPieceClass_LeftTurn, 20, 0) ); - currentPieces.push_back( new PieceWeight(EPieceClass_RightTurn, 20, 0) ); - currentPieces.push_back( new PieceWeight(EPieceClass_RoomCrossing, 10, 6) ); - currentPieces.push_back( new PieceWeight(EPieceClass_StraightStairsDown, 5, 5) ); - currentPieces.push_back( new PieceWeight(EPieceClass_StairsDown, 5, 5) ); - currentPieces.push_back( new PieceWeight(EPieceClass_FiveCrossing, 5, 4) ); + currentPieces.push_back( new PieceWeight(EPieceClass_Straight, 40, 0) ); + currentPieces.push_back( new PieceWeight(EPieceClass_PrisonHall, 5, 5) ); + currentPieces.push_back( new PieceWeight(EPieceClass_LeftTurn, 20, 0) ); + currentPieces.push_back( new PieceWeight(EPieceClass_RightTurn, 20, 0) ); + currentPieces.push_back( new PieceWeight(EPieceClass_RoomCrossing, 10, 6) ); + currentPieces.push_back( new PieceWeight(EPieceClass_StraightStairsDown, 5, 5) ); + currentPieces.push_back( new PieceWeight(EPieceClass_StairsDown, 5, 5) ); + currentPieces.push_back( new PieceWeight(EPieceClass_FiveCrossing, 5, 4) ); currentPieces.push_back( new PieceWeight(EPieceClass_ChestCorridor, 5, 4) ); - currentPieces.push_back( new PieceWeight_Library(EPieceClass_Library, 10, 2) ); + currentPieces.push_back( new PieceWeight_Library(EPieceClass_Library, 10, 2) ); currentPieces.push_back( new PieceWeight_PortalRoom(EPieceClass_PortalRoom, 20, 1) ); imposedPiece = EPieceClass_NULL; @@ -57,142 +75,142 @@ void StrongholdPieces::resetPieces() bool StrongholdPieces::updatePieceWeight() { - bool hasAnyPieces = false; - totalWeight = 0; + bool hasAnyPieces = false; + totalWeight = 0; for( AUTO_VAR(it, currentPieces.begin()); it != currentPieces.end(); it++ ) { PieceWeight *piece = *it; - if (piece->maxPlaceCount > 0 && piece->placeCount < piece->maxPlaceCount) + if (piece->maxPlaceCount > 0 && piece->placeCount < piece->maxPlaceCount) { - hasAnyPieces = true; - } - totalWeight += piece->weight; - } - return hasAnyPieces; + hasAnyPieces = true; + } + totalWeight += piece->weight; + } + return hasAnyPieces; } StrongholdPieces::StrongholdPiece *StrongholdPieces::findAndCreatePieceFactory(EPieceClass pieceClass, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth) { - StrongholdPiece *strongholdPiece = NULL; + StrongholdPiece *strongholdPiece = NULL; - if (pieceClass == EPieceClass_Straight) + if (pieceClass == EPieceClass_Straight) { - strongholdPiece = Straight::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = Straight::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } else if (pieceClass == EPieceClass_PrisonHall) { - strongholdPiece = PrisonHall::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = PrisonHall::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } else if (pieceClass == EPieceClass_LeftTurn) { - strongholdPiece = LeftTurn::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = LeftTurn::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } else if (pieceClass == EPieceClass_RightTurn) { - strongholdPiece = RightTurn::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = RightTurn::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } else if (pieceClass == EPieceClass_RoomCrossing) { - strongholdPiece = RoomCrossing::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = RoomCrossing::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } else if (pieceClass == EPieceClass_StraightStairsDown) { - strongholdPiece = StraightStairsDown::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = StraightStairsDown::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } else if (pieceClass == EPieceClass_StairsDown) { - strongholdPiece = StairsDown::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = StairsDown::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } else if (pieceClass == EPieceClass_FiveCrossing) { - strongholdPiece = FiveCrossing::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = FiveCrossing::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } else if (pieceClass == EPieceClass_ChestCorridor) { - strongholdPiece = ChestCorridor::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = ChestCorridor::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } else if (pieceClass == EPieceClass_Library) { - strongholdPiece = Library::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } - else if (pieceClass == EPieceClass_PortalRoom) + strongholdPiece = Library::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } + else if (pieceClass == EPieceClass_PortalRoom) { - strongholdPiece = PortalRoom::createPiece(pieces, random, footX, footY, footZ, direction, depth); - } + strongholdPiece = PortalRoom::createPiece(pieces, random, footX, footY, footZ, direction, depth); + } - return strongholdPiece; + return strongholdPiece; } StrongholdPieces::StrongholdPiece *StrongholdPieces::generatePieceFromSmallDoor(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth) { - if (!updatePieceWeight()) + if (!updatePieceWeight()) { - return NULL; - } + return NULL; + } if (imposedPiece != EPieceClass_NULL) { - StrongholdPiece *strongholdPiece = findAndCreatePieceFactory(imposedPiece, pieces, random, footX, footY, footZ, direction, depth); - imposedPiece = EPieceClass_NULL; + StrongholdPiece *strongholdPiece = findAndCreatePieceFactory(imposedPiece, pieces, random, footX, footY, footZ, direction, depth); + imposedPiece = EPieceClass_NULL; - if (strongholdPiece != NULL) + if (strongholdPiece != NULL) { - return strongholdPiece; - } - } + return strongholdPiece; + } + } - int numAttempts = 0; - while (numAttempts < 5) + int numAttempts = 0; + while (numAttempts < 5) { - numAttempts++; + numAttempts++; - int weightSelection = random->nextInt(totalWeight); + int weightSelection = random->nextInt(totalWeight); for( AUTO_VAR(it, currentPieces.begin()); it != currentPieces.end(); it++ ) { PieceWeight *piece = *it; - weightSelection -= piece->weight; - if (weightSelection < 0) + weightSelection -= piece->weight; + if (weightSelection < 0) { - if (!piece->doPlace(depth) || piece == startPiece->previousPiece) + if (!piece->doPlace(depth) || piece == startPiece->previousPiece) { - break; - } + break; + } - StrongholdPiece *strongholdPiece = findAndCreatePieceFactory(piece->pieceClass, pieces, random, footX, footY, footZ, direction, depth); - if (strongholdPiece != NULL) + StrongholdPiece *strongholdPiece = findAndCreatePieceFactory(piece->pieceClass, pieces, random, footX, footY, footZ, direction, depth); + if (strongholdPiece != NULL) { - piece->placeCount++; - startPiece->previousPiece = piece; + piece->placeCount++; + startPiece->previousPiece = piece; - if (!piece->isValid()) + if (!piece->isValid()) { - currentPieces.remove(piece); - } - return strongholdPiece; - } - } - } - } - { - BoundingBox *box = FillerCorridor::findPieceBox(pieces, random, footX, footY, footZ, direction); - if (box != NULL && box->y0 > 1) + currentPieces.remove(piece); + } + return strongholdPiece; + } + } + } + } + { + BoundingBox *box = FillerCorridor::findPieceBox(pieces, random, footX, footY, footZ, direction); + if (box != NULL && box->y0 > 1) { - return new FillerCorridor(depth, random, box, direction); - } + return new FillerCorridor(depth, random, box, direction); + } if(box != NULL) delete box; - } + } - return NULL; + return NULL; } StructurePiece *StrongholdPieces::generateAndAddPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth) { - if (depth > MAX_DEPTH) + if (depth > MAX_DEPTH) { - return NULL; - } - if (abs(footX - startPiece->getBoundingBox()->x0) > 3 * 16 || abs(footZ - startPiece->getBoundingBox()->z0) > 3 * 16) + return NULL; + } + if (abs(footX - startPiece->getBoundingBox()->x0) > 3 * 16 || abs(footZ - startPiece->getBoundingBox()->z0) > 3 * 16) { // Force attempt at spawning a portal room if(startPiece->m_level->getOriginalSaveVersion() >= SAVE_FILE_VERSION_MOVED_STRONGHOLD && !startPiece->m_level->getLevelData()->getHasStrongholdEndPortal()) @@ -223,142 +241,159 @@ StructurePiece *StrongholdPieces::generateAndAddPiece(StartPiece *startPiece, li } } } - return NULL; - } + return NULL; + } - StructurePiece *newPiece = generatePieceFromSmallDoor(startPiece, pieces, random, footX, footY, footZ, direction, depth + 1); - if (newPiece != NULL) + StructurePiece *newPiece = generatePieceFromSmallDoor(startPiece, pieces, random, footX, footY, footZ, direction, depth + 1); + if (newPiece != NULL) { pieces->push_back(newPiece); - startPiece->pendingChildren.push_back(newPiece); -// newPiece.addChildren(startPiece, pieces, random, depth + 1); - } - return newPiece; + startPiece->pendingChildren.push_back(newPiece); + // newPiece.addChildren(startPiece, pieces, random, depth + 1); + } + return newPiece; +} + +StrongholdPieces::StrongholdPiece::StrongholdPiece() +{ + entryDoor = OPENING; + // for reflection } StrongholdPieces::StrongholdPiece::StrongholdPiece(int genDepth) : StructurePiece(genDepth) { + entryDoor = OPENING; +} + +void StrongholdPieces::StrongholdPiece::addAdditonalSaveData(CompoundTag *tag) +{ + tag->putString(L"EntryDoor", _toString(entryDoor)); +} + +void StrongholdPieces::StrongholdPiece::readAdditonalSaveData(CompoundTag *tag) +{ + entryDoor = (SmallDoorType)_fromString(tag->getString(L"EntryDoor")); } void StrongholdPieces::StrongholdPiece::generateSmallDoor(Level *level, Random *random, BoundingBox *chunkBB, StrongholdPieces::StrongholdPiece::SmallDoorType doorType, int footX, int footY, int footZ) { - switch (doorType) - { - default: - case OPENING: - generateBox(level, chunkBB, footX, footY, footZ, footX + SMALL_DOOR_WIDTH - 1, footY + SMALL_DOOR_HEIGHT - 1, footZ, 0, 0, false); - break; - case WOOD_DOOR: - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX, footY, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX, footY + 1, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX, footY + 2, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX + 1, footY + 2, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX + 2, footY + 2, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX + 2, footY + 1, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX + 2, footY, footZ, chunkBB); - placeBlock(level, Tile::door_wood_Id, 0, footX + 1, footY, footZ, chunkBB); - placeBlock(level, Tile::door_wood_Id, DoorTile::UPPER_BIT, footX + 1, footY + 1, footZ, chunkBB); - break; - case GRATES: - placeBlock(level, 0, 0, footX + 1, footY, footZ, chunkBB); - placeBlock(level, 0, 0, footX + 1, footY + 1, footZ, chunkBB); - placeBlock(level, Tile::ironFence_Id, 0, footX, footY, footZ, chunkBB); - placeBlock(level, Tile::ironFence_Id, 0, footX, footY + 1, footZ, chunkBB); - placeBlock(level, Tile::ironFence_Id, 0, footX, footY + 2, footZ, chunkBB); - placeBlock(level, Tile::ironFence_Id, 0, footX + 1, footY + 2, footZ, chunkBB); - placeBlock(level, Tile::ironFence_Id, 0, footX + 2, footY + 2, footZ, chunkBB); - placeBlock(level, Tile::ironFence_Id, 0, footX + 2, footY + 1, footZ, chunkBB); - placeBlock(level, Tile::ironFence_Id, 0, footX + 2, footY, footZ, chunkBB); - break; - case IRON_DOOR: - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX, footY, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX, footY + 1, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX, footY + 2, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX + 1, footY + 2, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX + 2, footY + 2, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX + 2, footY + 1, footZ, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, footX + 2, footY, footZ, chunkBB); - placeBlock(level, Tile::door_iron_Id, 0, footX + 1, footY, footZ, chunkBB); - placeBlock(level, Tile::door_iron_Id, DoorTile::UPPER_BIT, footX + 1, footY + 1, footZ, chunkBB); - placeBlock(level, Tile::button_stone_Id, getOrientationData(Tile::button_stone_Id, 4), footX + 2, footY + 1, footZ + 1, chunkBB); - placeBlock(level, Tile::button_stone_Id, getOrientationData(Tile::button_stone_Id, 3), footX + 2, footY + 1, footZ - 1, chunkBB); - break; - } + switch (doorType) + { + default: + case OPENING: + generateBox(level, chunkBB, footX, footY, footZ, footX + SMALL_DOOR_WIDTH - 1, footY + SMALL_DOOR_HEIGHT - 1, footZ, 0, 0, false); + break; + case WOOD_DOOR: + placeBlock(level, Tile::stoneBrick_Id, 0, footX, footY, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX, footY + 1, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX, footY + 2, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX + 1, footY + 2, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX + 2, footY + 2, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX + 2, footY + 1, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX + 2, footY, footZ, chunkBB); + placeBlock(level, Tile::door_wood_Id, 0, footX + 1, footY, footZ, chunkBB); + placeBlock(level, Tile::door_wood_Id, DoorTile::UPPER_BIT, footX + 1, footY + 1, footZ, chunkBB); + break; + case GRATES: + placeBlock(level, 0, 0, footX + 1, footY, footZ, chunkBB); + placeBlock(level, 0, 0, footX + 1, footY + 1, footZ, chunkBB); + placeBlock(level, Tile::ironFence_Id, 0, footX, footY, footZ, chunkBB); + placeBlock(level, Tile::ironFence_Id, 0, footX, footY + 1, footZ, chunkBB); + placeBlock(level, Tile::ironFence_Id, 0, footX, footY + 2, footZ, chunkBB); + placeBlock(level, Tile::ironFence_Id, 0, footX + 1, footY + 2, footZ, chunkBB); + placeBlock(level, Tile::ironFence_Id, 0, footX + 2, footY + 2, footZ, chunkBB); + placeBlock(level, Tile::ironFence_Id, 0, footX + 2, footY + 1, footZ, chunkBB); + placeBlock(level, Tile::ironFence_Id, 0, footX + 2, footY, footZ, chunkBB); + break; + case IRON_DOOR: + placeBlock(level, Tile::stoneBrick_Id, 0, footX, footY, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX, footY + 1, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX, footY + 2, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX + 1, footY + 2, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX + 2, footY + 2, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX + 2, footY + 1, footZ, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, footX + 2, footY, footZ, chunkBB); + placeBlock(level, Tile::door_iron_Id, 0, footX + 1, footY, footZ, chunkBB); + placeBlock(level, Tile::door_iron_Id, DoorTile::UPPER_BIT, footX + 1, footY + 1, footZ, chunkBB); + placeBlock(level, Tile::button_stone_Id, getOrientationData(Tile::button_stone_Id, 4), footX + 2, footY + 1, footZ + 1, chunkBB); + placeBlock(level, Tile::button_stone_Id, getOrientationData(Tile::button_stone_Id, 3), footX + 2, footY + 1, footZ - 1, chunkBB); + break; + } } StrongholdPieces::StrongholdPiece::SmallDoorType StrongholdPieces::StrongholdPiece::randomSmallDoor(Random *random) { - int selection = random->nextInt(5); - switch (selection) - { - default: - case 0: - case 1: - return OPENING; - case 2: - return WOOD_DOOR; - case 3: - return GRATES; - case 4: - return IRON_DOOR; - } + int selection = random->nextInt(5); + switch (selection) + { + default: + case 0: + case 1: + return OPENING; + case 2: + return WOOD_DOOR; + case 3: + return GRATES; + case 4: + return IRON_DOOR; + } } StructurePiece *StrongholdPieces::StrongholdPiece::generateSmallDoorChildForward(StartPiece *startPiece, list *pieces, Random *random, int xOff, int yOff) { - switch (orientation) + switch (orientation) { - case Direction::NORTH: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + xOff, boundingBox->y0 + yOff, boundingBox->z0 - 1, orientation, getGenDepth()); - case Direction::SOUTH: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + xOff, boundingBox->y0 + yOff, boundingBox->z1 + 1, orientation, getGenDepth()); - case Direction::WEST: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 - 1, boundingBox->y0 + yOff, boundingBox->z0 + xOff, orientation, getGenDepth()); - case Direction::EAST: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x1 + 1, boundingBox->y0 + yOff, boundingBox->z0 + xOff, orientation, getGenDepth()); - } - return NULL; + case Direction::NORTH: + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + xOff, boundingBox->y0 + yOff, boundingBox->z0 - 1, orientation, getGenDepth()); + case Direction::SOUTH: + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + xOff, boundingBox->y0 + yOff, boundingBox->z1 + 1, orientation, getGenDepth()); + case Direction::WEST: + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 - 1, boundingBox->y0 + yOff, boundingBox->z0 + xOff, orientation, getGenDepth()); + case Direction::EAST: + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x1 + 1, boundingBox->y0 + yOff, boundingBox->z0 + xOff, orientation, getGenDepth()); + } + return NULL; } StructurePiece *StrongholdPieces::StrongholdPiece::generateSmallDoorChildLeft(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff) { - switch (orientation) + switch (orientation) { case Direction::NORTH: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 - 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::WEST, getGenDepth()); + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 - 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::WEST, getGenDepth()); case Direction::SOUTH: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 - 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::WEST, getGenDepth()); + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 - 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::WEST, getGenDepth()); case Direction::WEST: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z0 - 1, Direction::NORTH, getGenDepth()); + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z0 - 1, Direction::NORTH, getGenDepth()); case Direction::EAST: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z0 - 1, Direction::NORTH, getGenDepth()); - } - return NULL; + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z0 - 1, Direction::NORTH, getGenDepth()); + } + return NULL; } StructurePiece *StrongholdPieces::StrongholdPiece::generateSmallDoorChildRight(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff) { - switch (orientation) + switch (orientation) { case Direction::NORTH: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x1 + 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::EAST, getGenDepth()); + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x1 + 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::EAST, getGenDepth()); case Direction::SOUTH: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x1 + 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::EAST, getGenDepth()); + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x1 + 1, boundingBox->y0 + yOff, boundingBox->z0 + zOff, Direction::EAST, getGenDepth()); case Direction::WEST: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); case Direction::EAST: - return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); - } - return NULL; + return generateAndAddPiece(startPiece, pieces, random, boundingBox->x0 + zOff, boundingBox->y0 + yOff, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); + } + return NULL; } - + bool StrongholdPieces::StrongholdPiece::isOkBox(BoundingBox *box, StartPiece *startRoom) { //return box != NULL && box->y0 > LOWEST_Y_POSITION; - + bool bIsOk = false; - + if(box != NULL) { if( box->y0 > LOWEST_Y_POSITION ) bIsOk = true; @@ -379,107 +414,142 @@ bool StrongholdPieces::StrongholdPiece::isOkBox(BoundingBox *box, StartPiece *st return bIsOk; } +StrongholdPieces::FillerCorridor::FillerCorridor() : steps(0) +{ + // for reflection +} + StrongholdPieces::FillerCorridor::FillerCorridor(int genDepth, Random *random, BoundingBox *corridorBox, int direction) : StrongholdPiece(genDepth), steps((direction == Direction::NORTH || direction == Direction::SOUTH) ? corridorBox->getZSpan() : corridorBox->getXSpan()) { - orientation = direction; - boundingBox = corridorBox; + orientation = direction; + boundingBox = corridorBox; +} + +void StrongholdPieces::FillerCorridor::addAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::addAdditonalSaveData(tag); + tag->putInt(L"Steps", steps); +} + +void StrongholdPieces::FillerCorridor::readAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::readAdditonalSaveData(tag); + steps = tag->getInt(L"Steps"); } BoundingBox *StrongholdPieces::FillerCorridor::findPieceBox(list *pieces, Random *random, int footX, int footY, int footZ, int direction) { - const int maxLength = 3; + const int maxLength = 3; + + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, 5, 5, maxLength + 1, direction); - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, 5, 5, maxLength + 1, direction); + StructurePiece *collisionPiece = StructurePiece::findCollisionPiece(pieces, box); - StructurePiece *collisionPiece = StructurePiece::findCollisionPiece(pieces, box); - - if (collisionPiece == NULL) + if (collisionPiece == NULL) { delete box; - // the filler must collide with something in order to be - // generated - return NULL; - } + // the filler must collide with something in order to be + // generated + return NULL; + } - if (collisionPiece->getBoundingBox()->y0 == box->y0) + if (collisionPiece->getBoundingBox()->y0 == box->y0) { delete box; - // attempt to make a smaller piece until it fits - for (int depth = maxLength; depth >= 1; depth--) + // attempt to make a smaller piece until it fits + for (int depth = maxLength; depth >= 1; depth--) { - box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, 5, 5, depth - 1, direction); - if (!collisionPiece->getBoundingBox()->intersects(box)) + box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, 5, 5, depth - 1, direction); + if (!collisionPiece->getBoundingBox()->intersects(box)) { delete box; - // the corridor has shrunk enough to fit, but make it - // one step too big to build an entrance into the other - // block - return BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, 5, 5, depth, direction); - } + // the corridor has shrunk enough to fit, but make it + // one step too big to build an entrance into the other block + return BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, 5, 5, depth, direction); + } delete box; - } - } + } + } - return NULL; + return NULL; } bool StrongholdPieces::FillerCorridor::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) + if (edgesLiquid(level, chunkBB)) { - return false; - } + return false; + } - // filler corridor - for (int i = 0; i < steps; i++) - { - // row 0 - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 0, 0, i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 1, 0, i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 2, 0, i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 3, 0, i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 4, 0, i, chunkBB); - // row 1-3 - for (int y = 1; y <= 3; y++) + // filler corridor + for (int i = 0; i < steps; i++) + { + // row 0 + placeBlock(level, Tile::stoneBrick_Id, 0, 0, 0, i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 1, 0, i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 2, 0, i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 3, 0, i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 4, 0, i, chunkBB); + // row 1-3 + for (int y = 1; y <= 3; y++) { - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 0, y, i, chunkBB); - placeBlock(level, 0, 0, 1, y, i, chunkBB); - placeBlock(level, 0, 0, 2, y, i, chunkBB); - placeBlock(level, 0, 0, 3, y, i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 4, y, i, chunkBB); - } - // row 4 - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 0, 4, i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 1, 4, i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 2, 4, i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 3, 4, i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 4, 4, i, chunkBB); - } + placeBlock(level, Tile::stoneBrick_Id, 0, 0, y, i, chunkBB); + placeBlock(level, 0, 0, 1, y, i, chunkBB); + placeBlock(level, 0, 0, 2, y, i, chunkBB); + placeBlock(level, 0, 0, 3, y, i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 4, y, i, chunkBB); + } + // row 4 + placeBlock(level, Tile::stoneBrick_Id, 0, 0, 4, i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 1, 4, i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 2, 4, i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 3, 4, i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 4, 4, i, chunkBB); + } + + return true; +} - return true; +StrongholdPieces::StairsDown::StairsDown() +{ + // for reflection } -StrongholdPieces::StairsDown::StairsDown(int genDepth, Random *random, int west, int north) : StrongholdPiece(genDepth), isSource(true), entryDoor(OPENING) +StrongholdPieces::StairsDown::StairsDown(int genDepth, Random *random, int west, int north) : StrongholdPiece(genDepth), isSource(true) { - orientation = random->nextInt(4); + orientation = random->nextInt(4); + entryDoor = OPENING; - switch (orientation) + switch (orientation) { - case Direction::NORTH: - case Direction::SOUTH: - boundingBox = new BoundingBox(west, 64, north, west + width - 1, 64 + height - 1, north + depth - 1); - break; - default: - boundingBox = new BoundingBox(west, 64, north, west + depth - 1, 64 + height - 1, north + width - 1); - break; - } + case Direction::NORTH: + case Direction::SOUTH: + boundingBox = new BoundingBox(west, 64, north, west + width - 1, 64 + height - 1, north + depth - 1); + break; + default: + boundingBox = new BoundingBox(west, 64, north, west + depth - 1, 64 + height - 1, north + width - 1); + break; + } } -StrongholdPieces::StairsDown::StairsDown(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), isSource(false), entryDoor(randomSmallDoor(random)) +StrongholdPieces::StairsDown::StairsDown(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), isSource(false) { - orientation = direction; - boundingBox = stairsBox; + entryDoor = randomSmallDoor(random); + orientation = direction; + boundingBox = stairsBox; +} + +void StrongholdPieces::StairsDown::addAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::addAdditonalSaveData(tag); + tag->putBoolean(L"Source", isSource); +} + +void StrongholdPieces::StairsDown::readAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::readAdditonalSaveData(tag); + isSource = tag->getBoolean(L"Source"); } void StrongholdPieces::StairsDown::addChildren(StructurePiece *startPiece, list *pieces, Random *random) @@ -493,18 +563,18 @@ void StrongholdPieces::StairsDown::addChildren(StructurePiece *startPiece, list< StrongholdPieces::StairsDown *StrongholdPieces::StairsDown::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, 4 - height, 0, width, height, depth, direction); + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, 4 - height, 0, width, height, depth, direction); StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } + return NULL; + } - return new StairsDown(genDepth, random, box, direction); + return new StairsDown(genDepth, random, box, direction); } bool StrongholdPieces::StairsDown::postProcess(Level *level, Random *random, BoundingBox *chunkBB) @@ -522,27 +592,32 @@ bool StrongholdPieces::StairsDown::postProcess(Level *level, Random *random, Bou generateSmallDoor(level, random, chunkBB, OPENING, 1, 1, depth - 1); // stair steps - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 2, 6, 1, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 1, 5, 1, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 2, 6, 1, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 1, 5, 1, chunkBB); placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::STONE_SLAB, 1, 6, 1, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 1, 5, 2, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 1, 4, 3, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 1, 5, 2, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 1, 4, 3, chunkBB); placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::STONE_SLAB, 1, 5, 3, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 2, 4, 3, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 3, 3, 3, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 2, 4, 3, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 3, 3, 3, chunkBB); placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::STONE_SLAB, 3, 4, 3, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 3, 3, 2, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 3, 2, 1, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 3, 3, 2, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 3, 2, 1, chunkBB); placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::STONE_SLAB, 3, 3, 1, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 2, 2, 1, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 1, 1, 1, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 2, 2, 1, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 1, 1, 1, chunkBB); placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::STONE_SLAB, 1, 2, 1, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 1, 1, 2, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 1, 1, 2, chunkBB); placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::STONE_SLAB, 1, 1, 3, chunkBB); return true; } +StrongholdPieces::StartPiece::StartPiece() +{ + // for reflection +} + StrongholdPieces::StartPiece::StartPiece(int genDepth, Random *random, int west, int north, Level *level) : StairsDown(0, random, west, north) { // 4J added initialisers @@ -562,93 +637,136 @@ TilePos *StrongholdPieces::StartPiece::getLocatorPosition() return StairsDown::getLocatorPosition(); } +StrongholdPieces::Straight::Straight() +{ + // for reflection +} + StrongholdPieces::Straight::Straight(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), - entryDoor(randomSmallDoor(random)), - leftChild(random->nextInt(2) == 0), - rightChild(random->nextInt(2) == 0) + leftChild(random->nextInt(2) == 0), + rightChild(random->nextInt(2) == 0) +{ + entryDoor = randomSmallDoor(random); + orientation = direction; + boundingBox = stairsBox; +} + +void StrongholdPieces::Straight::addAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::addAdditonalSaveData(tag); + tag->putBoolean(L"Left", leftChild); + tag->putBoolean(L"Right", rightChild); +} + +void StrongholdPieces::Straight::readAdditonalSaveData(CompoundTag *tag) { - orientation = direction; - boundingBox = stairsBox; + StrongholdPiece::readAdditonalSaveData(tag); + leftChild = tag->getBoolean(L"Left"); + rightChild = tag->getBoolean(L"Right"); } void StrongholdPieces::Straight::addChildren(StructurePiece *startPiece, list *pieces, Random *random) { - generateSmallDoorChildForward((StartPiece *) startPiece, pieces, random, 1, 1); - if (leftChild) generateSmallDoorChildLeft((StartPiece *) startPiece, pieces, random, 1, 2); - if (rightChild) generateSmallDoorChildRight((StartPiece *) startPiece, pieces, random, 1, 2); + generateSmallDoorChildForward((StartPiece *) startPiece, pieces, random, 1, 1); + if (leftChild) generateSmallDoorChildLeft((StartPiece *) startPiece, pieces, random, 1, 2); + if (rightChild) generateSmallDoorChildRight((StartPiece *) startPiece, pieces, random, 1, 2); } StrongholdPieces::Straight *StrongholdPieces::Straight::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, width, height, depth, direction); + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, width, height, depth, direction); StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } + return NULL; + } - return new Straight(genDepth, random, box, direction); + return new Straight(genDepth, random, box, direction); } bool StrongholdPieces::Straight::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) + if (edgesLiquid(level, chunkBB)) { - return false; - } + return false; + } - // bounding walls - generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); - // entry door - generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); - // exit door - generateSmallDoor(level, random, chunkBB, OPENING, 1, 1, depth - 1); + // bounding walls + generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); + // entry door + generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); + // exit door + generateSmallDoor(level, random, chunkBB, OPENING, 1, 1, depth - 1); - maybeGenerateBlock(level, chunkBB, random, .1f, 1, 2, 1, Tile::torch_Id, 0); - maybeGenerateBlock(level, chunkBB, random, .1f, 3, 2, 1, Tile::torch_Id, 0); - maybeGenerateBlock(level, chunkBB, random, .1f, 1, 2, 5, Tile::torch_Id, 0); - maybeGenerateBlock(level, chunkBB, random, .1f, 3, 2, 5, Tile::torch_Id, 0); + maybeGenerateBlock(level, chunkBB, random, .1f, 1, 2, 1, Tile::torch_Id, 0); + maybeGenerateBlock(level, chunkBB, random, .1f, 3, 2, 1, Tile::torch_Id, 0); + maybeGenerateBlock(level, chunkBB, random, .1f, 1, 2, 5, Tile::torch_Id, 0); + maybeGenerateBlock(level, chunkBB, random, .1f, 3, 2, 5, Tile::torch_Id, 0); - if (leftChild) + if (leftChild) { - generateBox(level, chunkBB, 0, 1, 2, 0, 3, 4, 0, 0, false); - } - if (rightChild) + generateBox(level, chunkBB, 0, 1, 2, 0, 3, 4, 0, 0, false); + } + if (rightChild) { - generateBox(level, chunkBB, 4, 1, 2, 4, 3, 4, 0, 0, false); - } + generateBox(level, chunkBB, 4, 1, 2, 4, 3, 4, 0, 0, false); + } - return true; + return true; } WeighedTreasure *StrongholdPieces::ChestCorridor::treasureItems[TREASURE_ITEMS_COUNT] = { - new WeighedTreasure(Item::enderPearl_Id, 0, 1, 1, 10), - new WeighedTreasure(Item::diamond_Id, 0, 1, 3, 3), - new WeighedTreasure(Item::ironIngot_Id, 0, 1, 5, 10), - new WeighedTreasure(Item::goldIngot_Id, 0, 1, 3, 5), - new WeighedTreasure(Item::redStone_Id, 0, 4, 9, 5), - new WeighedTreasure(Item::bread_Id, 0, 1, 3, 15), - new WeighedTreasure(Item::apple_Id, 0, 1, 3, 15), - new WeighedTreasure(Item::pickAxe_iron_Id, 0, 1, 1, 5), - new WeighedTreasure(Item::sword_iron_Id, 0, 1, 1, 5), - new WeighedTreasure(Item::chestplate_iron_Id, 0, 1, 1, 5), - new WeighedTreasure(Item::helmet_iron_Id, 0, 1, 1, 5), - new WeighedTreasure(Item::leggings_iron_Id, 0, 1, 1, 5), - new WeighedTreasure(Item::boots_iron_Id, 0, 1, 1, 5), - new WeighedTreasure(Item::apple_gold_Id, 0, 1, 1, 1) + new WeighedTreasure(Item::enderPearl_Id, 0, 1, 1, 10), + new WeighedTreasure(Item::diamond_Id, 0, 1, 3, 3), + new WeighedTreasure(Item::ironIngot_Id, 0, 1, 5, 10), + new WeighedTreasure(Item::goldIngot_Id, 0, 1, 3, 5), + new WeighedTreasure(Item::redStone_Id, 0, 4, 9, 5), + new WeighedTreasure(Item::bread_Id, 0, 1, 3, 15), + new WeighedTreasure(Item::apple_Id, 0, 1, 3, 15), + new WeighedTreasure(Item::pickAxe_iron_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::sword_iron_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::chestplate_iron_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::helmet_iron_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::leggings_iron_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::boots_iron_Id, 0, 1, 1, 5), + new WeighedTreasure(Item::apple_gold_Id, 0, 1, 1, 1), + // very rare for strongholds ... + new WeighedTreasure(Item::saddle_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::horseArmorMetal_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::horseArmorGold_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::horseArmorDiamond_Id, 0, 1, 1, 1), + // ... }; -StrongholdPieces::ChestCorridor::ChestCorridor(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), entryDoor(randomSmallDoor(random)) +StrongholdPieces::ChestCorridor::ChestCorridor() { + // for reflection +} + +StrongholdPieces::ChestCorridor::ChestCorridor(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth) +{ + entryDoor = randomSmallDoor(random); orientation = direction; boundingBox = stairsBox; } +void StrongholdPieces::ChestCorridor::addAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::addAdditonalSaveData(tag); + tag->putBoolean(L"Chest", hasPlacedChest); +} + +void StrongholdPieces::ChestCorridor::readAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::readAdditonalSaveData(tag); + hasPlacedChest = tag->getBoolean(L"Chest"); +} + void StrongholdPieces::ChestCorridor::addChildren(StructurePiece *startPiece, list *pieces, Random *random) { generateSmallDoorChildForward((StartPiece *) startPiece, pieces, random, 1, 1); @@ -656,63 +774,69 @@ void StrongholdPieces::ChestCorridor::addChildren(StructurePiece *startPiece, li StrongholdPieces::ChestCorridor *StrongholdPieces::ChestCorridor::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, width, height, depth, direction); + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, width, height, depth, direction); StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } + return NULL; + } - return new ChestCorridor(genDepth, random, box, direction); + return new ChestCorridor(genDepth, random, box, direction); } bool StrongholdPieces::ChestCorridor::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) + if (edgesLiquid(level, chunkBB)) { - return false; - } + return false; + } - // bounding walls - generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); - // entry door - generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); - // exit door - generateSmallDoor(level, random, chunkBB, OPENING, 1, 1, depth - 1); + // bounding walls + generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); + // entry door + generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); + // exit door + generateSmallDoor(level, random, chunkBB, OPENING, 1, 1, depth - 1); - // chest placement - generateBox(level, chunkBB, 3, 1, 2, 3, 1, 4, Tile::stoneBrickSmooth_Id, Tile::stoneBrickSmooth_Id, false); - placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 3, 1, 1, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 3, 1, 5, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 3, 2, 2, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 3, 2, 4, chunkBB); - for (int z = 2; z <= 4; z++) + // chest placement + generateBox(level, chunkBB, 3, 1, 2, 3, 1, 4, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 3, 1, 1, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 3, 1, 5, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 3, 2, 2, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 3, 2, 4, chunkBB); + for (int z = 2; z <= 4; z++) { - placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 2, 1, z, chunkBB); - } + placeBlock(level, Tile::stoneSlabHalf_Id, StoneSlabTile::SMOOTHBRICK_SLAB, 2, 1, z, chunkBB); + } - if (!hasPlacedChest) + if (!hasPlacedChest) { - int y = getWorldY(2); - int x = getWorldX(3, 3), z = getWorldZ(3, 3); - if (chunkBB->isInside(x, y, z)) + int y = getWorldY(2); + int x = getWorldX(3, 3), z = getWorldZ(3, 3); + if (chunkBB->isInside(x, y, z)) { - hasPlacedChest = true; - createChest(level, chunkBB, random, 3, 2, 3, WeighedTreasure::addToTreasure(WeighedTreasureArray(treasureItems,TREASURE_ITEMS_COUNT), Item::enchantedBook->createForRandomTreasure(random)), 2 + random->nextInt(2)); - } - } + hasPlacedChest = true; + createChest(level, chunkBB, random, 3, 2, 3, WeighedTreasure::addToTreasure(WeighedTreasureArray(treasureItems,TREASURE_ITEMS_COUNT), Item::enchantedBook->createForRandomTreasure(random)), 2 + random->nextInt(2)); + } + } return true; } -StrongholdPieces::StraightStairsDown::StraightStairsDown(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), entryDoor(randomSmallDoor(random)) +StrongholdPieces::StraightStairsDown::StraightStairsDown() +{ + // for reflection +} + +StrongholdPieces::StraightStairsDown::StraightStairsDown(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth) { - orientation = direction; - boundingBox = stairsBox; + entryDoor = randomSmallDoor(random); + orientation = direction; + boundingBox = stairsBox; } void StrongholdPieces::StraightStairsDown::addChildren(StructurePiece *startPiece, list *pieces, Random *random) @@ -722,56 +846,62 @@ void StrongholdPieces::StraightStairsDown::addChildren(StructurePiece *startPiec StrongholdPieces::StraightStairsDown *StrongholdPieces::StraightStairsDown::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, 4 - height, 0, width, height, depth, direction); + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, 4 - height, 0, width, height, depth, direction); StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } + return NULL; + } - return new StraightStairsDown(genDepth, random, box, direction); + return new StraightStairsDown(genDepth, random, box, direction); } bool StrongholdPieces::StraightStairsDown::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) + if (edgesLiquid(level, chunkBB)) { - return false; - } + return false; + } - // bounding walls - generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); - // entry door - generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); - // exit door - generateSmallDoor(level, random, chunkBB, OPENING, 1, 1, depth - 1); + // bounding walls + generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); + // entry door + generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); + // exit door + generateSmallDoor(level, random, chunkBB, OPENING, 1, 1, depth - 1); - // stairs - int orientationData = getOrientationData(Tile::stairs_stone_Id, 2); - for (int i = 0; i < 6; i++) + // stairs + int orientationData = getOrientationData(Tile::stairs_stone_Id, 2); + for (int i = 0; i < 6; i++) { - placeBlock(level, Tile::stairs_stone_Id, orientationData, 1, height - 5 - i, 1 + i, chunkBB); - placeBlock(level, Tile::stairs_stone_Id, orientationData, 2, height - 5 - i, 1 + i, chunkBB); - placeBlock(level, Tile::stairs_stone_Id, orientationData, 3, height - 5 - i, 1 + i, chunkBB); - if (i < 5) + placeBlock(level, Tile::stairs_stone_Id, orientationData, 1, height - 5 - i, 1 + i, chunkBB); + placeBlock(level, Tile::stairs_stone_Id, orientationData, 2, height - 5 - i, 1 + i, chunkBB); + placeBlock(level, Tile::stairs_stone_Id, orientationData, 3, height - 5 - i, 1 + i, chunkBB); + if (i < 5) { - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 1, height - 6 - i, 1 + i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 2, height - 6 - i, 1 + i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 3, height - 6 - i, 1 + i, chunkBB); - } - } + placeBlock(level, Tile::stoneBrick_Id, 0, 1, height - 6 - i, 1 + i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 2, height - 6 - i, 1 + i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 3, height - 6 - i, 1 + i, chunkBB); + } + } - return true; + return true; } -StrongholdPieces::LeftTurn::LeftTurn(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), entryDoor(randomSmallDoor(random)) +StrongholdPieces::LeftTurn::LeftTurn() { - orientation = direction; - boundingBox = stairsBox; + // for reflection +} + +StrongholdPieces::LeftTurn::LeftTurn(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth) +{ + entryDoor = randomSmallDoor(random); + orientation = direction; + boundingBox = stairsBox; } void StrongholdPieces::LeftTurn::addChildren(StructurePiece *startPiece, list *pieces, Random *random) @@ -788,42 +918,47 @@ void StrongholdPieces::LeftTurn::addChildren(StructurePiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, width, height, depth, direction); + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, width, height, depth, direction); StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } + return NULL; + } - return new LeftTurn(genDepth, random, box, direction); + return new LeftTurn(genDepth, random, box, direction); } bool StrongholdPieces::LeftTurn::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) + if (edgesLiquid(level, chunkBB)) { - return false; - } + return false; + } - // bounding walls - generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); - // entry door - generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); - // exit opening - if (orientation == Direction::NORTH || orientation == Direction::EAST) + // bounding walls + generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); + // entry door + generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); + // exit opening + if (orientation == Direction::NORTH || orientation == Direction::EAST) { - generateBox(level, chunkBB, 0, 1, 1, 0, 3, 3, 0, 0, false); - } + generateBox(level, chunkBB, 0, 1, 1, 0, 3, 3, 0, 0, false); + } else { - generateBox(level, chunkBB, 4, 1, 1, 4, 3, 3, 0, 0, false); - } + generateBox(level, chunkBB, 4, 1, 1, 4, 3, 3, 0, 0, false); + } + + return true; +} - return true; +StrongholdPieces::RightTurn::RightTurn() +{ + // for reflection } StrongholdPieces::RightTurn::RightTurn(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : LeftTurn(genDepth, random, stairsBox, direction) @@ -832,160 +967,177 @@ StrongholdPieces::RightTurn::RightTurn(int genDepth, Random *random, BoundingBox void StrongholdPieces::RightTurn::addChildren(StructurePiece *startPiece, list *pieces, Random *random) { - if (orientation == Direction::NORTH || orientation == Direction::EAST) + if (orientation == Direction::NORTH || orientation == Direction::EAST) { - generateSmallDoorChildRight((StartPiece *) startPiece, pieces, random, 1, 1); - } + generateSmallDoorChildRight((StartPiece *) startPiece, pieces, random, 1, 1); + } else { - generateSmallDoorChildLeft((StartPiece *) startPiece, pieces, random, 1, 1); - } + generateSmallDoorChildLeft((StartPiece *) startPiece, pieces, random, 1, 1); + } } bool StrongholdPieces::RightTurn::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) + if (edgesLiquid(level, chunkBB)) { - return false; - } + return false; + } - // bounding walls - generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); - // entry door - generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); - // exit opening - if (orientation == Direction::NORTH || orientation == Direction::EAST) + // bounding walls + generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); + // entry door + generateSmallDoor(level, random, chunkBB, entryDoor, 1, height - SMALL_DOOR_HEIGHT - 1, 0); + // exit opening + if (orientation == Direction::NORTH || orientation == Direction::EAST) { - generateBox(level, chunkBB, 4, 1, 1, 4, 3, 3, 0, 0, false); - } + generateBox(level, chunkBB, 4, 1, 1, 4, 3, 3, 0, 0, false); + } else { - generateBox(level, chunkBB, 0, 1, 1, 0, 3, 3, 0, 0, false); - } + generateBox(level, chunkBB, 0, 1, 1, 0, 3, 3, 0, 0, false); + } + + return true; +} + +StrongholdPieces::RoomCrossing::RoomCrossing() +{ + // for reflection +} - return true; +StrongholdPieces::RoomCrossing::RoomCrossing(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), type(random->nextInt(5)) +{ + entryDoor = randomSmallDoor(random); + orientation = direction; + boundingBox = stairsBox; } +void StrongholdPieces::RoomCrossing::addAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::addAdditonalSaveData(tag); + tag->putInt(L"Type", type); +} -StrongholdPieces::RoomCrossing::RoomCrossing(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), entryDoor(randomSmallDoor(random)), type(random->nextInt(5)) +void StrongholdPieces::RoomCrossing::readAdditonalSaveData(CompoundTag *tag) { - orientation = direction; - boundingBox = stairsBox; + StrongholdPiece::readAdditonalSaveData(tag); + type = tag->getInt(L"Type"); } void StrongholdPieces::RoomCrossing::addChildren(StructurePiece *startPiece, list *pieces, Random *random) { - generateSmallDoorChildForward((StartPiece*) startPiece, pieces, random, 4, 1); - generateSmallDoorChildLeft((StartPiece*) startPiece, pieces, random, 1, 4); - generateSmallDoorChildRight((StartPiece*) startPiece, pieces, random, 1, 4); + generateSmallDoorChildForward((StartPiece*) startPiece, pieces, random, 4, 1); + generateSmallDoorChildLeft((StartPiece*) startPiece, pieces, random, 1, 4); + generateSmallDoorChildRight((StartPiece*) startPiece, pieces, random, 1, 4); } StrongholdPieces::RoomCrossing *StrongholdPieces::RoomCrossing::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -4, -1, 0, width, height, depth, direction); + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -4, -1, 0, width, height, depth, direction); StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } + return NULL; + } - return new RoomCrossing(genDepth, random, box, direction); + return new RoomCrossing(genDepth, random, box, direction); } WeighedTreasure *StrongholdPieces::RoomCrossing::smallTreasureItems[SMALL_TREASURE_ITEMS_COUNT] = { - new WeighedTreasure(Item::ironIngot_Id, 0, 1, 5, 10), - new WeighedTreasure(Item::goldIngot_Id, 0, 1, 3, 5), - new WeighedTreasure(Item::redStone_Id, 0, 4, 9, 5), - new WeighedTreasure(Item::coal_Id, CoalItem::STONE_COAL, 3, 8, 10), - new WeighedTreasure(Item::bread_Id, 0, 1, 3, 15), - new WeighedTreasure(Item::apple_Id, 0, 1, 3, 15), - new WeighedTreasure(Item::pickAxe_iron_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::ironIngot_Id, 0, 1, 5, 10), + new WeighedTreasure(Item::goldIngot_Id, 0, 1, 3, 5), + new WeighedTreasure(Item::redStone_Id, 0, 4, 9, 5), + new WeighedTreasure(Item::coal_Id, CoalItem::STONE_COAL, 3, 8, 10), + new WeighedTreasure(Item::bread_Id, 0, 1, 3, 15), + new WeighedTreasure(Item::apple_Id, 0, 1, 3, 15), + new WeighedTreasure(Item::pickAxe_iron_Id, 0, 1, 1, 1), }; bool StrongholdPieces::RoomCrossing::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) - { - return false; - } - - // bounding walls - generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); - // entry door - generateSmallDoor(level, random, chunkBB, entryDoor, 4, 1, 0); - // exit openings - generateBox(level, chunkBB, 4, 1, depth - 1, 6, 3, depth - 1, 0, 0, false); - generateBox(level, chunkBB, 0, 1, 4, 0, 3, 6, 0, 0, false); - generateBox(level, chunkBB, width - 1, 1, 4, width - 1, 3, 6, 0, 0, false); - - switch (type) - { - default: - break; - case 0: - // middle torch pillar - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 5, 1, 5, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 5, 2, 5, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 5, 3, 5, chunkBB); - placeBlock(level, Tile::torch_Id, 0, 4, 3, 5, chunkBB); - placeBlock(level, Tile::torch_Id, 0, 6, 3, 5, chunkBB); - placeBlock(level, Tile::torch_Id, 0, 5, 3, 4, chunkBB); - placeBlock(level, Tile::torch_Id, 0, 5, 3, 6, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, 0, 4, 1, 4, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, 0, 4, 1, 5, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, 0, 4, 1, 6, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, 0, 6, 1, 4, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, 0, 6, 1, 5, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, 0, 6, 1, 6, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, 0, 5, 1, 4, chunkBB); - placeBlock(level, Tile::stoneSlabHalf_Id, 0, 5, 1, 6, chunkBB); - break; - case 1: + if (edgesLiquid(level, chunkBB)) + { + return false; + } + + // bounding walls + generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); + // entry door + generateSmallDoor(level, random, chunkBB, entryDoor, 4, 1, 0); + // exit openings + generateBox(level, chunkBB, 4, 1, depth - 1, 6, 3, depth - 1, 0, 0, false); + generateBox(level, chunkBB, 0, 1, 4, 0, 3, 6, 0, 0, false); + generateBox(level, chunkBB, width - 1, 1, 4, width - 1, 3, 6, 0, 0, false); + + switch (type) + { + default: + break; + case 0: + // middle torch pillar + placeBlock(level, Tile::stoneBrick_Id, 0, 5, 1, 5, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 5, 2, 5, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 5, 3, 5, chunkBB); + placeBlock(level, Tile::torch_Id, 0, 4, 3, 5, chunkBB); + placeBlock(level, Tile::torch_Id, 0, 6, 3, 5, chunkBB); + placeBlock(level, Tile::torch_Id, 0, 5, 3, 4, chunkBB); + placeBlock(level, Tile::torch_Id, 0, 5, 3, 6, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, 0, 4, 1, 4, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, 0, 4, 1, 5, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, 0, 4, 1, 6, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, 0, 6, 1, 4, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, 0, 6, 1, 5, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, 0, 6, 1, 6, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, 0, 5, 1, 4, chunkBB); + placeBlock(level, Tile::stoneSlabHalf_Id, 0, 5, 1, 6, chunkBB); + break; + case 1: + { + for (int i = 0; i < 5; i++) { - for (int i = 0; i < 5; i++) - { - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 3, 1, 3 + i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 7, 1, 3 + i, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 3 + i, 1, 3, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 3 + i, 1, 7, chunkBB); - } - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 5, 1, 5, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 5, 2, 5, chunkBB); - placeBlock(level, Tile::stoneBrickSmooth_Id, 0, 5, 3, 5, chunkBB); - placeBlock(level, Tile::water_Id, 0, 5, 4, 5, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 3, 1, 3 + i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 7, 1, 3 + i, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 3 + i, 1, 3, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 3 + i, 1, 7, chunkBB); } - break; - case 2: - { + placeBlock(level, Tile::stoneBrick_Id, 0, 5, 1, 5, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 5, 2, 5, chunkBB); + placeBlock(level, Tile::stoneBrick_Id, 0, 5, 3, 5, chunkBB); + placeBlock(level, Tile::water_Id, 0, 5, 4, 5, chunkBB); + } + break; + case 2: + { for (int z = 1; z <= 9; z++) { - placeBlock(level, Tile::stoneBrick_Id, 0, 1, 3, z, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 9, 3, z, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 1, 3, z, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 9, 3, z, chunkBB); } for (int x = 1; x <= 9; x++) { - placeBlock(level, Tile::stoneBrick_Id, 0, x, 3, 1, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, x, 3, 9, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, x, 3, 1, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, x, 3, 9, chunkBB); } - placeBlock(level, Tile::stoneBrick_Id, 0, 5, 1, 4, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 5, 1, 6, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 5, 3, 4, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 5, 3, 6, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, 1, 5, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 6, 1, 5, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, 3, 5, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 6, 3, 5, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 5, 1, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 5, 1, 6, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 5, 3, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 5, 3, 6, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, 1, 5, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 6, 1, 5, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, 3, 5, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 6, 3, 5, chunkBB); for (int y = 1; y <= 3; y++) { - placeBlock(level, Tile::stoneBrick_Id, 0, 4, y, 4, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 6, y, 4, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, y, 6, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 6, y, 6, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, y, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 6, y, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, y, 6, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 6, y, 6, chunkBB); } placeBlock(level, Tile::torch_Id, 0, 5, 3, 5, chunkBB); for (int z = 2; z <= 8; z++) @@ -1007,18 +1159,24 @@ bool StrongholdPieces::RoomCrossing::postProcess(Level *level, Random *random, B createChest(level, chunkBB, random, 3, 4, 8, WeighedTreasure::addToTreasure(WeighedTreasureArray(smallTreasureItems,SMALL_TREASURE_ITEMS_COUNT), Item::enchantedBook->createForRandomTreasure(random)), 1 + random->nextInt(4)); // System.out.println("Created chest at " + getWorldX(3, 8) + - // "," + getWorldY(4) + "," + getWorldZ(3, 8)); + // "," + getWorldY(4) + "," + getWorldZ(3, 8)); } - break; - } - return true; + break; + } + return true; +} + +StrongholdPieces::PrisonHall::PrisonHall() +{ + // for reflection } -StrongholdPieces::PrisonHall::PrisonHall(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), entryDoor(randomSmallDoor(random)) +StrongholdPieces::PrisonHall::PrisonHall(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth) { - orientation = direction; - boundingBox = stairsBox; + entryDoor = randomSmallDoor(random); + orientation = direction; + boundingBox = stairsBox; } void StrongholdPieces::PrisonHall::addChildren(StructurePiece *startPiece, list *pieces, Random *random) @@ -1028,346 +1186,406 @@ void StrongholdPieces::PrisonHall::addChildren(StructurePiece *startPiece, list< StrongholdPieces::PrisonHall *StrongholdPieces::PrisonHall::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, width, height, depth, direction); + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, -1, 0, width, height, depth, direction); StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } + return NULL; + } - return new PrisonHall(genDepth, random, box, direction); + return new PrisonHall(genDepth, random, box, direction); } bool StrongholdPieces::PrisonHall::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) + if (edgesLiquid(level, chunkBB)) { - return false; - } + return false; + } - // bounding walls - generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); - // entry door - generateSmallDoor(level, random, chunkBB, entryDoor, 1, 1, 0); - // exit openings - generateBox(level, chunkBB, 1, 1, depth - 1, 3, 3, depth - 1, 0, 0, false); + // bounding walls + generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); + // entry door + generateSmallDoor(level, random, chunkBB, entryDoor, 1, 1, 0); + // exit openings + generateBox(level, chunkBB, 1, 1, depth - 1, 3, 3, depth - 1, 0, 0, false); + + // door pillars + generateBox(level, chunkBB, 4, 1, 1, 4, 3, 1, false, random, (BlockSelector *)smoothStoneSelector); + generateBox(level, chunkBB, 4, 1, 3, 4, 3, 3, false, random, (BlockSelector *)smoothStoneSelector); + generateBox(level, chunkBB, 4, 1, 7, 4, 3, 7, false, random, (BlockSelector *)smoothStoneSelector); + generateBox(level, chunkBB, 4, 1, 9, 4, 3, 9, false, random, (BlockSelector *)smoothStoneSelector); + + // grates + generateBox(level, chunkBB, 4, 1, 4, 4, 3, 6, Tile::ironFence_Id, Tile::ironFence_Id, false); + generateBox(level, chunkBB, 5, 1, 5, 7, 3, 5, Tile::ironFence_Id, Tile::ironFence_Id, false); + + // doors + placeBlock(level, Tile::ironFence_Id, 0, 4, 3, 2, chunkBB); + placeBlock(level, Tile::ironFence_Id, 0, 4, 3, 8, chunkBB); + placeBlock(level, Tile::door_iron_Id, getOrientationData(Tile::door_iron_Id, 3), 4, 1, 2, chunkBB); + placeBlock(level, Tile::door_iron_Id, getOrientationData(Tile::door_iron_Id, 3) + DoorTile::UPPER_BIT, 4, 2, 2, chunkBB); + placeBlock(level, Tile::door_iron_Id, getOrientationData(Tile::door_iron_Id, 3), 4, 1, 8, chunkBB); + placeBlock(level, Tile::door_iron_Id, getOrientationData(Tile::door_iron_Id, 3) + DoorTile::UPPER_BIT, 4, 2, 8, chunkBB); - // door pillars - generateBox(level, chunkBB, 4, 1, 1, 4, 3, 1, false, random, (BlockSelector *)smoothStoneSelector); - generateBox(level, chunkBB, 4, 1, 3, 4, 3, 3, false, random, (BlockSelector *)smoothStoneSelector); - generateBox(level, chunkBB, 4, 1, 7, 4, 3, 7, false, random, (BlockSelector *)smoothStoneSelector); - generateBox(level, chunkBB, 4, 1, 9, 4, 3, 9, false, random, (BlockSelector *)smoothStoneSelector); + return true; - // grates - generateBox(level, chunkBB, 4, 1, 4, 4, 3, 6, Tile::ironFence_Id, Tile::ironFence_Id, false); - generateBox(level, chunkBB, 5, 1, 5, 7, 3, 5, Tile::ironFence_Id, Tile::ironFence_Id, false); +} - // doors - placeBlock(level, Tile::ironFence_Id, 0, 4, 3, 2, chunkBB); - placeBlock(level, Tile::ironFence_Id, 0, 4, 3, 8, chunkBB); - placeBlock(level, Tile::door_iron_Id, getOrientationData(Tile::door_iron_Id, 3), 4, 1, 2, chunkBB); - placeBlock(level, Tile::door_iron_Id, getOrientationData(Tile::door_iron_Id, 3) + DoorTile::UPPER_BIT, 4, 2, 2, chunkBB); - placeBlock(level, Tile::door_iron_Id, getOrientationData(Tile::door_iron_Id, 3), 4, 1, 8, chunkBB); - placeBlock(level, Tile::door_iron_Id, getOrientationData(Tile::door_iron_Id, 3) + DoorTile::UPPER_BIT, 4, 2, 8, chunkBB); +StrongholdPieces::Library::Library() +{ + isTall = false; + // for reflection +} - return true; +StrongholdPieces::Library::Library(int genDepth, Random *random, BoundingBox *roomBox, int direction) : StrongholdPiece(genDepth), + isTall(roomBox->getYSpan() > height) +{ + entryDoor = randomSmallDoor(random); + orientation = direction; + boundingBox = roomBox; +} +void StrongholdPieces::Library::addAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::addAdditonalSaveData(tag); + tag->putBoolean(L"Tall", isTall); } -StrongholdPieces::Library::Library(int genDepth, Random *random, BoundingBox *roomBox, int direction) : StrongholdPiece(genDepth), - entryDoor(randomSmallDoor(random)), - isTall(roomBox->getYSpan() > height) +void StrongholdPieces::Library::readAdditonalSaveData(CompoundTag *tag) { - orientation = direction; - boundingBox = roomBox; + StrongholdPiece::readAdditonalSaveData(tag); + isTall = tag->getBoolean(L"Tall"); } StrongholdPieces::Library *StrongholdPieces::Library::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - // attempt to make a tall library first - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -4, -1, 0, width, tallHeight, depth, direction); + // attempt to make a tall library first + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -4, -1, 0, width, tallHeight, depth, direction); StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - // make a short library - box = BoundingBox::orientBox(footX, footY, footZ, -4, -1, 0, width, height, depth, direction); + // make a short library + box = BoundingBox::orientBox(footX, footY, footZ, -4, -1, 0, width, height, depth, direction); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } - } + return NULL; + } + } - return new Library(genDepth, random, box, direction); + return new Library(genDepth, random, box, direction); } WeighedTreasure *StrongholdPieces::Library::libraryTreasureItems[LIBRARY_TREASURE_ITEMS_COUNT] = { - new WeighedTreasure(Item::book_Id, 0, 1, 3, 20), - new WeighedTreasure(Item::paper_Id, 0, 2, 7, 20), - new WeighedTreasure(Item::map_Id, 0, 1, 1, 1), - new WeighedTreasure(Item::compass_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::book_Id, 0, 1, 3, 20), + new WeighedTreasure(Item::paper_Id, 0, 2, 7, 20), + new WeighedTreasure(Item::map_Id, 0, 1, 1, 1), + new WeighedTreasure(Item::compass_Id, 0, 1, 1, 1), }; bool StrongholdPieces::Library::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) + if (edgesLiquid(level, chunkBB)) { - return false; - } + return false; + } - int currentHeight = tallHeight; - if (!isTall) + int currentHeight = tallHeight; + if (!isTall) { - currentHeight = height; - } + currentHeight = height; + } - // bounding walls - generateBox(level, chunkBB, 0, 0, 0, width - 1, currentHeight - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); - // entry door - generateSmallDoor(level, random, chunkBB, entryDoor, 4, 1, 0); + // bounding walls + generateBox(level, chunkBB, 0, 0, 0, width - 1, currentHeight - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); + // entry door + generateSmallDoor(level, random, chunkBB, entryDoor, 4, 1, 0); - // place sparse cob webs - generateMaybeBox(level, chunkBB, random, .07f, 2, 1, 1, width - 1 - 2, height - 2, depth - 2, Tile::web_Id, Tile::web_Id, false); + // place sparse cob webs + generateMaybeBox(level, chunkBB, random, .07f, 2, 1, 1, width - 1 - 2, height - 2, depth - 2, Tile::web_Id, Tile::web_Id, false); - const int bookLeft = 1; - const int bookRight = width - 2; + const int bookLeft = 1; + const int bookRight = width - 2; - // place library walls - for (int d = 1; d <= depth - 2; d++) { - if (((d - 1) % 4) == 0) { - generateBox(level, chunkBB, bookLeft, 1, d, bookLeft, 4, d, Tile::wood_Id, Tile::wood_Id, false); - generateBox(level, chunkBB, bookRight, 1, d, bookRight, 4, d, Tile::wood_Id, Tile::wood_Id, false); + // place library walls + for (int d = 1; d <= depth - 2; d++) { + if (((d - 1) % 4) == 0) { + generateBox(level, chunkBB, bookLeft, 1, d, bookLeft, 4, d, Tile::wood_Id, Tile::wood_Id, false); + generateBox(level, chunkBB, bookRight, 1, d, bookRight, 4, d, Tile::wood_Id, Tile::wood_Id, false); - placeBlock(level, Tile::torch_Id, 0, 2, 3, d, chunkBB); - placeBlock(level, Tile::torch_Id, 0, width - 3, 3, d, chunkBB); + placeBlock(level, Tile::torch_Id, 0, 2, 3, d, chunkBB); + placeBlock(level, Tile::torch_Id, 0, width - 3, 3, d, chunkBB); - if (isTall) + if (isTall) { - generateBox(level, chunkBB, bookLeft, 6, d, bookLeft, 9, d, Tile::wood_Id, Tile::wood_Id, false); - generateBox(level, chunkBB, bookRight, 6, d, bookRight, 9, d, Tile::wood_Id, Tile::wood_Id, false); - } - } + generateBox(level, chunkBB, bookLeft, 6, d, bookLeft, 9, d, Tile::wood_Id, Tile::wood_Id, false); + generateBox(level, chunkBB, bookRight, 6, d, bookRight, 9, d, Tile::wood_Id, Tile::wood_Id, false); + } + } else { - generateBox(level, chunkBB, bookLeft, 1, d, bookLeft, 4, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); - generateBox(level, chunkBB, bookRight, 1, d, bookRight, 4, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); + generateBox(level, chunkBB, bookLeft, 1, d, bookLeft, 4, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); + generateBox(level, chunkBB, bookRight, 1, d, bookRight, 4, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); - if (isTall) + if (isTall) { - generateBox(level, chunkBB, bookLeft, 6, d, bookLeft, 9, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); - generateBox(level, chunkBB, bookRight, 6, d, bookRight, 9, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); - } - } - } - - // place book shelves - for (int d = 3; d < depth - 3; d += 2) - { - generateBox(level, chunkBB, 3, 1, d, 4, 3, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); - generateBox(level, chunkBB, 6, 1, d, 7, 3, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); - generateBox(level, chunkBB, 9, 1, d, 10, 3, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); - } - - if (isTall) - { - // create balcony - generateBox(level, chunkBB, 1, 5, 1, 3, 5, depth - 2, Tile::wood_Id, Tile::wood_Id, false); - generateBox(level, chunkBB, width - 4, 5, 1, width - 2, 5, depth - 2, Tile::wood_Id, Tile::wood_Id, false); - generateBox(level, chunkBB, 4, 5, 1, width - 5, 5, 2, Tile::wood_Id, Tile::wood_Id, false); - generateBox(level, chunkBB, 4, 5, depth - 3, width - 5, 5, depth - 2, Tile::wood_Id, Tile::wood_Id, false); - - placeBlock(level, Tile::wood_Id, 0, width - 5, 5, depth - 4, chunkBB); - placeBlock(level, Tile::wood_Id, 0, width - 6, 5, depth - 4, chunkBB); - placeBlock(level, Tile::wood_Id, 0, width - 5, 5, depth - 5, chunkBB); - - // balcony fences - generateBox(level, chunkBB, 3, 6, 2, 3, 6, depth - 3, Tile::fence_Id, Tile::fence_Id, false); - generateBox(level, chunkBB, width - 4, 6, 2, width - 4, 6, depth - 5, Tile::fence_Id, Tile::fence_Id, false); - generateBox(level, chunkBB, 4, 6, 2, width - 5, 6, 2, Tile::fence_Id, Tile::fence_Id, false); - generateBox(level, chunkBB, 4, 6, depth - 3, 8, 6, depth - 3, Tile::fence_Id, Tile::fence_Id, false); - placeBlock(level, Tile::fence_Id, 0, width - 5, 6, depth - 4, chunkBB); - placeBlock(level, Tile::fence_Id, 0, width - 6, 6, depth - 4, chunkBB); - placeBlock(level, Tile::fence_Id, 0, width - 5, 6, depth - 5, chunkBB); - - // ladder - int orientationData = getOrientationData(Tile::ladder_Id, 3); - placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 1, depth - 2, chunkBB); - placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 2, depth - 2, chunkBB); - placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 3, depth - 2, chunkBB); - placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 4, depth - 2, chunkBB); - placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 5, depth - 2, chunkBB); - placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 6, depth - 2, chunkBB); - placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 7, depth - 2, chunkBB); - - // chandelier - int x = width / 2; - int z = depth / 2; - placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 2, z, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 2, z, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 3, z, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 3, z, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 4, z, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 4, z, chunkBB); - - placeBlock(level, Tile::fence_Id, 0, x - 2, tallHeight - 4, z, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x + 1, tallHeight - 4, z, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 4, z - 1, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 4, z + 1, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 4, z - 1, chunkBB); - placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 4, z + 1, chunkBB); - - placeBlock(level, Tile::torch_Id, 0, x - 2, tallHeight - 3, z, chunkBB); - placeBlock(level, Tile::torch_Id, 0, x + 1, tallHeight - 3, z, chunkBB); - placeBlock(level, Tile::torch_Id, 0, x - 1, tallHeight - 3, z - 1, chunkBB); - placeBlock(level, Tile::torch_Id, 0, x - 1, tallHeight - 3, z + 1, chunkBB); - placeBlock(level, Tile::torch_Id, 0, x, tallHeight - 3, z - 1, chunkBB); - placeBlock(level, Tile::torch_Id, 0, x, tallHeight - 3, z + 1, chunkBB); - } - - // place chests - createChest(level, chunkBB, random, 3, 3, 5, WeighedTreasure::addToTreasure(WeighedTreasureArray(libraryTreasureItems,LIBRARY_TREASURE_ITEMS_COUNT), Item::enchantedBook->createForRandomTreasure(random, 1, 5, 2)), 1 + random->nextInt(4)); - if (isTall) - { - placeBlock(level, 0, 0, width - 2, tallHeight - 2, 1, chunkBB); - createChest(level, chunkBB, random, width - 2, tallHeight - 3, 1, WeighedTreasure::addToTreasure(WeighedTreasureArray(libraryTreasureItems,LIBRARY_TREASURE_ITEMS_COUNT), Item::enchantedBook->createForRandomTreasure(random, 1, 5, 2)), 1 + random->nextInt(4)); - } - - return true; - -} - -StrongholdPieces::FiveCrossing::FiveCrossing(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth), entryDoor(randomSmallDoor(random)) -{ - orientation = direction; - boundingBox = stairsBox; - - leftLow = random->nextBoolean(); - leftHigh = random->nextBoolean(); - rightLow = random->nextBoolean(); - rightHigh = random->nextInt(3) > 0; + generateBox(level, chunkBB, bookLeft, 6, d, bookLeft, 9, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); + generateBox(level, chunkBB, bookRight, 6, d, bookRight, 9, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); + } + } + } + + // place book shelves + for (int d = 3; d < depth - 3; d += 2) + { + generateBox(level, chunkBB, 3, 1, d, 4, 3, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); + generateBox(level, chunkBB, 6, 1, d, 7, 3, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); + generateBox(level, chunkBB, 9, 1, d, 10, 3, d, Tile::bookshelf_Id, Tile::bookshelf_Id, false); + } + + if (isTall) + { + // create balcony + generateBox(level, chunkBB, 1, 5, 1, 3, 5, depth - 2, Tile::wood_Id, Tile::wood_Id, false); + generateBox(level, chunkBB, width - 4, 5, 1, width - 2, 5, depth - 2, Tile::wood_Id, Tile::wood_Id, false); + generateBox(level, chunkBB, 4, 5, 1, width - 5, 5, 2, Tile::wood_Id, Tile::wood_Id, false); + generateBox(level, chunkBB, 4, 5, depth - 3, width - 5, 5, depth - 2, Tile::wood_Id, Tile::wood_Id, false); + + placeBlock(level, Tile::wood_Id, 0, width - 5, 5, depth - 4, chunkBB); + placeBlock(level, Tile::wood_Id, 0, width - 6, 5, depth - 4, chunkBB); + placeBlock(level, Tile::wood_Id, 0, width - 5, 5, depth - 5, chunkBB); + + // balcony fences + generateBox(level, chunkBB, 3, 6, 2, 3, 6, depth - 3, Tile::fence_Id, Tile::fence_Id, false); + generateBox(level, chunkBB, width - 4, 6, 2, width - 4, 6, depth - 5, Tile::fence_Id, Tile::fence_Id, false); + generateBox(level, chunkBB, 4, 6, 2, width - 5, 6, 2, Tile::fence_Id, Tile::fence_Id, false); + generateBox(level, chunkBB, 4, 6, depth - 3, 8, 6, depth - 3, Tile::fence_Id, Tile::fence_Id, false); + placeBlock(level, Tile::fence_Id, 0, width - 5, 6, depth - 4, chunkBB); + placeBlock(level, Tile::fence_Id, 0, width - 6, 6, depth - 4, chunkBB); + placeBlock(level, Tile::fence_Id, 0, width - 5, 6, depth - 5, chunkBB); + + // ladder + int orientationData = getOrientationData(Tile::ladder_Id, 3); + placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 1, depth - 2, chunkBB); + placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 2, depth - 2, chunkBB); + placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 3, depth - 2, chunkBB); + placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 4, depth - 2, chunkBB); + placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 5, depth - 2, chunkBB); + placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 6, depth - 2, chunkBB); + placeBlock(level, Tile::ladder_Id, orientationData, width - 4, 7, depth - 2, chunkBB); + + // chandelier + int x = width / 2; + int z = depth / 2; + placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 2, z, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 2, z, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 3, z, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 3, z, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 4, z, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 4, z, chunkBB); + + placeBlock(level, Tile::fence_Id, 0, x - 2, tallHeight - 4, z, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x + 1, tallHeight - 4, z, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 4, z - 1, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x - 1, tallHeight - 4, z + 1, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 4, z - 1, chunkBB); + placeBlock(level, Tile::fence_Id, 0, x, tallHeight - 4, z + 1, chunkBB); + + placeBlock(level, Tile::torch_Id, 0, x - 2, tallHeight - 3, z, chunkBB); + placeBlock(level, Tile::torch_Id, 0, x + 1, tallHeight - 3, z, chunkBB); + placeBlock(level, Tile::torch_Id, 0, x - 1, tallHeight - 3, z - 1, chunkBB); + placeBlock(level, Tile::torch_Id, 0, x - 1, tallHeight - 3, z + 1, chunkBB); + placeBlock(level, Tile::torch_Id, 0, x, tallHeight - 3, z - 1, chunkBB); + placeBlock(level, Tile::torch_Id, 0, x, tallHeight - 3, z + 1, chunkBB); + } + + // place chests + createChest(level, chunkBB, random, 3, 3, 5, WeighedTreasure::addToTreasure(WeighedTreasureArray(libraryTreasureItems,LIBRARY_TREASURE_ITEMS_COUNT), Item::enchantedBook->createForRandomTreasure(random, 1, 5, 2)), 1 + random->nextInt(4)); + if (isTall) + { + placeBlock(level, 0, 0, width - 2, tallHeight - 2, 1, chunkBB); + createChest(level, chunkBB, random, width - 2, tallHeight - 3, 1, WeighedTreasure::addToTreasure(WeighedTreasureArray(libraryTreasureItems,LIBRARY_TREASURE_ITEMS_COUNT), Item::enchantedBook->createForRandomTreasure(random, 1, 5, 2)), 1 + random->nextInt(4)); + } + + return true; + +} + +StrongholdPieces::FiveCrossing::FiveCrossing() +{ + leftLow = leftHigh = rightLow = rightHigh = false; + // for reflection +} + +StrongholdPieces::FiveCrossing::FiveCrossing(int genDepth, Random *random, BoundingBox *stairsBox, int direction) : StrongholdPiece(genDepth) +{ + entryDoor = randomSmallDoor(random); + orientation = direction; + boundingBox = stairsBox; + + leftLow = random->nextBoolean(); + leftHigh = random->nextBoolean(); + rightLow = random->nextBoolean(); + rightHigh = random->nextInt(3) > 0; +} + +void StrongholdPieces::FiveCrossing::addAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::addAdditonalSaveData(tag); + tag->putBoolean(L"leftLow", leftLow); + tag->putBoolean(L"leftHigh", leftHigh); + tag->putBoolean(L"rightLow", rightLow); + tag->putBoolean(L"rightHigh", rightHigh); +} + +void StrongholdPieces::FiveCrossing::readAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::readAdditonalSaveData(tag); + leftLow = tag->getBoolean(L"leftLow"); + leftHigh = tag->getBoolean(L"leftHigh"); + rightLow = tag->getBoolean(L"rightLow"); + rightHigh = tag->getBoolean(L"rightHigh"); } void StrongholdPieces::FiveCrossing::addChildren(StructurePiece *startPiece, list *pieces, Random *random) { - int zOffA = 3; - int zOffB = 5; - // compensate for weird negative-facing behaviour - if (orientation == Direction::WEST || orientation == Direction::NORTH) + int zOffA = 3; + int zOffB = 5; + // compensate for weird negative-facing behaviour + if (orientation == Direction::WEST || orientation == Direction::NORTH) { - zOffA = depth - 3 - zOffA; - zOffB = depth - 3 - zOffB; - } - + zOffA = depth - 3 - zOffA; + zOffB = depth - 3 - zOffB; + } + generateSmallDoorChildForward((StartPiece *) startPiece, pieces, random, 5, 1); - if (leftLow) generateSmallDoorChildLeft((StartPiece *) startPiece, pieces, random, zOffA, 1); - if (leftHigh) generateSmallDoorChildLeft((StartPiece *) startPiece, pieces, random, zOffB, 7); - if (rightLow) generateSmallDoorChildRight((StartPiece *) startPiece, pieces, random, zOffA, 1); - if (rightHigh) generateSmallDoorChildRight((StartPiece *) startPiece, pieces, random, zOffB, 7); + if (leftLow) generateSmallDoorChildLeft((StartPiece *) startPiece, pieces, random, zOffA, 1); + if (leftHigh) generateSmallDoorChildLeft((StartPiece *) startPiece, pieces, random, zOffB, 7); + if (rightLow) generateSmallDoorChildRight((StartPiece *) startPiece, pieces, random, zOffA, 1); + if (rightHigh) generateSmallDoorChildRight((StartPiece *) startPiece, pieces, random, zOffB, 7); } StrongholdPieces::FiveCrossing *StrongholdPieces::FiveCrossing::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -4, -3, 0, width, height, depth, direction); + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -4, -3, 0, width, height, depth, direction); StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } + return NULL; + } - return new FiveCrossing(genDepth, random, box, direction); + return new FiveCrossing(genDepth, random, box, direction); } bool StrongholdPieces::FiveCrossing::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { - if (edgesLiquid(level, chunkBB)) + if (edgesLiquid(level, chunkBB)) { - return false; - } - - // bounding walls - generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); - // entry door - generateSmallDoor(level, random, chunkBB, entryDoor, 4, 3, 0); - - // exit openings - if (leftLow) generateBox(level, chunkBB, 0, 3, 1, 0, 5, 3, 0, 0, false); - if (rightLow) generateBox(level, chunkBB, 9, 3, 1, 9, 5, 3, 0, 0, false); - if (leftHigh) generateBox(level, chunkBB, 0, 5, 7, 0, 7, 9, 0, 0, false); - if (rightHigh) generateBox(level, chunkBB, 9, 5, 7, 9, 7, 9, 0, 0, false); - generateBox(level, chunkBB, 5, 1, 10, 7, 3, 10, 0, 0, false); - - // main floor - generateBox(level, chunkBB, 1, 2, 1, 8, 2, 6, false, random, (BlockSelector *)smoothStoneSelector); - // side walls - generateBox(level, chunkBB, 4, 1, 5, 4, 4, 9, false, random, (BlockSelector *)smoothStoneSelector); - generateBox(level, chunkBB, 8, 1, 5, 8, 4, 9, false, random, (BlockSelector *)smoothStoneSelector); - // upper floor - generateBox(level, chunkBB, 1, 4, 7, 3, 4, 9, false, random, (BlockSelector *)smoothStoneSelector); - - // left stairs - generateBox(level, chunkBB, 1, 3, 5, 3, 3, 6, false, random, (BlockSelector *)smoothStoneSelector); - generateBox(level, chunkBB, 1, 3, 4, 3, 3, 4, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); - generateBox(level, chunkBB, 1, 4, 6, 3, 4, 6, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); + return false; + } - // lower stairs - generateBox(level, chunkBB, 5, 1, 7, 7, 1, 8, false, random, (BlockSelector *)smoothStoneSelector); - generateBox(level, chunkBB, 5, 1, 9, 7, 1, 9, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); - generateBox(level, chunkBB, 5, 2, 7, 7, 2, 7, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); + // bounding walls + generateBox(level, chunkBB, 0, 0, 0, width - 1, height - 1, depth - 1, CHECK_AIR, random, (BlockSelector *)smoothStoneSelector); + // entry door + generateSmallDoor(level, random, chunkBB, entryDoor, 4, 3, 0); + + // exit openings + if (leftLow) generateBox(level, chunkBB, 0, 3, 1, 0, 5, 3, 0, 0, false); + if (rightLow) generateBox(level, chunkBB, 9, 3, 1, 9, 5, 3, 0, 0, false); + if (leftHigh) generateBox(level, chunkBB, 0, 5, 7, 0, 7, 9, 0, 0, false); + if (rightHigh) generateBox(level, chunkBB, 9, 5, 7, 9, 7, 9, 0, 0, false); + generateBox(level, chunkBB, 5, 1, 10, 7, 3, 10, 0, 0, false); + + // main floor + generateBox(level, chunkBB, 1, 2, 1, 8, 2, 6, false, random, (BlockSelector *)smoothStoneSelector); + // side walls + generateBox(level, chunkBB, 4, 1, 5, 4, 4, 9, false, random, (BlockSelector *)smoothStoneSelector); + generateBox(level, chunkBB, 8, 1, 5, 8, 4, 9, false, random, (BlockSelector *)smoothStoneSelector); + // upper floor + generateBox(level, chunkBB, 1, 4, 7, 3, 4, 9, false, random, (BlockSelector *)smoothStoneSelector); + + // left stairs + generateBox(level, chunkBB, 1, 3, 5, 3, 3, 6, false, random, (BlockSelector *)smoothStoneSelector); + generateBox(level, chunkBB, 1, 3, 4, 3, 3, 4, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); + generateBox(level, chunkBB, 1, 4, 6, 3, 4, 6, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); + + // lower stairs + generateBox(level, chunkBB, 5, 1, 7, 7, 1, 8, false, random, (BlockSelector *)smoothStoneSelector); + generateBox(level, chunkBB, 5, 1, 9, 7, 1, 9, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); + generateBox(level, chunkBB, 5, 2, 7, 7, 2, 7, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); + + // bridge + generateBox(level, chunkBB, 4, 5, 7, 4, 5, 9, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); + generateBox(level, chunkBB, 8, 5, 7, 8, 5, 9, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); + generateBox(level, chunkBB, 5, 5, 7, 7, 5, 9, Tile::stoneSlab_Id, Tile::stoneSlab_Id, false); + placeBlock(level, Tile::torch_Id, 0, 6, 5, 6, chunkBB); - // bridge - generateBox(level, chunkBB, 4, 5, 7, 4, 5, 9, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); - generateBox(level, chunkBB, 8, 5, 7, 8, 5, 9, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); - generateBox(level, chunkBB, 5, 5, 7, 7, 5, 9, Tile::stoneSlab_Id, Tile::stoneSlab_Id, false); - placeBlock(level, Tile::torch_Id, 0, 6, 5, 6, chunkBB); + return true; - return true; +} +StrongholdPieces::PortalRoom::PortalRoom() +{ + // for reflection } StrongholdPieces::PortalRoom::PortalRoom(int genDepth, Random *random, BoundingBox *box, int direction) : StrongholdPiece(genDepth) { hasPlacedMobSpawner = false; - orientation = direction; - boundingBox = box; + orientation = direction; + boundingBox = box; +} + +void StrongholdPieces::PortalRoom::addAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::addAdditonalSaveData(tag); + tag->putBoolean(L"Mob", hasPlacedMobSpawner); +} + +void StrongholdPieces::PortalRoom::readAdditonalSaveData(CompoundTag *tag) +{ + StrongholdPiece::readAdditonalSaveData(tag); + hasPlacedMobSpawner = tag->getBoolean(L"Mob"); } void StrongholdPieces::PortalRoom::addChildren(StructurePiece *startPiece, list *pieces, Random *random) { - if (startPiece != NULL) + if (startPiece != NULL) { - ((StartPiece *) startPiece)->portalRoomPiece = this; - } + ((StartPiece *) startPiece)->portalRoomPiece = this; + } } StrongholdPieces::PortalRoom *StrongholdPieces::PortalRoom::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { - BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -4, -1, 0, width, height, depth, direction); + BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -4, -1, 0, width, height, depth, direction); // 4J Added so that we can check that Portals stay within the bounds of the world (which they ALWAYS should anyway) StartPiece *startPiece = NULL; if(pieces != NULL) startPiece = ((StrongholdPieces::StartPiece *) pieces->front()); - if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) + if (!isOkBox(box, startPiece) || StructurePiece::findCollisionPiece(pieces, box) != NULL) { delete box; - return NULL; - } + return NULL; + } - return new PortalRoom(genDepth, random, box, direction); + return new PortalRoom(genDepth, random, box, direction); } bool StrongholdPieces::PortalRoom::postProcess(Level *level, Random *random, BoundingBox *chunkBB) @@ -1406,15 +1624,15 @@ bool StrongholdPieces::PortalRoom::postProcess(Level *level, Random *random, Bou } // stair - int orientationData = getOrientationData(Tile::stairs_stoneBrickSmooth_Id, 3); + int orientationData = getOrientationData(Tile::stairs_stoneBrick_Id, 3); generateBox(level, chunkBB, 4, 1, 5, 6, 1, 7, false, random, (BlockSelector *)smoothStoneSelector); generateBox(level, chunkBB, 4, 2, 6, 6, 2, 7, false, random, (BlockSelector *)smoothStoneSelector); generateBox(level, chunkBB, 4, 3, 7, 6, 3, 7, false, random, (BlockSelector *)smoothStoneSelector); for (int x = 4; x <= 6; x++) { - placeBlock(level, Tile::stairs_stoneBrickSmooth_Id, orientationData, x, 1, 4, chunkBB); - placeBlock(level, Tile::stairs_stoneBrickSmooth_Id, orientationData, x, 2, 5, chunkBB); - placeBlock(level, Tile::stairs_stoneBrickSmooth_Id, orientationData, x, 3, 6, chunkBB); + placeBlock(level, Tile::stairs_stoneBrick_Id, orientationData, x, 1, 4, chunkBB); + placeBlock(level, Tile::stairs_stoneBrick_Id, orientationData, x, 2, 5, chunkBB); + placeBlock(level, Tile::stairs_stoneBrick_Id, orientationData, x, 3, 6, chunkBB); } int north = Direction::NORTH; @@ -1425,25 +1643,25 @@ bool StrongholdPieces::PortalRoom::postProcess(Level *level, Random *random, Bou switch (orientation) { case Direction::SOUTH: - north = Direction::SOUTH; - south = Direction::NORTH; - break; + north = Direction::SOUTH; + south = Direction::NORTH; + break; case Direction::EAST: - north = Direction::EAST; - south = Direction::WEST; - east = Direction::SOUTH; - west = Direction::NORTH; - break; + north = Direction::EAST; + south = Direction::WEST; + east = Direction::SOUTH; + west = Direction::NORTH; + break; case Direction::WEST: - north = Direction::WEST; - south = Direction::EAST; - east = Direction::SOUTH; - west = Direction::NORTH; - break; + north = Direction::WEST; + south = Direction::EAST; + east = Direction::SOUTH; + west = Direction::NORTH; + break; } // 4J-PB - Removed for Christmas update since we don't have The End - + // 4J-PB - not going to remove it, so that maps generated will have it in, but it can't be activated placeBlock(level, Tile::endPortalFrameTile_Id, north + ((random->nextFloat() > 0.9f) ? TheEndPortalFrameTile::EYE_BIT : 0), 4, 3, 8, chunkBB); placeBlock(level, Tile::endPortalFrameTile_Id, north + ((random->nextFloat() > 0.9f) ? TheEndPortalFrameTile::EYE_BIT : 0), 5, 3, 8, chunkBB); @@ -1457,7 +1675,7 @@ bool StrongholdPieces::PortalRoom::postProcess(Level *level, Random *random, Bou placeBlock(level, Tile::endPortalFrameTile_Id, west + ((random->nextFloat() > 0.9f) ? TheEndPortalFrameTile::EYE_BIT : 0), 7, 3, 9, chunkBB); placeBlock(level, Tile::endPortalFrameTile_Id, west + ((random->nextFloat() > 0.9f) ? TheEndPortalFrameTile::EYE_BIT : 0), 7, 3, 10, chunkBB); placeBlock(level, Tile::endPortalFrameTile_Id, west + ((random->nextFloat() > 0.9f) ? TheEndPortalFrameTile::EYE_BIT : 0), 7, 3, 11, chunkBB); - + if (!hasPlacedMobSpawner) { @@ -1472,9 +1690,9 @@ bool StrongholdPieces::PortalRoom::postProcess(Level *level, Random *random, Bou level->getLevelData()->setHasStrongholdEndPortal(); hasPlacedMobSpawner = true; - level->setTile(x, y, z, Tile::mobSpawner_Id); + level->setTileAndData(x, y, z, Tile::mobSpawner_Id, 0, Tile::UPDATE_CLIENTS); shared_ptr entity = dynamic_pointer_cast(level->getTileEntity(x, y, z)); - if (entity != NULL) entity->setEntityId(L"Silverfish"); + if (entity != NULL) entity->getSpawner()->setEntityId(L"Silverfish"); } } @@ -1484,34 +1702,34 @@ bool StrongholdPieces::PortalRoom::postProcess(Level *level, Random *random, Bou void StrongholdPieces::SmoothStoneSelector::next(Random *random, int worldX, int worldY, int worldZ, bool isEdge) { - if (isEdge) + if (isEdge) { - nextId = Tile::stoneBrickSmooth_Id; + nextId = Tile::stoneBrick_Id; - float selection = random->nextFloat(); - if (selection < 0.2f) + float selection = random->nextFloat(); + if (selection < 0.2f) { - nextData = SmoothStoneBrickTile::TYPE_CRACKED; - } + nextData = SmoothStoneBrickTile::TYPE_CRACKED; + } else if (selection < 0.5f) { - nextData = SmoothStoneBrickTile::TYPE_MOSSY; - } + nextData = SmoothStoneBrickTile::TYPE_MOSSY; + } else if (selection < 0.55f) { - nextId = Tile::monsterStoneEgg_Id; - nextData = StoneMonsterTile::HOST_STONEBRICK; - } + nextId = Tile::monsterStoneEgg_Id; + nextData = StoneMonsterTile::HOST_STONEBRICK; + } else { - nextData = 0; - } - } + nextData = 0; + } + } else { - nextId = 0; - nextData = 0; - } + nextId = 0; + nextData = 0; + } } const StrongholdPieces::SmoothStoneSelector *StrongholdPieces::smoothStoneSelector = new SmoothStoneSelector(); diff --git a/Minecraft.World/StrongholdPieces.h b/Minecraft.World/StrongholdPieces.h index c9751bae..2b15f3c2 100644 --- a/Minecraft.World/StrongholdPieces.h +++ b/Minecraft.World/StrongholdPieces.h @@ -6,11 +6,11 @@ class StrongholdPieces private: static const int SMALL_DOOR_WIDTH = 3; - static const int SMALL_DOOR_HEIGHT = 3; + static const int SMALL_DOOR_HEIGHT = 3; - static const int MAX_DEPTH = 50; - // the dungeon starts at 64 and traverses downwards to this point - static const int LOWEST_Y_POSITION = 10; + static const int MAX_DEPTH = 50; + // the dungeon starts at 64 and traverses downwards to this point + static const int LOWEST_Y_POSITION = 10; static const bool CHECK_AIR; // 4J - added to replace use of Class within this class @@ -30,6 +30,11 @@ private: EPieceClass_PortalRoom }; +public: + static void loadStatic(); + + +private: class PieceWeight { public: @@ -37,11 +42,11 @@ private: const int weight; int placeCount; int maxPlaceCount; - + PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount); virtual bool doPlace(int depth); bool isValid(); - }; + }; // 4J - added, java uses a local specialisation of these classes when instancing to achieve the same thing class PieceWeight_Library : public PieceWeight @@ -58,9 +63,9 @@ private: virtual bool doPlace(int depth) { return PieceWeight::doPlace(depth) && depth > 5; } }; - static list currentPieces; + static list currentPieces; static EPieceClass imposedPiece; - static int totalWeight; + static int totalWeight; public: static void resetPieces(); @@ -73,202 +78,268 @@ private: static StructurePiece *generateAndAddPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth); - /** - * - * - */ + /** + * + * + */ private: class StrongholdPiece : public StructurePiece { + protected: + enum SmallDoorType + { + OPENING, WOOD_DOOR, GRATES, IRON_DOOR, + }; + + SmallDoorType entryDoor; + + public: + StrongholdPiece(); protected: StrongholdPiece(int genDepth); - enum SmallDoorType - { - OPENING, WOOD_DOOR, GRATES, IRON_DOOR, - }; + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); void generateSmallDoor(Level *level, Random *random, BoundingBox *chunkBB, SmallDoorType doorType, int footX, int footY, int footZ); SmallDoorType randomSmallDoor(Random *random); StructurePiece *generateSmallDoorChildForward(StartPiece *startPiece, list *pieces, Random *random, int xOff, int yOff); StructurePiece *generateSmallDoorChildLeft(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff); StructurePiece *generateSmallDoorChildRight(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff); - + static bool isOkBox(BoundingBox *box, StartPiece *startRoom); // 4J added startRoom param - }; + }; - /** - * Corridor pieces that connects unconnected ends. - * - */ + /** + * Corridor pieces that connects unconnected ends. + * + */ public: class FillerCorridor : public StrongholdPiece { + public: + static StructurePiece *Create() { return new FillerCorridor(); } + virtual EStructurePiece GetType() { return eStructurePiece_FillerCorridor; } + private: - const int steps; + int steps; public: + FillerCorridor(); FillerCorridor(int genDepth, Random *random, BoundingBox *corridorBox, int direction); - static BoundingBox *findPieceBox(list *pieces, Random *random, int footX, int footY, int footZ, int direction); + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + static BoundingBox *findPieceBox(list *pieces, Random *random, int footX, int footY, int footZ, int direction); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + }; - /** - * - * - */ + /** + * + * + */ public: class StairsDown : public StrongholdPiece { + public: + static StructurePiece *Create() { return new StairsDown(); } + virtual EStructurePiece GetType() { return eStructurePiece_StairsDown; } + private: static const int width = 5; static const int height = 11; static const int depth = 5; - - const bool isSource; - const SmallDoorType entryDoor; + + bool isSource; public: + StairsDown(); StairsDown(int genDepth, Random *random, int west, int north); StairsDown(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static StairsDown *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static StairsDown *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; public: class PortalRoom; class StartPiece : public StairsDown { + public: + virtual EStructurePiece GetType() { return eStructurePiece_StrongholdStartPiece; } + public: bool isLibraryAdded; - PieceWeight *previousPiece; + PieceWeight *previousPiece; PortalRoom *portalRoomPiece; Level *m_level; // 4J added - // this queue is used so that the addChildren calls are - // called in a random order - vector pendingChildren; + // this queue is used so that the addChildren calls are + // called in a random order + vector pendingChildren; - StartPiece(int genDepth, Random *random, int west, int north, Level *level); // 4J Added level param + StartPiece(); + StartPiece(int genDepth, Random *random, int west, int north, Level *level); // 4J Added level param virtual TilePos *getLocatorPosition(); - }; + }; - /** - * - * - */ + /** + * + * + */ public: class Straight : public StrongholdPiece { + public: + static StructurePiece *Create() { return new Straight(); } + virtual EStructurePiece GetType() { return eStructurePiece_Straight; } + private: static const int width = 5; static const int height = 5; static const int depth = 7; - const SmallDoorType entryDoor; - const bool leftChild; - const bool rightChild; + bool leftChild; + bool rightChild; public: + Straight(); Straight(int genDepth, Random *random, BoundingBox *stairsBox, int direction); + + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); static Straight *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + }; - /** - * - * - */ + /** + * + * + */ - class ChestCorridor : public StrongholdPiece + class ChestCorridor : public StrongholdPiece { + public: + static StructurePiece *Create() { return new ChestCorridor(); } + virtual EStructurePiece GetType() { return eStructurePiece_ChestCorridor; } + private: static const int width = 5; - static const int height = 5; - static const int depth = 7; - static const int TREASURE_ITEMS_COUNT = 14; + static const int height = 5; + static const int depth = 7; + static const int TREASURE_ITEMS_COUNT = 18; static WeighedTreasure *treasureItems[TREASURE_ITEMS_COUNT]; - const SmallDoorType entryDoor; - boolean hasPlacedChest; + bool hasPlacedChest; public: + ChestCorridor(); ChestCorridor(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static ChestCorridor *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - - /** - * - * - */ + + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static ChestCorridor *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; + + /** + * + * + */ public: class StraightStairsDown : public StrongholdPiece { + public: + static StructurePiece *Create() { return new StraightStairsDown(); } + virtual EStructurePiece GetType() { return eStructurePiece_StraightStairsDown; } + private: static const int width = 5; static const int height = 11; static const int depth = 8; - const SmallDoorType entryDoor; - public: + StraightStairsDown(); StraightStairsDown(int genDepth, Random *random, BoundingBox *stairsBox, int direction); virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); static StraightStairsDown *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + }; - /** - * - * - */ + /** + * + * + */ public: class LeftTurn : public StrongholdPiece { + public: + static StructurePiece *Create() { return new LeftTurn(); } + virtual EStructurePiece GetType() { return eStructurePiece_LeftTurn; } + protected: static const int width = 5; static const int height = 5; static const int depth = 5; - const SmallDoorType entryDoor; - public: + LeftTurn(); LeftTurn(int genDepth, Random *random, BoundingBox *stairsBox, int direction); virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); static LeftTurn *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + }; - /** - * - * - */ + /** + * + * + */ public: class RightTurn : public LeftTurn { public: + static StructurePiece *Create() { return new RightTurn(); } + virtual EStructurePiece GetType() { return eStructurePiece_RightTurn; } + + public: + RightTurn(); RightTurn(int genDepth, Random *random, BoundingBox *stairsBox, int direction); virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); }; - /** - * - * - */ + /** + * + * + */ public: class RoomCrossing : public StrongholdPiece { + public: + static StructurePiece *Create() { return new RoomCrossing(); } + virtual EStructurePiece GetType() { return eStructurePiece_StrongholdRoomCrossing; } + private: static const int SMALL_TREASURE_ITEMS_COUNT = 7; // 4J added static WeighedTreasure *smallTreasureItems[SMALL_TREASURE_ITEMS_COUNT]; @@ -279,43 +350,57 @@ public: static const int depth = 11; protected: - const SmallDoorType entryDoor; - const int type; + int type; + public: + RoomCrossing(); RoomCrossing(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static RoomCrossing *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - - /** - * - * - */ + + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static RoomCrossing *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; + + /** + * + * + */ public: class PrisonHall : public StrongholdPiece { + public: + static StructurePiece *Create() { return new PrisonHall(); } + virtual EStructurePiece GetType() { return eStructurePiece_PrisonHall; } + protected: static const int width = 9; static const int height = 5; static const int depth = 11; - const SmallDoorType entryDoor; - public: + PrisonHall(); PrisonHall(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); static PrisonHall *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; - /** - * - * - */ + /** + * + * + */ public: class Library : public StrongholdPiece { + public: + static StructurePiece *Create() { return new Library(); } + virtual EStructurePiece GetType() { return eStructurePiece_Library; } + private: static const int LIBRARY_TREASURE_ITEMS_COUNT = 4; // 4J added static WeighedTreasure *libraryTreasureItems[LIBRARY_TREASURE_ITEMS_COUNT]; @@ -326,62 +411,88 @@ public: static const int tallHeight = 11; static const int depth = 15; - const SmallDoorType entryDoor; private: - const bool isTall; + bool isTall; public: + Library(); Library(int genDepth, Random *random, BoundingBox *roomBox, int direction); - static Library *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + static Library *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + + }; - /** - * - * - */ + /** + * + * + */ public: class FiveCrossing : public StrongholdPiece { + public: + static StructurePiece *Create() { return new FiveCrossing(); } + virtual EStructurePiece GetType() { return eStructurePiece_FiveCrossing; } + protected: static const int width = 10; - static const int height = 9; - static const int depth = 11; - - const SmallDoorType entryDoor; + static const int height = 9; + static const int depth = 11; private: bool leftLow, leftHigh, rightLow, rightHigh; public: + FiveCrossing(); FiveCrossing(int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - static FiveCrossing *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; - /** - * - * - */ + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + static FiveCrossing *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; - class PortalRoom : public StrongholdPiece + /** + * + * + */ + + class PortalRoom : public StrongholdPiece { + public: + static StructurePiece *Create() { return new PortalRoom(); } + virtual EStructurePiece GetType() { return eStructurePiece_PortalRoom; } + protected: static const int width = 11; - static const int height = 8; - static const int depth = 16; + static const int height = 8; + static const int depth = 16; private: bool hasPlacedMobSpawner; public: + PortalRoom(); PortalRoom(int genDepth, Random *random, BoundingBox *stairsBox, int direction); + + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: void addChildren(StructurePiece *startPiece, list *pieces, Random *random); static PortalRoom *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + }; private: @@ -389,7 +500,7 @@ private: { public: virtual void next(Random *random, int worldX, int worldY, int worldZ, bool isEdge); - }; + }; - static const SmoothStoneSelector *smoothStoneSelector; + static const SmoothStoneSelector *smoothStoneSelector; }; diff --git a/Minecraft.World/StructureFeature.cpp b/Minecraft.World/StructureFeature.cpp index 5e8489f0..41ee5c81 100644 --- a/Minecraft.World/StructureFeature.cpp +++ b/Minecraft.World/StructureFeature.cpp @@ -7,6 +7,13 @@ #include "net.minecraft.world.level.h" #include "LevelData.h" +StructureFeature::StructureFeature() +{ +#ifdef ENABLE_STRUCTURE_SAVING + savedData = nullptr; +#endif +} + StructureFeature::~StructureFeature() { for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) @@ -17,82 +24,95 @@ StructureFeature::~StructureFeature() void StructureFeature::addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks) { - // this method is called for each chunk within 8 chunk's distance from - // the chunk being generated, but not all chunks are the sources of - // structures + // this method is called for each chunk within 8 chunk's distance from + // the chunk being generated, but not all chunks are the sources of + // structures + + restoreSavedData(level); if (cachedStructures.find(ChunkPos::hashCode(x, z)) != cachedStructures.end()) { - return; - } + return; + } - // clear random key - random->nextInt(); + // clear random key + random->nextInt(); // 4J-PB - want to know if it's a superflat land, so we don't generate so many villages - we've changed the distance required between villages on the xbox - if (isFeatureChunk(x, z,level->getLevelData()->getGenerator() == LevelType::lvl_flat)) + if (isFeatureChunk(x, z,level->getLevelData()->getGenerator() == LevelType::lvl_flat)) { - StructureStart *start = createStructureStart(x, z); - cachedStructures[ChunkPos::hashCode(x, z)] = start; - } + StructureStart *start = createStructureStart(x, z); + cachedStructures[ChunkPos::hashCode(x, z)] = start; + saveFeature(x, z, start); + } } bool StructureFeature::postProcess(Level *level, Random *random, int chunkX, int chunkZ) { + restoreSavedData(level); + // 4J Stu - The x and z used to be offset by (+8) here, but that means we can miss out half structures on the edge of the world // Normal feature generation offsets generation by half a chunk to ensure that it can generate the entire feature in chunks already created // Structure features don't need this, as the PlaceBlock function only places blocks inside the BoundingBox specified, and parts // of a struture piece can be added in more than one post-process call - int cx = (chunkX << 4); // + 8; - int cz = (chunkZ << 4); // + 8; + int cx = (chunkX << 4); // + 8; + int cz = (chunkZ << 4); // + 8; - bool intersection = false; + bool intersection = false; for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) { StructureStart *structureStart = it->second; - if (structureStart->isValid()) + if (structureStart->isValid()) { - if (structureStart->getBoundingBox()->intersects(cx, cz, cx + 15, cz + 15)) + if (structureStart->getBoundingBox()->intersects(cx, cz, cx + 15, cz + 15)) { BoundingBox *bb = new BoundingBox(cx, cz, cx + 15, cz + 15); - structureStart->postProcess(level, random, bb); + structureStart->postProcess(level, random, bb); delete bb; - intersection = true; - } - } - } + intersection = true; - return intersection; + // because some feature pieces are modified in the postProcess step, we need to save them again + saveFeature(structureStart->getChunkX(), structureStart->getChunkZ(), structureStart); + } + } + } + + return intersection; } bool StructureFeature::isIntersection(int cellX, int cellZ) { + restoreSavedData(level); + for( AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); it++ ) { StructureStart *structureStart = it->second; - if (structureStart->isValid()) + if (structureStart->isValid()) { - if (structureStart->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ)) + if (structureStart->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ)) { AUTO_VAR(it2, structureStart->getPieces()->begin()); while( it2 != structureStart->getPieces()->end() ) { - StructurePiece *next = *it2++; - if (next->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ)) + StructurePiece *next = *it2++; + if (next->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ)) { - return true; - } - } - } - } - } - return false; + return true; + } + } + } + } + } + return false; } -/////////////////////////////////////////// -// 4J-PB - Below functions added from 1.2.3 -/////////////////////////////////////////// bool StructureFeature::isInsideFeature(int cellX, int cellY, int cellZ) +{ + restoreSavedData(level); + return getStructureAt(cellX, cellY, cellZ) != NULL; +} + +StructureStart *StructureFeature::getStructureAt(int cellX, int cellY, int cellZ) { //for (StructureStart structureStart : cachedStructures.values()) for(AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); ++it) @@ -118,22 +138,38 @@ bool StructureFeature::isInsideFeature(int cellX, int cellY, int cellZ) StructurePiece* piece = *it2; if ( piece->getBoundingBox()->isInside(cellX, cellY, cellZ) ) { - return true; + return pStructureStart; } } } } } + return NULL; +} + +bool StructureFeature::isInsideBoundingFeature(int cellX, int cellY, int cellZ) +{ + restoreSavedData(level); + + for(AUTO_VAR(it, cachedStructures.begin()); it != cachedStructures.end(); ++it) + { + StructureStart *structureStart = it->second; + if (structureStart->isValid()) + { + return (structureStart->getBoundingBox()->intersects(cellX, cellZ, cellX, cellZ)); + } + } return false; } TilePos *StructureFeature::getNearestGeneratedFeature(Level *level, int cellX, int cellY, int cellZ) { - // this is a hack that will "force" the feature to generate positions // even if the player hasn't generated new chunks yet this->level = level; + restoreSavedData(level); + random->setSeed(level->getSeed()); __int64 xScale = random->nextLong(); __int64 zScale = random->nextLong(); @@ -160,7 +196,7 @@ TilePos *StructureFeature::getNearestGeneratedFeature(Level *level, int cellX, i int dx = locatorPosition->x - cellX; int dy = locatorPosition->y - cellY; int dz = locatorPosition->z - cellZ; - double dist = dx + dx * dy * dy + dz * dz; + double dist = dx * dx + dy * dy + dz * dz; if (dist < minDistance) { @@ -178,14 +214,14 @@ TilePos *StructureFeature::getNearestGeneratedFeature(Level *level, int cellX, i vector *guesstimatedFeaturePositions = getGuesstimatedFeaturePositions(); if (guesstimatedFeaturePositions != NULL) { - TilePos *pSelectedPos = new TilePos(0,0,0); + TilePos *pSelectedPos = new TilePos(0,0,0); for(AUTO_VAR(it, guesstimatedFeaturePositions->begin()); it != guesstimatedFeaturePositions->end(); ++it) { int dx = (*it).x - cellX; int dy = (*it).y - cellY; int dz = (*it).z - cellZ; - double dist = dx + dx * dy * dy + dz * dz; + double dist = dx * dx + dy * dy + dz * dz; if (dist < minDistance) { @@ -206,3 +242,52 @@ vector *StructureFeature::getGuesstimatedFeaturePositions() { return NULL; } + +void StructureFeature::restoreSavedData(Level *level) +{ +#ifdef ENABLE_STRUCTURE_SAVING + if (savedData == NULL) + { + savedData = dynamic_pointer_cast( level->getSavedData(typeid(StructureFeatureSavedData), getFeatureName()) ); + + if (savedData == NULL) + { + savedData = shared_ptr( new StructureFeatureSavedData(getFeatureName()) ); + level->setSavedData(getFeatureName(), savedData); + } + else + { + CompoundTag *fullTag = savedData->getFullTag(); + + vector *allTags = fullTag->getAllTags(); + for (AUTO_VAR(it,allTags->begin()); it != allTags->end(); ++it) + { + Tag *featureTag = *it; + if (featureTag->getId() == Tag::TAG_Compound) + { + CompoundTag *ct = (CompoundTag *) featureTag; + + if (ct->contains(L"ChunkX") && ct->contains(L"ChunkZ")) + { + int cx = ct->getInt(L"ChunkX"); + int cz = ct->getInt(L"ChunkZ"); + + StructureStart *start = StructureFeatureIO::loadStaticStart(ct, level); + // System.out.println("Loaded " + start.getClass().getSimpleName() + " from file"); + cachedStructures[ChunkPos::hashCode(cx, cz)] = start; + } + } + } + delete allTags; + } + } +#endif +} + +void StructureFeature::saveFeature(int chunkX, int chunkZ, StructureStart *feature) +{ +#ifdef ENABLE_STRUCTURE_SAVING + savedData->putFeatureTag(feature->createTag(chunkX, chunkZ), chunkX, chunkZ); + savedData->setDirty(); +#endif +} diff --git a/Minecraft.World/StructureFeature.h b/Minecraft.World/StructureFeature.h index 642e6aad..ace5593d 100644 --- a/Minecraft.World/StructureFeature.h +++ b/Minecraft.World/StructureFeature.h @@ -1,7 +1,11 @@ #pragma once #include "LargeFeature.h" +#include "StructureFeatureSavedData.h" + class StructureStart; +//#define ENABLE_STRUCTURE_SAVING + class StructureFeature : public LargeFeature { public: @@ -15,44 +19,64 @@ public: eFeature_Village, }; +#ifdef ENABLE_STRUCTURE_SAVING +private: + shared_ptr savedData; +#endif + + protected: unordered_map<__int64, StructureStart *> cachedStructures; public: + StructureFeature(); ~StructureFeature(); + virtual wstring getFeatureName() = 0; + virtual void addFeature(Level *level, int x, int z, int xOffs, int zOffs, byteArray blocks); - bool postProcess(Level *level, Random *random, int chunkX, int chunkZ); - bool isIntersection(int cellX, int cellZ); + bool postProcess(Level *level, Random *random, int chunkX, int chunkZ); + bool isIntersection(int cellX, int cellZ); bool isInsideFeature(int cellX, int cellY, int cellZ); + +protected: + StructureStart *getStructureAt(int cellX, int cellY, int cellZ); + +public: + bool isInsideBoundingFeature(int cellX, int cellY, int cellZ); TilePos *getNearestGeneratedFeature(Level *level, int cellX, int cellY, int cellZ); + protected: vector *getGuesstimatedFeaturePositions(); - /** - * Returns true if the given chunk coordinates should hold a structure - * source. - * - * @param x - * chunk x - * @param z - * chunk z - * @return - */ +private: + virtual void restoreSavedData(Level *level); + virtual void saveFeature(int chunkX, int chunkZ, StructureStart *feature); + + /** + * Returns true if the given chunk coordinates should hold a structure + * source. + * + * @param x + * chunk x + * @param z + * chunk z + * @return + */ protected: virtual bool isFeatureChunk(int x, int z, bool bIsSuperflat=false) = 0; - /** - * Creates a new instance of a structure source at the given chunk - * coordinates. - * - * @param x - * chunk x - * @param z - * chunk z - * @return - */ - virtual StructureStart *createStructureStart(int x, int z) = 0; + /** + * Creates a new instance of a structure source at the given chunk + * coordinates. + * + * @param x + * chunk x + * @param z + * chunk z + * @return + */ + virtual StructureStart *createStructureStart(int x, int z) = 0; }; diff --git a/Minecraft.World/StructureFeatureIO.cpp b/Minecraft.World/StructureFeatureIO.cpp new file mode 100644 index 00000000..d910cf3d --- /dev/null +++ b/Minecraft.World/StructureFeatureIO.cpp @@ -0,0 +1,104 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.levelgen.structure.h" +#include "StructureFeatureIO.h" + +unordered_map StructureFeatureIO::startIdClassMap; +unordered_map StructureFeatureIO::startClassIdMap; + +unordered_map StructureFeatureIO::pieceIdClassMap; +unordered_map StructureFeatureIO::pieceClassIdMap; + +void StructureFeatureIO::setStartId(EStructureStart clas, structureStartCreateFn createFn, const wstring &id) +{ + startIdClassMap[id] = createFn; + startClassIdMap[clas] = id; +} + +void StructureFeatureIO::setPieceId(EStructurePiece clas, structurePieceCreateFn createFn, const wstring &id) +{ + pieceIdClassMap[id] = createFn; + pieceClassIdMap[clas] = id; +} + +void StructureFeatureIO::staticCtor() +{ + setStartId(eStructureStart_MineShaftStart, MineShaftStart::Create, L"Mineshaft"); + setStartId(eStructureStart_VillageStart, VillageFeature::VillageStart::Create, L"Village"); + setStartId(eStructureStart_NetherBridgeStart, NetherBridgeFeature::NetherBridgeStart::Create, L"Fortress"); + setStartId(eStructureStart_StrongholdStart, StrongholdFeature::StrongholdStart::Create, L"Stronghold"); + setStartId(eStructureStart_ScatteredFeatureStart, RandomScatteredLargeFeature::ScatteredFeatureStart::Create, L"Temple"); + + MineShaftPieces::loadStatic(); + VillagePieces::loadStatic(); + NetherBridgePieces::loadStatic(); + StrongholdPieces::loadStatic(); + ScatteredFeaturePieces::loadStatic(); +} + +wstring StructureFeatureIO::getEncodeId(StructureStart *start) +{ + AUTO_VAR(it, startClassIdMap.find( start->GetType() ) ); + if(it != startClassIdMap.end()) + { + return it->second; + } + else + { + return L""; + } +} + +wstring StructureFeatureIO::getEncodeId(StructurePiece *piece) +{ + AUTO_VAR(it, pieceClassIdMap.find( piece->GetType() ) ); + if(it != pieceClassIdMap.end()) + { + return it->second; + } + else + { + return L""; + } +} + +StructureStart *StructureFeatureIO::loadStaticStart(CompoundTag *tag, Level *level) +{ + StructureStart *start = NULL; + + AUTO_VAR(it, startIdClassMap.find( tag->getString(L"id") ) ); + if(it != startIdClassMap.end()) + { + start = (it->second)(); + } + + if (start != NULL) + { + start->load(level, tag); + } + else + { + app.DebugPrintf( "Skipping Structure with id %ls", tag->getString(L"id").c_str() ); + } + return start; +} + +StructurePiece *StructureFeatureIO::loadStaticPiece(CompoundTag *tag, Level *level) +{ + StructurePiece *piece = NULL; + + AUTO_VAR(it, pieceIdClassMap.find( tag->getString(L"id") ) ); + if(it != pieceIdClassMap.end()) + { + piece = (it->second)(); + } + + if (piece != NULL) + { + piece->load(level, tag); + } + else + { + app.DebugPrintf( "Skipping Piece with id %ls", tag->getString(L"id").c_str() ); + } + return piece; +} \ No newline at end of file diff --git a/Minecraft.World/StructureFeatureIO.h b/Minecraft.World/StructureFeatureIO.h new file mode 100644 index 00000000..90fc115d --- /dev/null +++ b/Minecraft.World/StructureFeatureIO.h @@ -0,0 +1,93 @@ +#pragma once + +class StructurePiece; +class StructureStart; + +typedef StructurePiece *(*structurePieceCreateFn)(); +typedef StructureStart *(*structureStartCreateFn)(); + +enum EStructureStart +{ + eStructureStart_MineShaftStart, + eStructureStart_VillageStart, + eStructureStart_NetherBridgeStart, + eStructureStart_StrongholdStart, + eStructureStart_ScatteredFeatureStart, +}; + +enum EStructurePiece +{ + eStructurePiece_MineShaftRoom, + eStructurePiece_MineShaftCorridor, + eStructurePiece_MineShaftCrossing, + eStructurePiece_MineShaftStairs, + + eStructurePiece_BridgeStraight, + eStructurePiece_BridgeEndFiller, + eStructurePiece_BridgeCrossing, + eStructurePiece_RoomCrossing, + eStructurePiece_StairsRoom, + eStructurePiece_MonsterThrone, + eStructurePiece_CastleEntrance, + eStructurePiece_CastleStalkRoom, + eStructurePiece_CastleSmallCorridorPiece, + eStructurePiece_CastleSmallCorridorCrossingPiece, + eStructurePiece_CastleSmallCorridorRightTurnPiece, + eStructurePiece_CastleSmallCorridorLeftTurnPiece, + eStructurePiece_CastleCorridorStairsPiece, + eStructurePiece_CastleCorridorTBalconyPiece, + eStructurePiece_NetherBridgeStartPiece, + + eStructurePiece_DesertPyramidPiece, + eStructurePiece_JunglePyramidPiece, + eStructurePiece_SwamplandHut, + + eStructurePiece_FillerCorridor, + eStructurePiece_StairsDown, + eStructurePiece_Straight, + eStructurePiece_ChestCorridor, + eStructurePiece_StraightStairsDown, + eStructurePiece_LeftTurn, + eStructurePiece_RightTurn, + eStructurePiece_StrongholdRoomCrossing, + eStructurePiece_PrisonHall, + eStructurePiece_Library, + eStructurePiece_FiveCrossing, + eStructurePiece_PortalRoom, + eStructurePiece_StrongholdStartPiece, + + eStructurePiece_Well, + eStructurePiece_StraightRoad, + eStructurePiece_SimpleHouse, + eStructurePiece_SmallTemple, + eStructurePiece_BookHouse, + eStructurePiece_SmallHut, + eStructurePiece_PigHouse, + eStructurePiece_TwoRoomHouse, + eStructurePiece_Smithy, + eStructurePiece_Farmland, + eStructurePiece_DoubleFarmland, + eStructurePiece_LightPost, + eStructurePiece_VillageStartPiece, +}; + +class StructureFeatureIO +{ +private: + static unordered_map startIdClassMap; + static unordered_map startClassIdMap; + + static unordered_map pieceIdClassMap; + static unordered_map pieceClassIdMap; + +public: + static void setStartId(EStructureStart clas, structureStartCreateFn createFn, const wstring &id); + static void setPieceId(EStructurePiece clas, structurePieceCreateFn createFn, const wstring &id); + +public: + static void staticCtor(); + static wstring getEncodeId(StructureStart *start); + static wstring getEncodeId(StructurePiece *piece); + static StructureStart *loadStaticStart(CompoundTag *tag, Level *level); + static StructurePiece *loadStaticPiece(CompoundTag *tag, Level *level); +}; \ No newline at end of file diff --git a/Minecraft.World/StructureFeatureSavedData.cpp b/Minecraft.World/StructureFeatureSavedData.cpp new file mode 100644 index 00000000..6c2aa412 --- /dev/null +++ b/Minecraft.World/StructureFeatureSavedData.cpp @@ -0,0 +1,47 @@ +#include "stdafx.h" + +#include "StructureFeatureSavedData.h" + +wstring StructureFeatureSavedData::TAG_FEATURES = L"Features"; + +StructureFeatureSavedData::StructureFeatureSavedData(const wstring &idName) : SavedData(idName) +{ + this->pieceTags = new CompoundTag(TAG_FEATURES); +} + +StructureFeatureSavedData::~StructureFeatureSavedData() +{ + delete pieceTags; +} + +void StructureFeatureSavedData::load(CompoundTag *tag) +{ + this->pieceTags = tag->getCompound(TAG_FEATURES); +} + +void StructureFeatureSavedData::save(CompoundTag *tag) +{ + tag->put(TAG_FEATURES, pieceTags->copy() ); +} + +CompoundTag *StructureFeatureSavedData::getFeatureTag(int chunkX, int chunkZ) +{ + return pieceTags->getCompound(createFeatureTagId(chunkX, chunkZ)); +} + +void StructureFeatureSavedData::putFeatureTag(CompoundTag *tag, int chunkX, int chunkZ) +{ + wstring name = createFeatureTagId(chunkX, chunkZ); + tag->setName(name); + pieceTags->put(name, tag); +} + +wstring StructureFeatureSavedData::createFeatureTagId(int chunkX, int chunkZ) +{ + return L"[" + _toString(chunkX) + L"," + _toString(chunkZ) + L"]"; +} + +CompoundTag *StructureFeatureSavedData::getFullTag() +{ + return pieceTags; +} \ No newline at end of file diff --git a/Minecraft.World/StructureFeatureSavedData.h b/Minecraft.World/StructureFeatureSavedData.h new file mode 100644 index 00000000..599befd3 --- /dev/null +++ b/Minecraft.World/StructureFeatureSavedData.h @@ -0,0 +1,21 @@ +#pragma once + +#include "SavedData.h" + +class StructureFeatureSavedData : public SavedData +{ +private: + static wstring TAG_FEATURES; + CompoundTag *pieceTags; + +public: + StructureFeatureSavedData(const wstring &idName); + ~StructureFeatureSavedData(); + + void load(CompoundTag *tag); + void save(CompoundTag *tag); + CompoundTag *getFeatureTag(int chunkX, int chunkZ); + void putFeatureTag(CompoundTag *tag, int chunkX, int chunkZ); + wstring createFeatureTagId(int chunkX, int chunkZ); + CompoundTag *getFullTag(); +}; \ No newline at end of file diff --git a/Minecraft.World/StructurePiece.cpp b/Minecraft.World/StructurePiece.cpp index 1d41a608..cd483a6e 100644 --- a/Minecraft.World/StructurePiece.cpp +++ b/Minecraft.World/StructurePiece.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "net.minecraft.world.level.levelgen.structure.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.material.h" @@ -41,6 +42,14 @@ * chunks, leading to infinite loops and other errors. */ +StructurePiece::StructurePiece() +{ + boundingBox = NULL; + orientation = 0; + genDepth = 0; + // for reflection +} + StructurePiece::StructurePiece( int genDepth ) { boundingBox = NULL; @@ -53,6 +62,33 @@ StructurePiece::~StructurePiece() if(boundingBox != NULL) delete boundingBox; } +CompoundTag *StructurePiece::createTag() +{ + CompoundTag *tag = new CompoundTag(); + + tag->putString(L"id", StructureFeatureIO::getEncodeId(this)); + tag->put(L"BB", boundingBox->createTag(L"BB")); + tag->putInt(L"O", orientation); + tag->putInt(L"GD", genDepth); + + addAdditonalSaveData(tag); + + return tag; +} + +void StructurePiece::load(Level *level, CompoundTag *tag) +{ + + if (tag->contains(L"BB")) + { + boundingBox = new BoundingBox(tag->getIntArray(L"BB")); + } + orientation = tag->getInt(L"O"); + genDepth = tag->getInt(L"GD"); + + readAdditonalSaveData(tag); +} + void StructurePiece::addChildren( StructurePiece* startPiece, list< StructurePiece* > *pieces, Random* random ) { } @@ -205,13 +241,13 @@ int StructurePiece::getOrientationData( int tile, int data ) { if ( orientation == Direction::WEST || orientation == Direction::EAST ) { - if ( data == RailTile::DIR_FLAT_X ) + if ( data == BaseRailTile::DIR_FLAT_X ) { - return RailTile::DIR_FLAT_Z; + return BaseRailTile::DIR_FLAT_Z; } else { - return RailTile::DIR_FLAT_X; + return BaseRailTile::DIR_FLAT_X; } } } @@ -245,7 +281,7 @@ int StructurePiece::getOrientationData( int tile, int data ) return ( data + 3 ) & 3; } } - else if ( tile == Tile::stairs_stone_Id || tile == Tile::stairs_wood_Id || tile == Tile::stairs_netherBricks_Id || tile == Tile::stairs_stoneBrickSmooth_Id || tile == Tile::stairs_sandstone_Id) + else if ( tile == Tile::stairs_stone_Id || tile == Tile::stairs_wood_Id || tile == Tile::stairs_netherBricks_Id || tile == Tile::stairs_stoneBrick_Id || tile == Tile::stairs_sandstone_Id) { if ( orientation == Direction::SOUTH ) { @@ -515,7 +551,7 @@ void StructurePiece::placeBlock( Level* level, int block, int data, int x, int y // 4J Stu - We shouldn't be removing bedrock when generating things (eg in SuperFlat) if(worldY == 0) return; - level->setTileAndDataNoUpdate( worldX, worldY, worldZ, block, data ); + level->setTileAndData( worldX, worldY, worldZ, block, data, Tile::UPDATE_CLIENTS); } @@ -745,13 +781,12 @@ void StructurePiece::generateAirColumnUp( Level* level, int x, int startY, int z while ( !level->isEmptyTile( worldX, worldY, worldZ ) && worldY < Level::maxBuildHeight - 1 ) { - level->setTileAndDataNoUpdate( worldX, worldY, worldZ, 0, 0 ); + level->setTileAndData( worldX, worldY, worldZ, 0, 0, Tile::UPDATE_CLIENTS); worldY++; } } -void StructurePiece::fillColumnDown( Level* level, int tile, int tileData, int x, int startY, int z, - BoundingBox* chunkBB ) +void StructurePiece::fillColumnDown( Level* level, int tile, int tileData, int x, int startY, int z, BoundingBox* chunkBB ) { int worldX = getWorldX( x, z ); int worldY = getWorldY( startY ); @@ -764,7 +799,7 @@ void StructurePiece::fillColumnDown( Level* level, int tile, int tileData, int x while ( ( level->isEmptyTile( worldX, worldY, worldZ ) || level->getMaterial( worldX, worldY, worldZ )->isLiquid() ) && worldY > 1 ) { - level->setTileAndDataNoUpdate( worldX, worldY, worldZ, tile, tileData ); + level->setTileAndData( worldX, worldY, worldZ, tile, tileData, Tile::UPDATE_CLIENTS ); worldY--; } } @@ -780,7 +815,7 @@ bool StructurePiece::createChest( Level* level, BoundingBox* chunkBB, Random* ra { if ( level->getTile( worldX, worldY, worldZ ) != Tile::chest->id ) { - level->setTile( worldX, worldY, worldZ, Tile::chest->id ); + level->setTileAndData( worldX, worldY, worldZ, Tile::chest->id, 0, Tile::UPDATE_CLIENTS ); shared_ptr chest = dynamic_pointer_cast(level->getTileEntity( worldX, worldY, worldZ )); if ( chest != NULL ) WeighedTreasure::addChestItems( random, treasure, chest, numRolls ); return true; @@ -799,7 +834,7 @@ bool StructurePiece::createDispenser(Level *level, BoundingBox *chunkBB, Random { if (level->getTile(worldX, worldY, worldZ) != Tile::dispenser_Id) { - level->setTileAndData(worldX, worldY, worldZ, Tile::dispenser_Id, getOrientationData(Tile::dispenser_Id, facing)); + level->setTileAndData(worldX, worldY, worldZ, Tile::dispenser_Id, getOrientationData(Tile::dispenser_Id, facing), Tile::UPDATE_CLIENTS); shared_ptr dispenser = dynamic_pointer_cast(level->getTileEntity(worldX, worldY, worldZ)); if (dispenser != NULL) WeighedTreasure::addDispenserItems(random, items, dispenser, numRolls); return true; diff --git a/Minecraft.World/StructurePiece.h b/Minecraft.World/StructurePiece.h index f1ead433..2d5767f9 100644 --- a/Minecraft.World/StructurePiece.h +++ b/Minecraft.World/StructurePiece.h @@ -1,6 +1,7 @@ #pragma once #include "WeighedRandom.h" #include "BoundingBox.h" +#include "StructureFeatureIO.h" class Level; class Random; @@ -10,49 +11,52 @@ class ChestTileEntity; class TilePos; /** - * - * A structure piece is a construction or room, located somewhere in the world - * with a given orientatino (out of Direction.java). Structure pieces have a - * bounding box that says where the piece is located and its bounds, and the - * orientation is used to translate local coordinates into world coordinates. - *

- * The default orientation is Direction.UNDEFINED, in which case no translation - * will occur. If the orientation is Direction.NORTH, coordinate (0, 0, 0) will - * be at (boundingBox.x0, boundingBox.y0, boundingBox.z1). In other words, (1, - * 1, 1) will be translated to (boundingBox.x0 + 1, boundingBox.y0 + 1, - * boundingBox.z1 - 1). - *

- * When using Direction.SOUTH, the x coordinate will be the same, and the z - * coordinate will be flipped. In other words, the bounding box is NOT rotated! - * It is only flipped along the z axis. Also note that the bounding box is in - * world coordinates, so the local drawing must never reach outside of this. - *

- * When using east and west coordinates, the local z coordinate will be swapped - * with the local x coordinate. For example, (0, 0, 0) is (boundingBox.z1, - * boundingBox.y0, boundingBox.z0), and (1, 1, 1) becomes (boundingBox.x1 - 1, - * boundingBox.y0 + 1, boundingBox.z0 + 1) when using Direction.WEST. - *

- * When-ever a structure piece is placing blocks, it is VERY IMPORTANT to always - * make sure that all getTile and setTile calls are within the chunk's bounding - * box. Failing to check this will cause the level generator to create new - * chunks, leading to infinite loops and other errors. - */ +* +* A structure piece is a construction or room, located somewhere in the world +* with a given orientatino (out of Direction.java). Structure pieces have a +* bounding box that says where the piece is located and its bounds, and the +* orientation is used to translate local coordinates into world coordinates. +*

+* The default orientation is Direction.UNDEFINED, in which case no translation +* will occur. If the orientation is Direction.NORTH, coordinate (0, 0, 0) will +* be at (boundingBox.x0, boundingBox.y0, boundingBox.z1). In other words, (1, +* 1, 1) will be translated to (boundingBox.x0 + 1, boundingBox.y0 + 1, +* boundingBox.z1 - 1). +*

+* When using Direction.SOUTH, the x coordinate will be the same, and the z +* coordinate will be flipped. In other words, the bounding box is NOT rotated! +* It is only flipped along the z axis. Also note that the bounding box is in +* world coordinates, so the local drawing must never reach outside of this. +*

+* When using east and west coordinates, the local z coordinate will be swapped +* with the local x coordinate. For example, (0, 0, 0) is (boundingBox.z1, +* boundingBox.y0, boundingBox.z0), and (1, 1, 1) becomes (boundingBox.x1 - 1, +* boundingBox.y0 + 1, boundingBox.z0 + 1) when using Direction.WEST. +*

+* When-ever a structure piece is placing blocks, it is VERY IMPORTANT to always +* make sure that all getTile and setTile calls are within the chunk's bounding +* box. Failing to check this will cause the level generator to create new +* chunks, leading to infinite loops and other errors. +*/ class StructurePiece { public: - class BlockSelector + virtual EStructurePiece GetType() = 0; + +public: + class BlockSelector { protected: int nextId; - int nextData; + int nextData; public: virtual void next(Random *random, int worldX, int worldY, int worldZ, bool isEdge) {} virtual int getNextId() { return nextId; } virtual int getNextData() { return nextData; } - }; + }; public: // 4J is protected in java, but accessed from VillagePieces, not sure how BoundingBox *boundingBox; @@ -60,20 +64,37 @@ protected: int orientation; int genDepth; - StructurePiece(int genDepth); +public: + StructurePiece(); + +protected: + StructurePiece(int genDepth); + public: virtual ~StructurePiece(); + virtual CompoundTag *createTag(); + +protected: + virtual void addAdditonalSaveData(CompoundTag *tag) = 0; + +public: + virtual void load(Level *level, CompoundTag *tag); + +protected: + virtual void readAdditonalSaveData(CompoundTag *tag) = 0; + +public: virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB) = 0; - virtual BoundingBox *getBoundingBox(); + virtual BoundingBox *getBoundingBox(); - int getGenDepth(); + int getGenDepth(); public: bool isInChunk(ChunkPos *pos); - static StructurePiece *findCollisionPiece(list *pieces, BoundingBox *box); + static StructurePiece *findCollisionPiece(list *pieces, BoundingBox *box); virtual TilePos *getLocatorPosition(); protected: bool edgesLiquid(Level *level, BoundingBox *chunkBB); @@ -85,31 +106,31 @@ public: int getOrientationData(int tile, int data); virtual void placeBlock(Level *level, int block, int data, int x, int y, int z, BoundingBox *chunkBB); - /** - * The purpose of this method is to wrap the getTile call on Level, in order - * to prevent the level from generating chunks that shouldn't be loaded yet. - * Returns 0 if the call is out of bounds. - * - * @param level - * @param x - * @param y - * @param z - * @param chunkPosition - * @return - */ - virtual int getBlock(Level *level, int x, int y, int z, BoundingBox *chunkBB); + /** + * The purpose of this method is to wrap the getTile call on Level, in order + * to prevent the level from generating chunks that shouldn't be loaded yet. + * Returns 0 if the call is out of bounds. + * + * @param level + * @param x + * @param y + * @param z + * @param chunkPosition + * @return + */ + virtual int getBlock(Level *level, int x, int y, int z, BoundingBox *chunkBB); virtual void generateAirBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1); - virtual void generateBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, int edgeTile, int fillTile, bool skipAir); + virtual void generateBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, int edgeTile, int fillTile, bool skipAir); virtual void generateBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, int edgeTile, int edgeData, int fillTile, int fillData, bool skipAir); - virtual void generateBox(Level *level, BoundingBox *chunkBB, BoundingBox *boxBB, int edgeTile, int fillTile, bool skipAir); - virtual void generateBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, bool skipAir, Random *random, BlockSelector *selector); - virtual void generateBox(Level *level, BoundingBox *chunkBB, BoundingBox *boxBB, bool skipAir, Random *random, BlockSelector *selector); - virtual void generateMaybeBox(Level *level, BoundingBox *chunkBB, Random *random, float probability, int x0, int y0, int z0, int x1, int y1, int z1, int edgeTile, int fillTile, bool skipAir); - virtual void maybeGenerateBlock(Level *level, BoundingBox *chunkBB, Random *random, float probability, int x, int y, int z, int tile, int data); - virtual void generateUpperHalfSphere(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, int fillTile, bool skipAir); - virtual void generateAirColumnUp(Level *level, int x, int startY, int z, BoundingBox *chunkBB); - virtual void fillColumnDown(Level *level, int tile, int tileData, int x, int startY, int z, BoundingBox *chunkBB); - virtual bool createChest(Level *level, BoundingBox *chunkBB, Random *random, int x, int y, int z, WeighedTreasureArray treasure, int numRolls); + virtual void generateBox(Level *level, BoundingBox *chunkBB, BoundingBox *boxBB, int edgeTile, int fillTile, bool skipAir); + virtual void generateBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, bool skipAir, Random *random, BlockSelector *selector); + virtual void generateBox(Level *level, BoundingBox *chunkBB, BoundingBox *boxBB, bool skipAir, Random *random, BlockSelector *selector); + virtual void generateMaybeBox(Level *level, BoundingBox *chunkBB, Random *random, float probability, int x0, int y0, int z0, int x1, int y1, int z1, int edgeTile, int fillTile, bool skipAir); + virtual void maybeGenerateBlock(Level *level, BoundingBox *chunkBB, Random *random, float probability, int x, int y, int z, int tile, int data); + virtual void generateUpperHalfSphere(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, int fillTile, bool skipAir); + virtual void generateAirColumnUp(Level *level, int x, int startY, int z, BoundingBox *chunkBB); + virtual void fillColumnDown(Level *level, int tile, int tileData, int x, int startY, int z, BoundingBox *chunkBB); + virtual bool createChest(Level *level, BoundingBox *chunkBB, Random *random, int x, int y, int z, WeighedTreasureArray treasure, int numRolls); virtual bool createDispenser(Level *level, BoundingBox *chunkBB, Random *random, int x, int y, int z, int facing, WeighedTreasureArray items, int numRolls); protected: diff --git a/Minecraft.World/StructureRecipies.cpp b/Minecraft.World/StructureRecipies.cpp index f8ac558c..c3e62863 100644 --- a/Minecraft.World/StructureRecipies.cpp +++ b/Minecraft.World/StructureRecipies.cpp @@ -63,7 +63,7 @@ void StructureRecipies::addRecipes(Recipes *r) L"# #", // L"###", // - L'#', Tile::stoneBrick, + L'#', Tile::cobblestone, L'S'); r->addShapedRecipy(new ItemInstance((Tile*)Tile::chest), // @@ -75,6 +75,13 @@ void StructureRecipies::addRecipes(Recipes *r) L'#', Tile::wood, L'S'); + r->addShapedRecipy(new ItemInstance(Tile::chest_trap), // + L"sctctg", + L"#-", // + + L'#', Tile::chest, L'-', Tile::tripWireSource, + L'S'); + r->addShapedRecipy(new ItemInstance(Tile::enderChest), // L"sssctcig", L"###", // @@ -84,12 +91,12 @@ void StructureRecipies::addRecipes(Recipes *r) L'#', Tile::obsidian, L'E', Item::eyeOfEnder, L'S'); - r->addShapedRecipy(new ItemInstance(Tile::stoneBrickSmooth, 4), // + r->addShapedRecipy(new ItemInstance(Tile::stoneBrick, 4), // L"ssctg", L"##", // L"##", // - L'#', Tile::rock, + L'#', Tile::stone, L'S'); // 4J Stu - Move this into "Recipes" to change the order things are displayed on the crafting menu @@ -122,7 +129,15 @@ void StructureRecipies::addRecipes(Recipes *r) L" R ", // L"RGR", // L" R ", // - L'R', Item::redStone, 'G', Tile::lightGem, + L'R', Item::redStone, 'G', Tile::glowstone, L'M'); + r->addShapedRecipy(new ItemInstance(Tile::beacon, 1), // + L"sssctcictg", + L"GGG", // + L"GSG", // + L"OOO", // + + L'G', Tile::glass, L'S', Item::netherStar, L'O', Tile::obsidian, + L'M'); } \ No newline at end of file diff --git a/Minecraft.World/StructureStart.cpp b/Minecraft.World/StructureStart.cpp index 22a4312c..9e5ba0a8 100644 --- a/Minecraft.World/StructureStart.cpp +++ b/Minecraft.World/StructureStart.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.levelgen.structure.h" #include "StructureStart.h" #include "StructurePiece.h" #include "BoundingBox.h" @@ -7,9 +8,17 @@ StructureStart::StructureStart() { + chunkX = chunkZ = 0; boundingBox = NULL; // 4J added initialiser } +StructureStart::StructureStart(int x, int z) +{ + this->chunkX = x; + this->chunkZ = z; + boundingBox = NULL; +} + StructureStart::~StructureStart() { for(AUTO_VAR(it, pieces.begin()); it != pieces.end(); it++ ) @@ -37,8 +46,8 @@ void StructureStart::postProcess(Level *level, Random *random, BoundingBox *chun { if( (*it)->getBoundingBox()->intersects(chunkBB) && !(*it)->postProcess(level, random, chunkBB)) { - // this piece can't be placed, so remove it to avoid future - // attempts + // this piece can't be placed, so remove it to avoid future + // attempts it = pieces.erase(it); } else @@ -50,7 +59,7 @@ void StructureStart::postProcess(Level *level, Random *random, BoundingBox *chun void StructureStart::calculateBoundingBox() { - boundingBox = BoundingBox::getUnknownBox(); + boundingBox = BoundingBox::getUnknownBox(); for( AUTO_VAR(it, pieces.begin()); it != pieces.end(); it++ ) { @@ -59,53 +68,113 @@ void StructureStart::calculateBoundingBox() } } +CompoundTag *StructureStart::createTag(int chunkX, int chunkZ) +{ + CompoundTag *tag = new CompoundTag(); + + tag->putString(L"id", StructureFeatureIO::getEncodeId(this)); + tag->putInt(L"ChunkX", chunkX); + tag->putInt(L"ChunkZ", chunkZ); + tag->put(L"BB", boundingBox->createTag(L"BB")); + + ListTag *childrenTags = new ListTag(L"Children"); + for(AUTO_VAR(it, pieces.begin()); it != pieces.end(); ++it) + { + StructurePiece *piece = *it; + childrenTags->add(piece->createTag()); + } + tag->put(L"Children", childrenTags); + + addAdditonalSaveData(tag); + + return tag; +} + +void StructureStart::addAdditonalSaveData(CompoundTag *tag) +{ + +} + +void StructureStart::load(Level *level, CompoundTag *tag) +{ + chunkX = tag->getInt(L"ChunkX"); + chunkZ = tag->getInt(L"ChunkZ"); + if (tag->contains(L"BB")) + { + boundingBox = new BoundingBox(tag->getIntArray(L"BB")); + } + + ListTag *children = (ListTag *) tag->getList(L"Children"); + for (int i = 0; i < children->size(); i++) + { + pieces.push_back(StructureFeatureIO::loadStaticPiece(children->get(i), level)); + } + + readAdditonalSaveData(tag); +} + +void StructureStart::readAdditonalSaveData(CompoundTag *tag) +{ + +} + void StructureStart::moveBelowSeaLevel(Level *level, Random *random, int offset) { const int MAX_Y = level->seaLevel - offset; - // set lowest possible position (at bedrock) - int y1Pos = boundingBox->getYSpan() + 1; - // move up randomly within the available span - if (y1Pos < MAX_Y) + // set lowest possible position (at bedrock) + int y1Pos = boundingBox->getYSpan() + 1; + // move up randomly within the available span + if (y1Pos < MAX_Y) { - y1Pos += random->nextInt(MAX_Y - y1Pos); - } + y1Pos += random->nextInt(MAX_Y - y1Pos); + } - // move all bounding boxes - int dy = y1Pos - boundingBox->y1; - boundingBox->move(0, dy, 0); + // move all bounding boxes + int dy = y1Pos - boundingBox->y1; + boundingBox->move(0, dy, 0); for( AUTO_VAR(it, pieces.begin()); it != pieces.end(); it++ ) { StructurePiece *piece = *it; - piece->getBoundingBox()->move(0, dy, 0); - } + piece->getBoundingBox()->move(0, dy, 0); + } } void StructureStart::moveInsideHeights(Level *level, Random *random, int lowestAllowed, int highestAllowed) { - int heightSpan = highestAllowed - lowestAllowed + 1 - boundingBox->getYSpan(); - int y0Pos = 1; + int heightSpan = highestAllowed - lowestAllowed + 1 - boundingBox->getYSpan(); + int y0Pos = 1; - if (heightSpan > 1) + if (heightSpan > 1) { - y0Pos = lowestAllowed + random->nextInt(heightSpan); - } + y0Pos = lowestAllowed + random->nextInt(heightSpan); + } else { - y0Pos = lowestAllowed; - } + y0Pos = lowestAllowed; + } - // move all bounding boxes - int dy = y0Pos - boundingBox->y0; - boundingBox->move(0, dy, 0); + // move all bounding boxes + int dy = y0Pos - boundingBox->y0; + boundingBox->move(0, dy, 0); for( AUTO_VAR(it, pieces.begin()); it != pieces.end(); it++ ) { StructurePiece *piece = *it; - piece->getBoundingBox()->move(0, dy, 0); - } + piece->getBoundingBox()->move(0, dy, 0); + } } bool StructureStart::isValid() { return true; +} + +int StructureStart::getChunkX() +{ + return chunkX; +} + +int StructureStart::getChunkZ() +{ + return chunkZ; } \ No newline at end of file diff --git a/Minecraft.World/StructureStart.h b/Minecraft.World/StructureStart.h index e035f564..72035367 100644 --- a/Minecraft.World/StructureStart.h +++ b/Minecraft.World/StructureStart.h @@ -2,24 +2,42 @@ class StructurePiece; class BoundingBox; +#include "StructureFeatureIO.h" + class StructureStart { +public: + list pieces; protected: - list pieces; - BoundingBox *boundingBox; + BoundingBox *boundingBox; + +private: + int chunkX, chunkZ; - StructureStart(); public: + StructureStart(); + StructureStart(int x, int z); ~StructureStart(); BoundingBox *getBoundingBox(); - list *getPieces(); - void postProcess(Level *level, Random *random, BoundingBox *chunkBB); + list *getPieces(); + void postProcess(Level *level, Random *random, BoundingBox *chunkBB); protected: void calculateBoundingBox(); - void moveBelowSeaLevel(Level *level, Random *random, int offset); + +public: + virtual CompoundTag *createTag(int chunkX, int chunkZ); + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void load(Level *level, CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + +protected: + void moveBelowSeaLevel(Level *level, Random *random, int offset); void moveInsideHeights(Level *level, Random *random, int lowestAllowed, int highestAllowed); public: bool isValid(); + int getChunkX(); + int getChunkZ(); + virtual EStructureStart GetType() = 0; }; diff --git a/Minecraft.World/SwampBiome.cpp b/Minecraft.World/SwampBiome.cpp index 0dec2f48..33403d90 100644 --- a/Minecraft.World/SwampBiome.cpp +++ b/Minecraft.World/SwampBiome.cpp @@ -14,6 +14,8 @@ SwampBiome::SwampBiome(int id) : Biome(id) decorator->waterlilyCount = 4; // waterColor = 0xe0ffae; + + enemies.push_back(new MobSpawnerData(eTYPE_SLIME, 1, 1, 1)); } diff --git a/Minecraft.World/SwellGoal.cpp b/Minecraft.World/SwellGoal.cpp index 9065ba16..040d09c2 100644 --- a/Minecraft.World/SwellGoal.cpp +++ b/Minecraft.World/SwellGoal.cpp @@ -7,7 +7,7 @@ SwellGoal::SwellGoal(Creeper *creeper) { - target = weak_ptr(); + target = weak_ptr(); this->creeper = creeper; setRequiredControlFlags(Control::MoveControlFlag); @@ -15,19 +15,19 @@ SwellGoal::SwellGoal(Creeper *creeper) bool SwellGoal::canUse() { - shared_ptr target = creeper->getTarget(); + shared_ptr target = creeper->getTarget(); return creeper->getSwellDir() > 0 || (target != NULL && (creeper->distanceToSqr(target) < 3 * 3)); } void SwellGoal::start() { creeper->getNavigation()->stop(); - target = weak_ptr(creeper->getTarget()); + target = weak_ptr(creeper->getTarget()); } void SwellGoal::stop() { - target = weak_ptr(); + target = weak_ptr(); } void SwellGoal::tick() diff --git a/Minecraft.World/SwellGoal.h b/Minecraft.World/SwellGoal.h index ba6b5379..7e2f68f3 100644 --- a/Minecraft.World/SwellGoal.h +++ b/Minecraft.World/SwellGoal.h @@ -8,7 +8,7 @@ class SwellGoal : public Goal { private: Creeper *creeper; - weak_ptr target; + weak_ptr target; public: SwellGoal(Creeper *creeper); diff --git a/Minecraft.World/SynchedEntityData.cpp b/Minecraft.World/SynchedEntityData.cpp index 9f1aa1f7..e6bb9ec7 100644 --- a/Minecraft.World/SynchedEntityData.cpp +++ b/Minecraft.World/SynchedEntityData.cpp @@ -47,6 +47,17 @@ void SynchedEntityData::define(int id, short value) m_isEmpty = false; } +void SynchedEntityData::define(int id, float value) +{ + MemSect(17); + checkId(id); + int type = TYPE_FLOAT; + shared_ptr dataItem = shared_ptr( new DataItem(type, id, value) ); + itemsById[id] = dataItem; + MemSect(0); + m_isEmpty = false; +} + void SynchedEntityData::define(int id, const wstring& value) { MemSect(17); @@ -100,8 +111,7 @@ int SynchedEntityData::getInteger(int id) float SynchedEntityData::getFloat(int id) { - assert(false); // 4J - not currently implemented - return 0; + return itemsById[id]->getValue_float(); } wstring SynchedEntityData::getString(int id) @@ -160,6 +170,19 @@ void SynchedEntityData::set(int id, short value) } } +void SynchedEntityData::set(int id, float value) +{ + shared_ptr dataItem = itemsById[id]; + + // update the value if it has changed + if (value != dataItem->getValue_float()) + { + dataItem->setValue(value); + dataItem->setDirty(true); + m_isDirty = true; + } +} + void SynchedEntityData::set(int id, const wstring& value) { shared_ptr dataItem = itemsById[id]; @@ -188,7 +211,7 @@ void SynchedEntityData::set(int id, shared_ptr value) void SynchedEntityData::markDirty(int id) { - (*itemsById.find(id)).second->dirty = true; + itemsById[id]->dirty = true; m_isDirty = true; } @@ -221,11 +244,10 @@ vector > *SynchedEntityData::packDirty() if (m_isDirty) { - AUTO_VAR(itEnd, itemsById.end()); - for ( AUTO_VAR(it, itemsById.begin()); it != itEnd; it++ ) + for( int i = 0; i <= MAX_ID_VALUE; i++ ) { - shared_ptr dataItem = (*it).second; - if (dataItem->isDirty()) + shared_ptr dataItem = itemsById[i]; + if ((dataItem != NULL) && dataItem->isDirty()) { dataItem->setDirty(false); @@ -244,11 +266,13 @@ vector > *SynchedEntityData::packDirty() void SynchedEntityData::packAll(DataOutputStream *output) // throws IOException { - AUTO_VAR(itEnd, itemsById.end()); - for (AUTO_VAR(it, itemsById.begin()); it != itEnd; it++ ) + for( int i = 0; i <= MAX_ID_VALUE; i++ ) { - shared_ptr dataItem = (*it).second; - writeDataItem(output, dataItem); + shared_ptr dataItem = itemsById[i]; + if(dataItem != NULL) + { + writeDataItem(output, dataItem); + } } // add an eof @@ -259,15 +283,17 @@ vector > *SynchedEntityData::getAll() { vector > *result = NULL; - AUTO_VAR(itEnd, itemsById.end()); - for (AUTO_VAR(it, itemsById.begin()); it != itEnd; it++ ) + for( int i = 0; i <= MAX_ID_VALUE; i++ ) { - if (result == NULL) + shared_ptr dataItem = itemsById[i]; + if(dataItem != NULL) { - result = new vector >(); + if (result == NULL) + { + result = new vector >(); + } + result->push_back(dataItem); } - shared_ptr dataItem = (*it).second; - result->push_back(dataItem); } return result; @@ -292,6 +318,9 @@ void SynchedEntityData::writeDataItem(DataOutputStream *output, shared_ptrwriteShort( dataItem->getValue_short()); break; + case TYPE_FLOAT: + output->writeFloat( dataItem->getValue_float()); + break; case TYPE_STRING: Packet::writeUtf(dataItem->getValue_wstring(), output); break; @@ -348,6 +377,13 @@ vector > *SynchedEntityData::unpack(Data item = shared_ptr( new DataItem(itemType, itemId, dataRead) ); } break; + case TYPE_FLOAT: + { + float dataRead = input->readFloat(); + item = shared_ptr( new DataItem(itemType, itemId, dataRead) ); + + } + break; case TYPE_STRING: item = shared_ptr( new DataItem(itemType, itemId, Packet::readUtf(input, MAX_STRING_DATA_LENGTH)) ); break; @@ -382,25 +418,29 @@ void SynchedEntityData::assignValues(vector > *items) for (AUTO_VAR(it, items->begin()); it != itEnd; it++) { shared_ptr item = *it; - AUTO_VAR(itemFromId, itemsById.find(item->getId())); - if (itemFromId != itemsById.end() ) + + shared_ptr itemFromId = itemsById[item->getId()]; + if( itemFromId != NULL ) { switch(item->getType()) { case TYPE_BYTE: - itemFromId->second->setValue(item->getValue_byte()); + itemFromId->setValue(item->getValue_byte()); break; case TYPE_SHORT: - itemFromId->second->setValue(item->getValue_short()); + itemFromId->setValue(item->getValue_short()); break; case TYPE_INT: - itemFromId->second->setValue(item->getValue_int()); + itemFromId->setValue(item->getValue_int()); + break; + case TYPE_FLOAT: + itemFromId->setValue(item->getValue_float()); break; case TYPE_STRING: - itemFromId->second->setValue(item->getValue_wstring()); + itemFromId->setValue(item->getValue_wstring()); break; case TYPE_ITEMINSTANCE: - itemFromId->second->setValue(item->getValue_itemInstance()); + itemFromId->setValue(item->getValue_itemInstance()); break; default: assert(false); // 4J - not implemented @@ -408,6 +448,9 @@ void SynchedEntityData::assignValues(vector > *items) } } } + + // client-side dirty + m_isDirty = true; } bool SynchedEntityData::isEmpty() @@ -415,38 +458,47 @@ bool SynchedEntityData::isEmpty() return m_isEmpty; } +void SynchedEntityData::clearDirty() +{ + m_isDirty = false; +} + int SynchedEntityData::getSizeInBytes() { int size = 1; - - AUTO_VAR(itEnd, itemsById.end()); - for (AUTO_VAR(it, itemsById.begin()); it != itEnd; it++ ) - { - shared_ptr dataItem = (*it).second; - size += 1; - - // write value - switch (dataItem->getType()) + for( int i = 0; i <= MAX_ID_VALUE; i++ ) + { + shared_ptr dataItem = itemsById[i]; + if(dataItem != NULL) { - case TYPE_BYTE: size += 1; - break; - case TYPE_SHORT: - size += 2; - break; - case TYPE_INT: - size += 4; - break; - case TYPE_STRING: - size += (int)dataItem->getValue_wstring().length() + 2; // Estimate, assuming all ascii chars - break; - case TYPE_ITEMINSTANCE: - // short + byte + short - size += 2 + 1 + 2; // Estimate, assuming all ascii chars - break; - default: - break; + + // write value + switch (dataItem->getType()) + { + case TYPE_BYTE: + size += 1; + break; + case TYPE_SHORT: + size += 2; + break; + case TYPE_INT: + size += 4; + break; + case TYPE_FLOAT: + size += 4; + break; + case TYPE_STRING: + size += (int)dataItem->getValue_wstring().length() + 2; // Estimate, assuming all ascii chars + break; + case TYPE_ITEMINSTANCE: + // short + byte + short + size += 2 + 1 + 2; // Estimate, assuming all ascii chars + break; + default: + break; + } } } return size; @@ -475,6 +527,12 @@ SynchedEntityData::DataItem::DataItem(int type, int id, short value) : type( typ this->dirty = true; } +SynchedEntityData::DataItem::DataItem(int type, int id, float value) : type( type ), id( id ) +{ + this->value_float = value; + this->dirty = true; +} + SynchedEntityData::DataItem::DataItem(int type, int id, const wstring& value) : type( type ), id( id ) { this->value_wstring = value; @@ -507,6 +565,11 @@ void SynchedEntityData::DataItem::setValue(short value) this->value_short = value; } +void SynchedEntityData::DataItem::setValue(float value) +{ + this->value_float = value; +} + void SynchedEntityData::DataItem::setValue(const wstring& value) { this->value_wstring = value; @@ -527,6 +590,11 @@ short SynchedEntityData::DataItem::getValue_short() return value_short; } +float SynchedEntityData::DataItem::getValue_float() +{ + return value_float; +} + byte SynchedEntityData::DataItem::getValue_byte() { return value_byte; diff --git a/Minecraft.World/SynchedEntityData.h b/Minecraft.World/SynchedEntityData.h index e79a10b8..69d0f248 100644 --- a/Minecraft.World/SynchedEntityData.h +++ b/Minecraft.World/SynchedEntityData.h @@ -15,9 +15,12 @@ public: const int id; // 4J - there used to be one "value" type here of general type Object, just storing the different (used) varieties // here separately for us - byte value_byte; - int value_int; - short value_short; + union { + byte value_byte; + int value_int; + short value_short; + float value_float; + }; wstring value_wstring; shared_ptr value_itemInstance; bool dirty; @@ -29,16 +32,19 @@ public: DataItem(int type, int id, const wstring& value); DataItem(int type, int id, shared_ptr itemInstance); DataItem(int type, int id, short value); + DataItem(int type, int id, float value); int getId(); void setValue(byte value); void setValue(int value); void setValue(short value); + void setValue(float value); void setValue(const wstring& value); void setValue(shared_ptr value); byte getValue_byte(); int getValue_int(); short getValue_short(); + float getValue_float(); wstring getValue_wstring(); shared_ptr getValue_itemInstance(); int getType(); @@ -50,7 +56,6 @@ public: static const int MAX_STRING_DATA_LENGTH = 64; static const int EOF_MARKER = 0x7f; -private: static const int TYPE_BYTE = 0; static const int TYPE_SHORT = 1; static const int TYPE_INT = 2; @@ -71,7 +76,7 @@ private: // the id value must fit in the remaining bits static const int MAX_ID_VALUE = ~TYPE_MASK & 0xff; - unordered_map > itemsById; + shared_ptr itemsById[MAX_ID_VALUE+1]; bool m_isDirty; public: @@ -83,6 +88,7 @@ public: void define(int id, const wstring& value); void define(int id, int value); void define(int id, short value); + void define(int id, float value); void defineNULL(int id, void *pVal); void checkId(int id); // 4J - added to contain common code from overloaded define functions above @@ -97,6 +103,7 @@ public: void set(int id, byte value); void set(int id, int value); void set(int id, short value); + void set(int id, float value); void set(int id, const wstring& value); void set(int id, shared_ptr); void markDirty(int id); @@ -121,6 +128,7 @@ public: public: void assignValues(vector > *items); bool isEmpty(); + void clearDirty(); // 4J Added int getSizeInBytes(); diff --git a/Minecraft.World/Tag.cpp b/Minecraft.World/Tag.cpp index 40da99fe..adc75360 100644 --- a/Minecraft.World/Tag.cpp +++ b/Minecraft.World/Tag.cpp @@ -78,6 +78,11 @@ Tag *Tag::setName(const wstring& name) } Tag *Tag::readNamedTag(DataInput *dis) +{ + return readNamedTag(dis,0); +} + +Tag *Tag::readNamedTag(DataInput *dis, int tagDepth) { byte type = dis->readByte(); if (type == 0) return new EndTag(); @@ -99,7 +104,7 @@ Tag *Tag::readNamedTag(DataInput *dis) // byte[] bytes = new byte[length]; // dis.readFully(bytes); - tag->load(dis); + tag->load(dis, tagDepth); return tag; } diff --git a/Minecraft.World/Tag.h b/Minecraft.World/Tag.h index c3221aea..dcd06722 100644 --- a/Minecraft.World/Tag.h +++ b/Minecraft.World/Tag.h @@ -19,7 +19,7 @@ public: static const byte TAG_List = 9; static const byte TAG_Compound = 10; static const byte TAG_Int_Array = 11; - + static const int MAX_DEPTH = 512; private: wstring name; @@ -28,7 +28,7 @@ protected: public: virtual void write(DataOutput *dos) = 0; - virtual void load(DataInput *dis) = 0; + virtual void load(DataInput *dis, int tagDepth) = 0; virtual wstring toString() = 0; virtual byte getId() = 0; void print(ostream out); @@ -36,6 +36,7 @@ public: wstring getName(); Tag *setName(const wstring& name); static Tag *readNamedTag(DataInput *dis); + static Tag *readNamedTag(DataInput *dis, int tagDepth); static void writeNamedTag(Tag *tag, DataOutput *dos); static Tag *newTag(byte type, const wstring &name); static wchar_t *getTagName(byte type); diff --git a/Minecraft.World/TakeFlowerGoal.cpp b/Minecraft.World/TakeFlowerGoal.cpp index 34c584c6..feb87093 100644 --- a/Minecraft.World/TakeFlowerGoal.cpp +++ b/Minecraft.World/TakeFlowerGoal.cpp @@ -67,7 +67,7 @@ void TakeFlowerGoal::tick() villager->getLookControl()->setLookAt(golem.lock(), 30, 30); if (golem.lock()->getOfferFlowerTick() == pickupTick) { - villager->getNavigation()->moveTo(golem.lock(), 0.15f); + villager->getNavigation()->moveTo(golem.lock(), 0.5f); takeFlower = true; } diff --git a/Minecraft.World/TallGrass.cpp b/Minecraft.World/TallGrass.cpp index e2e7cb19..1a89d3ed 100644 --- a/Minecraft.World/TallGrass.cpp +++ b/Minecraft.World/TallGrass.cpp @@ -8,7 +8,7 @@ #include "TallGrass.h" const unsigned int TallGrass::TALL_GRASS_TILE_NAMES[TALL_GRASS_TILE_NAMES_LENGTH] = { IDS_TILE_SHRUB, - IDS_TILE_GRASS, + IDS_TILE_TALL_GRASS, IDS_TILE_FERN, }; diff --git a/Minecraft.World/TallGrassFeature.cpp b/Minecraft.World/TallGrassFeature.cpp index d13ada49..f509ce68 100644 --- a/Minecraft.World/TallGrassFeature.cpp +++ b/Minecraft.World/TallGrassFeature.cpp @@ -11,23 +11,23 @@ TallGrassFeature::TallGrassFeature(int tile, int type) bool TallGrassFeature::place(Level *level, Random *random, int x, int y, int z) { - int t = 0; - while (((t = level->getTile(x, y, z)) == 0 || t == Tile::leaves_Id) && y > 0) - y--; + int t = 0; + while (((t = level->getTile(x, y, z)) == 0 || t == Tile::leaves_Id) && y > 0) + y--; - for (int i = 0; i < 128; i++) + for (int i = 0; i < 128; i++) { - int x2 = x + random->nextInt(8) - random->nextInt(8); - int y2 = y + random->nextInt(4) - random->nextInt(4); - int z2 = z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(x2, y2, z2)) + int x2 = x + random->nextInt(8) - random->nextInt(8); + int y2 = y + random->nextInt(4) - random->nextInt(4); + int z2 = z + random->nextInt(8) - random->nextInt(8); + if (level->isEmptyTile(x2, y2, z2)) { - if (Tile::tiles[tile]->canSurvive(level, x2, y2, z2)) + if (Tile::tiles[tile]->canSurvive(level, x2, y2, z2)) { - level->setTileAndDataNoUpdate(x2, y2, z2, tile, type); - } - } - } + level->setTileAndData(x2, y2, z2, tile, type, Tile::UPDATE_CLIENTS); + } + } + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/TamableAnimal.cpp b/Minecraft.World/TamableAnimal.cpp index b065d7bd..2a3ea037 100644 --- a/Minecraft.World/TamableAnimal.cpp +++ b/Minecraft.World/TamableAnimal.cpp @@ -68,6 +68,7 @@ void TamableAnimal::readAdditionalSaveData(CompoundTag *tag) setTame(true); } sitGoal->wantToSit(tag->getBoolean(L"Sitting")); + setSitting(tag->getBoolean(L"Sitting")); } void TamableAnimal::spawnTamingParticles(bool success) @@ -148,7 +149,7 @@ void TamableAnimal::setOwnerUUID(const wstring &name) entityData->set(DATA_OWNERUUID_ID, name); } -shared_ptr TamableAnimal::getOwner() +shared_ptr TamableAnimal::getOwner() { return level->getPlayerByUUID(getOwnerUUID()); } @@ -156,4 +157,39 @@ shared_ptr TamableAnimal::getOwner() SitGoal *TamableAnimal::getSitGoal() { return sitGoal; +} + +bool TamableAnimal::wantsToAttack(shared_ptr target, shared_ptr owner) +{ + return true; +} + +Team *TamableAnimal::getTeam() +{ + if (isTame()) + { + shared_ptr owner = dynamic_pointer_cast(getOwner()); + if (owner != NULL) + { + return owner->getTeam(); + } + } + return Animal::getTeam(); +} + +bool TamableAnimal::isAlliedTo(shared_ptr other) +{ + if (isTame()) + { + shared_ptr owner = dynamic_pointer_cast(getOwner()); + if (other == owner) + { + return true; + } + if (owner != NULL) + { + return owner->isAlliedTo(other); + } + } + return Animal::isAlliedTo(other); } \ No newline at end of file diff --git a/Minecraft.World/TamableAnimal.h b/Minecraft.World/TamableAnimal.h index 71502788..7d17a43c 100644 --- a/Minecraft.World/TamableAnimal.h +++ b/Minecraft.World/TamableAnimal.h @@ -1,10 +1,11 @@ #pragma once #include "Animal.h" +#include "OwnableEntity.h" class SitGoal; -class TamableAnimal : public Animal +class TamableAnimal : public Animal, public OwnableEntity { protected: static const int DATA_FLAGS_ID = 16; @@ -33,6 +34,9 @@ public: virtual void setSitting(bool value); virtual wstring getOwnerUUID(); virtual void setOwnerUUID(const wstring &name); - virtual shared_ptr getOwner(); + virtual shared_ptr getOwner(); virtual SitGoal *getSitGoal(); + bool wantsToAttack(shared_ptr target, shared_ptr owner); + Team *getTeam(); + bool isAlliedTo(shared_ptr other); }; \ No newline at end of file diff --git a/Minecraft.World/TargetGoal.cpp b/Minecraft.World/TargetGoal.cpp index c3ac4f59..982acb5e 100644 --- a/Minecraft.World/TargetGoal.cpp +++ b/Minecraft.World/TargetGoal.cpp @@ -1,40 +1,43 @@ #include "stdafx.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.navigation.h" #include "net.minecraft.world.entity.ai.sensing.h" -#include "net.minecraft.world.entity.h" #include "net.minecraft.world.entity.animal.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.level.pathfinder.h" #include "net.minecraft.world.phys.h" #include "TargetGoal.h" -void TargetGoal::_init(Mob *mob, float within, bool mustSee, bool mustReach) +void TargetGoal::_init(PathfinderMob *mob, bool mustSee, bool mustReach) { reachCache = EmptyReachCache; reachCacheTime = 0; unseenTicks = 0; this->mob = mob; - this->within = within; this->mustSee = mustSee; this->mustReach = mustReach; } -TargetGoal::TargetGoal(Mob *mob, float within, bool mustSee) +TargetGoal::TargetGoal(PathfinderMob *mob, bool mustSee) { - _init(mob, within, mustSee, false); + _init(mob, mustSee, false); } -TargetGoal::TargetGoal(Mob *mob, float within, bool mustSee, bool mustReach) +TargetGoal::TargetGoal(PathfinderMob *mob, bool mustSee, bool mustReach) { - _init(mob,within,mustSee,mustReach); + _init(mob,mustSee,mustReach); } bool TargetGoal::canContinueToUse() { - shared_ptr target = mob->getTarget(); + shared_ptr target = mob->getTarget(); if (target == NULL) return false; if (!target->isAlive()) return false; + + double within = getFollowDistance(); if (mob->distanceToSqr(target) > within * within) return false; if (mustSee) { @@ -50,6 +53,12 @@ bool TargetGoal::canContinueToUse() return true; } +double TargetGoal::getFollowDistance() +{ + AttributeInstance *followRange = mob->getAttribute(SharedMonsterAttributes::FOLLOW_RANGE); + return followRange == NULL ? 16 : followRange->getValue(); +} + void TargetGoal::start() { reachCache = EmptyReachCache; @@ -62,21 +71,30 @@ void TargetGoal::stop() mob->setTarget(nullptr); } -bool TargetGoal::canAttack(shared_ptr target, bool allowInvulnerable) +bool TargetGoal::canAttack(shared_ptr target, bool allowInvulnerable) { if (target == NULL) return false; if (target == mob->shared_from_this()) return false; if (!target->isAlive()) return false; if (!mob->canAttackType(target->GetType())) return false; - shared_ptr tamableAnimal = dynamic_pointer_cast(mob->shared_from_this()); - if (tamableAnimal != NULL && tamableAnimal->isTame()) + OwnableEntity *ownableMob = dynamic_cast(mob); + if (ownableMob != NULL && !ownableMob->getOwnerUUID().empty()) { - shared_ptr tamableTarget = dynamic_pointer_cast(target); - if (tamableTarget != NULL && tamableTarget->isTame()) return false; - if (target == tamableAnimal->getOwner()) return false; + shared_ptr ownableTarget = dynamic_pointer_cast(target); + if (ownableTarget != NULL && ownableMob->getOwnerUUID().compare(ownableTarget->getOwnerUUID()) == 0) + { + // We're attacking something owned by the same person... + return false; + } + + if (target == ownableMob->getOwner()) + { + // We're attacking our owner + return false; + } } - else if (dynamic_pointer_cast(target) != NULL) + else if (target->instanceof(eTYPE_PLAYER)) { if (!allowInvulnerable && (dynamic_pointer_cast(target))->abilities.invulnerable) return false; } @@ -95,7 +113,7 @@ bool TargetGoal::canAttack(shared_ptr target, bool allowInvulnerable) return true; } -bool TargetGoal::canReach(shared_ptr target) +bool TargetGoal::canReach(shared_ptr target) { reachCacheTime = 10 + mob->getRandom()->nextInt(5); Path *path = mob->getNavigation()->createPath(target); diff --git a/Minecraft.World/TargetGoal.h b/Minecraft.World/TargetGoal.h index 3bb9da09..4256985b 100644 --- a/Minecraft.World/TargetGoal.h +++ b/Minecraft.World/TargetGoal.h @@ -2,6 +2,8 @@ #include "Goal.h" +class PathfinderMob; + class TargetGoal : public Goal { @@ -15,8 +17,7 @@ private: static const int UnseenMemoryTicks = 60; protected: - Mob *mob; // Owner of this goal - float within; + PathfinderMob *mob; // Owner of this goal bool mustSee; private: @@ -25,20 +26,25 @@ private: int reachCacheTime; int unseenTicks; - void _init(Mob *mob, float within, bool mustSee, bool mustReach); + void _init(PathfinderMob *mob, bool mustSee, bool mustReach); public: - TargetGoal(Mob *mob, float within, bool mustSee); - TargetGoal(Mob *mob, float within, bool mustSee, bool mustReach); + TargetGoal(PathfinderMob *mob, bool mustSee); + TargetGoal(PathfinderMob *mob, bool mustSee, bool mustReach); virtual ~TargetGoal() {} virtual bool canContinueToUse(); + +protected: + virtual double getFollowDistance(); + +public: virtual void start(); virtual void stop(); protected: - virtual bool canAttack(shared_ptr target, bool allowInvulnerable); + virtual bool canAttack(shared_ptr target, bool allowInvulnerable); private: - bool canReach(shared_ptr target); + bool canReach(shared_ptr target); }; \ No newline at end of file diff --git a/Minecraft.World/Team.cpp b/Minecraft.World/Team.cpp new file mode 100644 index 00000000..f3f6e04e --- /dev/null +++ b/Minecraft.World/Team.cpp @@ -0,0 +1,16 @@ +#include "stdafx.h" + +#include "Team.h" + +bool Team::isAlliedTo(Team *other) +{ + if (other == NULL) + { + return false; + } + if (this == other) + { + return true; + } + return false; +} diff --git a/Minecraft.World/Team.h b/Minecraft.World/Team.h new file mode 100644 index 00000000..8374b56e --- /dev/null +++ b/Minecraft.World/Team.h @@ -0,0 +1,13 @@ +#pragma once + +class Team +{ +public: + virtual bool isAlliedTo(Team *other); + + virtual wstring getName() = 0; + virtual wstring getFormattedName(const wstring &teamMemberName) = 0; + virtual bool canSeeFriendlyInvisibles() = 0; + virtual bool isAllowFriendlyFire() = 0; + +}; \ No newline at end of file diff --git a/Minecraft.World/TeleportEntityPacket.cpp b/Minecraft.World/TeleportEntityPacket.cpp index f0ed1e95..d31f5bc2 100644 --- a/Minecraft.World/TeleportEntityPacket.cpp +++ b/Minecraft.World/TeleportEntityPacket.cpp @@ -49,8 +49,8 @@ void TeleportEntityPacket::read(DataInputStream *dis) //throws IOException y = dis->readShort(); z = dis->readShort(); #endif - yRot = (byte) dis->read(); - xRot = (byte) dis->read(); + yRot = dis->readByte(); + xRot = dis->readByte(); } void TeleportEntityPacket::write(DataOutputStream *dos) //throws IOException diff --git a/Minecraft.World/TemptGoal.cpp b/Minecraft.World/TemptGoal.cpp index cf0ee3d2..aebab8fa 100644 --- a/Minecraft.World/TemptGoal.cpp +++ b/Minecraft.World/TemptGoal.cpp @@ -6,7 +6,7 @@ #include "net.minecraft.world.level.h" #include "TemptGoal.h" -TemptGoal::TemptGoal(PathfinderMob *mob, float speed, int itemId, bool canScare) +TemptGoal::TemptGoal(PathfinderMob *mob, double speedModifier, int itemId, bool canScare) { px = py = pz = pRotX = pRotY = 0.0; player = weak_ptr(); @@ -15,7 +15,7 @@ TemptGoal::TemptGoal(PathfinderMob *mob, float speed, int itemId, bool canScare) oldAvoidWater = false; this->mob = mob; - this->speed = speed; + this->speedModifier = speedModifier; this->itemId = itemId; this->canScare = canScare; setRequiredControlFlags(Control::MoveControlFlag | Control::LookControlFlag); @@ -82,7 +82,7 @@ void TemptGoal::tick() { mob->getLookControl()->setLookAt(player.lock(), 30, mob->getMaxHeadXRot()); if (mob->distanceToSqr(player.lock()) < 2.5 * 2.5) mob->getNavigation()->stop(); - else mob->getNavigation()->moveTo(player.lock(), speed); + else mob->getNavigation()->moveTo(player.lock(), speedModifier); } bool TemptGoal::isRunning() diff --git a/Minecraft.World/TemptGoal.h b/Minecraft.World/TemptGoal.h index 78fbe1d8..898264e1 100644 --- a/Minecraft.World/TemptGoal.h +++ b/Minecraft.World/TemptGoal.h @@ -6,7 +6,7 @@ class TemptGoal : public Goal { private: PathfinderMob *mob; - float speed; + double speedModifier; double px, py, pz, pRotX, pRotY; weak_ptr player; int calmDown ; @@ -16,7 +16,7 @@ private: bool oldAvoidWater; public: - TemptGoal(PathfinderMob *mob, float speed, int itemId, bool canScare); + TemptGoal(PathfinderMob *mob, double speedModifier, int itemId, bool canScare); bool canUse(); bool canContinueToUse(); diff --git a/Minecraft.World/TheEndBiome.cpp b/Minecraft.World/TheEndBiome.cpp index 9b95d76a..9e2359ed 100644 --- a/Minecraft.World/TheEndBiome.cpp +++ b/Minecraft.World/TheEndBiome.cpp @@ -6,17 +6,18 @@ TheEndBiome::TheEndBiome(int id) : Biome(id) { - enemies.clear(); - friendlies.clear(); + enemies.clear(); + friendlies.clear(); friendlies_chicken.clear(); // 4J added friendlies_wolf.clear(); // 4J added - waterFriendlies.clear(); + waterFriendlies.clear(); + ambientFriendlies.clear(); - enemies.push_back(new MobSpawnerData(eTYPE_ENDERMAN, 10, 4, 4)); - topMaterial = (byte) Tile::dirt_Id; - this->material = (byte) Tile::dirt_Id; + enemies.push_back(new MobSpawnerData(eTYPE_ENDERMAN, 10, 4, 4)); + topMaterial = (byte) Tile::dirt_Id; + material = (byte) Tile::dirt_Id; - decorator = new TheEndBiomeDecorator(this); + decorator = new TheEndBiomeDecorator(this); } // 4J Stu - Don't need override diff --git a/Minecraft.World/TheEndBiomeDecorator.cpp b/Minecraft.World/TheEndBiomeDecorator.cpp index 31823c80..0ab1f766 100644 --- a/Minecraft.World/TheEndBiomeDecorator.cpp +++ b/Minecraft.World/TheEndBiomeDecorator.cpp @@ -33,8 +33,8 @@ TheEndBiomeDecorator::SPIKE TheEndBiomeDecorator::SpikeValA[8]= TheEndBiomeDecorator::TheEndBiomeDecorator(Biome *biome) : BiomeDecorator(biome) { - spikeFeature = new SpikeFeature(Tile::whiteStone_Id); - endPodiumFeature = new EndPodiumFeature(Tile::whiteStone_Id); + spikeFeature = new SpikeFeature(Tile::endStone_Id); + endPodiumFeature = new EndPodiumFeature(Tile::endStone_Id); } void TheEndBiomeDecorator::decorate() @@ -56,16 +56,17 @@ void TheEndBiomeDecorator::decorate() spikeFeature->placeWithIndex(level, random, SpikeValA[i].x, level->GetHighestY(), SpikeValA[i].z,i,SpikeValA[i].radius); } } - if (xo == 0 && zo == 0) + if (xo == 0 && zo == 0) { shared_ptr enderDragon = shared_ptr(new EnderDragon(level)); - enderDragon->moveTo(0, 128, 0, random->nextFloat() * 360, 0); - level->addEntity(enderDragon); + enderDragon->AddParts(); // 4J added + enderDragon->moveTo(0, 128, 0, random->nextFloat() * 360, 0); + level->addEntity(enderDragon); } // end podium radius is 4, position is 0,0, so chunk needs to be the -16,-16 one since this guarantees that all chunks required for the podium are loaded if (xo == -16 && zo == -16) { - endPodiumFeature->place(level, random, 0, Level::genDepth / 2, 0); - } + endPodiumFeature->place(level, random, 0, level->seaLevel, 0); + } } \ No newline at end of file diff --git a/Minecraft.World/TheEndLevelRandomLevelSource.cpp b/Minecraft.World/TheEndLevelRandomLevelSource.cpp index 46f3dbab..67d85a92 100644 --- a/Minecraft.World/TheEndLevelRandomLevelSource.cpp +++ b/Minecraft.World/TheEndLevelRandomLevelSource.cpp @@ -13,16 +13,16 @@ TheEndLevelRandomLevelSource::TheEndLevelRandomLevelSource(Level *level, __int64 { m_XZSize = END_LEVEL_MIN_WIDTH; - this->level = level; + this->level = level; - random = new Random(seed); + random = new Random(seed); pprandom = new Random(seed); // 4J added - lperlinNoise1 = new PerlinNoise(random, 16); - lperlinNoise2 = new PerlinNoise(random, 16); - perlinNoise1 = new PerlinNoise(random, 8); + lperlinNoise1 = new PerlinNoise(random, 16); + lperlinNoise2 = new PerlinNoise(random, 16); + perlinNoise1 = new PerlinNoise(random, 8); - scaleNoise = new PerlinNoise(random, 10); - depthNoise = new PerlinNoise(random, 16); + scaleNoise = new PerlinNoise(random, 10); + depthNoise = new PerlinNoise(random, 16); } TheEndLevelRandomLevelSource::~TheEndLevelRandomLevelSource() @@ -40,121 +40,121 @@ void TheEndLevelRandomLevelSource::prepareHeights(int xOffs, int zOffs, byteArra { doubleArray buffer; // 4J - used to be declared with class level scope but tidying up for thread safety reasons - int xChunks = 16 / CHUNK_WIDTH; + int xChunks = 16 / CHUNK_WIDTH; - int xSize = xChunks + 1; - int ySize = Level::genDepth / CHUNK_HEIGHT + 1; - int zSize = xChunks + 1; - buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize); + int xSize = xChunks + 1; + int ySize = Level::genDepth / CHUNK_HEIGHT + 1; + int zSize = xChunks + 1; + buffer = getHeights(buffer, xOffs * xChunks, 0, zOffs * xChunks, xSize, ySize, zSize); - for (int xc = 0; xc < xChunks; xc++) + for (int xc = 0; xc < xChunks; xc++) { - for (int zc = 0; zc < xChunks; zc++) + for (int zc = 0; zc < xChunks; zc++) { - for (int yc = 0; yc < Level::genDepth / CHUNK_HEIGHT; yc++) + for (int yc = 0; yc < Level::genDepth / CHUNK_HEIGHT; yc++) { - double yStep = 1 / (double) CHUNK_HEIGHT; - double s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; - double s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; - double s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; - double s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; - - double s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; - double s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; - double s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; - double s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; - - for (int y = 0; y < CHUNK_HEIGHT; y++) + double yStep = 1 / (double) CHUNK_HEIGHT; + double s0 = buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 0)]; + double s1 = buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 0)]; + double s2 = buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 0)]; + double s3 = buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 0)]; + + double s0a = (buffer[((xc + 0) * zSize + (zc + 0)) * ySize + (yc + 1)] - s0) * yStep; + double s1a = (buffer[((xc + 0) * zSize + (zc + 1)) * ySize + (yc + 1)] - s1) * yStep; + double s2a = (buffer[((xc + 1) * zSize + (zc + 0)) * ySize + (yc + 1)] - s2) * yStep; + double s3a = (buffer[((xc + 1) * zSize + (zc + 1)) * ySize + (yc + 1)] - s3) * yStep; + + for (int y = 0; y < CHUNK_HEIGHT; y++) { - double xStep = 1 / (double) CHUNK_WIDTH; + double xStep = 1 / (double) CHUNK_WIDTH; - double _s0 = s0; - double _s1 = s1; - double _s0a = (s2 - s0) * xStep; - double _s1a = (s3 - s1) * xStep; + double _s0 = s0; + double _s1 = s1; + double _s0a = (s2 - s0) * xStep; + double _s1a = (s3 - s1) * xStep; - for (int x = 0; x < CHUNK_WIDTH; x++) + for (int x = 0; x < CHUNK_WIDTH; x++) { - int offs = (x + xc * CHUNK_WIDTH) << Level::genDepthBitsPlusFour | (0 + zc * CHUNK_WIDTH) << Level::genDepthBits | (yc * CHUNK_HEIGHT + y); - int step = 1 << Level::genDepthBits; - double zStep = 1 / (double) CHUNK_WIDTH; + int offs = (x + xc * CHUNK_WIDTH) << Level::genDepthBitsPlusFour | (0 + zc * CHUNK_WIDTH) << Level::genDepthBits | (yc * CHUNK_HEIGHT + y); + int step = 1 << Level::genDepthBits; + double zStep = 1 / (double) CHUNK_WIDTH; - double val = _s0; - double vala = (_s1 - _s0) * zStep; - for (int z = 0; z < CHUNK_WIDTH; z++) + double val = _s0; + double vala = (_s1 - _s0) * zStep; + for (int z = 0; z < CHUNK_WIDTH; z++) { - int tileId = 0; - if (val > 0) + int tileId = 0; + if (val > 0) { - tileId = Tile::whiteStone_Id; - } else { - } - - blocks[offs] = (byte) tileId; - offs += step; - val += vala; - } - _s0 += _s0a; - _s1 += _s1a; - } - - s0 += s0a; - s1 += s1a; - s2 += s2a; - s3 += s3a; - } - } - } - } + tileId = Tile::endStone_Id; + } else { + } + + blocks[offs] = (byte) tileId; + offs += step; + val += vala; + } + _s0 += _s0a; + _s1 += _s1a; + } + + s0 += s0a; + s1 += s1a; + s2 += s2a; + s3 += s3a; + } + } + } + } delete [] buffer.data; } void TheEndLevelRandomLevelSource::buildSurfaces(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes) { - for (int x = 0; x < 16; x++) + for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) + for (int z = 0; z < 16; z++) { - int runDepth = 1; - int run = -1; + int runDepth = 1; + int run = -1; - byte top = (byte) Tile::whiteStone_Id; - byte material = (byte) Tile::whiteStone_Id; + byte top = (byte) Tile::endStone_Id; + byte material = (byte) Tile::endStone_Id; - for (int y = Level::genDepthMinusOne; y >= 0; y--) + for (int y = Level::genDepthMinusOne; y >= 0; y--) { - int offs = (z * 16 + x) * Level::genDepth + y; + int offs = (z * 16 + x) * Level::genDepth + y; - int old = blocks[offs]; + int old = blocks[offs]; - if (old == 0) + if (old == 0) { - run = -1; - } - else if (old == Tile::rock_Id) + run = -1; + } + else if (old == Tile::stone_Id) { - if (run == -1) + if (run == -1) { - if (runDepth <= 0) + if (runDepth <= 0) { - top = 0; - material = (byte) Tile::whiteStone_Id; - } - - run = runDepth; - if (y >= 0) blocks[offs] = top; - else blocks[offs] = material; - } + top = 0; + material = (byte) Tile::endStone_Id; + } + + run = runDepth; + if (y >= 0) blocks[offs] = top; + else blocks[offs] = material; + } else if (run > 0) { - run--; - blocks[offs] = material; - } - } - } - } - } + run--; + blocks[offs] = material; + } + } + } + } + } } LevelChunk *TheEndLevelRandomLevelSource::create(int x, int z) @@ -164,7 +164,7 @@ LevelChunk *TheEndLevelRandomLevelSource::create(int x, int z) LevelChunk *TheEndLevelRandomLevelSource::getChunk(int xOffs, int zOffs) { - random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); + random->setSeed(xOffs * 341873128712l + zOffs * 132897987541l); BiomeArray biomes; // 4J - now allocating this with a physical alloc & bypassing general memory management so that it will get cleanly freed @@ -172,119 +172,119 @@ LevelChunk *TheEndLevelRandomLevelSource::getChunk(int xOffs, int zOffs) byte *tileData = (byte *)XPhysicalAlloc(blocksSize, MAXULONG_PTR, 4096, PAGE_READWRITE); XMemSet128(tileData,0,blocksSize); byteArray blocks = byteArray(tileData,blocksSize); -// byteArray blocks = byteArray(16 * level->depth * 16); + // byteArray blocks = byteArray(16 * level->depth * 16); -// LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); // 4J moved below - level->getBiomeSource()->getBiomeBlock(biomes, xOffs * 16, zOffs * 16, 16, 16, true); + // LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); // 4J moved below + level->getBiomeSource()->getBiomeBlock(biomes, xOffs * 16, zOffs * 16, 16, 16, true); - prepareHeights(xOffs, zOffs, blocks, biomes); - buildSurfaces(xOffs, zOffs, blocks, biomes); + prepareHeights(xOffs, zOffs, blocks, biomes); + buildSurfaces(xOffs, zOffs, blocks, biomes); // 4J - this now creates compressed block data from the blocks array passed in, so moved it until after the blocks are actually finalised. We also // now need to free the passed in blocks as the LevelChunk doesn't use the passed in allocation anymore. LevelChunk *levelChunk = new LevelChunk(level, blocks, xOffs, zOffs); XPhysicalFree(tileData); - levelChunk->recalcHeightmap(); + levelChunk->recalcHeightmap(); //delete blocks.data; // Don't delete the blocks as the array data is actually owned by the chunk now delete biomes.data; - return levelChunk; + return levelChunk; } doubleArray TheEndLevelRandomLevelSource::getHeights(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize) { - if (buffer.data == NULL) + if (buffer.data == NULL) { - buffer = doubleArray(xSize * ySize * zSize); - } + buffer = doubleArray(xSize * ySize * zSize); + } - double s = 1 * 684.412; - double hs = 1 * 684.412; + double s = 1 * 684.412; + double hs = 1 * 684.412; doubleArray pnr, ar, br, sr, dr, fi, fis; // 4J - used to be declared with class level scope but moved here for thread safety - sr = scaleNoise->getRegion(sr, x, z, xSize, zSize, 1.121, 1.121, 0.5); - dr = depthNoise->getRegion(dr, x, z, xSize, zSize, 200.0, 200.0, 0.5); + sr = scaleNoise->getRegion(sr, x, z, xSize, zSize, 1.121, 1.121, 0.5); + dr = depthNoise->getRegion(dr, x, z, xSize, zSize, 200.0, 200.0, 0.5); - s *= 2; + s *= 2; - pnr = perlinNoise1->getRegion(pnr, x, y, z, xSize, ySize, zSize, s / 80.0, hs / 160.0, s / 80.0); - ar = lperlinNoise1->getRegion(ar, x, y, z, xSize, ySize, zSize, s, hs, s); - br = lperlinNoise2->getRegion(br, x, y, z, xSize, ySize, zSize, s, hs, s); + pnr = perlinNoise1->getRegion(pnr, x, y, z, xSize, ySize, zSize, s / 80.0, hs / 160.0, s / 80.0); + ar = lperlinNoise1->getRegion(ar, x, y, z, xSize, ySize, zSize, s, hs, s); + br = lperlinNoise2->getRegion(br, x, y, z, xSize, ySize, zSize, s, hs, s); - int p = 0; - int pp = 0; + int p = 0; + int pp = 0; - for (int xx = 0; xx < xSize; xx++) + for (int xx = 0; xx < xSize; xx++) { - for (int zz = 0; zz < zSize; zz++) + for (int zz = 0; zz < zSize; zz++) { - double scale = ((sr[pp] + 256.0) / 512); - if (scale > 1) scale = 1; + double scale = ((sr[pp] + 256.0) / 512); + if (scale > 1) scale = 1; - double depth = (dr[pp] / 8000.0); - if (depth < 0) depth = -depth * 0.3; - depth = depth * 3.0 - 2.0; + double depth = (dr[pp] / 8000.0); + if (depth < 0) depth = -depth * 0.3; + depth = depth * 3.0 - 2.0; - float xd = ((xx + x) - 0) / 1.0f; - float zd = ((zz + z) - 0) / 1.0f; - float doffs = 100 - sqrt(xd * xd + zd * zd) * 8; - if (doffs > 80) doffs = 80; - if (doffs < -100) doffs = -100; - if (depth > 1) depth = 1; - depth = depth / 8; - depth = 0; + float xd = ((xx + x) - 0) / 1.0f; + float zd = ((zz + z) - 0) / 1.0f; + float doffs = 100 - sqrt(xd * xd + zd * zd) * 8; + if (doffs > 80) doffs = 80; + if (doffs < -100) doffs = -100; + if (depth > 1) depth = 1; + depth = depth / 8; + depth = 0; - if (scale < 0) scale = 0; - scale = (scale) + 0.5; - depth = depth * ySize / 16; + if (scale < 0) scale = 0; + scale = (scale) + 0.5; + depth = depth * ySize / 16; - pp++; + pp++; - double yCenter = ySize / 2.0; + double yCenter = ySize / 2.0; - for (int yy = 0; yy < ySize; yy++) + for (int yy = 0; yy < ySize; yy++) { - double val = 0; - double yOffs = (yy - (yCenter)) * 8 / scale; + double val = 0; + double yOffs = (yy - (yCenter)) * 8 / scale; - if (yOffs < 0) yOffs *= -1; + if (yOffs < 0) yOffs *= -1; - double bb = ar[p] / 512; - double cc = br[p] / 512; + double bb = ar[p] / 512; + double cc = br[p] / 512; - double v = (pnr[p] / 10 + 1) / 2; - if (v < 0) val = bb; - else if (v > 1) val = cc; - else val = bb + (cc - bb) * v; - val -= 8; - val += doffs; + double v = (pnr[p] / 10 + 1) / 2; + if (v < 0) val = bb; + else if (v > 1) val = cc; + else val = bb + (cc - bb) * v; + val -= 8; + val += doffs; - int r = 2; - if (yy > ySize / 2 - r) + int r = 2; + if (yy > ySize / 2 - r) { - double slide = (yy - (ySize / 2 - r)) / (64.0f); - if (slide < 0) slide = 0; - if (slide > 1) slide = 1; - val = val * (1 - slide) + -3000 * slide; - } - r = 8; - if (yy < r) + double slide = (yy - (ySize / 2 - r)) / (64.0f); + if (slide < 0) slide = 0; + if (slide > 1) slide = 1; + val = val * (1 - slide) + -3000 * slide; + } + r = 8; + if (yy < r) { - double slide = (r - yy) / (r - 1.0f); - val = val * (1 - slide) + -30 * slide; - } + double slide = (r - yy) / (r - 1.0f); + val = val * (1 - slide) + -30 * slide; + } - buffer[p] = val; - p++; - } - } - } + buffer[p] = val; + p++; + } + } + } delete [] pnr.data; delete [] ar.data; @@ -294,7 +294,7 @@ doubleArray TheEndLevelRandomLevelSource::getHeights(doubleArray buffer, int x, delete [] fi.data; delete [] fis.data; - return buffer; + return buffer; } @@ -305,68 +305,68 @@ bool TheEndLevelRandomLevelSource::hasChunk(int x, int y) void TheEndLevelRandomLevelSource::calcWaterDepths(ChunkSource *parent, int xt, int zt) { - int xo = xt * 16; - int zo = zt * 16; - for (int x = 0; x < 16; x++) + int xo = xt * 16; + int zo = zt * 16; + for (int x = 0; x < 16; x++) { - int y = level->getSeaLevel(); - for (int z = 0; z < 16; z++) + int y = level->getSeaLevel(); + for (int z = 0; z < 16; z++) { - int xp = xo + x + 7; - int zp = zo + z + 7; - int h = level->getHeightmap(xp, zp); - if (h <= 0) + int xp = xo + x + 7; + int zp = zo + z + 7; + int h = level->getHeightmap(xp, zp); + if (h <= 0) { - if (level->getHeightmap(xp - 1, zp) > 0 || level->getHeightmap(xp + 1, zp) > 0 || level->getHeightmap(xp, zp - 1) > 0 || level->getHeightmap(xp, zp + 1) > 0) + if (level->getHeightmap(xp - 1, zp) > 0 || level->getHeightmap(xp + 1, zp) > 0 || level->getHeightmap(xp, zp - 1) > 0 || level->getHeightmap(xp, zp + 1) > 0) { - bool hadWater = false; - if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater_Id && level->getData(xp - 1, y, zp) < 7)) hadWater = true; - if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater_Id && level->getData(xp + 1, y, zp) < 7)) hadWater = true; - if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater_Id && level->getData(xp, y, zp - 1) < 7)) hadWater = true; - if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater_Id && level->getData(xp, y, zp + 1) < 7)) hadWater = true; - if (hadWater) + bool hadWater = false; + if (hadWater || (level->getTile(xp - 1, y, zp) == Tile::calmWater_Id && level->getData(xp - 1, y, zp) < 7)) hadWater = true; + if (hadWater || (level->getTile(xp + 1, y, zp) == Tile::calmWater_Id && level->getData(xp + 1, y, zp) < 7)) hadWater = true; + if (hadWater || (level->getTile(xp, y, zp - 1) == Tile::calmWater_Id && level->getData(xp, y, zp - 1) < 7)) hadWater = true; + if (hadWater || (level->getTile(xp, y, zp + 1) == Tile::calmWater_Id && level->getData(xp, y, zp + 1) < 7)) hadWater = true; + if (hadWater) { - for (int x2 = -5; x2 <= 5; x2++) + for (int x2 = -5; x2 <= 5; x2++) { - for (int z2 = -5; z2 <= 5; z2++) + for (int z2 = -5; z2 <= 5; z2++) { - int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2); + int d = (x2 > 0 ? x2 : -x2) + (z2 > 0 ? z2 : -z2); - if (d <= 5) + if (d <= 5) { - d = 6 - d; - if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater_Id) + d = 6 - d; + if (level->getTile(xp + x2, y, zp + z2) == Tile::calmWater_Id) { - int od = level->getData(xp + x2, y, zp + z2); - if (od < 7 && od < d) + int od = level->getData(xp + x2, y, zp + z2); + if (od < 7 && od < d) { - level->setData(xp + x2, y, zp + z2, d); - } - } - } - } - } - if (hadWater) + level->setData(xp + x2, y, zp + z2, d, Tile::UPDATE_CLIENTS); + } + } + } + } + } + if (hadWater) { - level->setTileAndDataNoUpdate(xp, y, zp, Tile::calmWater_Id, 7); - for (int y2 = 0; y2 < y; y2++) + level->setTileAndData(xp, y, zp, Tile::calmWater_Id, 7, Tile::UPDATE_CLIENTS); + for (int y2 = 0; y2 < y; y2++) { - level->setTileAndDataNoUpdate(xp, y2, zp, Tile::calmWater_Id, 8); - } - } - } - } - } - } - } + level->setTileAndData(xp, y2, zp, Tile::calmWater_Id, 8, Tile::UPDATE_CLIENTS); + } + } + } + } + } + } + } } void TheEndLevelRandomLevelSource::postProcess(ChunkSource *parent, int xt, int zt) { - HeavyTile::instaFall = true; - int xo = xt * 16; - int zo = zt * 16; + HeavyTile::instaFall = true; + int xo = xt * 16; + int zo = zt * 16; // 4J - added. The original java didn't do any setting of the random seed here, and passes the level random to the biome decorator. // We'll be running our postProcess in parallel with getChunk etc. so we need to use a separate random - have used the same initialisation code as @@ -376,11 +376,11 @@ void TheEndLevelRandomLevelSource::postProcess(ChunkSource *parent, int xt, int __int64 zScale = pprandom->nextLong() / 2 * 2 + 1; pprandom->setSeed(((xt * xScale) + (zt * zScale)) ^ level->getSeed()); - Biome *biome = level->getBiome(xo + 16, zo + 16); - biome->decorate(level, pprandom, xo, zo); // 4J - passing pprandom rather than level->random here to make this consistent with our parallel world generation + Biome *biome = level->getBiome(xo + 16, zo + 16); + biome->decorate(level, pprandom, xo, zo); // 4J - passing pprandom rather than level->random here to make this consistent with our parallel world generation + + HeavyTile::instaFall = false; - HeavyTile::instaFall = false; - app.processSchematics(parent->getChunk(xt,zt)); } @@ -406,16 +406,19 @@ wstring TheEndLevelRandomLevelSource::gatherStats() vector *TheEndLevelRandomLevelSource::getMobsAt(MobCategory *mobCategory, int x, int y, int z) { - Biome *biome = level->getBiome(x, z); - if (biome == NULL) + Biome *biome = level->getBiome(x, z); + if (biome == NULL) { - return NULL; - } - return biome->getMobs(mobCategory); + return NULL; + } + return biome->getMobs(mobCategory); } TilePos *TheEndLevelRandomLevelSource::findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z) { return NULL; } - + +void TheEndLevelRandomLevelSource::recreateLogicStructuresForChunk(int chunkX, int chunkZ) +{ +} \ No newline at end of file diff --git a/Minecraft.World/TheEndLevelRandomLevelSource.h b/Minecraft.World/TheEndLevelRandomLevelSource.h index 2dc7f131..4a2a4f2a 100644 --- a/Minecraft.World/TheEndLevelRandomLevelSource.h +++ b/Minecraft.World/TheEndLevelRandomLevelSource.h @@ -6,24 +6,24 @@ class PerlinNoise; class TheEndLevelRandomLevelSource : public ChunkSource { public: - static const double SNOW_CUTOFF; - static const double SNOW_SCALE; - static const bool FLOATING_ISLANDS; + static const double SNOW_CUTOFF; + static const double SNOW_SCALE; + static const bool FLOATING_ISLANDS; - static const int CHUNK_HEIGHT = 4; - static const int CHUNK_WIDTH = 8; + static const int CHUNK_HEIGHT = 4; + static const int CHUNK_WIDTH = 8; private: Random *random; Random *pprandom; private: PerlinNoise *lperlinNoise1; - PerlinNoise *lperlinNoise2; - PerlinNoise *perlinNoise1; + PerlinNoise *lperlinNoise2; + PerlinNoise *perlinNoise1; public: PerlinNoise *scaleNoise; - PerlinNoise *depthNoise; - PerlinNoise *forestNoise; + PerlinNoise *depthNoise; + PerlinNoise *forestNoise; private: @@ -33,12 +33,12 @@ public: TheEndLevelRandomLevelSource(Level *level, __int64 seed); ~TheEndLevelRandomLevelSource(); - void prepareHeights(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes); - void buildSurfaces(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes); + void prepareHeights(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes); + void buildSurfaces(int xOffs, int zOffs, byteArray blocks, BiomeArray biomes); public: virtual LevelChunk *create(int x, int z); - virtual LevelChunk *getChunk(int xOffs, int zOffs); + virtual LevelChunk *getChunk(int xOffs, int zOffs); private: doubleArray getHeights(doubleArray buffer, int x, int y, int z, int xSize, int ySize, int zSize); @@ -49,12 +49,13 @@ private: void calcWaterDepths(ChunkSource *parent, int xt, int zt); public: virtual void postProcess(ChunkSource *parent, int xt, int zt); - virtual bool save(bool force, ProgressListener *progressListener); - virtual bool tick(); - virtual bool shouldSave(); - virtual wstring gatherStats(); + virtual bool save(bool force, ProgressListener *progressListener); + virtual bool tick(); + virtual bool shouldSave(); + virtual wstring gatherStats(); public: virtual vector *getMobsAt(MobCategory *mobCategory, int x, int y, int z); - virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual TilePos *findNearestMapFeature(Level *level, const wstring& featureName, int x, int y, int z); + virtual void recreateLogicStructuresForChunk(int chunkX, int chunkZ); }; diff --git a/Minecraft.World/TheEndPortal.cpp b/Minecraft.World/TheEndPortal.cpp index 19d95b1f..f2cb5dad 100644 --- a/Minecraft.World/TheEndPortal.cpp +++ b/Minecraft.World/TheEndPortal.cpp @@ -21,9 +21,9 @@ void TheEndPortal::allowAnywhere(bool set) TlsSetValue(tlsIdx,(LPVOID)(set?1:0)); } -TheEndPortal::TheEndPortal(int id, Material *material) : EntityTile(id, material, isSolidRender()) +TheEndPortal::TheEndPortal(int id, Material *material) : BaseEntityTile(id, material, isSolidRender()) { - this->setLightEmission(1.0f); + this->setLightEmission(1.0f); } shared_ptr TheEndPortal::newTileEntity(Level *level) @@ -33,14 +33,14 @@ shared_ptr TheEndPortal::newTileEntity(Level *level) void TheEndPortal::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { - float r = 1 / 16.0f; - this->setShape(0, 0, 0, 1, r, 1); + float r = 1 / 16.0f; + setShape(0, 0, 0, 1, r, 1); } bool TheEndPortal::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { - if (face != 0) return false; - return EntityTile::shouldRenderFace(level, x, y, z, face); + if (face != 0) return false; + return BaseEntityTile::shouldRenderFace(level, x, y, z, face); } void TheEndPortal::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source) @@ -64,11 +64,13 @@ int TheEndPortal::getResourceCount(Random *random) void TheEndPortal::entityInside(Level *level, int x, int y, int z, shared_ptr entity) { - if (entity->riding == NULL && entity->rider.lock() == NULL) + if (entity->GetType() == eTYPE_EXPERIENCEORB ) return; // 4J added + + if (entity->riding == NULL && entity->rider.lock() == NULL) { - if (dynamic_pointer_cast(entity) != NULL) + if (!level->isClientSide) { - if (!level->isClientSide) + if ( entity->instanceof(eTYPE_PLAYER) ) { // 4J Stu - Update the level data position so that the stronghold portal can be shown on the maps int x,z; @@ -79,39 +81,38 @@ void TheEndPortal::entityInside(Level *level, int x, int y, int z, shared_ptrgetLevelData()->setZStrongholdEndPortal(z); level->getLevelData()->setHasStrongholdEndPortal(); } - - (dynamic_pointer_cast(entity))->changeDimension(1); - } - } - } + } + entity->changeDimension(1); + } + } } void TheEndPortal::animateTick(Level *level, int xt, int yt, int zt, Random *random) { - double x = xt + random->nextFloat(); - double y = yt + 0.8f; - double z = zt + random->nextFloat(); - double xa = 0; - double ya = 0; - double za = 0; + double x = xt + random->nextFloat(); + double y = yt + 0.8f; + double z = zt + random->nextFloat(); + double xa = 0; + double ya = 0; + double za = 0; - level->addParticle(eParticleType_endportal, x, y, z, xa, ya, za); + level->addParticle(eParticleType_endportal, x, y, z, xa, ya, za); } int TheEndPortal::getRenderShape() { - return SHAPE_INVISIBLE; + return SHAPE_INVISIBLE; } void TheEndPortal::onPlace(Level *level, int x, int y, int z) { - if (allowAnywhere()) return; + if (allowAnywhere()) return; - if (level->dimension->id != 0) + if (level->dimension->id != 0) { - level->setTile(x, y, z, 0); - return; - } + level->removeTile(x, y, z); + return; + } } int TheEndPortal::cloneTileId(Level *level, int x, int y, int z) diff --git a/Minecraft.World/TheEndPortal.h b/Minecraft.World/TheEndPortal.h index 31cddb2d..a1bb5498 100644 --- a/Minecraft.World/TheEndPortal.h +++ b/Minecraft.World/TheEndPortal.h @@ -1,27 +1,27 @@ #pragma once -#include "EntityTile.h" +#include "BaseEntityTile.h" -class TheEndPortal : public EntityTile +class TheEndPortal : public BaseEntityTile { public: static DWORD tlsIdx; // 4J - was just a static but implemented with TLS for our version - static bool allowAnywhere(); + static bool allowAnywhere(); static void allowAnywhere(bool set); TheEndPortal(int id, Material *material); - virtual shared_ptr newTileEntity(Level *level); - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param - virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); - virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); - virtual int getResourceCount(Random *random); - virtual void entityInside(Level *level, int x, int y, int z, shared_ptr entity); - virtual void animateTick(Level *level, int xt, int yt, int zt, Random *random); - virtual int getRenderShape(); - virtual void onPlace(Level *level, int x, int y, int z); + virtual shared_ptr newTileEntity(Level *level); + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param + virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); + virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); + virtual int getResourceCount(Random *random); + virtual void entityInside(Level *level, int x, int y, int z, shared_ptr entity); + virtual void animateTick(Level *level, int xt, int yt, int zt, Random *random); + virtual int getRenderShape(); + virtual void onPlace(Level *level, int x, int y, int z); virtual int cloneTileId(Level *level, int x, int y, int z); void registerIcons(IconRegister *iconRegister); }; \ No newline at end of file diff --git a/Minecraft.World/TheEndPortalFrameTile.cpp b/Minecraft.World/TheEndPortalFrameTile.cpp index cab8319f..f7b10a05 100644 --- a/Minecraft.World/TheEndPortalFrameTile.cpp +++ b/Minecraft.World/TheEndPortalFrameTile.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "TheEndPortalFrameTile.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" #include "net.minecraft.world.h" #include "Facing.h" @@ -14,15 +15,15 @@ TheEndPortalFrameTile::TheEndPortalFrameTile(int id) : Tile(id, Material::glass, Icon *TheEndPortalFrameTile::getTexture(int face, int data) { - if (face == Facing::UP) + if (face == Facing::UP) { - return iconTop; - } - if (face == Facing::DOWN) + return iconTop; + } + if (face == Facing::DOWN) { - return Tile::whiteStone->getTexture(face); - } - return icon; + return Tile::endStone->getTexture(face); + } + return icon; } void TheEndPortalFrameTile::registerIcons(IconRegister *iconRegister) @@ -54,16 +55,16 @@ void TheEndPortalFrameTile::updateDefaultShape() void TheEndPortalFrameTile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source) { - setShape(0, 0, 0, 1, 13.0f / 16.0f, 1); - Tile::addAABBs(level, x, y, z, box, boxes, source); + setShape(0, 0, 0, 1, 13.0f / 16.0f, 1); + Tile::addAABBs(level, x, y, z, box, boxes, source); - int data = level->getData(x, y, z); - if (hasEye(data)) + int data = level->getData(x, y, z); + if (hasEye(data)) { - setShape(5.0f / 16.0f, 13.0f / 16.0f, 5.0f / 16.0f, 11.0f / 16.0f, 1, 11.0f / 16.0f); - Tile::addAABBs(level, x, y, z, box, boxes, source); - } - updateDefaultShape(); + setShape(5.0f / 16.0f, 13.0f / 16.0f, 5.0f / 16.0f, 11.0f / 16.0f, 1, 11.0f / 16.0f); + Tile::addAABBs(level, x, y, z, box, boxes, source); + } + updateDefaultShape(); } bool TheEndPortalFrameTile::hasEye(int data) @@ -76,8 +77,27 @@ int TheEndPortalFrameTile::getResource(int data, Random *random, int playerBonus return 0; } -void TheEndPortalFrameTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void TheEndPortalFrameTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { - int dir = (((Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3) + 2) % 4; - level->setData(x, y, z, dir); + int dir = (((Mth::floor(by->yRot * 4 / (360) + 0.5)) & 3) + 2) % 4; + level->setData(x, y, z, dir, Tile::UPDATE_CLIENTS); } + +bool TheEndPortalFrameTile::hasAnalogOutputSignal() +{ + return true; +} + +int TheEndPortalFrameTile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + int data = level->getData(x, y, z); + + if (hasEye(data)) + { + return Redstone::SIGNAL_MAX; + } + else + { + return Redstone::SIGNAL_NONE; + } +} \ No newline at end of file diff --git a/Minecraft.World/TheEndPortalFrameTile.h b/Minecraft.World/TheEndPortalFrameTile.h index b48d3c09..d3119d00 100644 --- a/Minecraft.World/TheEndPortalFrameTile.h +++ b/Minecraft.World/TheEndPortalFrameTile.h @@ -12,15 +12,17 @@ private: Icon *iconEye; public: - TheEndPortalFrameTile(int id); - virtual Icon *getTexture(int face, int data); + TheEndPortalFrameTile(int id); + virtual Icon *getTexture(int face, int data); void registerIcons(IconRegister *iconRegister); Icon *getEye(); - virtual bool isSolidRender(bool isServerLevel = false); - virtual int getRenderShape(); - virtual void updateDefaultShape(); - virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); - static bool hasEye(int data); - virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); + virtual bool isSolidRender(bool isServerLevel = false); + virtual int getRenderShape(); + virtual void updateDefaultShape(); + virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); + static bool hasEye(int data); + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); }; \ No newline at end of file diff --git a/Minecraft.World/ThinFenceTile.cpp b/Minecraft.World/ThinFenceTile.cpp index bd1f1687..3f471ce4 100644 --- a/Minecraft.World/ThinFenceTile.cpp +++ b/Minecraft.World/ThinFenceTile.cpp @@ -32,7 +32,7 @@ bool ThinFenceTile::isCubeShaped() int ThinFenceTile::getRenderShape() { - return Tile::SHAPE_IRON_FENCE; + return material == Material::glass ? Tile::SHAPE_THIN_PANE : Tile::SHAPE_IRON_FENCE; } bool ThinFenceTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) @@ -134,7 +134,7 @@ Icon *ThinFenceTile::getEdgeTexture() bool ThinFenceTile::attachsTo(int tile) { - return Tile::solid[tile] || tile == id || tile == Tile::glass_Id; + return Tile::solid[tile] || tile == id || tile == Tile::glass_Id || tile == Tile::stained_glass_Id || tile == Tile::stained_glass_pane_Id; } bool ThinFenceTile::isSilkTouchable() diff --git a/Minecraft.World/ThinFenceTile.h b/Minecraft.World/ThinFenceTile.h index ca3c501f..eb310dd0 100644 --- a/Minecraft.World/ThinFenceTile.h +++ b/Minecraft.World/ThinFenceTile.h @@ -28,5 +28,5 @@ protected: shared_ptr getSilkTouchItemInstance(int data); public: - void registerIcons(IconRegister *iconRegister); + virtual void registerIcons(IconRegister *iconRegister); }; diff --git a/Minecraft.World/ThornsEnchantment.cpp b/Minecraft.World/ThornsEnchantment.cpp index e2d9f1fa..53668642 100644 --- a/Minecraft.World/ThornsEnchantment.cpp +++ b/Minecraft.World/ThornsEnchantment.cpp @@ -52,7 +52,7 @@ int ThornsEnchantment::getDamage(int level, Random *random) } } -void ThornsEnchantment::doThornsAfterAttack(shared_ptr source, shared_ptr target, Random *random) +void ThornsEnchantment::doThornsAfterAttack(shared_ptr source, shared_ptr target, Random *random) { int level = EnchantmentHelper::getArmorThorns(target); shared_ptr item = EnchantmentHelper::getRandomItemWith(Enchantment::thorns, target); @@ -64,14 +64,14 @@ void ThornsEnchantment::doThornsAfterAttack(shared_ptr source, shared_pt if (item != NULL) { - item->hurt(3, target); + item->hurtAndBreak(3, target); } } else { if (item != NULL) { - item->hurt(1, target); + item->hurtAndBreak(1, target); } } } \ No newline at end of file diff --git a/Minecraft.World/ThornsEnchantment.h b/Minecraft.World/ThornsEnchantment.h index 42f4326b..9383288a 100644 --- a/Minecraft.World/ThornsEnchantment.h +++ b/Minecraft.World/ThornsEnchantment.h @@ -16,5 +16,5 @@ public: virtual bool canEnchant(shared_ptr item); static bool shouldHit(int level, Random *random); static int getDamage(int level, Random *random); - static void doThornsAfterAttack(shared_ptr source, shared_ptr target, Random *random); + static void doThornsAfterAttack(shared_ptr source, shared_ptr target, Random *random); }; \ No newline at end of file diff --git a/Minecraft.World/Throwable.cpp b/Minecraft.World/Throwable.cpp index 2f9567a1..7d30b898 100644 --- a/Minecraft.World/Throwable.cpp +++ b/Minecraft.World/Throwable.cpp @@ -2,6 +2,7 @@ #include "net.minecraft.world.phys.h" #include "net.minecraft.world.entity.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" #include "com.mojang.nbt.h" #include "Throwable.h" @@ -18,6 +19,7 @@ void Throwable::_throwableInit() owner = nullptr; life = 0; flightTime = 0; + ownerName = L""; } Throwable::Throwable(Level *level) : Entity(level) @@ -37,21 +39,21 @@ bool Throwable::shouldRenderAtSqrDistance(double distance) return distance < size * size; } -Throwable::Throwable(Level *level, shared_ptr mob) : Entity(level) +Throwable::Throwable(Level *level, shared_ptr mob) : Entity(level) { _throwableInit(); - this->owner = mob; + owner = mob; setSize(4 / 16.0f, 4 / 16.0f); - this->moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot); + moveTo(mob->x, mob->y + mob->getHeadHeight(), mob->z, mob->yRot, mob->xRot); x -= cos(yRot / 180 * PI) * 0.16f; y -= 0.1f; z -= sin(yRot / 180 * PI) * 0.16f; - this->setPos(x, y, z); - this->heightOffset = 0; + setPos(x, y, z); + heightOffset = 0; float speed = 0.4f; @@ -69,8 +71,8 @@ Throwable::Throwable(Level *level, double x, double y, double z) : Entity(level) setSize(4 / 16.0f, 4 / 16.0f); - this->setPos(x, y, z); - this->heightOffset = 0; + setPos(x, y, z); + heightOffset = 0; } @@ -106,8 +108,8 @@ void Throwable::shoot(double xd, double yd, double zd, float pow, float uncertai float sd = (float) sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (atan2(xd, zd) * 180 / PI); - xRotO = this->xRot = (float) (atan2(yd, (double)sd) * 180 / PI); + yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI); + xRotO = xRot = (float) (atan2(yd, (double)sd) * 180 / PI); life = 0; } @@ -119,8 +121,8 @@ void Throwable::lerpMotion(double xd, double yd, double zd) if (xRotO == 0 && yRotO == 0) { float sd = (float) sqrt(xd * xd + zd * zd); - yRotO = this->yRot = (float) (atan2(xd, zd) * 180 / PI); - xRotO = this->xRot = (float) (atan2(yd, (double)sd) * 180 / PI); + yRotO = yRot = (float) (atan2(xd, zd) * 180 / PI); + xRotO = xRot = (float) (atan2(yd, (double)sd) * 180 / PI); } } @@ -172,8 +174,9 @@ void Throwable::tick() if (!level->isClientSide) { shared_ptr hitEntity = nullptr; - vector > *objects = level->getEntities(shared_from_this(), this->bb->expand(xd, yd, zd)->grow(1, 1, 1)); + vector > *objects = level->getEntities(shared_from_this(), bb->expand(xd, yd, zd)->grow(1, 1, 1)); double nearest = 0; + shared_ptr owner = getOwner(); for (int i = 0; i < objects->size(); i++) { shared_ptr e = objects->at(i); @@ -203,7 +206,14 @@ void Throwable::tick() if (res != NULL) { - onHit(res); + if ( (res->type == HitResult::TILE) && (level->getTile(res->x, res->y, res->z) == Tile::portalTile_Id) ) + { + handleInsidePortal(); + } + else + { + onHit(res); + } delete res; } x += xd; @@ -263,6 +273,13 @@ void Throwable::addAdditonalSaveData(CompoundTag *tag) tag->putByte(L"inTile", (byte) lastTile); tag->putByte(L"shake", (byte) shakeTime); tag->putByte(L"inGround", (byte) (inGround ? 1 : 0)); + + if (ownerName.empty() && (owner != NULL) && owner->instanceof(eTYPE_PLAYER) ) + { + ownerName = owner->getAName(); + } + + tag->putString(L"ownerName", ownerName.empty() ? L"" : ownerName); } void Throwable::readAdditionalSaveData(CompoundTag *tag) @@ -273,9 +290,20 @@ void Throwable::readAdditionalSaveData(CompoundTag *tag) lastTile = tag->getByte(L"inTile") & 0xff; shakeTime = tag->getByte(L"shake") & 0xff; inGround = tag->getByte(L"inGround") == 1; + ownerName = tag->getString(L"ownerName"); + if (ownerName.empty() ) ownerName = L""; } float Throwable::getShadowHeightOffs() { return 0; +} + +shared_ptr Throwable::getOwner() +{ + if (owner == NULL && !ownerName.empty() ) + { + owner = level->getPlayerByName(ownerName); + } + return owner; } \ No newline at end of file diff --git a/Minecraft.World/Throwable.h b/Minecraft.World/Throwable.h index 4d7daea0..217f2f1e 100644 --- a/Minecraft.World/Throwable.h +++ b/Minecraft.World/Throwable.h @@ -1,11 +1,12 @@ #pragma once #include "Entity.h" +#include "Projectile.h" class Mob; class HitResult; -class Throwable : public Entity +class Throwable : public Entity, public Projectile { private: int xTile; @@ -19,10 +20,10 @@ protected: public: int shakeTime; -protected: - shared_ptr owner; + shared_ptr owner; private: + wstring ownerName; int life; int flightTime; @@ -37,7 +38,7 @@ protected: public: virtual bool shouldRenderAtSqrDistance(double distance); - Throwable(Level *level, shared_ptr mob); + Throwable(Level *level, shared_ptr mob); Throwable(Level *level, double x, double y, double z); protected: @@ -57,4 +58,5 @@ public: virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); virtual float getShadowHeightOffs(); + virtual shared_ptr getOwner(); }; \ No newline at end of file diff --git a/Minecraft.World/ThrownEgg.cpp b/Minecraft.World/ThrownEgg.cpp index 45e5ca8c..1378e094 100644 --- a/Minecraft.World/ThrownEgg.cpp +++ b/Minecraft.World/ThrownEgg.cpp @@ -21,7 +21,7 @@ ThrownEgg::ThrownEgg(Level *level) : Throwable(level) _init(); } -ThrownEgg::ThrownEgg(Level *level, shared_ptr mob) : Throwable(level,mob) +ThrownEgg::ThrownEgg(Level *level, shared_ptr mob) : Throwable(level,mob) { _init(); } diff --git a/Minecraft.World/ThrownEgg.h b/Minecraft.World/ThrownEgg.h index 864755b7..324dc237 100644 --- a/Minecraft.World/ThrownEgg.h +++ b/Minecraft.World/ThrownEgg.h @@ -15,7 +15,7 @@ private: public: ThrownEgg(Level *level); - ThrownEgg(Level *level, shared_ptr mob); + ThrownEgg(Level *level, shared_ptr mob); ThrownEgg(Level *level, double x, double y, double z); protected: diff --git a/Minecraft.World/ThrownEnderpearl.cpp b/Minecraft.World/ThrownEnderpearl.cpp index 1cddfb1f..1035bffd 100644 --- a/Minecraft.World/ThrownEnderpearl.cpp +++ b/Minecraft.World/ThrownEnderpearl.cpp @@ -16,7 +16,7 @@ ThrownEnderpearl::ThrownEnderpearl(Level *level) : Throwable(level) this->defineSynchedData(); } -ThrownEnderpearl::ThrownEnderpearl(Level *level, shared_ptr mob) : Throwable(level,mob) +ThrownEnderpearl::ThrownEnderpearl(Level *level, shared_ptr mob) : Throwable(level,mob) { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called @@ -34,7 +34,7 @@ void ThrownEnderpearl::onHit(HitResult *res) { if (res->entity != NULL) { - DamageSource *damageSource = DamageSource::thrown(shared_from_this(), owner); + DamageSource *damageSource = DamageSource::thrown(shared_from_this(), getOwner() ); res->entity->hurt(damageSource, 0); delete damageSource; } @@ -47,14 +47,23 @@ void ThrownEnderpearl::onHit(HitResult *res) { // Fix for #67486 - TCR #001: BAS Game Stability: Customer Encountered: TU8: Code: Gameplay: The title crashes on Host's console when Client Player leaves the game before the Ender Pearl thrown by him touches the ground. // If the owner has been removed, then ignore - shared_ptr serverPlayer = dynamic_pointer_cast(owner); - if (serverPlayer != NULL && !serverPlayer->removed) + + // 4J-JEV: Cheap type check first. + if ( (getOwner() != NULL) && getOwner()->instanceof(eTYPE_SERVERPLAYER) ) { - if(!serverPlayer->connection->done && serverPlayer->level == this->level) + shared_ptr serverPlayer = dynamic_pointer_cast(getOwner() ); + if (!serverPlayer->removed) { - owner->teleportTo(x, y, z); - owner->fallDistance = 0; - owner->hurt(DamageSource::fall, 5); + if(!serverPlayer->connection->done && serverPlayer->level == this->level) + { + if (getOwner()->isRiding()) + { + getOwner()->ride(nullptr); + } + getOwner()->teleportTo(x, y, z); + getOwner()->fallDistance = 0; + getOwner()->hurt(DamageSource::fall, 5); + } } } remove(); diff --git a/Minecraft.World/ThrownEnderpearl.h b/Minecraft.World/ThrownEnderpearl.h index 6f16ebfc..2ce6ec1f 100644 --- a/Minecraft.World/ThrownEnderpearl.h +++ b/Minecraft.World/ThrownEnderpearl.h @@ -11,7 +11,7 @@ public: static Entity *create(Level *level) { return new ThrownEnderpearl(level); } ThrownEnderpearl(Level *level); - ThrownEnderpearl(Level *level, shared_ptr mob); + ThrownEnderpearl(Level *level, shared_ptr mob); ThrownEnderpearl(Level *level, double x, double y, double z); protected: diff --git a/Minecraft.World/ThrownExpBottle.cpp b/Minecraft.World/ThrownExpBottle.cpp index 75d3d9a1..b8dbef96 100644 --- a/Minecraft.World/ThrownExpBottle.cpp +++ b/Minecraft.World/ThrownExpBottle.cpp @@ -11,7 +11,7 @@ ThrownExpBottle::ThrownExpBottle(Level *level) : Throwable(level) { } -ThrownExpBottle::ThrownExpBottle(Level *level, shared_ptr mob) : Throwable(level,mob) +ThrownExpBottle::ThrownExpBottle(Level *level, shared_ptr mob) : Throwable(level,mob) { } diff --git a/Minecraft.World/ThrownExpBottle.h b/Minecraft.World/ThrownExpBottle.h index 8430794b..4531e3e7 100644 --- a/Minecraft.World/ThrownExpBottle.h +++ b/Minecraft.World/ThrownExpBottle.h @@ -11,7 +11,7 @@ public: static Entity *create(Level *level) { return new ThrownExpBottle(level); } public: ThrownExpBottle(Level *level); - ThrownExpBottle(Level *level, shared_ptr mob); + ThrownExpBottle(Level *level, shared_ptr mob); ThrownExpBottle(Level *level, double x, double y, double z); protected: diff --git a/Minecraft.World/ThrownPotion.cpp b/Minecraft.World/ThrownPotion.cpp index 7375d661..f99a0ecb 100644 --- a/Minecraft.World/ThrownPotion.cpp +++ b/Minecraft.World/ThrownPotion.cpp @@ -19,7 +19,7 @@ void ThrownPotion::_init() // the derived version of the function is called this->defineSynchedData(); - potionValue = 0; + potionItem = nullptr; } ThrownPotion::ThrownPotion(Level *level) : Throwable(level) @@ -27,17 +27,32 @@ ThrownPotion::ThrownPotion(Level *level) : Throwable(level) _init(); } -ThrownPotion::ThrownPotion(Level *level, shared_ptr mob, int potionValue) : Throwable(level,mob) +ThrownPotion::ThrownPotion(Level *level, shared_ptr mob, int potionValue) : Throwable(level,mob) { _init(); - this->potionValue = potionValue; + potionItem = shared_ptr( new ItemInstance(Item::potion, 1, potionValue)); +} + +ThrownPotion::ThrownPotion(Level *level, shared_ptr mob, shared_ptr potion) : Throwable(level, mob) +{ + _init(); + + potionItem = potion; } ThrownPotion::ThrownPotion(Level *level, double x, double y, double z, int potionValue) : Throwable(level,x,y,z) { _init(); - this->potionValue = potionValue; + + potionItem = shared_ptr( new ItemInstance(Item::potion, 1, potionValue)); +} + +ThrownPotion::ThrownPotion(Level *level, double x, double y, double z, shared_ptr potion) : Throwable(level, x, y, z) +{ + _init(); + + potionItem = potion; } float ThrownPotion::getGravity() @@ -57,24 +72,26 @@ float ThrownPotion::getThrowUpAngleOffset() void ThrownPotion::setPotionValue(int potionValue) { - this->potionValue = potionValue; + if (potionItem == NULL) potionItem = shared_ptr( new ItemInstance(Item::potion, 1, 0) ); + potionItem->setAuxValue(potionValue); } int ThrownPotion::getPotionValue() { - return potionValue; + if (potionItem == NULL) potionItem = shared_ptr( new ItemInstance(Item::potion, 1, 0) ); + return potionItem->getAuxValue(); } void ThrownPotion::onHit(HitResult *res) { if (!level->isClientSide) { - vector *mobEffects = Item::potion->getMobEffects(potionValue); + vector *mobEffects = Item::potion->getMobEffects(potionItem); if (mobEffects != NULL && !mobEffects->empty()) { AABB *aoe = bb->grow(SPLASH_RANGE, SPLASH_RANGE / 2, SPLASH_RANGE); - vector > *entitiesOfClass = level->getEntitiesOfClass(typeid(Mob), aoe); + vector > *entitiesOfClass = level->getEntitiesOfClass(typeid(LivingEntity), aoe); if (entitiesOfClass != NULL && !entitiesOfClass->empty()) { @@ -82,7 +99,7 @@ void ThrownPotion::onHit(HitResult *res) for(AUTO_VAR(it, entitiesOfClass->begin()); it != entitiesOfClass->end(); ++it) { //shared_ptr e = *it; - shared_ptr e = dynamic_pointer_cast( *it ); + shared_ptr e = dynamic_pointer_cast( *it ); double dist = distanceToSqr(e); if (dist < SPLASH_RANGE_SQ) { @@ -99,7 +116,7 @@ void ThrownPotion::onHit(HitResult *res) int id = effect->getId(); if (MobEffect::effects[id]->isInstantenous()) { - MobEffect::effects[id]->applyInstantenousEffect(this->owner, e, effect->getAmplifier(), scale); + MobEffect::effects[id]->applyInstantenousEffect(getOwner(), e, effect->getAmplifier(), scale); } else { @@ -115,7 +132,7 @@ void ThrownPotion::onHit(HitResult *res) } delete entitiesOfClass; } - level->levelEvent(LevelEvent::PARTICLES_POTION_SPLASH, (int) Math::round(x), (int) Math::round(y), (int) Math::round(z), potionValue); + level->levelEvent(LevelEvent::PARTICLES_POTION_SPLASH, (int) Math::round(x), (int) Math::round(y), (int) Math::round(z), getPotionValue() ); remove(); } @@ -125,12 +142,21 @@ void ThrownPotion::readAdditionalSaveData(CompoundTag *tag) { Throwable::readAdditionalSaveData(tag); - potionValue = tag->getInt(L"potionValue"); + if (tag->contains(L"Potion")) + { + potionItem = ItemInstance::fromTag(tag->getCompound(L"Potion")); + } + else + { + setPotionValue(tag->getInt(L"potionValue")); + } + + if (potionItem == NULL) remove(); } void ThrownPotion::addAdditonalSaveData(CompoundTag *tag) { Throwable::addAdditonalSaveData(tag); - tag->putInt(L"potionValue", potionValue); + if (potionItem != NULL) tag->putCompound(L"Potion", potionItem->save(new CompoundTag())); } \ No newline at end of file diff --git a/Minecraft.World/ThrownPotion.h b/Minecraft.World/ThrownPotion.h index cf27491c..ec6a14da 100644 --- a/Minecraft.World/ThrownPotion.h +++ b/Minecraft.World/ThrownPotion.h @@ -16,14 +16,16 @@ public: private: static const double SPLASH_RANGE_SQ; - int potionValue; + shared_ptr potionItem; void _init(); public: ThrownPotion(Level *level); - ThrownPotion(Level *level, shared_ptr mob, int potionValue); + ThrownPotion(Level *level, shared_ptr mob, int potionValue); + ThrownPotion(Level *level, shared_ptr mob, shared_ptr potion); ThrownPotion(Level *level, double x, double y, double z, int potionValue); + ThrownPotion(Level *level, double x, double y, double z, shared_ptr potion); protected: virtual float getGravity(); diff --git a/Minecraft.World/TickNextTickData.cpp b/Minecraft.World/TickNextTickData.cpp index 96771be1..277be1f8 100644 --- a/Minecraft.World/TickNextTickData.cpp +++ b/Minecraft.World/TickNextTickData.cpp @@ -1,5 +1,5 @@ #include "stdafx.h" - +#include "net.minecraft.world.level.tile.h" #include "TickNextTickData.h" int64_t TickNextTickData::C = 0; @@ -13,41 +13,53 @@ TickNextTickData::TickNextTickData(int x, int y, int z, int tileId) this->y = y; this->z = z; this->tileId = tileId; + priorityTilt = 0; } -bool TickNextTickData::equals(const void *o) const +bool TickNextTickData::equals(const TickNextTickData *o) const { // TODO 4J Is this safe to cast it before we do a dynamic_cast? Will the dynamic_cast still fail? // We cannot dynamic_cast a void* - if ( dynamic_cast( (TickNextTickData *) o ) != NULL) + if ( o != NULL) { TickNextTickData *t = (TickNextTickData *) o; - return x == t->x && y == t->y && z == t->z && tileId == t->tileId; + return x == t->x && y == t->y && z == t->z && Tile::isMatching(tileId, t->tileId); } return false; } int TickNextTickData::hashCode() const { - return (((x * 1024 * 1024) + (z * 1024) + y) * 256) + tileId; + return (((x * 1024 * 1024) + (z * 1024) + y) * 256); } TickNextTickData *TickNextTickData::delay(int64_t l) { - this->m_delay = l; + m_delay = l; return this; } +void TickNextTickData::setPriorityTilt(int priorityTilt) +{ + this->priorityTilt = priorityTilt; +} + int TickNextTickData::compareTo(const TickNextTickData *tnd) const { if (m_delay < tnd->m_delay) return -1; if (m_delay > tnd->m_delay) return 1; + if (priorityTilt != tnd->priorityTilt) return priorityTilt - tnd->priorityTilt; if (c < tnd->c) return -1; if (c > tnd->c) return 1; return 0; } +bool TickNextTickData::operator==(const TickNextTickData &k) +{ + return equals( &k ); +} + //A class that takes two arguments of the same type as the container elements and returns a bool. //The expression comp(a,b), where comp is an object of this comparison class and a and b are elements of the container, //shall return true if a is to be placed at an earlier position than b in a strict weak ordering operation. @@ -65,5 +77,5 @@ int TickNextTickData::hash_fnct(const TickNextTickData &k) bool TickNextTickData::eq_test(const TickNextTickData &x, const TickNextTickData &y) { - return ( x.x == y.x ) && ( x.y == y.y ) && ( x.z == y.z ) && ( x.tileId == y.tileId ); + return x.equals(&y); } \ No newline at end of file diff --git a/Minecraft.World/TickNextTickData.h b/Minecraft.World/TickNextTickData.h index c83f6993..04d9ed5e 100644 --- a/Minecraft.World/TickNextTickData.h +++ b/Minecraft.World/TickNextTickData.h @@ -12,7 +12,8 @@ private: public: int x, y, z, tileId; - int64_t m_delay; + __int64 m_delay; + int priorityTilt; private: int64_t c; @@ -20,14 +21,16 @@ private: public: TickNextTickData(int x, int y, int z, int tileId); - bool equals(const void *o) const; + bool equals(const TickNextTickData *o) const; int hashCode() const; - TickNextTickData *delay(int64_t l); + TickNextTickData *delay(__int64 l); + void setPriorityTilt(int priorityTilt); int compareTo(const TickNextTickData *tnd) const; static bool compare_fnct(const TickNextTickData &x, const TickNextTickData &y); static int hash_fnct(const TickNextTickData &k); static bool eq_test(const TickNextTickData &x, const TickNextTickData &y); + bool operator==(const TickNextTickData &k); }; struct TickNextTickDataKeyHash diff --git a/Minecraft.World/Tile.cpp b/Minecraft.World/Tile.cpp index e0ef8dd9..df4e407e 100644 --- a/Minecraft.World/Tile.cpp +++ b/Minecraft.World/Tile.cpp @@ -10,6 +10,7 @@ #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.tile.entity.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.food.h" #include "net.minecraft.world.h" @@ -43,10 +44,10 @@ bool Tile::propagate[TILE_NUM_COUNT]; Tile **Tile::tiles = NULL; -Tile *Tile::rock = NULL; +Tile *Tile::stone = NULL; GrassTile *Tile::grass = NULL; Tile *Tile::dirt = NULL; -Tile *Tile::stoneBrick = NULL; +Tile *Tile::cobblestone = NULL; Tile *Tile::wood = NULL; Tile *Tile::sapling = NULL; Tile *Tile::unbreakable = NULL; @@ -67,7 +68,7 @@ Tile *Tile::lapisOre = NULL; Tile *Tile::lapisBlock = NULL; Tile *Tile::dispenser = NULL; Tile *Tile::sandStone = NULL; -Tile *Tile::musicBlock = NULL; +Tile *Tile::noteblock = NULL; Tile *Tile::bed = NULL; Tile *Tile::goldenRail = NULL; Tile *Tile::detectorRail = NULL; @@ -77,12 +78,12 @@ TallGrass *Tile::tallgrass = NULL; DeadBushTile *Tile::deadBush = NULL; PistonBaseTile *Tile::pistonBase = NULL; PistonExtensionTile *Tile::pistonExtension = NULL; -Tile *Tile::cloth = NULL; +Tile *Tile::wool = NULL; PistonMovingPiece *Tile::pistonMovingPiece = NULL; Bush *Tile::flower = NULL; Bush *Tile::rose = NULL; -Bush *Tile::mushroom1 = NULL; -Bush *Tile::mushroom2 = NULL; +Bush *Tile::mushroom_brown = NULL; +Bush *Tile::mushroom_red = NULL; Tile *Tile::goldBlock = NULL; Tile *Tile::ironBlock = NULL; HalfSlabTile *Tile::stoneSlab = NULL; @@ -90,7 +91,7 @@ HalfSlabTile *Tile::stoneSlabHalf = NULL; Tile *Tile::redBrick = NULL; Tile *Tile::tnt = NULL; Tile *Tile::bookshelf = NULL; -Tile *Tile::mossStone = NULL; +Tile *Tile::mossyCobblestone = NULL; Tile *Tile::obsidian = NULL; Tile *Tile::torch = NULL; FireTile *Tile::fire = NULL; @@ -101,7 +102,7 @@ RedStoneDustTile *Tile::redStoneDust = NULL; Tile *Tile::diamondOre = NULL; Tile *Tile::diamondBlock = NULL; Tile *Tile::workBench = NULL; -Tile *Tile::crops = NULL; +Tile *Tile::wheat = NULL; Tile *Tile::farmland = NULL; Tile *Tile::furnace = NULL; Tile *Tile::furnace_lit = NULL; @@ -117,8 +118,8 @@ Tile *Tile::door_iron = NULL; Tile *Tile::pressurePlate_wood = NULL; Tile *Tile::redStoneOre = NULL; Tile *Tile::redStoneOre_lit = NULL; -Tile *Tile::notGate_off = NULL; -Tile *Tile::notGate_on = NULL; +Tile *Tile::redstoneTorch_off = NULL; +Tile *Tile::redstoneTorch_on = NULL; Tile *Tile::button = NULL; Tile *Tile::topSnow = NULL; Tile *Tile::ice = NULL; @@ -126,24 +127,24 @@ Tile *Tile::snow = NULL; Tile *Tile::cactus = NULL; Tile *Tile::clay = NULL; Tile *Tile::reeds = NULL; -Tile *Tile::recordPlayer = NULL; +Tile *Tile::jukebox = NULL; Tile *Tile::fence = NULL; Tile *Tile::pumpkin = NULL; -Tile *Tile::hellRock = NULL; -Tile *Tile::hellSand = NULL; -Tile *Tile::lightGem = NULL; +Tile *Tile::netherRack = NULL; +Tile *Tile::soulsand = NULL; +Tile *Tile::glowstone = NULL; PortalTile *Tile::portalTile = NULL; Tile *Tile::litPumpkin = NULL; Tile *Tile::cake = NULL; RepeaterTile *Tile::diode_off = NULL; RepeaterTile *Tile::diode_on = NULL; -Tile *Tile::aprilFoolsJoke = NULL; +Tile *Tile::stained_glass = NULL; Tile *Tile::trapdoor = NULL; Tile *Tile::monsterStoneEgg = NULL; -Tile *Tile::stoneBrickSmooth = NULL; -Tile *Tile::hugeMushroom1 = NULL; -Tile *Tile::hugeMushroom2 = NULL; +Tile *Tile::stoneBrick = NULL; +Tile *Tile::hugeMushroom_brown = NULL; +Tile *Tile::hugeMushroom_red = NULL; Tile *Tile::ironFence = NULL; Tile *Tile::thinGlass = NULL; Tile *Tile::melon = NULL; @@ -165,7 +166,7 @@ Tile *Tile::brewingStand = NULL; CauldronTile *Tile::cauldron = NULL; Tile *Tile::endPortalTile = NULL; Tile *Tile::endPortalFrameTile = NULL; -Tile *Tile::whiteStone = NULL; +Tile *Tile::endStone = NULL; Tile *Tile::dragonEgg = NULL; Tile *Tile::redstoneLight = NULL; Tile *Tile::redstoneLight_lit = NULL; @@ -175,7 +176,8 @@ Tile *Tile::stairs_sandstone = NULL; Tile *Tile::woodStairsDark = NULL; Tile *Tile::woodStairsBirch = NULL; Tile *Tile::woodStairsJungle = NULL; - +Tile *Tile::commandBlock = NULL; +BeaconTile *Tile::beacon = NULL; Tile *Tile::button_wood = NULL; HalfSlabTile *Tile::woodSlab = NULL; HalfSlabTile *Tile::woodSlabHalf = NULL; @@ -185,7 +187,7 @@ Tile *Tile::enderChest = NULL; TripWireSourceTile *Tile::tripWireSource = NULL; Tile *Tile::tripWire = NULL; Tile *Tile::emeraldBlock = NULL; - + Tile *Tile::cocoa = NULL; Tile *Tile::skull = NULL; @@ -195,11 +197,28 @@ Tile *Tile::flowerPot = NULL; Tile *Tile::carrots = NULL; Tile *Tile::potatoes = NULL; Tile *Tile::anvil = NULL; +Tile *Tile::chest_trap = NULL; +Tile *Tile::weightedPlate_light = NULL; +Tile *Tile::weightedPlate_heavy = NULL; +ComparatorTile *Tile::comparator_off = NULL; +ComparatorTile *Tile::comparator_on = NULL; + +DaylightDetectorTile *Tile::daylightDetector = NULL; +Tile *Tile::redstoneBlock = NULL; + Tile *Tile::netherQuartz = NULL; +HopperTile *Tile::hopper = NULL; Tile *Tile::quartzBlock = NULL; Tile *Tile::stairs_quartz = NULL; +Tile *Tile::activatorRail = NULL; +Tile *Tile::dropper = NULL; +Tile *Tile::clayHardened_colored = NULL; +Tile *Tile::stained_glass_pane = NULL; +Tile *Tile::hayBlock = NULL; Tile *Tile::woolCarpet = NULL; +Tile *Tile::clayHardened = NULL; +Tile *Tile::coalBlock = NULL; DWORD Tile::tlsIdxShape = TlsAlloc(); @@ -239,216 +258,219 @@ void Tile::staticCtor() Tile::tiles = new Tile *[TILE_NUM_COUNT]; memset( tiles, 0, sizeof( Tile *)*TILE_NUM_COUNT ); - Tile::rail = (new RailTile(66, false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_rail, Item::eMaterial_iron)->setDestroyTime(0.7f)->setSoundType(Tile::SOUND_METAL)->setTextureName(L"rail")->setDescriptionId(IDS_TILE_RAIL)->sendTileData()->setUseDescriptionId(IDS_DESC_RAIL)->disableMipmap(); - Tile::goldenRail = (new RailTile(27, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_rail, Item::eMaterial_gold)->setDestroyTime(0.7f)->setSoundType(Tile::SOUND_METAL)->setTextureName(L"goldenRail")->setDescriptionId(IDS_TILE_GOLDEN_RAIL)->sendTileData()->setUseDescriptionId(IDS_DESC_POWEREDRAIL)->disableMipmap(); - Tile::detectorRail = (new DetectorRailTile(28)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_rail, Item::eMaterial_detector)->setDestroyTime(0.7f)->setSoundType(Tile::SOUND_METAL)->setTextureName(L"detectorRail")->setDescriptionId(IDS_TILE_DETECTOR_RAIL)->sendTileData()->setUseDescriptionId(IDS_DESC_DETECTORRAIL)->disableMipmap(); - - Tile::goldBlock = (new MetalTile(41)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_gold)->setDestroyTime(3.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_METAL)->setTextureName(L"blockGold")->setDescriptionId(IDS_TILE_BLOCK_GOLD)->setUseDescriptionId(IDS_DESC_BLOCK_GOLD); - Tile::ironBlock = (new MetalTile(42)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_iron)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_METAL)->setTextureName(L"blockIron")->setDescriptionId(IDS_TILE_BLOCK_IRON)->setUseDescriptionId(IDS_DESC_BLOCK_IRON); - Tile::lapisBlock = (new Tile(22, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_lapis)->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"blockLapis")->setDescriptionId(IDS_TILE_BLOCK_LAPIS)->setUseDescriptionId(IDS_DESC_BLOCK_LAPIS); - Tile::musicBlock = (new MusicTile(25)) ->setDestroyTime(0.8f)->setTextureName(L"musicBlock")->setDescriptionId(IDS_TILE_MUSIC_BLOCK)->sendTileData()->setUseDescriptionId(IDS_DESC_NOTEBLOCK); - Tile::diamondBlock = (new MetalTile(57)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_diamond)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_METAL)->setTextureName(L"blockDiamond")->setDescriptionId(IDS_TILE_BLOCK_DIAMOND)->setUseDescriptionId(IDS_DESC_BLOCK_DIAMOND); - - Tile::goldOre = (new OreTile(14)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"oreGold")->setDescriptionId(IDS_TILE_ORE_GOLD)->setUseDescriptionId(IDS_DESC_ORE_GOLD); - Tile::ironOre = (new OreTile(15)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"oreIron")->setDescriptionId(IDS_TILE_ORE_IRON)->setUseDescriptionId(IDS_DESC_ORE_IRON); - Tile::coalOre = (new OreTile(16)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"oreCoal")->setDescriptionId(IDS_TILE_ORE_COAL)->setUseDescriptionId(IDS_DESC_ORE_COAL); - Tile::lapisOre = (new OreTile(21)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"oreLapis")->setDescriptionId(IDS_TILE_ORE_LAPIS)->setUseDescriptionId(IDS_DESC_ORE_LAPIS); - Tile::diamondOre = (new OreTile(56)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"oreDiamond")->setDescriptionId(IDS_TILE_ORE_DIAMOND)->setUseDescriptionId(IDS_DESC_ORE_DIAMOND); - - - Tile::rock = (new StoneTile(1)) ->setDestroyTime(1.5f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"stone")->setDescriptionId(IDS_TILE_STONE)->setUseDescriptionId(IDS_DESC_STONE); - Tile::grass = (GrassTile *) (new GrassTile(2)) ->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"grass")->setDescriptionId(IDS_TILE_GRASS)->setUseDescriptionId(IDS_DESC_GRASS); - Tile::dirt = (new DirtTile(3)) ->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_GRAVEL)->setTextureName(L"dirt")->setDescriptionId(IDS_TILE_DIRT)->setUseDescriptionId(IDS_DESC_DIRT); - Tile::sapling = (new Sapling(6)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"sapling")->setDescriptionId(IDS_TILE_SAPLING)->sendTileData()->setUseDescriptionId(IDS_DESC_SAPLING)->disableMipmap(); - Tile::unbreakable = (new Tile(7, Material::stone)) ->setIndestructible()->setExplodeable(6000000)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"bedrock")->setDescriptionId(IDS_TILE_BEDROCK)->setNotCollectStatistics()->setUseDescriptionId(IDS_DESC_BEDROCK); - Tile::water = (LiquidTile *)(new LiquidTileDynamic(8, Material::water)) ->setDestroyTime(100.0f)->setLightBlock(3)->setTextureName(L"water")->setDescriptionId(IDS_TILE_WATER)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_WATER); - Tile::calmWater = (new LiquidTileStatic(9, Material::water))->setDestroyTime(100.0f)->setLightBlock(3)->setTextureName(L"water")->setDescriptionId(IDS_TILE_WATER)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_WATER); - Tile::lava = (LiquidTile *)(new LiquidTileDynamic(10, Material::lava)) ->setDestroyTime(00.0f)->setLightEmission(1.0f)->setLightBlock(255)->setTextureName(L"lava")->setDescriptionId(IDS_TILE_LAVA)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_LAVA); - Tile::calmLava = (new LiquidTileStatic(11, Material::lava)) ->setDestroyTime(100.0f)->setLightEmission(1.0f)->setLightBlock(255)->setTextureName(L"lava")->setDescriptionId(IDS_TILE_LAVA)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_LAVA); - Tile::sand = (new HeavyTile(12)) ->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_SAND)->setTextureName(L"sand")->setDescriptionId(IDS_TILE_SAND)->setUseDescriptionId(IDS_DESC_SAND); - Tile::gravel = (new GravelTile(13)) ->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRAVEL)->setTextureName(L"gravel")->setDescriptionId(IDS_TILE_GRAVEL)->setUseDescriptionId(IDS_DESC_GRAVEL); - Tile::treeTrunk = (new TreeTile(17))->setDestroyTime(2.0f) ->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"log")->setDescriptionId(IDS_TILE_LOG)->sendTileData()->setUseDescriptionId(IDS_DESC_LOG); + Tile::stone = (new StoneTile(1)) ->setDestroyTime(1.5f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setIconName(L"stone")->setDescriptionId(IDS_TILE_STONE)->setUseDescriptionId(IDS_DESC_STONE); + Tile::grass = (GrassTile *) (new GrassTile(2)) ->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"grass")->setDescriptionId(IDS_TILE_GRASS)->setUseDescriptionId(IDS_DESC_GRASS); + Tile::dirt = (new DirtTile(3)) ->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_GRAVEL)->setIconName(L"dirt")->setDescriptionId(IDS_TILE_DIRT)->setUseDescriptionId(IDS_DESC_DIRT); + Tile::cobblestone = (new Tile(4, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_stone)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setIconName(L"cobblestone")->setDescriptionId(IDS_TILE_STONE_BRICK)->setUseDescriptionId(IDS_DESC_STONE_BRICK); + Tile::wood = (new WoodTile(5)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structwoodstuff, Item::eMaterial_wood)->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"planks")->setDescriptionId(IDS_TILE_OAKWOOD_PLANKS)->sendTileData()->setUseDescriptionId(IDS_DESC_WOODENPLANKS); + Tile::sapling = (new Sapling(6)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"sapling")->setDescriptionId(IDS_TILE_SAPLING)->sendTileData()->setUseDescriptionId(IDS_DESC_SAPLING)->disableMipmap(); + Tile::unbreakable = (new Tile(7, Material::stone)) ->setIndestructible()->setExplodeable(6000000)->setSoundType(Tile::SOUND_STONE)->setIconName(L"bedrock")->setDescriptionId(IDS_TILE_BEDROCK)->setNotCollectStatistics()->setUseDescriptionId(IDS_DESC_BEDROCK); + Tile::water = (LiquidTile *)(new LiquidTileDynamic(8, Material::water)) ->setDestroyTime(100.0f)->setLightBlock(3)->setIconName(L"water_flow")->setDescriptionId(IDS_TILE_WATER)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_WATER); + Tile::calmWater = (new LiquidTileStatic(9, Material::water)) ->setDestroyTime(100.0f)->setLightBlock(3)->setIconName(L"water_still")->setDescriptionId(IDS_TILE_WATER)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_WATER); + Tile::lava = (LiquidTile *)(new LiquidTileDynamic(10, Material::lava)) ->setDestroyTime(00.0f)->setLightEmission(1.0f)->setLightBlock(255)->setIconName(L"lava_flow")->setDescriptionId(IDS_TILE_LAVA)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_LAVA); + + Tile::calmLava = (new LiquidTileStatic(11, Material::lava)) ->setDestroyTime(100.0f)->setLightEmission(1.0f)->setLightBlock(255)->setIconName(L"lava_still")->setDescriptionId(IDS_TILE_LAVA)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_LAVA); + Tile::sand = (new HeavyTile(12)) ->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_SAND)->setIconName(L"sand")->setDescriptionId(IDS_TILE_SAND)->setUseDescriptionId(IDS_DESC_SAND); + Tile::gravel = (new GravelTile(13)) ->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRAVEL)->setIconName(L"gravel")->setDescriptionId(IDS_TILE_GRAVEL)->setUseDescriptionId(IDS_DESC_GRAVEL); + Tile::goldOre = (new OreTile(14)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setIconName(L"gold_ore")->setDescriptionId(IDS_TILE_ORE_GOLD)->setUseDescriptionId(IDS_DESC_ORE_GOLD); + Tile::ironOre = (new OreTile(15)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setIconName(L"iron_ore")->setDescriptionId(IDS_TILE_ORE_IRON)->setUseDescriptionId(IDS_DESC_ORE_IRON); + Tile::coalOre = (new OreTile(16)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setIconName(L"coal_ore")->setDescriptionId(IDS_TILE_ORE_COAL)->setUseDescriptionId(IDS_DESC_ORE_COAL); + Tile::treeTrunk = (new TreeTile(17))->setDestroyTime(2.0f) ->setSoundType(Tile::SOUND_WOOD)->setIconName(L"log")->setDescriptionId(IDS_TILE_LOG)->sendTileData()->setUseDescriptionId(IDS_DESC_LOG); // 4J - for leaves, have specified that only the data bits that encode the type of leaf are important to be sent - Tile::leaves = (LeafTile *)(new LeafTile(18)) ->setDestroyTime(0.2f)->setLightBlock(1)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"leaves")->setDescriptionId(IDS_TILE_LEAVES)->sendTileData(LeafTile::LEAF_TYPE_MASK)->setUseDescriptionId(IDS_DESC_LEAVES); - Tile::sponge = (new Sponge(19)) ->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"sponge")->setDescriptionId(IDS_TILE_SPONGE)->setUseDescriptionId(IDS_DESC_SPONGE); - Tile::glass = (new GlassTile(20, Material::glass, false)) ->setDestroyTime(0.3f)->setSoundType(Tile::SOUND_GLASS)->setTextureName(L"glass")->setDescriptionId(IDS_TILE_GLASS)->setUseDescriptionId(IDS_DESC_GLASS); - Tile::dispenser = (new DispenserTile(23)) ->setDestroyTime(3.5f)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"dispenser")->setDescriptionId(IDS_TILE_DISPENSER)->sendTileData()->setUseDescriptionId(IDS_DESC_DISPENSER); - - //Tile::wood = (new Tile(5, 4, Material::wood)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structwoodstuff, Item::eMaterial_wood)->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_WOOD)->setDescriptionId(IDS_TILE_WOOD)->sendTileData()->setUseDescriptionId(IDS_DESC_WOODENPLANKS); - Tile::wood = (new WoodTile(5)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structwoodstuff, Item::eMaterial_wood)->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"wood")->setDescriptionId(IDS_TILE_OAKWOOD_PLANKS)->sendTileData()->setUseDescriptionId(IDS_DESC_WOODENPLANKS); - Tile::sandStone = (new SandStoneTile(24)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_sand)->setSoundType(Tile::SOUND_STONE)->setDestroyTime(0.8f)->sendTileData()->setTextureName(L"sandStone")->setDescriptionId(IDS_TILE_SANDSTONE)->setUseDescriptionId(IDS_DESC_SANDSTONE)->sendTileData(); - Tile::stoneBrick = (new Tile(4, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_stone)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"stonebrick")->setDescriptionId(IDS_TILE_STONE_BRICK)->setUseDescriptionId(IDS_DESC_STONE_BRICK); - Tile::redBrick = (new Tile(45, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_brick)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"brick")->setDescriptionId(IDS_TILE_BRICK)->setUseDescriptionId(IDS_DESC_BRICK); - Tile::clay = (new ClayTile(82)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_clay)->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRAVEL)->setTextureName(L"clay")->setDescriptionId(IDS_TILE_CLAY)->setUseDescriptionId(IDS_DESC_CLAY_TILE); - Tile::snow = (new SnowTile(80)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_snow)->setDestroyTime(0.2f)->setSoundType(Tile::SOUND_CLOTH)->setTextureName(L"snow")->setDescriptionId(IDS_TILE_SNOW)->setUseDescriptionId(IDS_DESC_SNOW); - - Tile::torch = (new TorchTile(50)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_torch, Item::eMaterial_wood)->setDestroyTime(0.0f)->setLightEmission(15 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"torch")->setDescriptionId(IDS_TILE_TORCH)->sendTileData()->setUseDescriptionId(IDS_DESC_TORCH)->disableMipmap(); - Tile::litPumpkin = (new PumpkinTile(91, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_torch, Item::eMaterial_pumpkin)->setDestroyTime(1.0f)->setSoundType(Tile::SOUND_WOOD)->setLightEmission(1.0f)->setTextureName(L"litpumpkin")->setDescriptionId(IDS_TILE_LIT_PUMPKIN)->sendTileData()->setUseDescriptionId(IDS_DESC_JACKOLANTERN); - Tile::lightGem = (new LightGemTile(89, Material::glass)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_torch, Item::eMaterial_glowstone)->setDestroyTime(0.3f)->setSoundType(Tile::SOUND_GLASS)->setLightEmission(1.0f)->setTextureName(L"lightgem")->setDescriptionId(IDS_TILE_LIGHT_GEM)->setUseDescriptionId(IDS_DESC_GLOWSTONE); - - Tile::trapdoor = (new TrapDoorTile(96, Material::wood)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_door, Item::eMaterial_trap)->setDestroyTime(3.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"trapdoor")->setDescriptionId(IDS_TILE_TRAPDOOR)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_TRAPDOOR); - - Tile::bed = (new BedTile(26)) ->setDestroyTime(0.2f)->setTextureName(L"bed")->setDescriptionId(IDS_TILE_BED)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_BED); - Tile::pistonStickyBase = (PistonBaseTile *)(new PistonBaseTile(29, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_piston, Item::eMaterial_stickypiston)->setTextureName(L"pistonStickyBase")->setDescriptionId(IDS_TILE_PISTON_STICK_BASE)->setUseDescriptionId(IDS_DESC_STICKY_PISTON)->sendTileData(); - Tile::web = (new WebTile(30)) ->setLightBlock(1)->setDestroyTime(4.0f)->setTextureName(L"web")->setDescriptionId(IDS_TILE_WEB)->setUseDescriptionId(IDS_DESC_WEB); - Tile::tallgrass = (TallGrass *)(new TallGrass(31)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"tallgrass")->setDescriptionId(IDS_TILE_TALL_GRASS)->setUseDescriptionId(IDS_DESC_TALL_GRASS)->disableMipmap(); - Tile::deadBush = (DeadBushTile *)(new DeadBushTile(32)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"deadbush")->setDescriptionId(IDS_TILE_DEAD_BUSH)->setUseDescriptionId(IDS_DESC_DEAD_BUSH)->disableMipmap(); - Tile::pistonBase = (PistonBaseTile *)(new PistonBaseTile(33,false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_piston, Item::eMaterial_piston)->setTextureName(L"pistonBase")->setDescriptionId(IDS_TILE_PISTON_BASE)->setUseDescriptionId(IDS_DESC_PISTON)->sendTileData(); - Tile::pistonExtension = (PistonExtensionTile *)(new PistonExtensionTile(34)) ->setDescriptionId(IDS_TILE_PISTON_BASE)->setUseDescriptionId(-1)->sendTileData(); - - Tile::cloth = (new ClothTile()) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_cloth, Item::eMaterial_cloth)->setDestroyTime(0.8f)->setSoundType(Tile::SOUND_CLOTH)->setTextureName(L"cloth")->setDescriptionId(IDS_TILE_CLOTH)->sendTileData()->setUseDescriptionId(IDS_DESC_WOOL); + Tile::leaves = (LeafTile *)(new LeafTile(18)) ->setDestroyTime(0.2f)->setLightBlock(1)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"leaves")->setDescriptionId(IDS_TILE_LEAVES)->sendTileData(LeafTile::LEAF_TYPE_MASK)->setUseDescriptionId(IDS_DESC_LEAVES); + Tile::sponge = (new Sponge(19)) ->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"sponge")->setDescriptionId(IDS_TILE_SPONGE)->setUseDescriptionId(IDS_DESC_SPONGE); + Tile::glass = (new GlassTile(20, Material::glass, false)) ->setDestroyTime(0.3f)->setSoundType(Tile::SOUND_GLASS)->setIconName(L"glass")->setDescriptionId(IDS_TILE_GLASS)->setUseDescriptionId(IDS_DESC_GLASS); + + Tile::lapisOre = (new OreTile(21)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setIconName(L"lapis_ore")->setDescriptionId(IDS_TILE_ORE_LAPIS)->setUseDescriptionId(IDS_DESC_ORE_LAPIS); + Tile::lapisBlock = (new Tile(22, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_lapis)->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setIconName(L"lapis_block")->setDescriptionId(IDS_TILE_BLOCK_LAPIS)->setUseDescriptionId(IDS_DESC_BLOCK_LAPIS); + Tile::dispenser = (new DispenserTile(23)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_redstoneContainer, Item::eMaterial_undefined)->setDestroyTime(3.5f)->setSoundType(Tile::SOUND_STONE)->setIconName(L"dispenser")->setDescriptionId(IDS_TILE_DISPENSER)->sendTileData()->setUseDescriptionId(IDS_DESC_DISPENSER); + Tile::sandStone = (new SandStoneTile(24)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_sand)->setSoundType(Tile::SOUND_STONE)->setDestroyTime(0.8f)->sendTileData()->setIconName(L"sandstone")->setDescriptionId(IDS_TILE_SANDSTONE)->setUseDescriptionId(IDS_DESC_SANDSTONE)->sendTileData(); + Tile::noteblock = (new NoteBlockTile(25)) ->setDestroyTime(0.8f)->setIconName(L"noteblock")->setDescriptionId(IDS_TILE_MUSIC_BLOCK)->sendTileData()->setUseDescriptionId(IDS_DESC_NOTEBLOCK); + Tile::bed = (new BedTile(26)) ->setDestroyTime(0.2f)->setIconName(L"bed")->setDescriptionId(IDS_TILE_BED)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_BED); + Tile::goldenRail = (new PoweredRailTile(27)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_rail, Item::eMaterial_gold)->setDestroyTime(0.7f)->setSoundType(Tile::SOUND_METAL)->setIconName(L"rail_golden")->setDescriptionId(IDS_TILE_GOLDEN_RAIL)->sendTileData()->setUseDescriptionId(IDS_DESC_POWEREDRAIL)->disableMipmap(); + Tile::detectorRail = (new DetectorRailTile(28)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_rail, Item::eMaterial_detector)->setDestroyTime(0.7f)->setSoundType(Tile::SOUND_METAL)->setIconName(L"rail_detector")->setDescriptionId(IDS_TILE_DETECTOR_RAIL)->sendTileData()->setUseDescriptionId(IDS_DESC_DETECTORRAIL)->disableMipmap(); + Tile::pistonStickyBase = (PistonBaseTile *)(new PistonBaseTile(29, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_piston, Item::eMaterial_stickypiston)->setIconName(L"pistonStickyBase")->setDescriptionId(IDS_TILE_PISTON_STICK_BASE)->setUseDescriptionId(IDS_DESC_STICKY_PISTON)->sendTileData(); + Tile::web = (new WebTile(30)) ->setLightBlock(1)->setDestroyTime(4.0f)->setIconName(L"web")->setDescriptionId(IDS_TILE_WEB)->setUseDescriptionId(IDS_DESC_WEB); + + Tile::tallgrass = (TallGrass *)(new TallGrass(31)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"tallgrass")->setDescriptionId(IDS_TILE_TALL_GRASS)->setUseDescriptionId(IDS_DESC_TALL_GRASS)->disableMipmap(); + Tile::deadBush = (DeadBushTile *)(new DeadBushTile(32)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"deadbush")->setDescriptionId(IDS_TILE_DEAD_BUSH)->setUseDescriptionId(IDS_DESC_DEAD_BUSH)->disableMipmap(); + Tile::pistonBase = (PistonBaseTile *)(new PistonBaseTile(33,false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_piston, Item::eMaterial_piston)->setIconName(L"pistonBase")->setDescriptionId(IDS_TILE_PISTON_BASE)->setUseDescriptionId(IDS_DESC_PISTON)->sendTileData(); + Tile::pistonExtension = (PistonExtensionTile *)(new PistonExtensionTile(34))->setDescriptionId(IDS_TILE_PISTON_BASE)->setUseDescriptionId(-1)->sendTileData(); + Tile::wool = (new ColoredTile(35, Material::cloth)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_cloth, Item::eMaterial_cloth)->setDestroyTime(0.8f)->setSoundType(Tile::SOUND_CLOTH)->setIconName(L"wool_colored")->setDescriptionId(IDS_TILE_CLOTH)->sendTileData()->setUseDescriptionId(IDS_DESC_WOOL); Tile::pistonMovingPiece = (PistonMovingPiece *)(new PistonMovingPiece(36)) ->setDescriptionId(IDS_TILE_PISTON_BASE)->setUseDescriptionId(-1); + Tile::flower = (Bush *) (new Bush(37)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"flower_dandelion")->setDescriptionId(IDS_TILE_FLOWER)->setUseDescriptionId(IDS_DESC_FLOWER)->disableMipmap(); + Tile::rose = (Bush *) (new Bush(38)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"flower_rose")->setDescriptionId(IDS_TILE_ROSE)->setUseDescriptionId(IDS_DESC_FLOWER)->disableMipmap(); + Tile::mushroom_brown = (Bush *) (new Mushroom(39)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setLightEmission(2 / 16.0f)->setIconName(L"mushroom_brown")->setDescriptionId(IDS_TILE_MUSHROOM)->setUseDescriptionId(IDS_DESC_MUSHROOM)->disableMipmap(); + Tile::mushroom_red = (Bush *) (new Mushroom(40)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"mushroom_red")->setDescriptionId(IDS_TILE_MUSHROOM)->setUseDescriptionId(IDS_DESC_MUSHROOM)->disableMipmap(); + + Tile::goldBlock = (new MetalTile(41)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_gold)->setDestroyTime(3.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_METAL)->setIconName(L"gold_block")->setDescriptionId(IDS_TILE_BLOCK_GOLD)->setUseDescriptionId(IDS_DESC_BLOCK_GOLD); + Tile::ironBlock = (new MetalTile(42)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_iron)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_METAL)->setIconName(L"iron_block")->setDescriptionId(IDS_TILE_BLOCK_IRON)->setUseDescriptionId(IDS_DESC_BLOCK_IRON); + Tile::stoneSlab = (HalfSlabTile *) (new StoneSlabTile(Tile::stoneSlab_Id, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_slab, Item::eMaterial_stone)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setIconName(L"stoneSlab")->setDescriptionId(IDS_TILE_STONESLAB)->setUseDescriptionId(IDS_DESC_SLAB); + Tile::stoneSlabHalf = (HalfSlabTile *) (new StoneSlabTile(Tile::stoneSlabHalf_Id, false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_halfslab, Item::eMaterial_stone)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setIconName(L"stoneSlab")->setDescriptionId(IDS_TILE_STONESLAB)->setUseDescriptionId(IDS_DESC_HALFSLAB); + Tile::redBrick = (new Tile(45, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_brick)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setIconName(L"brick")->setDescriptionId(IDS_TILE_BRICK)->setUseDescriptionId(IDS_DESC_BRICK); + Tile::tnt = (new TntTile(46)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"tnt")->setDescriptionId(IDS_TILE_TNT)->setUseDescriptionId(IDS_DESC_TNT); + Tile::bookshelf = (new BookshelfTile(47)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_paper, Item::eMaterial_bookshelf)->setDestroyTime(1.5f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"bookshelf")->setDescriptionId(IDS_TILE_BOOKSHELF)->setUseDescriptionId(IDS_DESC_BOOKSHELF); + Tile::mossyCobblestone = (new Tile(48, Material::stone)) ->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setIconName(L"cobblestone_mossy")->setDescriptionId(IDS_TILE_STONE_MOSS)->setUseDescriptionId(IDS_DESC_MOSS_STONE); + Tile::obsidian = (new ObsidianTile(49)) ->setDestroyTime(50.0f)->setExplodeable(2000)->setSoundType(Tile::SOUND_STONE)->setIconName(L"obsidian")->setDescriptionId(IDS_TILE_OBSIDIAN)->setUseDescriptionId(IDS_DESC_OBSIDIAN); + Tile::torch = (new TorchTile(50)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_torch, Item::eMaterial_wood)->setDestroyTime(0.0f)->setLightEmission(15 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"torch_on")->setDescriptionId(IDS_TILE_TORCH)->setUseDescriptionId(IDS_DESC_TORCH)->disableMipmap(); + + Tile::fire = (FireTile *) ((new FireTile(51)) ->setDestroyTime(0.0f)->setLightEmission(1.0f)->setSoundType(Tile::SOUND_WOOD))->setIconName(L"fire")->setDescriptionId(IDS_TILE_FIRE)->setNotCollectStatistics()->setUseDescriptionId(-1); + Tile::mobSpawner = (new MobSpawnerTile(52)) ->setDestroyTime(5.0f)->setSoundType(Tile::SOUND_METAL)->setIconName(L"mob_spawner")->setDescriptionId(IDS_TILE_MOB_SPAWNER)->setNotCollectStatistics()->setUseDescriptionId(IDS_DESC_MOB_SPAWNER); + Tile::stairs_wood = (new StairTile(53, Tile::wood,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_wood) ->setIconName(L"stairsWood")->setDescriptionId(IDS_TILE_STAIRS_WOOD) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::chest = (ChestTile *)(new ChestTile(54, ChestTile::TYPE_BASIC)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_chest, Item::eMaterial_wood)->setDestroyTime(2.5f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"chest")->setDescriptionId(IDS_TILE_CHEST)->sendTileData()->setUseDescriptionId(IDS_DESC_CHEST); + Tile::redStoneDust = (RedStoneDustTile *)(new RedStoneDustTile(55)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_NORMAL)->setIconName(L"redstone_dust")->setDescriptionId(IDS_TILE_REDSTONE_DUST)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONE_DUST); + Tile::diamondOre = (new OreTile(56)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setIconName(L"diamond_ore")->setDescriptionId(IDS_TILE_ORE_DIAMOND)->setUseDescriptionId(IDS_DESC_ORE_DIAMOND); + Tile::diamondBlock = (new MetalTile(57)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_diamond)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_METAL)->setIconName(L"diamond_block")->setDescriptionId(IDS_TILE_BLOCK_DIAMOND)->setUseDescriptionId(IDS_DESC_BLOCK_DIAMOND); + Tile::workBench = (new WorkbenchTile(58)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_wood)->setDestroyTime(2.5f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"crafting_table")->setDescriptionId(IDS_TILE_WORKBENCH)->setUseDescriptionId(IDS_DESC_CRAFTINGTABLE); + Tile::wheat = (new CropTile(59)) ->setIconName(L"wheat")->setDescriptionId(IDS_TILE_CROPS)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_CROPS)->disableMipmap(); + Tile::farmland = (new FarmTile(60)) ->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRAVEL)->setIconName(L"farmland")->setDescriptionId(IDS_TILE_FARMLAND)->setUseDescriptionId(IDS_DESC_FARMLAND)->sendTileData(); + + Tile::furnace = (new FurnaceTile(61, false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_stone)->setDestroyTime(3.5f)->setSoundType(Tile::SOUND_STONE)->setIconName(L"furnace")->setDescriptionId(IDS_TILE_FURNACE)->sendTileData()->setUseDescriptionId(IDS_DESC_FURNACE); + Tile::furnace_lit = (new FurnaceTile(62, true)) ->setDestroyTime(3.5f)->setSoundType(Tile::SOUND_STONE)->setLightEmission(14 / 16.0f)->setIconName(L"furnace")->setDescriptionId(IDS_TILE_FURNACE)->sendTileData()->setUseDescriptionId(IDS_DESC_FURNACE); + Tile::sign = (new SignTile(63, eTYPE_SIGNTILEENTITY, true)) ->setDestroyTime(1.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"sign")->setDescriptionId(IDS_TILE_SIGN)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_SIGN); + Tile::door_wood = (new DoorTile(64, Material::wood)) ->setDestroyTime(3.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"door_wood")->setDescriptionId(IDS_TILE_DOOR_WOOD)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_DOOR_WOOD); + Tile::ladder = (new LadderTile(65)) ->setDestroyTime(0.4f)->setSoundType(Tile::SOUND_LADDER)->setIconName(L"ladder")->setDescriptionId(IDS_TILE_LADDER)->sendTileData()->setUseDescriptionId(IDS_DESC_LADDER)->disableMipmap(); + Tile::rail = (new RailTile(66)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_rail, Item::eMaterial_iron)->setDestroyTime(0.7f)->setSoundType(Tile::SOUND_METAL)->setIconName(L"rail_normal")->setDescriptionId(IDS_TILE_RAIL)->sendTileData()->setUseDescriptionId(IDS_DESC_RAIL)->disableMipmap(); + Tile::stairs_stone =(new StairTile(67, Tile::cobblestone,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_stone) ->setIconName(L"stairsStone")->setDescriptionId(IDS_TILE_STAIRS_STONE) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::wallSign = (new SignTile(68, eTYPE_SIGNTILEENTITY, false)) ->setDestroyTime(1.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"sign")->setDescriptionId(IDS_TILE_SIGN)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_SIGN); + Tile::lever = (new LeverTile(69)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_lever, Item::eMaterial_wood)->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"lever")->setDescriptionId(IDS_TILE_LEVER)->sendTileData()->setUseDescriptionId(IDS_DESC_LEVER); + Tile::pressurePlate_stone = (Tile *)(new PressurePlateTile(70, L"stone", Material::stone, PressurePlateTile::mobs)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_pressureplate, Item::eMaterial_stone)->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_STONE)->setDescriptionId(IDS_TILE_PRESSURE_PLATE)->sendTileData()->setUseDescriptionId(IDS_DESC_PRESSUREPLATE); + + Tile::door_iron = (new DoorTile(71, Material::metal)) ->setDestroyTime(5.0f)->setSoundType(Tile::SOUND_METAL)->setIconName(L"door_iron")->setDescriptionId(IDS_TILE_DOOR_IRON)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_DOOR_IRON); + Tile::pressurePlate_wood = (new PressurePlateTile(72, L"planks_oak", Material::wood, PressurePlateTile::everything)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_pressureplate, Item::eMaterial_wood)->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_WOOD)->setDescriptionId(IDS_TILE_PRESSURE_PLATE)->sendTileData()->setUseDescriptionId(IDS_DESC_PRESSUREPLATE); + Tile::redStoneOre = (new RedStoneOreTile(73,false)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setIconName(L"redstone_ore")->setDescriptionId(IDS_TILE_ORE_REDSTONE)->sendTileData()->setUseDescriptionId(IDS_DESC_ORE_REDSTONE); + Tile::redStoneOre_lit = (new RedStoneOreTile(74, true)) ->setLightEmission(10 / 16.0f)->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setIconName(L"redstone_ore")->setDescriptionId(IDS_TILE_ORE_REDSTONE)->sendTileData()->setUseDescriptionId(IDS_DESC_ORE_REDSTONE); + Tile::redstoneTorch_off = (new NotGateTile(75, false)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"redstone_torch_off")->setDescriptionId(IDS_TILE_NOT_GATE)->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONETORCH)->disableMipmap(); + Tile::redstoneTorch_on = (new NotGateTile(76, true)) ->setDestroyTime(0.0f)->setLightEmission(8 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"redstone_torch_on")->setDescriptionId(IDS_TILE_NOT_GATE)->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONETORCH)->disableMipmap(); + Tile::button = (new StoneButtonTile(77)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_button, Item::eMaterial_stone)->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_STONE)->setIconName(L"button")->setDescriptionId(IDS_TILE_BUTTON)->sendTileData()->setUseDescriptionId(IDS_DESC_BUTTON); + Tile::topSnow = (new TopSnowTile(78)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_snow)->setDestroyTime(0.1f)->setSoundType(Tile::SOUND_SNOW)->setIconName(L"snow")->setDescriptionId(IDS_TILE_SNOW)->setUseDescriptionId(IDS_DESC_TOP_SNOW)->sendTileData()->setLightBlock(0); + Tile::ice = (new IceTile(79)) ->setDestroyTime(0.5f)->setLightBlock(3)->setSoundType(Tile::SOUND_GLASS)->setIconName(L"ice")->setDescriptionId(IDS_TILE_ICE)->setUseDescriptionId(IDS_DESC_ICE); + Tile::snow = (new SnowTile(80)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_snow)->setDestroyTime(0.2f)->setSoundType(Tile::SOUND_CLOTH)->setIconName(L"snow")->setDescriptionId(IDS_TILE_SNOW)->setUseDescriptionId(IDS_DESC_SNOW); + + Tile::cactus = (new CactusTile(81)) ->setDestroyTime(0.4f)->setSoundType(Tile::SOUND_CLOTH)->setIconName(L"cactus")->setDescriptionId(IDS_TILE_CACTUS)->setUseDescriptionId(IDS_DESC_CACTUS)->disableMipmap(); + Tile::clay = (new ClayTile(82)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_clay)->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRAVEL)->setIconName(L"clay")->setDescriptionId(IDS_TILE_CLAY)->setUseDescriptionId(IDS_DESC_CLAY_TILE); + Tile::reeds = (new ReedTile(83)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setIconName(L"reeds")->setDescriptionId(IDS_TILE_REEDS)->setNotCollectStatistics()->setUseDescriptionId(IDS_DESC_REEDS)->disableMipmap(); + Tile::jukebox = (new JukeboxTile(84)) ->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setIconName(L"jukebox")->setDescriptionId(IDS_TILE_JUKEBOX)->sendTileData()->setUseDescriptionId(IDS_DESC_JUKEBOX); + Tile::fence = (new FenceTile(85, L"planks_oak", Material::wood)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fence, Item::eMaterial_wood)->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_WOOD)->setDescriptionId(IDS_TILE_FENCE)->setUseDescriptionId(IDS_DESC_FENCE); + Tile::pumpkin = (new PumpkinTile(86, false)) ->setDestroyTime(1.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"pumpkin")->setDescriptionId(IDS_TILE_PUMPKIN)->sendTileData()->setUseDescriptionId(IDS_DESC_PUMPKIN); + Tile::netherRack = (new NetherrackTile(87)) ->setDestroyTime(0.4f)->setSoundType(Tile::SOUND_STONE)->setIconName(L"netherrack")->setDescriptionId(IDS_TILE_HELL_ROCK)->setUseDescriptionId(IDS_DESC_HELL_ROCK); + Tile::soulsand = (new SoulSandTile(88)) ->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_SAND)->setIconName(L"soul_sand")->setDescriptionId(IDS_TILE_HELL_SAND)->setUseDescriptionId(IDS_DESC_HELL_SAND); + Tile::glowstone = (new Glowstonetile(89, Material::glass)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_torch, Item::eMaterial_glowstone)->setDestroyTime(0.3f)->setSoundType(Tile::SOUND_GLASS)->setLightEmission(1.0f)->setIconName(L"glowstone")->setDescriptionId(IDS_TILE_LIGHT_GEM)->setUseDescriptionId(IDS_DESC_GLOWSTONE); + Tile::portalTile = (PortalTile *) ((new PortalTile(90)) ->setDestroyTime(-1)->setSoundType(Tile::SOUND_GLASS)->setLightEmission(0.75f))->setIconName(L"portal")->setDescriptionId(IDS_TILE_PORTAL)->setUseDescriptionId(IDS_DESC_PORTAL); + + Tile::litPumpkin = (new PumpkinTile(91, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_torch, Item::eMaterial_pumpkin)->setDestroyTime(1.0f)->setSoundType(Tile::SOUND_WOOD)->setLightEmission(1.0f)->setIconName(L"pumpkin")->setDescriptionId(IDS_TILE_LIT_PUMPKIN)->sendTileData()->setUseDescriptionId(IDS_DESC_JACKOLANTERN); + Tile::cake = (new CakeTile(92)) ->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_CLOTH)->setIconName(L"cake")->setDescriptionId(IDS_TILE_CAKE)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_CAKE); + Tile::diode_off = (RepeaterTile *)(new RepeaterTile(93, false)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"repeater_off")->setDescriptionId(IDS_ITEM_DIODE)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONEREPEATER)->disableMipmap(); + Tile::diode_on = (RepeaterTile *)(new RepeaterTile(94, true)) ->setDestroyTime(0.0f)->setLightEmission(10 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"repeater_on")->setDescriptionId(IDS_ITEM_DIODE)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONEREPEATER)->disableMipmap(); + Tile::stained_glass = (new StainedGlassBlock(95, Material::glass))->setBaseItemTypeAndMaterial(Item::eBaseItemType_glass, Item::eMaterial_glass)->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setIconName(L"glass")->setDescriptionId(IDS_TILE_STAINED_GLASS)->setUseDescriptionId(IDS_DESC_STAINED_GLASS); + Tile::trapdoor = (new TrapDoorTile(96, Material::wood)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_door, Item::eMaterial_trap)->setDestroyTime(3.0f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"trapdoor")->setDescriptionId(IDS_TILE_TRAPDOOR)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_TRAPDOOR); + Tile::monsterStoneEgg = (new StoneMonsterTile(97)) ->setDestroyTime(0.75f)->setIconName(L"monsterStoneEgg")->setDescriptionId(IDS_TILE_STONE_SILVERFISH)->setUseDescriptionId(IDS_DESC_STONE_SILVERFISH); + Tile::stoneBrick = (new SmoothStoneBrickTile(98)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_stoneSmooth)->setDestroyTime(1.5f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setIconName(L"stonebrick")->setDescriptionId(IDS_TILE_STONE_BRICK_SMOOTH)->setUseDescriptionId(IDS_DESC_STONE_BRICK_SMOOTH); + Tile::hugeMushroom_brown = (new HugeMushroomTile(99, Material::wood, HugeMushroomTile::MUSHROOM_TYPE_BROWN)) ->setDestroyTime(0.2f)->setSoundType(SOUND_WOOD)->setIconName(L"mushroom_block")->setDescriptionId(IDS_TILE_HUGE_MUSHROOM_1)->setUseDescriptionId(IDS_DESC_MUSHROOM)->sendTileData(); + Tile::hugeMushroom_red = (new HugeMushroomTile(100, Material::wood, HugeMushroomTile::MUSHROOM_TYPE_RED)) ->setDestroyTime(0.2f)->setSoundType(SOUND_WOOD)->setIconName(L"mushroom_block")->setDescriptionId(IDS_TILE_HUGE_MUSHROOM_2)->setUseDescriptionId(IDS_DESC_MUSHROOM)->sendTileData(); + + + Tile::ironFence = (new ThinFenceTile(101, L"iron_bars", L"iron_bars", Material::metal, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fence, Item::eMaterial_iron)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setDescriptionId(IDS_TILE_IRON_FENCE)->setUseDescriptionId(IDS_DESC_IRON_FENCE); + Tile::thinGlass = (new ThinFenceTile(102, L"glass", L"glass_pane_top", Material::glass, false)) ->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setDescriptionId(IDS_TILE_THIN_GLASS)->setUseDescriptionId(IDS_DESC_THIN_GLASS); + Tile::melon = (new MelonTile(103)) ->setDestroyTime(1.0f)->setSoundType(SOUND_WOOD)->setIconName(L"melon")->setDescriptionId(IDS_TILE_MELON)->setUseDescriptionId(IDS_DESC_MELON_BLOCK); + Tile::pumpkinStem = (new StemTile(104, Tile::pumpkin)) ->setDestroyTime(0.0f)->setSoundType(SOUND_WOOD)->setIconName(L"pumpkin_stem")->setDescriptionId(IDS_TILE_PUMPKIN_STEM)->sendTileData(); + Tile::melonStem = (new StemTile(105, Tile::melon)) ->setDestroyTime(0.0f)->setSoundType(SOUND_WOOD)->setIconName(L"melon_stem")->setDescriptionId(IDS_TILE_MELON_STEM)->sendTileData(); + Tile::vine = (new VineTile(106))->setDestroyTime(0.2f) ->setSoundType(SOUND_GRASS)->setIconName(L"vine")->setDescriptionId(IDS_TILE_VINE)->setUseDescriptionId(IDS_DESC_VINE)->sendTileData(); + Tile::fenceGate = (new FenceGateTile(107)) ->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setIconName(L"fenceGate")->setDescriptionId(IDS_TILE_FENCE_GATE)->sendTileData()->setUseDescriptionId(IDS_DESC_FENCE_GATE); + Tile::stairs_bricks = (new StairTile(108, Tile::redBrick,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_brick) ->setIconName(L"stairsBrick")->setDescriptionId(IDS_TILE_STAIRS_BRICKS) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::stairs_stoneBrickSmooth = (new StairTile(109, Tile::stoneBrick,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_stoneSmooth)->setIconName(L"stairsStoneBrickSmooth")->setDescriptionId(IDS_TILE_STAIRS_STONE_BRICKS_SMOOTH) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::mycel = (MycelTile *)(new MycelTile(110)) ->setDestroyTime(0.6f)->setSoundType(SOUND_GRASS)->setIconName(L"mycelium")->setDescriptionId(IDS_TILE_MYCEL)->setUseDescriptionId(IDS_DESC_MYCEL); + + Tile::waterLily = (new WaterlilyTile(111)) ->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setIconName(L"waterlily")->setDescriptionId(IDS_TILE_WATERLILY)->setUseDescriptionId(IDS_DESC_WATERLILY); + Tile::netherBrick = (new Tile(112, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_netherbrick)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setIconName(L"nether_brick")->setDescriptionId(IDS_TILE_NETHERBRICK)->setUseDescriptionId(IDS_DESC_NETHERBRICK); + Tile::netherFence = (new FenceTile(113, L"nether_brick", Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fence, Item::eMaterial_netherbrick)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setDescriptionId(IDS_TILE_NETHERFENCE)->setUseDescriptionId(IDS_DESC_NETHERFENCE); + Tile::stairs_netherBricks = (new StairTile(114, Tile::netherBrick,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_netherbrick)->setIconName(L"stairsNetherBrick")->setDescriptionId(IDS_TILE_STAIRS_NETHERBRICK) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::netherStalk = (new NetherWartTile(115)) ->setIconName(L"nether_wart")->setDescriptionId(IDS_TILE_NETHERSTALK)->sendTileData()->setUseDescriptionId(IDS_DESC_NETHERSTALK); + Tile::enchantTable = (new EnchantmentTableTile(116)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_magic)->setDestroyTime(5.0f)->setExplodeable(2000)->setIconName(L"enchanting_table")->setDescriptionId(IDS_TILE_ENCHANTMENTTABLE)->setUseDescriptionId(IDS_DESC_ENCHANTMENTTABLE); + Tile::brewingStand = (new BrewingStandTile(117)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_blaze)->setDestroyTime(0.5f)->setLightEmission(2 / 16.0f)->setIconName(L"brewing_stand")->setDescriptionId(IDS_TILE_BREWINGSTAND)->sendTileData()->setUseDescriptionId(IDS_DESC_BREWING_STAND); + Tile::cauldron = (CauldronTile *)(new CauldronTile(118)) ->setDestroyTime(2.0f)->setIconName(L"cauldron")->setDescriptionId(IDS_TILE_CAULDRON)->sendTileData()->setUseDescriptionId(IDS_DESC_CAULDRON); + Tile::endPortalTile = (new TheEndPortal(119, Material::portal)) ->setDestroyTime(INDESTRUCTIBLE_DESTROY_TIME)->setExplodeable(6000000)->setDescriptionId(IDS_TILE_END_PORTAL)->setUseDescriptionId(IDS_DESC_END_PORTAL); + Tile::endPortalFrameTile = (new TheEndPortalFrameTile(120)) ->setSoundType(SOUND_GLASS)->setLightEmission(2 / 16.0f)->setDestroyTime(INDESTRUCTIBLE_DESTROY_TIME)->setIconName(L"endframe")->setDescriptionId(IDS_TILE_ENDPORTALFRAME)->sendTileData()->setExplodeable(6000000)->setUseDescriptionId(IDS_DESC_ENDPORTALFRAME); + + Tile::endStone = (new Tile(121, Material::stone)) ->setDestroyTime(3.0f)->setExplodeable(15)->setSoundType(SOUND_STONE)->setIconName(L"end_stone")->setDescriptionId(IDS_TILE_WHITESTONE)->setUseDescriptionId(IDS_DESC_WHITESTONE); + Tile::dragonEgg = (new EggTile(122)) ->setDestroyTime(3.0f)->setExplodeable(15)->setSoundType(SOUND_STONE)->setLightEmission(2.0f / 16.0f)->setIconName(L"dragon_egg")->setDescriptionId(IDS_TILE_DRAGONEGG)->setUseDescriptionId(IDS_DESC_DRAGONEGG); + Tile::redstoneLight = (new RedlightTile(123, false)) ->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setIconName(L"redstone_lamp_off")->setDescriptionId(IDS_TILE_REDSTONE_LIGHT)->setUseDescriptionId(IDS_DESC_REDSTONE_LIGHT); + Tile::redstoneLight_lit = (new RedlightTile(124, true)) ->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setIconName(L"redstone_lamp_on")->setDescriptionId(IDS_TILE_REDSTONE_LIGHT)->setUseDescriptionId(IDS_DESC_REDSTONE_LIGHT); + Tile::woodSlab = (HalfSlabTile *) (new WoodSlabTile(Tile::woodSlab_Id, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_slab, Item::eMaterial_wood)->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setIconName(L"woodSlab")->setDescriptionId(IDS_DESC_WOODSLAB)->setUseDescriptionId(IDS_DESC_WOODSLAB); + Tile::woodSlabHalf = (HalfSlabTile *) (new WoodSlabTile(Tile::woodSlabHalf_Id, false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_halfslab, Item::eMaterial_wood)->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setIconName(L"woodSlab")->setDescriptionId(IDS_DESC_WOODSLAB)->setUseDescriptionId(IDS_DESC_WOODSLAB); + Tile::cocoa = (new CocoaTile(127)) ->setDestroyTime(0.2f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setIconName(L"cocoa")->sendTileData()->setDescriptionId(IDS_TILE_COCOA)->setUseDescriptionId(IDS_DESC_COCOA); + Tile::stairs_sandstone = (new StairTile(128, Tile::sandStone,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_sand) ->setIconName(L"stairsSandstone")->setDescriptionId(IDS_TILE_STAIRS_SANDSTONE) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::emeraldOre = (new OreTile(129)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setIconName(L"emerald_ore")->setDescriptionId(IDS_TILE_EMERALDORE)->setUseDescriptionId(IDS_DESC_EMERALDORE); + Tile::enderChest = (new EnderChestTile(130)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_chest, Item::eMaterial_ender)->setDestroyTime(22.5f)->setExplodeable(1000)->setSoundType(SOUND_STONE)->setIconName(L"enderChest")->sendTileData()->setLightEmission(.5f)->setDescriptionId(IDS_TILE_ENDERCHEST)->setUseDescriptionId(IDS_DESC_ENDERCHEST); + + + Tile::tripWireSource = (TripWireSourceTile *)( new TripWireSourceTile(131) ) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_lever, Item::eMaterial_undefined)->setIconName(L"trip_wire_source")->sendTileData()->setDescriptionId(IDS_TILE_TRIPWIRE_SOURCE)->setUseDescriptionId(IDS_DESC_TRIPWIRE_SOURCE); + Tile::tripWire = (new TripWireTile(132)) ->setIconName(L"trip_wire")->sendTileData()->setDescriptionId(IDS_TILE_TRIPWIRE)->setUseDescriptionId(IDS_DESC_TRIPWIRE); + Tile::emeraldBlock = (new MetalTile(133)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_emerald)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setIconName(L"emerald_block")->setDescriptionId(IDS_TILE_EMERALDBLOCK)->setUseDescriptionId(IDS_DESC_EMERALDBLOCK); + Tile::woodStairsDark = (new StairTile(134, Tile::wood, TreeTile::DARK_TRUNK)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_sprucewood)->setIconName(L"stairsWoodSpruce")->setDescriptionId(IDS_TILE_STAIRS_SPRUCEWOOD) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::woodStairsBirch = (new StairTile(135, Tile::wood, TreeTile::BIRCH_TRUNK)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_birchwood)->setIconName(L"stairsWoodBirch")->setDescriptionId(IDS_TILE_STAIRS_BIRCHWOOD) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::woodStairsJungle =(new StairTile(136, Tile::wood, TreeTile::JUNGLE_TRUNK))->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_junglewood)->setIconName(L"stairsWoodJungle")->setDescriptionId(IDS_TILE_STAIRS_JUNGLEWOOD) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::commandBlock = (new CommandBlock(137)) ->setIndestructible()->setExplodeable(6000000)->setIconName(L"command_block")->setDescriptionId(IDS_TILE_COMMAND_BLOCK)->setUseDescriptionId(IDS_DESC_COMMAND_BLOCK); + Tile::beacon = (BeaconTile *) (new BeaconTile(138)) ->setLightEmission(1.0f)->setIconName(L"beacon")->setDescriptionId(IDS_TILE_BEACON)->setUseDescriptionId(IDS_DESC_BEACON); + Tile::cobbleWall = (new WallTile(139, Tile::stoneBrick)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fence, Item::eMaterial_stone)->setIconName(L"cobbleWall")->setDescriptionId(IDS_TILE_COBBLESTONE_WALL)->setUseDescriptionId(IDS_DESC_COBBLESTONE_WALL); + Tile::flowerPot = (new FlowerPotTile(140)) ->setDestroyTime(0.0f)->setSoundType(SOUND_NORMAL)->setIconName(L"flower_pot")->setDescriptionId(IDS_TILE_FLOWERPOT)->setUseDescriptionId(IDS_DESC_FLOWERPOT); + + Tile::carrots = (new CarrotTile(141)) ->setIconName(L"carrots")->setDescriptionId(IDS_TILE_CARROTS)->setUseDescriptionId(IDS_DESC_CARROTS)->disableMipmap(); + Tile::potatoes = (new PotatoTile(142)) ->setIconName(L"potatoes")->setDescriptionId(IDS_TILE_POTATOES)->setUseDescriptionId(IDS_DESC_POTATO)->disableMipmap(); + Tile::button_wood = (new WoodButtonTile(143)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_button, Item::eMaterial_wood)->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_WOOD)->setIconName(L"button")->setDescriptionId(IDS_TILE_BUTTON)->sendTileData()->setUseDescriptionId(IDS_DESC_BUTTON); + Tile::skull = (new SkullTile(144)) ->setDestroyTime(1.0f)->setSoundType(SOUND_STONE)->setIconName(L"skull")->setDescriptionId(IDS_TILE_SKULL)->setUseDescriptionId(IDS_DESC_SKULL); + Tile::anvil = (new AnvilTile(145)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_iron)->setDestroyTime(5.0f)->setSoundType(SOUND_ANVIL)->setExplodeable(2000)->setIconName(L"anvil")->sendTileData()->setDescriptionId(IDS_TILE_ANVIL)->setUseDescriptionId(IDS_DESC_ANVIL); + Tile::chest_trap = (new ChestTile(146, ChestTile::TYPE_TRAP)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_chest, Item::eMaterial_trap)->setDestroyTime(2.5f)->setSoundType(SOUND_WOOD)->setDescriptionId(IDS_TILE_CHEST_TRAP)->setUseDescriptionId(IDS_DESC_CHEST_TRAP); + Tile::weightedPlate_light = (new WeightedPressurePlateTile(147, L"gold_block", Material::metal, Redstone::SIGNAL_MAX)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_pressureplate, Item::eMaterial_gold)->setDestroyTime(0.5f)->setSoundType(SOUND_WOOD)->setDescriptionId(IDS_TILE_WEIGHTED_PLATE_LIGHT)->setUseDescriptionId(IDS_DESC_WEIGHTED_PLATE_LIGHT); + Tile::weightedPlate_heavy = (new WeightedPressurePlateTile(148, L"iron_block", Material::metal, Redstone::SIGNAL_MAX * 10))->setBaseItemTypeAndMaterial(Item::eBaseItemType_pressureplate, Item::eMaterial_iron)->setDestroyTime(0.5f)->setSoundType(SOUND_WOOD)->setDescriptionId(IDS_TILE_WEIGHTED_PLATE_HEAVY)->setUseDescriptionId(IDS_DESC_WEIGHTED_PLATE_HEAVY); + Tile::comparator_off = (ComparatorTile *) (new ComparatorTile(149, false)) ->setDestroyTime(0.0f)->setSoundType(SOUND_WOOD)->setIconName(L"comparator_off")->setDescriptionId(IDS_TILE_COMPARATOR)->setUseDescriptionId(IDS_DESC_COMPARATOR); + Tile::comparator_on = (ComparatorTile *) (new ComparatorTile(150, true)) ->setDestroyTime(0.0f)->setLightEmission(10 / 16.0f)->setSoundType(SOUND_WOOD)->setIconName(L"comparator_on")->setDescriptionId(IDS_TILE_COMPARATOR)->setUseDescriptionId(IDS_DESC_COMPARATOR); + + Tile::daylightDetector = (DaylightDetectorTile *) (new DaylightDetectorTile(151))->setDestroyTime(0.2f)->setSoundType(SOUND_WOOD)->setIconName(L"daylight_detector")->setDescriptionId(IDS_TILE_DAYLIGHT_DETECTOR)->setUseDescriptionId(IDS_DESC_DAYLIGHT_DETECTOR); + Tile::redstoneBlock = (new PoweredMetalTile(152)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_redstone)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setIconName(L"redstone_block")->setDescriptionId(IDS_TILE_REDSTONE_BLOCK)->setUseDescriptionId(IDS_DESC_REDSTONE_BLOCK); + Tile::netherQuartz = (new OreTile(153)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setIconName(L"quartz_ore")->setDescriptionId(IDS_TILE_NETHER_QUARTZ)->setUseDescriptionId(IDS_DESC_NETHER_QUARTZ_ORE); + Tile::hopper = (HopperTile *)(new HopperTile(154)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_redstoneContainer, Item::eMaterial_undefined)->setDestroyTime(3.0f)->setExplodeable(8)->setSoundType(SOUND_WOOD)->setIconName(L"hopper")->setDescriptionId(IDS_TILE_HOPPER)->setUseDescriptionId(IDS_DESC_HOPPER); + Tile::quartzBlock = (new QuartzBlockTile(155)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_quartz)->setSoundType(SOUND_STONE)->setDestroyTime(0.8f)->setIconName(L"quartz_block")->setDescriptionId(IDS_TILE_QUARTZ_BLOCK)->setUseDescriptionId(IDS_DESC_QUARTZ_BLOCK); + Tile::stairs_quartz = (new StairTile(156, Tile::quartzBlock, QuartzBlockTile::TYPE_DEFAULT)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_quartz)->setIconName(L"stairsQuartz")->setDescriptionId(IDS_TILE_STAIRS_QUARTZ)->setUseDescriptionId(IDS_DESC_STAIRS); + Tile::activatorRail = (new PoweredRailTile(157)) ->setDestroyTime(0.7f)->setSoundType(SOUND_METAL)->setIconName(L"rail_activator")->setDescriptionId(IDS_TILE_ACTIVATOR_RAIL)->setUseDescriptionId(IDS_DESC_ACTIVATOR_RAIL); + Tile::dropper = (new DropperTile(158)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_redstoneContainer, Item::eMaterial_undefined)->setDestroyTime(3.5f)->setSoundType(SOUND_STONE)->setIconName(L"dropper")->setDescriptionId(IDS_TILE_DROPPER)->setUseDescriptionId(IDS_DESC_DROPPER); + Tile::clayHardened_colored = (new ColoredTile(159, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_clay, Item::eMaterial_clay)->setDestroyTime(1.25f)->setExplodeable(7)->setSoundType(SOUND_STONE)->setIconName(L"hardened_clay_stained")->setDescriptionId(IDS_TILE_STAINED_CLAY)->setUseDescriptionId(IDS_DESC_STAINED_CLAY); + Tile::stained_glass_pane = (new StainedGlassPaneBlock(160)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_glass, Item::eMaterial_glass)->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setIconName(L"glass")->setDescriptionId(IDS_TILE_STAINED_GLASS_PANE)->setUseDescriptionId(IDS_DESC_STAINED_GLASS_PANE); + + Tile::hayBlock = (new HayBlockTile(170)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_wheat)->setDestroyTime(0.5f)->setSoundType(SOUND_GRASS)->setIconName(L"hay_block")->setDescriptionId(IDS_TILE_HAY)->setUseDescriptionId(IDS_DESC_HAY); + Tile::woolCarpet = (new WoolCarpetTile(171)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_carpet, Item::eMaterial_cloth)->setDestroyTime(0.1f)->setSoundType(SOUND_CLOTH)->setIconName(L"woolCarpet")->setLightBlock(0)->setDescriptionId(IDS_TILE_CARPET)->setUseDescriptionId(IDS_DESC_CARPET); + Tile::clayHardened = (new Tile(172, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_clay, Item::eMaterial_clay)->setDestroyTime(1.25f)->setExplodeable(7)->setSoundType(SOUND_STONE)->setIconName(L"hardened_clay")->setDescriptionId(IDS_TILE_HARDENED_CLAY)->setUseDescriptionId(IDS_DESC_HARDENED_CLAY); + Tile::coalBlock = (new Tile(173, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_coal)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setIconName(L"coal_block")->setDescriptionId(IDS_TILE_COAL)->setUseDescriptionId(IDS_DESC_COAL_BLOCK); - Tile::pressurePlate_stone = (Tile *)(new PressurePlateTile(70, L"stone", Material::stone, PressurePlateTile::mobs)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_pressureplate, Item::eMaterial_stone)->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"pressurePlate")->setDescriptionId(IDS_TILE_PRESSURE_PLATE)->sendTileData()->setUseDescriptionId(IDS_DESC_PRESSUREPLATE); - Tile::pressurePlate_wood = (new PressurePlateTile(72, L"wood", Material::wood, PressurePlateTile::everything)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_pressureplate, Item::eMaterial_wood)->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"pressurePlate")->setDescriptionId(IDS_TILE_PRESSURE_PLATE)->sendTileData()->setUseDescriptionId(IDS_DESC_PRESSUREPLATE); - - Tile::flower = (Bush *) (new Bush(37)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"flower")->setDescriptionId(IDS_TILE_FLOWER)->setUseDescriptionId(IDS_DESC_FLOWER)->disableMipmap(); - Tile::rose = (Bush *) (new Bush(38)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"rose")->setDescriptionId(IDS_TILE_ROSE)->setUseDescriptionId(IDS_DESC_FLOWER)->disableMipmap(); - Tile::mushroom1 = (Bush *) (new Mushroom(39, L"mushroom_brown")) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setLightEmission(2 / 16.0f)->setTextureName(L"mushroom")->setDescriptionId(IDS_TILE_MUSHROOM)->setUseDescriptionId(IDS_DESC_MUSHROOM)->disableMipmap(); - Tile::mushroom2 = (Bush *) (new Mushroom(40, L"mushroom_red")) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"mushroom")->setDescriptionId(IDS_TILE_MUSHROOM)->setUseDescriptionId(IDS_DESC_MUSHROOM)->disableMipmap(); - -// Tile::stoneSlab = (new StoneSlabTile(43, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_slab, Item::eMaterial_stone)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setDescriptionId(IDS_TILE_STONESLAB)->setUseDescriptionId(IDS_DESC_SLAB); -// Tile::stoneSlabHalf = (new StoneSlabTile(44, false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_halfslab, Item::eMaterial_stone)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setDescriptionId(IDS_TILE_STONESLAB)->setUseDescriptionId(IDS_DESC_HALFSLAB); - - - Tile::tnt = (new TntTile(46)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"tnt")->setDescriptionId(IDS_TILE_TNT)->setUseDescriptionId(IDS_DESC_TNT); - Tile::bookshelf = (new BookshelfTile(47)) ->setDestroyTime(1.5f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"bookshelf")->setDescriptionId(IDS_TILE_BOOKSHELF)->setUseDescriptionId(IDS_DESC_BOOKSHELF); - Tile::mossStone = (new Tile(48, Material::stone)) ->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"stoneMoss")->setDescriptionId(IDS_TILE_STONE_MOSS)->setUseDescriptionId(IDS_DESC_MOSS_STONE); - // 4J - change of destroy time from 10.0f -> 50.0f for obsidian brought forward from 1.2.3 - Tile::obsidian = (new ObsidianTile(49)) ->setDestroyTime(50.0f)->setExplodeable(2000)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"obsidian")->setDescriptionId(IDS_TILE_OBSIDIAN)->setUseDescriptionId(IDS_DESC_OBSIDIAN); - - - Tile::fire = (FireTile *) ((new FireTile(51)) ->setDestroyTime(0.0f)->setLightEmission(1.0f)->setSoundType(Tile::SOUND_WOOD))->setTextureName(L"fire")->setDescriptionId(IDS_TILE_FIRE)->setNotCollectStatistics()->setUseDescriptionId(-1); - Tile::mobSpawner = (new MobSpawnerTile(52)) ->setDestroyTime(5.0f)->setSoundType(Tile::SOUND_METAL)->setTextureName(L"mobSpawner")->setDescriptionId(IDS_TILE_MOB_SPAWNER)->setNotCollectStatistics()->setUseDescriptionId(IDS_DESC_MOB_SPAWNER); - - Tile::chest = (ChestTile *)(new ChestTile(54)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_chest, Item::eMaterial_ender)->setDestroyTime(2.5f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"chest")->setDescriptionId(IDS_TILE_CHEST)->sendTileData()->setUseDescriptionId(IDS_DESC_CHEST); - Tile::redStoneDust = (RedStoneDustTile *)(new RedStoneDustTile(55)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_NORMAL)->setTextureName(L"redstoneDust")->setDescriptionId(IDS_TILE_REDSTONE_DUST)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONE_DUST); - Tile::workBench = (new WorkbenchTile(58)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_wood)->setDestroyTime(2.5f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"workbench")->setDescriptionId(IDS_TILE_WORKBENCH)->setUseDescriptionId(IDS_DESC_CRAFTINGTABLE); - Tile::crops = (new CropTile(59)) ->setTextureName(L"crops")->setDescriptionId(IDS_TILE_CROPS)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_CROPS)->disableMipmap(); - Tile::farmland = (new FarmTile(60)) ->setDestroyTime(0.6f)->setSoundType(Tile::SOUND_GRAVEL)->setTextureName(L"farmland")->setDescriptionId(IDS_TILE_FARMLAND)->setUseDescriptionId(IDS_DESC_FARMLAND)->sendTileData(); - Tile::furnace = (new FurnaceTile(61, false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_stone)->setDestroyTime(3.5f)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"furnace")->setDescriptionId(IDS_TILE_FURNACE)->sendTileData()->setUseDescriptionId(IDS_DESC_FURNACE); - Tile::furnace_lit = (new FurnaceTile(62, true)) ->setDestroyTime(3.5f)->setSoundType(Tile::SOUND_STONE)->setLightEmission(14 / 16.0f)->setTextureName(L"furnace")->setDescriptionId(IDS_TILE_FURNACE)->sendTileData()->setUseDescriptionId(IDS_DESC_FURNACE); - Tile::sign = (new SignTile(63, eTYPE_SIGNTILEENTITY, true))->setDestroyTime(1.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"sign")->setDescriptionId(IDS_TILE_SIGN)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_SIGN); - Tile::door_wood = (new DoorTile(64, Material::wood)) ->setDestroyTime(3.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"doorWood")->setDescriptionId(IDS_TILE_DOOR_WOOD)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_DOOR_WOOD); - Tile::ladder = (new LadderTile(65)) ->setDestroyTime(0.4f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"ladder")->setDescriptionId(IDS_TILE_LADDER)->sendTileData()->setUseDescriptionId(IDS_DESC_LADDER)->disableMipmap(); - Tile::wallSign = (new SignTile(68, eTYPE_SIGNTILEENTITY, false))->setDestroyTime(1.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"sign")->setDescriptionId(IDS_TILE_SIGN)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_SIGN); - Tile::lever = (new LeverTile(69)) ->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"lever")->setDescriptionId(IDS_TILE_LEVER)->sendTileData()->setUseDescriptionId(IDS_DESC_LEVER); - Tile::door_iron = (new DoorTile(71, Material::metal)) ->setDestroyTime(5.0f)->setSoundType(Tile::SOUND_METAL)->setTextureName(L"doorIron")->setDescriptionId(IDS_TILE_DOOR_IRON)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_DOOR_IRON); - Tile::redStoneOre = (new RedStoneOreTile(73,false)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"oreRedstone")->setDescriptionId(IDS_TILE_ORE_REDSTONE)->sendTileData()->setUseDescriptionId(IDS_DESC_ORE_REDSTONE); - Tile::redStoneOre_lit = (new RedStoneOreTile(74, true)) ->setLightEmission(10 / 16.0f)->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"oreRedstone")->setDescriptionId(IDS_TILE_ORE_REDSTONE)->sendTileData()->setUseDescriptionId(IDS_DESC_ORE_REDSTONE); - Tile::notGate_off = (new NotGateTile(75, false)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"notGate")->setDescriptionId(IDS_TILE_NOT_GATE)->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONETORCH)->disableMipmap(); - Tile::notGate_on = (new NotGateTile(76, true)) ->setDestroyTime(0.0f)->setLightEmission(8 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"notGate")->setDescriptionId(IDS_TILE_NOT_GATE)->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONETORCH)->disableMipmap(); - Tile::button = (new ButtonTile(77,false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_button, Item::eMaterial_stone)->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"button")->setDescriptionId(IDS_TILE_BUTTON)->sendTileData()->setUseDescriptionId(IDS_DESC_BUTTON); - Tile::topSnow = (new TopSnowTile(78)) ->setDestroyTime(0.1f)->setSoundType(Tile::SOUND_CLOTH)->setTextureName(L"snow")->setDescriptionId(IDS_TILE_SNOW)->setUseDescriptionId(IDS_DESC_TOP_SNOW)->sendTileData()->setLightBlock(0); - Tile::ice = (new IceTile(79)) ->setDestroyTime(0.5f)->setLightBlock(3)->setSoundType(Tile::SOUND_GLASS)->setTextureName(L"ice")->setDescriptionId(IDS_TILE_ICE)->setUseDescriptionId(IDS_DESC_ICE); - Tile::cactus = (new CactusTile(81)) ->setDestroyTime(0.4f)->setSoundType(Tile::SOUND_CLOTH)->setTextureName(L"cactus")->setDescriptionId(IDS_TILE_CACTUS)->setUseDescriptionId(IDS_DESC_CACTUS)->disableMipmap(); - Tile::reeds = (new ReedTile(83)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_GRASS)->setTextureName(L"reeds")->setDescriptionId(IDS_TILE_REEDS)->setNotCollectStatistics()->setUseDescriptionId(IDS_DESC_REEDS)->disableMipmap(); - Tile::recordPlayer = (new RecordPlayerTile(84)) ->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"jukebox")->setDescriptionId(IDS_TILE_JUKEBOX)->sendTileData()->setUseDescriptionId(IDS_DESC_JUKEBOX); - Tile::fence = (new FenceTile(85, L"wood", Material::wood)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fence, Item::eMaterial_wood)->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"fence")->setDescriptionId(IDS_TILE_FENCE)->setUseDescriptionId(IDS_DESC_FENCE); - - Tile::pumpkin = (new PumpkinTile(86, false)) ->setDestroyTime(1.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"pumpkin")->setDescriptionId(IDS_TILE_PUMPKIN)->sendTileData()->setUseDescriptionId(IDS_DESC_PUMPKIN); - - Tile::hellRock = (new HellStoneTile(87)) ->setDestroyTime(0.4f)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"hellrock")->setDescriptionId(IDS_TILE_HELL_ROCK)->setUseDescriptionId(IDS_DESC_HELL_ROCK); - Tile::hellSand = (new HellSandTile(88)) ->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_SAND)->setTextureName(L"hellsand")->setDescriptionId(IDS_TILE_HELL_SAND)->setUseDescriptionId(IDS_DESC_HELL_SAND); - Tile::portalTile = (PortalTile *) ((new PortalTile(90)) ->setDestroyTime(-1)->setSoundType(Tile::SOUND_GLASS)->setLightEmission(0.75f))->setTextureName(L"portal")->setDescriptionId(IDS_TILE_PORTAL)->setUseDescriptionId(IDS_DESC_PORTAL); - Tile::cake = (new CakeTile(92)) ->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_CLOTH)->setTextureName(L"cake")->setDescriptionId(IDS_TILE_CAKE)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_CAKE); - - // TODO Copy the translations from IDS_ITEM_DIODE to IDS_TILE_DIODE - Tile::diode_off = (RepeaterTile *)(new DiodeTile(93, false)) ->setDestroyTime(0.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"diode")->setDescriptionId(IDS_ITEM_DIODE)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONEREPEATER)->disableMipmap(); - Tile::diode_on = (RepeaterTile *)(new DiodeTile(94, true)) ->setDestroyTime(0.0f)->setLightEmission(10 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"diode")->setDescriptionId(IDS_ITEM_DIODE)->setNotCollectStatistics()->sendTileData()->setUseDescriptionId(IDS_DESC_REDSTONEREPEATER)->disableMipmap(); - Tile::aprilFoolsJoke = (new LockedChestTile(95)) ->setDestroyTime(0.0f)->setLightEmission(16 / 16.0f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"lockedchest")->setDescriptionId(IDS_TILE_LOCKED_CHEST)->setTicking(true)->sendTileData()->setUseDescriptionId(-1); - - Tile::monsterStoneEgg = (new StoneMonsterTile(97)) ->setDestroyTime(0.75f)->setTextureName(L"monsterStoneEgg")->setDescriptionId(IDS_TILE_STONE_SILVERFISH)->setUseDescriptionId(IDS_DESC_STONE_SILVERFISH); - Tile::stoneBrickSmooth = (new SmoothStoneBrickTile(98)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_stoneSmooth)->setDestroyTime(1.5f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setTextureName(L"stonebricksmooth")->setDescriptionId(IDS_TILE_STONE_BRICK_SMOOTH)->setUseDescriptionId(IDS_DESC_STONE_BRICK_SMOOTH); - Tile::hugeMushroom1 = (new HugeMushroomTile(99, Material::wood, 0)) ->setDestroyTime(0.2f)->setSoundType(SOUND_WOOD)->setTextureName(L"mushroom")->setDescriptionId(IDS_TILE_HUGE_MUSHROOM_1)->setUseDescriptionId(IDS_DESC_MUSHROOM)->sendTileData(); - Tile::hugeMushroom2 = (new HugeMushroomTile(100, Material::wood, 1)) ->setDestroyTime(0.2f)->setSoundType(SOUND_WOOD)->setTextureName(L"mushroom")->setDescriptionId(IDS_TILE_HUGE_MUSHROOM_2)->setUseDescriptionId(IDS_DESC_MUSHROOM)->sendTileData(); - Tile::ironFence = (new ThinFenceTile(101, L"fenceIron", L"fenceIron", Material::metal, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fence, Item::eMaterial_iron)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setTextureName(L"fenceIron")->setDescriptionId(IDS_TILE_IRON_FENCE)->setUseDescriptionId(IDS_DESC_IRON_FENCE); - Tile::thinGlass = (new ThinFenceTile(102, L"glass", L"thinglass_top", Material::glass, false)) ->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setTextureName(L"thinGlass")->setDescriptionId(IDS_TILE_THIN_GLASS)->setUseDescriptionId(IDS_DESC_THIN_GLASS); - Tile::melon = (new MelonTile(103)) ->setDestroyTime(1.0f)->setSoundType(SOUND_WOOD)->setTextureName(L"melon")->setDescriptionId(IDS_TILE_MELON)->setUseDescriptionId(IDS_DESC_MELON_BLOCK); - Tile::pumpkinStem = (new StemTile(104, Tile::pumpkin)) ->setDestroyTime(0.0f)->setSoundType(SOUND_WOOD)->setTextureName(L"pumpkinStem")->setDescriptionId(IDS_TILE_PUMPKIN_STEM)->sendTileData(); - Tile::melonStem = (new StemTile(105, Tile::melon)) ->setDestroyTime(0.0f)->setSoundType(SOUND_WOOD)->setTextureName(L"pumpkinStem")->setDescriptionId(IDS_TILE_MELON_STEM)->sendTileData(); - Tile::vine = (new VineTile(106))->setDestroyTime(0.2f) ->setSoundType(SOUND_GRASS)->setTextureName(L"vine")->setDescriptionId(IDS_TILE_VINE)->setUseDescriptionId(IDS_DESC_VINE)->sendTileData(); - Tile::fenceGate = (new FenceGateTile(107)) ->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setTextureName(L"fenceGate")->setDescriptionId(IDS_TILE_FENCE_GATE)->sendTileData()->setUseDescriptionId(IDS_DESC_FENCE_GATE); - - - Tile::stairs_wood = (new StairTile(53, Tile::wood,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_wood) ->setTextureName(L"stairsWood")->setDescriptionId(IDS_TILE_STAIRS_WOOD) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); - Tile::stairs_stone = (new StairTile(67, Tile::stoneBrick,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_stone) ->setTextureName(L"stairsStone")->setDescriptionId(IDS_TILE_STAIRS_STONE) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); - Tile::stairs_bricks = (new StairTile(108, Tile::redBrick,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_brick) ->setTextureName(L"stairsBrick")->setDescriptionId(IDS_TILE_STAIRS_BRICKS) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); - Tile::stairs_stoneBrickSmooth = (new StairTile(109, Tile::stoneBrickSmooth,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_stoneSmooth)->setTextureName(L"stairsStoneBrickSmooth")->setDescriptionId(IDS_TILE_STAIRS_STONE_BRICKS_SMOOTH) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); - - Tile::mycel = (MycelTile *)(new MycelTile(110)) ->setDestroyTime(0.6f)->setSoundType(SOUND_GRASS)->setTextureName(L"mycel")->setDescriptionId(IDS_TILE_MYCEL)->setUseDescriptionId(IDS_DESC_MYCEL); - Tile::waterLily = (new WaterlilyTile(111)) ->setDestroyTime(0.0f)->setSoundType(SOUND_GRASS)->setTextureName(L"waterlily")->setDescriptionId(IDS_TILE_WATERLILY)->setUseDescriptionId(IDS_DESC_WATERLILY); - Tile::netherBrick = (new Tile(112, Material::stone)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_netherbrick)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setTextureName(L"netherBrick")->setDescriptionId(IDS_TILE_NETHERBRICK)->setUseDescriptionId(IDS_DESC_NETHERBRICK); - Tile::netherFence = (new FenceTile(113, L"netherBrick", Material::stone))->setBaseItemTypeAndMaterial(Item::eBaseItemType_fence, Item::eMaterial_netherbrick)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(SOUND_STONE)->setTextureName(L"netherFence")->setDescriptionId(IDS_TILE_NETHERFENCE)->setUseDescriptionId(IDS_DESC_NETHERFENCE); - Tile::stairs_netherBricks = (new StairTile(114, Tile::netherBrick,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_netherbrick)->setTextureName(L"stairsNetherBrick")->setDescriptionId(IDS_TILE_STAIRS_NETHERBRICK) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); - Tile::netherStalk = (new NetherStalkTile(115)) ->setTextureName(L"netherStalk")->setDescriptionId(IDS_TILE_NETHERSTALK)->sendTileData()->setUseDescriptionId(IDS_DESC_NETHERSTALK); - Tile::enchantTable = (new EnchantmentTableTile(116)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_magic)->setDestroyTime(5.0f)->setExplodeable(2000)->setTextureName(L"enchantmentTable")->setDescriptionId(IDS_TILE_ENCHANTMENTTABLE)->setUseDescriptionId(IDS_DESC_ENCHANTMENTTABLE); - Tile::brewingStand = (new BrewingStandTile(117)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_blaze)->setDestroyTime(0.5f)->setLightEmission(2 / 16.0f)->setTextureName(L"brewingStand")->setDescriptionId(IDS_TILE_BREWINGSTAND)->sendTileData()->setUseDescriptionId(IDS_DESC_BREWING_STAND); - Tile::cauldron = (CauldronTile *)(new CauldronTile(118)) ->setDestroyTime(2.0f)->setTextureName(L"cauldron")->setDescriptionId(IDS_TILE_CAULDRON)->sendTileData()->setUseDescriptionId(IDS_DESC_CAULDRON); - Tile::endPortalTile = (new TheEndPortal(119, Material::portal)) ->setDestroyTime(INDESTRUCTIBLE_DESTROY_TIME)->setExplodeable(6000000)->setDescriptionId(IDS_TILE_END_PORTAL)->setUseDescriptionId(IDS_DESC_END_PORTAL); - Tile::endPortalFrameTile = (new TheEndPortalFrameTile(120)) ->setSoundType(SOUND_GLASS)->setLightEmission(2 / 16.0f)->setDestroyTime(INDESTRUCTIBLE_DESTROY_TIME)->setTextureName(L"endPortalFrame")->setDescriptionId(IDS_TILE_ENDPORTALFRAME)->sendTileData()->setExplodeable(6000000)->setUseDescriptionId(IDS_DESC_ENDPORTALFRAME); - Tile::whiteStone = (new Tile(121, Material::stone)) ->setDestroyTime(3.0f)->setExplodeable(15)->setSoundType(SOUND_STONE)->setTextureName(L"whiteStone")->setDescriptionId(IDS_TILE_WHITESTONE)->setUseDescriptionId(IDS_DESC_WHITESTONE); - Tile::dragonEgg = (new EggTile(122)) ->setDestroyTime(3.0f)->setExplodeable(15)->setSoundType(SOUND_STONE)->setLightEmission(2.0f / 16.0f)->setTextureName(L"dragonEgg")->setDescriptionId(IDS_TILE_DRAGONEGG)->setUseDescriptionId(IDS_DESC_DRAGONEGG); - Tile::redstoneLight = (new RedlightTile(123, false)) ->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setTextureName(L"redstoneLight")->setDescriptionId(IDS_TILE_REDSTONE_LIGHT)->setUseDescriptionId(IDS_DESC_REDSTONE_LIGHT); - Tile::redstoneLight_lit = (new RedlightTile(124, true)) ->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setTextureName(L"redstoneLight")->setDescriptionId(IDS_TILE_REDSTONE_LIGHT)->setUseDescriptionId(IDS_DESC_REDSTONE_LIGHT); - - // TU9 - Tile::stairs_sandstone = (new StairTile(128, Tile::sandStone,0)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_sand) ->setTextureName(L"stairsSandstone")->setDescriptionId(IDS_TILE_STAIRS_SANDSTONE) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); - Tile::woodStairsDark = (new StairTile(134, Tile::wood, TreeTile::DARK_TRUNK)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_sprucewood)->setTextureName(L"stairsWoodSpruce")->setDescriptionId(IDS_TILE_STAIRS_SPRUCEWOOD) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); - Tile::woodStairsBirch = (new StairTile(135, Tile::wood, TreeTile::BIRCH_TRUNK)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_birchwood)->setTextureName(L"stairsWoodBirch")->setDescriptionId(IDS_TILE_STAIRS_BIRCHWOOD) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); - Tile::woodStairsJungle = (new StairTile(136, Tile::wood, TreeTile::JUNGLE_TRUNK))->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_junglewood)->setTextureName(L"stairsWoodJungle")->setDescriptionId(IDS_TILE_STAIRS_JUNGLEWOOD) ->sendTileData()->setUseDescriptionId(IDS_DESC_STAIRS); - Tile::button_wood = (new ButtonTile(143, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_button, Item::eMaterial_wood)->setDestroyTime(0.5f)->setSoundType(Tile::SOUND_WOOD)->setTextureName(L"button")->setDescriptionId(IDS_TILE_BUTTON)->sendTileData()->setUseDescriptionId(IDS_DESC_BUTTON); - - Tile::woodSlab = (HalfSlabTile *) (new WoodSlabTile(Tile::woodSlab_Id, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_slab, Item::eMaterial_wood)->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setTextureName(L"woodSlab")->setDescriptionId(IDS_DESC_WOODSLAB)->setUseDescriptionId(IDS_DESC_WOODSLAB); - Tile::woodSlabHalf = (HalfSlabTile *) (new WoodSlabTile(Tile::woodSlabHalf_Id, false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_halfslab, Item::eMaterial_wood)->setDestroyTime(2.0f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setTextureName(L"woodSlab")->setDescriptionId(IDS_DESC_WOODSLAB)->setUseDescriptionId(IDS_DESC_WOODSLAB); - Tile::stoneSlab = (HalfSlabTile *) (new StoneSlabTile(Tile::stoneSlab_Id, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_slab, Item::eMaterial_stone)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"stoneSlab")->setDescriptionId(IDS_TILE_STONESLAB)->setUseDescriptionId(IDS_DESC_SLAB); - Tile::stoneSlabHalf = (HalfSlabTile *) (new StoneSlabTile(Tile::stoneSlabHalf_Id, false)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_halfslab, Item::eMaterial_stone)->setDestroyTime(2.0f)->setExplodeable(10)->setSoundType(Tile::SOUND_STONE)->setTextureName(L"stoneSlab")->setDescriptionId(IDS_TILE_STONESLAB)->setUseDescriptionId(IDS_DESC_HALFSLAB); - - Tile::emeraldOre = (new OreTile(129)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setTextureName(L"oreEmerald")->setDescriptionId(IDS_TILE_EMERALDORE)->setUseDescriptionId(IDS_DESC_EMERALDORE); - Tile::enderChest = (new EnderChestTile(130)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_chest, Item::eMaterial_ender)->setDestroyTime(22.5f)->setExplodeable(1000)->setSoundType(SOUND_STONE)->setTextureName(L"enderChest")->sendTileData()->setLightEmission(.5f)->setDescriptionId(IDS_TILE_ENDERCHEST)->setUseDescriptionId(IDS_DESC_ENDERCHEST); - Tile::tripWireSource = (TripWireSourceTile *)( new TripWireSourceTile(131) ) ->setTextureName(L"tripWireSource")->sendTileData()->setDescriptionId(IDS_TILE_TRIPWIRE_SOURCE)->setUseDescriptionId(IDS_DESC_TRIPWIRE_SOURCE); - Tile::tripWire = (new TripWireTile(132)) ->setTextureName(L"tripWire")->sendTileData()->setDescriptionId(IDS_TILE_TRIPWIRE)->setUseDescriptionId(IDS_DESC_TRIPWIRE); - Tile::emeraldBlock = (new MetalTile(133)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_block, Item::eMaterial_emerald)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setTextureName(L"blockEmerald")->setDescriptionId(IDS_TILE_EMERALDBLOCK)->setUseDescriptionId(IDS_DESC_EMERALDBLOCK); - - - Tile::cocoa = (new CocoaTile(127)) ->setDestroyTime(0.2f)->setExplodeable(5)->setSoundType(SOUND_WOOD)->setTextureName(L"cocoa")->sendTileData()->setDescriptionId(IDS_TILE_COCOA)->setUseDescriptionId(IDS_DESC_COCOA); - Tile::skull = (new SkullTile(144)) ->setDestroyTime(1.0f)->setSoundType(SOUND_STONE)->setTextureName(L"skull")->setDescriptionId(IDS_TILE_SKULL)->setUseDescriptionId(IDS_DESC_SKULL); - - Tile::cobbleWall = (new WallTile(139, Tile::stoneBrick)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fence, Item::eMaterial_stone)->setTextureName(L"cobbleWall")->setDescriptionId(IDS_TILE_COBBLESTONE_WALL)->setUseDescriptionId(IDS_DESC_COBBLESTONE_WALL); - Tile::flowerPot = (new FlowerPotTile(140)) ->setDestroyTime(0.0f)->setSoundType(SOUND_NORMAL)->setTextureName(L"flowerPot")->setDescriptionId(IDS_TILE_FLOWERPOT)->setUseDescriptionId(IDS_DESC_FLOWERPOT); - Tile::carrots = (new CarrotTile(141)) ->setTextureName(L"carrots")->setDescriptionId(IDS_TILE_CARROTS)->setUseDescriptionId(IDS_DESC_CARROTS)->disableMipmap(); - Tile::potatoes = (new PotatoTile(142)) ->setTextureName(L"potatoes")->setDescriptionId(IDS_TILE_POTATOES)->setUseDescriptionId(IDS_DESC_POTATO)->disableMipmap(); - Tile::anvil = (new AnvilTile(145)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_device, Item::eMaterial_iron)->setDestroyTime(5.0f)->setSoundType(SOUND_ANVIL)->setExplodeable(2000)->setTextureName(L"anvil")->sendTileData()->setDescriptionId(IDS_TILE_ANVIL)->setUseDescriptionId(IDS_DESC_ANVIL); - Tile::netherQuartz = (new OreTile(153)) ->setDestroyTime(3.0f)->setExplodeable(5)->setSoundType(SOUND_STONE)->setTextureName(L"netherquartz")->setDescriptionId(IDS_TILE_NETHER_QUARTZ)->setUseDescriptionId(IDS_DESC_NETHER_QUARTZ_ORE); - Tile::quartzBlock = (new QuartzBlockTile(155)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_structblock, Item::eMaterial_quartz)->setSoundType(SOUND_STONE)->setDestroyTime(0.8f)->setTextureName(L"quartzBlock")->setDescriptionId(IDS_TILE_QUARTZ_BLOCK)->setUseDescriptionId(IDS_DESC_QUARTZ_BLOCK); - Tile::stairs_quartz = (new StairTile(156, Tile::quartzBlock, QuartzBlockTile::TYPE_DEFAULT)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_stairs, Item::eMaterial_quartz)->setTextureName(L"stairsQuartz")->setDescriptionId(IDS_TILE_STAIRS_QUARTZ)->setUseDescriptionId(IDS_DESC_STAIRS); - - Tile::woolCarpet = (new WoolCarpetTile(171)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_carpet, Item::eMaterial_cloth)->setDestroyTime(0.1f)->setSoundType(SOUND_CLOTH)->setTextureName(L"woolCarpet")->setLightBlock(0)->setDescriptionId(IDS_TILE_CARPET)->setUseDescriptionId(IDS_DESC_CARPET); // Special cases for certain items since they can have different icons - Item::items[Tile::cloth_Id] = ( new ClothTileItem(Tile::cloth_Id- 256) )->setTextureName(L"cloth")->setDescriptionId(IDS_TILE_CLOTH)->setUseDescriptionId(IDS_DESC_WOOL); - Item::items[Tile::woolCarpet_Id] = ( new ClothTileItem(Tile::woolCarpet_Id - 256))->setTextureName(L"woolCarpet")->setDescriptionId(IDS_TILE_CARPET)->setUseDescriptionId(IDS_DESC_CARPET); - Item::items[Tile::treeTrunk_Id] = ( new TreeTileItem(Tile::treeTrunk_Id - 256, treeTrunk) )->setTextureName(L"log")->setDescriptionId(IDS_TILE_LOG)->setUseDescriptionId(IDS_DESC_LOG); - Item::items[Tile::wood_Id] = ( new MultiTextureTileItem(Tile::wood_Id - 256, Tile::wood, (int *)WoodTile::WOOD_NAMES, 4))->setTextureName(L"wood")->setDescriptionId(IDS_TILE_OAKWOOD_PLANKS)->setUseDescriptionId(IDS_DESC_LOG); // <- TODO - Item::items[Tile::monsterStoneEgg_Id] = ( new StoneMonsterTileItem(Tile::monsterStoneEgg_Id - 256))->setTextureName(L"monsterStoneEgg")->setDescriptionId(IDS_TILE_STONE_SILVERFISH)->setUseDescriptionId(IDS_DESC_STONE_SILVERFISH); // 4J - Brought forward from post-1.2 to fix stacking problem - Item::items[Tile::stoneBrickSmooth_Id] = ( new SmoothStoneBrickTileItem(Tile::stoneBrickSmooth_Id - 256, stoneBrickSmooth))->setTextureName(L"stonebricksmooth")->setDescriptionId(IDS_TILE_STONE_BRICK_SMOOTH); - Item::items[Tile::sandStone_Id] = ( new MultiTextureTileItem(sandStone_Id - 256, sandStone, SandStoneTile::SANDSTONE_NAMES, SandStoneTile::SANDSTONE_BLOCK_NAMES) )->setTextureName(L"sandStone")->setDescriptionId(IDS_TILE_SANDSTONE)->setUseDescriptionId(IDS_DESC_SANDSTONE); - Item::items[Tile::quartzBlock_Id] = ( new MultiTextureTileItem(quartzBlock_Id - 256, quartzBlock, QuartzBlockTile::BLOCK_NAMES, QuartzBlockTile::QUARTZ_BLOCK_NAMES) )->setTextureName(L"quartzBlock")->setDescriptionId(IDS_TILE_QUARTZ_BLOCK)->setUseDescriptionId(IDS_DESC_QUARTZ_BLOCK); - Item::items[Tile::stoneSlabHalf_Id] = ( new StoneSlabTileItem(Tile::stoneSlabHalf_Id - 256, Tile::stoneSlabHalf, Tile::stoneSlab, false) )->setTextureName(L"stoneSlab")->setDescriptionId(IDS_TILE_STONESLAB)->setUseDescriptionId(IDS_DESC_HALFSLAB); - Item::items[Tile::stoneSlab_Id] = ( new StoneSlabTileItem(Tile::stoneSlab_Id - 256, Tile::stoneSlabHalf, Tile::stoneSlab, true))->setTextureName(L"stoneSlab")->setDescriptionId(IDS_DESC_STONESLAB)->setUseDescriptionId(IDS_DESC_SLAB); - Item::items[Tile::woodSlabHalf_Id] = ( new StoneSlabTileItem(Tile::woodSlabHalf_Id - 256, Tile::woodSlabHalf, Tile::woodSlab, false))->setTextureName(L"woodSlab")->setDescriptionId(IDS_DESC_WOODSLAB)->setUseDescriptionId(IDS_DESC_WOODSLAB); - Item::items[Tile::woodSlab_Id] = ( new StoneSlabTileItem(Tile::woodSlab_Id - 256, Tile::woodSlabHalf, Tile::woodSlab, true))->setTextureName(L"woodSlab")->setDescriptionId(IDS_DESC_WOODSLAB)->setUseDescriptionId(IDS_DESC_WOODSLAB); - Item::items[Tile::sapling_Id] = ( new SaplingTileItem(Tile::sapling_Id - 256) )->setTextureName(L"sapling")->setDescriptionId(IDS_TILE_SAPLING)->setUseDescriptionId(IDS_DESC_SAPLING); - Item::items[Tile::leaves_Id] = ( new LeafTileItem(Tile::leaves_Id - 256) )->setTextureName(L"leaves")->setDescriptionId(IDS_TILE_LEAVES)->setUseDescriptionId(IDS_DESC_LEAVES); - Item::items[Tile::vine_Id] = ( new ColoredTileItem(Tile::vine_Id - 256, false))->setDescriptionId(IDS_TILE_VINE)->setUseDescriptionId(IDS_DESC_VINE); - int idsData[3] = {IDS_TILE_SHRUB, IDS_TILE_GRASS, IDS_TILE_FERN}; + Item::items[wool_Id] = ( new WoolTileItem(Tile::wool_Id- 256) )->setIconName(L"cloth")->setDescriptionId(IDS_TILE_CLOTH)->setUseDescriptionId(IDS_DESC_WOOL); + Item::items[clayHardened_colored_Id]= ( new WoolTileItem(Tile::clayHardened_colored_Id - 256))->setIconName(L"clayHardenedStained")->setDescriptionId(IDS_TILE_STAINED_CLAY)->setUseDescriptionId(IDS_DESC_STAINED_CLAY); + Item::items[stained_glass_Id] = ( new WoolTileItem(Tile::stained_glass_Id - 256))->setIconName(L"stainedGlass")->setDescriptionId(IDS_TILE_STAINED_GLASS)->setUseDescriptionId(IDS_DESC_STAINED_GLASS); + Item::items[stained_glass_pane_Id] = ( new WoolTileItem(Tile::stained_glass_pane_Id - 256))->setIconName(L"stainedGlassPane")->setDescriptionId(IDS_TILE_STAINED_GLASS_PANE)->setUseDescriptionId(IDS_DESC_STAINED_GLASS_PANE); + Item::items[woolCarpet_Id] = ( new WoolTileItem(Tile::woolCarpet_Id - 256))->setIconName(L"woolCarpet")->setDescriptionId(IDS_TILE_CARPET)->setUseDescriptionId(IDS_DESC_CARPET); + Item::items[treeTrunk_Id] = ( new MultiTextureTileItem(Tile::treeTrunk_Id - 256, treeTrunk, (int *)TreeTile::TREE_NAMES, 4) )->setIconName(L"log")->setDescriptionId(IDS_TILE_LOG)->setUseDescriptionId(IDS_DESC_LOG); + Item::items[wood_Id] = ( new MultiTextureTileItem(Tile::wood_Id - 256, Tile::wood, (int *)WoodTile::WOOD_NAMES, 4, IDS_TILE_PLANKS))->setIconName(L"wood")->setDescriptionId(IDS_TILE_OAKWOOD_PLANKS)->setUseDescriptionId(IDS_DESC_LOG); // <- TODO + Item::items[monsterStoneEgg_Id] = ( new MultiTextureTileItem(Tile::monsterStoneEgg_Id - 256, monsterStoneEgg, (int *)StoneMonsterTile::STONE_MONSTER_NAMES, 3))->setIconName(L"monsterStoneEgg")->setDescriptionId(IDS_TILE_STONE_SILVERFISH)->setUseDescriptionId(IDS_DESC_STONE_SILVERFISH); // 4J - Brought forward from post-1.2 to fix stacking problem + Item::items[stoneBrick_Id] = ( new MultiTextureTileItem(Tile::stoneBrick_Id - 256, stoneBrick,(int *)SmoothStoneBrickTile::SMOOTH_STONE_BRICK_NAMES, 4))->setIconName(L"stonebricksmooth")->setDescriptionId(IDS_TILE_STONE_BRICK_SMOOTH); + Item::items[sandStone_Id] = ( new MultiTextureTileItem(sandStone_Id - 256, sandStone, SandStoneTile::SANDSTONE_NAMES, SandStoneTile::SANDSTONE_BLOCK_NAMES) )->setIconName(L"sandStone")->setDescriptionId(IDS_TILE_SANDSTONE)->setUseDescriptionId(IDS_DESC_SANDSTONE); + Item::items[quartzBlock_Id] = ( new MultiTextureTileItem(quartzBlock_Id - 256, quartzBlock, QuartzBlockTile::BLOCK_NAMES, QuartzBlockTile::QUARTZ_BLOCK_NAMES) )->setIconName(L"quartzBlock")->setDescriptionId(IDS_TILE_QUARTZ_BLOCK)->setUseDescriptionId(IDS_DESC_QUARTZ_BLOCK); + Item::items[stoneSlabHalf_Id] = ( new StoneSlabTileItem(Tile::stoneSlabHalf_Id - 256, Tile::stoneSlabHalf, Tile::stoneSlab, false) )->setIconName(L"stoneSlab")->setDescriptionId(IDS_TILE_STONESLAB)->setUseDescriptionId(IDS_DESC_HALFSLAB); + Item::items[stoneSlab_Id] = ( new StoneSlabTileItem(Tile::stoneSlab_Id - 256, Tile::stoneSlabHalf, Tile::stoneSlab, true))->setIconName(L"stoneSlab")->setDescriptionId(IDS_DESC_STONESLAB)->setUseDescriptionId(IDS_DESC_SLAB); + Item::items[woodSlabHalf_Id] = ( new StoneSlabTileItem(Tile::woodSlabHalf_Id - 256, Tile::woodSlabHalf, Tile::woodSlab, false))->setIconName(L"woodSlab")->setDescriptionId(IDS_DESC_WOODSLAB)->setUseDescriptionId(IDS_DESC_WOODSLAB); + Item::items[woodSlab_Id] = ( new StoneSlabTileItem(Tile::woodSlab_Id - 256, Tile::woodSlabHalf, Tile::woodSlab, true))->setIconName(L"woodSlab")->setDescriptionId(IDS_DESC_WOODSLAB)->setUseDescriptionId(IDS_DESC_WOODSLAB); + Item::items[sapling_Id] = ( new MultiTextureTileItem(Tile::sapling_Id - 256, Tile::sapling, Sapling::SAPLING_NAMES, 4) )->setIconName(L"sapling")->setDescriptionId(IDS_TILE_SAPLING)->setUseDescriptionId(IDS_DESC_SAPLING); + Item::items[leaves_Id] = ( new LeafTileItem(Tile::leaves_Id - 256) )->setIconName(L"leaves")->setDescriptionId(IDS_TILE_LEAVES)->setUseDescriptionId(IDS_DESC_LEAVES); + Item::items[vine_Id] = ( new ColoredTileItem(Tile::vine_Id - 256, false))->setDescriptionId(IDS_TILE_VINE)->setUseDescriptionId(IDS_DESC_VINE); + int idsData[3] = {IDS_TILE_SHRUB, IDS_TILE_TALL_GRASS, IDS_TILE_FERN}; intArray ids = intArray(idsData, 3); - Item::items[Tile::tallgrass_Id] = ((ColoredTileItem *)(new ColoredTileItem(Tile::tallgrass_Id - 256, true))->setDescriptionId(IDS_TILE_TALL_GRASS))->setDescriptionPostfixes(ids); - Item::items[Tile::waterLily_Id] = ( new WaterLilyTileItem(Tile::waterLily_Id - 256)); - Item::items[Tile::pistonBase_Id] = ( new PistonTileItem(Tile::pistonBase_Id - 256) )->setDescriptionId(IDS_TILE_PISTON_BASE)->setUseDescriptionId(IDS_DESC_PISTON); - Item::items[Tile::pistonStickyBase_Id] = ( new PistonTileItem(Tile::pistonStickyBase_Id - 256) )->setDescriptionId(IDS_TILE_PISTON_STICK_BASE)->setUseDescriptionId(IDS_DESC_STICKY_PISTON); - Item::items[Tile::cobbleWall_Id] = ( new MultiTextureTileItem(cobbleWall_Id - 256, cobbleWall, (int *)WallTile::COBBLE_NAMES, 2) )->setDescriptionId(IDS_TILE_COBBLESTONE_WALL)->setUseDescriptionId(IDS_DESC_COBBLESTONE_WALL); - Item::items[Tile::anvil_Id] = ( new AnvilTileItem(anvil) )->setDescriptionId(IDS_TILE_ANVIL)->setUseDescriptionId(IDS_DESC_ANVIL); + Item::items[tallgrass_Id] = ( (ColoredTileItem *)(new ColoredTileItem(Tile::tallgrass_Id - 256, true))->setDescriptionId(IDS_TILE_TALL_GRASS))->setDescriptionPostfixes(ids); + Item::items[topSnow_Id] = ( new SnowItem(topSnow_Id - 256, topSnow) ); + Item::items[waterLily_Id] = ( new WaterLilyTileItem(Tile::waterLily_Id - 256)); + Item::items[pistonBase_Id] = ( new PistonTileItem(Tile::pistonBase_Id - 256) )->setDescriptionId(IDS_TILE_PISTON_BASE)->setUseDescriptionId(IDS_DESC_PISTON); + Item::items[pistonStickyBase_Id] = ( new PistonTileItem(Tile::pistonStickyBase_Id - 256) )->setDescriptionId(IDS_TILE_PISTON_STICK_BASE)->setUseDescriptionId(IDS_DESC_STICKY_PISTON); + Item::items[cobbleWall_Id] = ( new MultiTextureTileItem(cobbleWall_Id - 256, cobbleWall, (int *)WallTile::COBBLE_NAMES, 2) )->setDescriptionId(IDS_TILE_COBBLESTONE_WALL)->setUseDescriptionId(IDS_DESC_COBBLESTONE_WALL); + Item::items[anvil_Id] = ( new AnvilTileItem(anvil) )->setDescriptionId(IDS_TILE_ANVIL)->setUseDescriptionId(IDS_DESC_ANVIL); for (int i = 0; i < 256; i++) @@ -461,13 +483,13 @@ void Tile::staticCtor() Tile::tiles[i]->init(); } - bool propagate = false; - if (i > 0 && Tile::tiles[i]->getRenderShape() == Tile::SHAPE_STAIRS) propagate = true; - if (i > 0 && dynamic_cast(Tile::tiles[i]) != NULL) + bool propagate = false; + if (i > 0 && Tile::tiles[i]->getRenderShape() == Tile::SHAPE_STAIRS) propagate = true; + if (i > 0 && dynamic_cast(Tile::tiles[i]) != NULL) { - propagate = true; - } - if (i == Tile::farmland_Id) propagate = true; + propagate = true; + } + if (i == Tile::farmland_Id) propagate = true; if (Tile::transculent[i]) { propagate = true; @@ -476,7 +498,7 @@ void Tile::staticCtor() { propagate = true; } - Tile::propagate[i] = propagate; + Tile::propagate[i] = propagate; } } Tile::transculent[0] = true; @@ -519,7 +541,7 @@ void Tile::_init(int id, Material *material, bool isSolidRender) lightBlock[id] = isSolidRender ? 255 : 0; transculent[id] = !material->blocksLight(); mipmapEnable[id] = true; // 4J added - m_textureName = L""; + iconName = L""; } Tile::Tile(int id, Material *material, bool isSolidRender) @@ -541,7 +563,6 @@ void Tile::init() } - // 4J-PB - adding so we can class different items together for the new crafting menu // so pickaxe_stone would get tagged with pickaxe and stone Tile *Tile::setBaseItemTypeAndMaterial(int iType,int iMaterial) @@ -590,7 +611,7 @@ bool Tile::isSolidBlockingTile(int t) { Tile *tile = Tile::tiles[t]; if (tile == NULL) return false; - return tile->material->isSolidBlocking() && tile->isCubeShaped(); + return tile->material->isSolidBlocking() && tile->isCubeShaped() && !tile->isSignalSource(); } bool Tile::isCubeShaped() @@ -658,7 +679,7 @@ void Tile::setShape(float x0, float y0, float z0, float x1, float y1, float z1) tls->yy1 = y1; tls->zz1 = z1; tls->tileId = this->id; - + //this->xx0 = x0; //this->yy0 = y0; //this->zz0 = z0; @@ -670,7 +691,7 @@ void Tile::setShape(float x0, float y0, float z0, float x1, float y1, float z1) float Tile::getBrightness(LevelSource *level, int x, int y, int z) { // Lighting fix brought forward from ~1.5 here - used to use the lightEmission level for this tile rather than getting the for the passed in x/y/z coords - return level->getBrightness(x, y, z, Tile::lightEmission[level->getTile(x,y,z)]); + return level->getBrightness(x, y, z, lightEmission[level->getTile(x,y,z)]); } // 4J - brought forward from 1.8.2 @@ -679,11 +700,11 @@ int Tile::getLightColor(LevelSource *level, int x, int y, int z, int tileId/*=-1 // Lighting fix brought forward from ~1.5 here - used to use the lightEmission level for this tile rather than getting the for the passed in x/y/z coords if( tileId == -1 ) { - return level->getLightColor(x, y, z, Tile::lightEmission[level->getTile(x,y,z)], -1); + return level->getLightColor(x, y, z, lightEmission[level->getTile(x,y,z)], -1); } else { - return level->getLightColor(x, y, z, Tile::lightEmission[tileId], tileId); + return level->getLightColor(x, y, z, lightEmission[tileId], tileId); } } @@ -847,7 +868,7 @@ void Tile::addLights(Level *level, int x, int y, int z) { } -int Tile::getTickDelay() +int Tile::getTickDelay(Level *level) { return 10; } @@ -874,8 +895,11 @@ float Tile::getDestroyProgress(shared_ptr player, Level *level, int x, i { float destroySpeed = getDestroySpeed(level, x, y, z); if (destroySpeed < 0) return 0; - if (!player->canDestroy(this)) return 1 / destroySpeed / 100.0f; - return (player->getDestroySpeed(this) / destroySpeed) / 30; + if (!player->canDestroy(this)) + { + return player->getDestroySpeed(this, false) / destroySpeed / 100.0f; + } + return (player->getDestroySpeed(this, true) / destroySpeed) / 30; } void Tile::spawnResources(Level *level, int x, int y, int z, int data, int playerBonusLevel) @@ -899,7 +923,7 @@ void Tile::spawnResources(Level *level, int x, int y, int z, int data, float odd void Tile::popResource(Level *level, int x, int y, int z, shared_ptr itemInstance) { - if( level->isClientSide ) return; + if( level->isClientSide || !level->getGameRules()->getBoolean(GameRules::RULE_DOTILEDROPS) ) return; float s = 0.7f; double xo = level->random->nextFloat() * s + (1 - s) * 0.5; @@ -977,7 +1001,7 @@ HitResult *Tile::clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b) bool Tile::containsX(Vec3 *v) { if( v == NULL) return false; - + ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); // 4J Stu - Added this so that the TLS shape is correct for this tile if(tls->tileId != this->id) updateDefaultShape(); @@ -1004,10 +1028,15 @@ bool Tile::containsZ(Vec3 *v) return v->x >= tls->xx0 && v->x <= tls->xx1 && v->y >= tls->yy0 && v->y <= tls->yy1; } -void Tile::wasExploded(Level *level, int x, int y, int z) +void Tile::wasExploded(Level *level, int x, int y, int z, Explosion *explosion) { } +bool Tile::mayPlace(Level *level, int x, int y, int z, int face, shared_ptr item) +{ + return mayPlace(level, x, y, z, face); +} + int Tile::getRenderLayer() { return 0; @@ -1136,14 +1165,9 @@ int Tile::getColor(LevelSource *level, int x, int y, int z, int data) return 0xffffff; } -bool Tile::getSignal(LevelSource *level, int x, int y, int z) -{ - return false; -} - -bool Tile::getSignal(LevelSource *level, int x, int y, int z, int dir) +int Tile::getSignal(LevelSource *level, int x, int y, int z, int dir) { - return false; + return Redstone::SIGNAL_NONE; } bool Tile::isSignalSource() @@ -1155,9 +1179,9 @@ void Tile::entityInside(Level *level, int x, int y, int z, shared_ptr en { } -bool Tile::getDirectSignal(Level *level, int x, int y, int z, int dir) +int Tile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir) { - return false; + return Redstone::SIGNAL_NONE; } void Tile::updateDefaultShape() @@ -1168,29 +1192,29 @@ void Tile::updateDefaultShape() void Tile::playerDestroy(Level *level, shared_ptr player, int x, int y, int z, int data) { // 4J Stu - Special case - only record a crop destroy if is fully grown - if( id==Tile::crops_Id ) + if( id==Tile::wheat_Id ) { - if( Tile::crops->getResource(data, NULL, 0) > 0 ) + if( Tile::wheat->getResource(data, NULL, 0) > 0 ) player->awardStat( - GenericStats::blocksMined(id), - GenericStats::param_blocksMined(id,data,1) - ); + GenericStats::blocksMined(id), + GenericStats::param_blocksMined(id,data,1) + ); } else if (id == Tile::potatoes_Id) { if (Tile::potatoes->getResource(data, NULL, 0) > 0) player->awardStat( - GenericStats::blocksMined(id), - GenericStats::param_blocksMined(id,data,1) - ); + GenericStats::blocksMined(id), + GenericStats::param_blocksMined(id,data,1) + ); } else if (id == Tile::carrots_Id) { if (Tile::potatoes->getResource(data, NULL, 0) > 0) player->awardStat( - GenericStats::blocksMined(id), - GenericStats::param_blocksMined(id,data,1) - ); + GenericStats::blocksMined(id), + GenericStats::param_blocksMined(id,data,1) + ); } else { @@ -1206,19 +1230,19 @@ void Tile::playerDestroy(Level *level, shared_ptr player, int x, int y, player->awardStat(GenericStats::mineWood(), GenericStats::param_noArgs()); - if (isSilkTouchable() && EnchantmentHelper::hasSilkTouch(player->inventory)) + if (isSilkTouchable() && EnchantmentHelper::hasSilkTouch(player)) { - shared_ptr item = getSilkTouchItemInstance(data); - if (item != NULL) + shared_ptr item = getSilkTouchItemInstance(data); + if (item != NULL) { - popResource(level, x, y, z, item); - } - } + popResource(level, x, y, z, item); + } + } else { - int playerBonusLevel = EnchantmentHelper::getDiggingLootBonus(player->inventory); - spawnResources(level, x, y, z, data, playerBonusLevel); - } + int playerBonusLevel = EnchantmentHelper::getDiggingLootBonus(player); + spawnResources(level, x, y, z, data, playerBonusLevel); + } } bool Tile::isSilkTouchable() @@ -1228,12 +1252,12 @@ bool Tile::isSilkTouchable() shared_ptr Tile::getSilkTouchItemInstance(int data) { - int popData = 0; - if (id >= 0 && id < Item::items.length && Item::items[id]->isStackedByData()) + int popData = 0; + if (id >= 0 && id < Item::items.length && Item::items[id]->isStackedByData()) { - popData = data; - } - return shared_ptr(new ItemInstance(id, 1, popData)); + popData = data; + } + return shared_ptr(new ItemInstance(id, 1, popData)); } int Tile::getResourceCountForLootBonus(int bonusLevel, Random *random) @@ -1246,7 +1270,7 @@ bool Tile::canSurvive(Level *level, int x, int y, int z) return true; } -void Tile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) +void Tile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance) { } @@ -1281,8 +1305,9 @@ unsigned int Tile::getUseDescriptionId() return useDescriptionId; } -void Tile::triggerEvent(Level *level, int x, int y, int z, int b0, int b1) +bool Tile::triggerEvent(Level *level, int x, int y, int z, int b0, int b1) { + return false; } bool Tile::isCollectStatistics() @@ -1333,26 +1358,74 @@ void Tile::handleRain(Level *level, int x, int y, int z) { } - void Tile::levelTimeChanged(Level *level, __int64 delta, __int64 newTime) +void Tile::levelTimeChanged(Level *level, __int64 delta, __int64 newTime) { } -void Tile::registerIcons(IconRegister *iconRegister) +bool Tile::useOwnCloneData() +{ + return false; +} + +bool Tile::canInstantlyTick() { - icon = iconRegister->registerIcon(m_textureName); + return true; } -wstring Tile::getTileItemIconName() +bool Tile::dropFromExplosion(Explosion *explosion) { - return L""; + return true; +} + +bool Tile::isMatching(int id) +{ + return this->id == id; +} + +bool Tile::isMatching(int tileIdA, int tileIdB) +{ + if (tileIdA == tileIdB) + { + return true; + } + if (tileIdA == 0 || tileIdB == 0 || tiles[tileIdA] == NULL || tiles[tileIdB] == NULL) + { + return false; + } + return tiles[tileIdA]->isMatching(tileIdB); +} + +bool Tile::hasAnalogOutputSignal() +{ + return false; +} + +int Tile::getAnalogOutputSignal(Level *level, int x, int y, int z, int dir) +{ + return Redstone::SIGNAL_NONE; } -Tile *Tile::setTextureName(const wstring &name) +Tile *Tile::setIconName(const wstring &iconName) { - m_textureName = name; + this->iconName = iconName; return this; } +wstring Tile::getIconName() +{ + return iconName.empty() ? L"MISSING_ICON_TILE_" + _toString(id) + L"_" + _toString(descriptionId) : iconName; +} + +void Tile::registerIcons(IconRegister *iconRegister) +{ + icon = iconRegister->registerIcon(getIconName()); +} + +wstring Tile::getTileItemIconName() +{ + return L""; +} + Tile::SoundType::SoundType(eMATERIALSOUND_TYPE eMaterialSound, float volume, float pitch, int iBreakSound, int iPlaceSound) { this->eMaterialSound = eMaterialSound; @@ -1478,14 +1551,14 @@ int Tile::SoundType::getPlaceSound() const /* - 4J: These are necessary on the PS3. - (and 4 and Vita). +4J: These are necessary on the PS3. +(and 4 and Vita). */ #if (defined __PS3__ || defined __ORBIS__ || defined __PSVITA__) -const int Tile::rock_Id; +const int Tile::stone_Id; const int Tile::grass_Id; const int Tile::dirt_Id; -const int Tile::stoneBrick_Id; +// 4 const int Tile::wood_Id; const int Tile::sapling_Id; const int Tile::unbreakable_Id; @@ -1506,7 +1579,7 @@ const int Tile::lapisOre_Id; const int Tile::lapisBlock_Id; const int Tile::dispenser_Id; const int Tile::sandStone_Id; -const int Tile::musicBlock_Id; +// 25 const int Tile::bed_Id; const int Tile::goldenRail_Id; const int Tile::detectorRail_Id; @@ -1516,12 +1589,12 @@ const int Tile::tallgrass_Id; const int Tile::deadBush_Id; const int Tile::pistonBase_Id; const int Tile::pistonExtensionPiece_Id; -const int Tile::cloth_Id; +const int Tile::wool_Id; const int Tile::pistonMovingPiece_Id; const int Tile::flower_Id; const int Tile::rose_Id; -const int Tile::mushroom1_Id; -const int Tile::mushroom2_Id; +const int Tile::mushroom_brown_Id; +const int Tile::mushroom_red_Id; const int Tile::goldBlock_Id; const int Tile::ironBlock_Id; const int Tile::stoneSlab_Id; @@ -1529,7 +1602,7 @@ const int Tile::stoneSlabHalf_Id; const int Tile::redBrick_Id; const int Tile::tnt_Id; const int Tile::bookshelf_Id; -const int Tile::mossStone_Id; +const int Tile::mossyCobblestone_Id; const int Tile::obsidian_Id; const int Tile::torch_Id; const int Tile::fire_Id; @@ -1540,7 +1613,7 @@ const int Tile::redStoneDust_Id; const int Tile::diamondOre_Id; const int Tile::diamondBlock_Id; const int Tile::workBench_Id; -const int Tile::crops_Id; +const int Tile::wheat_Id; const int Tile::farmland_Id; const int Tile::furnace_Id; const int Tile::furnace_lit_Id; @@ -1556,8 +1629,8 @@ const int Tile::door_iron_Id; const int Tile::pressurePlate_wood_Id; const int Tile::redStoneOre_Id; const int Tile::redStoneOre_lit_Id; -const int Tile::notGate_off_Id; -const int Tile::notGate_on_Id; +const int Tile::redstoneTorch_off_Id; +const int Tile::redstoneTorch_on_Id; const int Tile::button_stone_Id; const int Tile::topSnow_Id; const int Tile::ice_Id; @@ -1565,23 +1638,23 @@ const int Tile::snow_Id; const int Tile::cactus_Id; const int Tile::clay_Id; const int Tile::reeds_Id; -const int Tile::recordPlayer_Id; +const int Tile::jukebox_Id; const int Tile::fence_Id; const int Tile::pumpkin_Id; -const int Tile::hellRock_Id; -const int Tile::hellSand_Id; -const int Tile::lightGem_Id; +const int Tile::netherRack_Id; +const int Tile::soulsand_Id; +const int Tile::glowstone_Id; const int Tile::portalTile_Id; const int Tile::litPumpkin_Id; const int Tile::cake_Id; const int Tile::diode_off_Id; const int Tile::diode_on_Id; -const int Tile::aprilFoolsJoke_Id; +const int Tile::stained_glass_Id; const int Tile::trapdoor_Id; const int Tile::monsterStoneEgg_Id; -const int Tile::stoneBrickSmooth_Id; -const int Tile::hugeMushroom1_Id; -const int Tile::hugeMushroom2_Id; +const int Tile::stoneBrick_Id; +const int Tile::hugeMushroom_brown_Id; +const int Tile::hugeMushroom_red_Id; const int Tile::ironFence_Id; const int Tile::thinGlass_Id; const int Tile::melon_Id; @@ -1590,7 +1663,7 @@ const int Tile::melonStem_Id; const int Tile::vine_Id; const int Tile::fenceGate_Id; const int Tile::stairs_bricks_Id; -const int Tile::stairs_stoneBrickSmooth_Id; +const int Tile::stairs_stoneBrick_Id; const int Tile::mycel_Id; const int Tile::waterLily_Id; const int Tile::netherBrick_Id; @@ -1602,7 +1675,7 @@ const int Tile::brewingStand_Id; const int Tile::cauldron_Id; const int Tile::endPortalTile_Id; const int Tile::endPortalFrameTile_Id; -const int Tile::whiteStone_Id; +const int Tile::endStone_Id; const int Tile::dragonEgg_Id; const int Tile::redstoneLight_Id; const int Tile::redstoneLight_lit_Id; diff --git a/Minecraft.World/Tile.h b/Minecraft.World/Tile.h index fa2f5786..142b32e6 100644 --- a/Minecraft.World/Tile.h +++ b/Minecraft.World/Tile.h @@ -25,10 +25,13 @@ class RedStoneDustTile; class RepeaterTile; class CauldronTile; class TripWireSourceTile; +class BeaconTile; +class ComparatorTile; +class DaylightDetectorTile; class Random; class HitResult; class Level; - +class HopperTile; class Player; class LevelSource; class Mob; @@ -63,9 +66,22 @@ public: static void ReleaseThreadStorage(); public: - static const int TILE_NUM_COUNT = 4096; - static const int TILE_NUM_MASK = 0xfff; // 4096 - 1 - static const int TILE_NUM_SHIFT = 12; // 4096 is 12 bits + static const int TILE_NUM_COUNT = 4096; + static const int TILE_NUM_MASK = 0xfff; // 4096 - 1 + static const int TILE_NUM_SHIFT = 12; // 4096 is 12 bits + + // tile update flags + // neighbors: notify neighbors the block changed + static const int UPDATE_NEIGHBORS = (1 << 0); + // clients: send tile update over network connections + static const int UPDATE_CLIENTS = (1 << 1); + // invisible: this update is invisible, so don't rebuild graphics + static const int UPDATE_INVISIBLE = (1 << 2); + // clients: send tile update over network connections + static const int UPDATE_INVISIBLE_NO_LIGHT = (1 << 3) | UPDATE_INVISIBLE; + + static const int UPDATE_NONE = UPDATE_INVISIBLE; + static const int UPDATE_ALL = UPDATE_NEIGHBORS | UPDATE_CLIENTS; private: // 4J Stu - Was const but had to change it so that we can initialise it in TileStaticInit @@ -73,21 +89,23 @@ private: protected: static const float INDESTRUCTIBLE_DESTROY_TIME; + wstring iconName; + public: class SoundType { public: -// wstring name; -// wstring breakSound; -// wstring stepSound; + // wstring name; + // wstring breakSound; + // wstring stepSound; eMATERIALSOUND_TYPE eMaterialSound; int iBreakSound,iStepSound,iPlaceSound; - float volume; - float pitch; + float volume; + float pitch; + + SoundType(eMATERIALSOUND_TYPE eMaterialSound, float volume, float pitch, int iBreakSound = -1, int iPlaceSound = -1); - SoundType(eMATERIALSOUND_TYPE eMaterialSound, float volume, float pitch, int iBreakSound = -1, int iPlaceSound = -1); - float getVolume() const; float getPitch() const; //wstring getBreakSound() const { return breakSound; } @@ -95,38 +113,38 @@ public: int getBreakSound() const; int getStepSound() const; int getPlaceSound() const; - }; - - static SoundType *SOUND_NORMAL; - static SoundType *SOUND_WOOD; - static SoundType *SOUND_GRAVEL; - static SoundType *SOUND_GRASS; - static SoundType *SOUND_STONE; - static SoundType *SOUND_METAL; - static SoundType *SOUND_GLASS; - static SoundType *SOUND_CLOTH; - static SoundType *SOUND_SAND; + }; + + static SoundType *SOUND_NORMAL; + static SoundType *SOUND_WOOD; + static SoundType *SOUND_GRAVEL; + static SoundType *SOUND_GRASS; + static SoundType *SOUND_STONE; + static SoundType *SOUND_METAL; + static SoundType *SOUND_GLASS; + static SoundType *SOUND_CLOTH; + static SoundType *SOUND_SAND; static SoundType *SOUND_SNOW; static SoundType *SOUND_LADDER; static SoundType *SOUND_ANVIL; - static const int SHAPE_INVISIBLE = -1; - static const int SHAPE_BLOCK = 0; - static const int SHAPE_CROSS_TEXTURE = 1; - static const int SHAPE_TORCH = 2; - static const int SHAPE_FIRE = 3; - static const int SHAPE_WATER = 4; - static const int SHAPE_RED_DUST = 5; - static const int SHAPE_ROWS = 6; - static const int SHAPE_DOOR = 7; - static const int SHAPE_LADDER = 8; - static const int SHAPE_RAIL = 9; - static const int SHAPE_STAIRS = 10; - static const int SHAPE_FENCE = 11; - static const int SHAPE_LEVER = 12; - static const int SHAPE_CACTUS = 13; - static const int SHAPE_BED = 14; - static const int SHAPE_DIODE = 15; + static const int SHAPE_INVISIBLE = -1; + static const int SHAPE_BLOCK = 0; + static const int SHAPE_CROSS_TEXTURE = 1; + static const int SHAPE_TORCH = 2; + static const int SHAPE_FIRE = 3; + static const int SHAPE_WATER = 4; + static const int SHAPE_RED_DUST = 5; + static const int SHAPE_ROWS = 6; + static const int SHAPE_DOOR = 7; + static const int SHAPE_LADDER = 8; + static const int SHAPE_RAIL = 9; + static const int SHAPE_STAIRS = 10; + static const int SHAPE_FENCE = 11; + static const int SHAPE_LEVER = 12; + static const int SHAPE_CACTUS = 13; + static const int SHAPE_BED = 14; + static const int SHAPE_REPEATER = 15; static const int SHAPE_PISTON_BASE = 16; static const int SHAPE_PISTON_EXTENSION = 17; static const int SHAPE_IRON_FENCE = 18; @@ -147,120 +165,135 @@ public: static const int SHAPE_FLOWER_POT = 33; static const int SHAPE_BEACON = 34; static const int SHAPE_ANVIL = 35; + static const int SHAPE_DIODE = 36; + static const int SHAPE_COMPARATOR = 37; + static const int SHAPE_HOPPER = 38; static const int SHAPE_QUARTZ = 39; + static const int SHAPE_THIN_PANE = 40; - static Tile **tiles; + static const int SHAPE_COUNT = 41; + + static Tile **tiles; static bool mipmapEnable[TILE_NUM_COUNT]; - static bool solid[TILE_NUM_COUNT]; - static int lightBlock[TILE_NUM_COUNT]; - static bool transculent[TILE_NUM_COUNT]; - static int lightEmission[TILE_NUM_COUNT]; - static unsigned char _sendTileData[TILE_NUM_COUNT]; // 4J - was bool, changed to bitfield so we can indicate which bits are important to be sent + static bool solid[TILE_NUM_COUNT]; + static int lightBlock[TILE_NUM_COUNT]; + static bool transculent[TILE_NUM_COUNT]; + static int lightEmission[TILE_NUM_COUNT]; + static unsigned char _sendTileData[TILE_NUM_COUNT]; // 4J - was bool, changed to bitfield so we can indicate which bits are important to be sent static bool propagate[TILE_NUM_COUNT]; // 4J - this array of simple constants made so the compiler can optimise references to Ids that were previous of the form Tile::->id, and are now simply Tile::whatever_Id - static const int rock_Id = 1; - static const int grass_Id = 2; - static const int dirt_Id = 3; - static const int stoneBrick_Id = 4; - static const int wood_Id = 5; - static const int sapling_Id = 6; - static const int unbreakable_Id = 7; - static const int water_Id = 8; - static const int calmWater_Id = 9; - static const int lava_Id = 10; - static const int calmLava_Id = 11; - static const int sand_Id = 12; - static const int gravel_Id = 13; - static const int goldOre_Id = 14; - static const int ironOre_Id = 15; - static const int coalOre_Id = 16; - static const int treeTrunk_Id = 17; - static const int leaves_Id = 18; - static const int sponge_Id = 19; - static const int glass_Id = 20; - static const int lapisOre_Id = 21; - static const int lapisBlock_Id = 22; - static const int dispenser_Id = 23; - static const int sandStone_Id = 24; - static const int musicBlock_Id = 25; - static const int bed_Id = 26; - static const int goldenRail_Id = 27; - static const int detectorRail_Id = 28; + static const int stone_Id = 1; + static const int grass_Id = 2; + static const int dirt_Id = 3; + static const int cobblestone_Id = 4; + static const int wood_Id = 5; + static const int sapling_Id = 6; + static const int unbreakable_Id = 7; + static const int water_Id = 8; + static const int calmWater_Id = 9; + static const int lava_Id = 10; + + static const int calmLava_Id = 11; + static const int sand_Id = 12; + static const int gravel_Id = 13; + static const int goldOre_Id = 14; + static const int ironOre_Id = 15; + static const int coalOre_Id = 16; + static const int treeTrunk_Id = 17; + static const int leaves_Id = 18; + static const int sponge_Id = 19; + static const int glass_Id = 20; + + static const int lapisOre_Id = 21; + static const int lapisBlock_Id = 22; + static const int dispenser_Id = 23; + static const int sandStone_Id = 24; + static const int noteblock_Id = 25; + static const int bed_Id = 26; + static const int goldenRail_Id = 27; + static const int detectorRail_Id = 28; static const int pistonStickyBase_Id = 29; static const int web_Id = 30; - static const int tallgrass_Id = 31; - static const int deadBush_Id = 32; + + static const int tallgrass_Id = 31; + static const int deadBush_Id = 32; static const int pistonBase_Id = 33; static const int pistonExtensionPiece_Id = 34; - static const int cloth_Id = 35; + static const int wool_Id = 35; static const int pistonMovingPiece_Id = 36; - static const int flower_Id = 37; - static const int rose_Id = 38; - static const int mushroom1_Id = 39; - static const int mushroom2_Id = 40; - static const int goldBlock_Id = 41; - static const int ironBlock_Id = 42; - static const int stoneSlab_Id = 43; - static const int stoneSlabHalf_Id = 44; - static const int redBrick_Id = 45; - static const int tnt_Id = 46; - static const int bookshelf_Id = 47; - static const int mossStone_Id = 48; - static const int obsidian_Id = 49; - static const int torch_Id = 50; - static const int fire_Id = 51; - static const int mobSpawner_Id = 52; - static const int stairs_wood_Id = 53; - static const int chest_Id = 54; - static const int redStoneDust_Id = 55; - static const int diamondOre_Id = 56; - static const int diamondBlock_Id = 57; - static const int workBench_Id = 58; - static const int crops_Id = 59; - static const int farmland_Id = 60; - static const int furnace_Id = 61; - static const int furnace_lit_Id = 62; - static const int sign_Id = 63; - static const int door_wood_Id = 64; - static const int ladder_Id = 65; - static const int rail_Id = 66; - static const int stairs_stone_Id = 67; - static const int wallSign_Id = 68; - static const int lever_Id = 69; - static const int pressurePlate_stone_Id = 70; - static const int door_iron_Id = 71; - static const int pressurePlate_wood_Id = 72; - static const int redStoneOre_Id = 73; - static const int redStoneOre_lit_Id = 74; - static const int notGate_off_Id = 75; - static const int notGate_on_Id = 76; - static const int button_stone_Id = 77; - static const int topSnow_Id = 78; - static const int ice_Id = 79; - static const int snow_Id = 80; - static const int cactus_Id = 81; - static const int clay_Id = 82; - static const int reeds_Id = 83; - static const int recordPlayer_Id = 84; - static const int fence_Id = 85; - static const int pumpkin_Id = 86; - static const int hellRock_Id = 87; - static const int hellSand_Id = 88; - static const int lightGem_Id = 89; - static const int portalTile_Id = 90; - static const int litPumpkin_Id = 91; - static const int cake_Id = 92; - static const int diode_off_Id = 93; - static const int diode_on_Id = 94; - static const int aprilFoolsJoke_Id = 95; - static const int trapdoor_Id = 96; - + static const int flower_Id = 37; + static const int rose_Id = 38; + static const int mushroom_brown_Id = 39; + static const int mushroom_red_Id = 40; + + static const int goldBlock_Id = 41; + static const int ironBlock_Id = 42; + static const int stoneSlab_Id = 43; + static const int stoneSlabHalf_Id = 44; + static const int redBrick_Id = 45; + static const int tnt_Id = 46; + static const int bookshelf_Id = 47; + static const int mossyCobblestone_Id = 48; + static const int obsidian_Id = 49; + static const int torch_Id = 50; + + static const int fire_Id = 51; + static const int mobSpawner_Id = 52; + static const int stairs_wood_Id = 53; + static const int chest_Id = 54; + static const int redStoneDust_Id = 55; + static const int diamondOre_Id = 56; + static const int diamondBlock_Id = 57; + static const int workBench_Id = 58; + static const int wheat_Id = 59; + static const int farmland_Id = 60; + + static const int furnace_Id = 61; + static const int furnace_lit_Id = 62; + static const int sign_Id = 63; + static const int door_wood_Id = 64; + static const int ladder_Id = 65; + static const int rail_Id = 66; + static const int stairs_stone_Id = 67; + static const int wallSign_Id = 68; + static const int lever_Id = 69; + static const int pressurePlate_stone_Id = 70; + + static const int door_iron_Id = 71; + static const int pressurePlate_wood_Id = 72; + static const int redStoneOre_Id = 73; + static const int redStoneOre_lit_Id = 74; + static const int redstoneTorch_off_Id = 75; + static const int redstoneTorch_on_Id = 76; + static const int button_stone_Id = 77; + static const int topSnow_Id = 78; + static const int ice_Id = 79; + static const int snow_Id = 80; + + static const int cactus_Id = 81; + static const int clay_Id = 82; + static const int reeds_Id = 83; + static const int jukebox_Id = 84; + static const int fence_Id = 85; + static const int pumpkin_Id = 86; + static const int netherRack_Id = 87; + static const int soulsand_Id = 88; + static const int glowstone_Id = 89; + static const int portalTile_Id = 90; + + static const int litPumpkin_Id = 91; + static const int cake_Id = 92; + static const int diode_off_Id = 93; + static const int diode_on_Id = 94; + static const int stained_glass_Id = 95; + static const int trapdoor_Id = 96; static const int monsterStoneEgg_Id = 97; - static const int stoneBrickSmooth_Id = 98; - static const int hugeMushroom1_Id = 99; - static const int hugeMushroom2_Id = 100; + static const int stoneBrick_Id = 98; + static const int hugeMushroom_brown_Id = 99; + static const int hugeMushroom_red_Id = 100; + static const int ironFence_Id = 101; static const int thinGlass_Id = 102; static const int melon_Id = 103; @@ -269,9 +302,9 @@ public: static const int vine_Id = 106; static const int fenceGate_Id = 107; static const int stairs_bricks_Id = 108; - static const int stairs_stoneBrickSmooth_Id = 109; - + static const int stairs_stoneBrick_Id = 109; static const int mycel_Id = 110; + static const int waterLily_Id = 111; static const int netherBrick_Id = 112; static const int netherFence_Id = 113; @@ -282,140 +315,158 @@ public: static const int cauldron_Id = 118; static const int endPortalTile_Id = 119; static const int endPortalFrameTile_Id = 120; - static const int whiteStone_Id = 121; + + static const int endStone_Id = 121; static const int dragonEgg_Id = 122; static const int redstoneLight_Id = 123; static const int redstoneLight_lit_Id = 124; - - static const int woodSlab_Id = 125; static const int woodSlabHalf_Id = 126; static const int cocoa_Id = 127; static const int stairs_sandstone_Id = 128; - static const int stairs_sprucewood_Id = 134; - static const int stairs_birchwood_Id = 135; - static const int stairs_junglewood_Id = 136; static const int emeraldOre_Id = 129; static const int enderChest_Id = 130; + static const int tripWireSource_Id = 131; static const int tripWire_Id = 132; static const int emeraldBlock_Id = 133; - + static const int stairs_sprucewood_Id = 134; + static const int stairs_birchwood_Id = 135; + static const int stairs_junglewood_Id = 136; + static const int commandBlock_Id = 137; + static const int beacon_Id = 138; static const int cobbleWall_Id = 139; static const int flowerPot_Id = 140; + static const int carrots_Id = 141; static const int potatoes_Id = 142; - static const int anvil_Id = 145; static const int button_wood_Id = 143; static const int skull_Id = 144; + static const int anvil_Id = 145; + static const int chest_trap_Id = 146; + static const int weightedPlate_light_Id = 147; + static const int weightedPlate_heavy_Id = 148; + static const int comparator_off_Id = 149; + static const int comparator_on_Id = 150; + + static const int daylightDetector_Id = 151; + static const int redstoneBlock_Id = 152; static const int netherQuartz_Id = 153; + static const int hopper_Id = 154; static const int quartzBlock_Id = 155; static const int stairs_quartz_Id = 156; + static const int activatorRail_Id = 157; + static const int dropper_Id = 158; + static const int clayHardened_colored_Id = 159; + static const int stained_glass_pane_Id = 160; + static const int hayBlock_Id = 170; static const int woolCarpet_Id = 171; - - - static Tile *rock; - static GrassTile *grass; - static Tile *dirt; - static Tile *stoneBrick; - static Tile *wood; - static Tile *sapling; - static Tile *unbreakable; - static LiquidTile *water; - static Tile *calmWater; - static LiquidTile *lava; - static Tile *calmLava; - static Tile *sand; - static Tile *gravel; - static Tile *goldOre; - static Tile *ironOre; - static Tile *coalOre; - static Tile *treeTrunk; - static LeafTile *leaves; - static Tile *sponge; - static Tile *glass; - static Tile *lapisOre; - static Tile *lapisBlock; - static Tile *dispenser; - static Tile *sandStone; - static Tile *musicBlock; - static Tile *bed; - static Tile *goldenRail; - static Tile *detectorRail; + static const int clayHardened_Id = 172; + static const int coalBlock_Id = 173; + + + static Tile *stone; + static GrassTile *grass; + static Tile *dirt; + static Tile *cobblestone; + static Tile *wood; + static Tile *sapling; + static Tile *unbreakable; + static LiquidTile *water; + static Tile *calmWater; + static LiquidTile *lava; + static Tile *calmLava; + static Tile *sand; + static Tile *gravel; + static Tile *goldOre; + static Tile *ironOre; + static Tile *coalOre; + static Tile *treeTrunk; + static LeafTile *leaves; + static Tile *sponge; + static Tile *glass; + static Tile *lapisOre; + static Tile *lapisBlock; + static Tile *dispenser; + static Tile *sandStone; + static Tile *noteblock; + static Tile *bed; + static Tile *goldenRail; + static Tile *detectorRail; static PistonBaseTile *pistonStickyBase; - static Tile *web; - static TallGrass *tallgrass; - static DeadBushTile *deadBush; - static PistonBaseTile *pistonBase; - static PistonExtensionTile *pistonExtension; - static Tile *cloth; - static PistonMovingPiece *pistonMovingPiece; - static Bush *flower; - static Bush *rose; - static Bush *mushroom1; - static Bush *mushroom2; - static Tile *goldBlock; - static Tile *ironBlock; -// static Tile *stoneSlab; -// static Tile *stoneSlabHalf; - static Tile *redBrick; - static Tile *tnt; - static Tile *bookshelf; - static Tile *mossStone; - static Tile *obsidian; - static Tile *torch; - static FireTile *fire; - static Tile *mobSpawner; - static Tile *stairs_wood; - static ChestTile *chest; - static RedStoneDustTile *redStoneDust; - static Tile *diamondOre; - static Tile *diamondBlock; - static Tile *workBench; - static Tile *crops; - static Tile *farmland; - static Tile *furnace; - static Tile *furnace_lit; - static Tile *sign; - static Tile *door_wood; - static Tile *ladder; - static Tile *rail; - static Tile *stairs_stone; - static Tile *wallSign; - static Tile *lever; - static Tile *pressurePlate_stone; - static Tile *door_iron; - static Tile *pressurePlate_wood; - static Tile *redStoneOre; - static Tile *redStoneOre_lit; - static Tile *notGate_off; - static Tile *notGate_on; - static Tile *button; - static Tile *topSnow; - static Tile *ice; - static Tile *snow; - static Tile *cactus; - static Tile *clay; - static Tile *reeds; - static Tile *recordPlayer; - static Tile *fence; - static Tile *pumpkin; - static Tile *hellRock; - static Tile *hellSand; - static Tile *lightGem; - static PortalTile *portalTile; - static Tile *litPumpkin; - static Tile *cake; - static RepeaterTile *diode_off; - static RepeaterTile *diode_on; - static Tile *aprilFoolsJoke; - static Tile *trapdoor; + static Tile *web; + static TallGrass *tallgrass; + static DeadBushTile *deadBush; + static PistonBaseTile *pistonBase; + static PistonExtensionTile *pistonExtension; + static Tile *wool; + static PistonMovingPiece *pistonMovingPiece; + static Bush *flower; + static Bush *rose; + static Bush *mushroom_brown; + static Bush *mushroom_red; + static Tile *goldBlock; + static Tile *ironBlock; + // static Tile *stoneSlab; + // static Tile *stoneSlabHalf; + static Tile *redBrick; + static Tile *tnt; + static Tile *bookshelf; + static Tile *mossyCobblestone; + static Tile *obsidian; + static Tile *torch; + static FireTile *fire; + static Tile *mobSpawner; + static Tile *stairs_wood; + static ChestTile *chest; + static RedStoneDustTile *redStoneDust; + static Tile *diamondOre; + static Tile *diamondBlock; + static Tile *workBench; + static Tile *wheat; + static Tile *farmland; + static Tile *furnace; + static Tile *furnace_lit; + static Tile *sign; + static Tile *door_wood; + static Tile *ladder; + static Tile *rail; + static Tile *stairs_stone; + static Tile *wallSign; + static Tile *lever; + static Tile *pressurePlate_stone; + static Tile *door_iron; + static Tile *pressurePlate_wood; + static Tile *redStoneOre; + static Tile *redStoneOre_lit; + static Tile *redstoneTorch_off; + static Tile *redstoneTorch_on; + static Tile *button; + static Tile *topSnow; + static Tile *ice; + static Tile *snow; + static Tile *cactus; + static Tile *clay; + static Tile *reeds; + static Tile *jukebox; + static Tile *fence; + static Tile *pumpkin; + static Tile *netherRack; + static Tile *soulsand; + static Tile *glowstone; + static PortalTile *portalTile; + static Tile *litPumpkin; + static Tile *cake; + static RepeaterTile *diode_off; + static RepeaterTile *diode_on; + static Tile *stained_glass; + static Tile *trapdoor; static Tile *monsterStoneEgg; - static Tile *stoneBrickSmooth; - static Tile *hugeMushroom1; - static Tile *hugeMushroom2; + static Tile *stoneBrick; + static Tile *hugeMushroom_brown; + static Tile *hugeMushroom_red; static Tile *ironFence; static Tile *thinGlass; static Tile *melon; @@ -426,19 +477,19 @@ public: static Tile *stairs_bricks; static Tile *stairs_stoneBrickSmooth; - static MycelTile *mycel; - static Tile *waterLily; - static Tile *netherBrick; - static Tile *netherFence; - static Tile *stairs_netherBricks; - static Tile *netherStalk; - static Tile *enchantTable; - static Tile *brewingStand; - static CauldronTile *cauldron; - static Tile *endPortalTile; - static Tile *endPortalFrameTile; - static Tile *whiteStone; - static Tile *dragonEgg; + static MycelTile *mycel; + static Tile *waterLily; + static Tile *netherBrick; + static Tile *netherFence; + static Tile *stairs_netherBricks; + static Tile *netherStalk; + static Tile *enchantTable; + static Tile *brewingStand; + static CauldronTile *cauldron; + static Tile *endPortalTile; + static Tile *endPortalFrameTile; + static Tile *endStone; + static Tile *dragonEgg; static Tile *redstoneLight; static Tile *redstoneLight_lit; @@ -446,6 +497,8 @@ public: static Tile *woodStairsDark; static Tile *woodStairsBirch; static Tile *woodStairsJungle; + static Tile *commandBlock; + static BeaconTile *beacon; static Tile *button_wood; static HalfSlabTile *woodSlab; static HalfSlabTile *woodSlabHalf; @@ -456,7 +509,7 @@ public: static TripWireSourceTile *tripWireSource; static Tile *tripWire; static Tile *emeraldBlock; - + static Tile *cocoa; static Tile *skull; @@ -464,63 +517,78 @@ public: static Tile *flowerPot; static Tile *carrots; static Tile *potatoes; - static Tile *anvil; + static Tile *anvil; + static Tile *chest_trap; + static Tile *weightedPlate_light; + static Tile *weightedPlate_heavy; + static ComparatorTile *comparator_off; + static ComparatorTile *comparator_on; + + static DaylightDetectorTile *daylightDetector; + static Tile *redstoneBlock; + static Tile *netherQuartz; + static HopperTile *hopper; static Tile *quartzBlock; static Tile *stairs_quartz; + static Tile *activatorRail; + static Tile *dropper; + static Tile *clayHardened_colored; + static Tile *stained_glass_pane; + static Tile *hayBlock; static Tile *woolCarpet; + static Tile *clayHardened; + static Tile *coalBlock; static void staticCtor(); - int id; + int id; protected: - float destroySpeed; - float explosionResistance; - bool isInventoryItem; - bool collectStatistics; + float destroySpeed; + float explosionResistance; + bool isInventoryItem; + bool collectStatistics; bool _isTicking; bool _isEntityTile; int m_iMaterial; int m_iBaseItemType; // 4J Stu - Removed this in favour of a TLS version - //double xx0, yy0, zz0, xx1, yy1, zz1; + //double xx0, yy0, zz0, xx1, yy1, zz1; public: - const SoundType *soundType; + const SoundType *soundType; - float gravity; - Material *material; - float friction; + float gravity; + Material *material; + float friction; private: - unsigned int descriptionId; - unsigned int useDescriptionId; // 4J Added - - wstring m_textureName; + unsigned int descriptionId; + unsigned int useDescriptionId; // 4J Added protected: Icon *icon; protected: void _init(int id, Material *material, bool isSolidRender); - Tile(int id, Material *material, bool isSolidRender = true); + Tile(int id, Material *material, bool isSolidRender = true); virtual ~Tile() {} protected: - virtual Tile *sendTileData(unsigned char importantMask=15); // 4J - added importantMask to indicate which bits in the data are important + virtual Tile *sendTileData(unsigned char importantMask=15); // 4J - added importantMask to indicate which bits in the data are important protected: - virtual void init(); - virtual Tile *setSoundType(const SoundType *soundType); - virtual Tile *setLightBlock(int i); - virtual Tile *setLightEmission(float f); - virtual Tile *setExplodeable(float explosionResistance); + virtual void init(); + virtual Tile *setSoundType(const SoundType *soundType); + virtual Tile *setLightBlock(int i); + virtual Tile *setLightEmission(float f); + virtual Tile *setExplodeable(float explosionResistance); Tile *setBaseItemTypeAndMaterial(int iType,int iMaterial); public: static bool isSolidBlockingTile(int t); - virtual bool isCubeShaped(); + virtual bool isCubeShaped(); virtual bool isPathfindable(LevelSource *level, int x, int y, int z); - virtual int getRenderShape(); + virtual int getRenderShape(); // 4J-PB added int getBaseItemType(); int getMaterial(); @@ -530,103 +598,103 @@ protected: public: virtual float getDestroySpeed(Level *level, int x, int y, int z); protected: - virtual Tile *setTicking(bool tick); + virtual Tile *setTicking(bool tick); virtual Tile *disableMipmap(); public: virtual bool isTicking(); virtual bool isEntityTile(); virtual void setShape(float x0, float y0, float z0, float x1, float y1, float z1); - virtual float getBrightness(LevelSource *level, int x, int y, int z); + virtual float getBrightness(LevelSource *level, int x, int y, int z); virtual int getLightColor(LevelSource *level, int x, int y, int z, int tileId=-1); // 4J - brought forward from 1.8.2 - static bool isFaceVisible(Level *level, int x, int y, int z, int f); - virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); - virtual bool isSolidFace(LevelSource *level, int x, int y, int z, int face); - virtual Icon *getTexture(LevelSource *level, int x, int y, int z, int face); - virtual Icon *getTexture(int face, int data); - virtual Icon *getTexture(int face); - virtual AABB *getTileAABB(Level *level, int x, int y, int z); + static bool isFaceVisible(Level *level, int x, int y, int z, int f); + virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); + virtual bool isSolidFace(LevelSource *level, int x, int y, int z, int face); + virtual Icon *getTexture(LevelSource *level, int x, int y, int z, int face); + virtual Icon *getTexture(int face, int data); + virtual Icon *getTexture(int face); + virtual AABB *getTileAABB(Level *level, int x, int y, int z); virtual void addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source); - virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual bool isSolidRender(bool isServerLevel = false); // 4J - Added isServerLevel param - virtual bool mayPick(int data, bool liquid); - virtual bool mayPick(); - virtual void tick(Level *level, int x, int y, int z, Random *random); - virtual void animateTick(Level *level, int x, int y, int z, Random *random); - virtual void destroy(Level *level, int x, int y, int z, int data); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); - virtual void addLights(Level *level, int x, int y, int z); - virtual int getTickDelay(); - virtual void onPlace(Level *level, int x, int y, int z); - virtual void onRemove(Level *level, int x, int y, int z, int id, int data); - virtual int getResourceCount(Random *random); - virtual int getResource(int data, Random *random, int playerBonusLevel); - virtual float getDestroyProgress(shared_ptr player, Level *level, int x, int y, int z); - virtual void spawnResources(Level *level, int x, int y, int z, int data, int playerBonusLevel); - virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonusLevel); + virtual AABB *getAABB(Level *level, int x, int y, int z); + virtual bool isSolidRender(bool isServerLevel = false); // 4J - Added isServerLevel param + virtual bool mayPick(int data, bool liquid); + virtual bool mayPick(); + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual void animateTick(Level *level, int x, int y, int z, Random *random); + virtual void destroy(Level *level, int x, int y, int z, int data); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual void addLights(Level *level, int x, int y, int z); + virtual int getTickDelay(Level *level); + virtual void onPlace(Level *level, int x, int y, int z); + virtual void onRemove(Level *level, int x, int y, int z, int id, int data); + virtual int getResourceCount(Random *random); + virtual int getResource(int data, Random *random, int playerBonusLevel); + virtual float getDestroyProgress(shared_ptr player, Level *level, int x, int y, int z); + virtual void spawnResources(Level *level, int x, int y, int z, int data, int playerBonusLevel); + virtual void spawnResources(Level *level, int x, int y, int z, int data, float odds, int playerBonusLevel); protected: virtual void popResource(Level *level, int x, int y, int z, shared_ptr itemInstance); virtual void popExperience(Level *level, int x, int y, int z, int amount); public: virtual int getSpawnResourcesAuxValue(int data); - virtual float getExplosionResistance(shared_ptr source); - virtual HitResult *clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b); + virtual float getExplosionResistance(shared_ptr source); + virtual HitResult *clip(Level *level, int xt, int yt, int zt, Vec3 *a, Vec3 *b); private: - virtual bool containsX(Vec3 *v); - virtual bool containsY(Vec3 *v); - virtual bool containsZ(Vec3 *v); + virtual bool containsX(Vec3 *v); + virtual bool containsY(Vec3 *v); + virtual bool containsZ(Vec3 *v); public: - virtual void wasExploded(Level *level, int x, int y, int z); - virtual int getRenderLayer(); - virtual bool mayPlace(Level *level, int x, int y, int z, int face); - virtual bool mayPlace(Level *level, int x, int y, int z); + virtual void wasExploded(Level *level, int x, int y, int z, Explosion *explosion); + virtual int getRenderLayer(); + virtual bool mayPlace(Level *level, int x, int y, int z, int face, shared_ptr item); + virtual bool mayPlace(Level *level, int x, int y, int z, int face); + virtual bool mayPlace(Level *level, int x, int y, int z); virtual bool TestUse(); virtual bool TestUse(Level *level, int x, int y, int z, shared_ptr player); virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - virtual void stepOn(Level *level, int x, int y, int z, shared_ptr entity); + virtual void stepOn(Level *level, int x, int y, int z, shared_ptr entity); virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); - virtual void prepareRender(Level *level, int x, int y, int z); - virtual void attack(Level *level, int x, int y, int z, shared_ptr player); - virtual void handleEntityInside(Level *level, int x, int y, int z, shared_ptr e, Vec3 *current); - virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param + virtual void prepareRender(Level *level, int x, int y, int z); + virtual void attack(Level *level, int x, int y, int z, shared_ptr player); + virtual void handleEntityInside(Level *level, int x, int y, int z, shared_ptr e, Vec3 *current); + virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param virtual double getShapeX0(); virtual double getShapeX1(); virtual double getShapeY0(); virtual double getShapeY1(); virtual double getShapeZ0(); virtual double getShapeZ1(); - virtual int getColor() const; + virtual int getColor() const; virtual int getColor(int auxData); - virtual int getColor(LevelSource *level, int x, int y, int z); + virtual int getColor(LevelSource *level, int x, int y, int z); virtual int getColor(LevelSource *level, int x, int y, int z, int data); // 4J added - virtual bool getSignal(LevelSource *level, int x, int y, int z); - virtual bool getSignal(LevelSource *level, int x, int y, int z, int dir); - virtual bool isSignalSource(); - virtual void entityInside(Level *level, int x, int y, int z, shared_ptr entity); - virtual bool getDirectSignal(Level *level, int x, int y, int z, int dir); - virtual void updateDefaultShape(); - virtual void playerDestroy(Level *level, shared_ptr player, int x, int y, int z, int data); - virtual bool canSurvive(Level *level, int x, int y, int z); + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); + virtual bool isSignalSource(); + virtual void entityInside(Level *level, int x, int y, int z, shared_ptr entity); + virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir); + virtual void updateDefaultShape(); + virtual void playerDestroy(Level *level, shared_ptr player, int x, int y, int z, int data); + virtual bool canSurvive(Level *level, int x, int y, int z); protected: virtual bool isSilkTouchable(); virtual shared_ptr getSilkTouchItemInstance(int data); public: virtual int getResourceCountForLootBonus(int bonusLevel, Random *random); - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); + virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by, shared_ptr itemInstance); virtual void finalizePlacement(Level *level, int x, int y, int z, int data); - virtual Tile *setDescriptionId(unsigned int id); - virtual wstring getName(); - virtual unsigned int getDescriptionId(int iData = -1); - virtual Tile *setUseDescriptionId(unsigned int id); // 4J Added - virtual unsigned int getUseDescriptionId(); // 4J Added - virtual void triggerEvent(Level *level, int x, int y, int z, int b0, int b1); - virtual bool isCollectStatistics(); + virtual Tile *setDescriptionId(unsigned int id); + virtual wstring getName(); + virtual unsigned int getDescriptionId(int iData = -1); + virtual Tile *setUseDescriptionId(unsigned int id); // 4J Added + virtual unsigned int getUseDescriptionId(); // 4J Added + virtual bool triggerEvent(Level *level, int x, int y, int z, int b0, int b1); + virtual bool isCollectStatistics(); // 4J Added so we can check before we try to add a tile to the tick list if it's actually going to do seomthing // Default to true (it's also checking a bool array) and just override when we need to be able to say no virtual bool shouldTileTick(Level *level, int x,int y,int z) { return true; } protected: - virtual Tile *setNotCollectStatistics(); + virtual Tile *setNotCollectStatistics(); public: virtual int getPistonPushReaction(); virtual float getShadeBrightness(LevelSource *level, int x, int y, int z); // 4J - brought forward from 1.8.2 @@ -637,10 +705,22 @@ public: virtual void onRemoving(Level *level, int x, int y, int z, int data); virtual void handleRain(Level *level, int x, int y, int z); virtual void levelTimeChanged(Level *level, __int64 delta, __int64 newTime); + virtual bool useOwnCloneData(); + virtual bool canInstantlyTick(); + virtual bool dropFromExplosion(Explosion *explosion); + virtual bool isMatching(int id); + static bool isMatching(int tileIdA, int tileIdB); + virtual bool hasAnalogOutputSignal(); + virtual int getAnalogOutputSignal(Level *level, int x, int y, int z, int dir); + +protected: + virtual Tile *setIconName(const wstring &iconName); + virtual wstring getIconName(); + +public: virtual void registerIcons(IconRegister *iconRegister); virtual wstring getTileItemIconName(); - // 4J Using per-item textures now - Tile *setTextureName(const wstring &name); + // AP - added this function so we can generate the faceFlags for a block in a single fast function int getFaceFlags(LevelSource *level, int x, int y, int z); }; diff --git a/Minecraft.World/TileDestructionPacket.cpp b/Minecraft.World/TileDestructionPacket.cpp index e009e0e0..bf05e6e2 100644 --- a/Minecraft.World/TileDestructionPacket.cpp +++ b/Minecraft.World/TileDestructionPacket.cpp @@ -26,7 +26,7 @@ void TileDestructionPacket::read(DataInputStream *dis) x = dis->readInt(); y = dis->readInt(); z = dis->readInt(); - state = dis->read(); + state = dis->readUnsignedByte(); } void TileDestructionPacket::write(DataOutputStream *dos) diff --git a/Minecraft.World/TileEditorOpenPacket.cpp b/Minecraft.World/TileEditorOpenPacket.cpp new file mode 100644 index 00000000..7be8270b --- /dev/null +++ b/Minecraft.World/TileEditorOpenPacket.cpp @@ -0,0 +1,44 @@ +#include "stdafx.h" + +#include "PacketListener.h" +#include "TileEditorOpenPacket.h" + +TileEditorOpenPacket::TileEditorOpenPacket() +{ + editorType = 0; + x = y = z = 0; +} + +TileEditorOpenPacket::TileEditorOpenPacket(int editorType, int x, int y, int z) +{ + this->editorType = editorType; + this->x = x; + this->y = y; + this->z = z; +} + +void TileEditorOpenPacket::handle(PacketListener *listener) +{ + listener->handleTileEditorOpen(shared_from_this()); +} + +void TileEditorOpenPacket::read(DataInputStream *dis) +{ + this->editorType = dis->readByte(); + this->x = dis->readInt(); + this->y = dis->readInt(); + this->z = dis->readInt(); +} + +void TileEditorOpenPacket::write(DataOutputStream *dos) +{ + dos->writeByte(editorType); + dos->writeInt(x); + dos->writeInt(y); + dos->writeInt(z); +} + +int TileEditorOpenPacket::getEstimatedSize() +{ + return 1 + 3 * 4; +} \ No newline at end of file diff --git a/Minecraft.World/TileEditorOpenPacket.h b/Minecraft.World/TileEditorOpenPacket.h new file mode 100644 index 00000000..20a731bb --- /dev/null +++ b/Minecraft.World/TileEditorOpenPacket.h @@ -0,0 +1,25 @@ +#pragma once + +#include "Packet.h" + +class TileEditorOpenPacket : public Packet, public enable_shared_from_this +{ +public: + static const int SIGN = 0; + static const int COMMAND_BLOCK = 1; + + int editorType; + int x, y, z; + + TileEditorOpenPacket(); + TileEditorOpenPacket(int editorType, int x, int y, int z); + + virtual void handle(PacketListener *listener); + virtual void read(DataInputStream *dis); + virtual void write(DataOutputStream *dos); + virtual int getEstimatedSize(); + +public: + static shared_ptr create() { return shared_ptr(new TileEditorOpenPacket()); } + virtual int getId() { return 133; } +}; \ No newline at end of file diff --git a/Minecraft.World/TileEntity.cpp b/Minecraft.World/TileEntity.cpp index 0790601d..ded0c665 100644 --- a/Minecraft.World/TileEntity.cpp +++ b/Minecraft.World/TileEntity.cpp @@ -16,8 +16,9 @@ void TileEntity::staticCtor() TileEntity::setId(FurnaceTileEntity::create, eTYPE_FURNACETILEENTITY, L"Furnace"); TileEntity::setId(ChestTileEntity::create, eTYPE_CHESTTILEENTITY, L"Chest"); TileEntity::setId(EnderChestTileEntity::create, eTYPE_ENDERCHESTTILEENTITY, L"EnderChest"); - TileEntity::setId(RecordPlayerTile::Entity::create, eTYPE_RECORDPLAYERTILE, L"RecordPlayer"); + TileEntity::setId(JukeboxTile::Entity::create, eTYPE_RECORDPLAYERTILE, L"RecordPlayer"); TileEntity::setId(DispenserTileEntity::create, eTYPE_DISPENSERTILEENTITY, L"Trap"); + TileEntity::setId(DropperTileEntity::create, eTYPE_DROPPERTILEENTITY, L"Dropper"); TileEntity::setId(SignTileEntity::create, eTYPE_SIGNTILEENTITY, L"Sign"); TileEntity::setId(MobSpawnerTileEntity::create, eTYPE_MOBSPAWNERTILEENTITY, L"MobSpawner"); TileEntity::setId(MusicTileEntity::create, eTYPE_MUSICTILEENTITY, L"Music"); @@ -25,7 +26,12 @@ void TileEntity::staticCtor() TileEntity::setId(BrewingStandTileEntity::create, eTYPE_BREWINGSTANDTILEENTITY, L"Cauldron"); TileEntity::setId(EnchantmentTableEntity::create, eTYPE_ENCHANTMENTTABLEENTITY, L"EnchantTable"); TileEntity::setId(TheEndPortalTileEntity::create, eTYPE_THEENDPORTALTILEENTITY, L"Airportal"); + TileEntity::setId(CommandBlockEntity::create, eTYPE_COMMANDBLOCKTILEENTITY, L"Control"); + TileEntity::setId(BeaconTileEntity::create, eTYPE_BEACONTILEENTITY, L"Beacon"); TileEntity::setId(SkullTileEntity::create,eTYPE_SKULLTILEENTITY, L"Skull"); + TileEntity::setId(DaylightDetectorTileEntity::create, eTYPE_DAYLIGHTDETECTORTILEENTITY, L"DLDetector"); + TileEntity::setId(HopperTileEntity::create, eTYPE_HOPPERTILEENTITY, L"Hopper"); + TileEntity::setId(ComparatorTileEntity::create, eTYPE_COMPARATORTILEENTITY, L"Comparator"); } void TileEntity::setId(tileEntityCreateFn createFn, eINSTANCEOF clas, wstring id) @@ -123,10 +129,10 @@ int TileEntity::getData() return data; } -void TileEntity::setData(int data) +void TileEntity::setData(int data, int updateFlags) { this->data = data; - level->setData(x, y, z, data); + level->setData(x, y, z, data, updateFlags); } void TileEntity::setChanged() @@ -135,6 +141,7 @@ void TileEntity::setChanged() { data = level->getData(x, y, z); level->tileEntityChanged(x, y, z, shared_from_this()); + if (getTile() != NULL) level->updateNeighbourForOutputSignal(x, y, z, getTile()->id); } } @@ -146,6 +153,11 @@ double TileEntity::distanceToSqr(double xPlayer, double yPlayer, double zPlayer) return xd * xd + yd * yd + zd * zd; } +double TileEntity::getViewDistance() +{ + return 64 * 64; +} + Tile *TileEntity::getTile() { if( tile == NULL ) tile = Tile::tiles[level->getTile(x, y, z)]; @@ -171,14 +183,16 @@ void TileEntity::clearRemoved() { remove = false; } -void TileEntity::triggerEvent(int b0, int b1) + +bool TileEntity::triggerEvent(int b0, int b1) { + return false; } void TileEntity::clearCache() { - tile = NULL; - data = -1; + tile = NULL; + data = -1; } void TileEntity::setRenderRemoveStage( unsigned char stage ) diff --git a/Minecraft.World/TileEntity.h b/Minecraft.World/TileEntity.h index aa3ced4f..8addb3ed 100644 --- a/Minecraft.World/TileEntity.h +++ b/Minecraft.World/TileEntity.h @@ -48,23 +48,24 @@ public: void upgradeRenderRemoveStage(); // 4J added bool shouldRemoveForRender(); // 4J added - Level *getLevel(); - void setLevel(Level *level); - bool hasLevel(); + virtual Level *getLevel(); + virtual void setLevel(Level *level); + virtual bool hasLevel(); virtual void load(CompoundTag *tag); virtual void save(CompoundTag *tag); virtual void tick(); static shared_ptr loadStatic(CompoundTag *tag); - int getData(); - void setData(int data); - void setChanged(); - double distanceToSqr(double xPlayer, double yPlayer, double zPlayer); - Tile *getTile(); + virtual int getData(); + virtual void setData(int data, int updateFlags); + virtual void setChanged(); + virtual double distanceToSqr(double xPlayer, double yPlayer, double zPlayer); + virtual double getViewDistance(); + virtual Tile *getTile(); virtual shared_ptr getUpdatePacket(); virtual bool isRemoved(); virtual void setRemoved(); virtual void clearRemoved(); - virtual void triggerEvent(int b0, int b1); + virtual bool triggerEvent(int b0, int b1); virtual void clearCache(); // 4J Added diff --git a/Minecraft.World/TileEventPacket.cpp b/Minecraft.World/TileEventPacket.cpp index 51e6857c..1bdeaef7 100644 --- a/Minecraft.World/TileEventPacket.cpp +++ b/Minecraft.World/TileEventPacket.cpp @@ -30,8 +30,8 @@ void TileEventPacket::read(DataInputStream *dis) //throws IOException x = dis->readInt(); y = dis->readShort(); z = dis->readInt(); - b0 = dis->read(); - b1 = dis->read(); + b0 = dis->readUnsignedByte(); + b1 = dis->readUnsignedByte(); tile = dis->readShort() & Tile::TILE_NUM_MASK; } diff --git a/Minecraft.World/TileItem.cpp b/Minecraft.World/TileItem.cpp index 8f624bff..ce313dd6 100644 --- a/Minecraft.World/TileItem.cpp +++ b/Minecraft.World/TileItem.cpp @@ -19,13 +19,13 @@ using namespace std; TileItem::TileItem(int id) : Item(id) { - this->tileId = id + 256; - itemIcon = NULL; + this->tileId = id + 256; + itemIcon = NULL; } int TileItem::getTileId() { - return tileId; + return tileId; } int TileItem::getIconType() @@ -50,40 +50,40 @@ bool TileItem::useOn(shared_ptr instance, shared_ptr playe { // 4J-PB - Adding a test only version to allow tooltips to be displayed int currentTile = level->getTile(x, y, z); - if (currentTile == Tile::topSnow_Id) + if (currentTile == Tile::topSnow_Id && (level->getData(x, y, z) & TopSnowTile::HEIGHT_MASK) < 1) { - face = Facing::UP; + face = Facing::UP; } else if (currentTile == Tile::vine_Id || currentTile == Tile::tallgrass_Id || currentTile == Tile::deadBush_Id) { } else { - if (face == 0) y--; - if (face == 1) y++; - if (face == 2) z--; - if (face == 3) z++; - if (face == 4) x--; - if (face == 5) x++; - } + if (face == 0) y--; + if (face == 1) y++; + if (face == 2) z--; + if (face == 3) z++; + if (face == 4) x--; + if (face == 5) x++; + } - if (instance->count == 0) return false; - if (!player->mayBuild(x, y, z)) return false; + if (instance->count == 0) return false; + if (!player->mayUseItemAt(x, y, z, face, instance)) return false; if (y == Level::maxBuildHeight - 1 && Tile::tiles[tileId]->material->isSolid()) return false; int undertile = level->getTile(x,y-1,z); // For 'BodyGuard' achievement. - if (level->mayPlace(tileId, x, y, z, false, face, player)) + if (level->mayPlace(tileId, x, y, z, false, face, player, instance)) { if(!bTestUseOnOnly) { Tile *tile = Tile::tiles[tileId]; // 4J - Adding this from 1.6 - int itemValue = getLevelDataForAuxValue(instance->getAuxValue()); - int dataValue = Tile::tiles[tileId]->getPlacedOnFaceDataValue(level, x, y, z, face, clickX, clickY, clickZ, itemValue); - if (level->setTileAndData(x, y, z, tileId, dataValue)) + int itemValue = getLevelDataForAuxValue(instance->getAuxValue()); + int dataValue = Tile::tiles[tileId]->getPlacedOnFaceDataValue(level, x, y, z, face, clickX, clickY, clickZ, itemValue); + if (level->setTileAndData(x, y, z, tileId, dataValue, Tile::UPDATE_ALL)) { // 4J-JEV: Snow/Iron Golems do not have owners apparently. int newTileId = level->getTile(x,y,z); @@ -108,40 +108,40 @@ bool TileItem::useOn(shared_ptr instance, shared_ptr playe // 4J - Original comment // ok this may look stupid, but neighbor updates can cause the - // placed block to become something else before these methods - // are called + // placed block to become something else before these methods + // are called if (level->getTile(x, y, z) == tileId) { - Tile::tiles[tileId]->setPlacedBy(level, x, y, z, player); - Tile::tiles[tileId]->finalizePlacement(level, x, y, z, dataValue); + Tile::tiles[tileId]->setPlacedBy(level, x, y, z, player, instance); + Tile::tiles[tileId]->finalizePlacement(level, x, y, z, dataValue); } - + // 4J-PB - Java 1.4 change - getStepSound replaced with getPlaceSound //level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, tile->soundType->getStepSound(), (tile->soundType->getVolume() + 1) / 2, tile->soundType->getPitch() * 0.8f); #ifdef _DEBUG int iPlaceSound=tile->soundType->getPlaceSound(); int iStepSound=tile->soundType->getStepSound(); -// char szPlaceSoundName[256]; -// char szStepSoundName[256]; -// Minecraft *pMinecraft = Minecraft::GetInstance(); -// -// if(iPlaceSound==-1) -// { -// strcpy(szPlaceSoundName,"NULL"); -// } -// else -// { -// pMinecraft->soundEngine->GetSoundName(szPlaceSoundName,iPlaceSound); -// } -// if(iStepSound==-1) -// { -// strcpy(szStepSoundName,"NULL"); -// } -// else -// { -// pMinecraft->soundEngine->GetSoundName(szStepSoundName,iStepSound); -// } + // char szPlaceSoundName[256]; + // char szStepSoundName[256]; + // Minecraft *pMinecraft = Minecraft::GetInstance(); + // + // if(iPlaceSound==-1) + // { + // strcpy(szPlaceSoundName,"NULL"); + // } + // else + // { + // pMinecraft->soundEngine->GetSoundName(szPlaceSoundName,iPlaceSound); + // } + // if(iStepSound==-1) + // { + // strcpy(szStepSoundName,"NULL"); + // } + // else + // { + // pMinecraft->soundEngine->GetSoundName(szStepSoundName,iStepSound); + // } //app.DebugPrintf("Place Sound - %s, Step Sound - %s\n",szPlaceSoundName,szStepSoundName); app.DebugPrintf("Place Sound - %d, Step Sound - %d\n",iPlaceSound,iStepSound); @@ -156,9 +156,9 @@ bool TileItem::useOn(shared_ptr instance, shared_ptr playe } } } - return true; - } - return false; + return true; + } + return false; } @@ -179,7 +179,7 @@ bool TileItem::mayPlace(Level *level, int x, int y, int z, int face, shared_ptr< if (face == 5) x++; } - return level->mayPlace(getTileId(), x, y, z, false, face, nullptr); + return level->mayPlace(getTileId(), x, y, z, false, face, nullptr, item); } // 4J Added to colourise some tile types in the hint popups @@ -190,25 +190,25 @@ int TileItem::getColor(int itemAuxValue, int spriteLayer) unsigned int TileItem::getDescriptionId(shared_ptr instance) { - return Tile::tiles[tileId]->getDescriptionId(); + return Tile::tiles[tileId]->getDescriptionId(); } unsigned int TileItem::getDescriptionId(int iData /*= -1*/) { - return Tile::tiles[tileId]->getDescriptionId(iData); + return Tile::tiles[tileId]->getDescriptionId(iData); } unsigned int TileItem::getUseDescriptionId(shared_ptr instance) { - return Tile::tiles[tileId]->getUseDescriptionId(); + return Tile::tiles[tileId]->getUseDescriptionId(); } unsigned int TileItem::getUseDescriptionId() { - return Tile::tiles[tileId]->getUseDescriptionId(); + return Tile::tiles[tileId]->getUseDescriptionId(); } void TileItem::registerIcons(IconRegister *iconRegister) diff --git a/Minecraft.World/TilePlanterItem.cpp b/Minecraft.World/TilePlanterItem.cpp index 883da76e..3a8f0dea 100644 --- a/Minecraft.World/TilePlanterItem.cpp +++ b/Minecraft.World/TilePlanterItem.cpp @@ -12,40 +12,40 @@ TilePlanterItem::TilePlanterItem(int id, Tile *tile) : Item(id) { - this->tileId = tile->id; + this->tileId = tile->id; } bool TilePlanterItem::useOn(shared_ptr instance, shared_ptr player, Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, bool bTestUseOnOnly) { // 4J-PB - Adding a test only version to allow tooltips to be displayed int currentTile = level->getTile(x, y, z); - if (currentTile == Tile::topSnow_Id) + if (currentTile == Tile::topSnow_Id && (level->getData(x, y, z) & TopSnowTile::HEIGHT_MASK) < 1) { - face = Facing::UP; - } + face = Facing::UP; + } else if (currentTile == Tile::vine_Id || currentTile == Tile::tallgrass_Id || currentTile == Tile::deadBush_Id) { } else { - if (face == 0) y--; - if (face == 1) y++; - if (face == 2) z--; - if (face == 3) z++; - if (face == 4) x--; - if (face == 5) x++; - } + if (face == 0) y--; + if (face == 1) y++; + if (face == 2) z--; + if (face == 3) z++; + if (face == 4) x--; + if (face == 5) x++; + } - if (!player->mayBuild(x, y, z)) return false; - if (instance->count == 0) return false; + if (!player->mayUseItemAt(x, y, z, face, instance)) return false; + if (instance->count == 0) return false; - if (level->mayPlace(tileId, x, y, z, false, face, nullptr)) + if (level->mayPlace(tileId, x, y, z, false, face, nullptr, instance)) { if(!bTestUseOnOnly) { Tile *tile = Tile::tiles[tileId]; int dataValue = tile->getPlacedOnFaceDataValue(level, x, y, z, face, clickX, clickY, clickZ, 0); - if (level->setTileAndData(x, y, z, tileId, dataValue)) + if (level->setTileAndData(x, y, z, tileId, dataValue, Tile::UPDATE_ALL)) { // 4J-JEV: Hook for durango 'BlockPlaced' event. player->awardStat(GenericStats::blocksPlaced(tileId),GenericStats::param_blocksPlaced(tileId,instance->getAuxValue(),1)); @@ -56,14 +56,14 @@ bool TilePlanterItem::useOn(shared_ptr instance, shared_ptrgetTile(x, y, z) == tileId) { - Tile::tiles[tileId]->setPlacedBy(level, x, y, z, player); + Tile::tiles[tileId]->setPlacedBy(level, x, y, z, player, instance); Tile::tiles[tileId]->finalizePlacement(level, x, y, z, dataValue); } - level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, tile->soundType->getStepSound(), (tile->soundType->getVolume() + 1) / 2, tile->soundType->getPitch() * 0.8f); + level->playSound(x + 0.5f, y + 0.5f, z + 0.5f, tile->soundType->getPlaceSound(), (tile->soundType->getVolume() + 1) / 2, tile->soundType->getPitch() * 0.8f); // 4J-PB - If we have the debug option on, don't reduce the number of this item - #ifndef _FINAL_BUILD +#ifndef _FINAL_BUILD if(!(app.DebugSettingsOn() && app.GetGameSettingsDebugMask()&(1L<count--; } @@ -76,5 +76,5 @@ bool TilePlanterItem::useOn(shared_ptr instance, shared_ptrreadInt(); - y = dis->read(); + y = dis->readUnsignedByte(); z = dis->readInt(); block = (int)dis->readShort() & 0xffff; diff --git a/Minecraft.World/TimeCommand.cpp b/Minecraft.World/TimeCommand.cpp index e667a420..4ac23c94 100644 --- a/Minecraft.World/TimeCommand.cpp +++ b/Minecraft.World/TimeCommand.cpp @@ -10,6 +10,11 @@ EGameCommand TimeCommand::getId() return eGameCommand_Time; } +int TimeCommand::getPermissionLevel() +{ + return LEVEL_GAMEMASTERS; +} + void TimeCommand::execute(shared_ptr source, byteArray commandData) { ByteArrayInputStream bais(commandData); @@ -56,7 +61,7 @@ void TimeCommand::doSetTime(shared_ptr source, int value) { for (int i = 0; i < MinecraftServer::getInstance()->levels.length; i++) { - MinecraftServer::getInstance()->levels[i]->setTimeAndAdjustTileTicks(value); + MinecraftServer::getInstance()->levels[i]->setDayTime(value); } } @@ -65,7 +70,7 @@ void TimeCommand::doAddTime(shared_ptr source, int value) for (int i = 0; i < MinecraftServer::getInstance()->levels.length; i++) { ServerLevel *level = MinecraftServer::getInstance()->levels[i]; - level->setTimeAndAdjustTileTicks(level->getTime() + value); + level->setDayTime(level->getDayTime() + value); } } diff --git a/Minecraft.World/TimeCommand.h b/Minecraft.World/TimeCommand.h index f87fb27c..20d4ef54 100644 --- a/Minecraft.World/TimeCommand.h +++ b/Minecraft.World/TimeCommand.h @@ -6,6 +6,7 @@ class TimeCommand : public Command { public: virtual EGameCommand getId(); + virtual int getPermissionLevel(); virtual void execute(shared_ptr source, byteArray commandData); protected: diff --git a/Minecraft.World/TntTile.cpp b/Minecraft.World/TntTile.cpp index b422959c..430755fc 100644 --- a/Minecraft.World/TntTile.cpp +++ b/Minecraft.World/TntTile.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.h" #include "net.minecraft.h" @@ -25,22 +26,19 @@ Icon *TntTile::getTexture(int face, int data) void TntTile::onPlace(Level *level, int x, int y, int z) { Tile::onPlace(level, x, y, z); - if (level->hasNeighborSignal(x, y, z) && app.GetGameHostOption(eGameHostOption_TNT)) + if (level->hasNeighborSignal(x, y, z) && app.GetGameHostOption(eGameHostOption_TNT)) { - destroy(level, x, y, z, EXPLODE_BIT); - level->setTile(x, y, z, 0); - } + destroy(level, x, y, z, EXPLODE_BIT); + level->removeTile(x, y, z); + } } void TntTile::neighborChanged(Level *level, int x, int y, int z, int type) { - if (type > 0 && Tile::tiles[type]->isSignalSource()) + if (level->hasNeighborSignal(x, y, z) && app.GetGameHostOption(eGameHostOption_TNT)) { - if (level->hasNeighborSignal(x, y, z) && app.GetGameHostOption(eGameHostOption_TNT)) - { - destroy(level, x, y, z, EXPLODE_BIT); - level->setTile(x, y, z, 0); - } + destroy(level, x, y, z, EXPLODE_BIT); + level->removeTile(x, y, z); } } @@ -49,7 +47,7 @@ int TntTile::getResourceCount(Random *random) return 1; } -void TntTile::wasExploded(Level *level, int x, int y, int z) +void TntTile::wasExploded(Level *level, int x, int y, int z, Explosion *explosion) { // 4J - added - don't every create on the client, I think this must be the cause of a bug reported in the java // version where white tnts are created in the network game @@ -59,13 +57,18 @@ void TntTile::wasExploded(Level *level, int x, int y, int z) // 4J-JEV: Fix for #90934 - Customer Encountered: TU11: Content: Gameplay: TNT blocks are triggered by explosions even though "TNT explodes" option is unchecked. if( level->newPrimedTntAllowed() && app.GetGameHostOption(eGameHostOption_TNT) ) { - shared_ptr primed = shared_ptr( new PrimedTnt(level, x + 0.5f, y + 0.5f, z + 0.5f) ); + shared_ptr primed = shared_ptr( new PrimedTnt(level, x + 0.5f, y + 0.5f, z + 0.5f, explosion->getSourceMob()) ); primed->life = level->random->nextInt(primed->life / 4) + primed->life / 8; level->addEntity(primed); } } void TntTile::destroy(Level *level, int x, int y, int z, int data) +{ + destroy(level, x, y, z, data, nullptr); +} + +void TntTile::destroy(Level *level, int x, int y, int z, int data, shared_ptr source) { if (level->isClientSide) return; @@ -74,9 +77,9 @@ void TntTile::destroy(Level *level, int x, int y, int z, int data) // 4J - added condition to have finite limit of these if( level->newPrimedTntAllowed() && app.GetGameHostOption(eGameHostOption_TNT) ) { - shared_ptr tnt = shared_ptr( new PrimedTnt(level, x + 0.5f, y + 0.5f, z + 0.5f) ); + shared_ptr tnt = shared_ptr( new PrimedTnt(level, x + 0.5f, y + 0.5f, z + 0.5f, source) ); level->addEntity(tnt); - level->playSound(tnt, eSoundType_RANDOM_FUSE, 1, 1.0f); + level->playEntitySound(tnt, eSoundType_RANDOM_FUSE, 1, 1.0f); } } } @@ -86,8 +89,9 @@ bool TntTile::use(Level *level, int x, int y, int z, shared_ptr player, if (soundOnly) return false; if (player->getSelectedItem() != NULL && player->getSelectedItem()->id == Item::flintAndSteel_Id) { - destroy(level, x, y, z, EXPLODE_BIT); - level->setTile(x, y, z, 0); + destroy(level, x, y, z, EXPLODE_BIT, player); + level->removeTile(x, y, z); + player->getSelectedItem()->hurtAndBreak(1, player); return true; } return Tile::use(level, x, y, z, player, clickedFace, clickX, clickY, clickZ); @@ -97,24 +101,23 @@ void TntTile::entityInside(Level *level, int x, int y, int z, shared_ptr { if (entity->GetType() == eTYPE_ARROW && !level->isClientSide) { - // 4J Stu - Don't need to cast this - //shared_ptr arrow = dynamic_pointer_cast(entity); if (entity->isOnFire()) { - destroy(level, x, y, z, EXPLODE_BIT); - level->setTile(x, y, z, 0); + shared_ptr arrow = dynamic_pointer_cast(entity); + destroy(level, x, y, z, EXPLODE_BIT, arrow->owner->instanceof(eTYPE_LIVINGENTITY) ? dynamic_pointer_cast(arrow->owner) : nullptr); + level->removeTile(x, y, z); } } } -shared_ptr TntTile::getSilkTouchItemInstance(int data) -{ - return nullptr; -} - void TntTile::registerIcons(IconRegister *iconRegister) { icon = iconRegister->registerIcon(L"tnt_side"); iconTop = iconRegister->registerIcon(L"tnt_top"); iconBottom = iconRegister->registerIcon(L"tnt_bottom"); +} + +bool TntTile::dropFromExplosion(Explosion *explosion) +{ + return false; } \ No newline at end of file diff --git a/Minecraft.World/TntTile.h b/Minecraft.World/TntTile.h index 27b788c6..ac73e64b 100644 --- a/Minecraft.World/TntTile.h +++ b/Minecraft.World/TntTile.h @@ -12,20 +12,15 @@ public: static const int EXPLODE_BIT = 1; TntTile(int id); - Icon *getTexture(int face, int data); + virtual Icon *getTexture(int face, int data); virtual void onPlace(Level *level, int x, int y, int z); - - void neighborChanged(Level *level, int x, int y, int z, int type); - - int getResourceCount(Random *random); - - void wasExploded(Level *level, int x, int y, int z); - - void destroy(Level *level, int x, int y, int z, int data); - - bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param - - void entityInside(Level *level, int x, int y, int z, shared_ptr entity); - virtual shared_ptr getSilkTouchItemInstance(int data); - void registerIcons(IconRegister *iconRegister); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + virtual int getResourceCount(Random *random); + virtual void wasExploded(Level *level, int x, int y, int z, Explosion *explosion); + virtual void destroy(Level *level, int x, int y, int z, int data); + virtual void destroy(Level *level, int x, int y, int z, int data, shared_ptr source); + virtual bool use(Level *level, int x, int y, int z, shared_ptr player, int clickedFace, float clickX, float clickY, float clickZ, bool soundOnly = false); // 4J added soundOnly param + virtual void entityInside(Level *level, int x, int y, int z, shared_ptr entity); + virtual bool dropFromExplosion(Explosion *explosion); + virtual void registerIcons(IconRegister *iconRegister); }; \ No newline at end of file diff --git a/Minecraft.World/ToggleDownfallCommand.cpp b/Minecraft.World/ToggleDownfallCommand.cpp index 1ae2f3a9..1d0a4d9e 100644 --- a/Minecraft.World/ToggleDownfallCommand.cpp +++ b/Minecraft.World/ToggleDownfallCommand.cpp @@ -12,6 +12,11 @@ EGameCommand ToggleDownfallCommand::getId() return eGameCommand_ToggleDownfall; } +int ToggleDownfallCommand::getPermissionLevel() +{ + return LEVEL_GAMEMASTERS; +} + void ToggleDownfallCommand::execute(shared_ptr source, byteArray commandData) { doToggleDownfall(); diff --git a/Minecraft.World/ToggleDownfallCommand.h b/Minecraft.World/ToggleDownfallCommand.h index 2954962b..2623e8d4 100644 --- a/Minecraft.World/ToggleDownfallCommand.h +++ b/Minecraft.World/ToggleDownfallCommand.h @@ -7,6 +7,7 @@ class ToggleDownfallCommand : public Command { public: virtual EGameCommand getId(); + virtual int getPermissionLevel(); virtual void execute(shared_ptr source, byteArray commandData); protected: diff --git a/Minecraft.World/ToolRecipies.cpp b/Minecraft.World/ToolRecipies.cpp index 8524924b..8ee4bbab 100644 --- a/Minecraft.World/ToolRecipies.cpp +++ b/Minecraft.World/ToolRecipies.cpp @@ -1,7 +1,3 @@ -//package net.minecraft.world.item.crafting; - -//import net.minecraft.world.item.*; -//import net.minecraft.world.level.tile.Tile; #include "stdafx.h" #include "net.minecraft.world.item.h" #include "Tile.h" @@ -29,23 +25,12 @@ wstring ToolRecipies::shapes[][4] = L" #"},// }; -/* - Object[][] map = { - {Tile.wood, Tile.stoneBrick, Item.ironIngot, Item.diamond, Item.goldIngot}, - {Item.pickAxe_wood, Item.pickAxe_stone, Item.pickAxe_iron, Item.pickAxe_diamond, Item.pickAxe_gold}, - {Item.shovel_wood, Item.shovel_stone, Item.shovel_iron, Item.shovel_diamond, Item.shovel_gold}, - {Item.hatchet_wood, Item.hatchet_stone, Item.hatchet_iron, Item.hatchet_diamond, Item.hatchet_gold}, - {Item.hoe_wood, Item.hoe_stone, Item.hoe_iron, Item.hoe_diamond, Item.hoe_gold}, - }; - */ -//#define ADD_OBJECT(a,b) a.push_back(new Object(b)) - void ToolRecipies::_init() { map = new vector [MAX_TOOL_RECIPES]; ADD_OBJECT(map[0],Tile::wood); - ADD_OBJECT(map[0],Tile::stoneBrick); + ADD_OBJECT(map[0],Tile::cobblestone); ADD_OBJECT(map[0],Item::ironIngot); ADD_OBJECT(map[0],Item::diamond); ADD_OBJECT(map[0],Item::goldIngot); diff --git a/Minecraft.World/TopSnowTile.cpp b/Minecraft.World/TopSnowTile.cpp index 9bcf5527..033b4eb2 100644 --- a/Minecraft.World/TopSnowTile.cpp +++ b/Minecraft.World/TopSnowTile.cpp @@ -9,14 +9,13 @@ #include "TopSnowTile.h" const int TopSnowTile::MAX_HEIGHT = 6; - const int TopSnowTile::HEIGHT_MASK = 7; // max 8 steps - TopSnowTile::TopSnowTile(int id) : Tile(id, Material::topSnow,isSolidRender()) { setShape(0, 0, 0, 1, 2 / 16.0f, 1); setTicking(true); + updateShape(0); } void TopSnowTile::registerIcons(IconRegister *iconRegister) @@ -27,12 +26,9 @@ void TopSnowTile::registerIcons(IconRegister *iconRegister) AABB *TopSnowTile::getAABB(Level *level, int x, int y, int z) { int height = level->getData(x, y, z) & HEIGHT_MASK; - if (height >= (MAX_HEIGHT / 2)) - { - ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); - return AABB::newTemp(x + tls->xx0, y + tls->yy0, z + tls->zz0, x + tls->xx1, y + .5f, z + tls->zz1); - } - return NULL; + float offset = 2.0f / SharedConstants::WORLD_RESOLUTION; + ThreadStorage *tls = (ThreadStorage *)TlsGetValue(Tile::tlsIdxShape); + return AABB::newTemp(x + tls->xx0, y + tls->yy0, z + tls->zz0, x + tls->xx1, y + (height * offset), z + tls->zz1); } float TopSnowTile::getHeight(Level *level, int x, int y, int z) @@ -41,19 +37,16 @@ float TopSnowTile::getHeight(Level *level, int x, int y, int z) return 2 * (1 + height) / 16.0f; } - bool TopSnowTile::blocksLight() { return false; } - bool TopSnowTile::isSolidRender(bool isServerLevel) { return false; } - bool TopSnowTile::isCubeShaped() { return false; @@ -79,67 +72,57 @@ void TopSnowTile::updateShape(int data) bool TopSnowTile::mayPlace(Level *level, int x, int y, int z) { int t = level->getTile(x, y - 1, z); + if (t == 0) return false; + if (t == id && (level->getData(x, y - 1, z) & HEIGHT_MASK) == MAX_HEIGHT + 1) return true; // 4J Stu - Assume when placing that this is the server level and we don't care how it's going to be rendered // Fix for #9407 - Gameplay: Destroying a block of snow on top of trees, removes any adjacent snow. - if (t == 0 || (t != Tile::leaves_Id && !Tile::tiles[t]->isSolidRender(true))) return false; + if (t != Tile::leaves_Id && !Tile::tiles[t]->isSolidRender(true)) return false; return level->getMaterial(x, y - 1, z)->blocksMotion(); } - void TopSnowTile::neighborChanged(Level *level, int x, int y, int z, int type) { checkCanSurvive(level, x, y, z); } - bool TopSnowTile::checkCanSurvive(Level *level, int x, int y, int z) { if (!mayPlace(level, x, y, z)) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); return false; } return true; } - void TopSnowTile::playerDestroy(Level *level, shared_ptr player, int x, int y, int z, int data) { int type = Item::snowBall->id; - float s = 0.7f; - double xo = level->random->nextFloat() * s + (1 - s) * 0.5; - double yo = level->random->nextFloat() * s + (1 - s) * 0.5; - double zo = level->random->nextFloat() * s + (1 - s) * 0.5; - shared_ptr item = shared_ptr( new ItemEntity(level, x + xo, y + yo, z + zo, shared_ptr( new ItemInstance(type, 1, 0) ) ) ); - item->throwTime = 10; - level->addEntity(item); - level->setTile(x, y, z, 0); + int height = data & HEIGHT_MASK; + popResource(level, x, y, z, shared_ptr( new ItemInstance(type, height + 1, 0))); + level->removeTile(x, y, z); } - int TopSnowTile::getResource(int data, Random *random, int playerBonusLevel) { return Item::snowBall->id; } - int TopSnowTile::getResourceCount(Random *random) { return 0; } - void TopSnowTile::tick(Level *level, int x, int y, int z, Random *random) { if (level->getBrightness(LightLayer::Block, x, y, z) > 11) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); } } - bool TopSnowTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int face) { if (face == 1) return true; @@ -155,20 +138,20 @@ bool TopSnowTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int // offsetting by the face direction) switch(face) { - case 2: - zz += 1; - break; - case 3: - zz -= 1; - break; - case 4: - xx += 1; - break; - case 5: - xx -= 1; - break; - default: - break; + case 2: + zz += 1; + break; + case 3: + zz -= 1; + break; + case 4: + xx += 1; + break; + case 5: + xx -= 1; + break; + default: + break; } int h1 = level->getData(xx,yy,zz) & HEIGHT_MASK; if( h0 >= h1 ) return false; @@ -178,5 +161,5 @@ bool TopSnowTile::shouldRenderFace(LevelSource *level, int x, int y, int z, int bool TopSnowTile::shouldTileTick(Level *level, int x,int y,int z) { - return level->getBrightness(LightLayer::Block, x, y, z) > 11; + return level->getBrightness(LightLayer::Block, x, y, z) > 11; } diff --git a/Minecraft.World/TorchTile.cpp b/Minecraft.World/TorchTile.cpp index ea1d2ab7..cc377574 100644 --- a/Minecraft.World/TorchTile.cpp +++ b/Minecraft.World/TorchTile.cpp @@ -133,29 +133,34 @@ void TorchTile::onPlace(Level *level, int x, int y, int z) { if (level->isSolidBlockingTileInLoadedChunk(x - 1, y, z, true)) { - level->setData(x, y, z, 1); + level->setData(x, y, z, 1, Tile::UPDATE_CLIENTS); } else if (level->isSolidBlockingTileInLoadedChunk(x + 1, y, z, true)) { - level->setData(x, y, z, 2); + level->setData(x, y, z, 2, Tile::UPDATE_CLIENTS); } else if (level->isSolidBlockingTileInLoadedChunk(x, y, z - 1, true)) { - level->setData(x, y, z, 3); + level->setData(x, y, z, 3, Tile::UPDATE_CLIENTS); } else if (level->isSolidBlockingTileInLoadedChunk(x, y, z + 1, true)) { - level->setData(x, y, z, 4); + level->setData(x, y, z, 4, Tile::UPDATE_CLIENTS); } else if (isConnection(level, x, y - 1, z)) { - level->setData(x, y, z, 5); + level->setData(x, y, z, 5, Tile::UPDATE_CLIENTS); } } checkCanSurvive(level, x, y, z); } void TorchTile::neighborChanged(Level *level, int x, int y, int z, int type) +{ + checkDoPop(level, x, y, z, type); +} + +bool TorchTile::checkDoPop(Level *level, int x, int y, int z, int type) { if (checkCanSurvive(level, x, y, z)) { @@ -170,10 +175,16 @@ void TorchTile::neighborChanged(Level *level, int x, int y, int z, int type) if (replace) { - this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); + return true; } } + else + { + return true; + } + return false; } bool TorchTile::checkCanSurvive(Level *level, int x, int y, int z) @@ -183,7 +194,7 @@ bool TorchTile::checkCanSurvive(Level *level, int x, int y, int z) if (level->getTile(x, y, z) == id) { this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); } return false; } diff --git a/Minecraft.World/TorchTile.h b/Minecraft.World/TorchTile.h index 7e27f2ee..55043c4c 100644 --- a/Minecraft.World/TorchTile.h +++ b/Minecraft.World/TorchTile.h @@ -12,25 +12,28 @@ protected: TorchTile(int id); public: virtual AABB *getAABB(Level *level, int x, int y, int z); - virtual AABB *getTileAABB(Level *level, int x, int y, int z); + virtual AABB *getTileAABB(Level *level, int x, int y, int z); virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param using Tile::setShape; virtual void setShape(int data); - virtual bool isSolidRender(bool isServerLevel = false); - virtual bool isCubeShaped(); - virtual int getRenderShape(); - bool isConnection(Level *level, int x, int y, int z); - virtual bool mayPlace(Level *level, int x, int y, int z); - virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); - virtual void tick(Level *level, int x, int y, int z, Random *random); - virtual void onPlace(Level *level, int x, int y, int z); - virtual void neighborChanged(Level *level, int x, int y, int z, int type); -private: + virtual bool isSolidRender(bool isServerLevel = false); + virtual bool isCubeShaped(); + virtual int getRenderShape(); + virtual bool isConnection(Level *level, int x, int y, int z); + virtual bool mayPlace(Level *level, int x, int y, int z); + virtual int getPlacedOnFaceDataValue(Level *level, int x, int y, int z, int face, float clickX, float clickY, float clickZ, int itemValue); + virtual void tick(Level *level, int x, int y, int z, Random *random); + virtual void onPlace(Level *level, int x, int y, int z); + virtual void neighborChanged(Level *level, int x, int y, int z, int type); + +protected: + virtual bool checkDoPop(Level *level, int x, int y, int z, int type); virtual bool checkCanSurvive(Level *level, int x, int y, int z); + public: virtual HitResult *clip(Level *level, int x, int y, int z, Vec3 *a, Vec3 *b); - virtual void animateTick(Level *level, int xt, int yt, int zt, Random *random); - + virtual void animateTick(Level *level, int xt, int yt, int zt, Random *random); + // 4J Added so we can check before we try to add a tile to the tick list if it's actually going to do seomthing virtual bool shouldTileTick(Level *level, int x,int y,int z); }; diff --git a/Minecraft.World/TrapDoorTile.cpp b/Minecraft.World/TrapDoorTile.cpp index fc9d6580..9b668e3f 100644 --- a/Minecraft.World/TrapDoorTile.cpp +++ b/Minecraft.World/TrapDoorTile.cpp @@ -72,7 +72,14 @@ void TrapDoorTile::setShape(int data) { float r = 3 / 16.0f; - Tile::setShape(0, 0, 0, 1, r, 1); + if ((data & TOP_MASK) != 0) + { + setShape(0, 1 - r, 0, 1, 1, 1); + } + else + { + setShape(0, 0, 0, 1, r, 1); + } if (isOpen(data)) { if ((data & 3) == 0) setShape(0, 0, 1 - r, 1, 1, 1); @@ -85,7 +92,7 @@ void TrapDoorTile::setShape(int data) void TrapDoorTile::attack(Level *level, int x, int y, int z, shared_ptr player) { - use(level, x, y, z, player, 0, 0, 0, 0); + //use(level, x, y, z, player, 0, 0, 0, 0); } // 4J-PB - Adding a TestUse for tooltip display @@ -106,7 +113,7 @@ bool TrapDoorTile::use(Level *level, int x, int y, int z, shared_ptr pla } int dir = level->getData(x, y, z); - level->setData(x, y, z, dir ^ 4); + level->setData(x, y, z, dir ^ 4, Tile::UPDATE_CLIENTS); level->levelEvent(player, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); return true; @@ -120,7 +127,7 @@ void TrapDoorTile::setOpen(Level *level, int x, int y, int z, bool shouldOpen) bool wasOpen = (dir & 4) > 0; if (wasOpen == shouldOpen) return; - level->setData(x, y, z, dir ^ 4); + level->setData(x, y, z, dir ^ 4, Tile::UPDATE_CLIENTS); level->levelEvent(nullptr, LevelEvent::SOUND_OPEN_DOOR, x, y, z, 0); } @@ -140,7 +147,7 @@ void TrapDoorTile::neighborChanged(Level *level, int x, int y, int z, int type) if (!attachesTo(level->getTile(xt, y, zt))) { - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); spawnResources(level, x, y, z, data, 0); } @@ -205,5 +212,5 @@ bool TrapDoorTile::attachesTo(int id) } Tile *tile = Tile::tiles[id]; - return tile != NULL && (tile->material->isSolidBlocking() && tile->isCubeShaped()) || tile == Tile::lightGem || (dynamic_cast(tile) != NULL) || (dynamic_cast(tile) != NULL); + return tile != NULL && (tile->material->isSolidBlocking() && tile->isCubeShaped()) || tile == Tile::glowstone || (dynamic_cast(tile) != NULL) || (dynamic_cast(tile) != NULL); } \ No newline at end of file diff --git a/Minecraft.World/TrapMenu.cpp b/Minecraft.World/TrapMenu.cpp index 5e59c6fe..65757839 100644 --- a/Minecraft.World/TrapMenu.cpp +++ b/Minecraft.World/TrapMenu.cpp @@ -39,7 +39,7 @@ bool TrapMenu::stillValid(shared_ptr player) shared_ptr TrapMenu::quickMoveStack(shared_ptr player, int slotIndex) { shared_ptr clicked = nullptr; - Slot *slot = slots->at(slotIndex); + Slot *slot = slots.at(slotIndex); if (slot != NULL && slot->hasItem()) { shared_ptr stack = slot->getItem(); diff --git a/Minecraft.World/TreeFeature.cpp b/Minecraft.World/TreeFeature.cpp index 0ef4e320..f27258af 100644 --- a/Minecraft.World/TreeFeature.cpp +++ b/Minecraft.World/TreeFeature.cpp @@ -76,7 +76,8 @@ bool TreeFeature::place(Level *level, Random *random, int x, int y, int z) { int zo = zz - (z); if (abs(xo) == offs && abs(zo) == offs && (random->nextInt(2) == 0 || yo == 0)) continue; - if (!Tile::solid[level->getTile(xx, yy, zz)]) placeBlock(level, xx, yy, zz, Tile::leaves_Id, leafType); + int t = level->getTile(xx, yy, zz); + if (t == 0 || t == Tile::leaves_Id) placeBlock(level, xx, yy, zz, Tile::leaves_Id, leafType); } } } diff --git a/Minecraft.World/TreeTile.cpp b/Minecraft.World/TreeTile.cpp index 29871625..642d8fbb 100644 --- a/Minecraft.World/TreeTile.cpp +++ b/Minecraft.World/TreeTile.cpp @@ -7,23 +7,18 @@ #include "TreeTile.h" -const unsigned int TreeTile::TREE_NAMES[TREE_NAMES_LENGTH] = { IDS_TILE_LOG_OAK, +const unsigned int TreeTile::TREE_NAMES[ TreeTile::TREE_NAMES_LENGTH] = { IDS_TILE_LOG_OAK, IDS_TILE_LOG_SPRUCE, IDS_TILE_LOG_BIRCH, IDS_TILE_LOG_JUNGLE }; -const wstring TreeTile::TREE_TEXTURES[] = {L"tree_side", L"tree_spruce", L"tree_birch", L"tree_jungle"}; +const wstring TreeTile::TREE_STRING_NAMES[ TreeTile::TREE_NAMES_LENGTH] = {L"oak", L"spruce", L"birch", L"jungle"}; -TreeTile::TreeTile(int id) : Tile(id, Material::wood) -{ - icons = NULL; - iconTop = NULL; -} +const wstring TreeTile::TREE_TEXTURES[] = {L"tree_side", L"tree_spruce", L"tree_birch", L"tree_jungle"}; -int TreeTile::getRenderShape() +TreeTile::TreeTile(int id) : RotatedPillarTile(id, Material::wood) { - return Tile::SHAPE_TREE; } int TreeTile::getResourceCount(Random *random) @@ -53,58 +48,13 @@ void TreeTile::onRemove(Level *level, int x, int y, int z, int id, int data) int currentData = level->getData(x + xo, y + yo, z + zo); if ((currentData & LeafTile::UPDATE_LEAF_BIT) == 0) { - level->setDataNoUpdate(x + xo, y + yo, z + zo, currentData | LeafTile::UPDATE_LEAF_BIT); + level->setData(x + xo, y + yo, z + zo, currentData | LeafTile::UPDATE_LEAF_BIT, Tile::UPDATE_NONE); } } } } } -void TreeTile::setPlacedBy(Level *level, int x, int y, int z, shared_ptr by) -{ - int type = level->getData(x, y, z) & MASK_TYPE; - int dir = PistonBaseTile::getNewFacing(level, x, y, z, dynamic_pointer_cast(by)); - int facing = 0; - - switch (dir) - { - case Facing::NORTH: - case Facing::SOUTH: - facing = FACING_Z; - break; - case Facing::EAST: - case Facing::WEST: - facing = FACING_X; - break; - case Facing::UP: - case Facing::DOWN: - facing = FACING_Y; - break; - } - - level->setData(x, y, z, type | facing); -} - -Icon *TreeTile::getTexture(int face, int data) -{ - int dir = data & MASK_FACING; - int type = data & MASK_TYPE; - - if (dir == FACING_Y && (face == Facing::UP || face == Facing::DOWN)) - { - return iconTop; - } - else if (dir == FACING_X && (face == Facing::EAST || face == Facing::WEST)) - { - return iconTop; - } - else if (dir == FACING_Z && (face == Facing::NORTH || face == Facing::SOUTH)) - { - return iconTop; - } - - return icons[type]; -} unsigned int TreeTile::getDescriptionId(int iData /*= -1*/) { @@ -113,9 +63,14 @@ unsigned int TreeTile::getDescriptionId(int iData /*= -1*/) return TreeTile::TREE_NAMES[type]; } -int TreeTile::getSpawnResourcesAuxValue(int data) +Icon *TreeTile::getTypeTexture(int type) { - return data & MASK_TYPE; + return icons_side[type]; +} + +Icon *TreeTile::getTopTexture(int type) +{ + return icons_top[type]; } int TreeTile::getWoodType(int data) @@ -131,11 +86,9 @@ shared_ptr TreeTile::getSilkTouchItemInstance(int data) void TreeTile::registerIcons(IconRegister *iconRegister) { - iconTop = iconRegister->registerIcon(L"tree_top"); - icons = new Icon*[TREE_NAMES_LENGTH]; - for (int i = 0; i < TREE_NAMES_LENGTH; i++) { - icons[i] = iconRegister->registerIcon(TREE_TEXTURES[i]); + icons_side[i] = iconRegister->registerIcon(getIconName() + L"_" + TREE_STRING_NAMES[i]); + icons_top[i] = iconRegister->registerIcon(getIconName() + L"_" + TREE_STRING_NAMES[i] + L"_top"); } } \ No newline at end of file diff --git a/Minecraft.World/TreeTile.h b/Minecraft.World/TreeTile.h index b7e0d56d..8738c8cf 100644 --- a/Minecraft.World/TreeTile.h +++ b/Minecraft.World/TreeTile.h @@ -1,11 +1,11 @@ #pragma once -#include "Tile.h" +#include "RotatedPillarTile.h" class ChunkRebuildData; class Player; -class TreeTile : public Tile +class TreeTile : public RotatedPillarTile { friend class Tile; friend class ChunkRebuildData; @@ -25,26 +25,26 @@ public: static const unsigned int TREE_NAMES[TREE_NAMES_LENGTH]; + static const wstring TREE_STRING_NAMES[TREE_NAMES_LENGTH]; + static const wstring TREE_TEXTURES[]; private: - Icon **icons; - Icon *iconTop; + Icon *icons_side[TREE_NAMES_LENGTH]; + Icon *icons_top[TREE_NAMES_LENGTH]; protected: TreeTile(int id); public: - virtual int getRenderShape(); virtual int getResourceCount(Random *random); virtual int getResource(int data, Random *random, int playerBonusLevel); virtual void onRemove(Level *level, int x, int y, int z, int id, int data); - virtual void setPlacedBy(Level *level, int x, int y, int z, shared_ptr by); - virtual Icon *getTexture(int face, int data); virtual unsigned int getDescriptionId(int iData = -1); protected: - int getSpawnResourcesAuxValue(int data); + virtual Icon *getTypeTexture(int type); + virtual Icon *getTopTexture(int type); public: static int getWoodType(int data); diff --git a/Minecraft.World/TripWireSourceTile.cpp b/Minecraft.World/TripWireSourceTile.cpp index 33f857fa..c9271334 100644 --- a/Minecraft.World/TripWireSourceTile.cpp +++ b/Minecraft.World/TripWireSourceTile.cpp @@ -2,6 +2,7 @@ #include "net.minecraft.h" #include "net.minecraft.world.level.h" #include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.level.redstone.h" #include "TripWireSourceTile.h" TripWireSourceTile::TripWireSourceTile(int id) : Tile(id, Material::decoration, isSolidRender()) @@ -102,8 +103,8 @@ void TripWireSourceTile::neighborChanged(Level *level, int x, int y, int z, int if (replace) { - this->spawnResources(level, x, y, z, data, 0); - level->setTile(x, y, z, 0); + spawnResources(level, x, y, z, data, 0); + level->removeTile(x, y, z); } } } @@ -111,8 +112,6 @@ void TripWireSourceTile::neighborChanged(Level *level, int x, int y, int z, int void TripWireSourceTile::calculateState(Level *level, int x, int y, int z, int id, int data, bool canUpdate, /*4J-Jev, these parameters only used with 'updateSource' -->*/ int wireSource, int wireSourceData) { - - int dir = data & MASK_DIR; bool wasAttached = (data & MASK_ATTACHED) == MASK_ATTACHED; bool wasPowered = (data & MASK_POWERED) == MASK_POWERED; @@ -176,7 +175,7 @@ void TripWireSourceTile::calculateState(Level *level, int x, int y, int z, int i int xx = x + stepX * receiverPos; int zz = z + stepZ * receiverPos; int opposite = Direction::DIRECTION_OPPOSITE[dir]; - level->setData(xx, y, zz, opposite | state); + level->setData(xx, y, zz, opposite | state, Tile::UPDATE_ALL); notifyNeighbors(level, xx, y, zz, opposite); playSound(level, xx, y, zz, attached, powered, wasAttached, wasPowered); @@ -186,7 +185,7 @@ void TripWireSourceTile::calculateState(Level *level, int x, int y, int z, int i if (id > 0) // ie. it isn't being removed. { - level->setData(x, y, z, data); + level->setData(x, y, z, data, Tile::UPDATE_ALL); if (canUpdate) notifyNeighbors(level, x, y, z, dir); } @@ -209,7 +208,7 @@ void TripWireSourceTile::calculateState(Level *level, int x, int y, int z, int i } - level->setData(xx, y, zz, wireData); + level->setData(xx, y, zz, wireData, Tile::UPDATE_ALL); } } } @@ -241,23 +240,23 @@ void TripWireSourceTile::playSound(Level *level, int x, int y, int z, bool attac void TripWireSourceTile::notifyNeighbors(Level *level, int x, int y, int z, int dir) { - level->updateNeighborsAt(x, y, z, this->id); + level->updateNeighborsAt(x, y, z, id); if (dir == Direction::EAST) { - level->updateNeighborsAt(x - 1, y, z, this->id); + level->updateNeighborsAt(x - 1, y, z, id); } else if (dir == Direction::WEST) { - level->updateNeighborsAt(x + 1, y, z, this->id); + level->updateNeighborsAt(x + 1, y, z, id); } else if (dir == Direction::SOUTH) { - level->updateNeighborsAt(x, y, z - 1, this->id); + level->updateNeighborsAt(x, y, z - 1, id); } else if (dir == Direction::NORTH) { - level->updateNeighborsAt(x, y, z + 1, this->id); + level->updateNeighborsAt(x, y, z + 1, id); } } @@ -266,7 +265,7 @@ bool TripWireSourceTile::checkCanSurvive(Level *level, int x, int y, int z) if (!mayPlace(level, x, y, z)) { this->spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); return false; } @@ -333,24 +332,24 @@ void TripWireSourceTile::onRemove(Level *level, int x, int y, int z, int id, int Tile::onRemove(level, x, y, z, id, data); } -bool TripWireSourceTile::getSignal(LevelSource *level, int x, int y, int z, int dir) +int TripWireSourceTile::getSignal(LevelSource *level, int x, int y, int z, int dir) { - return (level->getData(x, y, z) & MASK_POWERED) == MASK_POWERED; + return (level->getData(x, y, z) & MASK_POWERED) == MASK_POWERED ? Redstone::SIGNAL_MAX : Redstone::SIGNAL_NONE; } -bool TripWireSourceTile::getDirectSignal(Level *level, int x, int y, int z, int dir) +int TripWireSourceTile::getDirectSignal(LevelSource *level, int x, int y, int z, int dir) { int data = level->getData(x, y, z); - if ((data & MASK_POWERED) != MASK_POWERED) return false; + if ((data & MASK_POWERED) != MASK_POWERED) return Redstone::SIGNAL_NONE; int myDir = data & MASK_DIR; - if (myDir == Direction::NORTH && dir == Facing::NORTH) return true; - if (myDir == Direction::SOUTH && dir == Facing::SOUTH) return true; - if (myDir == Direction::WEST && dir == Facing::WEST) return true; - if (myDir == Direction::EAST && dir == Facing::EAST) return true; + if (myDir == Direction::NORTH && dir == Facing::NORTH) return Redstone::SIGNAL_MAX; + if (myDir == Direction::SOUTH && dir == Facing::SOUTH) return Redstone::SIGNAL_MAX; + if (myDir == Direction::WEST && dir == Facing::WEST) return Redstone::SIGNAL_MAX; + if (myDir == Direction::EAST && dir == Facing::EAST) return Redstone::SIGNAL_MAX; - return false; + return Redstone::SIGNAL_NONE; } bool TripWireSourceTile::isSignalSource() diff --git a/Minecraft.World/TripWireSourceTile.h b/Minecraft.World/TripWireSourceTile.h index c86e781d..83adb9ab 100644 --- a/Minecraft.World/TripWireSourceTile.h +++ b/Minecraft.World/TripWireSourceTile.h @@ -37,7 +37,7 @@ private: public: void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); void onRemove(Level *level, int x, int y, int z, int id, int data); - virtual bool getSignal(LevelSource *level, int x, int y, int z, int dir); - virtual bool getDirectSignal(Level *level, int x, int y, int z, int dir); + virtual int getSignal(LevelSource *level, int x, int y, int z, int dir); + virtual int getDirectSignal(LevelSource *level, int x, int y, int z, int dir); bool isSignalSource(); }; diff --git a/Minecraft.World/TripWireTile.cpp b/Minecraft.World/TripWireTile.cpp index 40ad93f8..2fd7da6c 100644 --- a/Minecraft.World/TripWireTile.cpp +++ b/Minecraft.World/TripWireTile.cpp @@ -66,7 +66,7 @@ void TripWireTile::neighborChanged(Level *level, int x, int y, int z, int type) if (wasSuspended != isSuspended) { spawnResources(level, x, y, z, data, 0); - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); } } @@ -93,7 +93,7 @@ void TripWireTile::updateShape(LevelSource *level, int x, int y, int z, int forc void TripWireTile::onPlace(Level *level, int x, int y, int z) { int data = level->isTopSolidBlocking(x, y - 1, z) ? 0 : MASK_SUSPENDED; - level->setData(x, y, z, data); + level->setData(x, y, z, data, Tile::UPDATE_ALL); updateSource(level, x, y, z, data); } @@ -108,7 +108,7 @@ void TripWireTile::playerWillDestroy(Level *level, int x, int y, int z, int data if (player->getSelectedItem() != NULL && player->getSelectedItem()->id == Item::shears_Id) { - level->setData(x, y, z, data | MASK_DISARMED); + level->setData(x, y, z, data | MASK_DISARMED, Tile::UPDATE_NONE); } } @@ -169,7 +169,15 @@ void TripWireTile::checkPressed(Level *level, int x, int y, int z) vector > *entities = level->getEntities(nullptr, AABB::newTemp(x + tls->xx0, y + tls->yy0, z + tls->zz0, x + tls->xx1, y + tls->yy1, z + tls->zz1)); if (!entities->empty()) { - shouldBePressed = true; + for (AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) + { + shared_ptr e = *it; + if (!e->isIgnoringTileTriggers()) + { + shouldBePressed = true; + break; + } + } } if (shouldBePressed && !wasPressed) @@ -184,7 +192,7 @@ void TripWireTile::checkPressed(Level *level, int x, int y, int z) if (shouldBePressed != wasPressed) { - level->setData(x, y, z, data); + level->setData(x, y, z, data, Tile::UPDATE_ALL); updateSource(level, x, y, z, data); } diff --git a/Minecraft.World/UpdateAttributesPacket.cpp b/Minecraft.World/UpdateAttributesPacket.cpp new file mode 100644 index 00000000..45c20575 --- /dev/null +++ b/Minecraft.World/UpdateAttributesPacket.cpp @@ -0,0 +1,141 @@ +#include "stdafx.h" + +#include "net.minecraft.world.entity.ai.attributes.h" +#include "PacketListener.h" +#include "UpdateAttributesPacket.h" + +UpdateAttributesPacket::UpdateAttributesPacket() +{ + entityId = 0; +} + +UpdateAttributesPacket::UpdateAttributesPacket(int entityId, unordered_set *values) +{ + this->entityId = entityId; + + for (AUTO_VAR(it,values->begin()); it != values->end(); ++it) + { + AttributeInstance *value = *it; + unordered_set mods; + value->getModifiers(mods); + attributes.insert(new AttributeSnapshot(value->getAttribute()->getId(), value->getBaseValue(), &mods)); + } +} + +UpdateAttributesPacket::~UpdateAttributesPacket() +{ + // Delete modifiers - these are always copies, either on construction or on read + for(AUTO_VAR(it,attributes.begin()); it != attributes.end(); ++it) + { + delete (*it); + } +} + +void UpdateAttributesPacket::read(DataInputStream *dis) +{ + entityId = dis->readInt(); + + int attributeCount = dis->readInt(); + for (int i = 0; i < attributeCount; i++) + { + eATTRIBUTE_ID id = static_cast(dis->readShort()); + double base = dis->readDouble(); + unordered_set modifiers = unordered_set(); + int modifierCount = dis->readShort(); + + for (int j = 0; j < modifierCount; j++) + { + eMODIFIER_ID id = static_cast(dis->readInt()); + double amount = dis->readDouble(); + byte operation = dis->readByte(); + modifiers.insert(new AttributeModifier(id, /*L"Unknown synced attribute modifier",*/ amount, operation)); + } + + attributes.insert(new AttributeSnapshot(id, base, &modifiers)); + + // modifiers is copied in AttributeSnapshot ctor so delete contents + for(AUTO_VAR(it, modifiers.begin()); it != modifiers.end(); ++it) + { + delete *it; + } + } +} + +void UpdateAttributesPacket::write(DataOutputStream *dos) +{ + dos->writeInt(entityId); + dos->writeInt(attributes.size()); + + for(AUTO_VAR(it, attributes.begin()); it != attributes.end(); ++it) + { + AttributeSnapshot *attribute = (*it); + + unordered_set *modifiers = attribute->getModifiers(); + + dos->writeShort(attribute->getId()); + dos->writeDouble(attribute->getBase()); + dos->writeShort(modifiers->size()); + + for (AUTO_VAR(it2, modifiers->begin()); it2 != modifiers->end(); ++it2) + { + AttributeModifier *modifier = (*it2); + dos->writeInt(modifier->getId()); + dos->writeDouble(modifier->getAmount()); + dos->writeByte(modifier->getOperation()); + } + } +} + +void UpdateAttributesPacket::handle(PacketListener *listener) +{ + listener->handleUpdateAttributes(shared_from_this()); +} + +int UpdateAttributesPacket::getEstimatedSize() +{ + return 4 + 4 + attributes.size() * (8 + 8 + 8); +} + +int UpdateAttributesPacket::getEntityId() +{ + return entityId; +} + +unordered_set UpdateAttributesPacket::getValues() +{ + return attributes; +} + +UpdateAttributesPacket::AttributeSnapshot::AttributeSnapshot(eATTRIBUTE_ID id, double base, unordered_set *modifiers) +{ + this->id = id; + this->base = base; + + for(AUTO_VAR(it,modifiers->begin()); it != modifiers->end(); ++it) + { + this->modifiers.insert( new AttributeModifier((*it)->getId(), (*it)->getAmount(), (*it)->getOperation())); + } +} + +UpdateAttributesPacket::AttributeSnapshot::~AttributeSnapshot() +{ + for(AUTO_VAR(it, modifiers.begin()); it != modifiers.end(); ++it) + { + delete (*it); + } +} + +eATTRIBUTE_ID UpdateAttributesPacket::AttributeSnapshot::getId() +{ + return id; +} + +double UpdateAttributesPacket::AttributeSnapshot::getBase() +{ + return base; +} + +unordered_set *UpdateAttributesPacket::AttributeSnapshot::getModifiers() +{ + return &modifiers; +} \ No newline at end of file diff --git a/Minecraft.World/UpdateAttributesPacket.h b/Minecraft.World/UpdateAttributesPacket.h new file mode 100644 index 00000000..77ba08be --- /dev/null +++ b/Minecraft.World/UpdateAttributesPacket.h @@ -0,0 +1,46 @@ +#pragma once + +#include "Packet.h" + +class AttributeModifier; +class AttributeInstance; + +class UpdateAttributesPacket : public Packet, public enable_shared_from_this +{ +public: + class AttributeSnapshot + { + private: + eATTRIBUTE_ID id; + double base; + unordered_set modifiers; + + public: + AttributeSnapshot(eATTRIBUTE_ID id, double base, unordered_set *modifiers); + ~AttributeSnapshot(); + + eATTRIBUTE_ID getId(); + double getBase(); + unordered_set *getModifiers(); + }; + +private: + int entityId; + unordered_set attributes; + +public: + UpdateAttributesPacket(); + UpdateAttributesPacket(int entityId, unordered_set *values); + ~UpdateAttributesPacket(); + + void read(DataInputStream *dis); + void write(DataOutputStream *dos); + void handle(PacketListener *listener); + int getEstimatedSize(); + int getEntityId(); + unordered_set getValues(); + +public: + static shared_ptr create() { return shared_ptr(new UpdateAttributesPacket()); } + virtual int getId() { return 44; } +}; \ No newline at end of file diff --git a/Minecraft.World/UpdateMobEffectPacket.cpp b/Minecraft.World/UpdateMobEffectPacket.cpp index dec8d79f..e2f6233e 100644 --- a/Minecraft.World/UpdateMobEffectPacket.cpp +++ b/Minecraft.World/UpdateMobEffectPacket.cpp @@ -2,24 +2,34 @@ #include "net.minecraft.world.effect.h" #include "InputOutputStream.h" #include "PacketListener.h" +#include "BasicTree.h" +#include "BasicTypeContainers.h" #include "UpdateMobEffectPacket.h" UpdateMobEffectPacket::UpdateMobEffectPacket() { - this->entityId = 0; - this->effectId = 0; - this->effectAmplifier = 0; - this->effectDurationTicks = 0; + entityId = 0; + effectId = 0; + effectAmplifier = 0; + effectDurationTicks = 0; } UpdateMobEffectPacket::UpdateMobEffectPacket(int entityId, MobEffectInstance *effect) { this->entityId = entityId; - this->effectId = (BYTE) (effect->getId() & 0xff); - this->effectAmplifier = (char) (effect->getAmplifier() & 0xff); - this->effectDurationTicks = (short) effect->getDuration(); + effectId = (BYTE) (effect->getId() & 0xff); + effectAmplifier = (char) (effect->getAmplifier() & 0xff); + + if (effect->getDuration() > Short::MAX_VALUE) + { + effectDurationTicks = Short::MAX_VALUE; + } + else + { + effectDurationTicks = (short) effect->getDuration(); + } } void UpdateMobEffectPacket::read(DataInputStream *dis) @@ -38,6 +48,11 @@ void UpdateMobEffectPacket::write(DataOutputStream *dos) dos->writeShort(effectDurationTicks); } +bool UpdateMobEffectPacket::isSuperLongDuration() +{ + return effectDurationTicks == Short::MAX_VALUE; +} + void UpdateMobEffectPacket::handle(PacketListener *listener) { listener->handleUpdateMobEffect(shared_from_this()); diff --git a/Minecraft.World/UpdateMobEffectPacket.h b/Minecraft.World/UpdateMobEffectPacket.h index d17d1be4..39eb98e9 100644 --- a/Minecraft.World/UpdateMobEffectPacket.h +++ b/Minecraft.World/UpdateMobEffectPacket.h @@ -17,6 +17,7 @@ public: virtual void read(DataInputStream *dis); virtual void write(DataOutputStream *dos); + virtual bool isSuperLongDuration(); virtual void handle(PacketListener *listener); virtual int getEstimatedSize(); virtual bool canBeInvalidated(); diff --git a/Minecraft.World/UseItemPacket.cpp b/Minecraft.World/UseItemPacket.cpp index d9699130..55e44342 100644 --- a/Minecraft.World/UseItemPacket.cpp +++ b/Minecraft.World/UseItemPacket.cpp @@ -39,13 +39,13 @@ UseItemPacket::UseItemPacket(int x, int y, int z, int face, shared_ptrreadInt(); - y = dis->read(); + y = dis->readUnsignedByte(); z = dis->readInt(); face = dis->read(); item = readItem(dis); - clickX = dis->read() / CLICK_ACCURACY; - clickY = dis->read() / CLICK_ACCURACY; - clickZ = dis->read() / CLICK_ACCURACY; + clickX = dis->readUnsignedByte() / CLICK_ACCURACY; + clickY = dis->readUnsignedByte() / CLICK_ACCURACY; + clickZ = dis->readUnsignedByte() / CLICK_ACCURACY; } void UseItemPacket::write(DataOutputStream *dos) //throws IOException @@ -58,7 +58,7 @@ void UseItemPacket::write(DataOutputStream *dos) //throws IOException writeItem(item, dos); dos->write((int) (clickX * CLICK_ACCURACY)); dos->write((int) (clickY * CLICK_ACCURACY)); - dos->write((int)(clickZ * CLICK_ACCURACY)); + dos->write((int) (clickZ * CLICK_ACCURACY)); } void UseItemPacket::handle(PacketListener *listener) diff --git a/Minecraft.World/Vec3.cpp b/Minecraft.World/Vec3.cpp index b1f79043..1fc26fd5 100644 --- a/Minecraft.World/Vec3.cpp +++ b/Minecraft.World/Vec3.cpp @@ -59,35 +59,35 @@ Vec3 *Vec3::newTemp(double x, double y, double z) Vec3 *thisVec = &tls->pool[tls->poolPointer]; thisVec->set(x, y, z); tls->poolPointer = ( tls->poolPointer + 1 ) % ThreadStorage::POOL_SIZE; - return thisVec; + return thisVec; } Vec3::Vec3(double x, double y, double z) { - if (x == -0.0) x = 0.0; - if (y == -0.0) y = 0.0; - if (z == -0.0) z = 0.0; - this->x = x; - this->y = y; - this->z = z; + if (x == -0.0) x = 0.0; + if (y == -0.0) y = 0.0; + if (z == -0.0) z = 0.0; + this->x = x; + this->y = y; + this->z = z; } Vec3 *Vec3::set(double x, double y, double z) { - this->x = x; - this->y = y; - this->z = z; - return this; + this->x = x; + this->y = y; + this->z = z; + return this; } Vec3 *Vec3::interpolateTo(Vec3 *t, double p) { - double xt = x + (t->x - x) * p; - double yt = y + (t->y - y) * p; - double zt = z + (t->z - z) * p; + double xt = x + (t->x - x) * p; + double yt = y + (t->y - y) * p; + double zt = z + (t->z - z) * p; - return Vec3::newTemp(xt, yt, zt); + return Vec3::newTemp(xt, yt, zt); } Vec3 *Vec3::vectorTo(Vec3 *p) @@ -97,9 +97,9 @@ Vec3 *Vec3::vectorTo(Vec3 *p) Vec3 *Vec3::normalize() { - double dist = (double) (sqrt(x * x + y * y + z * z)); - if (dist < 0.0001) return Vec3::newTemp(0, 0, 0); - return Vec3::newTemp(x / dist, y / dist, z / dist); + double dist = (double) (sqrt(x * x + y * y + z * z)); + if (dist < 0.0001) return Vec3::newTemp(0, 0, 0); + return Vec3::newTemp(x / dist, y / dist, z / dist); } double Vec3::dot(Vec3 *p) @@ -119,26 +119,26 @@ Vec3 *Vec3::add(double x, double y, double z) double Vec3::distanceTo(Vec3 *p) { - double xd = p->x - x; - double yd = p->y - y; - double zd = p->z - z; - return (double) sqrt(xd * xd + yd * yd + zd * zd); + double xd = p->x - x; + double yd = p->y - y; + double zd = p->z - z; + return (double) sqrt(xd * xd + yd * yd + zd * zd); } double Vec3::distanceToSqr(Vec3 *p) { - double xd = p->x - x; - double yd = p->y - y; - double zd = p->z - z; - return xd * xd + yd * yd + zd * zd; + double xd = p->x - x; + double yd = p->y - y; + double zd = p->z - z; + return xd * xd + yd * yd + zd * zd; } double Vec3::distanceToSqr(double x2, double y2, double z2) { - double xd = x2 - x; - double yd = y2 - y; - double zd = z2 - z; - return xd * xd + yd * yd + zd * zd; + double xd = x2 - x; + double yd = y2 - y; + double zd = z2 - z; + return xd * xd + yd * yd + zd * zd; } Vec3 *Vec3::scale(double l) @@ -153,41 +153,41 @@ double Vec3::length() Vec3 *Vec3::clipX(Vec3 *b, double xt) { - double xd = b->x - x; - double yd = b->y - y; - double zd = b->z - z; + double xd = b->x - x; + double yd = b->y - y; + double zd = b->z - z; - if (xd * xd < 0.0000001f) return NULL; + if (xd * xd < 0.0000001f) return NULL; - double d = (xt - x) / xd; - if (d < 0 || d > 1) return NULL; - return Vec3::newTemp(x + xd * d, y + yd * d, z + zd * d); + double d = (xt - x) / xd; + if (d < 0 || d > 1) return NULL; + return Vec3::newTemp(x + xd * d, y + yd * d, z + zd * d); } Vec3 *Vec3::clipY(Vec3 *b, double yt) { - double xd = b->x - x; - double yd = b->y - y; - double zd = b->z - z; + double xd = b->x - x; + double yd = b->y - y; + double zd = b->z - z; - if (yd * yd < 0.0000001f) return NULL; + if (yd * yd < 0.0000001f) return NULL; - double d = (yt - y) / yd; - if (d < 0 || d > 1) return NULL; - return Vec3::newTemp(x + xd * d, y + yd * d, z + zd * d); + double d = (yt - y) / yd; + if (d < 0 || d > 1) return NULL; + return Vec3::newTemp(x + xd * d, y + yd * d, z + zd * d); } Vec3 *Vec3::clipZ(Vec3 *b, double zt) { - double xd = b->x - x; - double yd = b->y - y; - double zd = b->z - z; + double xd = b->x - x; + double yd = b->y - y; + double zd = b->z - z; - if (zd * zd < 0.0000001f) return NULL; + if (zd * zd < 0.0000001f) return NULL; - double d = (zt - z) / zd; - if (d < 0 || d > 1) return NULL; - return Vec3::newTemp(x + xd * d, y + yd * d, z + zd * d); + double d = (zt - z) / zd; + if (d < 0 || d > 1) return NULL; + return Vec3::newTemp(x + xd * d, y + yd * d, z + zd * d); } wstring Vec3::toString() @@ -204,44 +204,44 @@ Vec3 *Vec3::lerp(Vec3 *v, double a) void Vec3::xRot(float degs) { - double _cos = cos(degs); // 4J - cos/sin were floats but seems pointless wasting precision here - double _sin = sin(degs); + double _cos = cos(degs); // 4J - cos/sin were floats but seems pointless wasting precision here + double _sin = sin(degs); - double xx = x; - double yy = y * _cos + z * _sin; - double zz = z * _cos - y * _sin; + double xx = x; + double yy = y * _cos + z * _sin; + double zz = z * _cos - y * _sin; - this->x = xx; - this->y = yy; - this->z = zz; + x = xx; + y = yy; + z = zz; } void Vec3::yRot(float degs) { double _cos = cos(degs); // 4J - cos/sin were floats but seems pointless wasting precision here - double _sin = sin(degs); + double _sin = sin(degs); - double xx = x * _cos + z * _sin; - double yy = y; - double zz = z * _cos - x * _sin; + double xx = x * _cos + z * _sin; + double yy = y; + double zz = z * _cos - x * _sin; - this->x = xx; - this->y = yy; - this->z = zz; + x = xx; + y = yy; + z = zz; } void Vec3::zRot(float degs) { double _cos = cos(degs); // 4J - cos/sin were floats but seems pointless wasting precision here - double _sin = sin(degs); + double _sin = sin(degs); - double xx = x * _cos + y * _sin; - double yy = y * _cos - x * _sin; - double zz = z; + double xx = x * _cos + y * _sin; + double yy = y * _cos - x * _sin; + double zz = z; - this->x = xx; - this->y = yy; - this->z = zz; + x = xx; + y = yy; + z = zz; } // Returns 0 if this point is within the box @@ -262,4 +262,31 @@ double Vec3::distanceTo(AABB *box) else if( z > box->z1) zd = z - box->z1; return sqrt(xd * xd + yd * yd + zd * zd); -} \ No newline at end of file +} + + + +Vec3* Vec3::closestPointOnLine(Vec3* p1, Vec3* p2) +{ + Vec3* diff = newTemp(x-p1->x, y-p1->y, z-p1->z); + Vec3* dir = newTemp(p2->x-p1->x, p2->y-p1->y, p2->z-p1->z); + float dot1 = diff->dot(dir); + if (dot1 <= 0.0f) + return p1; + + float dot2 = dir->dot(dir); + + if (dot2 <= dot1) + return p2; + + float t=dot1/dot2; + return newTemp(p1->x + t * dir->x, p1->y + t * dir->y, p1->z + t * dir->z); +} + + +double Vec3::distanceFromLine(Vec3* p1, Vec3* p2) +{ + Vec3* closestPoint = closestPointOnLine(p1, p2); + Vec3* diff = newTemp(x-closestPoint->x, y-closestPoint->y, z-closestPoint->z); + return diff->length(); +} diff --git a/Minecraft.World/Vec3.h b/Minecraft.World/Vec3.h index 00a74103..0ef6cae0 100644 --- a/Minecraft.World/Vec3.h +++ b/Minecraft.World/Vec3.h @@ -56,4 +56,8 @@ public: // 4J Added double distanceTo(AABB *box); + + Vec3* closestPointOnLine(Vec3* p1, Vec3* p2); + double distanceFromLine(Vec3* p1, Vec3* p2); + }; \ No newline at end of file diff --git a/Minecraft.World/Village.cpp b/Minecraft.World/Village.cpp index aef38066..507bc717 100644 --- a/Minecraft.World/Village.cpp +++ b/Minecraft.World/Village.cpp @@ -8,7 +8,7 @@ #include "BasicTypeContainers.h" #include "Village.h" -Village::Aggressor::Aggressor(shared_ptr mob, int timeStamp) +Village::Aggressor::Aggressor(shared_ptr mob, int timeStamp) { this->mob = mob; this->timeStamp = timeStamp; @@ -248,7 +248,7 @@ bool Village::canRemove() return doorInfos.empty(); } -void Village::addAggressor(shared_ptr mob) +void Village::addAggressor(shared_ptr mob) { //for (Aggressor a : aggressors) for(AUTO_VAR(it, aggressors.begin()); it != aggressors.end(); ++it) @@ -263,7 +263,7 @@ void Village::addAggressor(shared_ptr mob) aggressors.push_back(new Aggressor(mob, _tick)); } -shared_ptr Village::getClosestAggressor(shared_ptr from) +shared_ptr Village::getClosestAggressor(shared_ptr from) { double closestSqr = Double::MAX_VALUE; Aggressor *closest = NULL; @@ -279,7 +279,7 @@ shared_ptr Village::getClosestAggressor(shared_ptr from) return closest != NULL ? closest->mob : nullptr; } -shared_ptr Village::getClosestBadStandingPlayer(shared_ptr from) // 4J Stu - Should be LivingEntity when we add that +shared_ptr Village::getClosestBadStandingPlayer(shared_ptr from) { double closestSqr = Double::MAX_VALUE; shared_ptr closest = nullptr; diff --git a/Minecraft.World/Village.h b/Minecraft.World/Village.h index 07858ef9..e1ee2d4b 100644 --- a/Minecraft.World/Village.h +++ b/Minecraft.World/Village.h @@ -19,10 +19,10 @@ private: class Aggressor { public: - shared_ptr mob; + shared_ptr mob; int timeStamp; - Aggressor(shared_ptr mob, int timeStamp); + Aggressor(shared_ptr mob, int timeStamp); }; vector aggressors; @@ -57,9 +57,9 @@ public: shared_ptr getDoorInfo(int x, int y, int z); void addDoorInfo(shared_ptr di); bool canRemove(); - void addAggressor(shared_ptr mob); - shared_ptr getClosestAggressor(shared_ptr from); - shared_ptr getClosestBadStandingPlayer(shared_ptr from); // 4J Stu - Should be LivingEntity when we add that + void addAggressor(shared_ptr mob); + shared_ptr getClosestAggressor(shared_ptr from); + shared_ptr getClosestBadStandingPlayer(shared_ptr from); private: void updateAggressors(); diff --git a/Minecraft.World/VillageFeature.cpp b/Minecraft.World/VillageFeature.cpp index be724be6..82974c7b 100644 --- a/Minecraft.World/VillageFeature.cpp +++ b/Minecraft.World/VillageFeature.cpp @@ -5,6 +5,9 @@ #include "net.minecraft.world.level.biome.h" #include "net.minecraft.world.level.dimension.h" +const wstring VillageFeature::OPTION_SIZE_MODIFIER = L"size"; +const wstring VillageFeature::OPTION_SPACING = L"distance"; + vector VillageFeature::allowedBiomes; void VillageFeature::staticCtor() @@ -13,67 +16,88 @@ void VillageFeature::staticCtor() allowedBiomes.push_back( Biome::desert ); } - -VillageFeature::VillageFeature(int villageSizeModifier, int iXZSize) : StructureFeature(), villageSizeModifier(villageSizeModifier) +void VillageFeature::_init(int iXZSize) { + villageSizeModifier = 0; + townSpacing = 32; + minTownSeparation = 8; + m_iXZSize=iXZSize; } -bool VillageFeature::isFeatureChunk(int x, int z,bool bIsSuperflat) +VillageFeature::VillageFeature(int iXZSize) { - int townSpacing; + _init(iXZSize); +} -#ifdef _LARGE_WORLDS - if(level->dimension->getXZSize() > 128) - { - townSpacing = 32; - } - else -#endif - if(bIsSuperflat) - { - townSpacing= 32; - } - else - { - townSpacing= 16;// 4J change 32; - } +VillageFeature::VillageFeature(unordered_map options, int iXZSize) +{ + _init(iXZSize); - int minTownSeparation = 8; - - int xx = x; - int zz = z; - if (x < 0) x -= townSpacing - 1; - if (z < 0) z -= townSpacing - 1; - - int xCenterTownChunk = x / townSpacing; - int zCenterTownChunk = z / townSpacing; - Random *r = level->getRandomFor(xCenterTownChunk, zCenterTownChunk, 10387312); - xCenterTownChunk *= townSpacing; - zCenterTownChunk *= townSpacing; - xCenterTownChunk += r->nextInt(townSpacing - minTownSeparation); - zCenterTownChunk += r->nextInt(townSpacing - minTownSeparation); - x = xx; - z = zz; - - bool forcePlacement = false; - LevelGenerationOptions *levelGenOptions = app.getLevelGenerationOptions(); - if( levelGenOptions != NULL ) + for (AUTO_VAR(it,options.begin()); it != options.end(); ++it) { - forcePlacement = levelGenOptions->isFeatureChunk(x,z,eFeature_Village); + if (it->first.compare(OPTION_SIZE_MODIFIER) == 0) + { + villageSizeModifier = Mth::getInt(it->second, villageSizeModifier, 0); + } + else if (it->first.compare(OPTION_SPACING) == 0) + { + townSpacing = Mth::getInt(it->second, townSpacing, minTownSeparation + 1); + } } +} - if (forcePlacement || (x == xCenterTownChunk && z == zCenterTownChunk) ) - { - bool biomeOk = level->getBiomeSource()->containsOnly(x * 16 + 8, z * 16 + 8, 0, allowedBiomes); - if (biomeOk) +wstring VillageFeature::getFeatureName() +{ + return L"Village"; +} + +bool VillageFeature::isFeatureChunk(int x, int z,bool bIsSuperflat) +{ + int townSpacing = this->townSpacing; + + if(!bIsSuperflat +#ifdef _LARGE_WORLDS + && level->dimension->getXZSize() < 128 +#endif + ) + { + townSpacing= 16;// 4J change 32; + } + + int xx = x; + int zz = z; + if (x < 0) x -= townSpacing - 1; + if (z < 0) z -= townSpacing - 1; + + int xCenterTownChunk = x / townSpacing; + int zCenterTownChunk = z / townSpacing; + Random *r = level->getRandomFor(xCenterTownChunk, zCenterTownChunk, 10387312); + xCenterTownChunk *= townSpacing; + zCenterTownChunk *= townSpacing; + xCenterTownChunk += r->nextInt(townSpacing - minTownSeparation); + zCenterTownChunk += r->nextInt(townSpacing - minTownSeparation); + x = xx; + z = zz; + + bool forcePlacement = false; + LevelGenerationOptions *levelGenOptions = app.getLevelGenerationOptions(); + if( levelGenOptions != NULL ) { - //app.DebugPrintf("Biome ok for Village at %d, %d\n",(x * 16 + 8),(z * 16 + 8)); - return true; - } - } + forcePlacement = levelGenOptions->isFeatureChunk(x,z,eFeature_Village); + } - return false; + if (forcePlacement || (x == xCenterTownChunk && z == zCenterTownChunk) ) + { + bool biomeOk = level->getBiomeSource()->containsOnly(x * 16 + 8, z * 16 + 8, 0, allowedBiomes); + if (biomeOk) + { + //app.DebugPrintf("Biome ok for Village at %d, %d\n",(x * 16 + 8),(z * 16 + 8)); + return true; + } + } + + return false; } StructureStart *VillageFeature::createStructureStart(int x, int z) @@ -84,51 +108,58 @@ StructureStart *VillageFeature::createStructureStart(int x, int z) return new VillageStart(level, random, x, z, villageSizeModifier, m_iXZSize); } +VillageFeature::VillageStart::VillageStart() +{ + valid = false; // 4J added initialiser + m_iXZSize = 0; + // for reflection +} + VillageFeature::VillageStart::VillageStart(Level *level, Random *random, int chunkX, int chunkZ, int villageSizeModifier, int iXZSize) { valid = false; // 4J added initialiser m_iXZSize=iXZSize; - list *pieceSet = VillagePieces::createPieceSet(random, villageSizeModifier); + list *pieceSet = VillagePieces::createPieceSet(random, villageSizeModifier); - VillagePieces::StartPiece *startRoom = new VillagePieces::StartPiece(level->getBiomeSource(), 0, random, (chunkX << 4) + 2, (chunkZ << 4) + 2, pieceSet, villageSizeModifier, level); + VillagePieces::StartPiece *startRoom = new VillagePieces::StartPiece(level->getBiomeSource(), 0, random, (chunkX << 4) + 2, (chunkZ << 4) + 2, pieceSet, villageSizeModifier, level); pieces.push_back(startRoom); - startRoom->addChildren(startRoom, &pieces, random); + startRoom->addChildren(startRoom, &pieces, random); - vector *pendingRoads = &startRoom->pendingRoads; - vector *pendingHouses = &startRoom->pendingHouses; - while (!pendingRoads->empty() || !pendingHouses->empty()) + vector *pendingRoads = &startRoom->pendingRoads; + vector *pendingHouses = &startRoom->pendingHouses; + while (!pendingRoads->empty() || !pendingHouses->empty()) { - // prioritize roads - if (pendingRoads->empty()) + // prioritize roads + if (pendingRoads->empty()) { - int pos = random->nextInt((int)pendingHouses->size()); + int pos = random->nextInt((int)pendingHouses->size()); AUTO_VAR(it, pendingHouses->begin() + pos); - StructurePiece *structurePiece = *it; + StructurePiece *structurePiece = *it; pendingHouses->erase(it); - structurePiece->addChildren(startRoom, &pieces, random); - } + structurePiece->addChildren(startRoom, &pieces, random); + } else { - int pos = random->nextInt((int)pendingRoads->size()); + int pos = random->nextInt((int)pendingRoads->size()); AUTO_VAR(it, pendingRoads->begin() + pos); - StructurePiece *structurePiece = *it; + StructurePiece *structurePiece = *it; pendingRoads->erase(it); - structurePiece->addChildren(startRoom, &pieces, random); - } - } + structurePiece->addChildren(startRoom, &pieces, random); + } + } - calculateBoundingBox(); + calculateBoundingBox(); - int count = 0; + int count = 0; for( AUTO_VAR(it, pieces.begin()); it != pieces.end(); it++ ) { StructurePiece *piece = *it; - if (dynamic_cast(piece) == NULL) + if (dynamic_cast(piece) == NULL) { - count++; - } + count++; + } } valid = count > 2; } @@ -142,3 +173,16 @@ bool VillageFeature::VillageStart::isValid() } return valid; } + +void VillageFeature::VillageStart::addAdditonalSaveData(CompoundTag *tag) +{ + StructureStart::addAdditonalSaveData(tag); + + tag->putBoolean(L"Valid", valid); +} + +void VillageFeature::VillageStart::readAdditonalSaveData(CompoundTag *tag) +{ + StructureStart::readAdditonalSaveData(tag); + valid = tag->getBoolean(L"Valid"); +} \ No newline at end of file diff --git a/Minecraft.World/VillageFeature.h b/Minecraft.World/VillageFeature.h index e998918a..1ff7ac75 100644 --- a/Minecraft.World/VillageFeature.h +++ b/Minecraft.World/VillageFeature.h @@ -5,27 +5,45 @@ class Biome; class VillageFeature : public StructureFeature { +public: + static const wstring OPTION_SIZE_MODIFIER; + static const wstring OPTION_SPACING; + private: - const int villageSizeModifier; + int villageSizeModifier; + int townSpacing; + int minTownSeparation; + + void _init(int iXZSize); public: static void staticCtor(); static vector allowedBiomes; - VillageFeature(int villageSizeModifier, int iXZSize); + VillageFeature(int iXZSize); + VillageFeature(unordered_map options, int iXZSize); + wstring getFeatureName(); protected: virtual bool isFeatureChunk(int x, int z, bool bIsSuperflat=false); - virtual StructureStart *createStructureStart(int x, int z); + virtual StructureStart *createStructureStart(int x, int z); -private: + +public: class VillageStart : public StructureStart { +public: + static StructureStart *Create() { return new VillageStart(); } + virtual EStructureStart GetType() { return eStructureStart_VillageStart; } + private: bool valid; int m_iXZSize; public: + VillageStart(); VillageStart(Level *level, Random *random, int chunkX, int chunkZ, int villageSizeModifier,int iXZSize); - bool isValid(); - }; + bool isValid(); + void addAdditonalSaveData(CompoundTag *tag); + void readAdditonalSaveData(CompoundTag *tag); + }; int m_iXZSize; }; diff --git a/Minecraft.World/VillagePieces.cpp b/Minecraft.World/VillagePieces.cpp index 27b21aa5..0a08d4fb 100644 --- a/Minecraft.World/VillagePieces.cpp +++ b/Minecraft.World/VillagePieces.cpp @@ -4,6 +4,7 @@ #include "net.minecraft.world.level.storage.h" #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.level.levelgen.h" +#include "net.minecraft.world.level.levelgen.structure.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.level.dimension.h" #include "net.minecraft.world.entity.npc.h" @@ -16,6 +17,23 @@ WeighedTreasureArray VillagePieces::Smithy::treasureItems; +void VillagePieces::loadStatic() +{ + StructureFeatureIO::setPieceId(eStructurePiece_BookHouse, BookHouse::Create, L"ViBH"); + StructureFeatureIO::setPieceId(eStructurePiece_DoubleFarmland, DoubleFarmland::Create, L"ViDF"); + StructureFeatureIO::setPieceId(eStructurePiece_Farmland, Farmland::Create, L"ViF"); + StructureFeatureIO::setPieceId(eStructurePiece_LightPost, LightPost::Create, L"ViL"); + StructureFeatureIO::setPieceId(eStructurePiece_PigHouse, PigHouse::Create, L"ViPH"); + StructureFeatureIO::setPieceId(eStructurePiece_SimpleHouse, SimpleHouse::Create, L"ViSH"); + StructureFeatureIO::setPieceId(eStructurePiece_SmallHut, SmallHut::Create, L"ViSmH"); + StructureFeatureIO::setPieceId(eStructurePiece_SmallTemple, SmallTemple::Create, L"ViST"); + StructureFeatureIO::setPieceId(eStructurePiece_Smithy, Smithy::Create, L"ViS"); + StructureFeatureIO::setPieceId(eStructurePiece_VillageStartPiece, StartPiece::Create, L"ViStart"); + StructureFeatureIO::setPieceId(eStructurePiece_StraightRoad, StraightRoad::Create, L"ViSR"); + StructureFeatureIO::setPieceId(eStructurePiece_TwoRoomHouse, TwoRoomHouse::Create, L"ViTRH"); + StructureFeatureIO::setPieceId(eStructurePiece_Well, Well::Create, L"ViW"); +} + VillagePieces::PieceWeight::PieceWeight(VillagePieces::EPieceClass pieceClass, int weight, int maxPlaceCount) : weight(weight) { this->placeCount = 0; // 4J added initialiser @@ -248,10 +266,39 @@ StructurePiece *VillagePieces::generateAndAddRoadPiece(StartPiece *startPiece, l return NULL; } +VillagePieces::VillagePiece::VillagePiece() +{ + heightPosition = -1; + spawnedVillagerCount = 0; + isDesertVillage = false; + startPiece = NULL; + // for reflection +} + VillagePieces::VillagePiece::VillagePiece(StartPiece *startPiece, int genDepth) : StructurePiece(genDepth) { + heightPosition = -1; + isDesertVillage = false; spawnedVillagerCount = 0; this->startPiece = startPiece; + if (startPiece != NULL) + { + this->isDesertVillage = startPiece->isDesertVillage; + } +} + +void VillagePieces::VillagePiece::addAdditonalSaveData(CompoundTag *tag) +{ + tag->putInt(L"HPos", heightPosition); + tag->putInt(L"VCount", spawnedVillagerCount); + tag->putBoolean(L"Desert", isDesertVillage); +} + +void VillagePieces::VillagePiece::readAdditonalSaveData(CompoundTag *tag) +{ + heightPosition = tag->getInt(L"HPos"); + spawnedVillagerCount = tag->getInt(L"VCount"); + isDesertVillage = tag->getBoolean(L"Desert"); } StructurePiece *VillagePieces::VillagePiece::generateHouseNorthernLeft(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff) @@ -366,13 +413,13 @@ int VillagePieces::VillagePiece::getVillagerProfession(int villagerNumber) int VillagePieces::VillagePiece::biomeBlock(int tile, int data) { - if (startPiece->isDesertVillage) + if (isDesertVillage) { if (tile == Tile::treeTrunk_Id) { return Tile::sandStone_Id; } - else if (tile == Tile::stoneBrick_Id) + else if (tile == Tile::cobblestone_Id) { return Tile::sandStone_Id; } @@ -398,13 +445,13 @@ int VillagePieces::VillagePiece::biomeBlock(int tile, int data) int VillagePieces::VillagePiece::biomeData(int tile, int data) { - if (startPiece->isDesertVillage) + if (isDesertVillage) { if (tile == Tile::treeTrunk_Id) { return 0; } - else if (tile == Tile::stoneBrick_Id) + else if (tile == Tile::cobblestone_Id) { return SandStoneTile::TYPE_DEFAULT; } @@ -439,9 +486,13 @@ void VillagePieces::VillagePiece::fillColumnDown(Level *level, int block, int da StructurePiece::fillColumnDown(level, bblock, bdata, x, startY, z, chunkBB); } -VillagePieces::Well::Well(StartPiece *startPiece, int genDepth, Random *random, int west, int north) : VillagePiece(startPiece, genDepth), isSource(true) +VillagePieces::Well::Well() +{ + // for reflection +} + +VillagePieces::Well::Well(StartPiece *startPiece, int genDepth, Random *random, int west, int north) : VillagePiece(startPiece, genDepth) { - heightPosition = -1; // 4J added initialiser orientation = random->nextInt(4); switch (orientation) @@ -456,10 +507,8 @@ VillagePieces::Well::Well(StartPiece *startPiece, int genDepth, Random *random, } } -VillagePieces::Well::Well(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth), isSource(false) +VillagePieces::Well::Well(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { - heightPosition = -1; // 4J added initialiser - orientation = direction; boundingBox = stairsBox; } @@ -472,19 +521,6 @@ void VillagePieces::Well::addChildren(StructurePiece *startPiece, listx0 + 1, boundingBox->y1 - 4, boundingBox->z1 + 1, Direction::SOUTH, getGenDepth()); } -//VillagePieces::Well *VillagePieces::Well::createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) -//{ -// BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, -1, 4 - height, 0, width, height, depth, direction); -// -// if (!isOkBox(box) || StructurePiece::findCollisionPiece(pieces, box) != NULL) -// { -// delete box; -// return NULL; -// } -// -// return new Well(genDepth, random, box, direction); -//} - bool VillagePieces::Well::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) @@ -497,7 +533,7 @@ bool VillagePieces::Well::postProcess(Level *level, Random *random, BoundingBox boundingBox->move(0, heightPosition - boundingBox->y1 + 3, 0); } - generateBox(level, chunkBB, 1, 0, 1, 4, height - 3, 4, Tile::stoneBrick_Id, Tile::water_Id, false); + generateBox(level, chunkBB, 1, 0, 1, 4, height - 3, 4, Tile::cobblestone_Id, Tile::water_Id, false); placeBlock(level, 0, 0, 2, height - 3, 2, chunkBB); placeBlock(level, 0, 0, 3, height - 3, 2, chunkBB); placeBlock(level, 0, 0, 2, height - 3, 3, chunkBB); @@ -511,7 +547,7 @@ bool VillagePieces::Well::postProcess(Level *level, Random *random, BoundingBox placeBlock(level, Tile::fence_Id, 0, 1, height - 1, 4, chunkBB); placeBlock(level, Tile::fence_Id, 0, 4, height - 2, 4, chunkBB); placeBlock(level, Tile::fence_Id, 0, 4, height - 1, 4, chunkBB); - generateBox(level, chunkBB, 1, height, 1, 4, height, 4, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 1, height, 1, 4, height, 4, Tile::cobblestone_Id, Tile::cobblestone_Id, false); for (int z = 0; z <= 5; z++) { @@ -531,6 +567,11 @@ bool VillagePieces::Well::postProcess(Level *level, Random *random, BoundingBox } +VillagePieces::StartPiece::StartPiece() +{ + // for reflection +} + VillagePieces::StartPiece::StartPiece(BiomeSource *biomeSource, int genDepth, Random *random, int west, int north, list *pieceSet, int villageSize, Level *level) : Well(NULL, 0, random, west, north) { isLibraryAdded = false; // 4J - added initialiser @@ -541,8 +582,7 @@ VillagePieces::StartPiece::StartPiece(BiomeSource *biomeSource, int genDepth, Ra m_level = level; Biome *biome = biomeSource->getBiome(west, north); - this->isDesertVillage = biome == Biome::desert || biome == Biome::desertHills; - this->startPiece = this; + isDesertVillage = biome == Biome::desert || biome == Biome::desertHills; } VillagePieces::StartPiece::~StartPiece() @@ -559,6 +599,11 @@ BiomeSource *VillagePieces::StartPiece::getBiomeSource() return biomeSource; } +VillagePieces::StraightRoad::StraightRoad() +{ + // for reflection +} + VillagePieces::StraightRoad::StraightRoad(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillageRoadPiece(startPiece, genDepth) { orientation = direction; @@ -566,6 +611,18 @@ VillagePieces::StraightRoad::StraightRoad(StartPiece *startPiece, int genDepth, length = Math::_max(stairsBox->getXSpan(), stairsBox->getZSpan()); } +void VillagePieces::StraightRoad::addAdditonalSaveData(CompoundTag *tag) +{ + VillageRoadPiece::addAdditonalSaveData(tag); + tag->putInt(L"Length", length); +} + +void VillagePieces::StraightRoad::readAdditonalSaveData(CompoundTag *tag) +{ + VillageRoadPiece::readAdditonalSaveData(tag); + length = tag->getInt(L"Length"); +} + void VillagePieces::StraightRoad::addChildren(StructurePiece *startPiece, list *pieces, Random *random) { bool hasHouses = false; @@ -663,7 +720,7 @@ bool VillagePieces::StraightRoad::postProcess(Level *level, Random *random, Boun if (chunkBB->isInside(x, 64, z)) { int y = level->getTopSolidBlock(x, z) - 1; - level->setTileNoUpdate(x, y, z,tile); + level->setTileAndData(x, y, z,tile, 0, Tile::UPDATE_CLIENTS); } } } @@ -671,17 +728,30 @@ bool VillagePieces::StraightRoad::postProcess(Level *level, Random *random, Boun return true; } -/* -int heightPosition; -const bool hasTerrace;*/ +VillagePieces::SimpleHouse::SimpleHouse() +{ + hasTerrace = false; + // for reflection +} VillagePieces::SimpleHouse::SimpleHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth), hasTerrace(random->nextBoolean()) { - heightPosition = -1; // 4J added initialiser orientation = direction; boundingBox = stairsBox; } +void VillagePieces::SimpleHouse::addAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::addAdditonalSaveData(tag); + tag->putBoolean(L"Terrace", hasTerrace); +} + +void VillagePieces::SimpleHouse::readAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::readAdditonalSaveData(tag); + hasTerrace = tag->getBoolean(L"Terrace"); +} + VillagePieces::SimpleHouse *VillagePieces::SimpleHouse::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, width, height, depth, direction); @@ -708,24 +778,24 @@ bool VillagePieces::SimpleHouse::postProcess(Level *level, Random *random, Bound } // floor - generateBox(level, chunkBB, 0, 0, 0, 4, 0, 4, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 0, 0, 4, 0, 4, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // roof generateBox(level, chunkBB, 0, 4, 0, 4, 4, 4, Tile::treeTrunk_Id, Tile::treeTrunk_Id, false); generateBox(level, chunkBB, 1, 4, 1, 3, 4, 3, Tile::wood_Id, Tile::wood_Id, false); // window walls - placeBlock(level, Tile::stoneBrick_Id, 0, 0, 1, 0, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 0, 2, 0, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 0, 3, 0, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, 1, 0, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, 2, 0, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, 3, 0, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 0, 1, 4, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 0, 2, 4, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 0, 3, 4, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, 1, 4, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, 2, 4, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, 3, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 0, 1, 0, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 0, 2, 0, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 0, 3, 0, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, 1, 0, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, 2, 0, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, 3, 0, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 0, 1, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 0, 2, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 0, 3, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, 1, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, 2, 4, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, 3, 4, chunkBB); generateBox(level, chunkBB, 0, 1, 1, 0, 3, 3, Tile::wood_Id, Tile::wood_Id, false); generateBox(level, chunkBB, 4, 1, 1, 4, 3, 3, Tile::wood_Id, Tile::wood_Id, false); generateBox(level, chunkBB, 1, 1, 4, 3, 3, 4, Tile::wood_Id, Tile::wood_Id, false); @@ -787,7 +857,7 @@ bool VillagePieces::SimpleHouse::postProcess(Level *level, Random *random, Bound for (int x = 0; x < width; x++) { generateAirColumnUp(level, x, height, z, chunkBB); - fillColumnDown(level, Tile::stoneBrick_Id, 0, x, -1, z, chunkBB); + fillColumnDown(level, Tile::cobblestone_Id, 0, x, -1, z, chunkBB); } } @@ -797,6 +867,11 @@ bool VillagePieces::SimpleHouse::postProcess(Level *level, Random *random, Bound } +VillagePieces::SmallTemple::SmallTemple() +{ + // for reflection +} + VillagePieces::SmallTemple::SmallTemple(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J added initialiser @@ -834,40 +909,40 @@ bool VillagePieces::SmallTemple::postProcess(Level *level, Random *random, Bound generateBox(level, chunkBB, 1, 5, 1, 3, 9, 3, 0, 0, false); // floor - generateBox(level, chunkBB, 1, 0, 0, 3, 0, 8, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 1, 0, 0, 3, 0, 8, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // front wall - generateBox(level, chunkBB, 1, 1, 0, 3, 10, 0, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 1, 1, 0, 3, 10, 0, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // left tall wall - generateBox(level, chunkBB, 0, 1, 1, 0, 10, 3, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 1, 1, 0, 10, 3, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // right tall wall - generateBox(level, chunkBB, 4, 1, 1, 4, 10, 3, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 4, 1, 1, 4, 10, 3, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // left low wall - generateBox(level, chunkBB, 0, 0, 4, 0, 4, 7, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 0, 4, 0, 4, 7, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // right low wall - generateBox(level, chunkBB, 4, 0, 4, 4, 4, 7, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 4, 0, 4, 4, 4, 7, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // far low wall - generateBox(level, chunkBB, 1, 1, 8, 3, 4, 8, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 1, 1, 8, 3, 4, 8, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // far upper wall - generateBox(level, chunkBB, 1, 5, 4, 3, 10, 4, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 1, 5, 4, 3, 10, 4, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // low roof - generateBox(level, chunkBB, 1, 5, 5, 3, 5, 7, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 1, 5, 5, 3, 5, 7, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // high roof - generateBox(level, chunkBB, 0, 9, 0, 4, 9, 4, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 9, 0, 4, 9, 4, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // middle floor / roof - generateBox(level, chunkBB, 0, 4, 0, 4, 4, 4, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - placeBlock(level, Tile::stoneBrick_Id, 0, 0, 11, 2, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 4, 11, 2, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 2, 11, 0, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 2, 11, 4, chunkBB); + generateBox(level, chunkBB, 0, 4, 0, 4, 4, 4, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + placeBlock(level, Tile::cobblestone_Id, 0, 0, 11, 2, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 4, 11, 2, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 2, 11, 0, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 2, 11, 4, chunkBB); // altar pieces - placeBlock(level, Tile::stoneBrick_Id, 0, 1, 1, 6, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 1, 1, 7, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 2, 1, 7, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 3, 1, 6, chunkBB); - placeBlock(level, Tile::stoneBrick_Id, 0, 3, 1, 7, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 1, 1, 6, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 1, 1, 7, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 2, 1, 7, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 3, 1, 6, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 3, 1, 7, chunkBB); placeBlock(level, Tile::stairs_stone_Id, getOrientationData(Tile::stairs_stone_Id, 3), 1, 1, 5, chunkBB); placeBlock(level, Tile::stairs_stone_Id, getOrientationData(Tile::stairs_stone_Id, 3), 2, 1, 6, chunkBB); placeBlock(level, Tile::stairs_stone_Id, getOrientationData(Tile::stairs_stone_Id, 3), 3, 1, 5, chunkBB); @@ -919,7 +994,7 @@ bool VillagePieces::SmallTemple::postProcess(Level *level, Random *random, Bound for (int x = 0; x < width; x++) { generateAirColumnUp(level, x, height, z, chunkBB); - fillColumnDown(level, Tile::stoneBrick_Id, 0, x, -1, z, chunkBB); + fillColumnDown(level, Tile::cobblestone_Id, 0, x, -1, z, chunkBB); } } @@ -934,6 +1009,10 @@ int VillagePieces::SmallTemple::getVillagerProfession(int villagerNumber) return Villager::PROFESSION_PRIEST; } +VillagePieces::BookHouse::BookHouse() +{ + // for reflection +} VillagePieces::BookHouse::BookHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { @@ -971,11 +1050,11 @@ bool VillagePieces::BookHouse::postProcess(Level *level, Random *random, Boundin generateBox(level, chunkBB, 1, 1, 1, 7, 5, 4, 0, 0, false); // floor - generateBox(level, chunkBB, 0, 0, 0, 8, 0, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 0, 0, 8, 0, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // roof - generateBox(level, chunkBB, 0, 5, 0, 8, 5, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 0, 6, 1, 8, 6, 4, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 0, 7, 2, 8, 7, 3, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 5, 0, 8, 5, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 0, 6, 1, 8, 6, 4, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 0, 7, 2, 8, 7, 3, Tile::cobblestone_Id, Tile::cobblestone_Id, false); int southStairs = getOrientationData(Tile::stairs_wood_Id, 3); int northStairs = getOrientationData(Tile::stairs_wood_Id, 2); for (int d = -1; d <= 2; d++) { @@ -986,14 +1065,14 @@ bool VillagePieces::BookHouse::postProcess(Level *level, Random *random, Boundin } // rock supports - generateBox(level, chunkBB, 0, 1, 0, 0, 1, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 1, 1, 5, 8, 1, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 8, 1, 0, 8, 1, 4, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 2, 1, 0, 7, 1, 0, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 0, 2, 0, 0, 4, 0, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 0, 2, 5, 0, 4, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 8, 2, 5, 8, 4, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 8, 2, 0, 8, 4, 0, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 1, 0, 0, 1, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 1, 1, 5, 8, 1, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 8, 1, 0, 8, 1, 4, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 2, 1, 0, 7, 1, 0, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 0, 2, 0, 0, 4, 0, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 0, 2, 5, 0, 4, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 8, 2, 5, 8, 4, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 8, 2, 0, 8, 4, 0, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // wooden walls generateBox(level, chunkBB, 0, 2, 1, 0, 4, 4, Tile::wood_Id, Tile::wood_Id, false); @@ -1056,7 +1135,7 @@ bool VillagePieces::BookHouse::postProcess(Level *level, Random *random, Boundin for (int x = 0; x < width; x++) { generateAirColumnUp(level, x, height, z, chunkBB); - fillColumnDown(level, Tile::stoneBrick_Id, 0, x, -1, z, chunkBB); + fillColumnDown(level, Tile::cobblestone_Id, 0, x, -1, z, chunkBB); } } @@ -1071,6 +1150,11 @@ int VillagePieces::BookHouse::getVillagerProfession(int villagerNumber) return Villager::PROFESSION_LIBRARIAN; } +VillagePieces::SmallHut::SmallHut() +{ + // for reflection +} + VillagePieces::SmallHut::SmallHut(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth), lowCeiling(random->nextBoolean()), tablePlacement(random->nextInt(3)) { heightPosition = -1; // 4J added initialiser @@ -1079,6 +1163,20 @@ VillagePieces::SmallHut::SmallHut(StartPiece *startPiece, int genDepth, Random * boundingBox = stairsBox; } +void VillagePieces::SmallHut::addAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::addAdditonalSaveData(tag); + tag->putInt(L"T", tablePlacement); + tag->putBoolean(L"C", lowCeiling); +} + +void VillagePieces::SmallHut::readAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::readAdditonalSaveData(tag); + tablePlacement = tag->getInt(L"T"); + lowCeiling = tag->getBoolean(L"C"); +} + VillagePieces::SmallHut *VillagePieces::SmallHut::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, width, height, depth, direction); @@ -1108,7 +1206,7 @@ bool VillagePieces::SmallHut::postProcess(Level *level, Random *random, Bounding generateBox(level, chunkBB, 1, 1, 1, 3, 5, 4, 0, 0, false); // floor - generateBox(level, chunkBB, 0, 0, 0, 3, 0, 4, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 0, 0, 3, 0, 4, Tile::cobblestone_Id, Tile::cobblestone_Id, false); generateBox(level, chunkBB, 1, 0, 1, 2, 0, 3, Tile::dirt_Id, Tile::dirt_Id, false); // roof if (lowCeiling) { @@ -1163,7 +1261,7 @@ bool VillagePieces::SmallHut::postProcess(Level *level, Random *random, Bounding for (int x = 0; x < width; x++) { generateAirColumnUp(level, x, height, z, chunkBB); - fillColumnDown(level, Tile::stoneBrick_Id, 0, x, -1, z, chunkBB); + fillColumnDown(level, Tile::cobblestone_Id, 0, x, -1, z, chunkBB); } } @@ -1173,9 +1271,13 @@ bool VillagePieces::SmallHut::postProcess(Level *level, Random *random, Bounding } +VillagePieces::PigHouse::PigHouse() +{ + // for reflection +} + VillagePieces::PigHouse::PigHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { - heightPosition = -1; // 4J added initialiser orientation = direction; boundingBox = stairsBox; } @@ -1212,7 +1314,7 @@ bool VillagePieces::PigHouse::postProcess(Level *level, Random *random, Bounding // pig floor generateBox(level, chunkBB, 2, 0, 6, 8, 0, 10, Tile::dirt_Id, Tile::dirt_Id, false); - placeBlock(level, Tile::stoneBrick_Id, 0, 6, 0, 6, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 6, 0, 6, chunkBB); // pig fence generateBox(level, chunkBB, 2, 1, 6, 2, 1, 10, Tile::fence_Id, Tile::fence_Id, false); generateBox(level, chunkBB, 8, 1, 6, 8, 1, 10, Tile::fence_Id, Tile::fence_Id, false); @@ -1220,10 +1322,10 @@ bool VillagePieces::PigHouse::postProcess(Level *level, Random *random, Bounding // floor generateBox(level, chunkBB, 1, 0, 1, 7, 0, 4, Tile::wood_Id, Tile::wood_Id, false); - generateBox(level, chunkBB, 0, 0, 0, 0, 3, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 8, 0, 0, 8, 3, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 1, 0, 0, 7, 1, 0, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 1, 0, 5, 7, 1, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 0, 0, 0, 3, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 8, 0, 0, 8, 3, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 1, 0, 0, 7, 1, 0, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 1, 0, 5, 7, 1, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // roof generateBox(level, chunkBB, 1, 2, 0, 7, 3, 0, Tile::wood_Id, Tile::wood_Id, false); @@ -1294,7 +1396,7 @@ bool VillagePieces::PigHouse::postProcess(Level *level, Random *random, Bounding for (int x = 0; x < width; x++) { generateAirColumnUp(level, x, height, z, chunkBB); - fillColumnDown(level, Tile::stoneBrick_Id, 0, x, -1, z, chunkBB); + fillColumnDown(level, Tile::cobblestone_Id, 0, x, -1, z, chunkBB); } } @@ -1313,6 +1415,11 @@ int VillagePieces::PigHouse::getVillagerProfession(int villagerNumber) return Villager::PROFESSION_FARMER; } +VillagePieces::TwoRoomHouse::TwoRoomHouse() +{ + // for reflection +} + VillagePieces::TwoRoomHouse::TwoRoomHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J added initialiser @@ -1353,12 +1460,12 @@ bool VillagePieces::TwoRoomHouse::postProcess(Level *level, Random *random, Boun // floor generateBox(level, chunkBB, 2, 0, 5, 8, 0, 10, Tile::wood_Id, Tile::wood_Id, false); generateBox(level, chunkBB, 1, 0, 1, 7, 0, 4, Tile::wood_Id, Tile::wood_Id, false); - generateBox(level, chunkBB, 0, 0, 0, 0, 3, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 8, 0, 0, 8, 3, 10, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 1, 0, 0, 7, 2, 0, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 1, 0, 5, 2, 1, 5, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 2, 0, 6, 2, 3, 10, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); - generateBox(level, chunkBB, 3, 0, 10, 7, 3, 10, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 0, 0, 0, 3, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 8, 0, 0, 8, 3, 10, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 1, 0, 0, 7, 2, 0, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 1, 0, 5, 2, 1, 5, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 2, 0, 6, 2, 3, 10, Tile::cobblestone_Id, Tile::cobblestone_Id, false); + generateBox(level, chunkBB, 3, 0, 10, 7, 3, 10, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // room 1 roof generateBox(level, chunkBB, 1, 2, 0, 7, 3, 0, Tile::wood_Id, Tile::wood_Id, false); @@ -1456,7 +1563,7 @@ bool VillagePieces::TwoRoomHouse::postProcess(Level *level, Random *random, Boun for (int x = 0; x < width; x++) { generateAirColumnUp(level, x, height, z, chunkBB); - fillColumnDown(level, Tile::stoneBrick_Id, 0, x, -1, z, chunkBB); + fillColumnDown(level, Tile::cobblestone_Id, 0, x, -1, z, chunkBB); } } for (int z = 5; z < depth - 1; z++) @@ -1464,7 +1571,7 @@ bool VillagePieces::TwoRoomHouse::postProcess(Level *level, Random *random, Boun for (int x = 2; x < width; x++) { generateAirColumnUp(level, x, height, z, chunkBB); - fillColumnDown(level, Tile::stoneBrick_Id, 0, x, -1, z, chunkBB); + fillColumnDown(level, Tile::cobblestone_Id, 0, x, -1, z, chunkBB); } } @@ -1476,7 +1583,7 @@ bool VillagePieces::TwoRoomHouse::postProcess(Level *level, Random *random, Boun void VillagePieces::Smithy::staticCtor() { - treasureItems = WeighedTreasureArray(13); + treasureItems = WeighedTreasureArray(17); treasureItems[0] = new WeighedTreasure(Item::diamond_Id, 0, 1, 3, 3); treasureItems[1] = new WeighedTreasure(Item::ironIngot_Id, 0, 1, 5, 10); treasureItems[2] = new WeighedTreasure(Item::goldIngot_Id, 0, 1, 3, 5); @@ -1490,11 +1597,21 @@ void VillagePieces::Smithy::staticCtor() treasureItems[10] = new WeighedTreasure(Item::boots_iron_Id, 0, 1, 1, 5); treasureItems[11] = new WeighedTreasure(Tile::obsidian_Id, 0, 3, 7, 5); treasureItems[12] = new WeighedTreasure(Tile::sapling_Id, 0, 3, 7, 5); + // very rare for villages ... + treasureItems[13] = new WeighedTreasure(Item::saddle_Id, 0, 1, 1, 3); + treasureItems[14] = new WeighedTreasure(Item::horseArmorMetal_Id, 0, 1, 1, 1); + treasureItems[15] = new WeighedTreasure(Item::horseArmorGold_Id, 0, 1, 1, 1); + treasureItems[16] = new WeighedTreasure(Item::horseArmorDiamond_Id, 0, 1, 1, 1); + // ... +} + +VillagePieces::Smithy::Smithy() +{ + // for reflection } VillagePieces::Smithy::Smithy(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { - heightPosition = -1; // 4J added initialiser hasPlacedChest = false; orientation = direction; @@ -1514,6 +1631,18 @@ VillagePieces::Smithy *VillagePieces::Smithy::createPiece(StartPiece *startPiece return new Smithy(startPiece, genDepth, random, box, direction); } +void VillagePieces::Smithy::addAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::addAdditonalSaveData(tag); + tag->putBoolean(L"Chest", hasPlacedChest); +} + +void VillagePieces::Smithy::readAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::readAdditonalSaveData(tag); + hasPlacedChest = tag->getBoolean(L"Chest"); +} + bool VillagePieces::Smithy::postProcess(Level *level, Random *random, BoundingBox *chunkBB) { if (heightPosition < 0) @@ -1530,10 +1659,10 @@ bool VillagePieces::Smithy::postProcess(Level *level, Random *random, BoundingBo generateBox(level, chunkBB, 0, 1, 0, 9, 4, 6, 0, 0, false); // floor - generateBox(level, chunkBB, 0, 0, 0, 9, 0, 6, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 0, 0, 9, 0, 6, Tile::cobblestone_Id, Tile::cobblestone_Id, false); // roof - generateBox(level, chunkBB, 0, 4, 0, 9, 4, 6, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 0, 4, 0, 9, 4, 6, Tile::cobblestone_Id, Tile::cobblestone_Id, false); generateBox(level, chunkBB, 0, 5, 0, 9, 5, 6, Tile::stoneSlabHalf_Id, Tile::stoneSlabHalf_Id, false); generateBox(level, chunkBB, 1, 5, 1, 8, 5, 5, 0, 0, false); @@ -1553,13 +1682,13 @@ bool VillagePieces::Smithy::postProcess(Level *level, Random *random, BoundingBo generateBox(level, chunkBB, 9, 1, 0, 9, 3, 0, Tile::fence_Id, Tile::fence_Id, false); // furnace - generateBox(level, chunkBB, 6, 1, 4, 9, 4, 6, Tile::stoneBrick_Id, Tile::stoneBrick_Id, false); + generateBox(level, chunkBB, 6, 1, 4, 9, 4, 6, Tile::cobblestone_Id, Tile::cobblestone_Id, false); placeBlock(level, Tile::lava_Id, 0, 7, 1, 5, chunkBB); placeBlock(level, Tile::lava_Id, 0, 8, 1, 5, chunkBB); placeBlock(level, Tile::ironFence_Id, 0, 9, 2, 5, chunkBB); placeBlock(level, Tile::ironFence_Id, 0, 9, 2, 4, chunkBB); generateBox(level, chunkBB, 7, 2, 4, 8, 2, 5, 0, 0, false); - placeBlock(level, Tile::stoneBrick_Id, 0, 6, 1, 3, chunkBB); + placeBlock(level, Tile::cobblestone_Id, 0, 6, 1, 3, chunkBB); placeBlock(level, Tile::furnace_Id, 0, 6, 2, 3, chunkBB); placeBlock(level, Tile::furnace_Id, 0, 6, 3, 3, chunkBB); placeBlock(level, Tile::stoneSlab_Id, 0, 8, 1, 1, chunkBB); @@ -1602,7 +1731,7 @@ bool VillagePieces::Smithy::postProcess(Level *level, Random *random, BoundingBo for (int x = 0; x < width; x++) { generateAirColumnUp(level, x, height, z, chunkBB); - fillColumnDown(level, Tile::stoneBrick_Id, 0, x, -1, z, chunkBB); + fillColumnDown(level, Tile::cobblestone_Id, 0, x, -1, z, chunkBB); } } @@ -1617,9 +1746,15 @@ int VillagePieces::Smithy::getVillagerProfession(int villagerNumber) return Villager::PROFESSION_SMITH; } +VillagePieces::Farmland::Farmland() +{ + cropsA = 0; + cropsB = 0; + // for reflection +} + VillagePieces::Farmland::Farmland(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { - heightPosition = -1; // 4J added initialiser orientation = direction; boundingBox = stairsBox; @@ -1632,7 +1767,7 @@ int VillagePieces::Farmland::selectCrops(Random *random) switch (random->nextInt(5)) { default: - return Tile::crops_Id; + return Tile::wheat_Id; case 0: return Tile::carrots_Id; case 1: @@ -1640,6 +1775,20 @@ int VillagePieces::Farmland::selectCrops(Random *random) } } +void VillagePieces::Farmland::addAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::addAdditonalSaveData(tag); + tag->putInt(L"CA", cropsA); + tag->putInt(L"CB", cropsB); +} + +void VillagePieces::Farmland::readAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::readAdditonalSaveData(tag); + cropsA = tag->getInt(L"CA"); + cropsB = tag->getInt(L"CB"); +} + VillagePieces::Farmland *VillagePieces::Farmland::createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth) { BoundingBox *box = BoundingBox::orientBox(footX, footY, footZ, 0, 0, 0, width, height, depth, direction); @@ -1700,6 +1849,15 @@ bool VillagePieces::Farmland::postProcess(Level *level, Random *random, Bounding } +VillagePieces::DoubleFarmland::DoubleFarmland() +{ + cropsA = 0; + cropsB = 0; + cropsC = 0; + cropsD = 0; + // for reflection +} + VillagePieces::DoubleFarmland::DoubleFarmland(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J added initialiser @@ -1712,12 +1870,30 @@ VillagePieces::DoubleFarmland::DoubleFarmland(StartPiece *startPiece, int genDep cropsD = selectCrops(random); } +void VillagePieces::DoubleFarmland::addAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::addAdditonalSaveData(tag); + tag->putInt(L"CA", cropsA); + tag->putInt(L"CB", cropsB); + tag->putInt(L"CC", cropsC); + tag->putInt(L"CD", cropsD); +} + +void VillagePieces::DoubleFarmland::readAdditonalSaveData(CompoundTag *tag) +{ + VillagePiece::readAdditonalSaveData(tag); + cropsA = tag->getInt(L"CA"); + cropsB = tag->getInt(L"CB"); + cropsC = tag->getInt(L"CC"); + cropsD = tag->getInt(L"CD"); +} + int VillagePieces::DoubleFarmland::selectCrops(Random *random) { switch (random->nextInt(5)) { default: - return Tile::crops_Id; + return Tile::wheat_Id; case 0: return Tile::carrots_Id; case 1: @@ -1794,6 +1970,11 @@ bool VillagePieces::DoubleFarmland::postProcess(Level *level, Random *random, Bo } +VillagePieces::LightPost::LightPost() +{ + // for reflection +} + VillagePieces::LightPost::LightPost(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *box, int direction) : VillagePiece(startPiece, genDepth) { heightPosition = -1; // 4J - added initialiser @@ -1835,7 +2016,7 @@ bool VillagePieces::LightPost::postProcess(Level *level, Random *random, Boundin placeBlock(level, Tile::fence_Id, 0, 1, 2, 0, chunkBB); // head - placeBlock(level, Tile::cloth_Id, DyePowderItem::WHITE, 1, 3, 0, chunkBB); + placeBlock(level, Tile::wool_Id, DyePowderItem::WHITE, 1, 3, 0, chunkBB); // torches placeBlock(level, Tile::torch_Id, 0, 0, 3, 0, chunkBB); diff --git a/Minecraft.World/VillagePieces.h b/Minecraft.World/VillagePieces.h index a80dfcf7..7570d65b 100644 --- a/Minecraft.World/VillagePieces.h +++ b/Minecraft.World/VillagePieces.h @@ -8,9 +8,9 @@ class VillagePieces private: static const int MAX_DEPTH = 50; - static const int BASE_ROAD_DEPTH = 3; - // the dungeon starts at 64 and traverses downwards to this point - static const int LOWEST_Y_POSITION = 10; + static const int BASE_ROAD_DEPTH = 3; + // the dungeon starts at 64 and traverses downwards to this point + static const int LOWEST_Y_POSITION = 10; public: static const int SIZE_SMALL = 0; @@ -31,19 +31,22 @@ public: EPieceClass_TwoRoomHouse }; - class PieceWeight { + static void loadStatic(); + + class PieceWeight + { public: EPieceClass pieceClass; // 4J - EPieceClass was Class - const int weight; - int placeCount; - int maxPlaceCount; + const int weight; + int placeCount; + int maxPlaceCount; - PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount); // 4J - EPieceClass was Class - bool doPlace(int depth); - bool isValid(); - }; + PieceWeight(EPieceClass pieceClass, int weight, int maxPlaceCount); // 4J - EPieceClass was Class + bool doPlace(int depth); + bool isValid(); + }; - static list *createPieceSet(Random *random, int villageSize); // 4J - was ArrayList + static list *createPieceSet(Random *random, int villageSize); // 4J - was ArrayList class StartPiece; private: @@ -55,19 +58,25 @@ private: static StructurePiece *generateAndAddRoadPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int depth); - /** - * - * - */ + /** + * + * + */ private: class VillagePiece : public StructurePiece { + protected: + int heightPosition; private: int spawnedVillagerCount; + bool isDesertVillage; protected: StartPiece *startPiece; + VillagePiece(); VillagePiece(StartPiece *startPiece, int genDepth); + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); StructurePiece *generateHouseNorthernLeft(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff); StructurePiece *generateHouseNorthernRight(StartPiece *startPiece, list *pieces, Random *random, int yOff, int zOff); int getAverageGroundHeight(Level *level, BoundingBox *chunkBB); @@ -79,108 +88,136 @@ private: virtual void placeBlock(Level *level, int block, int data, int x, int y, int z, BoundingBox *chunkBB); virtual void generateBox(Level *level, BoundingBox *chunkBB, int x0, int y0, int z0, int x1, int y1, int z1, int edgeTile, int fillTile, bool skipAir); virtual void fillColumnDown(Level *level, int block, int data, int x, int startY, int z, BoundingBox *chunkBB); - }; + }; - /** - * - * - */ + /** + * + * + */ public: class Well : public VillagePiece { + public: + static StructurePiece *Create() { return new Well(); } + virtual EStructurePiece GetType() { return eStructurePiece_Well; } + private: static const int width = 6; static const int height = 15; static const int depth = 6; - - const bool isSource; - int heightPosition; public: + Well(); Well(StartPiece *startPiece, int genDepth, Random *random, int west, int north); - - Well(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); - virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); - //static Well *createPiece(list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + Well(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); + virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; public: class StartPiece : public Well { public: + virtual EStructurePiece GetType() { return eStructurePiece_VillageStartPiece; } + + public: + // these fields are only used in generation step and aren't serialized :{ BiomeSource *biomeSource; bool isDesertVillage; int villageSize; bool isLibraryAdded; PieceWeight *previousPiece; - list *pieceSet; // 4J - was ArrayList + list *pieceSet; Level *m_level; - // these queues are used so that the addChildren calls are - // called in a random order - vector pendingHouses; // 4J - was ArrayList - vector pendingRoads; // 4J - was ArrayList - + // these queues are used so that the addChildren calls are called in a random order + vector pendingHouses; + vector pendingRoads; + + StartPiece(); StartPiece(BiomeSource *biomeSource, int genDepth, Random *random, int west, int north, list *pieceSet, int villageSize, Level *level); // 4J Added level param virtual ~StartPiece(); - + BiomeSource *getBiomeSource(); - }; + }; public: class VillageRoadPiece : public VillagePiece { - protected : + protected: + VillageRoadPiece() {} VillageRoadPiece(StartPiece *startPiece, int genDepth) : VillagePiece(startPiece, genDepth) {} - }; + }; - /** - * - * - */ + /** + * + * + */ public: class StraightRoad : public VillageRoadPiece { + public: + static StructurePiece *Create() { return new StraightRoad(); } + virtual EStructurePiece GetType() { return eStructurePiece_StraightRoad; } private: static const int width = 3; int length; public: + StraightRoad(); StraightRoad(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); + + protected: + void addAdditonalSaveData(CompoundTag *tag); + void readAdditonalSaveData(CompoundTag *tag); + + public: virtual void addChildren(StructurePiece *startPiece, list *pieces, Random *random); static BoundingBox *findPieceBox(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + }; - /** - * - * - */ + /** + * + * + */ public: class SimpleHouse : public VillagePiece { + public: + static StructurePiece *Create() { return new SimpleHouse(); } + virtual EStructurePiece GetType() { return eStructurePiece_SimpleHouse; } + private: static const int width = 5; static const int height = 6; static const int depth = 5; private: - int heightPosition; - const bool hasTerrace; + bool hasTerrace; public: + SimpleHouse(); SimpleHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); + + protected: + void addAdditonalSaveData(CompoundTag *tag); + void readAdditonalSaveData(CompoundTag *tag); + public: static SimpleHouse *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); }; public: class SmallTemple : public VillagePiece { + public: + static StructurePiece *Create() { return new SmallTemple(); } + virtual EStructurePiece GetType() { return eStructurePiece_SmallTemple; } + private: static const int width = 5; static const int height = 12; @@ -189,6 +226,7 @@ public: int heightPosition; public: + SmallTemple(); SmallTemple(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); static SmallTemple *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); @@ -199,6 +237,10 @@ public: public: class BookHouse : public VillagePiece { + public: + static StructurePiece *Create() { return new BookHouse(); } + virtual EStructurePiece GetType() { return eStructurePiece_BookHouse; } + private: static const int width = 9; static const int height = 9; @@ -207,6 +249,7 @@ public: int heightPosition; public: + BookHouse(); BookHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); static BookHouse *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); @@ -214,37 +257,50 @@ public: virtual int getVillagerProfession(int villagerNumber); }; +public: + class SmallHut : public VillagePiece + { public: - class SmallHut : public VillagePiece - { + static StructurePiece *Create() { return new SmallHut(); } + virtual EStructurePiece GetType() { return eStructurePiece_SmallHut; } + + + private: + static const int width = 4; + static const int height = 6; + static const int depth = 5; - private: - static const int width = 4; - static const int height = 6; - static const int depth = 5; + bool lowCeiling; + int tablePlacement; - int heightPosition; - const bool lowCeiling; - const int tablePlacement; + public: + SmallHut(); + SmallHut(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); - public: - SmallHut(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); - static SmallHut *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + static SmallHut *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; public: class PigHouse : public VillagePiece { + public: + static StructurePiece *Create() { return new PigHouse(); } + virtual EStructurePiece GetType() { return eStructurePiece_PigHouse; } + private: static const int width = 9; static const int height = 7; static const int depth = 11; - int heightPosition; - public: + PigHouse(); PigHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); static PigHouse *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); @@ -254,6 +310,10 @@ public: public: class TwoRoomHouse : public VillagePiece { + public: + static StructurePiece *Create() { return new TwoRoomHouse(); } + virtual EStructurePiece GetType() { return eStructurePiece_TwoRoomHouse; } + private: static const int width = 9; static const int height = 7; @@ -262,21 +322,25 @@ public: int heightPosition; public: + TwoRoomHouse(); TwoRoomHouse(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); static TwoRoomHouse *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); }; public: - class Smithy : public VillagePiece + class Smithy : public VillagePiece { + public: + static StructurePiece *Create() { return new Smithy(); } + virtual EStructurePiece GetType() { return eStructurePiece_Smithy; } + private: static const int width = 10; static const int height = 6; static const int depth = 7; - int heightPosition; bool hasPlacedChest; static WeighedTreasureArray treasureItems; @@ -284,22 +348,31 @@ public: public: static void staticCtor(); + Smithy(); Smithy(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); - static Smithy *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + static Smithy *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + + protected: + void addAdditonalSaveData(CompoundTag *tag); + void readAdditonalSaveData(CompoundTag *tag); + + public: + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); virtual int getVillagerProfession(int villagerNumber); - }; + }; public: class Farmland : public VillagePiece { + public: + static StructurePiece *Create() { return new Farmland(); } + virtual EStructurePiece GetType() { return eStructurePiece_Farmland; } + private: static const int width = 7; static const int height = 4; static const int depth = 9; - - int heightPosition; int cropsA; int cropsB; @@ -307,19 +380,30 @@ public: int selectCrops(Random *random); public: + Farmland(); Farmland(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); - static Farmland *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + static Farmland *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + }; public: class DoubleFarmland : public VillagePiece { + public: + static StructurePiece *Create() { return new DoubleFarmland(); } + virtual EStructurePiece GetType() { return eStructurePiece_DoubleFarmland; } + private: static const int width = 13; static const int height = 4; static const int depth = 9; - + int heightPosition; int cropsA; @@ -330,24 +414,36 @@ public: int selectCrops(Random *random); public: + DoubleFarmland(); DoubleFarmland(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *stairsBox, int direction); - static DoubleFarmland *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); + + protected: + virtual void addAdditonalSaveData(CompoundTag *tag); + virtual void readAdditonalSaveData(CompoundTag *tag); + + public: + static DoubleFarmland *createPiece(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction, int genDepth); virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + }; public: class LightPost : public VillagePiece { + public: + static StructurePiece *Create() { return new LightPost(); } + virtual EStructurePiece GetType() { return eStructurePiece_LightPost; } + private: static const int width = 3; - static const int height = 4; - static const int depth = 2; + static const int height = 4; + static const int depth = 2; - int heightPosition; + int heightPosition; public: + LightPost(); LightPost(StartPiece *startPiece, int genDepth, Random *random, BoundingBox *box, int direction); - static BoundingBox *findPieceBox(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction); - virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); - }; + static BoundingBox *findPieceBox(StartPiece *startPiece, list *pieces, Random *random, int footX, int footY, int footZ, int direction); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + }; }; diff --git a/Minecraft.World/VillageSiege.cpp b/Minecraft.World/VillageSiege.cpp index 55b2a3e8..0f967595 100644 --- a/Minecraft.World/VillageSiege.cpp +++ b/Minecraft.World/VillageSiege.cpp @@ -135,7 +135,7 @@ bool VillageSiege::trySpawn() //try { mob = shared_ptr( new Zombie(level) ); - mob->finalizeMobSpawn(); + mob->finalizeMobSpawn(NULL); mob->setVillager(false); } //catch (Exception e) { diff --git a/Minecraft.World/Villager.cpp b/Minecraft.World/Villager.cpp index 328c0c70..1fe32a12 100644 --- a/Minecraft.World/Villager.cpp +++ b/Minecraft.World/Villager.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "com.mojang.nbt.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.entity.ai.navigation.h" #include "net.minecraft.world.entity.ai.village.h" @@ -24,15 +25,12 @@ void Villager::_init(int profession) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); + setHealth(getMaxHealth()); setProfession(profession); setSize(.6f, 1.8f); - runSpeed = 0.5f; - villageUpdateInterval = 0; inLove = false; chasing = false; @@ -43,27 +41,27 @@ void Villager::_init(int profession) updateMerchantTimer = 0; addRecipeOnUpdate = false; riches = 0; - lastPlayerTradeName = L""; - rewardPlayersOnFirstVillage = false; + lastPlayerTradeName = L""; + rewardPlayersOnFirstVillage = false; baseRecipeChanceMod = 0.0f; getNavigation()->setCanOpenDoors(true); getNavigation()->setAvoidWater(true); goalSelector.addGoal(0, new FloatGoal(this)); - goalSelector.addGoal(1, new AvoidPlayerGoal(this, typeid(Zombie), 8, 0.3f, 0.35f)); + goalSelector.addGoal(1, new AvoidPlayerGoal(this, typeid(Zombie), 8, 0.6, 0.6)); goalSelector.addGoal(1, new TradeWithPlayerGoal(this)); goalSelector.addGoal(1, new LookAtTradingPlayerGoal(this)); goalSelector.addGoal(2, new MoveIndoorsGoal(this)); goalSelector.addGoal(3, new RestrictOpenDoorGoal(this)); goalSelector.addGoal(4, new OpenDoorGoal(this, true)); - goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 0.3f)); + goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 0.6)); goalSelector.addGoal(6, new MakeLoveGoal(this)); goalSelector.addGoal(7, new TakeFlowerGoal(this)); - goalSelector.addGoal(8, new PlayGoal(this, 0.32f)); + goalSelector.addGoal(8, new PlayGoal(this, 0.32)); goalSelector.addGoal(9, new InteractGoal(this, typeid(Player), 3, 1.f)); goalSelector.addGoal(9, new InteractGoal(this, typeid(Villager), 5, 0.02f)); - goalSelector.addGoal(9, new RandomStrollGoal(this, 0.3f)); + goalSelector.addGoal(9, new RandomStrollGoal(this, 0.6)); goalSelector.addGoal(10, new LookAtPlayerGoal(this, typeid(Mob), 8)); } @@ -82,6 +80,13 @@ Villager::~Villager() delete offers; } +void Villager::registerAttributes() +{ + AgableMob::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.5f); +} + bool Villager::useNewAi() { return true; @@ -145,11 +150,11 @@ void Villager::serverAiMobStep() AgableMob::serverAiMobStep(); } -bool Villager::interact(shared_ptr player) +bool Villager::mobInteract(shared_ptr player) { // [EB]: Truly dislike this code but I don't see another easy way shared_ptr item = player->inventory->getSelected(); - bool holdingSpawnEgg = item != NULL && item->id == Item::monsterPlacer_Id; + bool holdingSpawnEgg = item != NULL && item->id == Item::spawnEgg_Id; if (!holdingSpawnEgg && isAlive() && !isTrading() && !isBaby()) { @@ -157,11 +162,13 @@ bool Villager::interact(shared_ptr player) { // note: stop() logic is controlled by trading ai goal setTradingPlayer(player); - player->openTrading(dynamic_pointer_cast(shared_from_this())); + + // 4J-JEV: Villagers in PC game don't display professions. + player->openTrading(dynamic_pointer_cast(shared_from_this()), getDisplayName() ); } return true; } - return AgableMob::interact(player); + return AgableMob::mobInteract(player); } void Villager::defineSynchedData() @@ -170,11 +177,6 @@ void Villager::defineSynchedData() entityData->define(DATA_PROFESSION_ID, 0); } -int Villager::getMaxHealth() -{ - return 20; -} - void Villager::addAdditonalSaveData(CompoundTag *tag) { AgableMob::addAdditonalSaveData(tag); @@ -199,34 +201,6 @@ void Villager::readAdditionalSaveData(CompoundTag *tag) } } -int Villager::getTexture() -{ - // 4J Made switch - switch(getProfession()) - { - case PROFESSION_FARMER: - return TN_MOB_VILLAGER_FARMER; // 4J was "/mob/villager/farmer.png"; - break; - case PROFESSION_LIBRARIAN: - return TN_MOB_VILLAGER_LIBRARIAN; // 4J was "/mob/villager/librarian.png"; - break; - case PROFESSION_PRIEST: - return TN_MOB_VILLAGER_PRIEST; // 4J was "/mob/villager/priest.png"; - break; - case PROFESSION_SMITH: - return TN_MOB_VILLAGER_SMITH; // 4J was "/mob/villager/smith.png"; - break; - case PROFESSION_BUTCHER: - return TN_MOB_VILLAGER_BUTCHER; // 4J was "/mob/villager/butcher.png"; - break; - //default: - // return TN_MOB_VILLAGER_VILLAGER; // 4J was "/mob/villager/villager.png"; - // break; - } - - return AgableMob::getTexture(); -} - bool Villager::removeWhenFarAway() { return false; @@ -281,7 +255,7 @@ bool Villager::isChasing() return chasing; } -void Villager::setLastHurtByMob(shared_ptr mob) +void Villager::setLastHurtByMob(shared_ptr mob) { AgableMob::setLastHurtByMob(mob); shared_ptr _village = village.lock(); @@ -289,15 +263,14 @@ void Villager::setLastHurtByMob(shared_ptr mob) { _village->addAggressor(mob); - shared_ptr player = dynamic_pointer_cast(mob); - if (player) + if ( mob->instanceof(eTYPE_PLAYER) ) { int amount = -1; if (isBaby()) { amount = -3; } - _village->modifyStanding(player->getName(), amount); + _village->modifyStanding( dynamic_pointer_cast(mob)->getName(), amount ); if (isAlive()) { level->broadcastEntityEvent(shared_from_this(), EntityEvent::VILLAGER_ANGRY); @@ -314,12 +287,11 @@ void Villager::die(DamageSource *source) shared_ptr sourceEntity = source->getEntity(); if (sourceEntity != NULL) { - if ((sourceEntity->GetType() & eTYPE_PLAYER) == eTYPE_PLAYER) + if ( sourceEntity->instanceof(eTYPE_PLAYER) ) { - shared_ptr player = dynamic_pointer_cast(sourceEntity); - _village->modifyStanding(player->getName(), -2); + _village->modifyStanding( dynamic_pointer_cast(sourceEntity)->getName(), -2 ); } - else if ((sourceEntity->GetType() & eTYPE_ENEMY) == eTYPE_ENEMY) + else if ( sourceEntity->instanceof(eTYPE_ENEMY) ) { _village->resetNoBreedTimer(); } @@ -423,7 +395,7 @@ void Villager::addOffers(int addCount) { case PROFESSION_FARMER: addItemForTradeIn(newOffers, Item::wheat_Id, random, getRecipeChance(.9f)); - addItemForTradeIn(newOffers, Tile::cloth_Id, random, getRecipeChance(.5f)); + addItemForTradeIn(newOffers, Tile::wool_Id, random, getRecipeChance(.5f)); addItemForTradeIn(newOffers, Item::chicken_raw_Id, random, getRecipeChance(.5f)); addItemForTradeIn(newOffers, Item::fish_cooked_Id, random, getRecipeChance(.4f)); addItemForPurchase(newOffers, Item::bread_Id, random, getRecipeChance(.9f)); @@ -434,9 +406,9 @@ void Villager::addOffers(int addCount) addItemForPurchase(newOffers, Item::flintAndSteel_Id, random, getRecipeChance(.3f)); addItemForPurchase(newOffers, Item::chicken_cooked_Id, random, getRecipeChance(.3f)); addItemForPurchase(newOffers, Item::arrow_Id, random, getRecipeChance(.5f)); - if (random->nextFloat() < .5f) + if (random->nextFloat() < getRecipeChance(.5f)) { - newOffers->push_back(new MerchantRecipe(shared_ptr( new ItemInstance(Tile::gravel, 10) ), shared_ptr( new ItemInstance(Item::emerald) ), shared_ptr( new ItemInstance(Item::flint_Id, 2 + random->nextInt(2), 0)))); + newOffers->push_back(new MerchantRecipe(shared_ptr( new ItemInstance(Tile::gravel, 10) ), shared_ptr( new ItemInstance(Item::emerald) ), shared_ptr( new ItemInstance(Item::flint_Id, 4 + random->nextInt(2), 0)))); } break; case PROFESSION_BUTCHER: @@ -444,10 +416,10 @@ void Villager::addOffers(int addCount) addItemForTradeIn(newOffers, Item::porkChop_raw_Id, random, getRecipeChance(.5f)); addItemForTradeIn(newOffers, Item::beef_raw_Id, random, getRecipeChance(.5f)); addItemForPurchase(newOffers, Item::saddle_Id, random, getRecipeChance(.1f)); - addItemForPurchase(newOffers, Item::chestplate_cloth_Id, random, getRecipeChance(.3f)); - addItemForPurchase(newOffers, Item::boots_cloth_Id, random, getRecipeChance(.3f)); - addItemForPurchase(newOffers, Item::helmet_cloth_Id, random, getRecipeChance(.3f)); - addItemForPurchase(newOffers, Item::leggings_cloth_Id, random, getRecipeChance(.3f)); + addItemForPurchase(newOffers, Item::chestplate_leather_Id, random, getRecipeChance(.3f)); + addItemForPurchase(newOffers, Item::boots_leather_Id, random, getRecipeChance(.3f)); + addItemForPurchase(newOffers, Item::helmet_leather_Id, random, getRecipeChance(.3f)); + addItemForPurchase(newOffers, Item::leggings_leather_Id, random, getRecipeChance(.3f)); addItemForPurchase(newOffers, Item::porkChop_cooked_Id, random, getRecipeChance(.3f)); addItemForPurchase(newOffers, Item::beef_cooked_Id, random, getRecipeChance(.3f)); break; @@ -503,7 +475,7 @@ void Villager::addOffers(int addCount) addItemForPurchase(newOffers, Item::eyeOfEnder_Id, random, getRecipeChance(.3f)); addItemForPurchase(newOffers, Item::expBottle_Id, random, getRecipeChance(.2f)); addItemForPurchase(newOffers, Item::redStone_Id, random, getRecipeChance(.4f)); - addItemForPurchase(newOffers, Tile::lightGem_Id, random, getRecipeChance(.3f)); + addItemForPurchase(newOffers, Tile::glowstone_Id, random, getRecipeChance(.3f)); { int enchantItems[] = { Item::sword_iron_Id, Item::sword_diamond_Id, Item::chestplate_iron_Id, Item::chestplate_diamond_Id, Item::hatchet_iron_Id, Item::hatchet_diamond_Id, Item::pickAxe_iron_Id, @@ -570,7 +542,7 @@ void Villager::staticCtor() MIN_MAX_VALUES[Item::seeds_melon_Id] = pair(30, 38); MIN_MAX_VALUES[Item::seeds_pumpkin_Id] = pair(30, 38); MIN_MAX_VALUES[Item::wheat_Id] = pair(18, 22); - MIN_MAX_VALUES[Tile::cloth_Id] = pair(14, 22); + MIN_MAX_VALUES[Tile::wool_Id] = pair(14, 22); MIN_MAX_VALUES[Item::rotten_flesh_Id] = pair(36, 64); MIN_MAX_PRICES[Item::flintAndSteel_Id] = pair(3, 4); @@ -603,16 +575,16 @@ void Villager::staticCtor() MIN_MAX_PRICES[Item::cookie_Id] = pair(-10, -7); MIN_MAX_PRICES[Tile::glass_Id] = pair(-5, -3); MIN_MAX_PRICES[Tile::bookshelf_Id] = pair(3, 4); - MIN_MAX_PRICES[Item::chestplate_cloth_Id] = pair(4, 5); - MIN_MAX_PRICES[Item::boots_cloth_Id] = pair(2, 4); - MIN_MAX_PRICES[Item::helmet_cloth_Id] = pair(2, 4); - MIN_MAX_PRICES[Item::leggings_cloth_Id] = pair(2, 4); + MIN_MAX_PRICES[Item::chestplate_leather_Id] = pair(4, 5); + MIN_MAX_PRICES[Item::boots_leather_Id] = pair(2, 4); + MIN_MAX_PRICES[Item::helmet_leather_Id] = pair(2, 4); + MIN_MAX_PRICES[Item::leggings_leather_Id] = pair(2, 4); MIN_MAX_PRICES[Item::saddle_Id] = pair(6, 8); MIN_MAX_PRICES[Item::expBottle_Id] = pair(-4, -1); MIN_MAX_PRICES[Item::redStone_Id] = pair(-4, -1); MIN_MAX_PRICES[Item::compass_Id] = pair(10, 12); MIN_MAX_PRICES[Item::clock_Id] = pair(10, 12); - MIN_MAX_PRICES[Tile::lightGem_Id] = pair(-3, -1); + MIN_MAX_PRICES[Tile::glowstone_Id] = pair(-3, -1); MIN_MAX_PRICES[Item::porkChop_cooked_Id] = pair(-7, -5); MIN_MAX_PRICES[Item::beef_cooked_Id] = pair(-7, -5); MIN_MAX_PRICES[Item::chicken_cooked_Id] = pair(-8, -6); @@ -732,9 +704,13 @@ void Villager::addParticlesAroundSelf(ePARTICLE_TYPE particle) } } -void Villager::finalizeMobSpawn() +MobGroupData *Villager::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param { - setProfession(level->random->nextInt(Villager::PROFESSION_MAX)); + groupData = AgableMob::finalizeMobSpawn(groupData); + + setProfession(level->random->nextInt(PROFESSION_MAX)); + + return groupData; } void Villager::setRewardPlayersInVillage() @@ -748,7 +724,7 @@ shared_ptr Villager::getBreedOffspring(shared_ptr target) if(level->canCreateMore(GetType(), Level::eSpawnType_Breed) ) { shared_ptr villager = shared_ptr(new Villager(level)); - villager->finalizeMobSpawn(); + villager->finalizeMobSpawn(NULL); return villager; } else @@ -757,8 +733,15 @@ shared_ptr Villager::getBreedOffspring(shared_ptr target) } } -int Villager::getDisplayName() +bool Villager::canBeLeashed() +{ + return false; +} + +wstring Villager::getDisplayName() { + if (hasCustomName()) return getCustomName(); + int name = IDS_VILLAGER; switch(getProfession()) { @@ -778,5 +761,5 @@ int Villager::getDisplayName() name = IDS_VILLAGER_BUTCHER; break; }; - return name; + return app.GetString(name); } diff --git a/Minecraft.World/Villager.h b/Minecraft.World/Villager.h index b6ad7d1c..d8aeb15a 100644 --- a/Minecraft.World/Villager.h +++ b/Minecraft.World/Villager.h @@ -39,9 +39,9 @@ private: int updateMerchantTimer; bool addRecipeOnUpdate; int riches; - wstring lastPlayerTradeName; + wstring lastPlayerTradeName; - bool rewardPlayersOnFirstVillage; + bool rewardPlayersOnFirstVillage; private: @@ -52,24 +52,25 @@ public: Villager(Level *level, int profession); ~Villager(); +protected: + virtual void registerAttributes(); + +public: virtual bool useNewAi(); protected: virtual void serverAiMobStep(); public: - virtual bool interact(shared_ptr player); + virtual bool mobInteract(shared_ptr player); protected: virtual void defineSynchedData(); public: - virtual int getMaxHealth(); virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); - virtual int getTexture(); - protected: virtual bool removeWhenFarAway(); virtual int getAmbientSound(); @@ -83,7 +84,7 @@ public: void setInLove(bool inLove); void setChasing(bool chasing); bool isChasing(); - void setLastHurtByMob(shared_ptr mob); + void setLastHurtByMob(shared_ptr mob); void die(DamageSource *source); void handleEntityEvent(byte id); @@ -141,9 +142,9 @@ private: static int getPurchaseCost(int itemId, Random *random); public: - void finalizeMobSpawn(); - void setRewardPlayersInVillage(); - shared_ptr getBreedOffspring(shared_ptr target); - - virtual int getDisplayName(); + virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param + virtual void setRewardPlayersInVillage(); + virtual shared_ptr getBreedOffspring(shared_ptr target); + virtual bool canBeLeashed(); + virtual wstring getDisplayName(); }; \ No newline at end of file diff --git a/Minecraft.World/VillagerGolem.cpp b/Minecraft.World/VillagerGolem.cpp index a0f05472..dba80ffa 100644 --- a/Minecraft.World/VillagerGolem.cpp +++ b/Minecraft.World/VillagerGolem.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.control.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.entity.ai.goal.target.h" @@ -23,34 +24,30 @@ VillagerGolem::VillagerGolem(Level *level) : Golem(level) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); + setHealth(getMaxHealth()); villageUpdateInterval = 0; village = weak_ptr(); attackAnimationTick = 0; offerFlowerTick = 0; - this->textureIdx = TN_MOB_VILLAGER_GOLEM; // "/mob/villager_golem.png"; - this->setSize(1.4f, 2.9f); + setSize(1.4f, 2.9f); getNavigation()->setAvoidWater(true); - // 4J-JEV: These speed values are as they appear before 1.6.4 (1.5), - // as the movement speed system changes then. (Mob attributes added) - goalSelector.addGoal(1, new MeleeAttackGoal(this, 0.25f, true)); - goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.22f, 32)); - goalSelector.addGoal(3, new MoveThroughVillageGoal(this, 0.16f, true)); - goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, 0.16f)); + goalSelector.addGoal(1, new MeleeAttackGoal(this, 1.0, true)); + goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, 0.9, 32)); + goalSelector.addGoal(3, new MoveThroughVillageGoal(this, 0.6, true)); + goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, 1.0)); goalSelector.addGoal(5, new OfferFlowerGoal(this)); - goalSelector.addGoal(6, new RandomStrollGoal(this, 0.16f)); + goalSelector.addGoal(6, new RandomStrollGoal(this, 0.6)); goalSelector.addGoal(7, new LookAtPlayerGoal(this, typeid(Player), 6)); goalSelector.addGoal(8, new RandomLookAroundGoal(this)); targetSelector.addGoal(1, new DefendVillageTargetGoal(this)); targetSelector.addGoal(2, new HurtByTargetGoal(this, false)); - targetSelector.addGoal(3, new NearestAttackableTargetGoal(this, typeid(Monster), 16, 0, false, true)); + targetSelector.addGoal(3, new NearestAttackableTargetGoal(this, typeid(Mob), 0, false, true, Enemy::ENEMY_SELECTOR)); } void VillagerGolem::defineSynchedData() @@ -82,9 +79,12 @@ void VillagerGolem::serverAiMobStep() Golem::serverAiMobStep(); } -int VillagerGolem::getMaxHealth() +void VillagerGolem::registerAttributes() { - return 100; + Golem::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(100); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f); } int VillagerGolem::decreaseAirSupply(int currentSupply) @@ -93,6 +93,18 @@ int VillagerGolem::decreaseAirSupply(int currentSupply) return currentSupply; } +void VillagerGolem::doPush(shared_ptr e) +{ + if ( e->instanceof(eTYPE_ENEMY) ) + { + if (getRandom()->nextInt(20) == 0) + { + setTarget(dynamic_pointer_cast(e)); + } + } + Golem::doPush(e); +} + void VillagerGolem::aiStep() { Golem::aiStep(); @@ -103,7 +115,7 @@ void VillagerGolem::aiStep() if (xd * xd + zd * zd > MoveControl::MIN_SPEED_SQR && random->nextInt(5) == 0) { int xt = Mth::floor(x); - int yt = Mth::floor(y - 0.2f - this->heightOffset); + int yt = Mth::floor(y - 0.2f - heightOffset); int zt = Mth::floor(z); int t = level->getTile(xt, yt, zt); int d = level->getData(xt, yt, zt); @@ -139,7 +151,7 @@ bool VillagerGolem::doHurtTarget(shared_ptr target) level->broadcastEntityEvent(shared_from_this(), EntityEvent::START_ATTACKING); bool hurt = target->hurt(DamageSource::mobAttack(dynamic_pointer_cast(shared_from_this())), 7 + random->nextInt(15)); if (hurt) target->yd += 0.4f; - level->playSound(shared_from_this(), eSoundType_MOB_IRONGOLEM_THROW, 1, 1); + playSound(eSoundType_MOB_IRONGOLEM_THROW, 1, 1); return hurt; } @@ -148,7 +160,7 @@ void VillagerGolem::handleEntityEvent(byte id) if (id == EntityEvent::START_ATTACKING) { attackAnimationTick = 10; - level->playSound(shared_from_this(), eSoundType_MOB_IRONGOLEM_THROW, 1, 1); + playSound(eSoundType_MOB_IRONGOLEM_THROW, 1, 1); } else if (id == EntityEvent::OFFER_FLOWER) { @@ -190,7 +202,7 @@ int VillagerGolem::getDeathSound() void VillagerGolem::playStepSound(int xt, int yt, int zt, int t) { - level->playSound(shared_from_this(), eSoundType_MOB_IRONGOLEM_WALK, 1, 1); + playSound(eSoundType_MOB_IRONGOLEM_WALK, 1, 1); } void VillagerGolem::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) @@ -237,4 +249,20 @@ void VillagerGolem::die(DamageSource *source) village.lock()->modifyStanding(lastHurtByPlayer->getName(), -5); } Golem::die(source); +} + +bool VillagerGolem::hurt(DamageSource *source, float dmg) +{ + // 4J: Protect owned golem from untrusted players + if (isPlayerCreated()) + { + shared_ptr entity = source->getDirectEntity(); + if (entity != NULL && entity->instanceof(eTYPE_PLAYER)) + { + shared_ptr player = dynamic_pointer_cast(entity); + if (!player->isAllowedToAttackPlayers()) return false; + } + } + + return Golem::hurt(source, dmg); } \ No newline at end of file diff --git a/Minecraft.World/VillagerGolem.h b/Minecraft.World/VillagerGolem.h index dfcd3ac0..55b6cae2 100644 --- a/Minecraft.World/VillagerGolem.h +++ b/Minecraft.World/VillagerGolem.h @@ -31,12 +31,9 @@ public: protected: virtual void serverAiMobStep(); - -public: - virtual int getMaxHealth(); - -protected: + virtual void registerAttributes(); virtual int decreaseAirSupply(int currentSupply); + virtual void doPush(shared_ptr e); public: virtual void aiStep(); @@ -61,4 +58,5 @@ public: virtual bool isPlayerCreated(); virtual void setPlayerCreated(bool value); virtual void die(DamageSource *source); + virtual bool hurt(DamageSource *source, float dmg); }; \ No newline at end of file diff --git a/Minecraft.World/Villages.cpp b/Minecraft.World/Villages.cpp index 995befe8..ddb0e7dc 100644 --- a/Minecraft.World/Villages.cpp +++ b/Minecraft.World/Villages.cpp @@ -64,14 +64,12 @@ void Villages::tick() void Villages::removeVillages() { - //for (Iterator it = villages.iterator(); it.hasNext();) for(AUTO_VAR(it, villages.begin()); it != villages.end(); ) { - shared_ptr village = *it; //it.next(); + shared_ptr village = *it; if (village->canRemove()) { it = villages.erase(it); - //it.remove(); setDirty(); } else @@ -90,7 +88,6 @@ shared_ptr Villages::getClosestVillage(int x, int y, int z, int maxDist { shared_ptr closest = nullptr; float closestDistSqr = Float::MAX_VALUE; - //for (Village village : villages) for(AUTO_VAR(it, villages.begin()); it != villages.end(); ++it) { shared_ptr village = *it; @@ -118,13 +115,11 @@ void Villages::processNextQuery() void Villages::cluster() { // note doesn't merge or split existing villages - //for (int i = 0; i < unclustered.size(); ++i) for(AUTO_VAR(it, unclustered.begin()); it != unclustered.end(); ++it) { - shared_ptr di = *it; //unclustered.get(i); + shared_ptr di = *it; bool found = false; - //for (Village village : villages) for(AUTO_VAR(itV, villages.begin()); itV != villages.end(); ++itV) { shared_ptr village = *itV; diff --git a/Minecraft.World/VineTile.cpp b/Minecraft.World/VineTile.cpp index 1170caf2..25600cbd 100644 --- a/Minecraft.World/VineTile.cpp +++ b/Minecraft.World/VineTile.cpp @@ -10,7 +10,7 @@ VineTile::VineTile(int id) : Tile(id, Material::replaceable_plant, isSolidRender() ) { - setTicking(true); + setTicking(true); } void VineTile::updateDefaultShape() @@ -35,68 +35,68 @@ bool VineTile::isCubeShaped() void VineTile::updateShape(LevelSource *level, int x, int y, int z, int forceData, shared_ptr forceEntity) // 4J added forceData, forceEntity param { - const float thickness = 1.0f / 16.0f; + const float thickness = 1.0f / 16.0f; - int facings = level->getData(x, y, z); + int facings = level->getData(x, y, z); - float minX = 1; - float minY = 1; - float minZ = 1; - float maxX = 0; - float maxY = 0; - float maxZ = 0; - bool hasWall = facings > 0; + float minX = 1; + float minY = 1; + float minZ = 1; + float maxX = 0; + float maxY = 0; + float maxZ = 0; + bool hasWall = facings > 0; - if ((facings & VINE_WEST) != 0) + if ((facings & VINE_WEST) != 0) { - maxX = Math::_max(maxX, thickness); - minX = 0; - minY = 0; - maxY = 1; - minZ = 0; - maxZ = 1; - hasWall = true; - } - if ((facings & VINE_EAST) != 0) + maxX = Math::_max(maxX, thickness); + minX = 0; + minY = 0; + maxY = 1; + minZ = 0; + maxZ = 1; + hasWall = true; + } + if ((facings & VINE_EAST) != 0) { - minX = Math::_min(minX, 1 - thickness); - maxX = 1; - minY = 0; - maxY = 1; - minZ = 0; - maxZ = 1; - hasWall = true; - } - if ((facings & VINE_NORTH) != 0) + minX = Math::_min(minX, 1 - thickness); + maxX = 1; + minY = 0; + maxY = 1; + minZ = 0; + maxZ = 1; + hasWall = true; + } + if ((facings & VINE_NORTH) != 0) { - maxZ = Math::_max(maxZ, thickness); - minZ = 0; - minX = 0; - maxX = 1; - minY = 0; - maxY = 1; - hasWall = true; - } - if ((facings & VINE_SOUTH) != 0) + maxZ = Math::_max(maxZ, thickness); + minZ = 0; + minX = 0; + maxX = 1; + minY = 0; + maxY = 1; + hasWall = true; + } + if ((facings & VINE_SOUTH) != 0) { - minZ = Math::_min(minZ, 1 - thickness); - maxZ = 1; - minX = 0; - maxX = 1; - minY = 0; - maxY = 1; - hasWall = true; - } - if (!hasWall && isAcceptableNeighbor(level->getTile(x, y + 1, z))) + minZ = Math::_min(minZ, 1 - thickness); + maxZ = 1; + minX = 0; + maxX = 1; + minY = 0; + maxY = 1; + hasWall = true; + } + if (!hasWall && isAcceptableNeighbor(level->getTile(x, y + 1, z))) { - minY = Math::_min(minY, 1 - thickness); - maxY = 1; - minX = 0; - maxX = 1; - minZ = 0; - maxZ = 1; - } - setShape(minX, minY, minZ, maxX, maxY, maxZ); + minY = Math::_min(minY, 1 - thickness); + maxY = 1; + minX = 0; + maxX = 1; + minZ = 0; + maxZ = 1; + } + setShape(minX, minY, minZ, maxX, maxY, maxZ); } @@ -107,69 +107,69 @@ AABB *VineTile::getAABB(Level *level, int x, int y, int z) bool VineTile::mayPlace(Level *level, int x, int y, int z, int face) { - switch (face) + switch (face) { - default: - return false; - case Facing::UP: - return isAcceptableNeighbor(level->getTile(x, y + 1, z)); - case Facing::NORTH: - return isAcceptableNeighbor(level->getTile(x, y, z + 1)); - case Facing::SOUTH: - return isAcceptableNeighbor(level->getTile(x, y, z - 1)); - case Facing::EAST: - return isAcceptableNeighbor(level->getTile(x - 1, y, z)); - case Facing::WEST: - return isAcceptableNeighbor(level->getTile(x + 1, y, z)); - } + default: + return false; + case Facing::UP: + return isAcceptableNeighbor(level->getTile(x, y + 1, z)); + case Facing::NORTH: + return isAcceptableNeighbor(level->getTile(x, y, z + 1)); + case Facing::SOUTH: + return isAcceptableNeighbor(level->getTile(x, y, z - 1)); + case Facing::EAST: + return isAcceptableNeighbor(level->getTile(x - 1, y, z)); + case Facing::WEST: + return isAcceptableNeighbor(level->getTile(x + 1, y, z)); + } } bool VineTile::isAcceptableNeighbor(int id) { - if (id == 0) return false; - Tile *tile = Tile::tiles[id]; - if (tile->isCubeShaped() && tile->material->blocksMotion()) return true; - return false; + if (id == 0) return false; + Tile *tile = Tile::tiles[id]; + if (tile->isCubeShaped() && tile->material->blocksMotion()) return true; + return false; } bool VineTile::updateSurvival(Level *level, int x, int y, int z) { - int facings = level->getData(x, y, z); - int newFacings = facings; + int facings = level->getData(x, y, z); + int newFacings = facings; - if (newFacings > 0) + if (newFacings > 0) { - for (int d = 0; d <= 3; d++) + for (int d = 0; d <= 3; d++) { - int facing = 1 << d; - if ((facings & facing) != 0) + int facing = 1 << d; + if ((facings & facing) != 0) { - if (!isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[d], y, z + Direction::STEP_Z[d]))) + if (!isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[d], y, z + Direction::STEP_Z[d]))) { - // no attachment in this direction, - // verify that there is vines hanging above - if (level->getTile(x, y + 1, z) != id || (level->getData(x, y + 1, z) & facing) == 0) + // no attachment in this direction, + // verify that there is vines hanging above + if (level->getTile(x, y + 1, z) != id || (level->getData(x, y + 1, z) & facing) == 0) { - newFacings &= ~facing; - } - } - } - } - } - - if (newFacings == 0) + newFacings &= ~facing; + } + } + } + } + } + + if (newFacings == 0) { - // the block will die unless it has a roof - if (!isAcceptableNeighbor(level->getTile(x, y + 1, z))) + // the block will die unless it has a roof + if (!isAcceptableNeighbor(level->getTile(x, y + 1, z))) { - return false; - } - } - if (newFacings != facings) + return false; + } + } + if (newFacings != facings) { - level->setData(x, y, z, newFacings); - } - return true; + level->setData(x, y, z, newFacings, Tile::UPDATE_CLIENTS); + } + return true; } @@ -195,18 +195,18 @@ int VineTile::getColor(LevelSource *level, int x, int y, int z) void VineTile::neighborChanged(Level *level, int x, int y, int z, int type) { - if (!level->isClientSide && !updateSurvival(level, x, y, z)) + if (!level->isClientSide && !updateSurvival(level, x, y, z)) { - spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); - } + spawnResources(level, x, y, z, level->getData(x, y, z), 0); + level->removeTile(x, y, z); + } } void VineTile::tick(Level *level, int x, int y, int z, Random *random) { - if (!level->isClientSide) + if (!level->isClientSide) { - if (level->random->nextInt(4) == 0) + if (level->random->nextInt(4) == 0) { // 4J - Brought side spread check forward from 1.2.3 int r = 4; @@ -226,110 +226,111 @@ void VineTile::tick(Level *level, int x, int y, int z, Random *random) testLoop: if(noSideSpread) break; } - int currentFacings = level->getData(x, y, z); - int testFacing = level->random->nextInt(6); - int testDirection = Direction::FACING_DIRECTION[testFacing]; + int currentFacings = level->getData(x, y, z); + int testFacing = level->random->nextInt(6); + int testDirection = Direction::FACING_DIRECTION[testFacing]; if (testFacing == Facing::UP && y < (Level::maxBuildHeight - 1) && level->isEmptyTile(x, y + 1, z)) { // 4J - Brought side spread check forward from 1.2.3 if (noSideSpread) return; - // grow upwards, but only if there is something to cling to - int spawnFacings = level->random->nextInt(16) & currentFacings; - if (spawnFacings > 0) + // grow upwards, but only if there is something to cling to + int spawnFacings = level->random->nextInt(16) & currentFacings; + if (spawnFacings > 0) { - for (int d = 0; d <= 3; d++) + for (int d = 0; d <= 3; d++) { - if (!isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[d], y + 1, z + Direction::STEP_Z[d]))) + if (!isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[d], y + 1, z + Direction::STEP_Z[d]))) { - spawnFacings &= ~(1 << d); - } - } - if (spawnFacings > 0) + spawnFacings &= ~(1 << d); + } + } + if (spawnFacings > 0) { - level->setTileAndData(x, y + 1, z, id, spawnFacings); - } - } - } + level->setTileAndData(x, y + 1, z, id, spawnFacings, Tile::UPDATE_CLIENTS); + } + } + } else if (testFacing >= Facing::NORTH && testFacing <= Facing::EAST && (currentFacings & (1 << testDirection)) == 0) { // 4J - Brought side spread check forward from 1.2.3 if (noSideSpread) return; - int edgeTile = level->getTile(x + Direction::STEP_X[testDirection], y, z + Direction::STEP_Z[testDirection]); + int edgeTile = level->getTile(x + Direction::STEP_X[testDirection], y, z + Direction::STEP_Z[testDirection]); - if (edgeTile == 0 || Tile::tiles[edgeTile] == NULL) + if (edgeTile == 0 || Tile::tiles[edgeTile] == NULL) { - // if the edge tile is air, we could possibly cling - // to something - int left = (testDirection + 1) & 3; - int right = (testDirection + 3) & 3; - - // attempt to grow straight onto solid tiles - if ((currentFacings & (1 << left)) != 0 - && isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[testDirection] + Direction::STEP_X[left], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[left]))) + // if the edge tile is air, we could possibly cling + // to something + int left = (testDirection + 1) & 3; + int right = (testDirection + 3) & 3; + + // attempt to grow straight onto solid tiles + if ((currentFacings & (1 << left)) != 0 + && isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[testDirection] + Direction::STEP_X[left], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[left]))) { - level->setTileAndData(x + Direction::STEP_X[testDirection], y, z + Direction::STEP_Z[testDirection], id, 1 << left); - } + level->setTileAndData(x + Direction::STEP_X[testDirection], y, z + Direction::STEP_Z[testDirection], id, 1 << left, Tile::UPDATE_CLIENTS); + } else if ((currentFacings & (1 << right)) != 0 - && isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[testDirection] + Direction::STEP_X[right], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[right]))) + && isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[testDirection] + Direction::STEP_X[right], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[right]))) { - level->setTileAndData(x + Direction::STEP_X[testDirection], y, z + Direction::STEP_Z[testDirection], id, 1 << right); - } - // attempt to grow around corners, but only if the - // base tile is solid - else if ((currentFacings & (1 << left)) != 0 - && level->isEmptyTile(x + Direction::STEP_X[testDirection] + Direction::STEP_X[left], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[left]) - && isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[left], y, z + Direction::STEP_Z[left]))) + level->setTileAndData(x + Direction::STEP_X[testDirection], y, z + Direction::STEP_Z[testDirection], id, 1 << right, Tile::UPDATE_CLIENTS); + } + // attempt to grow around corners, but only if the + // base tile is solid + else if ((currentFacings & (1 << left)) != 0 + && level->isEmptyTile(x + Direction::STEP_X[testDirection] + Direction::STEP_X[left], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[left]) + && isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[left], y, z + Direction::STEP_Z[left]))) { - level->setTileAndData(x + Direction::STEP_X[testDirection] + Direction::STEP_X[left], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[left], id, - 1 << ((testDirection + 2) & 3)); - } + level->setTileAndData(x + Direction::STEP_X[testDirection] + Direction::STEP_X[left], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[left], id, + 1 << ((testDirection + 2) & 3), Tile::UPDATE_CLIENTS); + } else if ((currentFacings & (1 << right)) != 0 - && level->isEmptyTile(x + Direction::STEP_X[testDirection] + Direction::STEP_X[right], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[right]) - && isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[right], y, z + Direction::STEP_Z[right]))) + && level->isEmptyTile(x + Direction::STEP_X[testDirection] + Direction::STEP_X[right], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[right]) + && isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[right], y, z + Direction::STEP_Z[right]))) { - level->setTileAndData(x + Direction::STEP_X[testDirection] + Direction::STEP_X[right], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[right], id, - 1 << ((testDirection + 2) & 3)); - } - // attempt to grow onto the ceiling - else if (isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[testDirection], y + 1, z + Direction::STEP_Z[testDirection]))) + level->setTileAndData(x + Direction::STEP_X[testDirection] + Direction::STEP_X[right], y, z + Direction::STEP_Z[testDirection] + Direction::STEP_Z[right], id, + 1 << ((testDirection + 2) & 3), Tile::UPDATE_CLIENTS); + } + // attempt to grow onto the ceiling + else if (isAcceptableNeighbor(level->getTile(x + Direction::STEP_X[testDirection], y + 1, z + Direction::STEP_Z[testDirection]))) { - level->setTileAndData(x + Direction::STEP_X[testDirection], y, z + Direction::STEP_Z[testDirection], id, 0); - } + level->setTileAndData(x + Direction::STEP_X[testDirection], y, z + Direction::STEP_Z[testDirection], id, 0, Tile::UPDATE_CLIENTS); + } - } + } else if (Tile::tiles[edgeTile]->material->isSolidBlocking() && Tile::tiles[edgeTile]->isCubeShaped()) { - // we have a wall that we can cling to - level->setData(x, y, z, currentFacings | (1 << testDirection)); - } - } - // growing downwards happens more often than the other - // directions - else if (y > 1) + // we have a wall that we can cling to + level->setData(x, y, z, currentFacings | (1 << testDirection), Tile::UPDATE_CLIENTS); + } + } + // growing downwards happens more often than the other + // directions + else if (y > 1) { - int belowTile = level->getTile(x, y - 1, z); - // grow downwards into air - if (belowTile == 0) + int belowTile = level->getTile(x, y - 1, z); + // grow downwards into air + if (belowTile == 0) { - int spawnFacings = level->random->nextInt(16) & currentFacings; - if (spawnFacings > 0) + int spawnFacings = level->random->nextInt(16) & currentFacings; + if (spawnFacings > 0) { - level->setTileAndData(x, y - 1, z, id, spawnFacings); - } - } + level->setTileAndData(x, y - 1, z, id, spawnFacings, Tile::UPDATE_CLIENTS); + } + } else if (belowTile == id) { - int spawnFacings = level->random->nextInt(16) & currentFacings; - int belowData = level->getData(x, y - 1, z); - if (belowData != (belowData | spawnFacings)) { - level->setData(x, y - 1, z, belowData | spawnFacings); - } - } - } - } + int spawnFacings = level->random->nextInt(16) & currentFacings; + int belowData = level->getData(x, y - 1, z); + if (belowData != (belowData | spawnFacings)) + { + level->setData(x, y - 1, z, belowData | spawnFacings, Tile::UPDATE_CLIENTS); + } + } + } + } } } @@ -377,11 +378,11 @@ void VineTile::playerDestroy(Level *level, shared_ptrplayer, int x, int GenericStats::param_blocksMined(id,data,1) ); - // drop leaf block instead of sapling - popResource(level, x, y, z, shared_ptr(new ItemInstance(Tile::vine, 1, 0))); - } + // drop leaf block instead of sapling + popResource(level, x, y, z, shared_ptr(new ItemInstance(Tile::vine, 1, 0))); + } else { - Tile::playerDestroy(level, player, x, y, z, data); - } + Tile::playerDestroy(level, player, x, y, z, data); + } } diff --git a/Minecraft.World/VinesFeature.cpp b/Minecraft.World/VinesFeature.cpp index 314b978e..1f2dacf4 100644 --- a/Minecraft.World/VinesFeature.cpp +++ b/Minecraft.World/VinesFeature.cpp @@ -22,7 +22,7 @@ bool VinesFeature::place(Level *level, Random *random, int x, int y, int z) { if (Tile::vine->mayPlace(level, x, y, z, face)) { - level->setTileAndDataNoUpdate(x, y, z, Tile::vine_Id, 1 << Direction::FACING_DIRECTION[Facing::OPPOSITE_FACING[face]]); + level->setTileAndData(x, y, z, Tile::vine_Id, 1 << Direction::FACING_DIRECTION[Facing::OPPOSITE_FACING[face]], Tile::UPDATE_CLIENTS); break; } } diff --git a/Minecraft.World/WallTile.cpp b/Minecraft.World/WallTile.cpp index 6275eef7..a95360ce 100644 --- a/Minecraft.World/WallTile.cpp +++ b/Minecraft.World/WallTile.cpp @@ -26,9 +26,9 @@ Icon *WallTile::getTexture(int face, int data) { if (data == TYPE_MOSSY) { - return Tile::mossStone->getTexture(face); + return Tile::mossyCobblestone->getTexture(face); } - return Tile::stoneBrick->getTexture(face); + return Tile::cobblestone->getTexture(face); } int WallTile::getRenderShape() diff --git a/Minecraft.World/WaterAnimal.cpp b/Minecraft.World/WaterAnimal.cpp index 0a7313d1..fe94b628 100644 --- a/Minecraft.World/WaterAnimal.cpp +++ b/Minecraft.World/WaterAnimal.cpp @@ -3,6 +3,7 @@ #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.phys.h" #include "net.minecraft.world.level.h" +#include "net.minecraft.world.damagesource.h" #include "WaterAnimal.h" @@ -39,4 +40,25 @@ bool WaterAnimal::removeWhenFarAway() int WaterAnimal::getExperienceReward(shared_ptr killedBy) { return 1 + level->random->nextInt(3); +} + +void WaterAnimal::baseTick() +{ + int airSupply = getAirSupply(); + + PathfinderMob::baseTick(); // this modified the airsupply + + if (isAlive() && !isInWater()) + { + setAirSupply(--airSupply); + if (getAirSupply() == -20) + { + setAirSupply(0); + hurt(DamageSource::drown, 2); + } + } + else + { + setAirSupply(TOTAL_AIR_SUPPLY); + } } \ No newline at end of file diff --git a/Minecraft.World/WaterAnimal.h b/Minecraft.World/WaterAnimal.h index 23b984f5..1da551c5 100644 --- a/Minecraft.World/WaterAnimal.h +++ b/Minecraft.World/WaterAnimal.h @@ -15,4 +15,7 @@ public: protected: virtual bool removeWhenFarAway(); virtual int getExperienceReward(shared_ptr killedBy); + +public: + virtual void baseTick(); }; diff --git a/Minecraft.World/WaterLevelChunk.cpp b/Minecraft.World/WaterLevelChunk.cpp index b6dbd05d..7727898b 100644 --- a/Minecraft.World/WaterLevelChunk.cpp +++ b/Minecraft.World/WaterLevelChunk.cpp @@ -94,6 +94,11 @@ void WaterLevelChunk::unload(bool unloadTileEntities) // 4J - added parameter { } +bool WaterLevelChunk::containsPlayer() +{ + return false; +} + void WaterLevelChunk::markUnsaved() { } diff --git a/Minecraft.World/WaterLevelChunk.h b/Minecraft.World/WaterLevelChunk.h index 18dc8a05..d2753cfa 100644 --- a/Minecraft.World/WaterLevelChunk.h +++ b/Minecraft.World/WaterLevelChunk.h @@ -31,6 +31,7 @@ public: void removeTileEntity(int x, int y, int z); void load(); void unload(bool unloadTileEntities) ; // 4J - added parameter + bool containsPlayer(); // 4J added void markUnsaved(); void getEntities(shared_ptr except, AABB bb, vector > &es); void getEntitiesOfClass(const type_info& ec, AABB bb, vector > &es); diff --git a/Minecraft.World/WaterLilyTile.cpp b/Minecraft.World/WaterLilyTile.cpp index 91203922..15e43b9d 100644 --- a/Minecraft.World/WaterLilyTile.cpp +++ b/Minecraft.World/WaterLilyTile.cpp @@ -7,25 +7,25 @@ WaterlilyTile::WaterlilyTile(int id) : Bush(id) { - this->updateDefaultShape(); + this->updateDefaultShape(); } // 4J Added override void WaterlilyTile::updateDefaultShape() { - float ss = 0.5f; - float hh = 0.25f / 16.0f; - this->setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, hh, 0.5f + ss); + float ss = 0.5f; + float hh = 0.25f / 16.0f; + setShape(0.5f - ss, 0, 0.5f - ss, 0.5f + ss, hh, 0.5f + ss); } int WaterlilyTile::getRenderShape() { - return Tile::SHAPE_LILYPAD; + return Tile::SHAPE_LILYPAD; } void WaterlilyTile::addAABBs(Level *level, int x, int y, int z, AABB *box, AABBList *boxes, shared_ptr source) { - if (source == NULL || !(dynamic_pointer_cast(source))) + if (source == NULL || !source->instanceof(eTYPE_BOAT)) { Bush::addAABBs(level, x, y, z, box, boxes, source); } @@ -67,7 +67,7 @@ bool WaterlilyTile::mayPlaceOn(int tile) bool WaterlilyTile::canSurvive(Level *level, int x, int y, int z) { if (y < 0 || y >= Level::maxBuildHeight) return false; - return level->getMaterial(x, y - 1, z) == Material::water && level->getData(x, y - 1, z) == 0; + return level->getMaterial(x, y - 1, z) == Material::water && level->getData(x, y - 1, z) == 0; } bool WaterlilyTile::growTree(Level *level, int x, int y, int z, Random *random) diff --git a/Minecraft.World/WaterLilyTileItem.cpp b/Minecraft.World/WaterLilyTileItem.cpp index 13814e5c..fe523c05 100644 --- a/Minecraft.World/WaterLilyTileItem.cpp +++ b/Minecraft.World/WaterLilyTileItem.cpp @@ -10,7 +10,7 @@ WaterLilyTileItem::WaterLilyTileItem(int id) : ColoredTileItem(id, false) { } -bool WaterLilyTileItem::TestUse(Level *level, shared_ptr player) +bool WaterLilyTileItem::TestUse(shared_ptr itemInstance, Level *level, shared_ptr player) { HitResult *hr = getPlayerPOVHitResult(level, player, true); if (hr == NULL) return false; @@ -20,13 +20,18 @@ bool WaterLilyTileItem::TestUse(Level *level, shared_ptr player) int xt = hr->x; int yt = hr->y; int zt = hr->z; - delete hr; if (!level->mayInteract(player, xt, yt, zt, 0)) { + delete hr; return false; } - if (!player->mayBuild(xt, yt, zt)) return false; - + if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) + { + delete hr; + return false; + } + + delete hr; if (level->getMaterial(xt, yt, zt) == Material::water && level->getData(xt, yt, zt) == 0 && level->isEmptyTile(xt, yt + 1, zt)) { return true; @@ -49,16 +54,21 @@ shared_ptr WaterLilyTileItem::use(shared_ptr itemIns int xt = hr->x; int yt = hr->y; int zt = hr->z; - delete hr; if (!level->mayInteract(player, xt, yt, zt, 0)) { + delete hr; return itemInstance; } - if (!player->mayBuild(xt, yt, zt)) return itemInstance; - + if (!player->mayUseItemAt(xt, yt, zt, hr->f, itemInstance)) + { + delete hr; + return itemInstance; + } + + delete hr; if (level->getMaterial(xt, yt, zt) == Material::water && level->getData(xt, yt, zt) == 0 && level->isEmptyTile(xt, yt + 1, zt)) { - level->setTile(xt, yt + 1, zt, Tile::waterLily->id); + level->setTileAndUpdate(xt, yt + 1, zt, Tile::waterLily->id); if (!player->abilities.instabuild) { itemInstance->count--; diff --git a/Minecraft.World/WaterLilyTileItem.h b/Minecraft.World/WaterLilyTileItem.h index c0c5db99..c107578f 100644 --- a/Minecraft.World/WaterLilyTileItem.h +++ b/Minecraft.World/WaterLilyTileItem.h @@ -9,6 +9,6 @@ public: WaterLilyTileItem(int id); virtual shared_ptr use(shared_ptr itemInstance, Level *level, shared_ptr player); - virtual bool TestUse(Level *level, shared_ptr player); + virtual bool TestUse(shared_ptr itemInstance, Level *level, shared_ptr player); virtual int getColor(int data, int spriteLayer); }; diff --git a/Minecraft.World/WaterlilyFeature.cpp b/Minecraft.World/WaterlilyFeature.cpp index c47a667c..eccfcaf6 100644 --- a/Minecraft.World/WaterlilyFeature.cpp +++ b/Minecraft.World/WaterlilyFeature.cpp @@ -5,19 +5,19 @@ bool WaterlilyFeature::place(Level *level, Random *random, int x, int y, int z) { - for (int i = 0; i < 10; i++) + for (int i = 0; i < 10; i++) { - int x2 = x + random->nextInt(8) - random->nextInt(8); - int y2 = y + random->nextInt(4) - random->nextInt(4); - int z2 = z + random->nextInt(8) - random->nextInt(8); - if (level->isEmptyTile(x2, y2, z2)) + int x2 = x + random->nextInt(8) - random->nextInt(8); + int y2 = y + random->nextInt(4) - random->nextInt(4); + int z2 = z + random->nextInt(8) - random->nextInt(8); + if (level->isEmptyTile(x2, y2, z2)) { - if (Tile::waterLily->mayPlace(level, x2, y2, z2)) + if (Tile::waterLily->mayPlace(level, x2, y2, z2)) { - level->setTileNoUpdate(x2, y2, z2, Tile::waterLily_Id); - } - } - } + level->setTileAndData(x2, y2, z2, Tile::waterLily_Id, 0, Tile::UPDATE_CLIENTS); + } + } + } - return true; + return true; } \ No newline at end of file diff --git a/Minecraft.World/WeaponItem.cpp b/Minecraft.World/WeaponItem.cpp index 82b16bde..67b887af 100644 --- a/Minecraft.World/WeaponItem.cpp +++ b/Minecraft.World/WeaponItem.cpp @@ -1,49 +1,58 @@ #include "stdafx.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.player.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.level.tile.h" #include "WeaponItem.h" WeaponItem::WeaponItem(int id, const Tier *tier) : Item(id), tier( tier ) { - maxStackSize = 1; - setMaxDamage(tier->getUses()); + maxStackSize = 1; + setMaxDamage(tier->getUses()); - damage = 4 + tier->getAttackDamageBonus(); + damage = 4 + tier->getAttackDamageBonus(); } -float WeaponItem::getDestroySpeed(shared_ptr itemInstance, Tile *tile) +float WeaponItem::getTierDamage() { - if (tile->id == Tile::web_Id) - { - // swords can quickly cut web - return 15; - } - return 1.5f; + return tier->getAttackDamageBonus(); } -bool WeaponItem::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) +float WeaponItem::getDestroySpeed(shared_ptr itemInstance, Tile *tile) { - itemInstance->hurt(1, attacker); - return true; + if (tile->id == Tile::web_Id) + { + // swords can quickly cut web + return 15; + } + // this change modifies which tiles the swords can destroy in creative + // mode (>1 == yes) + Material *material = tile->material; + if (material == Material::plant || material == Material::replaceable_plant || material == Material::coral || material == Material::leaves || material == Material::vegetable) + { + return 1.5f; + } + return 1.0f; } -bool WeaponItem::mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner) +bool WeaponItem::hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker) { - // Don't damage weapons if the tile can be destroyed in one hit. - if (Tile::tiles[tile]->getDestroySpeed(level, x, y, z) != 0.0) itemInstance->hurt(2, owner); + itemInstance->hurtAndBreak(1, attacker); return true; } -int WeaponItem::getAttackDamage(shared_ptr entity) +bool WeaponItem::mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner) { - return damage; + // Don't damage weapons if the tile can be destroyed in one hit. + if (Tile::tiles[tile]->getDestroySpeed(level, x, y, z) != 0.0) itemInstance->hurtAndBreak(2, owner); + return true; } bool WeaponItem::isHandEquipped() { - return true; + return true; } UseAnim WeaponItem::getUseAnimation(shared_ptr itemInstance) @@ -64,7 +73,7 @@ shared_ptr WeaponItem::use(shared_ptr instance, Leve bool WeaponItem::canDestroySpecial(Tile *tile) { - return tile->id == Tile::web_Id; + return tile->id == Tile::web_Id; } int WeaponItem::getEnchantmentValue() @@ -84,4 +93,13 @@ bool WeaponItem::isValidRepairItem(shared_ptr source, shared_ptrinsert(attrAttrModMap::value_type( SharedMonsterAttributes::ATTACK_DAMAGE->getId(), new AttributeModifier(eModifierId_ITEM_BASEDAMAGE, damage, AttributeModifier::OPERATION_ADDITION) ) ); + + return result; } \ No newline at end of file diff --git a/Minecraft.World/WeaponItem.h b/Minecraft.World/WeaponItem.h index 2150f6e9..54cb2f2d 100644 --- a/Minecraft.World/WeaponItem.h +++ b/Minecraft.World/WeaponItem.h @@ -6,16 +6,15 @@ using namespace std; class WeaponItem : public Item { private: - int damage; + float damage; const Tier *tier; public: WeaponItem(int id, const Tier *tier); - + virtual float getTierDamage(); virtual float getDestroySpeed(shared_ptr itemInstance, Tile *tile); - virtual bool hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker); - virtual bool mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner); - virtual int getAttackDamage(shared_ptr entity); + virtual bool hurtEnemy(shared_ptr itemInstance, shared_ptr mob, shared_ptr attacker); + virtual bool mineBlock(shared_ptr itemInstance, Level *level, int tile, int x, int y, int z, shared_ptr owner); virtual bool isHandEquipped(); virtual UseAnim getUseAnimation(shared_ptr itemInstance); virtual int getUseDuration(shared_ptr itemInstance); @@ -25,4 +24,5 @@ public: const Tier *getTier(); bool isValidRepairItem(shared_ptr source, shared_ptr repairItem); + attrAttrModMap *getDefaultAttributeModifiers(); }; \ No newline at end of file diff --git a/Minecraft.World/WeaponRecipies.cpp b/Minecraft.World/WeaponRecipies.cpp index e90ebea6..1dbe6bda 100644 --- a/Minecraft.World/WeaponRecipies.cpp +++ b/Minecraft.World/WeaponRecipies.cpp @@ -13,20 +13,13 @@ wstring WeaponRecipies::shapes[][4] = L"X",// L"#",L""},// }; - -/* - private Object[][] map = { - {Tile.wood, Tile.stoneBrick, Item.ironIngot, Item.diamond, Item.goldIngot}, - {Item.sword_wood, Item.sword_stone, Item.sword_iron, Item.sword_diamond, Item.sword_gold}, - }; -*/ void WeaponRecipies::_init() { map = new vector [MAX_WEAPON_RECIPES]; ADD_OBJECT(map[0],Tile::wood); - ADD_OBJECT(map[0],Tile::stoneBrick); + ADD_OBJECT(map[0],Tile::cobblestone); ADD_OBJECT(map[0],Item::ironIngot); ADD_OBJECT(map[0],Item::diamond); ADD_OBJECT(map[0],Item::goldIngot); diff --git a/Minecraft.World/WeatherCommand.h b/Minecraft.World/WeatherCommand.h new file mode 100644 index 00000000..795b7bdf --- /dev/null +++ b/Minecraft.World/WeatherCommand.h @@ -0,0 +1,73 @@ +/* +package net.minecraft.commands.common; + +import java.util.*; + +import net.minecraft.SharedConstants; +import net.minecraft.commands.*; +import net.minecraft.commands.exceptions.UsageException; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.storage.LevelData; + +public class WeatherCommand extends BaseCommand { + @Override + public String getName() { + return "weather"; + } + + @Override + public int getPermissionLevel() { + return LEVEL_GAMEMASTERS; + } + + @Override + public String getUsage(CommandSender source) { + return "commands.weather.usage"; + } + + @Override + public void execute(CommandSender source, String[] args) { + if (args.length < 1 || args.length > 2) { + throw new UsageException("commands.weather.usage"); + } + + int duration = (300 + new Random().nextInt(600)) * SharedConstants.TICKS_PER_SECOND; + if (args.length >= 2) { + duration = convertArgToInt(source, args[1], 1, 1000000) * SharedConstants.TICKS_PER_SECOND; + } + + Level level = MinecraftServer.getInstance().levels[0]; + LevelData levelData = level.getLevelData(); + levelData.setRainTime(duration); + levelData.setThunderTime(duration); + + if ("clear".equalsIgnoreCase(args[0])) { + levelData.setRaining(false); + levelData.setThundering(false); + logAdminAction(source, "commands.weather.clear"); + } else if ("rain".equalsIgnoreCase(args[0])) { + levelData.setRaining(true); + levelData.setThundering(false); + logAdminAction(source, "commands.weather.rain"); + } else if ("thunder".equalsIgnoreCase(args[0])) { + levelData.setRaining(true); + levelData.setThundering(true); + logAdminAction(source, "commands.weather.thunder"); + } else { + throw new UsageException("commands.weather.usage"); + } + } + + @Override + public List matchArguments(CommandSender source, String[] args) { + if (args.length == 1) { + return matchArguments(args, "clear", "rain", "thunder"); + } + + return null; + } + +} + +*/ \ No newline at end of file diff --git a/Minecraft.World/WeighedTreasure.cpp b/Minecraft.World/WeighedTreasure.cpp index d7044644..ec4280e4 100644 --- a/Minecraft.World/WeighedTreasure.cpp +++ b/Minecraft.World/WeighedTreasure.cpp @@ -18,7 +18,7 @@ WeighedTreasure::WeighedTreasure(shared_ptr item, int minCount, in this->maxCount = maxCount; } -void WeighedTreasure::addChestItems(Random *random, WeighedTreasureArray items, shared_ptr dest, int numRolls) +void WeighedTreasure::addChestItems(Random *random, WeighedTreasureArray items, shared_ptr dest, int numRolls) { for (int r = 0; r < numRolls; r++) { diff --git a/Minecraft.World/WeighedTreasure.h b/Minecraft.World/WeighedTreasure.h index a37bc6ae..c97def3d 100644 --- a/Minecraft.World/WeighedTreasure.h +++ b/Minecraft.World/WeighedTreasure.h @@ -13,7 +13,7 @@ public: WeighedTreasure(int itemId, int auxValue, int minCount, int maxCount, int weight); WeighedTreasure(shared_ptr item, int minCount, int maxCount, int weight); - static void addChestItems(Random *random, WeighedTreasureArray items, shared_ptr dest, int numRolls); + static void addChestItems(Random *random, WeighedTreasureArray items, shared_ptr dest, int numRolls); static void addDispenserItems(Random *random, WeighedTreasureArray items, shared_ptr dest, int numRolls); static WeighedTreasureArray addToTreasure(WeighedTreasureArray items, WeighedTreasure *extra); }; \ No newline at end of file diff --git a/Minecraft.World/WeightedPressurePlateTile.cpp b/Minecraft.World/WeightedPressurePlateTile.cpp new file mode 100644 index 00000000..352747ce --- /dev/null +++ b/Minecraft.World/WeightedPressurePlateTile.cpp @@ -0,0 +1,46 @@ +#include "stdafx.h" +#include "net.minecraft.world.entity.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.redstone.h" +#include "net.minecraft.world.item.h" +#include "Entity.h" +#include "WeightedPressurePlateTile.h" + +WeightedPressurePlateTile::WeightedPressurePlateTile(int id, const wstring &tex, Material *material, int maxWeight) : BasePressurePlateTile(id, tex, material) +{ + this->maxWeight = maxWeight; + + // 4J Stu - Move this from base class to use virtual function + updateShape(getDataForSignal(Redstone::SIGNAL_MAX)); +} + +int WeightedPressurePlateTile::getSignalStrength(Level *level, int x, int y, int z) +{ + int weightOfEntities = level->getEntitiesOfClass(typeid(Entity), getSensitiveAABB(x, y, z))->size(); + int count = min(weightOfEntities, maxWeight); + + if (count <= 0) + { + return 0; + } + else + { + float pct = min(maxWeight, count) / (float) maxWeight; + return Mth::ceil(pct * Redstone::SIGNAL_MAX); + } +} + +int WeightedPressurePlateTile::getSignalForData(int data) +{ + return data; +} + +int WeightedPressurePlateTile::getDataForSignal(int signal) +{ + return signal; +} + +int WeightedPressurePlateTile::getTickDelay(Level *level) +{ + return SharedConstants::TICKS_PER_SECOND / 2; +} \ No newline at end of file diff --git a/Minecraft.World/WeightedPressurePlateTile.h b/Minecraft.World/WeightedPressurePlateTile.h new file mode 100644 index 00000000..797d7e22 --- /dev/null +++ b/Minecraft.World/WeightedPressurePlateTile.h @@ -0,0 +1,18 @@ +#pragma once + +#include "BasePressurePlateTile.h" + +class WeightedPressurePlateTile : public BasePressurePlateTile +{ +private: + int maxWeight; + +public: + WeightedPressurePlateTile(int id, const wstring &tex, Material *material, int maxWeight); + +protected: + virtual int getSignalStrength(Level *level, int x, int y, int z); + virtual int getSignalForData(int data); + virtual int getDataForSignal(int signal); + virtual int getTickDelay(Level *level); +}; \ No newline at end of file diff --git a/Minecraft.World/Witch.cpp b/Minecraft.World/Witch.cpp new file mode 100644 index 00000000..c73e9198 --- /dev/null +++ b/Minecraft.World/Witch.cpp @@ -0,0 +1,224 @@ +#include "stdafx.h" +#include "net.minecraft.world.effect.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.ai.goal.h" +#include "net.minecraft.world.entity.ai.goal.target.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.entity.projectile.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.item.alchemy.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.phys.h" +#include "Witch.h" + +AttributeModifier *Witch::SPEED_MODIFIER_DRINKING = (new AttributeModifier(eModifierId_MOB_WITCH_DRINKSPEED, -0.25f, AttributeModifier::OPERATION_ADDITION))->setSerialize(false); + +const int Witch::DEATH_LOOT[Witch::DEATH_LOOT_COUNT] = { + Item::yellowDust_Id, Item::sugar_Id, Item::redStone_Id, Item::spiderEye_Id, Item::glassBottle_Id, Item::gunpowder_Id, Item::stick_Id, Item::stick_Id, +}; + +Witch::Witch(Level *level) : Monster(level) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); + + usingTime = 0; + + goalSelector.addGoal(1, new FloatGoal(this)); + goalSelector.addGoal(2, new RangedAttackGoal(this, this, 1.0, SharedConstants::TICKS_PER_SECOND * 3, 10)); + goalSelector.addGoal(2, new RandomStrollGoal(this, 1.0)); + goalSelector.addGoal(3, new LookAtPlayerGoal(this, typeid(Player), 8)); + goalSelector.addGoal(3, new RandomLookAroundGoal(this)); + + targetSelector.addGoal(1, new HurtByTargetGoal(this, false)); + targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Player), 0, true)); +} + +void Witch::defineSynchedData() +{ + Monster::defineSynchedData(); + + getEntityData()->define(DATA_USING_ITEM, (byte) 0); +} + +int Witch::getAmbientSound() +{ + return eSoundType_MOB_WITCH_IDLE; //"mob.witch.idle"; +} + +int Witch::getHurtSound() +{ + return eSoundType_MOB_WITCH_HURT; //"mob.witch.hurt"; +} + +int Witch::getDeathSound() +{ + return eSoundType_MOB_WITCH_DEATH; //"mob.witch.death"; +} + +void Witch::setUsingItem(bool isUsing) +{ + getEntityData()->set(DATA_USING_ITEM, isUsing ? (byte) 1 : (byte) 0); +} + +bool Witch::isUsingItem() +{ + return getEntityData()->getByte(DATA_USING_ITEM) == 1; +} + +void Witch::registerAttributes() +{ + Monster::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(26); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.25f); +} + +bool Witch::useNewAi() +{ + return true; +} + +void Witch::aiStep() +{ + if (!level->isClientSide) + { + if (isUsingItem()) + { + if (usingTime-- <= 0) + { + setUsingItem(false); + shared_ptr item = getCarriedItem(); + setEquippedSlot(SLOT_WEAPON, nullptr); + + if (item != NULL && item->id == Item::potion_Id) + { + vector *effects = Item::potion->getMobEffects(item); + if (effects != NULL) + { + for(AUTO_VAR(it, effects->begin()); it != effects->end(); ++it) + { + addEffect(new MobEffectInstance(*it)); + } + } + delete effects; + } + + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->removeModifier(SPEED_MODIFIER_DRINKING); + } + } + else + { + int potion = -1; + + if (random->nextFloat() < 0.15f && isOnFire() && !hasEffect(MobEffect::fireResistance)) + { + potion = PotionBrewing::POTION_ID_FIRE_RESISTANCE; + } + else if (random->nextFloat() < 0.05f && getHealth() < getMaxHealth()) + { + potion = PotionBrewing::POTION_ID_HEAL; + } + else if (random->nextFloat() < 0.25f && getTarget() != NULL && !hasEffect(MobEffect::movementSpeed) && getTarget()->distanceToSqr(shared_from_this()) > 11 * 11) + { + potion = PotionBrewing::POTION_ID_SWIFTNESS; + } + else if (random->nextFloat() < 0.25f && getTarget() != NULL && !hasEffect(MobEffect::movementSpeed) && getTarget()->distanceToSqr(shared_from_this()) > 11 * 11) + { + potion = PotionBrewing::POTION_ID_SWIFTNESS; + } + + if (potion > -1) + { + setEquippedSlot(SLOT_WEAPON, shared_ptr( new ItemInstance(Item::potion, 1, potion)) ); + usingTime = getCarriedItem()->getUseDuration(); + setUsingItem(true); + AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + speed->removeModifier(SPEED_MODIFIER_DRINKING); + speed->addModifier(new AttributeModifier(*SPEED_MODIFIER_DRINKING)); + } + } + + if (random->nextFloat() < 0.00075f) + { + level->broadcastEntityEvent(shared_from_this(), EntityEvent::WITCH_HAT_MAGIC); + } + } + + Monster::aiStep(); +} + +void Witch::handleEntityEvent(byte id) +{ + if (id == EntityEvent::WITCH_HAT_MAGIC) + { + for (int i = 0; i < random->nextInt(35) + 10; i++) + { + level->addParticle(eParticleType_witchMagic, x + random->nextGaussian() * .13f, bb->y1 + 0.5f + random->nextGaussian() * .13f, z + random->nextGaussian() * .13f, 0, 0, 0); + } + } + else + { + Monster::handleEntityEvent(id); + } +} + +float Witch::getDamageAfterMagicAbsorb(DamageSource *damageSource, float damage) +{ + damage = Monster::getDamageAfterMagicAbsorb(damageSource, damage); + + if (damageSource->getEntity() == shared_from_this()) damage = 0; + if (damageSource->isMagic()) damage *= 0.15; + + return damage; +} + +void Witch::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) +{ + int passes = random->nextInt(3) + 1; + for (int pass = 0; pass < passes; pass++) + { + int count = random->nextInt(3); + int type = DEATH_LOOT[random->nextInt(DEATH_LOOT_COUNT)]; + if (playerBonusLevel > 0) count += random->nextInt(playerBonusLevel + 1); + + for (int i = 0; i < count; i++) + { + spawnAtLocation(type, 1); + } + } +} + +void Witch::performRangedAttack(shared_ptr target, float power) +{ + if (isUsingItem()) return; + + shared_ptr potion = shared_ptr( new ThrownPotion(level, dynamic_pointer_cast(shared_from_this()), PotionBrewing::POTION_ID_SPLASH_DAMAGE) ); + potion->xRot -= -20; + double xd = (target->x + target->xd) - x; + double yd = (target->y + target->getHeadHeight() - 1.1f) - y; + double zd = (target->z + target->zd) - z; + float dist = Mth::sqrt(xd * xd + zd * zd); + + if (dist >= 8 && !target->hasEffect(MobEffect::movementSlowdown)) + { + potion->setPotionValue(PotionBrewing::POTION_ID_SPLASH_SLOWNESS); + } + else if (target->getHealth() >= 8 && !target->hasEffect(MobEffect::poison)) + { + potion->setPotionValue(PotionBrewing::POTION_ID_SPLASH_POISON); + } + else if (dist <= 3 && !target->hasEffect(MobEffect::weakness) && random->nextFloat() < 0.25f) + { + potion->setPotionValue(PotionBrewing::POTION_ID_SPLASH_WEAKNESS); + } + + potion->shoot(xd, yd + dist * 0.2f, zd, 0.75f, 8); + + level->addEntity(potion); +} \ No newline at end of file diff --git a/Minecraft.World/Witch.h b/Minecraft.World/Witch.h new file mode 100644 index 00000000..256f358f --- /dev/null +++ b/Minecraft.World/Witch.h @@ -0,0 +1,48 @@ +#pragma once + +#include "Monster.h" +#include "RangedAttackMob.h" + +class Witch : public Monster, public RangedAttackMob +{ +public: + eINSTANCEOF GetType() { return eTYPE_WITCH; } + static Entity *create(Level *level) { return new Witch(level); } + +private: + static AttributeModifier *SPEED_MODIFIER_DRINKING; + + static const int DATA_USING_ITEM = 21; + static const int DEATH_LOOT_COUNT = 8; + static const int DEATH_LOOT[DEATH_LOOT_COUNT]; + + int usingTime; + +public: + Witch(Level *level); + +protected: + virtual void defineSynchedData(); + virtual int getAmbientSound(); + virtual int getHurtSound(); + virtual int getDeathSound(); + +public: + virtual void setUsingItem(bool isUsing); + virtual bool isUsingItem(); + +protected: + virtual void registerAttributes(); + +public: + virtual bool useNewAi(); + virtual void aiStep(); + virtual void handleEntityEvent(byte id); + +protected: + virtual float getDamageAfterMagicAbsorb(DamageSource *damageSource, float damage); + virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); + +public: + virtual void performRangedAttack(shared_ptr target, float power); +}; \ No newline at end of file diff --git a/Minecraft.World/WitherBoss.cpp b/Minecraft.World/WitherBoss.cpp new file mode 100644 index 00000000..676f07d9 --- /dev/null +++ b/Minecraft.World/WitherBoss.cpp @@ -0,0 +1,584 @@ +#include "stdafx.h" +#include "net.minecraft.world.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.entity.ai.attributes.h" +#include "net.minecraft.world.entity.ai.goal.h" +#include "net.minecraft.world.entity.ai.goal.target.h" +#include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.monster.h" +#include "net.minecraft.world.entity.projectile.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.item.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" +#include "Mth.h" + +#include "SoundTypes.h" + +#include "WitherBoss.h" + +bool LivingEntitySelector::matches(shared_ptr entity) const +{ + if ( entity->instanceof(eTYPE_LIVINGENTITY) ) + { + return dynamic_pointer_cast(entity)->getMobType() != UNDEAD; + } + else + { + return false; + } +} + +EntitySelector *WitherBoss::livingEntitySelector = new LivingEntitySelector(); + +WitherBoss::WitherBoss(Level *level) : Monster(level) +{ + // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that + // the derived version of the function is called + this->defineSynchedData(); + registerAttributes(); + setHealth(getMaxHealth()); + + for(unsigned int i = 0; i < 2; ++i) + { + xRotHeads[i] = 0.0f; + yRotHeads[i] = 0.0f; + xRotOHeads[i] = 0.0f; + yRotOHeads[i] = 0.0f; + nextHeadUpdate[i] = 0; + idleHeadUpdates[i] = 0; + } + destroyBlocksTick = 0; + + setSize(.9f, 4); + + // noPhysics = true; + fireImmune = true; + + // noCulling = true; + + getNavigation()->setCanFloat(true); + + goalSelector.addGoal(0, new FloatGoal(this)); + goalSelector.addGoal(2, new RangedAttackGoal(this, this, 1.0, SharedConstants::TICKS_PER_SECOND * 2, 20)); + + goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); + goalSelector.addGoal(6, new LookAtPlayerGoal(this, typeid(Player), 8)); + goalSelector.addGoal(7, new RandomLookAroundGoal(this)); + + targetSelector.addGoal(1, new HurtByTargetGoal(this, false)); + targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Mob), 0, false, false, livingEntitySelector)); + + xpReward = Enemy::XP_REWARD_BOSS; +} + +void WitherBoss::defineSynchedData() +{ + Monster::defineSynchedData(); + + entityData->define(DATA_TARGET_A, (int)0); + entityData->define(DATA_TARGET_B, (int)0); + entityData->define(DATA_TARGET_C, (int)0); + entityData->define(DATA_ID_INV, (int)0); +} + +void WitherBoss::addAdditonalSaveData(CompoundTag *entityTag) +{ + Monster::addAdditonalSaveData(entityTag); + + entityTag->putInt(L"Invul", getInvulnerableTicks()); +} + +void WitherBoss::readAdditionalSaveData(CompoundTag *tag) +{ + Monster::readAdditionalSaveData(tag); + + setInvulnerableTicks(tag->getInt(L"Invul")); +} + +float WitherBoss::getShadowHeightOffs() +{ + return bbHeight / 8; +} + +int WitherBoss::getAmbientSound() +{ + return eSoundType_MOB_WITHER_IDLE; //"mob.wither.idle"; +} + +int WitherBoss::getHurtSound() +{ + return eSoundType_MOB_WITHER_HURT; //"mob.wither.hurt"; +} + +int WitherBoss::getDeathSound() +{ + return eSoundType_MOB_WITHER_DEATH; //"mob.wither.death"; +} + +void WitherBoss::aiStep() +{ + yd *= 0.6f; + + if (!level->isClientSide && getAlternativeTarget(0) > 0) + { + shared_ptr e = level->getEntity(getAlternativeTarget(0)); + if (e != NULL) + { + if ((y < e->y) || (!isPowered() && y < (e->y + 5))) + { + if (yd < 0) + { + yd = 0; + } + yd += (.5f - yd) * .6f; + } + + double xdist = e->x - x; + double zdist = e->z - z; + double distSqr = xdist * xdist + zdist * zdist; + if (distSqr > 9) + { + double sd = Mth::sqrt(distSqr); + xd += ((xdist / sd) * .5f - xd) * .6f; + zd += ((zdist / sd) * .5f - zd) * .6f; + } + } + } + if ((xd * xd + zd * zd) > .05f) + { + yRot = (float) atan2(zd, xd) * Mth::RADDEG - 90; + } + Monster::aiStep(); + + + for (int i = 0; i < 2; i++) + { + yRotOHeads[i] = yRotHeads[i]; + xRotOHeads[i] = xRotHeads[i]; + } + + for (int i = 0; i < 2; i++) + { + int entityId = getAlternativeTarget(i + 1); + shared_ptr e = nullptr; + if (entityId > 0) + { + e = level->getEntity(entityId); + } + if (e != NULL) + { + double hx = getHeadX(i + 1); + double hy = getHeadY(i + 1); + double hz = getHeadZ(i + 1); + + double xd = e->x - hx; + double yd = e->y + e->getHeadHeight() - hy; + double zd = e->z - hz; + double sd = Mth::sqrt(xd * xd + zd * zd); + + float yRotD = (float) (atan2(zd, xd) * 180 / PI) - 90; + float xRotD = (float) -(atan2(yd, sd) * 180 / PI); + xRotHeads[i] = rotlerp(xRotHeads[i], xRotD, 40); + yRotHeads[i] = rotlerp(yRotHeads[i], yRotD, 10); + + + } + else + { + yRotHeads[i] = rotlerp(yRotHeads[i], yBodyRot, 10); + } + } + bool _isPowered = isPowered(); + for (int i = 0; i < 3; i++) + { + double hx = getHeadX(i); + double hy = getHeadY(i); + double hz = getHeadZ(i); + + level->addParticle(eParticleType_smoke, hx + random->nextGaussian() * .3f, hy + random->nextGaussian() * .3f, hz + random->nextGaussian() * .3f, 0, 0, 0); + if (_isPowered && level->random->nextInt(4) == 0) + { + level->addParticle(eParticleType_mobSpell, hx + random->nextGaussian() * .3f, hy + random->nextGaussian() * .3f, hz + random->nextGaussian() * .3f, .7f, .7f, .5f); + } + } + if (getInvulnerableTicks() > 0) + { + for (int i = 0; i < 3; i++) + { + level->addParticle(eParticleType_mobSpell, x + random->nextGaussian() * 1.0f, y + random->nextFloat() * 3.3f, z + random->nextGaussian() * 1.0f, .7f, .7f, .9f); + } + } +} + +void WitherBoss::newServerAiStep() +{ + if (getInvulnerableTicks() > 0) + { + int newCount = getInvulnerableTicks() - 1; + + if (newCount <= 0) + { + level->explode(shared_from_this(), x, y + getHeadHeight(), z, 7, false, level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)); + level->globalLevelEvent(LevelEvent::SOUND_WITHER_BOSS_SPAWN, (int) x, (int) y, (int) z, 0); + } + + setInvulnerableTicks(newCount); + if (tickCount % 10 == 0) + { + heal(10); + } + + return; + } + + Monster::newServerAiStep(); + + for (int i = 1; i < 3; i++) + { + if (tickCount >= nextHeadUpdate[i - 1]) + { + nextHeadUpdate[i - 1] = tickCount + SharedConstants::TICKS_PER_SECOND / 2 + random->nextInt(SharedConstants::TICKS_PER_SECOND / 2); + + if (level->difficulty >= Difficulty::NORMAL && idleHeadUpdates[i - 1]++ > 15) + { + float hrange = 10; + float vrange = 5; + double xt = Mth::nextDouble(random, x - hrange, x + hrange); + double yt = Mth::nextDouble(random, y - vrange, y + vrange); + double zt = Mth::nextDouble(random, z - hrange, z + hrange); + performRangedAttack(i + 1, xt, yt, zt, true); + idleHeadUpdates[i - 1] = 0; + } + + int headTarget = getAlternativeTarget(i); + if (headTarget > 0) + { + shared_ptr current = level->getEntity(headTarget); + + // 4J: Added check for instance of living entity, had a problem with IDs being recycled to other entities + if (current == NULL || !current->instanceof(eTYPE_LIVINGENTITY) || !current->isAlive() || distanceToSqr(current) > 30 * 30 || !canSee(current)) + { + setAlternativeTarget(i, 0); + } + else + { + performRangedAttack(i + 1, dynamic_pointer_cast(current) ); + nextHeadUpdate[i - 1] = tickCount + SharedConstants::TICKS_PER_SECOND * 2 + random->nextInt(SharedConstants::TICKS_PER_SECOND); + idleHeadUpdates[i - 1] = 0; + } + } + else + { + vector > *entities = level->getEntitiesOfClass(typeid(LivingEntity), bb->grow(20, 8, 20), livingEntitySelector); + // randomly try to find a target 10 times + for (int attempt = 0; attempt < 10 && !entities->empty(); attempt++) + { + int randomIndex = random->nextInt(entities->size()); + shared_ptr selected = dynamic_pointer_cast( entities->at(randomIndex) ); + + if (selected != shared_from_this() && selected->isAlive() && canSee(selected)) + { + if ( selected->instanceof(eTYPE_PLAYER) ) + { + if (!dynamic_pointer_cast(selected)->abilities.invulnerable) + { + assert(selected->instanceof(eTYPE_LIVINGENTITY)); + setAlternativeTarget(i, selected->entityId); + } + break; + } + else + { + assert(selected->instanceof(eTYPE_LIVINGENTITY)); + setAlternativeTarget(i, selected->entityId); + break; + } + } + // don't pick this again + entities->erase(entities->begin() + randomIndex); + } + delete entities; + } + } + } + if (getTarget() != NULL) + { + assert(getTarget()->instanceof(eTYPE_LIVINGENTITY)); + setAlternativeTarget(0, getTarget()->entityId); + } + else + { + setAlternativeTarget(0, 0); + } + + if (destroyBlocksTick > 0) + { + destroyBlocksTick--; + + if (destroyBlocksTick == 0 && level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)) + { + // destroy all blocks that are within 1 range, counting from + // feet and 3 blocks up + + int feet = Mth::floor(y); + int ox = Mth::floor(x); + int oz = Mth::floor(z); + bool destroyed = false; + + for (int xStep = -1; xStep <= 1; xStep++) + { + for (int zStep = -1; zStep <= 1; zStep++) + { + for (int yStep = 0; yStep <= 3; yStep++) + { + int tx = ox + xStep; + int ty = feet + yStep; + int tz = oz + zStep; + int tile = level->getTile(tx, ty, tz); + if (tile > 0 && tile != Tile::unbreakable_Id && tile != Tile::endPortalTile_Id && tile != Tile::endPortalFrameTile_Id) + { + destroyed = level->destroyTile(tx, ty, tz, true) || destroyed; + } + } + } + } + if (destroyed) + { + level->levelEvent(nullptr, LevelEvent::SOUND_ZOMBIE_DOOR_CRASH, (int) x, (int) y, (int) z, 0); + } + } + } + + if ((tickCount % (SharedConstants::TICKS_PER_SECOND)) == 0) + { + heal(1); + } +} + +void WitherBoss::makeInvulnerable() +{ + setInvulnerableTicks(SharedConstants::TICKS_PER_SECOND * 11); + setHealth(getMaxHealth() / 3); +} + +void WitherBoss::makeStuckInWeb() +{ +} + +int WitherBoss::getArmorValue() +{ + return 4; +} + +double WitherBoss::getHeadX(int index) +{ + if (index <= 0) + { + return x; + } + float headAngle = (yBodyRot + 180 * (index - 1)) / 180.0f * PI; + float cos = Mth::cos(headAngle); + return x + cos * 1.3; +} + +double WitherBoss::getHeadY(int index) +{ + if (index <= 0) + { + return y + 3; + } + else + { + return y + 2.2; + } +} + +double WitherBoss::getHeadZ(int index) +{ + if (index <= 0) + { + return z; + } + float headAngle = (yBodyRot + 180 * (index - 1)) / 180.0f * PI; + float sin = Mth::sin(headAngle); + return z + sin * 1.3; +} + +float WitherBoss::rotlerp(float a, float b, float max) +{ + float diff = Mth::wrapDegrees(b - a); + if (diff > max) + { + diff = max; + } + if (diff < -max) + { + diff = -max; + } + return a + diff; +} + +void WitherBoss::performRangedAttack(int head, shared_ptr target) +{ + performRangedAttack(head, target->x, target->y + target->getHeadHeight() * .5, target->z, head == 0 && random->nextFloat() < 0.001f); +} + +void WitherBoss::performRangedAttack(int head, double tx, double ty, double tz, bool dangerous) +{ + level->levelEvent(nullptr, LevelEvent::SOUND_WITHER_BOSS_SHOOT, (int) x, (int) y, (int) z, 0); + + double hx = getHeadX(head); + double hy = getHeadY(head); + double hz = getHeadZ(head); + + double xd = tx - hx; + double yd = ty - hy; + double zd = tz - hz; + + shared_ptr ie = shared_ptr( new WitherSkull(level, dynamic_pointer_cast(shared_from_this()), xd, yd, zd) ); + if (dangerous) ie->setDangerous(true); + ie->y = hy; + ie->x = hx; + ie->z = hz; + level->addEntity(ie); +} + +void WitherBoss::performRangedAttack(shared_ptr target, float power) +{ + performRangedAttack(0, target); +} + +bool WitherBoss::hurt(DamageSource *source, float dmg) +{ + if (isInvulnerable()) return false; + if (source == DamageSource::drown) return false; + if (getInvulnerableTicks() > 0) + { + return false; + } + + if (isPowered()) + { + shared_ptr directEntity = source->getDirectEntity(); + if (directEntity != NULL && directEntity->GetType() == eTYPE_ARROW) + { + return false; + } + } + + shared_ptr sourceEntity = source->getEntity(); + if (sourceEntity != NULL) + { + if ( sourceEntity->instanceof(eTYPE_PLAYER) ) + { + } + else if ( sourceEntity->instanceof(eTYPE_LIVINGENTITY) && dynamic_pointer_cast(sourceEntity)->getMobType() == getMobType()) + { + // can't be harmed by other undead + return false; + } + } + if (destroyBlocksTick <= 0) + { + destroyBlocksTick = SharedConstants::TICKS_PER_SECOND; + } + + for (int i = 0; i < IDLE_HEAD_UPDATES_SIZE; i++) + { + idleHeadUpdates[i] += 3; + } + + return Monster::hurt(source, dmg); +} + +void WitherBoss::dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel) +{ + spawnAtLocation(Item::netherStar_Id, 1); +} + +void WitherBoss::checkDespawn() +{ + noActionTime = 0; +} + +int WitherBoss::getLightColor(float a) +{ + return SharedConstants::FULLBRIGHT_LIGHTVALUE; +} + +bool WitherBoss::isPickable() +{ + return !removed; +} + +void WitherBoss::causeFallDamage(float distance) +{ +} + +void WitherBoss::addEffect(MobEffectInstance *newEffect) +{ + // do nothing +} + +bool WitherBoss::useNewAi() +{ + return true; +} + +void WitherBoss::registerAttributes() +{ + Monster::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(300); + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.6f); + + // 4J Stu - Don't make it so far! + //getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->setBaseValue(40); +} + +float WitherBoss::getHeadYRot(int i) +{ + return yRotHeads[i]; +} + +float WitherBoss::getHeadXRot(int i) +{ + return xRotHeads[i]; +} + +int WitherBoss::getInvulnerableTicks() +{ + return entityData->getInteger(DATA_ID_INV); +} + +void WitherBoss::setInvulnerableTicks(int invulnerableTicks) +{ + entityData->set(DATA_ID_INV, invulnerableTicks); +} + +int WitherBoss::getAlternativeTarget(int headIndex) +{ + return entityData->getInteger(DATA_TARGET_A + headIndex); +} + +void WitherBoss::setAlternativeTarget(int headIndex, int entityId) +{ + entityData->set(DATA_TARGET_A + headIndex, entityId); +} + +bool WitherBoss::isPowered() +{ + return getHealth() <= getMaxHealth() / 2; +} + +MobType WitherBoss::getMobType() +{ + return UNDEAD; +} + +void WitherBoss::ride(shared_ptr e) +{ + riding = nullptr; +} \ No newline at end of file diff --git a/Minecraft.World/WitherBoss.h b/Minecraft.World/WitherBoss.h new file mode 100644 index 00000000..47e2dff1 --- /dev/null +++ b/Minecraft.World/WitherBoss.h @@ -0,0 +1,109 @@ +#pragma once + +#include "Monster.h" +#include "RangedAttackMob.h" +#include "BossMob.h" + +class LivingEntitySelector : public EntitySelector +{ +public: + virtual bool matches(shared_ptr entity) const; +}; + +class WitherBoss : public Monster, public RangedAttackMob, public BossMob +{ +public: + eINSTANCEOF GetType() { return eTYPE_WITHERBOSS; }; + static Entity *create(Level *level) { return new WitherBoss(level); } + +private: + static const int DATA_TARGET_A = 17; + static const int DATA_TARGET_B = 18; + static const int DATA_TARGET_C = 19; + static const int DATA_ID_INV = 20; + +private: + static const int IDLE_HEAD_UPDATES_SIZE = 2; + float xRotHeads[2]; + float yRotHeads[2]; + float xRotOHeads[2]; + float yRotOHeads[2]; + int nextHeadUpdate[2]; + int idleHeadUpdates[IDLE_HEAD_UPDATES_SIZE]; + int destroyBlocksTick; + + static EntitySelector *livingEntitySelector; + +public: + WitherBoss(Level *level); + +protected: + virtual void defineSynchedData(); + +public: + virtual void addAdditonalSaveData(CompoundTag *entityTag); + virtual void readAdditionalSaveData(CompoundTag *tag); + virtual float getShadowHeightOffs(); + +protected: + virtual int getAmbientSound(); + virtual int getHurtSound(); + virtual int getDeathSound(); + +public: + virtual void aiStep(); + +protected: + virtual void newServerAiStep(); + +public: + virtual void makeInvulnerable(); + virtual void makeStuckInWeb(); + virtual int getArmorValue(); + +private: + virtual double getHeadX(int index); + virtual double getHeadY(int index); + virtual double getHeadZ(int index); + virtual float rotlerp(float a, float b, float max); + virtual void performRangedAttack(int head, shared_ptr target); + virtual void performRangedAttack(int head, double tx, double ty, double tz, bool dangerous); + +public: + virtual void performRangedAttack(shared_ptr target, float power); + virtual bool hurt(DamageSource *source, float dmg); + +protected: + virtual void dropDeathLoot(bool wasKilledByPlayer, int playerBonusLevel); + virtual void checkDespawn(); + +public: + virtual int getLightColor(float a); + virtual bool isPickable(); + +protected: + virtual void causeFallDamage(float distance); + +public: + virtual void addEffect(MobEffectInstance *newEffect); + +protected: + virtual bool useNewAi(); + virtual void registerAttributes(); + +public: + virtual float getHeadYRot(int i); + virtual float getHeadXRot(int i); + virtual int getInvulnerableTicks(); + virtual void setInvulnerableTicks(int invulnerableTicks); + virtual int getAlternativeTarget(int headIndex); + virtual void setAlternativeTarget(int headIndex, int entityId); + virtual bool isPowered(); + virtual MobType getMobType(); + virtual void ride(shared_ptr e); + + // 4J Stu - These are required for the BossMob interface + virtual float getMaxHealth() { return Monster::getMaxHealth(); }; + virtual float getHealth() { return Monster::getHealth(); }; + virtual wstring getAName() { return app.GetString(IDS_WITHER); }; +}; \ No newline at end of file diff --git a/Minecraft.World/WitherSkull.cpp b/Minecraft.World/WitherSkull.cpp new file mode 100644 index 00000000..d67660c4 --- /dev/null +++ b/Minecraft.World/WitherSkull.cpp @@ -0,0 +1,130 @@ +#include "stdafx.h" +#include "net.minecraft.world.h" +#include "net.minecraft.world.damagesource.h" +#include "net.minecraft.world.effect.h" +#include "net.minecraft.world.entity.h" +#include "net.minecraft.world.level.h" +#include "net.minecraft.world.level.tile.h" +#include "net.minecraft.world.phys.h" +#include "WitherSkull.h" + +WitherSkull::WitherSkull(Level *level) : Fireball(level) +{ + defineSynchedData(); + + setSize(5 / 16.0f, 5 / 16.0f); +} + +WitherSkull::WitherSkull(Level *level, shared_ptr mob, double xa, double ya, double za) : Fireball(level, mob, xa, ya, za) +{ + defineSynchedData(); + + setSize(5 / 16.0f, 5 / 16.0f); +} + +float WitherSkull::getInertia() +{ + return isDangerous() ? 0.73f : Fireball::getInertia(); +} + +WitherSkull::WitherSkull(Level *level, double x, double y, double z, double xa, double ya, double za) : Fireball(level, x, y, z, xa, ya, za) +{ + defineSynchedData(); + + setSize(5 / 16.0f, 5 / 16.0f); +} + +bool WitherSkull::isOnFire() +{ + return false; +} + +float WitherSkull::getTileExplosionResistance(Explosion *explosion, Level *level, int x, int y, int z, Tile *tile) +{ + float result = Fireball::getTileExplosionResistance(explosion, level, x, y, z, tile); + + if (isDangerous() && tile != Tile::unbreakable && tile != Tile::endPortalTile && tile != Tile::endPortalFrameTile) + { + result = min(0.8f, result); + } + + return result; +} + +void WitherSkull::onHit(HitResult *res) +{ + if (!level->isClientSide) + { + if (res->entity != NULL) + { + if (owner != NULL) + { + DamageSource *damageSource = DamageSource::mobAttack(owner); + if (res->entity->hurt(damageSource, 8)) + { + if (!res->entity->isAlive()) + { + owner->heal(5); + } + } + delete damageSource; + } + else + { + res->entity->hurt(DamageSource::magic, 5); + } + if ( res->entity->instanceof(eTYPE_LIVINGENTITY) ) + { + int witherSeconds = 0; + if (level->difficulty <= Difficulty::EASY) + { + // Nothing + } + else if (level->difficulty == Difficulty::NORMAL) + { + witherSeconds = 10; + } + else if (level->difficulty == Difficulty::HARD) + { + witherSeconds = 40; + } + if (witherSeconds > 0) + { + dynamic_pointer_cast( res->entity )->addEffect(new MobEffectInstance(MobEffect::wither->id, SharedConstants::TICKS_PER_SECOND * witherSeconds, 1)); + } + } + } + level->explode(shared_from_this(), x, y, z, 1, false, level->getGameRules()->getBoolean(GameRules::RULE_MOBGRIEFING)); + remove(); + } +} + +bool WitherSkull::isPickable() +{ + return false; +} + +bool WitherSkull::hurt(DamageSource *source, float damage) +{ + return false; +} + +void WitherSkull::defineSynchedData() +{ + entityData->define(DATA_DANGEROUS, (byte) 0); +} + +bool WitherSkull::isDangerous() +{ + return entityData->getByte(DATA_DANGEROUS) == 1; +} + +void WitherSkull::setDangerous(bool value) +{ + entityData->set(DATA_DANGEROUS, value ? (byte) 1 : (byte) 0); +} + +bool WitherSkull::shouldBurn() +{ + return false; +} \ No newline at end of file diff --git a/Minecraft.World/WitherSkull.h b/Minecraft.World/WitherSkull.h new file mode 100644 index 00000000..ac393c69 --- /dev/null +++ b/Minecraft.World/WitherSkull.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Fireball.h" + +class WitherSkull : public Fireball +{ +public: + eINSTANCEOF GetType() { return eTYPE_WITHER_SKULL; } + static Entity *create(Level *level) { return new WitherSkull(level); } + +private: + static const int DATA_DANGEROUS = 10; + +public: + WitherSkull(Level *level); + WitherSkull(Level *level, shared_ptr mob, double xa, double ya, double za); + +protected: + virtual float getInertia(); + +public: + WitherSkull(Level *level, double x, double y, double z, double xa, double ya, double za); + + virtual bool isOnFire(); + virtual float getTileExplosionResistance(Explosion *explosion, Level *level, int x, int y, int z, Tile *tile); + +protected: + virtual void onHit(HitResult *res); + +public: + virtual bool isPickable(); + virtual bool hurt(DamageSource *source, float damage); + +protected: + virtual void defineSynchedData(); + +public: + virtual bool isDangerous(); + virtual void setDangerous(bool value); + +protected: + virtual bool shouldBurn(); // 4J Added. +}; \ No newline at end of file diff --git a/Minecraft.World/Wolf.cpp b/Minecraft.World/Wolf.cpp index 8ffc45c6..1988382e 100644 --- a/Minecraft.World/Wolf.cpp +++ b/Minecraft.World/Wolf.cpp @@ -5,9 +5,12 @@ #include "net.minecraft.world.level.h" #include "net.minecraft.world.item.h" #include "net.minecraft.world.entity.h" +#include "net.minecraft.world.entity.animal.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.entity.ai.goal.target.h" #include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.entity.player.h" #include "net.minecraft.world.entity.projectile.h" #include "net.minecraft.world.level.pathfinder.h" @@ -25,26 +28,23 @@ Wolf::Wolf(Level *level) : TamableAnimal( level ) // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); + registerAttributes(); + setHealth(getMaxHealth()); interestedAngle = interestedAngleO = 0.0f; m_isWet = isShaking = false; shakeAnim = shakeAnimO = 0.0f; - this->textureIdx = TN_MOB_WOLF; // 4J - was L"/mob/wolf.png"; this->setSize(0.60f, 0.8f); - runSpeed = 0.3f; getNavigation()->setAvoidWater(true); goalSelector.addGoal(1, new FloatGoal(this)); goalSelector.addGoal(2, sitGoal, false); - goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4f)); - goalSelector.addGoal(4, new MeleeAttackGoal(this, runSpeed, true)); - goalSelector.addGoal(5, new FollowOwnerGoal(this, runSpeed, 10, 2)); - goalSelector.addGoal(6, new BreedGoal(this, runSpeed)); - goalSelector.addGoal(7, new RandomStrollGoal(this, runSpeed)); + goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4)); + goalSelector.addGoal(4, new MeleeAttackGoal(this, 1.0, true)); + goalSelector.addGoal(5, new FollowOwnerGoal(this, 1.0, 10, 2)); + goalSelector.addGoal(6, new BreedGoal(this, 1.0)); + goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0)); goalSelector.addGoal(8, new BegGoal(this, 8)); goalSelector.addGoal(9, new LookAtPlayerGoal(this, typeid(Player), 8)); goalSelector.addGoal(9, new RandomLookAroundGoal(this)); @@ -52,7 +52,25 @@ Wolf::Wolf(Level *level) : TamableAnimal( level ) targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this)); targetSelector.addGoal(2, new OwnerHurtTargetGoal(this)); targetSelector.addGoal(3, new HurtByTargetGoal(this, true)); - targetSelector.addGoal(4, new NonTameRandomTargetGoal(this, typeid(Sheep), 16, 200, false)); + targetSelector.addGoal(4, new NonTameRandomTargetGoal(this, typeid(Sheep), 200, false)); + + setTame(false); // Initialize health +} + +void Wolf::registerAttributes() +{ + TamableAnimal::registerAttributes(); + + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.3f); + + if (isTame()) + { + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(TAME_HEALTH); + } + else + { + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(START_HEALTH); + } } bool Wolf::useNewAi() @@ -60,10 +78,10 @@ bool Wolf::useNewAi() return true; } -void Wolf::setTarget(shared_ptr target) +void Wolf::setTarget(shared_ptr target) { TamableAnimal::setTarget(target); - if ( dynamic_pointer_cast(target) == NULL ) + if ( target == NULL ) { setAngry(false); } @@ -78,39 +96,17 @@ void Wolf::serverAiMobStep() entityData->set(DATA_HEALTH_ID, getHealth()); } -int Wolf::getMaxHealth() -{ - if (isTame()) - { - return TAME_HEALTH; - } - return START_HEALTH; -} - void Wolf::defineSynchedData() { TamableAnimal::defineSynchedData(); entityData->define(DATA_HEALTH_ID, getHealth()); entityData->define(DATA_INTERESTED_ID, (byte)0); - entityData->define(DATA_COLLAR_COLOR, (byte) ClothTile::getTileDataForItemAuxValue(DyePowderItem::RED)); + entityData->define(DATA_COLLAR_COLOR, (byte) ColoredTile::getTileDataForItemAuxValue(DyePowderItem::RED)); } -bool Wolf::makeStepSound() +void Wolf::playStepSound(int xt, int yt, int zt, int t) { - return false; -} - -int Wolf::getTexture() -{ - if (isTame()) - { - return TN_MOB_WOLF_TAME; // 4J was L"/mob/wolf_tame.png"; - } - if (isAngry()) - { - return TN_MOB_WOLF_ANGRY; // 4J was L"/mob/wolf_angry.png"; - } - return TamableAnimal::getTexture(); + playSound(eSoundType_MOB_WOLF_STEP, 0.15f, 1); } void Wolf::addAdditonalSaveData(CompoundTag *tag) @@ -129,11 +125,6 @@ void Wolf::readAdditionalSaveData(CompoundTag *tag) if (tag->contains(L"CollarColor")) setCollarColor(tag->getByte(L"CollarColor")); } -bool Wolf::removeWhenFarAway() -{ - return !isTame(); -} - int Wolf::getAmbientSound() { if (isAngry()) @@ -142,7 +133,7 @@ int Wolf::getAmbientSound() } if (random->nextInt(3) == 0) { - if (isTame() && entityData->getInteger(DATA_HEALTH_ID) < 10) + if (isTame() && entityData->getFloat(DATA_HEALTH_ID) < 10) { return eSoundType_MOB_WOLF_WHINE; } @@ -217,7 +208,7 @@ void Wolf::tick() if (shakeAnim == 0) { - level->playSound(shared_from_this(), eSoundType_MOB_WOLF_SHAKE, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); + playSound(eSoundType_MOB_WOLF_SHAKE, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f); } shakeAnimO = shakeAnim; @@ -289,14 +280,25 @@ int Wolf::getMaxHeadXRot() return TamableAnimal::getMaxHeadXRot(); } -bool Wolf::hurt(DamageSource *source, int dmg) +bool Wolf::hurt(DamageSource *source, float dmg) { + // 4J: Protect owned wolves from untrusted players + if (isTame()) + { + shared_ptr entity = source->getDirectEntity(); + if (entity != NULL && entity->instanceof(eTYPE_PLAYER)) + { + shared_ptr attacker = dynamic_pointer_cast(entity); + attacker->canHarmPlayer(getOwnerUUID()); + } + } + if (isInvulnerable()) return false; shared_ptr sourceEntity = source->getEntity(); sitGoal->wantToSit(false); - if (sourceEntity != NULL && !(dynamic_pointer_cast(sourceEntity) != NULL || dynamic_pointer_cast(sourceEntity) != NULL)) + if (sourceEntity != NULL && !(sourceEntity->instanceof(eTYPE_PLAYER) || sourceEntity->instanceof(eTYPE_ARROW))) { - // take half damage from non-players and arrows + // Take half damage from non-players and arrows dmg = (dmg + 1) / 2; } return TamableAnimal::hurt(source, dmg); @@ -308,6 +310,20 @@ bool Wolf::doHurtTarget(shared_ptr target) return target->hurt(DamageSource::mobAttack(dynamic_pointer_cast(shared_from_this())), damage); } +void Wolf::setTame(bool value) +{ + TamableAnimal::setTame(value); + + if (value) + { + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(TAME_HEALTH); + } + else + { + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->setBaseValue(START_HEALTH); + } +} + void Wolf::tame(const wstring &wsOwnerUUID, bool bDisplayTamingParticles, bool bSetSitting) { setTame(true); @@ -322,7 +338,7 @@ void Wolf::tame(const wstring &wsOwnerUUID, bool bDisplayTamingParticles, bool b spawnTamingParticles(bDisplayTamingParticles); } -bool Wolf::interact(shared_ptr player) +bool Wolf::mobInteract(shared_ptr player) { shared_ptr item = player->inventory->getSelected(); @@ -334,28 +350,24 @@ bool Wolf::interact(shared_ptr player) { FoodItem *food = dynamic_cast( Item::items[item->id] ); - if (food->isMeat()) + if (food->isMeat() && entityData->getFloat(DATA_HEALTH_ID) < MAX_HEALTH) { - if(entityData->getInteger(DATA_HEALTH_ID) < MAX_HEALTH) + heal(food->getNutrition()); + // 4J-PB - don't lose the bone in creative mode + if (player->abilities.instabuild==false) { - heal(food->getNutrition()); - // 4J-PB - don't lose the bone in creative mode - if (player->abilities.instabuild==false) + item->count--; + if (item->count <= 0) { - item->count--; - if (item->count <= 0) - { - player->inventory->setItem(player->inventory->selected, nullptr); - } + player->inventory->setItem(player->inventory->selected, nullptr); } - return true; } - else return TamableAnimal::interact(player); + return true; } } else if (item->id == Item::dye_powder_Id) { - int color = ClothTile::getTileDataForItemAuxValue(item->getAuxValue()); + int color = ColoredTile::getTileDataForItemAuxValue(item->getAuxValue()); if (color != getCollarColor()) { setCollarColor(color); @@ -376,6 +388,8 @@ bool Wolf::interact(shared_ptr player) sitGoal->wantToSit(!isSitting()); jumping = false; setPath(NULL); + setAttackTarget(nullptr); + setTarget(nullptr); } } } @@ -403,7 +417,7 @@ bool Wolf::interact(shared_ptr player) // 4J Changed to this tame(player->getUUID(),true,true); - level->broadcastEntityEvent(shared_from_this(), EntityEvent::TAMING_SUCCEEDED); + level->broadcastEntityEvent(shared_from_this(), EntityEvent::TAMING_SUCCEEDED); } else { @@ -421,7 +435,7 @@ bool Wolf::interact(shared_ptr player) return false; } } - return TamableAnimal::interact(player); + return TamableAnimal::mobInteract(player); } void Wolf::handleEntityEvent(byte id) @@ -446,7 +460,7 @@ float Wolf::getTailAngle() } else if (isTame()) { - return (0.55f - (MAX_HEALTH - entityData->getInteger(DATA_HEALTH_ID)) * 0.02f) * PI; + return (0.55f - (MAX_HEALTH - entityData->getFloat(DATA_HEALTH_ID)) * 0.02f) * PI; } return 0.20f * PI; } @@ -520,8 +534,6 @@ shared_ptr Wolf::getBreedOffspring(shared_ptr target) void Wolf::setIsInterested(bool value) { - //byte current = entityData->getByte(DATA_INTERESTED_ID); - if (value) { entityData->set(DATA_INTERESTED_ID, (byte) 1); @@ -536,7 +548,10 @@ bool Wolf::canMate(shared_ptr animal) { if (animal == shared_from_this()) return false; if (!isTame()) return false; + + if (!animal->instanceof(eTYPE_WOLF)) return false; shared_ptr partner = dynamic_pointer_cast(animal); + if (partner == NULL) return false; if (!partner->isTame()) return false; if (partner->isSitting()) return false; @@ -548,3 +563,37 @@ bool Wolf::isInterested() { return entityData->getByte(DATA_INTERESTED_ID) == 1; } + +bool Wolf::removeWhenFarAway() +{ + return !isTame() && tickCount > SharedConstants::TICKS_PER_SECOND * 60 * 2; +} + +bool Wolf::wantsToAttack(shared_ptr target, shared_ptr owner) +{ + // filter un-attackable mobs + if (target->GetType() == eTYPE_CREEPER || target->GetType() == eTYPE_GHAST) + { + return false; + } + // never target wolves that has this player as owner + if (target->GetType() == eTYPE_WOLF) + { + shared_ptr wolfTarget = dynamic_pointer_cast(target); + if (wolfTarget->isTame() && wolfTarget->getOwner() == owner) + { + return false; + } + } + if ( target->instanceof(eTYPE_PLAYER) && owner->instanceof(eTYPE_PLAYER) && !dynamic_pointer_cast(owner)->canHarmPlayer(dynamic_pointer_cast(target) )) + { + // pvp is off + return false; + } + // don't attack tame horses + if ((target->GetType() == eTYPE_HORSE) && dynamic_pointer_cast(target)->isTamed()) + { + return false; + } + return true; +} \ No newline at end of file diff --git a/Minecraft.World/Wolf.h b/Minecraft.World/Wolf.h index 52f2a23b..edfd3814 100644 --- a/Minecraft.World/Wolf.h +++ b/Minecraft.World/Wolf.h @@ -15,6 +15,7 @@ private: static const int DATA_HEALTH_ID = 18; static const int DATA_INTERESTED_ID = 19; static const int DATA_COLLAR_COLOR = 20; + static const int START_HEALTH = 8; static const int MAX_HEALTH = 20; static const int TAME_HEALTH = 20; @@ -25,26 +26,24 @@ private: public: Wolf(Level *level); - virtual bool useNewAi(); - virtual void setTarget(shared_ptr target); protected: - virtual void serverAiMobStep(); + virtual void registerAttributes(); public: - virtual int getMaxHealth(); + virtual bool useNewAi(); + virtual void setTarget(shared_ptr target); protected: + virtual void serverAiMobStep(); virtual void defineSynchedData(); - virtual bool makeStepSound(); + virtual void playStepSound(int xt, int yt, int zt, int t); public: - virtual int getTexture(); // 4J - changed from wstring to ing virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); protected: - virtual bool removeWhenFarAway(); virtual int getAmbientSound(); virtual int getHurtSound(); virtual int getDeathSound(); @@ -60,9 +59,10 @@ public: float getHeadRollAngle(float a); float getHeadHeight(); int getMaxHeadXRot(); - virtual bool hurt(DamageSource *source, int dmg); + virtual bool hurt(DamageSource *source, float dmg); virtual bool doHurtTarget(shared_ptr target); - virtual bool interact(shared_ptr player); + virtual void setTame(bool value); + virtual bool mobInteract(shared_ptr player); virtual void handleEntityEvent(byte id); float getTailAngle(); virtual bool isFood(shared_ptr item); @@ -83,4 +83,10 @@ public: virtual void setIsInterested(bool isInterested); virtual bool canMate(shared_ptr animal); bool isInterested(); + +protected: + virtual bool removeWhenFarAway(); + +public: + virtual bool wantsToAttack(shared_ptr target, shared_ptr owner); }; diff --git a/Minecraft.World/WoodButtonTile.cpp b/Minecraft.World/WoodButtonTile.cpp new file mode 100644 index 00000000..514d21de --- /dev/null +++ b/Minecraft.World/WoodButtonTile.cpp @@ -0,0 +1,12 @@ +#include "stdafx.h" +#include "net.minecraft.h" +#include "WoodButtonTile.h" + +WoodButtonTile::WoodButtonTile(int id) : ButtonTile(id, true) +{ +} + +Icon *WoodButtonTile::getTexture(int face, int data) +{ + return Tile::wood->getTexture(Facing::UP); +} \ No newline at end of file diff --git a/Minecraft.World/WoodButtonTile.h b/Minecraft.World/WoodButtonTile.h new file mode 100644 index 00000000..9b1a3b61 --- /dev/null +++ b/Minecraft.World/WoodButtonTile.h @@ -0,0 +1,11 @@ +#pragma once + +#include "ButtonTile.h" + +class WoodButtonTile : public ButtonTile +{ +public: + WoodButtonTile(int id); + + Icon *getTexture(int face, int data); +}; \ No newline at end of file diff --git a/Minecraft.World/WoodTile.cpp b/Minecraft.World/WoodTile.cpp index 43101d58..c735c581 100644 --- a/Minecraft.World/WoodTile.cpp +++ b/Minecraft.World/WoodTile.cpp @@ -13,7 +13,7 @@ const unsigned int WoodTile::WOOD_NAMES[WOOD_NAMES_LENGTH] = { IDS_TILE_OAKWOOD_ IDS_TILE_JUNGLE_PLANKS, }; -const wstring WoodTile::TEXTURE_NAMES[] = {L"wood", L"wood_spruce", L"wood_birch", L"wood_jungle"}; +const wstring WoodTile::TEXTURE_NAMES[] = {L"oak", L"spruce", L"birch", L"jungle"}; // public static final String[] WOOD_NAMES = { // "oak", "spruce", "birch", "jungle" @@ -51,6 +51,6 @@ void WoodTile::registerIcons(IconRegister *iconRegister) for (int i = 0; i < WOOD_NAMES_LENGTH; i++) { - icons[i] = iconRegister->registerIcon(TEXTURE_NAMES[i]); + icons[i] = iconRegister->registerIcon(getIconName() + L"_" + TEXTURE_NAMES[i]); } } \ No newline at end of file diff --git a/Minecraft.World/WoolCarpetTile.cpp b/Minecraft.World/WoolCarpetTile.cpp index 16a3d0aa..b509a312 100644 --- a/Minecraft.World/WoolCarpetTile.cpp +++ b/Minecraft.World/WoolCarpetTile.cpp @@ -13,7 +13,7 @@ WoolCarpetTile::WoolCarpetTile(int id) : Tile(id, Material::clothDecoration, isS Icon *WoolCarpetTile::getTexture(int face, int data) { - return Tile::cloth->getTexture(face, data); + return Tile::wool->getTexture(face, data); } AABB *WoolCarpetTile::getAABB(Level *level, int x, int y, int z) @@ -73,7 +73,7 @@ bool WoolCarpetTile::checkCanSurvive(Level *level, int x, int y, int z) if (!canSurvive(level, x, y, z)) { spawnResources(level, x, y, z, level->getData(x, y, z), 0); - level->setTile(x, y, z, 0); + level->removeTile(x, y, z); return false; } return true; diff --git a/Minecraft.World/WoolTileItem.cpp b/Minecraft.World/WoolTileItem.cpp new file mode 100644 index 00000000..0f079571 --- /dev/null +++ b/Minecraft.World/WoolTileItem.cpp @@ -0,0 +1,149 @@ +#include "stdafx.h" +#include "net.minecraft.world.level.tile.h" +#include "ItemInstance.h" +#include "DyePowderItem.h" +#include "WoolTileItem.h" + +const unsigned int WoolTileItem::COLOR_DESCS[] = +{ + IDS_TILE_CLOTH_BLACK, + IDS_TILE_CLOTH_RED, + IDS_TILE_CLOTH_GREEN, + IDS_TILE_CLOTH_BROWN, + IDS_TILE_CLOTH_BLUE, + IDS_TILE_CLOTH_PURPLE, + IDS_TILE_CLOTH_CYAN, + IDS_TILE_CLOTH_SILVER, + IDS_TILE_CLOTH_GRAY, + IDS_TILE_CLOTH_PINK, + IDS_TILE_CLOTH_LIME, + IDS_TILE_CLOTH_YELLOW, + IDS_TILE_CLOTH_LIGHT_BLUE, + IDS_TILE_CLOTH_MAGENTA, + IDS_TILE_CLOTH_ORANGE, + IDS_TILE_CLOTH_WHITE +}; + +const unsigned int WoolTileItem::CARPET_COLOR_DESCS[] = +{ + IDS_TILE_CARPET_BLACK, + IDS_TILE_CARPET_RED, + IDS_TILE_CARPET_GREEN, + IDS_TILE_CARPET_BROWN, + IDS_TILE_CARPET_BLUE, + IDS_TILE_CARPET_PURPLE, + IDS_TILE_CARPET_CYAN, + IDS_TILE_CARPET_SILVER, + IDS_TILE_CARPET_GRAY, + IDS_TILE_CARPET_PINK, + IDS_TILE_CARPET_LIME, + IDS_TILE_CARPET_YELLOW, + IDS_TILE_CARPET_LIGHT_BLUE, + IDS_TILE_CARPET_MAGENTA, + IDS_TILE_CARPET_ORANGE, + IDS_TILE_CARPET_WHITE +}; + +const unsigned int WoolTileItem::CLAY_COLOR_DESCS[] = +{ + IDS_TILE_STAINED_CLAY_BLACK, + IDS_TILE_STAINED_CLAY_RED, + IDS_TILE_STAINED_CLAY_GREEN, + IDS_TILE_STAINED_CLAY_BROWN, + IDS_TILE_STAINED_CLAY_BLUE, + IDS_TILE_STAINED_CLAY_PURPLE, + IDS_TILE_STAINED_CLAY_CYAN, + IDS_TILE_STAINED_CLAY_SILVER, + IDS_TILE_STAINED_CLAY_GRAY, + IDS_TILE_STAINED_CLAY_PINK, + IDS_TILE_STAINED_CLAY_LIME, + IDS_TILE_STAINED_CLAY_YELLOW, + IDS_TILE_STAINED_CLAY_LIGHT_BLUE, + IDS_TILE_STAINED_CLAY_MAGENTA, + IDS_TILE_STAINED_CLAY_ORANGE, + IDS_TILE_STAINED_CLAY_WHITE +}; + +const unsigned int WoolTileItem::GLASS_COLOR_DESCS[] = +{ + IDS_TILE_STAINED_GLASS_BLACK, + IDS_TILE_STAINED_GLASS_RED, + IDS_TILE_STAINED_GLASS_GREEN, + IDS_TILE_STAINED_GLASS_BROWN, + IDS_TILE_STAINED_GLASS_BLUE, + IDS_TILE_STAINED_GLASS_PURPLE, + IDS_TILE_STAINED_GLASS_CYAN, + IDS_TILE_STAINED_GLASS_SILVER, + IDS_TILE_STAINED_GLASS_GRAY, + IDS_TILE_STAINED_GLASS_PINK, + IDS_TILE_STAINED_GLASS_LIME, + IDS_TILE_STAINED_GLASS_YELLOW, + IDS_TILE_STAINED_GLASS_LIGHT_BLUE, + IDS_TILE_STAINED_GLASS_MAGENTA, + IDS_TILE_STAINED_GLASS_ORANGE, + IDS_TILE_STAINED_GLASS_WHITE +}; + +const unsigned int WoolTileItem::GLASS_PANE_COLOR_DESCS[] = +{ + IDS_TILE_STAINED_GLASS_PANE_BLACK, + IDS_TILE_STAINED_GLASS_PANE_RED, + IDS_TILE_STAINED_GLASS_PANE_GREEN, + IDS_TILE_STAINED_GLASS_PANE_BROWN, + IDS_TILE_STAINED_GLASS_PANE_BLUE, + IDS_TILE_STAINED_GLASS_PANE_PURPLE, + IDS_TILE_STAINED_GLASS_PANE_CYAN, + IDS_TILE_STAINED_GLASS_PANE_SILVER, + IDS_TILE_STAINED_GLASS_PANE_GRAY, + IDS_TILE_STAINED_GLASS_PANE_PINK, + IDS_TILE_STAINED_GLASS_PANE_LIME, + IDS_TILE_STAINED_GLASS_PANE_YELLOW, + IDS_TILE_STAINED_GLASS_PANE_LIGHT_BLUE, + IDS_TILE_STAINED_GLASS_PANE_MAGENTA, + IDS_TILE_STAINED_GLASS_PANE_ORANGE, + IDS_TILE_STAINED_GLASS_PANE_WHITE +}; + +WoolTileItem::WoolTileItem(int id) : TileItem(id) +{ + setMaxDamage(0); + setStackedByData(true); +} + +Icon *WoolTileItem::getIcon(int itemAuxValue) +{ +#ifndef _CONTENT_PACKAGE + if(Tile::tiles[id]) + { + return Tile::tiles[id]->getTexture(2, ColoredTile::getTileDataForItemAuxValue(itemAuxValue)); + } + else +#endif + { + return Tile::wool->getTexture(2, ColoredTile::getTileDataForItemAuxValue(itemAuxValue)); + } +} + +int WoolTileItem::getLevelDataForAuxValue(int auxValue) +{ + return auxValue; +} + +unsigned int WoolTileItem::getDescriptionId(shared_ptr instance) +{ + int tileId = getTileId(); + switch(getTileId()) + { + case Tile::stained_glass_Id: + return GLASS_COLOR_DESCS[ColoredTile::getTileDataForItemAuxValue(instance->getAuxValue())]; + case Tile::stained_glass_pane_Id: + return GLASS_PANE_COLOR_DESCS[ColoredTile::getTileDataForItemAuxValue(instance->getAuxValue())]; + case Tile::clayHardened_colored_Id: + return CLAY_COLOR_DESCS[ColoredTile::getTileDataForItemAuxValue(instance->getAuxValue())]; + case Tile::woolCarpet_Id: + return CARPET_COLOR_DESCS[ColoredTile::getTileDataForItemAuxValue(instance->getAuxValue())]; + case Tile::wool_Id: + default: + return COLOR_DESCS[ColoredTile::getTileDataForItemAuxValue(instance->getAuxValue())]; + }; +} diff --git a/Minecraft.World/WoolTileItem.h b/Minecraft.World/WoolTileItem.h new file mode 100644 index 00000000..49af2142 --- /dev/null +++ b/Minecraft.World/WoolTileItem.h @@ -0,0 +1,20 @@ +#pragma once +using namespace std; + +#include "TileItem.h" + +class WoolTileItem : public TileItem +{ +public: + static const unsigned int COLOR_DESCS[]; + static const unsigned int CARPET_COLOR_DESCS[]; + static const unsigned int CLAY_COLOR_DESCS[]; + static const unsigned int GLASS_COLOR_DESCS[]; + static const unsigned int GLASS_PANE_COLOR_DESCS[]; + + WoolTileItem(int id); + + virtual Icon *getIcon(int itemAuxValue); + virtual int getLevelDataForAuxValue(int auxValue); + virtual unsigned int getDescriptionId(shared_ptr instance); +}; \ No newline at end of file diff --git a/Minecraft.World/WorkbenchTile.cpp b/Minecraft.World/WorkbenchTile.cpp index 7af19755..82193b69 100644 --- a/Minecraft.World/WorkbenchTile.cpp +++ b/Minecraft.World/WorkbenchTile.cpp @@ -40,5 +40,6 @@ bool WorkbenchTile::use(Level *level, int x, int y, int z, shared_ptr pl return true; } player->startCrafting(x, y, z); + //player->openFireworks(x, y, z); return true; } \ No newline at end of file diff --git a/Minecraft.World/WorldlyContainer.h b/Minecraft.World/WorldlyContainer.h new file mode 100644 index 00000000..6141dc1b --- /dev/null +++ b/Minecraft.World/WorldlyContainer.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Container.h" + +class WorldlyContainer : public Container +{ +public: + virtual intArray getSlotsForFace(int face) = 0; + virtual bool canPlaceItemThroughFace(int slot, shared_ptr item, int face) = 0; + virtual bool canTakeItemThroughFace(int slot, shared_ptr item, int face) = 0; +}; \ No newline at end of file diff --git a/Minecraft.World/WrittenBookItem.h b/Minecraft.World/WrittenBookItem.h new file mode 100644 index 00000000..74648558 --- /dev/null +++ b/Minecraft.World/WrittenBookItem.h @@ -0,0 +1,82 @@ +#pragma once + +/* +class WrittenBookItem extends Item { + + public static final int TITLE_LENGTH = 16; + public static final int PAGE_LENGTH = 256; + public static final int MAX_PAGES = 50; + public static final String TAG_TITLE = "title"; + public static final String TAG_AUTHOR = "author"; + public static final String TAG_PAGES = "pages"; + + public WrittenBookItem(int id) { + super(id); + setMaxStackSize(1); + } + + public static boolean makeSureTagIsValid(CompoundTag bookTag) { + + if (!WritingBookItem.makeSureTagIsValid(bookTag)) { + return false; + } + + if (!bookTag.contains(TAG_TITLE)) { + return false; + } + String title = bookTag.getString(TAG_TITLE); + if (title == null || title.length() > TITLE_LENGTH) { + return false; + } + + if (!bookTag.contains(TAG_AUTHOR)) { + return false; + } + + return true; + } + + @Override + public String getHoverName(ItemInstance itemInstance) { + if (itemInstance.hasTag()) { + CompoundTag itemTag = itemInstance.getTag(); + + StringTag titleTag = (StringTag) itemTag.get(TAG_TITLE); + if (titleTag != null) { + return titleTag.toString(); + } + } + return super.getHoverName(itemInstance); + } + + @Override + public void appendHoverText(ItemInstance itemInstance, Player player, List lines, boolean advanced) { + + if (itemInstance.hasTag()) { + CompoundTag itemTag = itemInstance.getTag(); + + StringTag authorTag = (StringTag) itemTag.get(TAG_AUTHOR); + if (authorTag != null) { + lines.add(ChatFormatting.GRAY + String.format(I18n.get("book.byAuthor", authorTag.data))); + } + } + } + + @Override + public ItemInstance use(ItemInstance itemInstance, Level level, Player player) { + player.openItemInstanceGui(itemInstance); + return itemInstance; + } + + @Override + public boolean shouldOverrideMultiplayerNBT() { + return true; + } + + @Override + public boolean isFoil(ItemInstance itemInstance) { + return true; + } + +}; +*/ \ No newline at end of file diff --git a/Minecraft.World/Zombie.cpp b/Minecraft.World/Zombie.cpp index b167635f..df9d5c6b 100644 --- a/Minecraft.World/Zombie.cpp +++ b/Minecraft.World/Zombie.cpp @@ -3,81 +3,81 @@ #include "net.minecraft.world.level.tile.h" #include "net.minecraft.world.h" #include "net.minecraft.world.item.h" +#include "net.minecraft.world.damagesource.h" #include "net.minecraft.world.effect.h" +#include "net.minecraft.world.entity.ai.attributes.h" #include "net.minecraft.world.entity.ai.goal.h" #include "net.minecraft.world.entity.ai.goal.target.h" #include "net.minecraft.world.entity.ai.navigation.h" +#include "net.minecraft.world.entity.monster.h" #include "net.minecraft.world.entity.npc.h" #include "net.minecraft.world.entity.player.h" #include "Zombie.h" #include "GenericStats.h" #include "..\Minecraft.Client\Textures.h" #include "net.minecraft.world.entity.h" +#include "JavaMath.h" #include "SoundTypes.h" + Attribute *Zombie::SPAWN_REINFORCEMENTS_CHANCE = (new RangedAttribute(eAttributeId_ZOMBIE_SPAWNREINFORCEMENTS, 0, 0, 1)); + AttributeModifier *Zombie::SPEED_MODIFIER_BABY = new AttributeModifier(eModifierId_MOB_ZOMBIE_BABYSPEED, 0.5f, AttributeModifier::OPERATION_MULTIPLY_BASE); + +const float Zombie::ZOMBIE_LEADER_CHANCE = 0.05f; + + Zombie::Zombie(Level *level) : Monster( level ) { // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that // the derived version of the function is called this->defineSynchedData(); - - // 4J Stu - This function call had to be moved here from the Entity ctor to ensure that the derived version of the function is called - health = getMaxHealth(); - - this->textureIdx = TN_MOB_ZOMBIE; // 4J was L"/mob/zombie.png"; - runSpeed = 0.23f; - attackDamage = 4; + registerAttributes(); + setHealth(getMaxHealth()); villagerConversionTime = 0; - - registeredBBWidth = -1; - registeredBBHeight = 0; - - setSize(bbWidth, bbHeight); getNavigation()->setCanOpenDoors(true); goalSelector.addGoal(0, new FloatGoal(this)); goalSelector.addGoal(1, new BreakDoorGoal(this)); - goalSelector.addGoal(2, new MeleeAttackGoal(this, eTYPE_PLAYER, runSpeed, false)); - goalSelector.addGoal(3, new MeleeAttackGoal(this, eTYPE_VILLAGER, runSpeed, true)); - goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, runSpeed)); - goalSelector.addGoal(5, new MoveThroughVillageGoal(this, runSpeed, false)); - goalSelector.addGoal(6, new RandomStrollGoal(this, runSpeed)); + goalSelector.addGoal(2, new MeleeAttackGoal(this, eTYPE_PLAYER, 1.0, false)); + goalSelector.addGoal(3, new MeleeAttackGoal(this, eTYPE_VILLAGER, 1.0, true)); + goalSelector.addGoal(4, new MoveTowardsRestrictionGoal(this, 1.0)); + goalSelector.addGoal(5, new MoveThroughVillageGoal(this, 1.0, false)); + goalSelector.addGoal(6, new RandomStrollGoal(this, 1.0)); goalSelector.addGoal(7, new LookAtPlayerGoal(this, typeid(Player), 8)); goalSelector.addGoal(7, new RandomLookAroundGoal(this)); - targetSelector.addGoal(1, new HurtByTargetGoal(this, false)); - targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Player), 16, 0, true)); - targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Villager), 16, 0, false)); + targetSelector.addGoal(1, new HurtByTargetGoal(this, true)); + targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Player), 0, true)); + targetSelector.addGoal(2, new NearestAttackableTargetGoal(this, typeid(Villager), 0, false)); } -void Zombie::defineSynchedData() +void Zombie::registerAttributes() { - Monster::defineSynchedData(); + Monster::registerAttributes(); - getEntityData()->define(DATA_BABY_ID, (byte) 0); - getEntityData()->define(DATA_VILLAGER_ID, (byte) 0); - getEntityData()->define(DATA_CONVERTING_ID, (byte) 0); -} + // 4J Stu - Don't make it so far! + //getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->setBaseValue(40); -float Zombie::getWalkingSpeedModifier() -{ - return Monster::getWalkingSpeedModifier() * (isBaby() ? 1.5f : 1.0f); -} + getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED)->setBaseValue(0.23f); + getAttribute(SharedMonsterAttributes::ATTACK_DAMAGE)->setBaseValue(3); -int Zombie::getTexture() -{ - return isVillager() ? TN_MOB_ZOMBIE_VILLAGER : TN_MOB_ZOMBIE; + getAttributes()->registerAttribute(SPAWN_REINFORCEMENTS_CHANCE)->setBaseValue(random->nextDouble() * 0.10f); } -int Zombie::getMaxHealth() +void Zombie::defineSynchedData() { - return 20; + Monster::defineSynchedData(); + + getEntityData()->define(DATA_BABY_ID, (byte) 0); + getEntityData()->define(DATA_VILLAGER_ID, (byte) 0); + getEntityData()->define(DATA_CONVERTING_ID, (byte) 0); } int Zombie::getArmorValue() { - return 2; + int value = Monster::getArmorValue() + 2; + if (value > 20) value = 20; + return value; } bool Zombie::useNewAi() @@ -92,8 +92,17 @@ bool Zombie::isBaby() void Zombie::setBaby(bool baby) { - getEntityData()->set(DATA_BABY_ID, (byte) 1); - updateSize(isBaby()); + getEntityData()->set(DATA_BABY_ID, (byte) (baby ? 1 : 0)); + + if (level != NULL && !level->isClientSide) + { + AttributeInstance *speed = getAttribute(SharedMonsterAttributes::MOVEMENT_SPEED); + speed->removeModifier(SPEED_MODIFIER_BABY); + if (baby) + { + speed->addModifier(new AttributeModifier(*SPEED_MODIFIER_BABY)); + } + } } bool Zombie::isVillager() @@ -108,21 +117,83 @@ void Zombie::setVillager(bool villager) void Zombie::aiStep() { - if(level->isClientSide) - { - updateSize(isBaby()); - } - else if (level->isDay() && !level->isClientSide && !isBaby()) + if (level->isDay() && !level->isClientSide && !isBaby()) { float br = getBrightness(1); - if (br > 0.5f && random->nextFloat() * 30 < (br - 0.4f) * 2 && level->canSeeSky( Mth::floor(x), Mth::floor(y), Mth::floor(z))) + if (br > 0.5f && random->nextFloat() * 30 < (br - 0.4f) * 2 && level->canSeeSky(Mth::floor(x), (int)floor( y + 0.5 ), Mth::floor(z))) { - setOnFire(8); + bool burn = true; + + shared_ptr helmet = getCarried(SLOT_HELM); + if (helmet != NULL) + { + if (helmet->isDamageableItem()) + { + helmet->setAuxValue(helmet->getDamageValue() + random->nextInt(2)); + if (helmet->getDamageValue() >= helmet->getMaxDamage()) + { + breakItem(helmet); + setEquippedSlot(SLOT_HELM, nullptr); + } + } + + burn = false; + } + + if (burn) + { + setOnFire(8); + } } } Monster::aiStep(); } +bool Zombie::hurt(DamageSource *source, float dmg) +{ + if (Monster::hurt(source, dmg)) + { + shared_ptr target = getTarget(); + if ( (target == NULL) && getAttackTarget() != NULL && getAttackTarget()->instanceof(eTYPE_LIVINGENTITY) ) target = dynamic_pointer_cast( getAttackTarget() ); + if ( (target == NULL) && source->getEntity() != NULL && source->getEntity()->instanceof(eTYPE_LIVINGENTITY) ) target = dynamic_pointer_cast( source->getEntity() ); + + if ( (target != NULL) && level->difficulty >= Difficulty::HARD && random->nextFloat() < getAttribute(SPAWN_REINFORCEMENTS_CHANCE)->getValue()) + { + int x = Mth::floor(this->x); + int y = Mth::floor(this->y); + int z = Mth::floor(this->z); + shared_ptr reinforcement = shared_ptr( new Zombie(level) ); + + for (int i = 0; i < REINFORCEMENT_ATTEMPTS; i++) + { + int xt = x + Mth::nextInt(random, REINFORCEMENT_RANGE_MIN, REINFORCEMENT_RANGE_MAX) * Mth::nextInt(random, -1, 1); + int yt = y + Mth::nextInt(random, REINFORCEMENT_RANGE_MIN, REINFORCEMENT_RANGE_MAX) * Mth::nextInt(random, -1, 1); + int zt = z + Mth::nextInt(random, REINFORCEMENT_RANGE_MIN, REINFORCEMENT_RANGE_MAX) * Mth::nextInt(random, -1, 1); + + if (level->isTopSolidBlocking(xt, yt - 1, zt) && level->getRawBrightness(xt, yt, zt) < 10) + { + reinforcement->setPos(xt, yt, zt); + + if (level->isUnobstructed(reinforcement->bb) && level->getCubes(reinforcement, reinforcement->bb)->empty() && !level->containsAnyLiquid(reinforcement->bb)) + { + level->addEntity(reinforcement); + reinforcement->setTarget(target); + reinforcement->finalizeMobSpawn(NULL); + + getAttribute(SPAWN_REINFORCEMENTS_CHANCE)->addModifier(new AttributeModifier(-0.05f, AttributeModifier::OPERATION_ADDITION)); + reinforcement->getAttribute(SPAWN_REINFORCEMENTS_CHANCE)->addModifier(new AttributeModifier(-0.05f, AttributeModifier::OPERATION_ADDITION)); + break; + } + } + } + } + + return true; + } + + return false; +} + void Zombie::tick() { if (!level->isClientSide && isConverting()) @@ -140,6 +211,21 @@ void Zombie::tick() Monster::tick(); } +bool Zombie::doHurtTarget(shared_ptr target) +{ + bool result = Monster::doHurtTarget(target); + + if (result) + { + if (getCarriedItem() == NULL && isOnFire() && random->nextFloat() < level->difficulty * 0.3f) + { + target->setOnFire(2 * level->difficulty); + } + } + + return result; +} + int Zombie::getAmbientSound() { return eSoundType_MOB_ZOMBIE_AMBIENT; @@ -160,6 +246,11 @@ int Zombie::getDeathLoot() return Item::rotten_flesh_Id; } +void Zombie::playStepSound(int xt, int yt, int zt, int t) +{ + playSound(eSoundType_MOB_ZOMBIE_STEP, 0.15f, 1); +} + MobType Zombie::getMobType() { return UNDEAD; @@ -169,18 +260,6 @@ void Zombie::dropRareDeathLoot(int rareLootLevel) { switch (random->nextInt(3)) { -/* case 0: - spawnAtLocation(Item::sword_iron_Id, 1); - break; - case 1: - spawnAtLocation(Item::helmet_iron_Id, 1); - break; - case 2: - spawnAtLocation(Item::ironIngot_Id, 1); - break; - case 3: - spawnAtLocation(Item::shovel_iron_Id, 1); - break;*/ case 0: spawnAtLocation(Item::ironIngot_Id, 1); break; @@ -193,6 +272,24 @@ void Zombie::dropRareDeathLoot(int rareLootLevel) } } +void Zombie::populateDefaultEquipmentSlots() +{ + Monster::populateDefaultEquipmentSlots(); + + if (random->nextFloat() < (level->difficulty == Difficulty::HARD ? 0.05f : 0.01f)) + { + int rand = random->nextInt(3); + if (rand == 0) + { + setEquippedSlot(SLOT_WEAPON, shared_ptr( new ItemInstance(Item::sword_iron)) ); + } + else + { + setEquippedSlot(SLOT_WEAPON, shared_ptr( new ItemInstance(Item::shovel_iron)) ); + } + } +} + void Zombie::addAdditonalSaveData(CompoundTag *tag) { Monster::addAdditonalSaveData(tag); @@ -211,19 +308,18 @@ void Zombie::readAdditionalSaveData(CompoundTag *tag) if (tag->contains(L"ConversionTime") && tag->getInt(L"ConversionTime") > -1) startConverting(tag->getInt(L"ConversionTime")); } -void Zombie::killed(shared_ptr mob) +void Zombie::killed(shared_ptr mob) { Monster::killed(mob); - if (level->difficulty >= Difficulty::NORMAL && ((mob->GetType() & eTYPE_VILLAGER) == eTYPE_VILLAGER)) + if ( level->difficulty >= Difficulty::NORMAL && (mob->GetType() == eTYPE_VILLAGER) ) // 4J-JEV: Villager isn't a non-terminal class, no need to instanceof. { - if( !level->canCreateMore( GetType(), Level::eSpawnType_Egg) ) return; if (level->difficulty == Difficulty::NORMAL && random->nextBoolean()) return; shared_ptr zombie = shared_ptr(new Zombie(level)); zombie->copyPosition(mob); level->removeEntity(mob); - zombie->finalizeMobSpawn(); + zombie->finalizeMobSpawn(NULL); zombie->setVillager(true); if (mob->isBaby()) zombie->setBaby(true); level->addEntity(zombie); @@ -232,38 +328,64 @@ void Zombie::killed(shared_ptr mob) } } -void Zombie::finalizeMobSpawn() +MobGroupData *Zombie::finalizeMobSpawn(MobGroupData *groupData, int extraData /*= 0*/) // 4J Added extraData param { - // 4J Stu - TODO TU15 -#if 0 - canPickUpLoot = random->nextFloat() < CAN_PICK_UP_LOOT_CHANCES[level->difficulty]; -#endif + groupData = Monster::finalizeMobSpawn(groupData); + float difficulty = level->getDifficulty(x, y, z); + + setCanPickUpLoot(random->nextFloat() < MAX_PICKUP_LOOT_CHANCE * difficulty); + + if (groupData == NULL) + { + groupData = new ZombieGroupData(level->random->nextFloat() < 0.05f, level->random->nextFloat() < 0.05f); + } - if (level->random->nextFloat() < 0.05f) + if ( dynamic_cast( groupData ) != NULL) { - setVillager(true); + ZombieGroupData *zombieData = (ZombieGroupData *) groupData; + + if (zombieData->isVillager) + { + setVillager(true); + } + + if (zombieData->isBaby) + { + setBaby(true); + } } - // 4J Stu - TODO TU15 -#if 0 populateDefaultEquipmentSlots(); populateDefaultEquipmentEnchantments(); - if (getCarried(SLOT_HELM) == null) + if (getCarried(SLOT_HELM) == NULL) { - Calendar cal = level.getCalendar(); - - if (cal.get(Calendar.MONTH) + 1 == 10 && cal.get(Calendar.DAY_OF_MONTH) == 31 && random.nextFloat() < 0.25f) { + // [EB]: We have this code in quite some places, shouldn't we set + // something like this globally? + if (Calendar::GetMonth() + 1 == 10 && Calendar::GetDayOfMonth() == 31 && random->nextFloat() < 0.25f) + { // Halloween! OooOOo! 25% of all skeletons/zombies can wear // pumpkins on their heads. - setEquippedSlot(SLOT_HELM, new ItemInstance(random.nextFloat() < 0.1f ? Tile.litPumpkin : Tile.pumpkin)); + setEquippedSlot(SLOT_HELM, shared_ptr( new ItemInstance(random->nextFloat() < 0.1f ? Tile::litPumpkin : Tile::pumpkin) )); dropChances[SLOT_HELM] = 0; } } -#endif + + getAttribute(SharedMonsterAttributes::KNOCKBACK_RESISTANCE)->addModifier(new AttributeModifier(random->nextDouble() * 0.05f, AttributeModifier::OPERATION_ADDITION)); + + // 4J Stu - Take this out, it's not good and nobody will notice. Also not great for performance. + //getAttribute(SharedMonsterAttributes::FOLLOW_RANGE)->addModifier(new AttributeModifier(random->nextDouble() * 1.50f, AttributeModifier::OPERATION_MULTIPLY_TOTAL)); + + if (random->nextFloat() < difficulty * ZOMBIE_LEADER_CHANCE) + { + getAttribute(SPAWN_REINFORCEMENTS_CHANCE)->addModifier(new AttributeModifier(random->nextDouble() * 0.25f + 0.50f, AttributeModifier::OPERATION_ADDITION)); + getAttribute(SharedMonsterAttributes::MAX_HEALTH)->addModifier(new AttributeModifier(random->nextDouble() * 3.0f + 1.0f, AttributeModifier::OPERATION_MULTIPLY_TOTAL)); + } + + return groupData; } -bool Zombie::interact(shared_ptr player) +bool Zombie::mobInteract(shared_ptr player) { shared_ptr item = player->getSelectedItem(); @@ -304,7 +426,7 @@ void Zombie::handleEntityEvent(byte id) { if (id == EntityEvent::ZOMBIE_CONVERTING) { - level->playLocalSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_MOB_ZOMBIE_REMEDY, 1 + random->nextFloat(), random->nextFloat() * 0.7f + 0.3f);//, false); + level->playLocalSound(x + 0.5f, y + 0.5f, z + 0.5f, eSoundType_MOB_ZOMBIE_REMEDY, 1 + random->nextFloat(), random->nextFloat() * 0.7f + 0.3f, false); } else { @@ -312,6 +434,11 @@ void Zombie::handleEntityEvent(byte id) } } +bool Zombie::removeWhenFarAway() +{ + return !isConverting(); +} + bool Zombie::isConverting() { return getEntityData()->getByte(DATA_CONVERTING_ID) == (byte) 1; @@ -321,7 +448,7 @@ void Zombie::finishConversion() { shared_ptr villager = shared_ptr(new Villager(level)); villager->copyPosition(shared_from_this()); - villager->finalizeMobSpawn(); + villager->finalizeMobSpawn(NULL); villager->setRewardPlayersInVillage(); if (isBaby()) villager->setAge(-20 * 60 * 20); level->removeEntity(shared_from_this()); @@ -359,25 +486,8 @@ int Zombie::getConversionProgress() return amount; } -void Zombie::updateSize(bool isBaby) +Zombie::ZombieGroupData::ZombieGroupData(bool baby, bool villager) { - internalSetSize(isBaby ? .5f : 1.0f); -} - -void Zombie::setSize(float w, float h) -{ - bool inited = registeredBBWidth > 0; - - registeredBBWidth = w; - registeredBBHeight = h; - - if (!inited) - { - internalSetSize(1.0f); - } -} - -void Zombie::internalSetSize(float scale) -{ - PathfinderMob::setSize(registeredBBWidth * scale, registeredBBHeight * scale); -} + isBaby = baby; + isVillager = villager; +} \ No newline at end of file diff --git a/Minecraft.World/Zombie.h b/Minecraft.World/Zombie.h index 237db15b..d79df182 100644 --- a/Minecraft.World/Zombie.h +++ b/Minecraft.World/Zombie.h @@ -3,6 +3,7 @@ using namespace std; #include "Monster.h" #include "SharedConstants.h" +#include "MobGroupData.h" class Zombie : public Monster { @@ -10,14 +11,25 @@ private: static const int VILLAGER_CONVERSION_WAIT_MIN = SharedConstants::TICKS_PER_SECOND * 60 * 3; static const int VILLAGER_CONVERSION_WAIT_MAX = SharedConstants::TICKS_PER_SECOND * 60 * 5; +protected: + static Attribute *SPAWN_REINFORCEMENTS_CHANCE; + +private: + static AttributeModifier *SPEED_MODIFIER_BABY; + + static const int DATA_BABY_ID = 12; static const int DATA_VILLAGER_ID = 13; static const int DATA_CONVERTING_ID = 14; - int villagerConversionTime; +public: + static const float ZOMBIE_LEADER_CHANCE; + static const int REINFORCEMENT_ATTEMPTS = 50; + static const int REINFORCEMENT_RANGE_MAX = 40; + static const int REINFORCEMENT_RANGE_MIN = 7; - float registeredBBWidth; - float registeredBBHeight; +private: + int villagerConversionTime; public: static const int MAX_SPECIAL_BLOCKS_COUNT = 14; @@ -28,61 +40,71 @@ public: static Entity *create(Level *level) { return new Zombie(level); } Zombie(Level *level); - virtual float getWalkingSpeedModifier(); protected: + virtual void registerAttributes(); virtual void defineSynchedData(); public: - virtual int getTexture(); - virtual int getMaxHealth(); - int getArmorValue(); + virtual int getArmorValue(); protected: virtual bool useNewAi(); public: - bool isBaby(); - void setBaby(bool baby); - bool isVillager(); - void setVillager(bool villager); - virtual void aiStep(); - virtual void tick(); - + virtual bool isBaby(); + virtual void setBaby(bool baby); + virtual bool isVillager(); + virtual void setVillager(bool villager); + virtual void aiStep(); + virtual bool hurt(DamageSource *source, float dmg); + virtual void tick(); + virtual bool doHurtTarget(shared_ptr target); + protected: virtual int getAmbientSound(); - virtual int getHurtSound(); - virtual int getDeathSound(); - virtual int getDeathLoot(); + virtual int getHurtSound(); + virtual int getDeathSound(); + virtual int getDeathLoot(); + virtual void playStepSound(int xt, int yt, int zt, int t); public: - MobType getMobType(); + virtual MobType getMobType(); protected: virtual void dropRareDeathLoot(int rareLootLevel); + virtual void populateDefaultEquipmentSlots(); public: virtual void addAdditonalSaveData(CompoundTag *tag); virtual void readAdditionalSaveData(CompoundTag *tag); - void killed(shared_ptr mob); - virtual void finalizeMobSpawn(); - bool interact(shared_ptr player); + virtual void killed(shared_ptr mob); + virtual MobGroupData *finalizeMobSpawn(MobGroupData *groupData, int extraData = 0); // 4J Added extraData param + virtual bool mobInteract(shared_ptr player); protected: - void startConverting(int time); + virtual void startConverting(int time); public: - void handleEntityEvent(byte id); - bool isConverting(); + virtual void handleEntityEvent(byte id); protected: - void finishConversion(); - int getConversionProgress(); + virtual bool removeWhenFarAway(); public: - virtual void updateSize(bool isBaby); + virtual bool isConverting(); protected: - virtual void setSize(float w, float h); - void internalSetSize(float scale); + virtual void finishConversion(); + virtual int getConversionProgress(); + +private: + class ZombieGroupData : public MobGroupData + { + public: + bool isBaby; + bool isVillager; + + ZombieGroupData(bool baby, bool villager); + }; }; diff --git a/Minecraft.World/net.minecraft.commands.common.h b/Minecraft.World/net.minecraft.commands.common.h index aa2e2f6f..83b0dca5 100644 --- a/Minecraft.World/net.minecraft.commands.common.h +++ b/Minecraft.World/net.minecraft.commands.common.h @@ -1,6 +1,7 @@ #pragma once #include "DefaultGameModeCommand.h" +#include "EffectCommand.h" #include "EnchantItemCommand.h" #include "ExperienceCommand.h" #include "GameModeCommand.h" diff --git a/Minecraft.World/net.minecraft.core.h b/Minecraft.World/net.minecraft.core.h new file mode 100644 index 00000000..d6778989 --- /dev/null +++ b/Minecraft.World/net.minecraft.core.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Behavior.h" +#include "BlockSource.h" +#include "BlockSourceImpl.h" +#include "BehaviorRegistry.h" +#include "DispenseItemBehavior.h" +#include "DefaultDispenseItemBehavior.h" +#include "AbstractProjectileDispenseBehavior.h" +#include "ItemDispenseBehaviors.h" +#include "FacingEnum.h" +#include "LocatableSource.h" +#include "Location.h" +#include "Position.h" +#include "PositionImpl.h" +#include "Source.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.network.packet.h b/Minecraft.World/net.minecraft.network.packet.h index b7bfee5d..c1d52d14 100644 --- a/Minecraft.World/net.minecraft.network.packet.h +++ b/Minecraft.World/net.minecraft.network.packet.h @@ -45,7 +45,7 @@ #include "SetEntityMotionPacket.h" #include "SetEquippedItemPacket.h" #include "SetHealthPacket.h" -#include "SetRidingPacket.h" +#include "SetEntityLinkPacket.h" #include "SetSpawnPositionPacket.h" #include "SetTimePacket.h" #include "SignUpdatePacket.h" @@ -84,6 +84,15 @@ #include "ServerAuthDataPacket.h" #include "TileDestructionPacket.h" +// 1.6.4 +#include "LevelParticlesPacket.h" +#include "SetDisplayObjectivePacket.h" +#include "SetObjectivePacket.h" +#include "SetPlayerTeamPacket.h" +#include "SetScorePacket.h" +#include "TileEditorOpenPacket.h" +#include "UpdateAttributesPacket.h" + // 4J Added #include "CraftItemPacket.h" #include "TradeItemPacket.h" diff --git a/Minecraft.World/net.minecraft.world.ContainerListener.h b/Minecraft.World/net.minecraft.world.ContainerListener.h index 1ac036a5..8323c530 100644 --- a/Minecraft.World/net.minecraft.world.ContainerListener.h +++ b/Minecraft.World/net.minecraft.world.ContainerListener.h @@ -11,8 +11,8 @@ namespace net_minecraft_world { class ContainerListener { - friend class SimpleContainer; + friend class ::SimpleContainer; private: - virtual void containerChanged(shared_ptr simpleContainer) = 0; + virtual void containerChanged() = 0; }; } \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.damagesource.h b/Minecraft.World/net.minecraft.world.damagesource.h index 03f354ec..df0ccd8f 100644 --- a/Minecraft.World/net.minecraft.world.damagesource.h +++ b/Minecraft.World/net.minecraft.world.damagesource.h @@ -1,5 +1,7 @@ #pragma once +#include "CombatEntry.h" +#include "CombatTracker.h" #include "DamageSource.h" #include "EntityDamageSource.h" #include "IndirectEntityDamageSource.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.effect.h b/Minecraft.World/net.minecraft.world.effect.h index f5bd448f..5dad4fe9 100644 --- a/Minecraft.World/net.minecraft.world.effect.h +++ b/Minecraft.World/net.minecraft.world.effect.h @@ -1,5 +1,8 @@ #pragma once +#include "AbsoptionMobEffect.h" +#include "AttackDamageMobEffect.h" +#include "HealthBoostMobEffect.h" #include "MobEffect.h" #include "InstantenousMobEffect.h" #include "MobEffectInstance.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.entity.ai.attributes.h b/Minecraft.World/net.minecraft.world.entity.ai.attributes.h new file mode 100644 index 00000000..783f48b5 --- /dev/null +++ b/Minecraft.World/net.minecraft.world.entity.ai.attributes.h @@ -0,0 +1,10 @@ +#pragma once + +#include "Attribute.h" +#include "AttributeInstance.h" +#include "AttributeModifier.h" +#include "BaseAttribute.h" +#include "BaseAttributeMap.h" +#include "ModifiableAttributeInstance.h" +#include "RangedAttribute.h" +#include "ServersideAttributeMap.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.entity.ai.goal.h b/Minecraft.World/net.minecraft.world.entity.ai.goal.h index 5944daf2..73273e13 100644 --- a/Minecraft.World/net.minecraft.world.entity.ai.goal.h +++ b/Minecraft.World/net.minecraft.world.entity.ai.goal.h @@ -1,7 +1,6 @@ #pragma once #include "Goal.h" -#include "ArrowAttackGoal.h" #include "AvoidPlayerGoal.h" #include "BegGoal.h" #include "BreakDoorGoal.h" @@ -27,13 +26,15 @@ #include "OcelotSitOnTileGoal.h" #include "OfferFlowerGoal.h" #include "OpenDoorGoal.h" -#include "OzelotAttackGoal.h" +#include "OcelotAttackGoal.h" #include "PanicGoal.h" #include "PlayGoal.h" #include "RandomLookAroundGoal.h" #include "RandomStrollGoal.h" +#include "RangedAttackGoal.h" #include "RestrictOpenDoorGoal.h" #include "RestrictSunGoal.h" +#include "RunAroundLikeCrazyGoal.h" #include "SitGoal.h" #include "SwellGoal.h" #include "TakeFlowerGoal.h" diff --git a/Minecraft.World/net.minecraft.world.entity.ambient.h b/Minecraft.World/net.minecraft.world.entity.ambient.h new file mode 100644 index 00000000..924d413a --- /dev/null +++ b/Minecraft.World/net.minecraft.world.entity.ambient.h @@ -0,0 +1,4 @@ +#pragma once + +#include "AmbientCreature.h" +#include "Bat.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.entity.animal.h b/Minecraft.World/net.minecraft.world.entity.animal.h index efeb2c96..2bcb81f1 100644 --- a/Minecraft.World/net.minecraft.world.entity.animal.h +++ b/Minecraft.World/net.minecraft.world.entity.animal.h @@ -15,6 +15,8 @@ #include "SnowMan.h" // 1.2.3 -#include "TamableAnimal.h" -#include "Ozelot.h" -#include "VillagerGolem.h" \ No newline at end of file +#include "Ocelot.h" +#include "VillagerGolem.h" + +// 1.6.4 +#include "EntityHorse.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.entity.boss.h b/Minecraft.World/net.minecraft.world.entity.boss.h index 15aa271a..76409201 100644 --- a/Minecraft.World/net.minecraft.world.entity.boss.h +++ b/Minecraft.World/net.minecraft.world.entity.boss.h @@ -1,4 +1,5 @@ #pragma once #include "BossMob.h" -#include "BossMobPart.h" \ No newline at end of file +#include "MultiEntityMob.h" +#include "MultiEntityMobPart.h" diff --git a/Minecraft.World/net.minecraft.world.entity.h b/Minecraft.World/net.minecraft.world.entity.h index 9aa62632..2ba64218 100644 --- a/Minecraft.World/net.minecraft.world.entity.h +++ b/Minecraft.World/net.minecraft.world.entity.h @@ -23,4 +23,12 @@ #include "ItemFrame.h" // 1.2.3 -#include "AgableMob.h" \ No newline at end of file +#include "AgableMob.h" +#include "TamableAnimal.h" + +// 1.6.4 +#include "LeashFenceKnotEntity.h" +#include "MobGroupData.h" +#include "OwnableEntity.h" +#include "EntitySelector.h" +#include "LivingEntity.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.entity.item.h b/Minecraft.World/net.minecraft.world.entity.item.h index e35176bc..575f18b5 100644 --- a/Minecraft.World/net.minecraft.world.entity.item.h +++ b/Minecraft.World/net.minecraft.world.entity.item.h @@ -4,4 +4,11 @@ #include "FallingTile.h" #include "ItemEntity.h" #include "Minecart.h" +#include "MinecartChest.h" +#include "MinecartContainer.h" +#include "MinecartHopper.h" +#include "MinecartFurnace.h" +#include "MinecartRideable.h" +#include "MinecartSpawner.h" +#include "MinecartTNT.h" #include "PrimedTnt.h" diff --git a/Minecraft.World/net.minecraft.world.entity.monster.h b/Minecraft.World/net.minecraft.world.entity.monster.h index 1d6b8495..edeaf925 100644 --- a/Minecraft.World/net.minecraft.world.entity.monster.h +++ b/Minecraft.World/net.minecraft.world.entity.monster.h @@ -18,4 +18,9 @@ // 1.0.1 #include "Blaze.h" -#include "LavaSlime.h" \ No newline at end of file +#include "LavaSlime.h" + +// 1.6.4 +#include "RangedAttackMob.h" +#include "SharedMonsterAttributes.h" +#include "Witch.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.entity.projectile.h b/Minecraft.World/net.minecraft.world.entity.projectile.h index 3e56b04e..f871230a 100644 --- a/Minecraft.World/net.minecraft.world.entity.projectile.h +++ b/Minecraft.World/net.minecraft.world.entity.projectile.h @@ -15,4 +15,10 @@ #include "ThrownExpBottle.h" // Brought forward from 1.2 // Added TU 9 -#include "DragonFireball.h" \ No newline at end of file +#include "DragonFireball.h" + +// 1.6.4 +#include "FireworksRocketEntity.h" +#include "LargeFireball.h" +#include "Projectile.h" +#include "WitherSkull.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.h b/Minecraft.World/net.minecraft.world.h index 4e600b33..8b4f3e34 100644 --- a/Minecraft.World/net.minecraft.world.h +++ b/Minecraft.World/net.minecraft.world.h @@ -10,4 +10,6 @@ // TU10 #include "Icon.h" #include "IconRegister.h" -#include "FlippedIcon.h" \ No newline at end of file +#include "FlippedIcon.h" + +#include "WorldlyContainer.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.inventory.h b/Minecraft.World/net.minecraft.world.inventory.h index a2608dbd..82a8a52d 100644 --- a/Minecraft.World/net.minecraft.world.inventory.h +++ b/Minecraft.World/net.minecraft.world.inventory.h @@ -1,13 +1,18 @@ #pragma once #include "AbstractContainerMenu.h" +#include "AnimalChest.h" #include "ArmorSlot.h" +#include "BeaconMenu.h" #include "net.minecraft.world.inventory.ContainerListener.h" #include "ContainerMenu.h" #include "CraftingContainer.h" #include "CraftingMenu.h" +#include "FireworksMenu.h" #include "FurnaceMenu.h" #include "FurnaceResultSlot.h" +#include "HopperMenu.h" +#include "HorseInventoryMenu.h" #include "InventoryMenu.h" #include "MenuBackup.h" #include "ResultContainer.h" @@ -22,6 +27,6 @@ #include "MerchantMenu.h" #include "MerchantResultSlot.h" #include "PlayerEnderChestContainer.h" -#include "RepairMenu.h" +#include "AnvilMenu.h" #include "RepairContainer.h" #include "RepairResultSlot.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.item.crafting.h b/Minecraft.World/net.minecraft.world.item.crafting.h index ab6a32eb..f547c15e 100644 --- a/Minecraft.World/net.minecraft.world.item.crafting.h +++ b/Minecraft.World/net.minecraft.world.item.crafting.h @@ -6,6 +6,7 @@ #include "ArmorRecipes.h" #include "ClothDyeRecipes.h" #include "FoodRecipies.h" +#include "FireworksRecipe.h" #include "FurnaceRecipes.h" #include "OreRecipies.h" #include "ShapedRecipy.h" diff --git a/Minecraft.World/net.minecraft.world.item.h b/Minecraft.World/net.minecraft.world.item.h index 0300b954..07728069 100644 --- a/Minecraft.World/net.minecraft.world.item.h +++ b/Minecraft.World/net.minecraft.world.item.h @@ -6,7 +6,7 @@ #include "BowItem.h" #include "BowlFoodItem.h" #include "BucketItem.h" -#include "ClothTileItem.h" +#include "WoolTileItem.h" #include "CoalItem.h" #include "ComplexItem.h" #include "DiggerItem.h" @@ -38,14 +38,12 @@ #include "StoneSlabTileItem.h" #include "TileItem.h" #include "TilePlanterItem.h" -#include "TreeTileItem.h" #include "WeaponItem.h" // 1.8.2 #include "AuxDataTileItem.h" #include "ColoredTileItem.h" #include "UseAnim.h" -#include "StoneMonsterTileItem.h" // 1.0.1 #include "BottleItem.h" @@ -57,12 +55,11 @@ #include "Rarity.h" #include "WaterLilyTileItem.h" #include "ExperienceItem.h" // 4J Stu brought forward -#include "SmoothStoneBrickTileItem.h" // 4J Stu brought forward // TU9 #include "FireChargeItem.h" #include "ItemFrame.h" -#include "MonsterPlacerItem.h" +#include "SpawnEggItem.h" #include "MultiTextureTileItem.h" // TU12 @@ -75,6 +72,16 @@ #include "EnchantedBookItem.h" #include "SeedFoodItem.h" +// 1.6.4 +#include "FireworksChargeItem.h" +#include "FireworksItem.h" +#include "LeashItem.h" +#include "NameTagItem.h" +#include "SimpleFoiledItem.h" +#include "SnowItem.h" +#include "EmptyMapItem.h" + // 4J Added #include "ClockItem.h" -#include "CompassItem.h" \ No newline at end of file +#include "CompassItem.h" +#include "HtmlString.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.level.h b/Minecraft.World/net.minecraft.world.level.h index 01d14fcb..e69d423b 100644 --- a/Minecraft.World/net.minecraft.world.level.h +++ b/Minecraft.World/net.minecraft.world.level.h @@ -1,9 +1,12 @@ #pragma once +#include "BaseMobSpawner.h" +#include "BlockDestructionProgress.h" #include "ChunkPos.h" #include "Coord.h" #include "Explosion.h" #include "FoliageColor.h" +#include "GameRules.h" #include "GrassColor.h" #include "LevelConflictException.h" #include "LevelListener.h" @@ -13,13 +16,11 @@ #include "PortalForcer.h" #include "Region.h" #include "TickNextTickData.h" +#include "TileEventData.h" #include "TilePos.h" #include "WaterColor.h" #include "Level.h" #include "LevelType.h" #include "LevelSettings.h" -// TU 10 -#include "BlockDestructionProgress.h" - -#include "TileEventData.h" \ No newline at end of file +#include "Calendar.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.level.levelgen.flat.h b/Minecraft.World/net.minecraft.world.level.levelgen.flat.h new file mode 100644 index 00000000..92b8023c --- /dev/null +++ b/Minecraft.World/net.minecraft.world.level.levelgen.flat.h @@ -0,0 +1,4 @@ +#pragma once + +#include "FlatGeneratorInfo.h" +#include "FlatLayerInfo.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.level.levelgen.structure.h b/Minecraft.World/net.minecraft.world.level.levelgen.structure.h index 2bd9cfa2..e7dae5ea 100644 --- a/Minecraft.World/net.minecraft.world.level.levelgen.structure.h +++ b/Minecraft.World/net.minecraft.world.level.levelgen.structure.h @@ -5,9 +5,13 @@ #include "MineShaftFeature.h" #include "MineShaftPieces.h" #include "MineShaftStart.h" +#include "NetherBridgeFeature.h" +#include "NetherBridgePieces.h" #include "StrongholdFeature.h" #include "StrongholdPieces.h" #include "StructureFeature.h" +#include "StructureFeatureIO.h" +#include "StructureFeatureSavedData.h" #include "StructurePiece.h" #include "StructureStart.h" #include "VillageFeature.h" diff --git a/Minecraft.World/net.minecraft.world.level.redstone.h b/Minecraft.World/net.minecraft.world.level.redstone.h new file mode 100644 index 00000000..8e30ebfc --- /dev/null +++ b/Minecraft.World/net.minecraft.world.level.redstone.h @@ -0,0 +1,3 @@ +#pragma once + +#include "Redstone.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.level.tile.entity.h b/Minecraft.World/net.minecraft.world.level.tile.entity.h index 0b6cb04a..c3209df9 100644 --- a/Minecraft.World/net.minecraft.world.level.tile.entity.h +++ b/Minecraft.World/net.minecraft.world.level.tile.entity.h @@ -1,10 +1,17 @@ #pragma once +#include "BeaconTileEntity.h" #include "BrewingStandTileEntity.h" #include "ChestTileEntity.h" +#include "CommandBlockEntity.h" +#include "ComparatorTileEntity.h" +#include "DaylightDetectorTileEntity.h" #include "DispenserTileEntity.h" +#include "DropperTileEntity.h" #include "EnchantmentTableEntity.h" #include "FurnaceTileEntity.h" +#include "Hopper.h" +#include "HopperTileEntity.h" #include "MobSpawnerTileEntity.h" #include "MusicTileEntity.h" #include "SignTileEntity.h" diff --git a/Minecraft.World/net.minecraft.world.level.tile.h b/Minecraft.World/net.minecraft.world.level.tile.h index f039b000..36c7ac5c 100644 --- a/Minecraft.World/net.minecraft.world.level.tile.h +++ b/Minecraft.World/net.minecraft.world.level.tile.h @@ -3,6 +3,10 @@ #include "Tile.h" #include "AirTile.h" #include "AnvilTile.h" +#include "BaseEntityTile.h" +#include "BasePressurePlateTile.h" +#include "BaseRailTile.h" +#include "BeaconTile.h" #include "BedTile.h" #include "BookshelfTile.h" #include "BrewingStandTile.h" @@ -14,10 +18,13 @@ #include "CauldronTile.h" #include "ChestTile.h" #include "ClayTile.h" -#include "ClothTile.h" #include "CocoaTile.h" +#include "ColoredTile.h" +#include "CommandBlock.h" +#include "ComparatorTile.h" #include "CoralTile.h" #include "CropTile.h" +#include "DaylightDetectorTile.h" #include "DeadBushTile.h" #include "DetectorRailTile.h" #include "DiodeTile.h" @@ -25,6 +32,7 @@ #include "DirtTile.h" #include "DispenserTile.h" #include "DoorTile.h" +#include "DropperTile.h" #include "EggTile.h" #include "EnchantmentTableTile.h" #include "EnderChestTile.h" @@ -36,19 +44,21 @@ #include "FlowerPotTile.h" #include "FurnaceTile.h" #include "GlassTile.h" +#include "Glowstonetile.h" #include "GrassTile.h" #include "GravelTile.h" +#include "HalfSlabTile.h" #include "HalfTransparentTile.h" +#include "HayBlockTile.h" #include "HeavyTile.h" -#include "HellSandTile.h" -#include "HellStoneTile.h" +#include "HopperTile.h" #include "HugeMushroomTile.h" #include "IceTile.h" +#include "JukeboxTile.h" #include "LadderTile.h" #include "LeafTile.h" #include "LevelEvent.h" #include "LeverTile.h" -#include "LightGemTile.h" #include "LiquidTile.h" #include "LiquidTileDynamic.h" #include "LiquidTileStatic.h" @@ -57,9 +67,10 @@ #include "MetalTile.h" #include "MobSpawnerTile.h" #include "Mushroom.h" -#include "MusicTile.h" +#include "NoteBlockTile.h" #include "MycelTile.h" -#include "NetherStalkTile.h" +#include "NetherrackTile.h" +#include "NetherWartTile.h" #include "NotGateTile.h" #include "ObsidianTile.h" #include "OreTile.h" @@ -67,25 +78,31 @@ #include "PistonExtensionTile.h" #include "PortalTile.h" #include "PotatoTile.h" +#include "PoweredMetalTile.h" +#include "PoweredRailTile.h" #include "PressurePlateTile.h" #include "PumpkinTile.h" #include "QuartzBlockTile.h" #include "RailTile.h" -#include "RecordPlayerTile.h" #include "RedlightTile.h" #include "RedStoneDustTile.h" #include "RedStoneOreTile.h" #include "ReedTile.h" +#include "RepeaterTile.h" +#include "RotatedPillarTile.h" #include "SandStoneTile.h" #include "Sapling.h" #include "SignTile.h" #include "SkullTile.h" #include "SmoothStoneBrickTile.h" #include "SnowTile.h" +#include "SoulSandTile.h" #include "Sponge.h" -#include "SpringTile.h" +#include "StainedGlassBlock.h" +#include "StainedGlassPaneBlock.h" #include "StairTile.h" #include "StemTile.h" +#include "StoneButtonTile.h" #include "StoneMonsterTile.h" #include "StoneSlabTile.h" #include "StoneTile.h" @@ -105,6 +122,8 @@ #include "WallTile.h" #include "WaterLilyTile.h" #include "WebTile.h" +#include "WeightedPressurePlateTile.h" +#include "WoodButtonTile.h" #include "WorkbenchTile.h" #include "WoodTile.h" #include "HalfSlabTile.h" diff --git a/Minecraft.World/net.minecraft.world.scores.criteria.h b/Minecraft.World/net.minecraft.world.scores.criteria.h new file mode 100644 index 00000000..fd8c8640 --- /dev/null +++ b/Minecraft.World/net.minecraft.world.scores.criteria.h @@ -0,0 +1,5 @@ +#pragma once + +#include "DummyCriteria.h" +#include "HealthCriteria.h" +#include "ObjectiveCriteria.h" \ No newline at end of file diff --git a/Minecraft.World/net.minecraft.world.scores.h b/Minecraft.World/net.minecraft.world.scores.h new file mode 100644 index 00000000..0dccff46 --- /dev/null +++ b/Minecraft.World/net.minecraft.world.scores.h @@ -0,0 +1,9 @@ +#pragma once + +#include "Objective.h" +#include "PlayerTeam.h" +#include "Score.h" +#include "Scoreboard.h" +#include "ScoreboardSaveData.h" +#include "ScoreHolder.h" +#include "Team.h" \ No newline at end of file diff --git a/Minecraft.World/stdafx.h b/Minecraft.World/stdafx.h index 614f997b..48e52544 100644 --- a/Minecraft.World/stdafx.h +++ b/Minecraft.World/stdafx.h @@ -183,8 +183,8 @@ void MemSect(int sect); #include "..\Minecraft.Client\Common\Network\GameNetworkManager.h" // #ifdef _XBOX -#include "..\Minecraft.Client\Common\UI\UIEnums.h" #include "..\Minecraft.Client\Common\App_defines.h" +#include "..\Minecraft.Client\Common\UI\UIEnums.h" #include "..\Minecraft.Client\Common\App_enums.h" #include "..\Minecraft.Client\Common\Tutorial\TutorialEnum.h" #include "..\Minecraft.Client\Common\App_structs.h" diff --git a/Minecraft.World/system.cpp b/Minecraft.World/system.cpp index cce04bdc..b6dd56d9 100644 --- a/Minecraft.World/system.cpp +++ b/Minecraft.World/system.cpp @@ -124,10 +124,9 @@ __int64 System::currentTimeMillis() __int64 System::currentRealTimeMillis() { #ifdef __PSVITA__ - SceDateTime Time; - sceRtcGetCurrentClockLocalTime(&Time); - __int64 systTime = (((((((Time.day * 24) + Time.hour) * 60) + Time.minute) * 60) + Time.second) * 1000) + (Time.microsecond / 1000); - return systTime; + SceFiosDate fileTime = sceFiosDateGetCurrent(); + + return fileTime/1000000; #else return currentTimeMillis(); #endif diff --git a/Minecraft.World/x64headers/extraX64.h b/Minecraft.World/x64headers/extraX64.h index d06b2420..2205ae05 100644 --- a/Minecraft.World/x64headers/extraX64.h +++ b/Minecraft.World/x64headers/extraX64.h @@ -50,9 +50,9 @@ typedef SQRNetworkManager::PresenceSyncInfo INVITE_INFO; #include #include #include -#include "..\..\Minecraft.Client\PSVita\PSVita_PlayerUID.h" #include "..\..\Minecraft.Client\PSVita\Network\SQRNetworkManager_Vita.h" #include "..\..\Minecraft.Client\PSVita\Network\SQRNetworkManager_AdHoc_Vita.h" +#include "..\..\Minecraft.Client\PSVita\4JLibs\inc\4J_Profile.h" typedef SQRNetworkManager_Vita::SessionID SessionID; typedef SQRNetworkManager_Vita::PresenceSyncInfo INVITE_INFO; @@ -70,7 +70,7 @@ class INVITE_INFO; #endif // __PS3__ -#ifndef _DURANGO +#if !(defined _DURANGO || defined __PSVITA__) typedef PlayerUID *PPlayerUID; #endif typedef struct _XUIOBJ* HXUIOBJ; @@ -332,6 +332,7 @@ void XSetThreadProcessor(HANDLE a, int b); const int QNET_SENDDATA_LOW_PRIORITY = 0; const int QNET_SENDDATA_SECONDARY = 0; + #if defined(__PS3__) || defined(__ORBIS__) || defined(_DURANGO) || defined(__PSVITA__) #define INVALID_XUID PlayerUID() #else @@ -560,7 +561,7 @@ const int XC_LANGUAGE_DUTCH =0x10; const int XC_LANGUAGE_SCHINESE =0x11; // for Sony -const int XC_LANGUAGE_LATINAMERICANSPANISH =0xF0; +// const int XC_LANGUAGE_LATINAMERICANSPANISH =0xF0; // 4J-JEV: Now differentiated via XC_LOCALE_LATIN_AMERICA const int XC_LANGUAGE_FINISH =0xF1; const int XC_LANGUAGE_GREEK =0xF2; const int XC_LANGUAGE_DANISH =0xF3; -- cgit v1.2.3