1
0

Merge branch 'master' into WebAdmin

This commit is contained in:
Howaner 2014-09-02 19:37:03 +02:00
commit b8769e3fb4
27 changed files with 785 additions and 308 deletions

View File

@ -2846,7 +2846,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)." }, 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"}, 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." }, 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." }, 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." }, 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."}, 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."},

View File

@ -61,30 +61,45 @@ Furnace = Cobblestone, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
#******************************************************# #******************************************************#
# Blocks # Blocks
# #
IronBlock = IronIngot, 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 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 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 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 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 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 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 NetherBrick = netherbrickitem, 1:1, 1:2, 2:1, 2:2
Glowstone = GlowstoneDust, 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 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 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 PillarQuartzBlock = QuartzSlab, 1:1, 1:2
ChiseledQuartzBlock, 2 = QuartzBlock, 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 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 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 SnowBlock = SnowBall, 1:1, 1:2, 2:1, 2:2
ClayBlock = Clay, 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 BrickBlock = Brick, 1:1, 1:2, 2:1, 2:2
StoneBrick, 4 = Stone, 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 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 Sandstone, 4 = Sand, 1:1, 1:2, 2:1, 2:2
SmoothSandstone, 4 = Sandstone, 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 OrnamentSandstone = SandstoneSlab, 1:1, 1:2
JackOLantern = Pumpkin, 1:1 | Torch, 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: # Slabs:
StoneSlab, 6 = Stone, 1:1, 2:1, 3:1 StoneSlab, 6 = Stone, 1:1, 2:1, 3:1
@ -101,6 +116,7 @@ StonebrickSlab, 6 = StoneBrick, 1:1, 2:1, 3:1
NetherbrickSlab, 6 = NetherBrick, 1:1, 2:1, 3:1 NetherbrickSlab, 6 = NetherBrick, 1:1, 2:1, 3:1
Quartzslab, 6 = QuartzBlock, 1:1, 2:1, 3:1 Quartzslab, 6 = QuartzBlock, 1:1, 2:1, 3:1
snow, 6 = SnowBlock, 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: # Stairs:
@ -128,6 +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 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, 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 StoneBrickStairs, 4 = StoneBrick, 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
RedSandstoneStairs, 4 = RedSandstone, 3:1, 2:2, 3:2, 1:3, 2:3, 3:3
# Other # Other
Carpet = Wool, 1:3, 2:3 Carpet = Wool, 1:3, 2:3
@ -262,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 # Mechanisms
# #
WoodenDoor = Planks, 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
IronDoor = IronIngot, 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 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 WoodPlate = Planks, 1:1, 2:1
StonePlate = Stone, 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 StoneButton = Stone, 1:1
WoodenButton = Planks, 1:1 WoodenButton = Planks, 1:1
RedstoneTorchOn = Stick, 1:2 | RedstoneDust, 1:1 RedstoneTorchOn = Stick, 1:2 | RedstoneDust, 1:1
@ -304,6 +330,8 @@ MelonSeeds = MelonSlice, *
PumpkinSeeds, 4 = Pumpkin, * PumpkinSeeds, 4 = Pumpkin, *
PumpkinPie = Pumpkin, * | Sugar, * | egg, * PumpkinPie = Pumpkin, * | Sugar, * | egg, *
Wheat, 9 = Haybale, * 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
@ -332,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 Paper, 3 = Sugarcane, 1:1, 2:1, 3:1
Book = Paper, *, *, * | leather, * Book = Paper, *, *, * | leather, *
Bookandquill = Book, * | feather, * | inksac, * 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 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 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 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 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 GoldIngot = GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
EyeOfEnder = EnderPearl, * | BlazePowder, * 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 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 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 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

View File

