Merge branch 'master' into Effects
This commit is contained in:
commit
d3b8100a7b
@ -2848,7 +2848,7 @@ end
|
||||
MirrorBlockFaceY = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after mirroring it around the Y axis (or rotating 180 degrees around it)." },
|
||||
NoCaseCompare = {Params = "string, string", Return = "number", Notes = "Case-insensitive string comparison; returns 0 if the strings are the same"},
|
||||
NormalizeAngleDegrees = { Params = "AngleDegrees", Return = "AngleDegrees", Notes = "Returns the angle, wrapped into the [-180, +180) range." },
|
||||
ReplaceString = {Params = "full-string, to-be-replaced-string, to-replace-string", Notes = "Replaces *each* occurence of to-be-replaced-string in full-string with to-replace-string"},
|
||||
ReplaceString = {Params = "full-string, to-be-replaced-string, to-replace-string", Return = "string", Notes = "Replaces *each* occurence of to-be-replaced-string in full-string with to-replace-string"},
|
||||
RotateBlockFaceCCW = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after rotating it around the Y axis 90 degrees counter-clockwise." },
|
||||
RotateBlockFaceCW = { Params = "{{Globals#BlockFaces|eBlockFace}}", Return = "{{Globals#BlockFaces|eBlockFace}}", Notes = "Returns the {{Globals#BlockFaces|eBlockFace}} that corresponds to the given {{Globals#BlockFaces|eBlockFace}} after rotating it around the Y axis 90 degrees clockwise." },
|
||||
StringSplit = {Params = "string, SeperatorsString", Return = "array table of strings", Notes = "Seperates string into multiple by splitting every time any of the characters in SeperatorsString is encountered."},
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 7cc99285ae5117418f657c3b295ca71f2b75b4f4
|
||||
Subproject commit bd23915df763b182610c6163c5ff2d64a0756560
|
@ -44,6 +44,8 @@ ApplePlanks, 4 = AppleLog, *
|
||||
ConiferPlanks, 4 = ConiferLog, *
|
||||
BirchPlanks, 4 = BirchLog, *
|
||||
JunglePlanks, 4 = JungleLog, *
|
||||
AcaciaPlanks, 4 = AcaciaLog, *
|
||||
DarkOakPlanks, 4 = DarkOakLog, *
|
||||
Stick, 4 = Planks, 2:2, 2:3
|
||||
Torch, 4 = Stick, 1:2 | Coal, 1:1
|
||||
Workbench = Planks, 1:1, 1:2, 2:1, 2:2
|
||||
@ -59,36 +61,77 @@ Furnace = Cobblestone, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
|
||||
#******************************************************#
|
||||
# Blocks
|
||||
#
|
||||
IronBlock = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
GoldBlock = GoldIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
DiamondBlock = Diamond, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
LapisBlock = LapisLazuli, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
EmeraldBlock = Emerald, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
RedstoneBlock = RedstoneDust, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
QuartzBlock = NetherQuartz, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
NetherBrick = netherbrickitem, 1:1, 1:2, 2:1, 2:2
|
||||
Glowstone = GlowstoneDust, 1:1, 1:2, 2:1, 2:2
|
||||
Wool = String, 1:1, 1:2, 2:1, 2:2
|
||||
TNT = Gunpowder, 1:1, 3:1, 2:2, 1:3, 3:3 | Sand, 2:1, 1:2, 3:2, 2:3
|
||||
PillarQuartzBlock = QuartzSlab, 1:1, 1:2
|
||||
ChiseledQuartzBlock, 2 = QuartzBlock, 1:1, 1:2
|
||||
CoalBlock = Coal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
HayBale = Wheat, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
IronBlock = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
GoldBlock = GoldIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
DiamondBlock = Diamond, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
LapisBlock = LapisLazuli, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
EmeraldBlock = Emerald, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
RedstoneBlock = RedstoneDust, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
QuartzBlock = NetherQuartz, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
NetherBrick = netherbrickitem, 1:1, 1:2, 2:1, 2:2
|
||||
Glowstone = GlowstoneDust, 1:1, 1:2, 2:1, 2:2
|
||||
Wool = String, 1:1, 1:2, 2:1, 2:2
|
||||
TNT = Gunpowder, 1:1, 3:1, 2:2, 1:3, 3:3 | Sand, 2:1, 1:2, 3:2, 2:3
|
||||
PillarQuartzBlock = QuartzSlab, 1:1, 1:2
|
||||
ChiseledQuartzBlock, 2 = QuartzBlock, 1:1, 1:2
|
||||
CoalBlock = Coal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
HayBale = Wheat, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2
|
||||
ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2
|
||||
BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2
|
||||
StoneBrick, 4 = Stone, 1:1, 1:2, 2:1, 2:2
|
||||
BookShelf = Planks, 1:1, 2:1, 3:1, 1:3, 2:3, 3:3 | Book, 1:2, 2:2, 3:2
|
||||
Sandstone, 4 = Sand, 1:1, 1:2, 2:1, 2:2
|
||||
SmoothSandstone, 4 = Sandstone, 1:1, 1:2, 2:1, 2:2
|
||||
OrnamentSandstone = SandstoneSlab, 1:1, 1:2
|
||||
JackOLantern = Pumpkin, 1:1 | Torch, 1:2
|
||||
PolishedGranite, 4 = Granite, 1:1, 1:2, 2:1, 2:2
|
||||
PolishedDiorite, 4 = Diorite, 1:1, 1:2, 2:1, 2:2
|
||||
PolishedAndesite, 4 = Andesite, 1:1, 1:2, 2:1, 2:2
|
||||
CoarsedDirt, 4 = Dirt, 1:1, 2:2 | Gravel, 1:2, 2:1
|
||||
CoarsedDirt, 4 = Gravel, 1:1, 2:2 | Dirt, 1:2, 2:1
|
||||
SlimeBlock = Slimeball, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
Prismarine = PrismarineShard, 1:1, 1:2, 2:1, 2:2
|
||||
PrismarineBricks = PrismarineShard, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
DarkPrismarine = PrismarineShard, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Inksac, 2:2
|
||||
SeaLantern = PrismarineShard, 1:1, 1:3, 3:1, 3:3 | PrismarineCrystals, 1:2, 2:1, 2:2, 2:3, 3:2
|
||||
RedSandstone, 4 = RedSand, 1:1, 1:2, 2:1, 2:2
|
||||
ChiseledRedSandstone, 4 = RedSandstoneSlab, 1:1, 1:2
|
||||
SmoothRedSandstone, 4 = RedSand, 1:1, 1:2, 2:1, 2:2
|
||||
MossyStoneBrick = Stonebrick, * | Vines, *
|
||||
Leather = RabbitHide, 1:1, 1:2, 2:1, 2:2
|
||||
|
||||
# Slabs:
|
||||
StoneSlab, 6 = Stone, 1:1, 2:1, 3:1
|
||||
SandstoneSlab, 6 = Sandstone, 1:1, 2:1, 3:1
|
||||
WoodSlab, 6 = Planks, 1:1, 2:1, 3:1
|
||||
SpruceWoodSlab, 6 = SprucePlanks, 1:1, 2:1, 3:1
|
||||
BirchWoodSlab, 6 = BirchPlanks, 1:1, 2:1, 3:1
|
||||
JungleWoodSlab, 6 = JunglePlanks, 1:1, 2:1, 3:1
|
||||
AcaciaWoodSlab, 6 = AcaciaPlanks, 1:1, 2:1, 3:1
|
||||
DarkOakWoodSlab, 6 = DarkOakPlanks, 1:1, 2:1, 3:1
|
||||
OakWoodSlab, 6 = OakPlanks, 1:1, 2:1, 3:1
|
||||
CobblestoneSlab, 6 = Cobblestone, 1:1, 2:1, 3:1
|
||||
BrickSlab, 6 = BrickBlock, 1:1, 2:1, 3:1
|
||||
StonebrickSlab, 6 = StoneBrick, 1:1, 2:1, 3:1
|
||||
NetherbrickSlab, 6 = NetherBrick, 1:1, 2:1, 3:1
|
||||
Quartzslab, 6 = QuartzBlock, 1:1, 2:1, 3:1
|
||||
snow, 6 = SnowBlock, 1:1, 2:1, 3:1
|
||||
RedSandstoneSlab, 6 = RedSandstone, 1:1, 2:1, 3:1
|
||||
|
||||
|
||||
# Stairs:
|
||||
WoodStairs, 4 = Planks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
WoodStairs, 4 = Planks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
SpruceWoodStairs, 4 = SprucePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
SpruceWoodStairs, 4 = SprucePlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
BirchWoodStairs, 4 = BirchPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
BirchWoodStairs, 4 = BirchPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
JungleWoodStairs, 4 = JunglePlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
JungleWoodStairs, 4 = JunglePlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
AcaciaWoodStairs, 4 = AcaciaPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
AcaciaWoodStairs, 4 = AcaciaPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
DarkOakWoodStairs, 4 = DarkOakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
DarkOakWoodStairs, 4 = DarkOakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
WoodStairs, 4 = OakPlanks, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
WoodStairs, 4 = OakPlanks, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
cobblestoneStairs, 4 = Cobblestone, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
cobblestoneStairs, 4 = Cobblestone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
BrickStairs, 4 = BrickBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
@ -101,15 +144,8 @@ quartzstairs, 4 = QuartzBlock, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
quartzstairs, 4 = QuartzBlock, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
StoneBrickStairs, 4 = StoneBrick, 1:1, 1:2, 2:2, 1:3, 2:3, 3:3
|
||||
StoneBrickStairs, 4 = StoneBrick, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2
|
||||
ClayBlock = Clay, 1:1, 1:2, 2:1, 2:2
|
||||
BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2
|
||||
StoneBrick, 4 = Stone, 1:1, 1:2, 2:1, 2:2
|
||||
BookShelf = Planks, 1:1, 2:1, 3:1, 1:3, 2:3, 3:3 | Book, 1:2, 2:2, 3:2
|
||||
Sandstone, 4 = Sand, 1:1, 1:2, 2:1, 2:2
|
||||
SmoothSandstone, 4 = Sandstone, 1:1, 1:2, 2:1, 2:2
|
||||
OrnamentSandstone = SandstoneSlab, 1:1, 1:2
|
||||
JackOLantern = Pumpkin, 1:1 | Torch, 1:2
|
||||
RedSandstoneStairs, 4 = RedSandstone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
RedSandstoneStairs, 4 = RedSandstone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
|
||||
|
||||
# Other
|
||||
Carpet = Wool, 1:3, 2:3
|
||||
@ -244,11 +280,19 @@ ActivatorRail, 6 = IronIngot, 1:1, 1:2, 1:3, 3:1, 3:2, 3:3 | Stick, 2:1, 2:3 | R
|
||||
#******************************************************#
|
||||
# Mechanisms
|
||||
#
|
||||
WoodenDoor = Planks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
|
||||
IronDoor = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
|
||||
WoodenDoor, 3 = OakPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
|
||||
SpruceDoor, 3 = SprucePlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
|
||||
BirchDoor, 3 = BirchPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
|
||||
JungleDoor, 3 = JunglePlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
|
||||
AcaciaDoor, 3 = AcaciaPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
|
||||
DarkOakDoor, 3 = DarkOakPlanks, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
|
||||
IronDoor, 3 = IronIngot, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3
|
||||
TrapDoor, 2 = Planks, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
|
||||
IronTrapDoor = IronIngot, 1:1, 1:2, 2:1, 2:2
|
||||
WoodPlate = Planks, 1:1, 2:1
|
||||
StonePlate = Stone, 1:1, 2:1
|
||||
lightweightedpressureplate = IronIngot, 1:1, 2:1
|
||||
heavyweightedpressureplate = GoldIngot, 1:1, 2:1
|
||||
StoneButton = Stone, 1:1
|
||||
WoodenButton = Planks, 1:1
|
||||
RedstoneTorchOn = Stick, 1:2 | RedstoneDust, 1:1
|
||||
@ -286,6 +330,8 @@ MelonSeeds = MelonSlice, *
|
||||
PumpkinSeeds, 4 = Pumpkin, *
|
||||
PumpkinPie = Pumpkin, * | Sugar, * | egg, *
|
||||
Wheat, 9 = Haybale, *
|
||||
RabbitStew = Cooked Rabbit, 2:1 | Carrot, 1:2 | BakedPotato, 2:2 | BrownMushroom, 3:2 | Bowl, 2:3
|
||||
RabbitStew = Cooked Rabbit, 2:1 | Carrot, 1:2 | BakedPotato, 2:2 | RedMushroom, 3:2 | Bowl, 2:3
|
||||
|
||||
|
||||
|
||||
@ -314,17 +360,49 @@ IronBars, 16 = IronIngot, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
|
||||
Paper, 3 = Sugarcane, 1:1, 2:1, 3:1
|
||||
Book = Paper, *, *, * | leather, *
|
||||
Bookandquill = Book, * | feather, * | inksac, *
|
||||
Fence, 2 = Stick, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
|
||||
Fence, 3 = OakPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
|
||||
SpruceFence, 3 = SprucePlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
|
||||
BirchFence, 3 = BirchPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
|
||||
JungleFence, 3 = JunglePlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
|
||||
DarkOakFence, 3 = DarkOakPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
|
||||
AcaciaFence, 3 = AcaciaPlanks, 1:1, 1:2, 3:1, 3:2 | Stick, 2:1, 2:2
|
||||
Cobblestonewall, 6 = cobblestone, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
|
||||
mossycobblestonewall, 6 = mossycobblestone, 1:2, 1:3, 2:2, 2:3, 3:2, 3:3
|
||||
NetherBrickFence, 6 = NetherBrick, 1:1, 2:1, 3:1, 1:2, 2:2, 3:2
|
||||
FenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | Planks, 2:1, 2:2
|
||||
FenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | OakPlanks, 2:1, 2:2
|
||||
SpruceFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | SprucePlanks, 2:1, 2:2
|
||||
BirchFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | BirchPlanks, 2:1, 2:2
|
||||
JungleFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | JunglePlanks, 2:1, 2:2
|
||||
DarkOakFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | DarkOakPlanks, 2:1, 2:2
|
||||
AcaciaFenceGate = Stick, 1:1, 1:2, 3:1, 3:2 | AcaciaPlanks, 2:1, 2:2
|
||||
Bed = Planks, 1:2, 2:2, 3:2 | Wool, 1:1, 2:1, 3:1
|
||||
GoldIngot = GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||
EyeOfEnder = EnderPearl, * | BlazePowder, *
|
||||
Beacon = Glass, 1:1, 1:2, 2:1, 3:1, 3:2 | Obsidian, 1:3, 2:3, 3:3 | NetherStar, 2:2
|
||||
Anvil = IronBlock, 1:1, 2:1, 3:1 | IronIngot, 2:2, 1:3, 2:3, 3:3
|
||||
FlowerPot = Brick, 1:2, 2:3, 3:2
|
||||
ArmorStand = Stick, 1:1, 1:3, 2:1, 2:2, 3:1, 3:3 | StoneSlab, 2:3
|
||||
|
||||
# These are just the basic ones, you can add various shapes and stuff to each of them
|
||||
# ToDo: Add the various shapes (saved in NBT-Tags, not in meta)
|
||||
# Banners:
|
||||
|
||||
WhiteBanner = Stick, 2:3 | WhiteWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
OrangeBanner = Stick, 2:3 | OrangeWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
MagentaBanner = Stick, 2:3 | MagentaWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
LightBlueBanner = Stick, 2:3 | LightBlueWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
YellowBanner = Stick, 2:3 | YellowWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
LimeBanner = Stick, 2:3 | LimeWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
PinkBanner = Stick, 2:3 | PinkWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
GrayBanner = Stick, 2:3 | GrayWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
LightGrayBanner = Stick, 2:3 | LightGrayWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
CyanBanner = Stick, 2:3 | CyanWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
PurpleBanner = Stick, 2:3 | PurpleWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
BlueBanner = Stick, 2:3 | BlueWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
BrownBanner = Stick, 2:3 | BrownWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
GreenBanner = Stick, 2:3 | GreenWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
RedBanner = Stick, 2:3 | RedWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
BlackBanner = Stick, 2:3 | BlackWool, 1:1, 1:2, 2:1, 2:2, 2:1, 2:2
|
||||
|
||||
|
||||
|
||||
|
@ -10,25 +10,28 @@
|
||||
# An Item is defined by an Item Type, an amount (and damage)
|
||||
# The damage is optional, and if not specified it's assumed to be 0
|
||||
#
|
||||
# -Cactus Green:
|
||||
# 351 : 1 ( : 2 )
|
||||
# ItemType : Amount ( : Damage )
|
||||
# Cactus Green example:
|
||||
# 351 : 2 ( , 1 )
|
||||
# ItemType : Damage ( , Amount )
|
||||
# or simple use the item name (marked in items.ini):
|
||||
# CactusGreen ( , 1 )
|
||||
#
|
||||
#
|
||||
# **** Recipe and result ****
|
||||
#
|
||||
# 4:1@200=1:1 -> Produces 1 smooth stone from 1 cobblestone in 200 ticks (10 seconds)
|
||||
# Cobble @ 200 = Stone -> Produces 1 smooth stone from 1 cobblestone in 200 ticks (10 seconds)
|
||||
#
|
||||
# 4 : 1 @ 200 = 1 : 1
|
||||
# ItemType : Amount @ ticks = ItemID : Amount
|
||||
# Write in full:
|
||||
# Cobble : 0 , 1 @ 200 = 1 : 1 , 1
|
||||
# ItemType : Damage , Amount @ ticks = ItemType : Damage , Amount
|
||||
#
|
||||
#
|
||||
# **** Fuel ****
|
||||
#
|
||||
# !17:1 = 300 -> 1 Wood burns for 300 ticks (15 s)
|
||||
#
|
||||
# ! 17 : 1 = 300
|
||||
# Fuel ItemType : Amount = ticks
|
||||
# ! Wood , 1 = 300
|
||||
# Fuel ItemType , Amount = ticks
|
||||
#
|
||||
#******************************************************#
|
||||
|
||||
@ -39,20 +42,24 @@
|
||||
#--------------------------
|
||||
# Smelting recipes
|
||||
|
||||
4:1 @ 200 = 1:1 # 1 Cobblestone -> 1 Rock
|
||||
15:1 @ 200 = 265:1 # 1 Iron Ore -> 1 Iron Ingot
|
||||
14:1 @ 200 = 266:1 # 1 Gold Ore -> 1 Gold Ingot
|
||||
153:1 @ 200 = 406:1 # 1 Quartz Ore -> 1 Quartz
|
||||
12:1 @ 200 = 20:1 # 1 Sand -> 1 Glass
|
||||
319:1 @ 200 = 320:1 # 1 Raw Pork -> 1 Cooked Pork
|
||||
363:1 @ 200 = 364:1 # 1 Raw Beef -> 1 Cooked Beef (steak)
|
||||
365:1 @ 200 = 366:1 # 1 Raw Chicken -> 1 Cooked Chicken
|
||||
337:1 @ 200 = 336:1 # 1 Clay -> 1 Clay Brick
|
||||
82:1 @ 200 = 172:1 # 1 Clay Block -> 1 Hardened Clay
|
||||
87:1 @ 200 = 405:1 # 1 NetherRack -> 1 NetherBrick
|
||||
349:1 @ 200 = 350:1 # 1 Raw Fish -> 1 Cooked Fish
|
||||
17:1 @ 200 = 263:1:1 # 1 Log -> 1 Charcoal
|
||||
81:1 @ 200 = 351:1:2 # 1 Cactus -> 1 Green Dye
|
||||
Cobble = Stone
|
||||
IronOre = IronIngot
|
||||
GoldOre = GoldIngot
|
||||
NetherQuartzOre = NetherQuartz
|
||||
Sand = Glass
|
||||
Pork = CookedPork
|
||||
RawBeef = Steak
|
||||
RawChicken = CookedChicken
|
||||
Clay = Brick
|
||||
ClayBlock = HardenedClay
|
||||
TallGrass = NetherBrickItem
|
||||
RawFish = CookedFish
|
||||
Log = CharCoal
|
||||
Cactus = GreenDye
|
||||
WetSponge = Sponge
|
||||
Stonebrick = CrackedStonebrick
|
||||
RawRabbit = CookedRabbit
|
||||
RawMutton = CookedMutton
|
||||
|
||||
|
||||
|
||||
@ -61,31 +68,41 @@
|
||||
#--------------------------
|
||||
# Fuels
|
||||
|
||||
! 263:1 = 1600 # 1 Coal -> 80 sec
|
||||
! 263:1:1 = 1600 # 1 Charcoal -> 80 sec
|
||||
! 126:1 = 15 # 1 Halfslab -> 7.5 sec
|
||||
! 5:1 = 300 # 1 Planks -> 15 sec
|
||||
! 280:1 = 100 # 1 Stick -> 5 sec
|
||||
! 85:1 = 300 # 1 Fence -> 15 sec
|
||||
! 53:1 = 300 # 1 Wooden Stairs -> 15 sec
|
||||
! 58:1 = 300 # 1 Crafting Table -> 15 sec
|
||||
! 47:1 = 300 # 1 Bookshelf -> 15 sec
|
||||
! 54:1 = 300 # 1 Chest -> 15 sec
|
||||
! 84:1 = 300 # 1 Jukebox -> 15 sec
|
||||
! 327:1 = 20000 # 1 Lava Bucket -> 1000 sec
|
||||
! 17:1 = 300 # 1 Wood -> 15 sec
|
||||
! 6:1 = 100 # 1 Sapling -> 5 sec
|
||||
! 173:1 = 16000 # 1 Coal Block -> 800 sec
|
||||
! 369:1 = 2400 # 1 Blaze Rod -> 120 sec
|
||||
! 25:1 = 300 # 1 Note Block -> 15 sec
|
||||
! 151:1 = 300 # 1 Daylight Sensor -> 15 sec
|
||||
! 107:1 = 300 # 1 Fence Gate -> 15 sec
|
||||
! 167:1 = 300 # 1 Trapdoor -> 15 sec
|
||||
! 146:1 = 300 # 1 Trapped Chest -> 15 sec
|
||||
! 72:1 = 300 # 1 Pressure Plate -> 15 sec
|
||||
! 270:1 = 200 # 1 Wooden Pickaxe -> 10 sec
|
||||
! 271:1 = 200 # 1 Wooden Axe -> 10 sec
|
||||
! 269:1 = 200 # 1 Wooden Shovel -> 10 sec
|
||||
! 290:1 = 200 # 1 Wooden Hoe -> 10 sec
|
||||
! 268:1 = 200 # 1 Wooden Sword -> 10 sec
|
||||
! CharCoal = 1600 # -> 80 sec
|
||||
! Coal = 1600 # -> 80 sec
|
||||
! WoodenSlab = 15 # -> 7.5 sec
|
||||
! Planks = 300 # -> 15 sec
|
||||
! Stick = 100 # -> 5 sec
|
||||
! Fence = 300 # -> 15 sec
|
||||
! SpruceFence = 300 # -> 15 sec
|
||||
! BirchFence = 300 # -> 15 sec
|
||||
! JungleFence = 300 # -> 15 sec
|
||||
! DarkOakFence = 300 # -> 15 sec
|
||||
! AcaciaFence = 300 # -> 15 sec
|
||||
! WoodStairs = 300 # -> 15 sec
|
||||
! Workbench = 300 # -> 15 sec
|
||||
! Bookshelf = 300 # -> 15 sec
|
||||
! Chest = 300 # -> 15 sec
|
||||
! Jukebox = 300 # -> 15 sec
|
||||
! Lavabucket = 20000 # -> 1000 sec
|
||||
! Log = 300 # -> 15 sec
|
||||
! Sapling = 100 # -> 5 sec
|
||||
! CoalBlock = 16000 # -> 800 sec
|
||||
! BlazeRod = 2400 # -> 120 sec
|
||||
! NoteBlock = 300 # -> 15 sec
|
||||
! DaylightSensor = 300 # -> 15 sec
|
||||
! FenceGate = 300 # -> 15 sec
|
||||
! SpruceFenceGate = 300 # -> 15 sec
|
||||
! BirchFenceGate = 300 # -> 15 sec
|
||||
! JungleFenceGate = 300 # -> 15 sec
|
||||
! DarkOakFenceGate = 300 # -> 15 sec
|
||||
! Trapdoor = 300 # -> 15 sec
|
||||
! TrappedChest = 300 # -> 15 sec
|
||||
! WoodPlate = 300 # -> 15 sec
|
||||
! WoodPickaxe = 200 # -> 10 sec
|
||||
! WoodAxe = 200 # -> 10 sec
|
||||
! WoodShovel = 200 # -> 10 sec
|
||||
! WoodHoe = 200 # -> 10 sec
|
||||
! WoodSword = 200 # -> 10 sec
|
||||
|
||||
|
||||
|
@ -1,9 +1,17 @@
|
||||
[Items]
|
||||
air=0
|
||||
rock=1
|
||||
granite=1:1
|
||||
polishedgranite=1:2
|
||||
diorite=1:3
|
||||
polisheddiorite=1:4
|
||||
andesite=1:5
|
||||
polishedandesite=1:6
|
||||
stone=1
|
||||
grass=2
|
||||
dirt=3
|
||||
coarseddirt=3:1
|
||||
podzol=3:2
|
||||
cobblestone=4
|
||||
cobble=4
|
||||
planks=5
|
||||
@ -17,6 +25,11 @@ birchplanks=5:2
|
||||
lightplanks=5:2
|
||||
jungleplanks=5:3
|
||||
redplanks=5:3
|
||||
acaciaplanks=5:4
|
||||
darkoakplanks=5:5
|
||||
bigoakplanks=5:5
|
||||
roofedoakplanks=5:5
|
||||
|
||||
|
||||
; Obsolete: do not use "wood", as its meaning is not clear - wiki uses log as wood, we use planks as wood.
|
||||
wood=5
|
||||
@ -40,6 +53,7 @@ stilllava=11
|
||||
slava=11
|
||||
stationarylava=11
|
||||
sand=12
|
||||
redsand=12:1
|
||||
gravel=13
|
||||
goldore=14
|
||||
ironore=15
|
||||
@ -64,6 +78,7 @@ spruceleaves=18:1
|
||||
birchleaves=18:2
|
||||
jungleleaves=18:3
|
||||
sponge=19
|
||||
wetsponge=19:1
|
||||
glass=20
|
||||
lapisore=21
|
||||
lapisblock=22
|
||||
@ -169,6 +184,7 @@ torch=50
|
||||
fire=51
|
||||
mobspawner=52
|
||||
woodstairs=53
|
||||
oakwoodstairs=53
|
||||
chest=54
|
||||
redstonedust=55
|
||||
redstonewire=55
|
||||
@ -274,13 +290,47 @@ redstonelamp=123
|
||||
redstonelampoff=123
|
||||
redstonelampon=124
|
||||
woodendoubleslab=125
|
||||
appledoublewoodslab=125:0
|
||||
oakwooddoubleslab=125:0
|
||||
coniferwooddoubleslab=125:1
|
||||
pinewooddoubleslab=125:1
|
||||
sprucewooddoubleslab=125:1
|
||||
darkwooddoubleslab=125:1
|
||||
birchwooddoubleslab=125:2
|
||||
whitewooddoubleslab=125:2
|
||||
junglewooddoubleslab=125:3
|
||||
acaciawooddoubleslab=125:4
|
||||
bigoakwooddoubleslab=125:5
|
||||
darkoakwooddoubleslab=125:5
|
||||
roofedwooddoubleslab=125:5
|
||||
woodenslab=126
|
||||
applewoodslab=126:0
|
||||
oakwoodslab=126:0
|
||||
coniferwoodslab=126:1
|
||||
pinewoodslab=126:1
|
||||
sprucewoodslab=126:1
|
||||
darkwoodslab=126:1
|
||||
birchwoodslab=126:2
|
||||
whitewoodslab=126:2
|
||||
junglewoodslab=126:3
|
||||
acaciawoodslab=126:4
|
||||
bigoakwoodslab=126:5
|
||||
darkoakwoodslab=126:5
|
||||
roofedwoodslab=126:5
|
||||
cocoabeans=127
|
||||
sandstonestairs=128
|
||||
emeraldore=129
|
||||
enderchest=130
|
||||
tripwirehook=131
|
||||
tripwire=132
|
||||
emeraldblock=133
|
||||
coniferwoodstairs=134
|
||||
pinewoodstairs=134
|
||||
sprucewoodstairs=134
|
||||
darkwoodstairs=134
|
||||
birchwoodstairs=135
|
||||
whitewoodstairs=135
|
||||
junglewoodstairs=136
|
||||
commandblock=137
|
||||
beacon=138
|
||||
cobblestonewall=139
|
||||
@ -343,12 +393,54 @@ brownstainedglasspane=160:12
|
||||
greenstainedglasspane=160:13
|
||||
redstainedglasspane=160:14
|
||||
blackstainedglasspane=160:15
|
||||
acaciawood=162
|
||||
darkoakwood=162:1
|
||||
acaciawoodenstairs=163
|
||||
darkoakwoodenstairs=164
|
||||
acacialeaves=161
|
||||
bigoakleaves=161:1
|
||||
darkoakleaves=161:1
|
||||
roofedoakleaves=161:1
|
||||
acacialog=162
|
||||
bigoaklog=162:1
|
||||
darkoaklog=162:1
|
||||
roofedoaklog=162:1
|
||||
acaciawoodstairs=163
|
||||
bigoakwoodstiars=164
|
||||
darkoakwoodstairs=164
|
||||
roofedoakwoodstairs=164
|
||||
slimeblock=165
|
||||
irontrapdoor=167
|
||||
prismarine=168
|
||||
prismarinebricks=168:1
|
||||
darkprismarine=168:2
|
||||
sealantern=169
|
||||
haybale=170
|
||||
carpet=171
|
||||
hardenedclay=172
|
||||
redsandstone=179
|
||||
chiseledredsandstone=179:1
|
||||
smoothredsandstone=179:2
|
||||
redsandstonestairs=180
|
||||
redsandstoneslab=182
|
||||
coniferfencegate=183
|
||||
pinefencegate=183
|
||||
sprucefencegate=183
|
||||
darkfencegate=183
|
||||
birchfencegate=184
|
||||
whitefencegate=184
|
||||
junglefencegate=185
|
||||
darkoakfencegate=186
|
||||
bigoakfencegate=186
|
||||
roofedoakfencegate=186
|
||||
acaciafencegate=187
|
||||
coniferfence=188
|
||||
pinefence=188
|
||||
sprucefence=188
|
||||
darkfence=188
|
||||
birchfence=189
|
||||
whitefence=189
|
||||
junglefence=190
|
||||
darkoakfence=191
|
||||
bigoakfence=191
|
||||
roofedoakfence=191
|
||||
acaciafence=192
|
||||
ironshovel=256
|
||||
ironspade=256
|
||||
ironpickaxe=257
|
||||
@ -596,13 +688,52 @@ netherbrickitem=405
|
||||
netherquartz=406
|
||||
tntminecart=407
|
||||
hopperminecart=408
|
||||
prismarineshard=409
|
||||
prismarinecrystals=410
|
||||
rawrabbit=411
|
||||
cookedrabbit=412
|
||||
rabbitstew=413
|
||||
rabbitsoup=413
|
||||
rabbitsfood=414
|
||||
rabbithide=415
|
||||
armorstand=416
|
||||
ironhorsearmor=417
|
||||
goldhorsearmor=418
|
||||
diamondhorsearmor=419
|
||||
lead=420
|
||||
nametag=421
|
||||
commandblockminecart=422
|
||||
|
||||
rawmutton=423
|
||||
cookedmutton=424
|
||||
banner=425
|
||||
blackbanner=415:0
|
||||
redbanner=415:1
|
||||
greenbanner=415:2
|
||||
brownbanner=415:3
|
||||
bluebanner=415:4
|
||||
purplebanner=415:5
|
||||
cyanbanner=415:6
|
||||
silverbanner=415:7
|
||||
lightgraybanner=415:7
|
||||
graybanner=415:8
|
||||
pinkbanner=415:9
|
||||
limebanner=415:10
|
||||
yellowbanner=415:11
|
||||
lightbluebanner=415:12
|
||||
magentabanner=415:13
|
||||
orangebanner=415:14
|
||||
whitebanner=415:15
|
||||
coniferdoor=427
|
||||
pinedoor=427
|
||||
sprucedoor=427
|
||||
darkdoor=427
|
||||
birchdoor=428
|
||||
whitedoor=428
|
||||
jungledoor=429
|
||||
acaciadoor=430
|
||||
bigoakdoor=431
|
||||
darkoakdoor=431
|
||||
roofedoakdoor=431
|
||||
goldrecord=2256
|
||||
greenrecord=2257
|
||||
blocksrecord=2258
|
||||
|
@ -2663,7 +2663,7 @@ static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S)
|
||||
|
||||
// Get the recipe for the input
|
||||
cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe();
|
||||
const cFurnaceRecipe::Recipe * Recipe = FR->GetRecipeFrom(*Input);
|
||||
const cFurnaceRecipe::cRecipe * Recipe = FR->GetRecipeFrom(*Input);
|
||||
if (Recipe == NULL)
|
||||
{
|
||||
// There is no such furnace recipe for this input, return no value
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "../Root.h"
|
||||
#include "../Server.h" // ExecuteConsoleCommand()
|
||||
#include "../Chunk.h"
|
||||
#include "../ChatColor.h"
|
||||
|
||||
|
||||
|
||||
@ -187,12 +188,11 @@ void cCommandBlockEntity::SaveToJson(Json::Value & a_Value)
|
||||
|
||||
void cCommandBlockEntity::Execute()
|
||||
{
|
||||
if (m_World != NULL)
|
||||
ASSERT(m_World != NULL); // Execute should not be called before the command block is attached to a world
|
||||
|
||||
if (!m_World->AreCommandBlocksEnabled())
|
||||
{
|
||||
if (!m_World->AreCommandBlocksEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
class CommandBlockOutCb :
|
||||
@ -206,15 +206,28 @@ void cCommandBlockEntity::Execute()
|
||||
virtual void Out(const AString & a_Text)
|
||||
{
|
||||
// Overwrite field
|
||||
m_CmdBlock->SetLastOutput(a_Text);
|
||||
m_CmdBlock->SetLastOutput(cClientHandle::FormatChatPrefix(m_CmdBlock->GetWorld()->ShouldUseChatPrefixes(), "SUCCESS", cChatColor::Green, cChatColor::White) + a_Text);
|
||||
}
|
||||
} CmdBlockOutCb(this);
|
||||
|
||||
LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str());
|
||||
|
||||
cServer * Server = cRoot::Get()->GetServer();
|
||||
|
||||
Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb);
|
||||
// Administrator commands are not executable by command blocks:
|
||||
if (
|
||||
(m_Command != "stop") &&
|
||||
(m_Command != "restart") &&
|
||||
(m_Command != "kick") &&
|
||||
(m_Command != "ban") &&
|
||||
(m_Command != "ipban")
|
||||
)
|
||||
{
|
||||
cServer * Server = cRoot::Get()->GetServer();
|
||||
LOGD("cCommandBlockEntity: Executing command %s", m_Command.c_str());
|
||||
Server->ExecuteConsoleCommand(m_Command, CmdBlockOutCb);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastOutput(cClientHandle::FormatChatPrefix(GetWorld()->ShouldUseChatPrefixes(), "FAILURE", cChatColor::Rose, cChatColor::White) + "Adminstration commands can not be executed");
|
||||
LOGD("cCommandBlockEntity: Prevented execution of administration command %s", m_Command.c_str());
|
||||
}
|
||||
|
||||
// TODO 2014-01-18 xdot: Update the signal strength.
|
||||
m_Result = 0;
|
||||
|
@ -105,7 +105,7 @@ protected:
|
||||
NIBBLETYPE m_BlockMeta;
|
||||
|
||||
/// The recipe for the current input slot
|
||||
const cFurnaceRecipe::Recipe * m_CurrentRecipe;
|
||||
const cFurnaceRecipe::cRecipe * m_CurrentRecipe;
|
||||
|
||||
/// The item that is being smelted
|
||||
cItem m_LastInput;
|
||||
|
@ -431,10 +431,45 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
|
||||
else
|
||||
{
|
||||
// TODO: Add a proper overridable function for this
|
||||
Pickups.Add(m_BlockType, 1, Meta);
|
||||
if (a_Digger != NULL)
|
||||
{
|
||||
cEnchantments Enchantments = a_Digger->GetEquippedWeapon().m_Enchantments;
|
||||
if ((Enchantments.GetLevel(cEnchantments::enchSilkTouch) > 0) && a_Digger->IsPlayer())
|
||||
{
|
||||
switch (m_BlockType)
|
||||
{
|
||||
case E_BLOCK_CAKE:
|
||||
case E_BLOCK_CARROTS:
|
||||
case E_BLOCK_COCOA_POD:
|
||||
case E_BLOCK_DOUBLE_STONE_SLAB:
|
||||
case E_BLOCK_DOUBLE_WOODEN_SLAB:
|
||||
case E_BLOCK_FIRE:
|
||||
case E_BLOCK_FARMLAND:
|
||||
case E_BLOCK_MELON_STEM:
|
||||
case E_BLOCK_MOB_SPAWNER:
|
||||
case E_BLOCK_NETHER_WART:
|
||||
case E_BLOCK_POTATOES:
|
||||
case E_BLOCK_PUMPKIN_STEM:
|
||||
case E_BLOCK_SNOW:
|
||||
case E_BLOCK_SUGARCANE:
|
||||
case E_BLOCK_TALL_GRASS:
|
||||
case E_BLOCK_CROPS:
|
||||
{
|
||||
// Silktouch can't be used for this blocks
|
||||
ConvertToPickups(Pickups, Meta);
|
||||
break;
|
||||
};
|
||||
default: Pickups.Add(m_BlockType, 1, Meta);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Pickups.Add(m_BlockType, 1, Meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Allow plugins to modify the pickups:
|
||||
a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Pickups);
|
||||
|
||||
|
@ -30,18 +30,18 @@ public:
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
|
||||
if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow) && !IsBlockLiquid(BlockBelow))
|
||||
|
||||
cEnchantments Enchantments = a_Player->GetInventory().GetEquippedItem().m_Enchantments;
|
||||
if (Enchantments.GetLevel(cEnchantments::enchSilkTouch) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
|
||||
if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow) && !IsBlockLiquid(BlockBelow))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WATER, 0);
|
||||
// This is called later than the real destroying of this ice block
|
||||
a_ChunkInterface.FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_WATER, 0);
|
||||
// This is called later than the real destroying of this ice block
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -152,7 +152,7 @@ bool HasNearLog(cBlockArea & a_Area, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
a_Area.SetBlockType(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SPONGE);
|
||||
for (int i = 0; i < LEAVES_CHECK_DISTANCE; i++)
|
||||
{
|
||||
for (int y = a_BlockY - i; y <= a_BlockY + i; y++)
|
||||
for (int y = std::max(a_BlockY - i, 0); y <= std::min(a_BlockY + i, 255); y++)
|
||||
{
|
||||
for (int z = a_BlockZ - i; z <= a_BlockZ + i; z++)
|
||||
{
|
||||
|
@ -256,6 +256,11 @@ set(EXECUTABLE MCServer)
|
||||
if (MSVC)
|
||||
get_directory_property(BINDING_OUTPUTS DIRECTORY "Bindings" DEFINITION BINDING_OUTPUTS)
|
||||
get_directory_property(BINDING_DEPENDENCIES DIRECTORY "Bindings" DEFINITION BINDING_DEPENDENCIES)
|
||||
|
||||
# The paths in BINDING_DEPENDENCIES are relative to the Bindings folder, convert them relative to this folder:
|
||||
foreach (dep ${BINDING_DEPENDENCIES})
|
||||
list (APPEND BINDINGS_DEPENDENCIES "Bindings/${dep}")
|
||||
endforeach(dep)
|
||||
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${BINDING_OUTPUTS}
|
||||
@ -268,7 +273,7 @@ if (MSVC)
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/
|
||||
|
||||
# add any new generation dependencies here
|
||||
DEPENDS ${BINDING_DEPENDENCIES}
|
||||
DEPENDS ${BINDINGS_DEPENDENCIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
@ -197,32 +197,32 @@ public:
|
||||
|
||||
inline static int GetHeight(const HeightMap & a_HeightMap, int a_X, int a_Z)
|
||||
{
|
||||
ASSERT((a_X >= 0) && (a_X <= Width));
|
||||
ASSERT((a_Z >= 0) && (a_Z <= Width));
|
||||
ASSERT((a_X >= 0) && (a_X < Width));
|
||||
ASSERT((a_Z >= 0) && (a_Z < Width));
|
||||
return a_HeightMap[a_X + Width * a_Z];
|
||||
}
|
||||
|
||||
|
||||
inline static void SetHeight(HeightMap & a_HeightMap, int a_X, int a_Z, unsigned char a_Height)
|
||||
{
|
||||
ASSERT((a_X >= 0) && (a_X <= Width));
|
||||
ASSERT((a_Z >= 0) && (a_Z <= Width));
|
||||
ASSERT((a_X >= 0) && (a_X < Width));
|
||||
ASSERT((a_Z >= 0) && (a_Z < Width));
|
||||
a_HeightMap[a_X + Width * a_Z] = a_Height;
|
||||
}
|
||||
|
||||
|
||||
inline static EMCSBiome GetBiome(const BiomeMap & a_BiomeMap, int a_X, int a_Z)
|
||||
{
|
||||
ASSERT((a_X >= 0) && (a_X <= Width));
|
||||
ASSERT((a_Z >= 0) && (a_Z <= Width));
|
||||
ASSERT((a_X >= 0) && (a_X < Width));
|
||||
ASSERT((a_Z >= 0) && (a_Z < Width));
|
||||
return a_BiomeMap[a_X + Width * a_Z];
|
||||
}
|
||||
|
||||
|
||||
inline static void SetBiome(BiomeMap & a_BiomeMap, int a_X, int a_Z, EMCSBiome a_Biome)
|
||||
{
|
||||
ASSERT((a_X >= 0) && (a_X <= Width));
|
||||
ASSERT((a_Z >= 0) && (a_Z <= Width));
|
||||
ASSERT((a_X >= 0) && (a_X < Width));
|
||||
ASSERT((a_Z >= 0) && (a_Z < Width));
|
||||
a_BiomeMap[a_X + Width * a_Z] = a_Biome;
|
||||
}
|
||||
|
||||
|
@ -1880,21 +1880,19 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||
}
|
||||
else if ((m_World->GetTNTShrapnelLevel() > slNone) && (m_World->GetTickRandomNumber(100) < 20)) // 20% chance of flinging stuff around
|
||||
{
|
||||
if (!cBlockInfo::FullyOccupiesVoxel(Block))
|
||||
// If the block is shrapnel-able, make a falling block entity out of it:
|
||||
if (
|
||||
((m_World->GetTNTShrapnelLevel() == slAll) && cBlockInfo::FullyOccupiesVoxel(Block)) ||
|
||||
((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block == E_BLOCK_SAND) || (Block == E_BLOCK_GRAVEL)))
|
||||
)
|
||||
{
|
||||
break;
|
||||
m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z));
|
||||
}
|
||||
else if ((m_World->GetTNTShrapnelLevel() == slGravityAffectedOnly) && ((Block != E_BLOCK_SAND) && (Block != E_BLOCK_GRAVEL)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_World->SpawnFallingBlock(bx + x, by + y + 5, bz + z, Block, area.GetBlockMeta(bx + x, by + y, bz + z));
|
||||
}
|
||||
|
||||
area.SetBlockTypeMeta(bx + x, by + y, bz + z, E_BLOCK_AIR, 0);
|
||||
a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z));
|
||||
break;
|
||||
|
||||
}
|
||||
} // switch (BlockType)
|
||||
} // for z
|
||||
@ -1916,51 +1914,31 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
|
||||
|
||||
virtual bool Item(cEntity * a_Entity) override
|
||||
{
|
||||
if (a_Entity->IsPickup())
|
||||
if (a_Entity->IsPickup() && (a_Entity->GetTicksAlive() < 20))
|
||||
{
|
||||
if (((cPickup *)a_Entity)->GetAge() < 20) // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned)
|
||||
// If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned)
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3d DistanceFromExplosion = a_Entity->GetPosition() - m_ExplosionPos;
|
||||
|
||||
if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible
|
||||
{
|
||||
cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
|
||||
|
||||
if (!m_bbTNT.IsInside(bbEntity)) // If bbEntity is inside bbTNT, not vice versa!
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3d EntityPos = a_Entity->GetPosition();
|
||||
cBoundingBox bbEntity(EntityPos, a_Entity->GetWidth() / 2, a_Entity->GetHeight());
|
||||
|
||||
if (!m_bbTNT.IsInside(bbEntity)) // IsInside actually acts like DoesSurround
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3d AbsoluteEntityPos(abs(EntityPos.x), abs(EntityPos.y), abs(EntityPos.z));
|
||||
|
||||
// Work out how far we are from the edge of the TNT's explosive effect
|
||||
AbsoluteEntityPos -= m_ExplosionPos;
|
||||
|
||||
// All to positive
|
||||
AbsoluteEntityPos.x = abs(AbsoluteEntityPos.x);
|
||||
AbsoluteEntityPos.y = abs(AbsoluteEntityPos.y);
|
||||
AbsoluteEntityPos.z = abs(AbsoluteEntityPos.z);
|
||||
|
||||
double FinalDamage = (((1 / AbsoluteEntityPos.x) + (1 / AbsoluteEntityPos.y) + (1 / AbsoluteEntityPos.z)) * 2) * m_ExplosionSize;
|
||||
|
||||
// Clip damage values
|
||||
FinalDamage = Clamp(FinalDamage, 0.0, (double)a_Entity->GetMaxHealth());
|
||||
|
||||
if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible
|
||||
{
|
||||
a_Entity->TakeDamage(dtExplosion, NULL, (int)FinalDamage, 0);
|
||||
// Ensure that the damage dealt is inversely proportional to the distance to the TNT centre - the closer a player is, the harder they are hit
|
||||
a_Entity->TakeDamage(dtExplosion, NULL, (int)((1 / DistanceFromExplosion.Length()) * 6 * m_ExplosionSize), 0);
|
||||
}
|
||||
|
||||
// Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt()
|
||||
Vector3d distance_explosion = a_Entity->GetPosition() - m_ExplosionPos;
|
||||
if (distance_explosion.SqrLength() < 4096.0)
|
||||
{
|
||||
distance_explosion.Normalize();
|
||||
distance_explosion *= m_ExplosionSize * m_ExplosionSize;
|
||||
|
||||
a_Entity->AddSpeed(distance_explosion);
|
||||
}
|
||||
DistanceFromExplosion.Normalize();
|
||||
DistanceFromExplosion *= m_ExplosionSize * m_ExplosionSize;
|
||||
a_Entity->AddSpeed(DistanceFromExplosion);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ void cCraftingRecipes::ClearRecipes(void)
|
||||
void cCraftingRecipes::AddRecipeLine(int a_LineNum, const AString & a_RecipeLine)
|
||||
{
|
||||
AString RecipeLine(a_RecipeLine);
|
||||
RecipeLine.erase(std::remove(RecipeLine.begin(), RecipeLine.end(), ' '), RecipeLine.end());
|
||||
RecipeLine.erase(std::remove_if(RecipeLine.begin(), RecipeLine.end(), isspace), RecipeLine.end());
|
||||
|
||||
AStringVector Sides = StringSplit(RecipeLine, "=");
|
||||
if (Sides.size() != 2)
|
||||
|
@ -90,6 +90,13 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa
|
||||
|
||||
// Broadcast arrow hit sound
|
||||
m_World->BroadcastSoundEffect("random.bowhit", (double)X, (double)Y, (double)Z, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
|
||||
if ((m_World->GetBlock(Hit) == E_BLOCK_TNT) && IsOnFire())
|
||||
{
|
||||
m_World->SetBlock(X, Y, Z, E_BLOCK_AIR, 0);
|
||||
m_World->SpawnPrimedTNT(X, Y, Z);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -103,8 +110,36 @@ void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||
{
|
||||
Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
|
||||
}
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
|
||||
|
||||
int PowerLevel = m_CreatorData.m_Enchantments.GetLevel(cEnchantments::enchPower);
|
||||
if (PowerLevel > 0)
|
||||
{
|
||||
int ExtraDamage = (int)ceil(0.25 * (PowerLevel + 1));
|
||||
Damage += ExtraDamage;
|
||||
}
|
||||
|
||||
int KnockbackAmount = 1;
|
||||
int PunchLevel = m_CreatorData.m_Enchantments.GetLevel(cEnchantments::enchPunch);
|
||||
if (PunchLevel > 0)
|
||||
{
|
||||
Vector3d LookVector = GetLookVector();
|
||||
Vector3f FinalSpeed = Vector3f(0, 0, 0);
|
||||
switch (PunchLevel)
|
||||
{
|
||||
case 1: FinalSpeed = LookVector * Vector3d(5, 0.3, 5); break;
|
||||
case 2: FinalSpeed = LookVector * Vector3d(8, 0.3, 8); break;
|
||||
default: break;
|
||||
}
|
||||
a_EntityHit.SetSpeed(FinalSpeed);
|
||||
}
|
||||
|
||||
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, KnockbackAmount);
|
||||
|
||||
if (IsOnFire() && !a_EntityHit.IsSubmerged() && !a_EntityHit.IsSwimming())
|
||||
{
|
||||
a_EntityHit.StartBurning(100);
|
||||
}
|
||||
|
||||
// Broadcast successful hit sound
|
||||
GetWorld()->BroadcastSoundEffect("random.successful_hit", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
|
||||
|
||||
|
||||
// tolua_begin
|
||||
|
||||
class cArrowEntity :
|
||||
@ -46,7 +47,7 @@ public:
|
||||
|
||||
/// Returns the damage modifier coeff.
|
||||
double GetDamageCoeff(void) const { return m_DamageCoeff; }
|
||||
|
||||
|
||||
/// Sets the damage modifier coeff
|
||||
void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
|
||||
|
||||
@ -89,7 +90,7 @@ protected:
|
||||
|
||||
/// If true, the arrow is in the process of being collected - don't go to anyone else
|
||||
bool m_bIsCollected;
|
||||
|
||||
|
||||
/// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
|
||||
Vector3i m_HitBlockPos;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "../Tracer.h"
|
||||
#include "Player.h"
|
||||
#include "Items/ItemHandler.h"
|
||||
#include "../FastRandom.h"
|
||||
|
||||
|
||||
|
||||
@ -316,8 +317,107 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
|
||||
// IsOnGround() only is false if the player is moving downwards
|
||||
// TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
|
||||
if (!Player->IsOnGround())
|
||||
const cEnchantments & Enchantments = Player->GetEquippedItem().m_Enchantments;
|
||||
|
||||
int SharpnessLevel = Enchantments.GetLevel(cEnchantments::enchSharpness);
|
||||
int SmiteLevel = Enchantments.GetLevel(cEnchantments::enchSmite);
|
||||
int BaneOfArthropodsLevel = Enchantments.GetLevel(cEnchantments::enchBaneOfArthropods);
|
||||
|
||||
if (SharpnessLevel > 0)
|
||||
{
|
||||
a_TDI.FinalDamage += (int)ceil(1.25 * SharpnessLevel);
|
||||
}
|
||||
else if (SmiteLevel > 0)
|
||||
{
|
||||
if (IsMob())
|
||||
{
|
||||
cMonster * Monster = (cMonster *)this;
|
||||
switch (Monster->GetMobType())
|
||||
{
|
||||
case cMonster::mtSkeleton:
|
||||
case cMonster::mtZombie:
|
||||
case cMonster::mtWither:
|
||||
case cMonster::mtZombiePigman:
|
||||
{
|
||||
a_TDI.FinalDamage += (int)ceil(2.5 * SmiteLevel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (BaneOfArthropodsLevel > 0)
|
||||
{
|
||||
if (IsMob())
|
||||
{
|
||||
cMonster * Monster = (cMonster *)this;
|
||||
switch (Monster->GetMobType())
|
||||
{
|
||||
case cMonster::mtSpider:
|
||||
case cMonster::mtCaveSpider:
|
||||
case cMonster::mtSilverfish:
|
||||
{
|
||||
a_TDI.RawDamage += (int)ceil(2.5 * BaneOfArthropodsLevel);
|
||||
// TODO: Add slowness effect
|
||||
|
||||
break;
|
||||
};
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int FireAspectLevel = Enchantments.GetLevel(cEnchantments::enchFireAspect);
|
||||
if (FireAspectLevel > 0)
|
||||
{
|
||||
int BurnTicks = 3;
|
||||
|
||||
if (FireAspectLevel > 1)
|
||||
{
|
||||
BurnTicks += 4 * (FireAspectLevel - 1);
|
||||
}
|
||||
if (!IsMob() && !IsSubmerged() && !IsSwimming())
|
||||
{
|
||||
StartBurning(BurnTicks * 20);
|
||||
}
|
||||
else if (IsMob() && !IsSubmerged() && !IsSwimming())
|
||||
{
|
||||
cMonster * Monster = (cMonster *)this;
|
||||
switch (Monster->GetMobType())
|
||||
{
|
||||
case cMonster::mtGhast:
|
||||
case cMonster::mtZombiePigman:
|
||||
case cMonster::mtMagmaCube:
|
||||
{
|
||||
break;
|
||||
};
|
||||
default: StartBurning(BurnTicks * 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ThornsLevel = 0;
|
||||
const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() };
|
||||
for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++)
|
||||
{
|
||||
const cItem & Item = ArmorItems[i];
|
||||
ThornsLevel = std::max(ThornsLevel, Item.m_Enchantments.GetLevel(cEnchantments::enchThorns));
|
||||
}
|
||||
|
||||
if (ThornsLevel > 0)
|
||||
{
|
||||
int Chance = ThornsLevel * 15;
|
||||
|
||||
cFastRandom Random;
|
||||
int RandomValue = Random.GenerateRandomInteger(0, 100);
|
||||
|
||||
if (RandomValue <= Chance)
|
||||
{
|
||||
a_TDI.Attacker->TakeDamage(dtAttack, this, 0, Random.GenerateRandomInteger(1, 4), 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Player->IsOnGround())
|
||||
{
|
||||
if ((a_TDI.DamageType == dtAttack) || (a_TDI.DamageType == dtArrowAttack))
|
||||
{
|
||||
a_TDI.FinalDamage += 2;
|
||||
@ -328,13 +428,123 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5));
|
||||
}
|
||||
|
||||
if (IsPlayer())
|
||||
{
|
||||
double TotalEPF = 0.0;
|
||||
double EPFProtection = 0.00;
|
||||
double EPFFireProtection = 0.00;
|
||||
double EPFBlastProtection = 0.00;
|
||||
double EPFProjectileProtection = 0.00;
|
||||
double EPFFeatherFalling = 0.00;
|
||||
|
||||
const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() };
|
||||
for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++)
|
||||
{
|
||||
const cItem & Item = ArmorItems[i];
|
||||
int Level = Item.m_Enchantments.GetLevel(cEnchantments::enchProtection);
|
||||
if (Level > 0)
|
||||
{
|
||||
EPFProtection += (6 + Level * Level) * 0.75 / 3;
|
||||
}
|
||||
|
||||
Level = Item.m_Enchantments.GetLevel(cEnchantments::enchFireProtection);
|
||||
if (Level > 0)
|
||||
{
|
||||
EPFFireProtection += (6 + Level * Level) * 1.25 / 3;
|
||||
}
|
||||
|
||||
Level = Item.m_Enchantments.GetLevel(cEnchantments::enchFeatherFalling);
|
||||
if (Level > 0)
|
||||
{
|
||||
EPFFeatherFalling += (6 + Level * Level) * 2.5 / 3;
|
||||
}
|
||||
|
||||
Level = Item.m_Enchantments.GetLevel(cEnchantments::enchBlastProtection);
|
||||
if (Level > 0)
|
||||
{
|
||||
EPFBlastProtection += (6 + Level * Level) * 1.5 / 3;
|
||||
}
|
||||
|
||||
Level = Item.m_Enchantments.GetLevel(cEnchantments::enchProjectileProtection);
|
||||
if (Level > 0)
|
||||
{
|
||||
EPFProjectileProtection += (6 + Level * Level) * 1.5 / 3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TotalEPF = EPFProtection + EPFFireProtection + EPFFeatherFalling + EPFBlastProtection + EPFProjectileProtection;
|
||||
|
||||
EPFProtection = EPFProtection / TotalEPF;
|
||||
EPFFireProtection = EPFFireProtection / TotalEPF;
|
||||
EPFFeatherFalling = EPFFeatherFalling / TotalEPF;
|
||||
EPFBlastProtection = EPFBlastProtection / TotalEPF;
|
||||
EPFProjectileProtection = EPFProjectileProtection / TotalEPF;
|
||||
|
||||
if (TotalEPF > 25)
|
||||
{
|
||||
TotalEPF = 25;
|
||||
}
|
||||
|
||||
cFastRandom Random;
|
||||
float RandomValue = Random.GenerateRandomInteger(50, 100) * 0.01f;
|
||||
|
||||
TotalEPF = ceil(TotalEPF * RandomValue);
|
||||
|
||||
if (TotalEPF > 20)
|
||||
{
|
||||
TotalEPF = 20;
|
||||
}
|
||||
|
||||
EPFProtection = TotalEPF * EPFProtection;
|
||||
EPFFireProtection = TotalEPF * EPFFireProtection;
|
||||
EPFFeatherFalling = TotalEPF * EPFFeatherFalling;
|
||||
EPFBlastProtection = TotalEPF * EPFBlastProtection;
|
||||
EPFProjectileProtection = TotalEPF * EPFProjectileProtection;
|
||||
|
||||
int RemovedDamage = 0;
|
||||
|
||||
if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtAdmin))
|
||||
{
|
||||
RemovedDamage += (int)ceil(EPFProtection * 0.04 * a_TDI.FinalDamage);
|
||||
}
|
||||
|
||||
if ((a_TDI.DamageType == dtFalling) || (a_TDI.DamageType == dtFall) || (a_TDI.DamageType == dtEnderPearl))
|
||||
{
|
||||
RemovedDamage += (int)ceil(EPFFeatherFalling * 0.04 * a_TDI.FinalDamage);
|
||||
}
|
||||
|
||||
if (a_TDI.DamageType == dtBurning)
|
||||
{
|
||||
RemovedDamage += (int)ceil(EPFFireProtection * 0.04 * a_TDI.FinalDamage);
|
||||
}
|
||||
|
||||
if (a_TDI.DamageType == dtExplosion)
|
||||
{
|
||||
RemovedDamage += (int)ceil(EPFBlastProtection * 0.04 * a_TDI.FinalDamage);
|
||||
}
|
||||
|
||||
if (a_TDI.DamageType == dtProjectile)
|
||||
{
|
||||
RemovedDamage += (int)ceil(EPFBlastProtection * 0.04 * a_TDI.FinalDamage);
|
||||
}
|
||||
|
||||
if (a_TDI.FinalDamage < RemovedDamage)
|
||||
{
|
||||
RemovedDamage = 0;
|
||||
}
|
||||
|
||||
a_TDI.FinalDamage -= RemovedDamage;
|
||||
}
|
||||
|
||||
m_Health -= (short)a_TDI.FinalDamage;
|
||||
|
||||
// TODO: Apply damage to armor
|
||||
|
||||
m_Health = std::max(m_Health, 0);
|
||||
|
||||
if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL)) // Knockback for only players and mobs
|
||||
// Add knockback:
|
||||
if ((IsMob() || IsPlayer()) && (a_TDI.Attacker != NULL))
|
||||
{
|
||||
int KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); // More common enchantment
|
||||
if (KnockbackLevel < 1)
|
||||
@ -1252,6 +1462,8 @@ void cEntity::HandleAir(void)
|
||||
// See if the entity is /submerged/ water (block above is water)
|
||||
// Get the type of block the entity is standing in:
|
||||
|
||||
int RespirationLevel = GetEquippedHelmet().m_Enchantments.GetLevel(cEnchantments::enchRespiration);
|
||||
|
||||
if (IsSubmerged())
|
||||
{
|
||||
if (!IsPlayer()) // Players control themselves
|
||||
@ -1259,6 +1471,11 @@ void cEntity::HandleAir(void)
|
||||
SetSpeedY(1); // Float in the water
|
||||
}
|
||||
|
||||
if (RespirationLevel > 0)
|
||||
{
|
||||
((cPawn *)this)->AddEntityEffect(cEntityEffect::effNightVision, 200, 5, 0);
|
||||
}
|
||||
|
||||
if (m_AirLevel <= 0)
|
||||
{
|
||||
// Runs the air tick timer to check whether the player should be damaged
|
||||
@ -1285,6 +1502,12 @@ void cEntity::HandleAir(void)
|
||||
// Set the air back to maximum
|
||||
m_AirLevel = MAX_AIR_LEVEL;
|
||||
m_AirTickTimer = DROWNING_TICKS;
|
||||
|
||||
if (RespirationLevel > 0)
|
||||
{
|
||||
m_AirTickTimer = DROWNING_TICKS + (RespirationLevel * 15 * 20);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,6 @@ void cItemFrame::KilledBy(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
if (m_Item.IsEmpty())
|
||||
{
|
||||
SetHealth(0);
|
||||
super::KilledBy(a_TDI);
|
||||
Destroy();
|
||||
return;
|
||||
|
@ -891,31 +891,31 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
|
||||
)
|
||||
{
|
||||
// Moving -X +Z
|
||||
if ((-GetSpeedX() * 0.4 / sqrt(2)) < 0.01)
|
||||
if ((-GetSpeedX() * 0.4 / sqrt(2.0)) < 0.01)
|
||||
{
|
||||
// ~ SpeedX >= 0 Immobile or not moving in the "right" direction. Give it a bump!
|
||||
AddSpeedX(-4 / sqrt(2));
|
||||
AddSpeedZ(4 / sqrt(2));
|
||||
AddSpeedX(-4 / sqrt(2.0));
|
||||
AddSpeedZ(4 / sqrt(2.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ~ SpeedX < 0 Moving in the "right" direction. Only accelerate it a bit.
|
||||
SetSpeedX(GetSpeedX() * 0.4 / sqrt(2));
|
||||
SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2));
|
||||
SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0));
|
||||
SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0));
|
||||
}
|
||||
}
|
||||
else if ((GetSpeedX() * 0.4 / sqrt(2)) < 0.01)
|
||||
else if ((GetSpeedX() * 0.4 / sqrt(2.0)) < 0.01)
|
||||
{
|
||||
// Moving +X -Z
|
||||
// ~ SpeedX <= 0 Immobile or not moving in the "right" direction
|
||||
AddSpeedX(4 / sqrt(2));
|
||||
AddSpeedZ(-4 / sqrt(2));
|
||||
AddSpeedX(4 / sqrt(2.0));
|
||||
AddSpeedZ(-4 / sqrt(2.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ~ SpeedX > 0 Moving in the "right" direction
|
||||
SetSpeedX(GetSpeedX() * 0.4 / sqrt(2));
|
||||
SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2));
|
||||
SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0));
|
||||
SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -943,28 +943,28 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
|
||||
if ((GetSpeedX() * 0.4) < 0.01)
|
||||
{
|
||||
// ~ SpeedX <= 0 Immobile or not moving in the "right" direction
|
||||
AddSpeedX(4 / sqrt(2));
|
||||
AddSpeedZ(4 / sqrt(2));
|
||||
AddSpeedX(4 / sqrt(2.0));
|
||||
AddSpeedZ(4 / sqrt(2.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ~ SpeedX > 0 Moving in the "right" direction
|
||||
SetSpeedX(GetSpeedX() * 0.4 / sqrt(2));
|
||||
SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2));
|
||||
SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0));
|
||||
SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0));
|
||||
}
|
||||
}
|
||||
else if ((-GetSpeedX() * 0.4) < 0.01)
|
||||
{
|
||||
// Moving -X -Z
|
||||
// ~ SpeedX >= 0 Immobile or not moving in the "right" direction
|
||||
AddSpeedX(-4 / sqrt(2));
|
||||
AddSpeedZ(-4 / sqrt(2));
|
||||
AddSpeedX(-4 / sqrt(2.0));
|
||||
AddSpeedZ(-4 / sqrt(2.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ~ SpeedX < 0 Moving in the "right" direction
|
||||
SetSpeedX(GetSpeedX() * 0.4 / sqrt(2));
|
||||
SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2));
|
||||
SetSpeedX(GetSpeedX() * 0.4 / sqrt(2.0));
|
||||
SetSpeedZ(GetSpeedZ() * 0.4 / sqrt(2.0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -150,10 +150,14 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsDestroyed() && (m_Item.m_ItemCount < m_Item.GetMaxStackSize())) // Don't combine into an already full pickup
|
||||
// Try to combine the pickup with adjacent same-item pickups:
|
||||
if (!IsDestroyed() && (m_Item.m_ItemCount < m_Item.GetMaxStackSize())) // Don't combine if already full
|
||||
{
|
||||
// By using a_Chunk's ForEachEntity() instead of cWorld's, pickups don't combine across chunk boundaries.
|
||||
// That is a small price to pay for not having to traverse the entire world for each entity.
|
||||
// The speedup in the tick thread is quite considerable.
|
||||
cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this);
|
||||
m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
|
||||
a_Chunk.ForEachEntity(PickupCombiningCallback);
|
||||
if (PickupCombiningCallback.FoundMatchingPickup())
|
||||
{
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "../Chunk.h"
|
||||
#include "../Items/ItemHandler.h"
|
||||
#include "../Vector3.h"
|
||||
#include "../FastRandom.h"
|
||||
|
||||
#include "../WorldStorage/StatSerializer.h"
|
||||
#include "../CompositeChat.h"
|
||||
@ -1793,6 +1794,28 @@ void cPlayer::UseEquippedItem(int a_Amount)
|
||||
return;
|
||||
}
|
||||
|
||||
// If the item has an unbreaking enchantment, give it a random chance of not breaking:
|
||||
cItem Item = GetEquippedItem();
|
||||
int UnbreakingLevel = Item.m_Enchantments.GetLevel(cEnchantments::enchUnbreaking);
|
||||
if (UnbreakingLevel > 0)
|
||||
{
|
||||
int chance;
|
||||
if (ItemCategory::IsArmor(Item.m_ItemType))
|
||||
{
|
||||
chance = 60 + (40 / (UnbreakingLevel + 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
chance = 100 / (UnbreakingLevel + 1);
|
||||
}
|
||||
|
||||
cFastRandom Random;
|
||||
if (Random.NextInt(101) <= chance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetInventory().DamageEquippedItem(a_Amount))
|
||||
{
|
||||
m_World->BroadcastSoundEffect("random.break", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||
|
@ -222,7 +222,8 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a
|
||||
m_ProjectileKind(a_Kind),
|
||||
m_CreatorData(
|
||||
((a_Creator != NULL) ? a_Creator->GetUniqueID() : -1),
|
||||
((a_Creator != NULL) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : "")
|
||||
((a_Creator != NULL) ? (a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "") : ""),
|
||||
((a_Creator != NULL) ? a_Creator->GetEquippedWeapon().m_Enchantments : cEnchantments())
|
||||
),
|
||||
m_IsInGround(false)
|
||||
{
|
||||
@ -235,7 +236,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a
|
||||
cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Vector3d & a_Pos, const Vector3d & a_Speed, double a_Width, double a_Height) :
|
||||
super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height),
|
||||
m_ProjectileKind(a_Kind),
|
||||
m_CreatorData(a_Creator->GetUniqueID(), a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : ""),
|
||||
m_CreatorData(a_Creator->GetUniqueID(), a_Creator->IsPlayer() ? ((cPlayer *)a_Creator)->GetName() : "", a_Creator->GetEquippedWeapon().m_Enchantments),
|
||||
m_IsInGround(false)
|
||||
{
|
||||
SetSpeed(a_Speed);
|
||||
|
@ -94,14 +94,16 @@ protected:
|
||||
*/
|
||||
struct CreatorData
|
||||
{
|
||||
CreatorData(int a_UniqueID, const AString & a_Name) :
|
||||
CreatorData(int a_UniqueID, const AString & a_Name, const cEnchantments & a_Enchantments) :
|
||||
m_UniqueID(a_UniqueID),
|
||||
m_Name(a_Name)
|
||||
m_Name(a_Name),
|
||||
m_Enchantments(a_Enchantments)
|
||||
{
|
||||
}
|
||||
|
||||
const int m_UniqueID;
|
||||
AString m_Name;
|
||||
cEnchantments m_Enchantments;
|
||||
};
|
||||
|
||||
/** The type of projectile I am */
|
||||
|
@ -12,8 +12,8 @@
|
||||
|
||||
|
||||
|
||||
typedef std::list< cFurnaceRecipe::Recipe > RecipeList;
|
||||
typedef std::list< cFurnaceRecipe::Fuel > FuelList;
|
||||
typedef std::list<cFurnaceRecipe::cRecipe> RecipeList;
|
||||
typedef std::list<cFurnaceRecipe::cFuel> FuelList;
|
||||
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ struct cFurnaceRecipe::sFurnaceRecipeState
|
||||
|
||||
|
||||
cFurnaceRecipe::cFurnaceRecipe()
|
||||
: m_pState( new sFurnaceRecipeState)
|
||||
: m_pState(new sFurnaceRecipeState)
|
||||
{
|
||||
ReloadRecipes();
|
||||
}
|
||||
@ -68,12 +68,18 @@ void cFurnaceRecipe::ReloadRecipes(void)
|
||||
while (std::getline(f, ParsingLine))
|
||||
{
|
||||
LineNum++;
|
||||
ParsingLine.erase(std::remove_if(ParsingLine.begin(), ParsingLine.end(), isspace), ParsingLine.end()); // Remove ALL whitespace from the line
|
||||
if (ParsingLine.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove comments from the line:
|
||||
size_t FirstCommentSymbol = ParsingLine.find('#');
|
||||
if ((FirstCommentSymbol != AString::npos) && (FirstCommentSymbol != 0))
|
||||
{
|
||||
ParsingLine.erase(ParsingLine.begin() + (const long)FirstCommentSymbol, ParsingLine.end());
|
||||
}
|
||||
|
||||
switch (ParsingLine[0])
|
||||
{
|
||||
case '#':
|
||||
@ -103,97 +109,131 @@ void cFurnaceRecipe::ReloadRecipes(void)
|
||||
|
||||
|
||||
|
||||
void cFurnaceRecipe::AddFuelFromLine(const AString & a_Line, int a_LineNum)
|
||||
void cFurnaceRecipe::AddFuelFromLine(const AString & a_Line, unsigned int a_LineNum)
|
||||
{
|
||||
// Fuel
|
||||
int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0;
|
||||
AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang)
|
||||
AString Line(a_Line);
|
||||
Line.erase(Line.begin()); // Remove the beginning "!"
|
||||
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
|
||||
|
||||
if (
|
||||
!ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID
|
||||
!ReadOptionalNumbers(BeginPos, ":", "=", a_Line, a_LineNum, IItemCount, IItemHealth) || // Read item count (and optionally health)
|
||||
!ReadMandatoryNumber(BeginPos, "0123456789", a_Line, a_LineNum, IBurnTime, true) // Read item burn time - last value
|
||||
)
|
||||
std::auto_ptr<cItem> Item(new cItem);
|
||||
int BurnTime;
|
||||
|
||||
const AStringVector & Sides = StringSplit(Line, "=");
|
||||
if (Sides.size() != 2)
|
||||
{
|
||||
LOGWARNING("furnace.txt: line %d: A single '=' was expected, got %d", a_LineNum, (int)Sides.size() - 1);
|
||||
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ParseItem(Sides[0], *Item))
|
||||
{
|
||||
LOGWARNING("furnace.txt: line %d: Cannot parse item \"%s\".", a_LineNum, Sides[0].c_str());
|
||||
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!StringToInteger<int>(Sides[1], BurnTime))
|
||||
{
|
||||
LOGWARNING("furnace.txt: line %d: Cannot parse burn time.", a_LineNum);
|
||||
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Add to fuel list:
|
||||
Fuel F;
|
||||
F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth);
|
||||
F.BurnTime = IBurnTime;
|
||||
m_pState->Fuel.push_back(F);
|
||||
cFuel Fuel;
|
||||
Fuel.In = Item.release();
|
||||
Fuel.BurnTime = BurnTime;
|
||||
m_pState->Fuel.push_back(Fuel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFurnaceRecipe::AddRecipeFromLine(const AString & a_Line, int a_LineNum)
|
||||
void cFurnaceRecipe::AddRecipeFromLine(const AString & a_Line, unsigned int a_LineNum)
|
||||
{
|
||||
int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0;
|
||||
int OItemID = 0, OItemCount = 0, OItemHealth = 0;
|
||||
AString::size_type BeginPos = 0; // Begin at start of line
|
||||
AString Line(a_Line);
|
||||
Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
|
||||
|
||||
if (
|
||||
!ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID
|
||||
!ReadOptionalNumbers(BeginPos, ":", "@", a_Line, a_LineNum, IItemCount, IItemHealth) || // Read item count (and optionally health)
|
||||
!ReadMandatoryNumber(BeginPos, "=", a_Line, a_LineNum, IBurnTime) || // Read item burn time
|
||||
!ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, OItemID) || // Read result ID
|
||||
!ReadOptionalNumbers(BeginPos, ":", "012456789", a_Line, a_LineNum, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value
|
||||
)
|
||||
int CookTime = 200;
|
||||
std::auto_ptr<cItem> InputItem(new cItem());
|
||||
std::auto_ptr<cItem> OutputItem(new cItem());
|
||||
|
||||
const AStringVector & Sides = StringSplit(Line, "=");
|
||||
if (Sides.size() != 2)
|
||||
{
|
||||
LOGWARNING("furnace.txt: line %d: A single '=' was expected, got %d", a_LineNum, (int)Sides.size() - 1);
|
||||
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Add to recipe list
|
||||
Recipe R;
|
||||
R.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth);
|
||||
R.Out = new cItem((ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth);
|
||||
R.CookTime = IBurnTime;
|
||||
m_pState->Recipes.push_back(R);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFurnaceRecipe::PrintParseError(unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing)
|
||||
{
|
||||
LOGWARN("Error parsing furnace recipes at line %i pos " SIZE_T_FMT ": missing '%s'", a_Line, a_Position, a_CharactersMissing.c_str());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, unsigned int a_Line, int & a_Value, bool a_IsLastValue)
|
||||
{
|
||||
// TODO: replace atoi with std::stoi
|
||||
AString::size_type End;
|
||||
if (a_IsLastValue)
|
||||
const AStringVector & InputSplit = StringSplit(Sides[0], "@");
|
||||
if (!ParseItem(InputSplit[0], *InputItem))
|
||||
{
|
||||
End = a_Text.find_first_not_of(a_Delimiter, a_Begin);
|
||||
LOGWARNING("furnace.txt: line %d: Cannot parse input item \"%s\".", a_LineNum, InputSplit[0].c_str());
|
||||
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if (InputSplit.size() > 1)
|
||||
{
|
||||
End = a_Text.find_first_of(a_Delimiter, a_Begin);
|
||||
if (End == AString::npos)
|
||||
if (!StringToInteger<int>(InputSplit[1], CookTime))
|
||||
{
|
||||
LOGWARNING("furnace.txt: line %d: Cannot parse cook time \"%s\".", a_LineNum, InputSplit[1].c_str());
|
||||
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ParseItem(Sides[1], *OutputItem))
|
||||
{
|
||||
LOGWARNING("furnace.txt: line %d: Cannot parse output item \"%s\".", a_LineNum, Sides[1].c_str());
|
||||
LOGINFO("Offending line: \"%s\"", a_Line.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
cRecipe Recipe;
|
||||
Recipe.In = InputItem.release();
|
||||
Recipe.Out = OutputItem.release();
|
||||
Recipe.CookTime = CookTime;
|
||||
m_pState->Recipes.push_back(Recipe);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cFurnaceRecipe::ParseItem(const AString & a_String, cItem & a_Item)
|
||||
{
|
||||
AString ItemString = a_String;
|
||||
|
||||
const AStringVector & SplitAmount = StringSplit(ItemString, ",");
|
||||
ItemString = SplitAmount[0];
|
||||
|
||||
const AStringVector & SplitMeta = StringSplit(ItemString, ":");
|
||||
ItemString = SplitMeta[0];
|
||||
|
||||
if (!StringToItem(ItemString, a_Item))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SplitAmount.size() > 1)
|
||||
{
|
||||
if (!StringToInteger<char>(SplitAmount[1].c_str(), a_Item.m_ItemCount))
|
||||
{
|
||||
PrintParseError(a_Line, a_Begin, a_Delimiter);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// stoi won't throw an exception if the string is alphanumeric, we should check for this
|
||||
if (!DoesStringContainOnlyNumbers(a_Text.substr(a_Begin, End - a_Begin)))
|
||||
{
|
||||
PrintParseError(a_Line, a_Begin, "number");
|
||||
return false;
|
||||
}
|
||||
a_Value = atoi(a_Text.substr(a_Begin, End - a_Begin).c_str());
|
||||
|
||||
a_Begin = End + 1; // Jump over delimiter
|
||||
if (SplitMeta.size() > 1)
|
||||
{
|
||||
if (!StringToInteger<short>(SplitMeta[1].c_str(), a_Item.m_ItemDamage))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -201,84 +241,23 @@ bool cFurnaceRecipe::ReadMandatoryNumber(AString::size_type & a_Begin, const ASt
|
||||
|
||||
|
||||
|
||||
bool cFurnaceRecipe::ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue)
|
||||
{
|
||||
// TODO: replace atoi with std::stoi
|
||||
AString::size_type End, Begin = a_Begin;
|
||||
|
||||
End = a_Text.find_first_of(a_DelimiterOne, Begin);
|
||||
if (End != AString::npos)
|
||||
{
|
||||
if (DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin)))
|
||||
{
|
||||
a_ValueOne = std::atoi(a_Text.substr(Begin, End - Begin).c_str());
|
||||
Begin = End + 1;
|
||||
|
||||
if (a_IsLastValue)
|
||||
{
|
||||
End = a_Text.find_first_not_of(a_DelimiterTwo, Begin);
|
||||
}
|
||||
else
|
||||
{
|
||||
End = a_Text.find_first_of(a_DelimiterTwo, Begin);
|
||||
if (End == AString::npos)
|
||||
{
|
||||
PrintParseError(a_Line, Begin, a_DelimiterTwo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// stoi won't throw an exception if the string is alphanumeric, we should check for this
|
||||
if (!DoesStringContainOnlyNumbers(a_Text.substr(Begin, End - Begin)))
|
||||
{
|
||||
PrintParseError(a_Line, Begin, "number");
|
||||
return false;
|
||||
}
|
||||
a_ValueTwo = atoi(a_Text.substr(Begin, End - Begin).c_str());
|
||||
|
||||
a_Begin = End + 1; // Jump over delimiter
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_Line, a_ValueOne, a_IsLastValue);
|
||||
}
|
||||
}
|
||||
|
||||
return ReadMandatoryNumber(a_Begin, a_DelimiterTwo, a_Text, a_Line, a_ValueOne, a_IsLastValue);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cFurnaceRecipe::DoesStringContainOnlyNumbers(const AString & a_String)
|
||||
{
|
||||
// TODO: replace this with std::all_of(a_String.begin(), a_String.end(), isdigit)
|
||||
return (a_String.find_first_not_of("0123456789") == AString::npos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFurnaceRecipe::ClearRecipes(void)
|
||||
{
|
||||
for (RecipeList::iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
|
||||
{
|
||||
Recipe R = *itr;
|
||||
delete R.In;
|
||||
R.In = NULL;
|
||||
delete R.Out;
|
||||
R.Out = NULL;
|
||||
cRecipe Recipe = *itr;
|
||||
delete Recipe.In;
|
||||
Recipe.In = NULL;
|
||||
delete Recipe.Out;
|
||||
Recipe.Out = NULL;
|
||||
}
|
||||
m_pState->Recipes.clear();
|
||||
|
||||
for (FuelList::iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
|
||||
{
|
||||
Fuel F = *itr;
|
||||
delete F.In;
|
||||
F.In = NULL;
|
||||
cFuel Fuel = *itr;
|
||||
delete Fuel.In;
|
||||
Fuel.In = NULL;
|
||||
}
|
||||
m_pState->Fuel.clear();
|
||||
}
|
||||
@ -287,21 +266,21 @@ void cFurnaceRecipe::ClearRecipes(void)
|
||||
|
||||
|
||||
|
||||
const cFurnaceRecipe::Recipe * cFurnaceRecipe::GetRecipeFrom(const cItem & a_Ingredient) const
|
||||
const cFurnaceRecipe::cRecipe * cFurnaceRecipe::GetRecipeFrom(const cItem & a_Ingredient) const
|
||||
{
|
||||
const Recipe * BestRecipe = 0;
|
||||
const cRecipe * BestRecipe = 0;
|
||||
for (RecipeList::const_iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
|
||||
{
|
||||
const Recipe & R = *itr;
|
||||
if ((R.In->m_ItemType == a_Ingredient.m_ItemType) && (R.In->m_ItemCount <= a_Ingredient.m_ItemCount))
|
||||
const cRecipe & Recipe = *itr;
|
||||
if ((Recipe.In->m_ItemType == a_Ingredient.m_ItemType) && (Recipe.In->m_ItemCount <= a_Ingredient.m_ItemCount))
|
||||
{
|
||||
if (BestRecipe && (BestRecipe->In->m_ItemCount > R.In->m_ItemCount))
|
||||
if (BestRecipe && (BestRecipe->In->m_ItemCount > Recipe.In->m_ItemCount))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
BestRecipe = &R;
|
||||
BestRecipe = &Recipe;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -317,16 +296,16 @@ int cFurnaceRecipe::GetBurnTime(const cItem & a_Fuel) const
|
||||
int BestFuel = 0;
|
||||
for (FuelList::const_iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
|
||||
{
|
||||
const Fuel & F = *itr;
|
||||
if ((F.In->m_ItemType == a_Fuel.m_ItemType) && (F.In->m_ItemCount <= a_Fuel.m_ItemCount))
|
||||
const cFuel & Fuel = *itr;
|
||||
if ((Fuel.In->m_ItemType == a_Fuel.m_ItemType) && (Fuel.In->m_ItemCount <= a_Fuel.m_ItemCount))
|
||||
{
|
||||
if (BestFuel > 0 && (BestFuel > F.BurnTime))
|
||||
if (BestFuel > 0 && (BestFuel > Fuel.BurnTime))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
BestFuel = F.BurnTime;
|
||||
BestFuel = Fuel.BurnTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,23 +19,23 @@ public:
|
||||
|
||||
void ReloadRecipes(void);
|
||||
|
||||
struct Fuel
|
||||
struct cFuel
|
||||
{
|
||||
cItem * In;
|
||||
int BurnTime; ///< How long this fuel burns, in ticks
|
||||
};
|
||||
|
||||
struct Recipe
|
||||
struct cRecipe
|
||||
{
|
||||
cItem * In;
|
||||
cItem * Out;
|
||||
int CookTime; ///< How long this recipe takes to smelt, in ticks
|
||||
};
|
||||
|
||||
/// Returns a recipe for the specified input, NULL if no recipe found
|
||||
const Recipe * GetRecipeFrom(const cItem & a_Ingredient) const;
|
||||
/** Returns a recipe for the specified input, NULL if no recipe found */
|
||||
const cRecipe * GetRecipeFrom(const cItem & a_Ingredient) const;
|
||||
|
||||
/// Returns the amount of time that the specified fuel burns, in ticks
|
||||
/** Returns the amount of time that the specified fuel burns, in ticks */
|
||||
int GetBurnTime(const cItem & a_Fuel) const;
|
||||
|
||||
private:
|
||||
@ -43,33 +43,14 @@ private:
|
||||
|
||||
/** Parses the fuel contained in the line, adds it to m_pState's fuels.
|
||||
Logs a warning to the console on input error. */
|
||||
void AddFuelFromLine(const AString & a_Line, int a_LineNum);
|
||||
void AddFuelFromLine(const AString & a_Line, unsigned int a_LineNum);
|
||||
|
||||
/** Parses the recipe contained in the line, adds it to m_pState's recipes.
|
||||
Logs a warning to the console on input error. */
|
||||
void AddRecipeFromLine(const AString & a_Line, int a_LineNum);
|
||||
|
||||
/** Calls LOGWARN with the line, position, and error */
|
||||
static void PrintParseError(unsigned int a_Line, size_t a_Position, const AString & a_CharactersMissing);
|
||||
|
||||
/** Reads a number from a string given, starting at a given position and ending at a delimiter given
|
||||
Updates beginning position to the delimiter found + 1, and updates the value to the one read
|
||||
If it encounters a substring that is not fully numeric, it will call SetParseError() and return false; the caller should abort processing
|
||||
Otherwise, the function will return true
|
||||
*/
|
||||
static bool ReadMandatoryNumber(AString::size_type & a_Begin, const AString & a_Delimiter, const AString & a_Text, unsigned int a_Line, int & a_Value, bool a_IsLastValue = false);
|
||||
|
||||
/** Reads two numbers from a string given, starting at a given position and ending at the first delimiter given, then again (with an updated position) until the second delimiter given
|
||||
Updates beginning position to the second delimiter found + 1, and updates the values to the ones read
|
||||
If it encounters a substring that is not fully numeric whilst reading the second value, it will call SetParseError() and return false; the caller should abort processing
|
||||
If this happens whilst reading the first value, it will call ReadMandatoryNumber() with the appropriate position, as this may legitimately occur with the optional value and AString::find_first_of finding the incorrect delimiter. It will return the result of ReadMandatoryNumber()
|
||||
True will be returned definitively for an optional value that is valid
|
||||
*/
|
||||
static bool ReadOptionalNumbers(AString::size_type & a_Begin, const AString & a_DelimiterOne, const AString & a_DelimiterTwo, const AString & a_Text, unsigned int a_Line, int & a_ValueOne, int & a_ValueTwo, bool a_IsLastValue = false);
|
||||
|
||||
/** Uses std::all_of to determine if a string contains only digits */
|
||||
static bool DoesStringContainOnlyNumbers(const AString & a_String);
|
||||
void AddRecipeFromLine(const AString & a_Line, unsigned int a_LineNum);
|
||||
|
||||
/** Parses an item string in the format "<ItemType>[: <Damage>][, <Amount>]", returns true if successful. */
|
||||
bool ParseItem(const AString & a_String, cItem & a_Item);
|
||||
|
||||
struct sFurnaceRecipeState;
|
||||
sFurnaceRecipeState * m_pState;
|
||||
|
@ -75,7 +75,6 @@ public:
|
||||
Arrow = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force);
|
||||
if (!a_Player->IsGameModeCreative())
|
||||
{
|
||||
@ -83,8 +82,19 @@ public:
|
||||
{
|
||||
a_Player->GetInventory().RemoveItem(cItem(E_ITEM_ARROW));
|
||||
}
|
||||
else
|
||||
{
|
||||
Arrow->SetPickupState(cArrowEntity::psNoPickup);
|
||||
}
|
||||
|
||||
|
||||
a_Player->UseEquippedItem();
|
||||
}
|
||||
|
||||
if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchFlame) > 0)
|
||||
{
|
||||
Arrow->StartBurning(100);
|
||||
}
|
||||
}
|
||||
} ;
|
||||
|
||||
|
@ -75,7 +75,7 @@ public:
|
||||
int FoodLevel;
|
||||
double Saturation;
|
||||
|
||||
FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
|
||||
FoodInfo(int a_FoodLevel, double a_Saturation) :
|
||||
FoodLevel(a_FoodLevel),
|
||||
Saturation(a_Saturation)
|
||||
{
|
||||
|
@ -158,7 +158,8 @@ cMojangAPI::cMojangAPI(void) :
|
||||
m_NameToUUIDServer(DEFAULT_NAME_TO_UUID_SERVER),
|
||||
m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS),
|
||||
m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER),
|
||||
m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS)
|
||||
m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS),
|
||||
m_RankMgr(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -979,9 +979,18 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
|
||||
AString ServerAddress;
|
||||
short ServerPort;
|
||||
UInt32 NextState;
|
||||
m_Buffer.ReadVarUTF8String(ServerAddress);
|
||||
m_Buffer.ReadBEShort(ServerPort);
|
||||
m_Buffer.ReadVarInt(NextState);
|
||||
if (!m_Buffer.ReadVarUTF8String(ServerAddress))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!m_Buffer.ReadBEShort(ServerPort))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!m_Buffer.ReadVarInt(NextState))
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_Buffer.CommitRead();
|
||||
m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
|
||||
return true;
|
||||
@ -991,9 +1000,18 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
|
||||
AString ServerAddress;
|
||||
short ServerPort;
|
||||
UInt32 NextState;
|
||||
m_Buffer.ReadVarUTF8String(ServerAddress);
|
||||
m_Buffer.ReadBEShort(ServerPort);
|
||||
m_Buffer.ReadVarInt(NextState);
|
||||
if (!m_Buffer.ReadVarUTF8String(ServerAddress))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!m_Buffer.ReadBEShort(ServerPort))
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!m_Buffer.ReadVarInt(NextState))
|
||||
{
|
||||
break;
|
||||
}
|
||||
m_Buffer.CommitRead();
|
||||
m_Protocol = new cProtocol176(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
|
||||
return true;
|
||||
|
@ -477,8 +477,8 @@ AString cRankManager::GetPlayerRankName(const AString & a_PlayerUUID)
|
||||
{
|
||||
SQLite::Statement stmt(m_DB, "SELECT Rank.Name FROM Rank LEFT JOIN PlayerRank ON Rank.RankID = PlayerRank.RankID WHERE PlayerRank.PlayerUUID = ?");
|
||||
stmt.bind(1, a_PlayerUUID);
|
||||
stmt.executeStep();
|
||||
if (stmt.isDone())
|
||||
// executeStep returns false on no data
|
||||
if (!stmt.executeStep())
|
||||
{
|
||||
// No data returned from the DB
|
||||
return AString();
|
||||
|
14
src/Root.cpp
14
src/Root.cpp
@ -468,16 +468,6 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCall
|
||||
|
||||
void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd)
|
||||
{
|
||||
// Some commands are built-in:
|
||||
if (a_Cmd == "stop")
|
||||
{
|
||||
m_bStop = true;
|
||||
}
|
||||
else if (a_Cmd == "restart")
|
||||
{
|
||||
m_bRestart = true;
|
||||
}
|
||||
|
||||
// Put the command into a queue (Alleviates FS #363):
|
||||
cCSLock Lock(m_CSPendingCommands);
|
||||
m_PendingCommands.push_back(cCommand(a_Cmd, new cLogCommandDeleteSelfOutputCallback));
|
||||
@ -489,14 +479,16 @@ void cRoot::QueueExecuteConsoleCommand(const AString & a_Cmd)
|
||||
|
||||
void cRoot::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output)
|
||||
{
|
||||
// Some commands are built-in:
|
||||
// cRoot handles stopping and restarting due to our access to controlling variables
|
||||
if (a_Cmd == "stop")
|
||||
{
|
||||
m_bStop = true;
|
||||
return;
|
||||
}
|
||||
else if (a_Cmd == "restart")
|
||||
{
|
||||
m_bRestart = true;
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("Executing console command: \"%s\"", a_Cmd.c_str());
|
||||
|
@ -458,56 +458,80 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
|
||||
return;
|
||||
}
|
||||
|
||||
// Special handling: "stop" and "restart" are built in
|
||||
if ((split[0].compare("stop") == 0) || (split[0].compare("restart") == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// "stop" and "restart" are handled in cRoot::ExecuteConsoleCommand, our caller, due to its access to controlling variables
|
||||
|
||||
// "help" and "reload" are to be handled by MCS, so that they work no matter what
|
||||
if (split[0] == "help")
|
||||
{
|
||||
PrintHelp(split, a_Output);
|
||||
a_Output.Finished();
|
||||
return;
|
||||
}
|
||||
else if (split[0] == "reload")
|
||||
{
|
||||
cPluginManager::Get()->ReloadPlugins();
|
||||
a_Output.Finished();
|
||||
return;
|
||||
}
|
||||
else if (split[0] == "reloadplugins")
|
||||
{
|
||||
cPluginManager::Get()->ReloadPlugins();
|
||||
a_Output.Out("Plugins reloaded");
|
||||
a_Output.Finished();
|
||||
return;
|
||||
}
|
||||
else if (split[0] == "load")
|
||||
{
|
||||
if (split.size() > 1)
|
||||
{
|
||||
cPluginManager::Get()->LoadPlugin(split[1]);
|
||||
|
||||
return;
|
||||
a_Output.Out(cPluginManager::Get()->LoadPlugin(split[1]) ? "Plugin loaded" : "Error occurred loading plugin");
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Output.Out("No plugin given! Command: load <pluginname>");
|
||||
a_Output.Finished();
|
||||
return;
|
||||
a_Output.Out("Usage: load <pluginname>");
|
||||
}
|
||||
a_Output.Finished();
|
||||
return;
|
||||
}
|
||||
else if (split[0] == "unload")
|
||||
{
|
||||
if (split.size() > 1)
|
||||
{
|
||||
cPluginManager::Get()->RemovePlugin(cPluginManager::Get()->GetPlugin(split[1]));
|
||||
return;
|
||||
a_Output.Out("Plugin unloaded");
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Output.Out("No plugin given! Command: unload <pluginname>");
|
||||
a_Output.Finished();
|
||||
return;
|
||||
a_Output.Out("Usage: unload <pluginname>");
|
||||
}
|
||||
a_Output.Finished();
|
||||
return;
|
||||
}
|
||||
if (split[0] == "destroyentities")
|
||||
{
|
||||
class WorldCallback : public cWorldListCallback
|
||||
{
|
||||
virtual bool Item(cWorld * a_World) override
|
||||
{
|
||||
class EntityCallback : public cEntityCallback
|
||||
{
|
||||
virtual bool Item(cEntity * a_Entity) override
|
||||
{
|
||||
if (!a_Entity->IsPlayer())
|
||||
{
|
||||
a_Entity->Destroy();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} EC;
|
||||
a_World->ForEachEntity(EC);
|
||||
return false;
|
||||
}
|
||||
} WC;
|
||||
cRoot::Get()->ForEachWorld(WC);
|
||||
a_Output.Out("Destroyed all entities");
|
||||
a_Output.Finished();
|
||||
return;
|
||||
}
|
||||
|
||||
// There is currently no way a plugin can do these (and probably won't ever be):
|
||||
@ -602,6 +626,7 @@ void cServer::BindBuiltInConsoleCommands(void)
|
||||
PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics");
|
||||
PlgMgr->BindConsoleCommand("load <pluginname>", NULL, " - Adds and enables the specified plugin");
|
||||
PlgMgr->BindConsoleCommand("unload <pluginname>", NULL, " - Disables the specified plugin");
|
||||
PlgMgr->BindConsoleCommand("destroyentities", NULL, " - Destroys all entities in all worlds");
|
||||
|
||||
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
||||
PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml");
|
||||
|
@ -134,8 +134,8 @@ void cSetChunkData::RemoveInvalidBlockEntities(void)
|
||||
);
|
||||
cBlockEntityList::iterator itr2 = itr;
|
||||
itr2++;
|
||||
m_BlockEntities.erase(itr);
|
||||
delete *itr;
|
||||
m_BlockEntities.erase(itr);
|
||||
itr = itr2;
|
||||
}
|
||||
else
|
||||
|
@ -1226,24 +1226,26 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Add damage to entities and implement block hardiness
|
||||
// TODO: Implement block hardiness
|
||||
Vector3d explosion_pos = Vector3d(a_BlockX, a_BlockY, a_BlockZ);
|
||||
cVector3iArray BlocksAffected;
|
||||
m_ChunkMap->DoExplosionAt(a_ExplosionSize, a_BlockX, a_BlockY, a_BlockZ, BlocksAffected);
|
||||
BroadcastSoundEffect("random.explode", (double)a_BlockX, (double)a_BlockY, (double)a_BlockZ, 1.0f, 0.6f);
|
||||
|
||||
{
|
||||
cCSLock Lock(m_CSPlayers);
|
||||
for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
|
||||
{
|
||||
cClientHandle * ch = (*itr)->GetClientHandle();
|
||||
if ((ch == NULL) || !ch->IsLoggedIn() || ch->IsDestroyed())
|
||||
if (ch == NULL)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector3d distance_explosion = (*itr)->GetPosition() - explosion_pos;
|
||||
if (distance_explosion.SqrLength() < 4096.0)
|
||||
{
|
||||
double real_distance = std::max(0.004, sqrt(distance_explosion.SqrLength()));
|
||||
double real_distance = std::max(0.004, distance_explosion.Length());
|
||||
double power = a_ExplosionSize / real_distance;
|
||||
if (power <= 1)
|
||||
{
|
||||
@ -1255,6 +1257,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cPluginManager::Get()->CallHookExploded(*this, a_ExplosionSize, a_CanCauseFire, a_BlockX, a_BlockY, a_BlockZ, a_Source, a_SourceData);
|
||||
}
|
||||
|
||||
|
@ -615,7 +615,6 @@ void cNBTChunkSerializer::AddProjectileEntity(cProjectileEntity * a_Projectile)
|
||||
{
|
||||
m_Writer.BeginCompound("");
|
||||
AddBasicEntity(a_Projectile, a_Projectile->GetMCAClassName());
|
||||
Vector3d Pos = a_Projectile->GetPosition();
|
||||
m_Writer.AddByte("inGround", a_Projectile->IsInGround() ? 1 : 0);
|
||||
|
||||
switch (a_Projectile->GetProjectileKind())
|
||||
|
@ -592,10 +592,6 @@ void cWSSAnvil::LoadBlockEntitiesFromNBT(cBlockEntityList & a_BlockEntities, con
|
||||
}
|
||||
int RelX = x, RelY = y, RelZ = z, ChunkX, ChunkZ;
|
||||
cChunkDef::AbsoluteToRelative(RelX, RelY, RelZ, ChunkX, ChunkZ);
|
||||
if (RelY == 2)
|
||||
{
|
||||
LOGD("HERE");
|
||||
}
|
||||
|
||||
// Load the proper BlockEntity type based on the block type:
|
||||
BLOCKTYPE BlockType = cChunkDef::GetBlock(a_BlockTypes, RelX, RelY, RelZ);
|
||||
|
@ -45,7 +45,7 @@ int main(int argc, char ** argv)
|
||||
BLOCKTYPE * WritePosition = &TestBuffer[WritePosIdx];
|
||||
memset(TestBuffer, 0x03, sizeof(TestBuffer));
|
||||
size_t LastReportedStep = 1;
|
||||
for (size_t idx = 0; idx < 5000; idx += 7)
|
||||
for (size_t idx = 0; idx < 5000; idx += 73)
|
||||
{
|
||||
if (idx / 500 != LastReportedStep)
|
||||
{
|
||||
@ -53,7 +53,7 @@ int main(int argc, char ** argv)
|
||||
LastReportedStep = idx / 500;
|
||||
}
|
||||
|
||||
for (size_t len = 3; len < 1000; len += 13)
|
||||
for (size_t len = 3; len < 700; len += 13)
|
||||
{
|
||||
Data.CopyBlockTypes(WritePosition, idx, len);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user