diff --git a/contrib/png-it.py b/contrib/png-it.py index fa3c393..3e62312 100644 --- a/contrib/png-it.py +++ b/contrib/png-it.py @@ -27,6 +27,9 @@ def main(): parser.add_option('--center', '-e', help = 'Mark what will be the center of the image, two percentage values comma separated',\ metavar = '
', type = str, dest = 'center', default = None) + parser.add_option('--autocrop', '-a', help = 'Calculates the center and crop vales automatically to show all the tiles in the minimun image size.Unless you want a very specific image this options is very recommendedable.',\ + action = 'store_true', dest = 'autocrop', default = False) + parser.add_option('--output', '-o', help = 'Path for the resulting PNG. It will save it as PNG, no matter what extension do you use.',\ metavar = '', type = str, dest = 'output', default = "output.png") @@ -43,6 +46,9 @@ def main(): if not options.zoom_level: parser.error("Error! The option zoom-level is mandatory.") + if options.autocrop and (options.center or options.crop): + parser.error("Error! You can't mix --autocrop with --center or --crop.") + # check for the output folder, filename = split(options.output) if folder != '' and not exists(folder): @@ -54,32 +60,6 @@ def main(): tile_size = (384,384) px_size = 4 # bytes - # the vector that joins the center tile with the new center tile in - # tile coords (tile coords is how many tile are on the left, x, and - # how many above, y. The top-left tile has coords (0,0) - if options.center: - center_x, center_y = options.center.split(",") - center_x = int(center_x) - center_y = int(center_y) - center_tile_x = int(2**n*(center_x/100.)) - center_tile_y = int(2**n*(center_y/100.)) - center_vector = (int(center_tile_x - length_in_tiles/2.), int(center_tile_y - length_in_tiles/2.)) - else: - center_vector = (0,0) - - tiles_to_crop = int(2**n*(options.crop/100.)) - crop = (tiles_to_crop, tiles_to_crop) - - final_img_size = (tile_size[0]*length_in_tiles,tile_size[1]*length_in_tiles) - final_cropped_img_size = (final_img_size[0] - 2*crop[0]*tile_size[0],final_img_size[1] - 2*crop[1]*tile_size[1]) - - mem = final_cropped_img_size[0]*final_cropped_img_size[1]*px_size # bytes! - print "The image size will be {0}x{1}".format(final_cropped_img_size[0],final_cropped_img_size[1]) - print "A total of {0} MB of memory will be used.".format(mem/1024**2) - if mem/1024.**2. > options.memory_limit: - print "Warning! The expected RAM usage exceeds the spicifyed limit. Exiting." - sys.exit(1) - # create a list with all the images in the zoom level path = tileset for i in range(options.zoom_level): @@ -91,6 +71,64 @@ def main(): "Error! No images found in this zoom leve. Is this really an overviewer tile set directory?" sys.exit(1) + # autocrop will calculate the center and crop values automagically + if options.autocrop: + min_x = min_y = length_in_tiles + max_x = max_y = 0 + counter = 0 + total = len(all_images) + print "Checking tiles for autocrop calculations:" + # get the maximun and minimun tiles coordinates of the map + for path in all_images: + t = get_tuple_coords(options, path) + c = get_tile_coords_from_tuple(options, t) + min_x = min(min_x, c[0]) + min_y = min(min_y, c[1]) + max_x = max(max_x, c[0]) + max_y = max(max_y, c[1]) + counter += 1 + if (counter % 100 == 0 or counter == total or counter == 1): print "Checked {0} of {1}".format(counter, total) + + # the center of the map will be in the middle of the occupied zone + center = (int((min_x + max_x)/2.), int((min_y + max_y)/2.)) + # see the next next comment to know what's center_vector + center_vector = (int(center[0] - (length_in_tiles/2. - 1)), int(center[1] - (length_in_tiles/2. - 1))) + # I'm not completely sure why, but the - 1 factor in ^ makes everything nicer. + + # min_x - center_vector[0] will be the unused amount of tiles in + # the left and the right of the map (and this is true because we + # are in the actual center of the map) + crop = (min_x - center_vector[0], min_y - center_vector[1]) + + else: + # center_vector is the vector that joins the center tile with + # the new center tile in tile coords + #(tile coords are how many tile are on the left, x, and + # how many above, y. The top-left tile has coords (0,0) + if options.center: + center_x, center_y = options.center.split(",") + center_x = int(center_x) + center_y = int(center_y) + center_tile_x = int(2**n*(center_x/100.)) + center_tile_y = int(2**n*(center_y/100.)) + center_vector = (int(center_tile_x - length_in_tiles/2.), int(center_tile_y - length_in_tiles/2.)) + else: + center_vector = (0,0) + + # crop if needed + tiles_to_crop = int(2**n*(options.crop/100.)) + crop = (tiles_to_crop, tiles_to_crop) + + final_img_size = (tile_size[0]*length_in_tiles,tile_size[1]*length_in_tiles) + final_cropped_img_size = (final_img_size[0] - 2*crop[0]*tile_size[0],final_img_size[1] - 2*crop[1]*tile_size[1]) + + mem = final_cropped_img_size[0]*final_cropped_img_size[1]*px_size # bytes! + print "The image size will be {0}x{1}".format(final_cropped_img_size[0],final_cropped_img_size[1]) + print "A total of {0} MB of memory will be used.".format(mem/1024**2) + if mem/1024.**2. > options.memory_limit: + print "Warning! The expected RAM usage exceeds the spicifyed limit. Exiting." + sys.exit(1) + # Create a new huge image final_img = Image.new("RGBA", final_cropped_img_size, (26, 26, 26, 0)) diff --git a/overviewer_core/src/iterate.c b/overviewer_core/src/iterate.c index 4b1f313..2bc0a23 100644 --- a/overviewer_core/src/iterate.c +++ b/overviewer_core/src/iterate.c @@ -298,8 +298,8 @@ generate_pseudo_data(RenderState *state, unsigned char ancilData) { above_level_data = check_adjacent_blocks(state, x, y+1, z, state->block); } /* else above_level_data = 0 */ - /* check connection with same level */ - same_level_data = check_adjacent_blocks(state, x, y, z, 55); + /* check connection with same level (other redstone and trapped chests */ + same_level_data = check_adjacent_blocks(state, x, y, z, 55) | check_adjacent_blocks(state, x, y, z, 146); /* check the posibility of connection with y-1 level, check for air */ possibly_connected = check_adjacent_blocks(state, x, y, z, 0); diff --git a/overviewer_core/src/primitives/lighting.c b/overviewer_core/src/primitives/lighting.c index d264ae7..beffff9 100644 --- a/overviewer_core/src/primitives/lighting.c +++ b/overviewer_core/src/primitives/lighting.c @@ -158,8 +158,9 @@ get_lighting_color(RenderPrimitiveLighting *self, RenderState *state, blocklevel = get_data(state, BLOCKLIGHT, x, y, z); /* special half-step handling, stairs handling */ + /* Anvil also needs to be here, blockid 145 */ if (block == 44 || block == 53 || block == 67 || block == 108 || block == 109 || block == 114 || - block == 128 || block == 134 || block == 135 || block == 136) { + block == 128 || block == 134 || block == 135 || block == 136 || block == 145 || block == 156) { unsigned int upper_block; /* stairs and half-blocks take the skylevel from the upper block if it's transparent */ @@ -170,7 +171,7 @@ get_lighting_color(RenderPrimitiveLighting *self, RenderState *state, upper_block = get_data(state, BLOCKS, x, y + upper_counter, z); } while (upper_block == 44 || upper_block == 53 || upper_block == 67 || upper_block == 108 || upper_block == 109 || upper_block == 114 || upper_block == 128 || upper_block == 134 || - upper_block == 135 || upper_block == 136); + upper_block == 135 || upper_block == 136 || upper_block == 156 ); if (is_transparent(upper_block)) { skylevel = get_data(state, SKYLIGHT, x, y + upper_counter, z); } else { diff --git a/overviewer_core/textures.py b/overviewer_core/textures.py index f55c041..b352425 100644 --- a/overviewer_core/textures.py +++ b/overviewer_core/textures.py @@ -53,6 +53,9 @@ class Textures(object): # this is set in in generate() self.generated = False + + # see load_image_texture() + self.texture_cache = {} ## ## pickle support @@ -61,7 +64,7 @@ class Textures(object): def __getstate__(self): # we must get rid of the huge image lists, and other images attributes = self.__dict__.copy() - for attr in ['terrain_images', 'blockmap', 'biome_grass_texture', 'watertexture', 'lavatexture', 'firetexture', 'portaltexture', 'lightcolor', 'grasscolor', 'foliagecolor', 'watercolor']: + for attr in ['blockmap', 'biome_grass_texture', 'watertexture', 'lavatexture', 'firetexture', 'portaltexture', 'lightcolor', 'grasscolor', 'foliagecolor', 'watercolor', 'texture_cache']: try: del attributes[attr] except KeyError: @@ -71,6 +74,7 @@ class Textures(object): # regenerate textures, if needed for attr, val in attrs.iteritems(): setattr(self, attr, val) + self.texture_cache = {} if self.generated: self.generate() @@ -79,11 +83,9 @@ class Textures(object): ## def generate(self): - # maps terrainids to 16x16 images - self.terrain_images = self._split_terrain(self.load_image("terrain.png")) # generate biome grass mask - self.biome_grass_texture = self.build_block(self.terrain_images[0], self.terrain_images[38]) + self.biome_grass_texture = self.build_block(self.load_image_texture("textures/blocks/grass_top.png"), self.load_image_texture("textures/blocks/grass_side_overlay.png")) # generate the blocks global blockmap_generators @@ -220,11 +222,33 @@ class Textures(object): raise TextureException("Could not find the file `{0}'. Try specifying the 'texturepath' option in your config file. Set it to the directory where I can find {0}. Also see ".format(filename)) + def load_image_texture(self, filename): + # Textures may be animated or in a different resolution than 16x16. + # This method will always return a 16x16 image + if filename in self.texture_cache: + return self.texture_cache[filename] + + img = self.load_image(filename) + + w,h = img.size + if w != h: + img = img.crop((0,0,w,w)) + if w != 16: + img = img.resize((16, 16), Image.ANTIALIAS) + + self.texture_cache[filename] = img + return img + def load_image(self, filename): """Returns an image object""" + + fileobj = self.find_file(filename) buffer = StringIO(fileobj.read()) - return Image.open(buffer).convert("RGBA") + img = Image.open(buffer).convert("RGBA") + return img + + def load_water(self): """Special-case function for loading water, handles @@ -701,45 +725,45 @@ def material(blockid=[], data=[0], **kwargs): return inner_material # shortcut function for pure blocks, default to solid, nodata -def block(blockid=[], top_index=None, side_index=None, **kwargs): +def block(blockid=[], top_image=None, side_image=None, **kwargs): new_kwargs = {'solid' : True, 'nodata' : True} new_kwargs.update(kwargs) - if top_index is None: - raise ValueError("top_index was not provided") + if top_image is None: + raise ValueError("top_image was not provided") - if side_index is None: - side_index = top_index + if side_image is None: + side_image = top_image @material(blockid=blockid, **new_kwargs) def inner_block(self, unused_id, unused_data): - return self.build_block(self.terrain_images[top_index], self.terrain_images[side_index]) + return self.build_block(self.load_image_texture(top_image), self.load_image_texture(side_image)) return inner_block # shortcut function for sprite blocks, defaults to transparent, nodata -def sprite(blockid=[], index=None, **kwargs): +def sprite(blockid=[], imagename=None, **kwargs): new_kwargs = {'transparent' : True, 'nodata' : True} new_kwargs.update(kwargs) - if index is None: - raise ValueError("index was not provided") + if imagename is None: + raise ValueError("imagename was not provided") @material(blockid=blockid, **new_kwargs) def inner_sprite(self, unused_id, unused_data): - return self.build_sprite(self.terrain_images[index]) + return self.build_sprite(self.load_image_texture(imagename)) return inner_sprite # shortcut function for billboard blocks, defaults to transparent, nodata -def billboard(blockid=[], index=None, **kwargs): +def billboard(blockid=[], imagename=None, **kwargs): new_kwargs = {'transparent' : True, 'nodata' : True} new_kwargs.update(kwargs) - if index is None: - raise ValueError("index was not provided") + if imagename is None: + raise ValueError("imagename was not provided") @material(blockid=blockid, **new_kwargs) def inner_billboard(self, unused_id, unused_data): - return self.build_billboard(self.terrain_images[index]) + return self.build_billboard(self.load_image_texture(imagename)) return inner_billboard ## @@ -747,51 +771,51 @@ def billboard(blockid=[], index=None, **kwargs): ## # stone -block(blockid=1, top_index=1) +block(blockid=1, top_image="textures/blocks/stone.png") @material(blockid=2, data=range(11)+[0x10,], solid=True) def grass(self, blockid, data): # 0x10 bit means SNOW - side_img = self.terrain_images[3] + side_img = self.load_image_texture("textures/blocks/grass_side.png") if data & 0x10: - side_img = self.terrain_images[68] - img = self.build_block(self.terrain_images[0], side_img) + side_img = self.load_image_texture("textures/blocks/snow_side.png") + img = self.build_block(self.load_image_texture("textures/blocks/grass_top.png"), side_img) if not data & 0x10: alpha_over(img, self.biome_grass_texture, (0, 0), self.biome_grass_texture) return img # dirt -block(blockid=3, top_index=2) +block(blockid=3, top_image="textures/blocks/dirt.png") # cobblestone -block(blockid=4, top_index=16) +block(blockid=4, top_image="textures/blocks/stonebrick.png") # wooden planks @material(blockid=5, data=range(4), solid=True) def wooden_planks(self, blockid, data): if data == 0: # normal - return self.build_block(self.terrain_images[4],self.terrain_images[4]) + return self.build_block(self.load_image_texture("textures/blocks/wood.png"), self.load_image_texture("textures/blocks/wood.png")) if data == 1: # pine - return self.build_block(self.terrain_images[198],self.terrain_images[198]) + return self.build_block(self.load_image_texture("textures/blocks/wood_spruce.png"),self.load_image_texture("textures/blocks/wood_spruce.png")) if data == 2: # birch - return self.build_block(self.terrain_images[214],self.terrain_images[214]) + return self.build_block(self.load_image_texture("textures/blocks/wood_birch.png"),self.load_image_texture("textures/blocks/wood_birch.png")) if data == 3: # jungle wood - return self.build_block(self.terrain_images[199],self.terrain_images[199]) + return self.build_block(self.load_image_texture("textures/blocks/wood_jungle.png"),self.load_image_texture("textures/blocks/wood_jungle.png")) @material(blockid=6, data=range(16), transparent=True) def saplings(self, blockid, data): # usual saplings - tex = self.terrain_images[15] + tex = self.load_image_texture("textures/blocks/sapling.png") if data & 0x3 == 1: # spruce sapling - tex = self.terrain_images[63] + tex = self.load_image_texture("textures/blocks/sapling_spruce.png") elif data & 0x3 == 2: # birch sapling - tex = self.terrain_images[79] + tex = self.load_image_texture("textures/blocks/sapling_birch.png") elif data & 0x3 == 3: # jungle sapling - tex = self.terrain_images[30] + tex = self.load_image_texture("textures/blocks/sapling_jungle.png") return self.build_sprite(tex) # bedrock -block(blockid=7, top_index=17) +block(blockid=7, top_image="textures/blocks/bedrock.png") @material(blockid=8, data=range(16), fluid=True, transparent=True, nospawn=True) def water(self, blockid, data): @@ -805,9 +829,9 @@ def no_inner_surfaces(self, blockid, data): if blockid == 9: texture = self.load_water() elif blockid == 20: - texture = self.terrain_images[49] + texture = self.load_image_texture("textures/blocks/glass.png") else: - texture = self.terrain_images[67] + texture = self.load_image_texture("textures/blocks/ice.png") if (data & 0b10000) == 16: top = texture @@ -847,15 +871,15 @@ def lava(self, blockid, data): return self.build_block(lavatex, lavatex) # sand -block(blockid=12, top_index=18) +block(blockid=12, top_image="textures/blocks/sand.png") # gravel -block(blockid=13, top_index=19) +block(blockid=13, top_image="textures/blocks/gravel.png") # gold ore -block(blockid=14, top_index=32) +block(blockid=14, top_image="textures/blocks/oreGold.png") # iron ore -block(blockid=15, top_index=33) +block(blockid=15, top_image="textures/blocks/oreIron.png") # coal ore -block(blockid=16, top_index=34) +block(blockid=16, top_image="textures/blocks/oreCoal.png") @material(blockid=17, data=range(12), solid=True) def wood(self, blockid, data): @@ -870,15 +894,15 @@ def wood(self, blockid, data): elif wood_orientation == 8: wood_orientation = 4 # choose textures - top = self.terrain_images[21] + top = self.load_image_texture("textures/blocks/tree_top.png") if wood_type == 0: # normal - side = self.terrain_images[20] - if wood_type == 1: # birch - side = self.terrain_images[116] - if wood_type == 2: # pine - side = self.terrain_images[117] + side = self.load_image_texture("textures/blocks/tree_side.png") + if wood_type == 1: # spruce + side = self.load_image_texture("textures/blocks/tree_spruce.png") + if wood_type == 2: # birch + side = self.load_image_texture("textures/blocks/tree_birch.png") if wood_type == 3: # jungle wood - side = self.terrain_images[153] + side = self.load_image_texture("textures/blocks/tree_jungle.png") # choose orientation and paste textures if wood_orientation == 0: @@ -893,24 +917,24 @@ def leaves(self, blockid, data): # mask out the bits 4 and 8 # they are used for player placed and check-for-decay blocks data = data & 0x3 - t = self.terrain_images[52] + t = self.load_image_texture("textures/blocks/leaves.png") if data == 1: # pine! - t = self.terrain_images[132] + t = self.load_image_texture("textures/blocks/leaves_spruce.png") elif data == 3: # jungle tree - t = self.terrain_images[196] + t = self.load_image_texture("textures/blocks/leaves_jungle.png") return self.build_block(t, t) # sponge -block(blockid=19, top_index=48) +block(blockid=19, top_image="textures/blocks/sponge.png") # lapis lazuli ore -block(blockid=21, top_index=160) +block(blockid=21, top_image="textures/blocks/oreLapis.png") # lapis lazuli block -block(blockid=22, top_index=144) +block(blockid=22, top_image="textures/blocks/blockLapis.png") -# dispensers, furnaces, and burning furnaces -@material(blockid=[23, 61, 62], data=range(6), solid=True) +# dispensers, dropper, furnaces, and burning furnaces +@material(blockid=[23, 61, 62, 158], data=range(6), solid=True) def furnaces(self, blockid, data): # first, do the rotation if needed if self.rotation == 1: @@ -929,15 +953,27 @@ def furnaces(self, blockid, data): elif data == 4: data = 3 elif data == 5: data = 2 - top = self.terrain_images[62] - side = self.terrain_images[45] + top = self.load_image_texture("textures/blocks/furnace_top.png") + side = self.load_image_texture("textures/blocks/furnace_side.png") if blockid == 61: - front = self.terrain_images[44] + front = self.load_image_texture("textures/blocks/furnace_front.png") elif blockid == 62: - front = self.terrain_images[61] + front = self.load_image_texture("textures/blocks/furnace_front_lit.png") elif blockid == 23: - front = self.terrain_images[46] + front = self.load_image_texture("textures/blocks/dispenser_front.png") + if data == 0: # dispenser pointing down + return self.build_block(top, top) + elif data == 1: # dispenser pointing up + dispenser_top = self.load_image_texture("textures/blocks/dispenser_front_vertical.png") + return self.build_block(dispenser_top, top) + elif blockid == 158: + front = self.load_image_texture("textures/blocks/dropper_front.png") + if data == 0: # dropper pointing down + return self.build_block(top, top) + elif data == 1: # dispenser pointing up + dropper_top = self.load_image_texture("textures/blocks/dropper_front_vertical.png") + return self.build_block(dropper_top, top) if data == 3: # pointing west return self.build_full_block(top, None, None, side, front) @@ -949,16 +985,16 @@ def furnaces(self, blockid, data): # sandstone @material(blockid=24, data=range(3), solid=True) def sandstone(self, blockid, data): - top = self.terrain_images[176] + top = self.load_image_texture("textures/blocks/sandstone_top.png") if data == 0: # normal - return self.build_block(top, self.terrain_images[192]) + return self.build_block(top, self.load_image_texture("textures/blocks/sandstone_side.png")) if data == 1: # hieroglyphic - return self.build_block(top, self.terrain_images[229]) + return self.build_block(top, self.load_image_texture("textures/blocks/sandstone_carved.png")) if data == 2: # soft - return self.build_block(top, self.terrain_images[230]) + return self.build_block(top, self.load_image_texture("textures/blocks/sandstone_smooth.png")) # note block -block(blockid=25, top_index=74) +block(blockid=25, top_image="textures/blocks/musicBlock.png") @material(blockid=26, data=range(12), transparent=True, nospawn=True) def bed(self, blockid, data): @@ -984,46 +1020,46 @@ def bed(self, blockid, data): left_face = None right_face = None if data & 0x8 == 0x8: # head of the bed - top = self.terrain_images[135] + top = self.load_image_texture("textures/blocks/bed_head_top.png") if data & 0x00 == 0x00: # head pointing to West top = top.copy().rotate(270) - left_face = self.terrain_images[151] - right_face = self.terrain_images[152] + left_face = self.load_image_texture("textures/blocks/bed_head_side.png") + right_face = self.load_image_texture("textures/blocks/bed_head_end.png") if data & 0x01 == 0x01: # ... North top = top.rotate(270) - left_face = self.terrain_images[152] - right_face = self.terrain_images[151] + left_face = self.load_image_texture("textures/blocks/bed_head_end.png") + right_face = self.load_image_texture("textures/blocks/bed_head_side.png") if data & 0x02 == 0x02: # East top = top.rotate(180) - left_face = self.terrain_images[151].transpose(Image.FLIP_LEFT_RIGHT) + left_face = self.load_image_texture("textures/blocks/bed_head_side.png").transpose(Image.FLIP_LEFT_RIGHT) right_face = None if data & 0x03 == 0x03: # South right_face = None - right_face = self.terrain_images[151].transpose(Image.FLIP_LEFT_RIGHT) + right_face = self.load_image_texture("textures/blocks/bed_head_side.png").transpose(Image.FLIP_LEFT_RIGHT) else: # foot of the bed - top = self.terrain_images[134] + top = self.load_image_texture("textures/blocks/bed_feet_top.png") if data & 0x00 == 0x00: # head pointing to West top = top.rotate(270) - left_face = self.terrain_images[150] + left_face = self.load_image_texture("textures/blocks/bed_feet_side.png") right_face = None if data & 0x01 == 0x01: # ... North top = top.rotate(270) left_face = None - right_face = self.terrain_images[150] + right_face = self.load_image_texture("textures/blocks/bed_feet_side.png") if data & 0x02 == 0x02: # East top = top.rotate(180) - left_face = self.terrain_images[150].transpose(Image.FLIP_LEFT_RIGHT) - right_face = self.terrain_images[149].transpose(Image.FLIP_LEFT_RIGHT) + left_face = self.load_image_texture("textures/blocks/bed_feet_side.png").transpose(Image.FLIP_LEFT_RIGHT) + right_face = self.load_image_texture("textures/blocks/bed_feet_end.png").transpose(Image.FLIP_LEFT_RIGHT) if data & 0x03 == 0x03: # South - left_face = self.terrain_images[149] - right_face = self.terrain_images[150].transpose(Image.FLIP_LEFT_RIGHT) + left_face = self.load_image_texture("textures/blocks/bed_feet_end.png") + right_face = self.load_image_texture("textures/blocks/bed_feet_side.png").transpose(Image.FLIP_LEFT_RIGHT) top = (top, increment) return self.build_full_block(top, None, None, left_face, right_face) -# powered, detector, and normal rails -@material(blockid=[27, 28, 66], data=range(14), transparent=True) +# powered, detector, activator and normal rails +@material(blockid=[27, 28, 66, 157], data=range(14), transparent=True) def rails(self, blockid, data): # first, do rotation # Masked to not clobber powered rail on/off info @@ -1068,22 +1104,33 @@ def rails(self, blockid, data): if blockid == 27: # powered rail if data & 0x8 == 0: # unpowered - raw_straight = self.terrain_images[163] - raw_corner = self.terrain_images[112] # they don't exist but make the code + raw_straight = self.load_image_texture("textures/blocks/goldenRail.png") + raw_corner = self.load_image_texture("textures/blocks/rail_turn.png") # they don't exist but make the code # much simplier elif data & 0x8 == 0x8: # powered - raw_straight = self.terrain_images[179] - raw_corner = self.terrain_images[112] # leave corners for code simplicity + raw_straight = self.load_image_texture("textures/blocks/goldenRail_powered.png") + raw_corner = self.load_image_texture("textures/blocks/rail_turn.png") # leave corners for code simplicity # filter the 'powered' bit data = data & 0x7 elif blockid == 28: # detector rail - raw_straight = self.terrain_images[195] - raw_corner = self.terrain_images[112] # leave corners for code simplicity + raw_straight = self.load_image_texture("textures/blocks/detectorRail.png") + raw_corner = self.load_image_texture("textures/blocks/rail_turn.png") # leave corners for code simplicity elif blockid == 66: # normal rail - raw_straight = self.terrain_images[128] - raw_corner = self.terrain_images[112] + raw_straight = self.load_image_texture("textures/blocks/rail.png") + raw_corner = self.load_image_texture("textures/blocks/rail_turn.png") + + elif blockid == 157: # activator rail + if data & 0x8 == 0: # unpowered + raw_straight = self.load_image_texture("textures/blocks/activatorRail.png") + raw_corner = self.load_image_texture("textures/blocks/rail_turn.png") # they don't exist but make the code + # much simplier + elif data & 0x8 == 0x8: # powered + raw_straight = self.load_image_texture("textures/blocks/activatorRail_powered.png") + raw_corner = self.load_image_texture("textures/blocks/rail_turn.png") # leave corners for code simplicity + # filter the 'powered' bit + data = data & 0x7 ## use transform_image to scale and shear if data == 0: @@ -1151,14 +1198,14 @@ def piston(self, blockid, data): elif (data & 0b0111) == 5: data = data & 0b1000 | 2 if blockid == 29: # sticky - piston_t = self.terrain_images[106].copy() + piston_t = self.load_image_texture("textures/blocks/piston_top_sticky.png").copy() else: # normal - piston_t = self.terrain_images[107].copy() + piston_t = self.load_image_texture("textures/blocks/piston_top.png").copy() # other textures - side_t = self.terrain_images[108].copy() - back_t = self.terrain_images[109].copy() - interior_t = self.terrain_images[110].copy() + side_t = self.load_image_texture("textures/blocks/piston_side.png").copy() + back_t = self.load_image_texture("textures/blocks/piston_bottom.png").copy() + interior_t = self.load_image_texture("textures/blocks/piston_inner_top.png").copy() if data & 0x08 == 0x08: # pushed out, non full blocks, tricky stuff # remove piston texture from piston body @@ -1227,13 +1274,13 @@ def piston_extension(self, blockid, data): elif (data & 0b0111) == 5: data = data & 0b1000 | 2 if (data & 0x8) == 0x8: # sticky - piston_t = self.terrain_images[106].copy() + piston_t = self.load_image_texture("textures/blocks/piston_top_sticky.png").copy() else: # normal - piston_t = self.terrain_images[107].copy() + piston_t = self.load_image_texture("textures/blocks/piston_top.png").copy() # other textures - side_t = self.terrain_images[108].copy() - back_t = self.terrain_images[107].copy() + side_t = self.load_image_texture("textures/blocks/piston_side.png").copy() + back_t = self.load_image_texture("textures/blocks/piston_top.png").copy() # crop piston body ImageDraw.Draw(side_t).rectangle((0, 4,16,16),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -1293,94 +1340,72 @@ def piston_extension(self, blockid, data): return img # cobweb -sprite(blockid=30, index=11, nospawn=True) +sprite(blockid=30, imagename="textures/blocks/web.png", nospawn=True) @material(blockid=31, data=range(3), transparent=True) def tall_grass(self, blockid, data): if data == 0: # dead shrub - texture = self.terrain_images[55] + texture = self.load_image_texture("textures/blocks/deadbush.png") elif data == 1: # tall grass - texture = self.terrain_images[39] + texture = self.load_image_texture("textures/blocks/tallgrass.png") elif data == 2: # fern - texture = self.terrain_images[56] + texture = self.load_image_texture("textures/blocks/fern.png") return self.build_billboard(texture) # dead bush -billboard(blockid=32, index=55) +billboard(blockid=32, imagename="textures/blocks/deadbush.png") @material(blockid=35, data=range(16), solid=True) def wool(self, blockid, data): - if data == 0: # white - texture = self.terrain_images[64] - elif data == 1: # orange - texture = self.terrain_images[210] - elif data == 2: # magenta - texture = self.terrain_images[194] - elif data == 3: # light blue - texture = self.terrain_images[178] - elif data == 4: # yellow - texture = self.terrain_images[162] - elif data == 5: # light green - texture = self.terrain_images[146] - elif data == 6: # pink - texture = self.terrain_images[130] - elif data == 7: # grey - texture = self.terrain_images[114] - elif data == 8: # light grey - texture = self.terrain_images[225] - elif data == 9: # cyan - texture = self.terrain_images[209] - elif data == 10: # purple - texture = self.terrain_images[193] - elif data == 11: # blue - texture = self.terrain_images[177] - elif data == 12: # brown - texture = self.terrain_images[161] - elif data == 13: # dark green - texture = self.terrain_images[145] - elif data == 14: # red - texture = self.terrain_images[129] - elif data == 15: # black - texture = self.terrain_images[113] + texture = self.load_image_texture("textures/blocks/cloth_%d.png" % data) return self.build_block(texture, texture) # dandelion -sprite(blockid=37, index=13) +sprite(blockid=37, imagename="textures/blocks/flower.png") # rose -sprite(blockid=38, index=12) +sprite(blockid=38, imagename="textures/blocks/rose.png") # brown mushroom -sprite(blockid=39, index=29) +sprite(blockid=39, imagename="textures/blocks/mushroom_brown.png") # red mushroom -sprite(blockid=40, index=28) +sprite(blockid=40, imagename="textures/blocks/mushroom_red.png") # block of gold -block(blockid=41, top_index=23) +block(blockid=41, top_image="textures/blocks/blockGold.png") # block of iron -block(blockid=42, top_index=22) +block(blockid=42, top_image="textures/blocks/blockIron.png") # double slabs and slabs # these wooden slabs are unobtainable without cheating, they are still # here because lots of pre-1.3 worlds use this blocks @material(blockid=[43, 44], data=range(16), transparent=(44,), solid=True) def slabs(self, blockid, data): - texture = data & 7 + if blockid == 44: + texture = data & 7 + else: # data > 8 are special double slabs + texture = data if texture== 0: # stone slab - top = self.terrain_images[6] - side = self.terrain_images[5] - elif texture== 1: # stone slab - top = self.terrain_images[176] - side = self.terrain_images[192] + top = self.load_image_texture("textures/blocks/stoneslab_top.png") + side = self.load_image_texture("textures/blocks/stoneslab_side.png") + elif texture== 1: # smooth stone + top = self.load_image_texture("textures/blocks/sandstone_top.png") + side = self.load_image_texture("textures/blocks/sandstone_side.png") elif texture== 2: # wooden slab - top = side = self.terrain_images[4] - elif texture== 3: # cobblestone slab - top = side = self.terrain_images[16] + top = side = self.load_image_texture("textures/blocks/wood.png") + elif texture== 3: # c43obblestone slab + top = side = self.load_image_texture("textures/blocks/stonebrick.png") elif texture== 4: # brick - top = side = self.terrain_images[7] + top = side = self.load_image_texture("textures/blocks/brick.png") elif texture== 5: # stone brick - top = side = self.terrain_images[54] + top = side = self.load_image_texture("textures/blocks/stonebricksmooth.png") elif texture== 6: # nether brick slab - top = side = self.terrain_images[224] + top = side = self.load_image_texture("textures/blocks/netherBrick.png") + elif texture== 7: #quartz + top = side = self.load_image_texture("textures/blocks/quartzblock_side.png") + elif texture== 8: # special stone double slab with top texture only + top = side = self.load_image_texture("textures/blocks/stoneslab_top.png") + elif texture== 9: # special sandstone double slab with top texture only + top = side = self.load_image_texture("textures/blocks/sandstone_top.png") else: return None @@ -1417,15 +1442,15 @@ def slabs(self, blockid, data): return img # brick block -block(blockid=45, top_index=7) +block(blockid=45, top_image="textures/blocks/brick.png") # TNT -block(blockid=46, top_index=9, side_index=8, nospawn=True) +block(blockid=46, top_image="textures/blocks/tnt_top.png", side_image="textures/blocks/tnt_side.png", nospawn=True) # bookshelf -block(blockid=47, top_index=4, side_index=35) +block(blockid=47, top_image="textures/blocks/wood.png", side_image="textures/blocks/bookshelf.png") # moss stone -block(blockid=48, top_index=36) +block(blockid=48, top_image="textures/blocks/stoneMoss.png") # obsidian -block(blockid=49, top_index=37) +block(blockid=49, top_image="textures/blocks/obsidian.png") # torch, redstone torch (off), redstone torch(on) @material(blockid=[50, 75, 76], data=[1, 2, 3, 4, 5], transparent=True) @@ -1449,11 +1474,11 @@ def torches(self, blockid, data): # choose the proper texture if blockid == 50: # torch - small = self.terrain_images[80] + small = self.load_image_texture("textures/blocks/torch.png") elif blockid == 75: # off redstone torch - small = self.terrain_images[115] + small = self.load_image_texture("textures/blocks/redtorch.png") else: # on redstone torch - small = self.terrain_images[99] + small = self.load_image_texture("textures/blocks/redtorch_lit.png") # compose a torch bigger than the normal # (better for doing transformations) @@ -1515,10 +1540,10 @@ def fire(self, blockid, data): return img # monster spawner -block(blockid=52, top_index=65, transparent=True) +block(blockid=52, top_image="textures/blocks/mobSpawner.png", transparent=True) -# wooden, cobblestone, red brick, stone brick, netherbrick, sandstone, spruce, birch and jungle stairs. -@material(blockid=[53,67,108,109,114,128,134,135,136], data=range(8), transparent=True, solid=True, nospawn=True) +# wooden, cobblestone, red brick, stone brick, netherbrick, sandstone, spruce, birch, jungle and quartz stairs. +@material(blockid=[53,67,108,109,114,128,134,135,136,156], data=range(8), transparent=True, solid=True, nospawn=True) def stairs(self, blockid, data): # first, rotations @@ -1543,23 +1568,25 @@ def stairs(self, blockid, data): data = data | upside_down if blockid == 53: # wooden - texture = self.terrain_images[4] + texture = self.load_image_texture("textures/blocks/wood.png") elif blockid == 67: # cobblestone - texture = self.terrain_images[16] + texture = self.load_image_texture("textures/blocks/stonebrick.png") elif blockid == 108: # red brick stairs - texture = self.terrain_images[7] + texture = self.load_image_texture("textures/blocks/brick.png") elif blockid == 109: # stone brick stairs - texture = self.terrain_images[54] + texture = self.load_image_texture("textures/blocks/stonebricksmooth.png") elif blockid == 114: # netherbrick stairs - texture = self.terrain_images[224] + texture = self.load_image_texture("textures/blocks/netherBrick.png") elif blockid == 128: # sandstone stairs - texture = self.terrain_images[192] + texture = self.load_image_texture("textures/blocks/sandstone_side.png") elif blockid == 134: # spruce wood stairs - texture = self.terrain_images[198] + texture = self.load_image_texture("textures/blocks/wood_spruce.png") elif blockid == 135: # birch wood stairs - texture = self.terrain_images[214] + texture = self.load_image_texture("textures/blocks/wood_birch.png") elif blockid == 136: # jungle good stairs - texture = self.terrain_images[199] + texture = self.load_image_texture("textures/blocks/wood_jungle.png") + elif blockid == 156: # quartz block stairs + texture = self.load_image_texture("textures/blocks/quartzblock_side.png") side = texture.copy() @@ -1570,9 +1597,13 @@ def stairs(self, blockid, data): # sandstone stairs have spcial top texture if blockid == 128: - half_block_u = self.terrain_images[176].copy() - half_block_d = self.terrain_images[176].copy() - texture = self.terrain_images[176].copy() + half_block_u = self.load_image_texture("textures/blocks/sandstone_top.png").copy() + half_block_d = self.load_image_texture("textures/blocks/sandstone_top.png").copy() + texture = self.load_image_texture("textures/blocks/sandstone_top.png").copy() + elif blockid == 156: # also quartz stairs + half_block_u = self.load_image_texture("textures/blocks/quartzblock_top.png").copy() + half_block_d = self.load_image_texture("textures/blocks/quartzblock_top.png").copy() + texture = self.load_image_texture("textures/blocks/quartzblock_top.png").copy() # generate needed geometries ImageDraw.Draw(side).rectangle((0,0,7,6),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -1651,8 +1682,8 @@ def stairs(self, blockid, data): return img -# normal, locked (used in april's fool day) and ender chests chests -@material(blockid=[54,95,130], data=range(30), transparent = True) +# normal, locked (used in april's fool day), ender and trapped chest +@material(blockid=[54,95,130,146], data=range(30), transparent = True) def chests(self, blockid, data): # the first 3 bits are the orientation as stored in minecraft, # bits 0x8 and 0x10 indicate which half of the double chest is it. @@ -1849,18 +1880,18 @@ def chests(self, blockid, data): def wire(self, blockid, data): if data & 0b1000000 == 64: # powered redstone wire - redstone_wire_t = self.terrain_images[165] + redstone_wire_t = self.load_image_texture("textures/blocks/redstoneDust_line.png") redstone_wire_t = self.tint_texture(redstone_wire_t,(255,0,0)) - redstone_cross_t = self.terrain_images[164] + redstone_cross_t = self.load_image_texture("textures/blocks/redstoneDust_cross.png") redstone_cross_t = self.tint_texture(redstone_cross_t,(255,0,0)) else: # unpowered redstone wire - redstone_wire_t = self.terrain_images[165] + redstone_wire_t = self.load_image_texture("textures/blocks/redstoneDust_line.png") redstone_wire_t = self.tint_texture(redstone_wire_t,(48,0,0)) - redstone_cross_t = self.terrain_images[164] + redstone_cross_t = self.load_image_texture("textures/blocks/redstoneDust_cross.png") redstone_cross_t = self.tint_texture(redstone_cross_t,(48,0,0)) # generate an image per redstone direction @@ -1924,17 +1955,17 @@ def wire(self, blockid, data): return img # diamond ore -block(blockid=56, top_index=50) +block(blockid=56, top_image="textures/blocks/oreDiamond.png") # diamond block -block(blockid=57, top_index=24) +block(blockid=57, top_image="textures/blocks/blockDiamond.png") # crafting table # needs two different sides @material(blockid=58, solid=True, nodata=True) def crafting_table(self, blockid, data): - top = self.terrain_images[43] - side3 = self.terrain_images[43+16] - side4 = self.terrain_images[43+16+1] + top = self.load_image_texture("textures/blocks/workbench_top.png") + side3 = self.load_image_texture("textures/blocks/workbench_side.png") + side4 = self.load_image_texture("textures/blocks/workbench_front.png") img = self.build_full_block(top, None, None, side3, side4, None) return img @@ -1942,7 +1973,7 @@ def crafting_table(self, blockid, data): # crops @material(blockid=59, data=range(8), transparent=True, nospawn=True) def crops(self, blockid, data): - raw_crop = self.terrain_images[88+data] + raw_crop = self.load_image_texture("textures/blocks/crops_%d.png" % data) crop1 = self.transform_image_top(raw_crop) crop2 = self.transform_image_side(raw_crop) crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) @@ -1956,10 +1987,10 @@ def crops(self, blockid, data): # farmland @material(blockid=60, data=range(9), solid=True) def farmland(self, blockid, data): - top = self.terrain_images[86] + top = self.load_image_texture("textures/blocks/farmland_wet.png") if data == 0: - top = self.terrain_images[87] - return self.build_block(top, self.terrain_images[2]) + top = self.load_image_texture("textures/blocks/farmland_dry.png") + return self.build_block(top, self.load_image_texture("textures/blocks/dirt.png")) # signposts @material(blockid=63, data=range(16), transparent=True) @@ -1973,7 +2004,7 @@ def signpost(self, blockid, data): elif self.rotation == 3: data = (data + 12) % 16 - texture = self.terrain_images[4].copy() + texture = self.load_image_texture("textures/blocks/wood.png").copy() # cut the planks to the size of a signpost ImageDraw.Draw(texture).rectangle((0,12,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -1986,7 +2017,7 @@ def signpost(self, blockid, data): texture.putpixel((x,y),(0,0,0,255)) # Minecraft uses wood texture for the signpost stick - texture_stick = self.terrain_images[20] + texture_stick = self.load_image_texture("textures/blocks/tree_side.png") texture_stick = texture_stick.resize((12,12), Image.ANTIALIAS) ImageDraw.Draw(texture_stick).rectangle((2,0,12,12),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -2036,9 +2067,9 @@ def door(self, blockid, data): elif (data & 0b00011) == 3: data = data & 0b11100 | 2 if data & 0x8 == 0x8: # top of the door - raw_door = self.terrain_images[81 if blockid == 64 else 82] + raw_door = self.load_image_texture("textures/blocks/%s.png" % ("doorWood_upper" if blockid == 64 else "doorIron_upper")) else: # bottom of the door - raw_door = self.terrain_images[97 if blockid == 64 else 98] + raw_door = self.load_image_texture("textures/blocks/%s.png" % ("doorWood_lower" if blockid == 64 else "doorIron_lower")) # if you want to render all doors as closed, then force # force closed to be True @@ -2158,7 +2189,7 @@ def ladder(self, blockid, data): elif data == 5: data = 2 img = Image.new("RGBA", (24,24), self.bgcolor) - raw_texture = self.terrain_images[83] + raw_texture = self.load_image_texture("textures/blocks/ladder.png") if data == 5: # normally this ladder would be obsured by the block it's attached to @@ -2202,7 +2233,7 @@ def wall_sign(self, blockid, data): # wall sign elif data == 4: data = 3 elif data == 5: data = 2 - texture = self.terrain_images[4].copy() + texture = self.load_image_texture("textures/blocks/wood.png").copy() # cut the planks to the size of a signpost ImageDraw.Draw(texture).rectangle((0,12,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -2272,7 +2303,7 @@ def levers(self, blockid, data): elif data == 6: data = 5 # generate the texture for the base of the lever - t_base = self.terrain_images[16].copy() + t_base = self.load_image_texture("textures/blocks/stonebrick.png").copy() ImageDraw.Draw(t_base).rectangle((0,0,15,3),outline=(0,0,0,0),fill=(0,0,0,0)) ImageDraw.Draw(t_base).rectangle((0,12,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -2280,7 +2311,7 @@ def levers(self, blockid, data): ImageDraw.Draw(t_base).rectangle((11,0,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) # generate the texture for the stick - stick = self.terrain_images[96].copy() + stick = self.load_image_texture("textures/blocks/lever.png").copy() c_stick = Image.new("RGBA", (16,16), self.bgcolor) tmp = ImageEnhance.Brightness(stick).enhance(0.8) @@ -2381,13 +2412,17 @@ def levers(self, blockid, data): return img -# wooden and stone pressure plates -@material(blockid=[70, 72], data=[0,1], transparent=True) +# wooden and stone pressure plates, and weighted pressure plates +@material(blockid=[70, 72,147,148], data=[0,1], transparent=True) def pressure_plate(self, blockid, data): if blockid == 70: # stone - t = self.terrain_images[1].copy() - else: # wooden - t = self.terrain_images[4].copy() + t = self.load_image_texture("textures/blocks/stone.png").copy() + elif blockid == 72: # wooden + t = self.load_image_texture("textures/blocks/wood.png").copy() + elif blockid == 147: # light golden + t = self.load_image_texture("textures/blocks/blockGold.png").copy() + else: # blockid == 148: # heavy iron + t = self.load_image_texture("textures/blocks/blockIron.png").copy() # cut out the outside border, pressure plates are smaller # than a normal block @@ -2413,7 +2448,7 @@ def pressure_plate(self, blockid, data): return img # normal and glowing redstone ore -block(blockid=[73, 74], top_index=51) +block(blockid=[73, 74], top_image="textures/blocks/oreRedstone.png") # stone a wood buttons @material(blockid=(77,143), data=range(16), transparent=True) @@ -2440,9 +2475,9 @@ def buttons(self, blockid, data): elif data == 4: data = 2 if blockid == 77: - t = self.terrain_images[1].copy() + t = self.load_image_texture("textures/blocks/stone.png").copy() else: - t = self.terrain_images[4].copy() + t = self.load_image_texture("textures/blocks/wood.png").copy() # generate the texture for the button ImageDraw.Draw(t).rectangle((0,0,15,5),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -2492,7 +2527,7 @@ def buttons(self, blockid, data): def snow(self, blockid, data): # still not rendered correctly: data other than 0 - tex = self.terrain_images[66] + tex = self.load_image_texture("textures/blocks/snow.png") # make the side image, top 3/4 transparent mask = tex.crop((0,12,16,16)) @@ -2512,13 +2547,13 @@ def snow(self, blockid, data): return img # snow block -block(blockid=80, top_index=66) +block(blockid=80, top_image="textures/blocks/snow.png") # cactus @material(blockid=81, data=range(15), transparent=True, solid=True, nospawn=True) def cactus(self, blockid, data): - top = self.terrain_images[69] - side = self.terrain_images[70] + top = self.load_image_texture("textures/blocks/cactus_top.png") + side = self.load_image_texture("textures/blocks/cactus_side.png") img = Image.new("RGBA", (24,24), self.bgcolor) @@ -2540,18 +2575,18 @@ def cactus(self, blockid, data): return img # clay block -block(blockid=82, top_index=72) +block(blockid=82, top_image="textures/blocks/clay.png") # sugar cane @material(blockid=83, data=range(16), transparent=True) def sugar_cane(self, blockid, data): - tex = self.terrain_images[73] + tex = self.load_image_texture("textures/blocks/reeds.png") return self.build_sprite(tex) # jukebox @material(blockid=84, data=range(16), solid=True) def jukebox(self, blockid, data): - return self.build_block(self.terrain_images[75], self.terrain_images[74]) + return self.build_block(self.load_image_texture("textures/blocks/jukebox_top.png"), self.load_image_texture("textures/blocks/musicBlock.png")) # nether and normal fences # uses pseudo-ancildata found in iterate.c @@ -2560,13 +2595,13 @@ def fence(self, blockid, data): # no need for rotations, it uses pseudo data. # create needed images for Big stick fence if blockid == 85: # normal fence - fence_top = self.terrain_images[4].copy() - fence_side = self.terrain_images[4].copy() - fence_small_side = self.terrain_images[4].copy() + fence_top = self.load_image_texture("textures/blocks/wood.png").copy() + fence_side = self.load_image_texture("textures/blocks/wood.png").copy() + fence_small_side = self.load_image_texture("textures/blocks/wood.png").copy() else: # netherbrick fence - fence_top = self.terrain_images[224].copy() - fence_side = self.terrain_images[224].copy() - fence_small_side = self.terrain_images[224].copy() + fence_top = self.load_image_texture("textures/blocks/netherBrick.png").copy() + fence_side = self.load_image_texture("textures/blocks/netherBrick.png").copy() + fence_small_side = self.load_image_texture("textures/blocks/netherBrick.png").copy() # generate the textures of the fence ImageDraw.Draw(fence_top).rectangle((0,0,5,15),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -2671,10 +2706,10 @@ def pumpkin(self, blockid, data): # pumpkins, jack-o-lantern elif data == 3: data = 2 # texture generation - top = self.terrain_images[102] - frontID = 119 if blockid == 86 else 120 - front = self.terrain_images[frontID] - side = self.terrain_images[118] + top = self.load_image_texture("textures/blocks/pumpkin_top.png") + frontName = "textures/blocks/pumpkin_face.png" if blockid == 86 else "textures/blocks/pumpkin_jack.png" + front = self.load_image_texture(frontName) + side = self.load_image_texture("textures/blocks/pumpkin_side.png") if data == 0: # pointing west img = self.build_full_block(top, None, None, side, front) @@ -2688,13 +2723,13 @@ def pumpkin(self, blockid, data): # pumpkins, jack-o-lantern return img # netherrack -block(blockid=87, top_index=103) +block(blockid=87, top_image="textures/blocks/hellrock.png") # soul sand -block(blockid=88, top_index=104) +block(blockid=88, top_image="textures/blocks/hellsand.png") # glowstone -block(blockid=89, top_index=105) +block(blockid=89, top_image="textures/blocks/lightgem.png") # portal @material(blockid=90, data=[1, 2, 4, 8], transparent=True) @@ -2719,10 +2754,10 @@ def portal(self, blockid, data): def cake(self, blockid, data): # cake textures - top = self.terrain_images[121].copy() - side = self.terrain_images[122].copy() + top = self.load_image_texture("textures/blocks/cake_top.png").copy() + side = self.load_image_texture("textures/blocks/cake_side.png").copy() fullside = side.copy() - inside = self.terrain_images[123] + inside = self.load_image_texture("textures/blocks/cake_inner.png") img = Image.new("RGBA", (24,24), self.bgcolor) if data == 0: # unbitten cake @@ -2860,8 +2895,8 @@ def repeater(self, blockid, data): elif (data & 0b0011) == 3: data = data & 0b1100 | 2 # generate the diode - top = self.terrain_images[131] if blockid == 93 else self.terrain_images[147] - side = self.terrain_images[5] + top = self.load_image_texture("textures/blocks/repeater.png") if blockid == 93 else self.load_image_texture("textures/blocks/repeater_lit.png") + side = self.load_image_texture("textures/blocks/stoneslab_side.png") increment = 13 if (data & 0x3) == 0: # pointing east @@ -2879,7 +2914,7 @@ def repeater(self, blockid, data): img = self.build_full_block( (top, increment), None, None, side, side) # compose a "3d" redstone torch - t = self.terrain_images[115].copy() if blockid == 93 else self.terrain_images[99].copy() + t = self.load_image_texture("textures/blocks/redtorch.png").copy() if blockid == 93 else self.load_image_texture("textures/blocks/redtorch_lit.png").copy() torch = Image.new("RGBA", (24,24), self.bgcolor) t_crop = t.crop((2,2,14,14)) @@ -2982,6 +3017,70 @@ def repeater(self, blockid, data): alpha_over(img, torch, moving_torch, torch) return img + +# redstone comparator (149 is inactive, 150 is active) +@material(blockid=[149,150], data=range(16), transparent=True, nospawn=True) +def comparator(self, blockid, data): + + # rotation + # add self.rotation to the lower 2 bits, mod 4 + data = data & 0b1100 | (((data & 0b11) + self.rotation) % 4) + + + top = self.load_image_texture("textures/blocks/comparator.png") if blockid == 149 else self.load_image_texture("textures/blocks/comparator_lit.png") + side = self.load_image_texture("textures/blocks/stoneslab_side.png") + increment = 13 + + if (data & 0x3) == 0: # pointing north + pass + static_torch = (-3,-1) + torch = ((0,2),(6,-1)) + + if (data & 0x3) == 1: # pointing east + top = top.rotate(270) + static_torch = (5,-1) + torch = ((-4,-1),(0,2)) + + if (data & 0x3) == 2: # pointing south + top = top.rotate(180) + static_torch = (5,3) + torch = ((0,-4),(-4,-1)) + + if (data & 0x3) == 3: # pointing west + top = top.rotate(90) + static_torch = (-3,3) + torch = ((1,-4),(6,-1)) + + + def build_torch(active): + # compose a "3d" redstone torch + t = self.load_image_texture("textures/blocks/redtorch.png").copy() if not active else self.load_image_texture("textures/blocks/redtorch_lit.png").copy() + torch = Image.new("RGBA", (24,24), self.bgcolor) + + t_crop = t.crop((2,2,14,14)) + slice = t_crop.copy() + ImageDraw.Draw(slice).rectangle((6,0,12,12),outline=(0,0,0,0),fill=(0,0,0,0)) + ImageDraw.Draw(slice).rectangle((0,0,4,12),outline=(0,0,0,0),fill=(0,0,0,0)) + + alpha_over(torch, slice, (6,4)) + alpha_over(torch, t_crop, (5,5)) + alpha_over(torch, t_crop, (6,5)) + alpha_over(torch, slice, (6,6)) + + return torch + + active_torch = build_torch(True) + inactive_torch = build_torch(False) + back_torch = active_torch if (blockid == 150 or data & 0b1000 == 0b1000) else inactive_torch + static_torch_img = active_torch if (data & 0b100 == 0b100) else inactive_torch + + img = self.build_full_block( (top, increment), None, None, side, side) + + alpha_over(img, static_torch_img, static_torch, static_torch_img) + alpha_over(img, back_torch, torch[0], back_torch) + alpha_over(img, back_torch, torch[1], back_torch) + return img + # trapdoor # TODO the trapdoor is looks like a sprite when opened, that's not good @@ -3007,7 +3106,7 @@ def trapdoor(self, blockid, data): elif (data & 0b0011) == 3: data = data & 0b1100 | 0 # texture generation - texture = self.terrain_images[84] + texture = self.load_image_texture("textures/blocks/trapdoor.png") if data & 0x4 == 0x4: # opened trapdoor if data & 0x3 == 0: # west img = self.build_full_block(None, None, None, None, texture) @@ -3032,11 +3131,11 @@ def trapdoor(self, blockid, data): @material(blockid=97, data=range(3), solid=True) def hidden_silverfish(self, blockid, data): if data == 0: # stone - t = self.terrain_images[1] + t = self.load_image_texture("textures/blocks/stone.png") elif data == 1: # cobblestone - t = self.terrain_images[16] + t = self.load_image_texture("textures/blocks/stonebrick.png") elif data == 2: # stone brick - t = self.terrain_images[54] + t = self.load_image_texture("textures/blocks/stonebricksmooth.png") img = self.build_block(t, t) @@ -3046,13 +3145,13 @@ def hidden_silverfish(self, blockid, data): @material(blockid=98, data=range(4), solid=True) def stone_brick(self, blockid, data): if data == 0: # normal - t = self.terrain_images[54] + t = self.load_image_texture("textures/blocks/stonebricksmooth.png") elif data == 1: # mossy - t = self.terrain_images[100] + t = self.load_image_texture("textures/blocks/stonebricksmooth_mossy.png") elif data == 2: # cracked - t = self.terrain_images[101] + t = self.load_image_texture("textures/blocks/stonebricksmooth_cracked.png") elif data == 3: # "circle" stone brick - t = self.terrain_images[213] + t = self.load_image_texture("textures/blocks/stonebricksmooth_carved.png") img = self.build_full_block(t, None, None, t, t) @@ -3092,12 +3191,12 @@ def huge_mushroom(self, blockid, data): # texture generation if blockid == 99: # brown - cap = self.terrain_images[126] + cap = self.load_image_texture("textures/blocks/mushroom_skin_brown.png") else: # red - cap = self.terrain_images[125] + cap = self.load_image_texture("textures/blocks/mushroom_skin_red.png") - stem = self.terrain_images[141] - porous = self.terrain_images[142] + stem = self.load_image_texture("textures/blocks/mushroom_skin_stem.png") + porous = self.load_image_texture("textures/blocks/mushroom_inside.png") if data == 0: # fleshy piece img = self.build_full_block(porous, None, None, porous, porous) @@ -3142,10 +3241,10 @@ def panes(self, blockid, data): # no rotation, uses pseudo data if blockid == 101: # iron bars - t = self.terrain_images[85] + t = self.load_image_texture("textures/blocks/fenceIron.png") else: # glass panes - t = self.terrain_images[49] + t = self.load_image_texture("textures/blocks/glass.png") left = t.copy() right = t.copy() @@ -3178,7 +3277,7 @@ def panes(self, blockid, data): return img # melon -block(blockid=103, top_index=137, side_index=136, solid=True) +block(blockid=103, top_image="textures/blocks/melon_top.png", side_image="textures/blocks/melon_side.png", solid=True) # pumpkin and melon stem # TODO To render it as in game needs from pseudo data and ancil data: @@ -3191,7 +3290,7 @@ def stem(self, blockid, data): # not fully grown stem or no pumpkin/melon touching it, # straight up stem - t = self.terrain_images[111].copy() + t = self.load_image_texture("textures/blocks/stem_straight.png").copy() img = Image.new("RGBA", (16,16), self.bgcolor) alpha_over(img, t, (0, int(16 - 16*((data + 1)/8.))), t) img = self.build_sprite(t) @@ -3227,7 +3326,7 @@ def vines(self, blockid, data): data = (data - 16) | 1 # decode data and prepare textures - raw_texture = self.terrain_images[143] + raw_texture = self.load_image_texture("textures/blocks/vine.png") s = w = n = e = None if data & 1: # south @@ -3272,7 +3371,7 @@ def fence_gate(self, blockid, data): data = data | 0x4 # create the closed gate side - gate_side = self.terrain_images[4].copy() + gate_side = self.load_image_texture("textures/blocks/wood.png").copy() gate_side_draw = ImageDraw.Draw(gate_side) gate_side_draw.rectangle((7,0,15,0),outline=(0,0,0,0),fill=(0,0,0,0)) gate_side_draw.rectangle((7,4,9,6),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -3329,7 +3428,7 @@ def fence_gate(self, blockid, data): return img # mycelium -block(blockid=110, top_index=78, side_index=77) +block(blockid=110, top_image="textures/blocks/mycel_top.png", side_image="textures/blocks/mycel_side.png") # lilypad # At the moment of writing this lilypads has no ancil data and their @@ -3338,21 +3437,21 @@ block(blockid=110, top_index=78, side_index=77) # with ancil data. @material(blockid=111, data=range(4), transparent=True) def lilypad(self, blockid, data): - t = self.terrain_images[76] + t = self.load_image_texture("textures/blocks/waterlily.png") return self.build_full_block(None, None, None, None, None, t) # nether brick -block(blockid=112, top_index=224, side_index=224) +block(blockid=112, top_image="textures/blocks/netherBrick.png") # nether wart @material(blockid=115, data=range(4), transparent=True) def nether_wart(self, blockid, data): if data == 0: # just come up - t = self.terrain_images[226] + t = self.load_image_texture("textures/blocks/netherStalk_0.png") elif data in (1, 2): - t = self.terrain_images[227] + t = self.load_image_texture("textures/blocks/netherStalk_1.png") else: # fully grown - t = self.terrain_images[228] + t = self.load_image_texture("textures/blocks/netherStalk_2.png") # use the same technic as tall grass img = self.build_billboard(t) @@ -3364,8 +3463,8 @@ def nether_wart(self, blockid, data): @material(blockid=116, transparent=True, nodata=True) def enchantment_table(self, blockid, data): # no book at the moment - top = self.terrain_images[166] - side = self.terrain_images[182] + top = self.load_image_texture("textures/blocks/enchantment_top.png") + side = self.load_image_texture("textures/blocks/enchantment_side.png") img = self.build_full_block((top, 4), None, None, side, side) return img @@ -3374,9 +3473,9 @@ def enchantment_table(self, blockid, data): # TODO this is a place holder, is a 2d image pasted @material(blockid=117, data=range(5), transparent=True) def brewing_stand(self, blockid, data): - base = self.terrain_images[156] + base = self.load_image_texture("textures/blocks/brewingStand_base.png") img = self.build_full_block(None, None, None, None, None, base) - t = self.terrain_images[157] + t = self.load_image_texture("textures/blocks/brewingStand.png") stand = self.build_billboard(t) alpha_over(img,stand,(0,-2)) return img @@ -3384,9 +3483,9 @@ def brewing_stand(self, blockid, data): # cauldron @material(blockid=118, data=range(4), transparent=True) def cauldron(self, blockid, data): - side = self.terrain_images[154] - top = self.terrain_images[138] - bottom = self.terrain_images[139] + side = self.load_image_texture("textures/blocks/cauldron_side.png") + top = self.load_image_texture("textures/blocks/cauldron_top.png") + bottom = self.load_image_texture("textures/blocks/cauldron_inner.png") water = self.transform_image_top(self.load_water()) if data == 0: # empty img = self.build_full_block(top, side, side, side, side) @@ -3425,19 +3524,19 @@ def end_portal(self, blockid, data): return img -# end portal frame -@material(blockid=120, data=range(5), transparent=True) +# end portal frame (data range 8 to get all orientations of filled) +@material(blockid=120, data=range(8), transparent=True) def end_portal_frame(self, blockid, data): # The bottom 2 bits are oritation info but seems there is no # graphical difference between orientations - top = self.terrain_images[158] - eye_t = self.terrain_images[174] - side = self.terrain_images[159] + top = self.load_image_texture("textures/blocks/endframe_top.png") + eye_t = self.load_image_texture("textures/blocks/endframe_eye.png") + side = self.load_image_texture("textures/blocks/endframe_side.png") img = self.build_full_block((top, 4), None, None, side, side) if data & 0x4 == 0x4: # ender eye on it # generate the eye - eye_t = self.terrain_images[174].copy() - eye_t_s = self.terrain_images[174].copy() + eye_t = self.load_image_texture("textures/blocks/endframe_eye.png").copy() + eye_t_s = self.load_image_texture("textures/blocks/endframe_eye.png").copy() # cut out from the texture the side and the top of the eye ImageDraw.Draw(eye_t).rectangle((0,0,15,4),outline=(0,0,0,0),fill=(0,0,0,0)) ImageDraw.Draw(eye_t_s).rectangle((0,4,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -3452,17 +3551,48 @@ def end_portal_frame(self, blockid, data): return img # end stone -block(blockid=121, top_index=175) +block(blockid=121, top_image="textures/blocks/whiteStone.png") # dragon egg # NOTE: this isn't a block, but I think it's better than nothing -block(blockid=122, top_index=37) +block(blockid=122, top_image="textures/blocks/dragonEgg.png") # inactive redstone lamp -block(blockid=123, top_index=211) +block(blockid=123, top_image="textures/blocks/redstoneLight.png") # active redstone lamp -block(blockid=124, top_index=212) +block(blockid=124, top_image="textures/blocks/redstoneLight_lit.png") + +# daylight sensor. +@material(blockid=151, transparent=True) +def daylight_sensor(self, blockid, data): + top = self.load_image_texture("textures/blocks/daylightDetector_top.png") + side = self.load_image_texture("textures/blocks/daylightDetector_side.png") + + # cut the side texture in half + mask = side.crop((0,8,16,16)) + side = Image.new(side.mode, side.size, self.bgcolor) + alpha_over(side, mask,(0,0,16,8), mask) + + # plain slab + top = self.transform_image_top(top) + side = self.transform_image_side(side) + otherside = side.transpose(Image.FLIP_LEFT_RIGHT) + + sidealpha = side.split()[3] + side = ImageEnhance.Brightness(side).enhance(0.9) + side.putalpha(sidealpha) + othersidealpha = otherside.split()[3] + otherside = ImageEnhance.Brightness(otherside).enhance(0.8) + otherside.putalpha(othersidealpha) + + img = Image.new("RGBA", (24,24), self.bgcolor) + alpha_over(img, side, (0,12), side) + alpha_over(img, otherside, (12,12), otherside) + alpha_over(img, top, (0,6), top) + + return img + # wooden double and normal slabs # these are the new wooden slabs, blockids 43 44 still have wooden @@ -3471,13 +3601,13 @@ block(blockid=124, top_index=212) def wooden_slabs(self, blockid, data): texture = data & 7 if texture== 0: # oak - top = side = self.terrain_images[4] + top = side = self.load_image_texture("textures/blocks/wood.png") elif texture== 1: # spruce - top = side = self.terrain_images[198] + top = side = self.load_image_texture("textures/blocks/wood_spruce.png") elif texture== 2: # birch - top = side = self.terrain_images[214] + top = side = self.load_image_texture("textures/blocks/wood_birch.png") elif texture== 3: # jungle - top = side = self.terrain_images[199] + top = side = self.load_image_texture("textures/blocks/wood_jungle.png") else: return None @@ -3514,10 +3644,10 @@ def wooden_slabs(self, blockid, data): return img # emerald ore -block(blockid=129, top_index=171) +block(blockid=129, top_image="textures/blocks/oreEmerald.png") # emerald block -block(blockid=133, top_index=25) +block(blockid=133, top_image="textures/blocks/blockEmerald.png") # cocoa plant @material(blockid=127, data=range(12), transparent=True) @@ -3542,17 +3672,17 @@ def cocoa_plant(self, blockid, data): size = data & 12 if size == 8: # big - t = self.terrain_images[168] + t = self.load_image_texture("textures/blocks/cocoa_2.png") c_left = (0,3) c_right = (8,3) c_top = (5,2) elif size == 4: # normal - t = self.terrain_images[169] + t = self.load_image_texture("textures/blocks/cocoa_1.png") c_left = (-2,2) c_right = (8,2) c_top = (5,2) elif size == 0: # small - t = self.terrain_images[170] + t = self.load_image_texture("textures/blocks/cocoa_0.png") c_left = (-3,2) c_right = (6,2) c_top = (5,2) @@ -3601,7 +3731,7 @@ def cocoa_plant(self, blockid, data): return img # command block -block(blockid=137, top_index=184) +block(blockid=137, top_image="textures/blocks/commandBlock.png") # beacon block # at the moment of writing this, it seems the beacon block doens't use @@ -3609,12 +3739,12 @@ block(blockid=137, top_index=184) @material(blockid=138, transparent=True, nodata = True) def beacon(self, blockid, data): # generate the three pieces of the block - t = self.terrain_images[49] + t = self.load_image_texture("textures/blocks/glass.png") glass = self.build_block(t,t) - t = self.terrain_images[37] + t = self.load_image_texture("textures/blocks/obsidian.png") obsidian = self.build_full_block((t,12),None, None, t, t) obsidian = obsidian.resize((20,20), Image.ANTIALIAS) - t = self.terrain_images[41] + t = self.load_image_texture("textures/blocks/beacon.png") crystal = self.build_block(t,t) crystal = crystal.resize((16,16),Image.ANTIALIAS) @@ -3633,10 +3763,10 @@ def cobblestone_wall(self, blockid, data): # no rotation, uses pseudo data if data & 0b10000 == 0: # cobblestone - t = self.terrain_images[16].copy() + t = self.load_image_texture("textures/blocks/stonebrick.png").copy() else: # mossy cobblestone - t = self.terrain_images[36].copy() + t = self.load_image_texture("textures/blocks/stoneMoss.png").copy() wall_pole_top = t.copy() wall_pole_side = t.copy() @@ -3761,11 +3891,11 @@ def crops(self, blockid, data): if data != 7: # when growing they look the same # data = 7 -> fully grown, everything else is growing # this seems to work, but still not sure - raw_crop = self.terrain_images[200 + (data % 3)] + raw_crop = self.load_image_texture("textures/blocks/potatoes_%d.png" % (data % 3)) elif blockid == 141: # carrots - raw_crop = self.terrain_images[203] + raw_crop = self.load_image_texture("textures/blocks/carrots_3.png") else: # potatoes - raw_crop = self.terrain_images[204] + raw_crop = self.load_image_texture("textures/blocks/potatoes_3.png") crop1 = self.transform_image_top(raw_crop) crop2 = self.transform_image_side(raw_crop) crop3 = crop2.transpose(Image.FLIP_LEFT_RIGHT) @@ -3791,16 +3921,16 @@ def anvil(self, blockid, data): # get the correct textures # the bits 0x4 and 0x8 determine how damaged is the anvil if (data & 0xc) == 0: # non damaged anvil - top = self.terrain_images[231] + top = self.load_image_texture("textures/blocks/anvil_top.png") elif (data & 0xc) == 0x4: # slightly damaged - top = self.terrain_images[232] + top = self.load_image_texture("textures/blocks/anvil_top_damaged_1.png") elif (data & 0xc) == 0x8: # very damaged - top = self.terrain_images[216] + top = self.load_image_texture("textures/blocks/anvil_top_damaged_2.png") # everything else use this texture - big_side = self.terrain_images[215].copy() - small_side = self.terrain_images[215].copy() - base = self.terrain_images[215].copy() - small_base = self.terrain_images[215].copy() + big_side = self.load_image_texture("textures/blocks/anvil_base.png").copy() + small_side = self.load_image_texture("textures/blocks/anvil_base.png").copy() + base = self.load_image_texture("textures/blocks/anvil_base.png").copy() + small_base = self.load_image_texture("textures/blocks/anvil_base.png").copy() # cut needed patterns ImageDraw.Draw(big_side).rectangle((0,8,15,15),outline=(0,0,0,0),fill=(0,0,0,0)) @@ -3860,3 +3990,62 @@ def anvil(self, blockid, data): alpha_over(img, right_side, right_pos, right_side) return img + + +# block of redstone +block(blockid=152, top_image="textures/blocks/blockRedstone.png") + +# nether quartz ore +block(blockid=153, top_image="textures/blocks/netherquartz.png") + +# block of quartz +@material(blockid=155, data=range(5), solid=True) +def quartz_block(self, blockid, data): + + if data in (0,1): # normal and chiseled quartz block + if data == 0: + top = self.load_image_texture("textures/blocks/quartzblock_top.png") + side = self.load_image_texture("textures/blocks/quartzblock_side.png") + else: + top = self.load_image_texture("textures/blocks/quartzblock_chiseled_top.png") + side = self.load_image_texture("textures/blocks/quartzblock_chiseled.png") + return self.build_block(top, side) + + # pillar quartz block with orientation + top = self.load_image_texture("textures/blocks/quartzblock_lines_top.png") + side = self.load_image_texture("textures/blocks/quartzblock_lines.png").copy() + if data == 2: # vertical + return self.build_block(top, side) + elif data == 3: # north-south oriented + if self.rotation in (0,2): + return self.build_full_block(side, None, None, top, side.rotate(90)) + return self.build_full_block(side.rotate(90), None, None, side.rotate(90), top) + + elif data == 4: # east-west oriented + if self.rotation in (0,2): + return self.build_full_block(side.rotate(90), None, None, side.rotate(90), top) + return self.build_full_block(side, None, None, top, side.rotate(90)) + +# hopper +@material(blockid=154, data=range(4), transparent=True) +def hopper(self, blockid, data): + #build the top + side = self.load_image_texture("textures/blocks/hopper.png") + top = self.load_image_texture("textures/blocks/hopper_top.png") + bottom = self.load_image_texture("textures/blocks/hopper_inside.png") + hop_top = self.build_full_block((top,10), side, side, side, side, side) + + #build a solid block for mid/top + hop_mid = self.build_full_block((top,5), side, side, side, side, side) + hop_bot = self.build_block(side,side) + + hop_mid = hop_mid.resize((17,17),Image.ANTIALIAS) + hop_bot = hop_bot.resize((10,10),Image.ANTIALIAS) + + #compose the final block + img = Image.new("RGBA", (24,24), self.bgcolor) + alpha_over(img, hop_bot, (7,14), hop_bot) + alpha_over(img, hop_mid, (3,3), hop_mid) + alpha_over(img, hop_top, (0,-6), hop_top) + + return img