@ -10,25 +10,28 @@
# An Item is defined by an Item Type, an amount (and damage) # 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 # The damage is optional, and if not specified it's assumed to be 0
# #
# -Cactus Green: # Cactus Green example:
# 351 : 1 ( : 2 ) # 351 : 2 ( , 1 )
# ItemType : Amount ( : Damage ) # ItemType : Damage ( , Amount )
# or simple use the item name (marked in items.ini):
# CactusGreen ( , 1 )
# #
# #
# **** Recipe and result **** # **** 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 # Write in full:
# ItemType : Amount @ ticks = ItemID : Amount # Cobble : 0 , 1 @ 200 = 1 : 1 , 1
# ItemType : Damage , Amount @ ticks = ItemType : Damage , Amount
# #
# #
# **** Fuel **** # **** Fuel ****
# #
# !17:1 = 300 -> 1 Wood burns for 300 ticks (15 s) # !17:1 = 300 -> 1 Wood burns for 300 ticks (15 s)
# #
# ! 17 : 1 = 300 # ! Wood , 1 = 300
# Fuel ItemType : Amount = ticks # Fuel ItemType , Amount = ticks
# #
#******************************************************# #******************************************************#
@ -39,20 +42,24 @@
#-------------------------- #--------------------------
# Smelting recipes # Smelting recipes
4:1 @ 200 = 1:1 # 1 Cobblestone -> 1 Rock Cobble = Stone
15:1 @ 200 = 265:1 # 1 Iron Ore -> 1 Iron Ingot IronOre = IronIngot
14:1 @ 200 = 266:1 # 1 Gold Ore -> 1 Gold Ingot GoldOre = GoldIngot
153:1 @ 200 = 406:1 # 1 Quartz Ore -> 1 Quartz NetherQuartzOre = NetherQuartz
12:1 @ 200 = 20:1 # 1 Sand -> 1 Glass Sand = Glass
319:1 @ 200 = 320:1 # 1 Raw Pork -> 1 Cooked Pork Pork = CookedPork
363:1 @ 200 = 364:1 # 1 Raw Beef -> 1 Cooked Beef (steak) RawBeef = Steak
365:1 @ 200 = 366:1 # 1 Raw Chicken -> 1 Cooked Chicken RawChicken = CookedChicken
337:1 @ 200 = 336:1 # 1 Clay -> 1 Clay Brick Clay = Brick
82:1 @ 200 = 172:1 # 1 Clay Block -> 1 Hardened Clay ClayBlock = HardenedClay
87:1 @ 200 = 405:1 # 1 NetherRack -> 1 NetherBrick TallGrass = NetherBrickItem
349:1 @ 200 = 350:1 # 1 Raw Fish -> 1 Cooked Fish RawFish = CookedFish
17:1 @ 200 = 263:1:1 # 1 Log -> 1 Charcoal Log = CharCoal
81:1 @ 200 = 351:1:2 # 1 Cactus -> 1 Green Dye Cactus = GreenDye
WetSponge = Sponge
Stonebrick = CrackedStonebrick
RawRabbit = CookedRabbit
RawMutton = CookedMutton
@ -61,31 +68,41 @@
#-------------------------- #--------------------------
# Fuels # Fuels
! 263:1 = 1600 # 1 Coal -> 80 sec ! CharCoal = 1600 # -> 80 sec
! 263:1:1 = 1600 # 1 Charcoal -> 80 sec ! Coal = 1600 # -> 80 sec
! 126:1 = 15 # 1 Halfslab -> 7.5 sec ! WoodenSlab = 15 # -> 7.5 sec
! 5:1 = 300 # 1 Planks -> 15 sec ! Planks = 300 # -> 15 sec
! 280:1 = 100 # 1 Stick -> 5 sec ! Stick = 100 # -> 5 sec
! 85:1 = 300 # 1 Fence -> 15 sec ! Fence = 300 # -> 15 sec
! 53:1 = 300 # 1 Wooden Stairs -> 15 sec ! SpruceFence = 300 # -> 15 sec
! 58:1 = 300 # 1 Crafting Table -> 15 sec ! BirchFence = 300 # -> 15 sec
! 47:1 = 300 # 1 Bookshelf -> 15 sec ! JungleFence = 300 # -> 15 sec
! 54:1 = 300 # 1 Chest -> 15 sec ! DarkOakFence = 300 # -> 15 sec
! 84:1 = 300 # 1 Jukebox -> 15 sec ! AcaciaFence = 300 # -> 15 sec
! 327:1 = 20000 # 1 Lava Bucket -> 1000 sec ! WoodStairs = 300 # -> 15 sec
! 17:1 = 300 # 1 Wood -> 15 sec ! Workbench = 300 # -> 15 sec
! 6:1 = 100 # 1 Sapling -> 5 sec ! Bookshelf = 300 # -> 15 sec
! 173:1 = 16000 # 1 Coal Block -> 800 sec ! Chest = 300 # -> 15 sec
! 369:1 = 2400 # 1 Blaze Rod -> 120 sec ! Jukebox = 300 # -> 15 sec
! 25:1 = 300 # 1 Note Block -> 15 sec ! Lavabucket = 20000 # -> 1000 sec
! 151:1 = 300 # 1 Daylight Sensor -> 15 sec ! Log = 300 # -> 15 sec
! 107:1 = 300 # 1 Fence Gate -> 15 sec ! Sapling = 100 # -> 5 sec
! 167:1 = 300 # 1 Trapdoor -> 15 sec ! CoalBlock = 16000 # -> 800 sec
! 146:1 = 300 # 1 Trapped Chest -> 15 sec ! BlazeRod = 2400 # -> 120 sec
! 72:1 = 300 # 1 Pressure Plate -> 15 sec ! NoteBlock = 300 # -> 15 sec
! 270:1 = 200 # 1 Wooden Pickaxe -> 10 sec ! DaylightSensor = 300 # -> 15 sec
! 271:1 = 200 # 1 Wooden Axe -> 10 sec ! FenceGate = 300 # -> 15 sec
! 269:1 = 200 # 1 Wooden Shovel -> 10 sec ! SpruceFenceGate = 300 # -> 15 sec
! 290:1 = 200 # 1 Wooden Hoe -> 10 sec ! BirchFenceGate = 300 # -> 15 sec
! 268:1 = 200 # 1 Wooden Sword -> 10 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

View File

@ -1,9 +1,17 @@
[Items] [Items]
air=0 air=0
rock=1 rock=1
granite=1:1
polishedgranite=1:2
diorite=1:3
polisheddiorite=1:4
andesite=1:5
polishedandesite=1:6
stone=1 stone=1
grass=2 grass=2
dirt=3 dirt=3
coarseddirt=3:1
podzol=3:2
cobblestone=4 cobblestone=4
cobble=4 cobble=4
planks=5 planks=5
@ -45,6 +53,7 @@ stilllava=11
slava=11 slava=11
stationarylava=11 stationarylava=11
sand=12 sand=12
redsand=12:1
gravel=13 gravel=13
goldore=14 goldore=14
ironore=15 ironore=15
@ -69,6 +78,7 @@ spruceleaves=18:1
birchleaves=18:2 birchleaves=18:2
jungleleaves=18:3 jungleleaves=18:3
sponge=19 sponge=19
wetsponge=19:1
glass=20 glass=20
lapisore=21 lapisore=21
lapisblock=22 lapisblock=22
@ -395,8 +405,42 @@ acaciawoodstairs=163
bigoakwoodstiars=164 bigoakwoodstiars=164
darkoakwoodstairs=164 darkoakwoodstairs=164
roofedoakwoodstairs=164 roofedoakwoodstairs=164
slimeblock=165
irontrapdoor=167
prismarine=168
prismarinebricks=168:1
darkprismarine=168:2
sealantern=169
haybale=170 haybale=170
carpet=171 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 ironshovel=256
ironspade=256 ironspade=256
ironpickaxe=257 ironpickaxe=257
@ -644,13 +688,52 @@ netherbrickitem=405
netherquartz=406 netherquartz=406
tntminecart=407 tntminecart=407
hopperminecart=408 hopperminecart=408
prismarineshard=409
prismarinecrystals=410
rawrabbit=411
cookedrabbit=412
rabbitstew=413
rabbitsoup=413
rabbitsfood=414
rabbithide=415
armorstand=416
ironhorsearmor=417 ironhorsearmor=417
goldhorsearmor=418 goldhorsearmor=418
diamondhorsearmor=419 diamondhorsearmor=419
lead=420 lead=420
nametag=421 nametag=421
commandblockminecart=422 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 goldrecord=2256
greenrecord=2257 greenrecord=2257
blocksrecord=2258 blocksrecord=2258

View File

@ -2663,7 +2663,7 @@ static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S)
// Get the recipe for the input // Get the recipe for the input
cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe(); cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe();
const cFurnaceRecipe::Recipe * Recipe = FR->GetRecipeFrom(*Input); const cFurnaceRecipe::cRecipe * Recipe = FR->GetRecipeFrom(*Input);
if (Recipe == NULL) if (Recipe == NULL)
{ {
// There is no such furnace recipe for this input, return no value // There is no such furnace recipe for this input, return no value

View File

@ -188,12 +188,11 @@ void cCommandBlockEntity::SaveToJson(Json::Value & a_Value)
void cCommandBlockEntity::Execute() 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 : class CommandBlockOutCb :

View File

@ -105,7 +105,7 @@ protected:
NIBBLETYPE m_BlockMeta; NIBBLETYPE m_BlockMeta;
/// The recipe for the current input slot /// The recipe for the current input slot
const cFurnaceRecipe::Recipe * m_CurrentRecipe; const cFurnaceRecipe::cRecipe * m_CurrentRecipe;
/// The item that is being smelted /// The item that is being smelted
cItem m_LastInput; cItem m_LastInput;

View File

@ -431,10 +431,45 @@ void cBlockHandler::DropBlock(cChunkInterface & a_ChunkInterface, cWorldInterfac
else else
{ {
// TODO: Add a proper overridable function for this // 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: // Allow plugins to modify the pickups:
a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Pickups); a_BlockPluginInterface.CallHookBlockToPickups(a_Digger, a_BlockX, a_BlockY, a_BlockZ, m_BlockType, Meta, Pickups);

View File

@ -30,18 +30,18 @@ public:
{ {
return; return;
} }
BLOCKTYPE BlockBelow = a_ChunkInterface.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); cEnchantments Enchantments = a_Player->GetInventory().GetEquippedItem().m_Enchantments;
if (!cBlockInfo::FullyOccupiesVoxel(BlockBelow) && !IsBlockLiquid(BlockBelow)) 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); 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 // This is called later than the real destroying of this ice block
}
} }
} ; } ;

View File

@ -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); a_Area.SetBlockType(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_SPONGE);
for (int i = 0; i < LEAVES_CHECK_DISTANCE; i++) 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++) for (int z = a_BlockZ - i; z <= a_BlockZ + i; z++)
{ {

View File

@ -256,6 +256,11 @@ set(EXECUTABLE MCServer)
if (MSVC) if (MSVC)
get_directory_property(BINDING_OUTPUTS DIRECTORY "Bindings" DEFINITION BINDING_OUTPUTS) get_directory_property(BINDING_OUTPUTS DIRECTORY "Bindings" DEFINITION BINDING_OUTPUTS)
get_directory_property(BINDING_DEPENDENCIES DIRECTORY "Bindings" DEFINITION BINDING_DEPENDENCIES) 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( ADD_CUSTOM_COMMAND(
OUTPUT ${BINDING_OUTPUTS} OUTPUT ${BINDING_OUTPUTS}
@ -268,7 +273,7 @@ if (MSVC)
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/Bindings/
# add any new generation dependencies here # add any new generation dependencies here
DEPENDS ${BINDING_DEPENDENCIES} DEPENDS ${BINDINGS_DEPENDENCIES}
) )
endif() endif()

View File

@ -197,32 +197,32 @@ public:
inline static int GetHeight(const HeightMap & a_HeightMap, int a_X, int a_Z) inline static int GetHeight(const HeightMap & a_HeightMap, int a_X, int a_Z)
{ {
ASSERT((a_X >= 0) && (a_X <= Width)); ASSERT((a_X >= 0) && (a_X < Width));
ASSERT((a_Z >= 0) && (a_Z <= Width)); ASSERT((a_Z >= 0) && (a_Z < Width));
return a_HeightMap[a_X + Width * a_Z]; 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) 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_X >= 0) && (a_X < Width));
ASSERT((a_Z >= 0) && (a_Z <= Width)); ASSERT((a_Z >= 0) && (a_Z < Width));
a_HeightMap[a_X + Width * a_Z] = a_Height; a_HeightMap[a_X + Width * a_Z] = a_Height;
} }
inline static EMCSBiome GetBiome(const BiomeMap & a_BiomeMap, int a_X, int a_Z) inline static EMCSBiome GetBiome(const BiomeMap & a_BiomeMap, int a_X, int a_Z)
{ {
ASSERT((a_X >= 0) && (a_X <= Width)); ASSERT((a_X >= 0) && (a_X < Width));
ASSERT((a_Z >= 0) && (a_Z <= Width)); ASSERT((a_Z >= 0) && (a_Z < Width));
return a_BiomeMap[a_X + Width * a_Z]; return a_BiomeMap[a_X + Width * a_Z];
} }
inline static void SetBiome(BiomeMap & a_BiomeMap, int a_X, int a_Z, EMCSBiome a_Biome) 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_X >= 0) && (a_X < Width));
ASSERT((a_Z >= 0) && (a_Z <= Width)); ASSERT((a_Z >= 0) && (a_Z < Width));
a_BiomeMap[a_X + Width * a_Z] = a_Biome; a_BiomeMap[a_X + Width * a_Z] = a_Biome;
} }

View File

@ -90,6 +90,13 @@ void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFa
// Broadcast arrow hit sound // 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)); 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); 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 // Broadcast successful hit sound
GetWorld()->BroadcastSoundEffect("random.successful_hit", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); GetWorld()->BroadcastSoundEffect("random.successful_hit", GetPosX(), GetPosY(), GetPosZ(), 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));

View File

@ -10,6 +10,7 @@
// tolua_begin // tolua_begin
class cArrowEntity : class cArrowEntity :
@ -46,7 +47,7 @@ public:
/// Returns the damage modifier coeff. /// Returns the damage modifier coeff.
double GetDamageCoeff(void) const { return m_DamageCoeff; } double GetDamageCoeff(void) const { return m_DamageCoeff; }
/// Sets the damage modifier coeff /// Sets the damage modifier coeff
void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; } 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 /// If true, the arrow is in the process of being collected - don't go to anyone else
bool m_bIsCollected; bool m_bIsCollected;
/// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air /// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
Vector3i m_HitBlockPos; Vector3i m_HitBlockPos;

View File

@ -13,6 +13,7 @@
#include "../Tracer.h" #include "../Tracer.h"
#include "Player.h" #include "Player.h"
#include "Items/ItemHandler.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 // 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) // 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)) if ((a_TDI.DamageType == dtAttack) || (a_TDI.DamageType == dtArrowAttack))
{ {
a_TDI.FinalDamage += 2; 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)); 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; m_Health -= (short)a_TDI.FinalDamage;
// TODO: Apply damage to armor // TODO: Apply damage to armor
m_Health = std::max(m_Health, 0); 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 int KnockbackLevel = a_TDI.Attacker->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchKnockback); // More common enchantment
if (KnockbackLevel < 1) if (KnockbackLevel < 1)
@ -1252,6 +1462,8 @@ void cEntity::HandleAir(void)
// See if the entity is /submerged/ water (block above is water) // See if the entity is /submerged/ water (block above is water)
// Get the type of block the entity is standing in: // Get the type of block the entity is standing in:
int RespirationLevel = GetEquippedHelmet().m_Enchantments.GetLevel(cEnchantments::enchRespiration);
if (IsSubmerged()) if (IsSubmerged())
{ {
if (!IsPlayer()) // Players control themselves if (!IsPlayer()) // Players control themselves
@ -1259,6 +1471,11 @@ void cEntity::HandleAir(void)
SetSpeedY(1); // Float in the water SetSpeedY(1); // Float in the water
} }
if (RespirationLevel > 0)
{
((cPawn *)this)->AddEntityEffect(cEntityEffect::effNightVision, 200, 5, 0);
}
if (m_AirLevel <= 0) if (m_AirLevel <= 0)
{ {
// Runs the air tick timer to check whether the player should be damaged // 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 // Set the air back to maximum
m_AirLevel = MAX_AIR_LEVEL; m_AirLevel = MAX_AIR_LEVEL;
m_AirTickTimer = DROWNING_TICKS; m_AirTickTimer = DROWNING_TICKS;
if (RespirationLevel > 0)
{
m_AirTickTimer = DROWNING_TICKS + (RespirationLevel * 15 * 20);
}
} }
} }

View File

@ -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); 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()) if (PickupCombiningCallback.FoundMatchingPickup())
{ {
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);

View File

@ -15,6 +15,7 @@
#include "../Chunk.h" #include "../Chunk.h"
#include "../Items/ItemHandler.h" #include "../Items/ItemHandler.h"
#include "../Vector3.h" #include "../Vector3.h"
#include "../FastRandom.h"
#include "../WorldStorage/StatSerializer.h" #include "../WorldStorage/StatSerializer.h"
#include "../CompositeChat.h" #include "../CompositeChat.h"
@ -1795,6 +1796,28 @@ void cPlayer::UseEquippedItem(int a_Amount)
return; 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)) if (GetInventory().DamageEquippedItem(a_Amount))
{ {
m_World->BroadcastSoundEffect("random.break", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64)); m_World->BroadcastSoundEffect("random.break", GetPosX(), GetPosY(), GetPosZ(), 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));

View File

@ -222,7 +222,8 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, double a
m_ProjectileKind(a_Kind), m_ProjectileKind(a_Kind),
m_CreatorData( m_CreatorData(
((a_Creator != NULL) ? a_Creator->GetUniqueID() : -1), ((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) 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) : 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), super(etProjectile, a_Pos.x, a_Pos.y, a_Pos.z, a_Width, a_Height),
m_ProjectileKind(a_Kind), 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) m_IsInGround(false)
{ {
SetSpeed(a_Speed); SetSpeed(a_Speed);

View File

@ -94,14 +94,16 @@ protected:
*/ */
struct CreatorData 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_UniqueID(a_UniqueID),
m_Name(a_Name) m_Name(a_Name),
m_Enchantments(a_Enchantments)
{ {
} }
const int m_UniqueID; const int m_UniqueID;
AString m_Name; AString m_Name;
cEnchantments m_Enchantments;
}; };
/** The type of projectile I am */ /** The type of projectile I am */

View File

@ -12,8 +12,8 @@
typedef std::list< cFurnaceRecipe::Recipe > RecipeList; typedef std::list<cFurnaceRecipe::cRecipe> RecipeList;
typedef std::list< cFurnaceRecipe::Fuel > FuelList; typedef std::list<cFurnaceRecipe::cFuel> FuelList;
@ -30,7 +30,7 @@ struct cFurnaceRecipe::sFurnaceRecipeState
cFurnaceRecipe::cFurnaceRecipe() cFurnaceRecipe::cFurnaceRecipe()
: m_pState( new sFurnaceRecipeState) : m_pState(new sFurnaceRecipeState)
{ {
ReloadRecipes(); ReloadRecipes();
} }
@ -68,12 +68,18 @@ void cFurnaceRecipe::ReloadRecipes(void)
while (std::getline(f, ParsingLine)) while (std::getline(f, ParsingLine))
{ {
LineNum++; LineNum++;
ParsingLine.erase(std::remove_if(ParsingLine.begin(), ParsingLine.end(), isspace), ParsingLine.end()); // Remove ALL whitespace from the line
if (ParsingLine.empty()) if (ParsingLine.empty())
{ {
continue; 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]) switch (ParsingLine[0])
{ {
case '#': 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 AString Line(a_Line);
int IItemID = 0, IItemCount = 0, IItemHealth = 0, IBurnTime = 0; Line.erase(Line.begin()); // Remove the beginning "!"
AString::size_type BeginPos = 1; // Begin at one after exclamation mark (bang) Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
if ( std::auto_ptr<cItem> Item(new cItem);
!ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID int BurnTime;
!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 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; return;
} }
// Add to fuel list: // Add to fuel list:
Fuel F; cFuel Fuel;
F.In = new cItem((ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth); Fuel.In = Item.release();
F.BurnTime = IBurnTime; Fuel.BurnTime = BurnTime;
m_pState->Fuel.push_back(F); 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; AString Line(a_Line);
int OItemID = 0, OItemCount = 0, OItemHealth = 0; Line.erase(std::remove_if(Line.begin(), Line.end(), isspace), Line.end());
AString::size_type BeginPos = 0; // Begin at start of line
if ( int CookTime = 200;
!ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, IItemID) || // Read item ID std::auto_ptr<cItem> InputItem(new cItem());
!ReadOptionalNumbers(BeginPos, ":", "@", a_Line, a_LineNum, IItemCount, IItemHealth) || // Read item count (and optionally health) std::auto_ptr<cItem> OutputItem(new cItem());
!ReadMandatoryNumber(BeginPos, "=", a_Line, a_LineNum, IBurnTime) || // Read item burn time
!ReadMandatoryNumber(BeginPos, ":", a_Line, a_LineNum, OItemID) || // Read result ID const AStringVector & Sides = StringSplit(Line, "=");
!ReadOptionalNumbers(BeginPos, ":", "012456789", a_Line, a_LineNum, OItemCount, OItemHealth, true) // Read result count (and optionally health) - last value 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; return;
} }
// Add to recipe list const AStringVector & InputSplit = StringSplit(Sides[0], "@");
Recipe R; if (!ParseItem(InputSplit[0], *InputItem))
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)
{ {
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 (!StringToInteger<int>(InputSplit[1], CookTime))
if (End == AString::npos) {
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; 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; 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) void cFurnaceRecipe::ClearRecipes(void)
{ {
for (RecipeList::iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr) for (RecipeList::iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
{ {
Recipe R = *itr; cRecipe Recipe = *itr;
delete R.In; delete Recipe.In;
R.In = NULL; Recipe.In = NULL;
delete R.Out; delete Recipe.Out;
R.Out = NULL; Recipe.Out = NULL;
} }
m_pState->Recipes.clear(); m_pState->Recipes.clear();
for (FuelList::iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr) for (FuelList::iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
{ {
Fuel F = *itr; cFuel Fuel = *itr;
delete F.In; delete Fuel.In;
F.In = NULL; Fuel.In = NULL;
} }
m_pState->Fuel.clear(); 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) for (RecipeList::const_iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr)
{ {
const Recipe & R = *itr; const cRecipe & Recipe = *itr;
if ((R.In->m_ItemType == a_Ingredient.m_ItemType) && (R.In->m_ItemCount <= a_Ingredient.m_ItemCount)) 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; continue;
} }
else else
{ {
BestRecipe = &R; BestRecipe = &Recipe;
} }
} }
} }
@ -317,16 +296,16 @@ int cFurnaceRecipe::GetBurnTime(const cItem & a_Fuel) const
int BestFuel = 0; int BestFuel = 0;
for (FuelList::const_iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr) for (FuelList::const_iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr)
{ {
const Fuel & F = *itr; const cFuel & Fuel = *itr;
if ((F.In->m_ItemType == a_Fuel.m_ItemType) && (F.In->m_ItemCount <= a_Fuel.m_ItemCount)) 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; continue;
} }
else else
{ {
BestFuel = F.BurnTime; BestFuel = Fuel.BurnTime;
} }
} }
} }

View File

@ -19,23 +19,23 @@ public:
void ReloadRecipes(void); void ReloadRecipes(void);
struct Fuel struct cFuel
{ {
cItem * In; cItem * In;
int BurnTime; ///< How long this fuel burns, in ticks int BurnTime; ///< How long this fuel burns, in ticks
}; };
struct Recipe struct cRecipe
{ {
cItem * In; cItem * In;
cItem * Out; cItem * Out;
int CookTime; ///< How long this recipe takes to smelt, in ticks int CookTime; ///< How long this recipe takes to smelt, in ticks
}; };
/// Returns a recipe for the specified input, NULL if no recipe found /** Returns a recipe for the specified input, NULL if no recipe found */
const Recipe * GetRecipeFrom(const cItem & a_Ingredient) const; 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; int GetBurnTime(const cItem & a_Fuel) const;
private: private:
@ -43,33 +43,14 @@ private:
/** Parses the fuel contained in the line, adds it to m_pState's fuels. /** Parses the fuel contained in the line, adds it to m_pState's fuels.
Logs a warning to the console on input error. */ 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. /** Parses the recipe contained in the line, adds it to m_pState's recipes.
Logs a warning to the console on input error. */ Logs a warning to the console on input error. */
void AddRecipeFromLine(const AString & a_Line, int a_LineNum); void AddRecipeFromLine(const AString & a_Line, unsigned 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);
/** 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; struct sFurnaceRecipeState;
sFurnaceRecipeState * m_pState; sFurnaceRecipeState * m_pState;

View File

@ -75,7 +75,6 @@ public:
Arrow = NULL; Arrow = NULL;
return; return;
} }
a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force); a_Player->GetWorld()->BroadcastSoundEffect("random.bow", a_Player->GetPosX(), a_Player->GetPosY(), a_Player->GetPosZ(), 0.5, (float)Force);
if (!a_Player->IsGameModeCreative()) if (!a_Player->IsGameModeCreative())
{ {
@ -83,8 +82,19 @@ public:
{ {
a_Player->GetInventory().RemoveItem(cItem(E_ITEM_ARROW)); a_Player->GetInventory().RemoveItem(cItem(E_ITEM_ARROW));
} }
else
{
Arrow->SetPickupState(cArrowEntity::psNoPickup);
}
a_Player->UseEquippedItem(); a_Player->UseEquippedItem();
} }
if (a_Player->GetEquippedItem().m_Enchantments.GetLevel(cEnchantments::enchFlame) > 0)
{
Arrow->StartBurning(100);
}
} }
} ; } ;

View File

@ -158,7 +158,8 @@ cMojangAPI::cMojangAPI(void) :
m_NameToUUIDServer(DEFAULT_NAME_TO_UUID_SERVER), m_NameToUUIDServer(DEFAULT_NAME_TO_UUID_SERVER),
m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS), m_NameToUUIDAddress(DEFAULT_NAME_TO_UUID_ADDRESS),
m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER), m_UUIDToProfileServer(DEFAULT_UUID_TO_PROFILE_SERVER),
m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS) m_UUIDToProfileAddress(DEFAULT_UUID_TO_PROFILE_ADDRESS),
m_RankMgr(NULL)
{ {
} }

View File

@ -979,9 +979,18 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
AString ServerAddress; AString ServerAddress;
short ServerPort; short ServerPort;
UInt32 NextState; UInt32 NextState;
m_Buffer.ReadVarUTF8String(ServerAddress); if (!m_Buffer.ReadVarUTF8String(ServerAddress))
m_Buffer.ReadBEShort(ServerPort); {
m_Buffer.ReadVarInt(NextState); break;
}
if (!m_Buffer.ReadBEShort(ServerPort))
{
break;
}
if (!m_Buffer.ReadVarInt(NextState))
{
break;
}
m_Buffer.CommitRead(); m_Buffer.CommitRead();
m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState); m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
return true; return true;
@ -991,9 +1000,18 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
AString ServerAddress; AString ServerAddress;
short ServerPort; short ServerPort;
UInt32 NextState; UInt32 NextState;
m_Buffer.ReadVarUTF8String(ServerAddress); if (!m_Buffer.ReadVarUTF8String(ServerAddress))
m_Buffer.ReadBEShort(ServerPort); {
m_Buffer.ReadVarInt(NextState); break;
}
if (!m_Buffer.ReadBEShort(ServerPort))
{
break;
}
if (!m_Buffer.ReadVarInt(NextState))
{
break;
}
m_Buffer.CommitRead(); m_Buffer.CommitRead();
m_Protocol = new cProtocol176(m_Client, ServerAddress, (UInt16)ServerPort, NextState); m_Protocol = new cProtocol176(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
return true; return true;

View File

@ -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 = ?"); 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.bind(1, a_PlayerUUID);
stmt.executeStep(); // executeStep returns false on no data
if (stmt.isDone()) if (!stmt.executeStep())
{ {
// No data returned from the DB // No data returned from the DB
return AString(); return AString();

View File

@ -134,8 +134,8 @@ void cSetChunkData::RemoveInvalidBlockEntities(void)
); );
cBlockEntityList::iterator itr2 = itr; cBlockEntityList::iterator itr2 = itr;
itr2++; itr2++;
m_BlockEntities.erase(itr);
delete *itr; delete *itr;
m_BlockEntities.erase(itr);
itr = itr2; itr = itr2;
} }
else else

View File

@ -45,7 +45,7 @@ int main(int argc, char ** argv)
BLOCKTYPE * WritePosition = &TestBuffer[WritePosIdx]; BLOCKTYPE * WritePosition = &TestBuffer[WritePosIdx];
memset(TestBuffer, 0x03, sizeof(TestBuffer)); memset(TestBuffer, 0x03, sizeof(TestBuffer));
size_t LastReportedStep = 1; 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) if (idx / 500 != LastReportedStep)
{ {
@ -53,7 +53,7 @@ int main(int argc, char ** argv)
LastReportedStep = idx / 500; 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); Data.CopyBlockTypes(WritePosition, idx, len);