diff --git a/.gitignore b/.gitignore index ce00d58..f0c372a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ cmake_install.cmake src/jthread/libjthread.a debug.txt bin/debug.txt - +minetestmapper/map.png diff --git a/.hgtags b/.hgtags index a124357..95bda33 100644 --- a/.hgtags +++ b/.hgtags @@ -1,13 +1 @@ c37bcfd89dd627fdb131ae3f77fcaab02721bf76 working -69547bd6be420eb40f55524fd2131cbbaa2e0e29 110107195706-exp -e3c3c8e27bbc8c9b61710517a78944deb1c61696 110211211322 -23880c78e40c50ad54fcd8844510f7a423b37f2a 110212200513 -20c49c98c92a62df457b773c562df41d4167492b 110214175330 -10be2b71f965585af90af96903e83b4ddff52bf9 20110424_0 -9b05d4bfee9312aef4182fa6f63b4237368cec34 0.2.20110529_0 -6fa0a8b40406aa567f8fa84b5e2045a7e3762c1d 0.2.20110529_1 -cf6dd618ef0b7514c81ae87749733b5a328fc763 0.2.20110529_2 -96efc17b4cd92aacbe947b520a6ba91727d42f03 0.2.20110602_0 -0000000000000000000000000000000000000000 0.2.20110602_0 -6f17cd3f6c5481e6abc906fc441980c764632cbc 0.2.20110602_0 -dd08a9b5cb84d55b7576bb3fde3068dd263bc3bc 0.2.20110618_0_dev diff --git a/CMakeLists.txt b/CMakeLists.txt index 5167789..854c4b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,7 @@ elseif(UNIX) # Linux, BSD etc set(EXAMPLE_CONF_DIR "share/doc/minetest") endif() -install(FILES "README.txt" DESTINATION "${DOCDIR}") +install(FILES "doc/README.txt" DESTINATION "${DOCDIR}") install(FILES "minetest.conf.example" DESTINATION "${DOCDIR}") # @@ -104,7 +104,7 @@ elseif(APPLE) set(CPACK_BUNDLE_ICON "") set(CPACK_BUNDLE_PLIST "") set(CPACK_BUNDLE_STARTUP_COMMAND "Contents/MacOS/minetest") - set(CPACK_GENERATOR Bundle) + set(CPACK_GENERATOR "Bundle") else() set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-linux") set(CPACK_GENERATOR TGZ) diff --git a/README b/README new file mode 100644 index 0000000..9b1f54e --- /dev/null +++ b/README @@ -0,0 +1,29 @@ +Minetest Δ (“Minetest Delta”) is a fork of Minetest-c55 , incorporating experimental features that are not (yet) included in Minetest-c55. + +New features: +* Submenu for key assignment (changes apply after restart) + +New bricks: +* Sandstone (crafted from 4 sand, yields sand) +* Cactus (plant that grows on sand) +* Clay (found in sand at sea level, yields 4 lumps of clay) +* Brick (made from 4 clay bricks, yields 4 clay bricks) +* Papyrus (plant that grows in shallow water, yields paper) +* Book shelf (made from 6 wood and 3 books, sandwhiched) +* Rail (made from 6 iron ingots and 3 sticks, vertically sandwhiched) + +New materials: +* Lump of clay +* Clay brick (made from lumps of clay in the furnace) +* Paper +* Book (made from 3 paper) + +Alternate graphics: +* Player +* Omsk birds (instead of Oerkki ghosts) +* Rat +* Glass + +Building on GNU/Linux or OS X: + cmake . -DRUN_IN_PLACE=1 + make -j2 diff --git a/data/book.png b/data/book.png new file mode 100644 index 0000000..176fb6a Binary files /dev/null and b/data/book.png differ diff --git a/data/bookshelf.png b/data/bookshelf.png new file mode 100644 index 0000000..5ecc50f Binary files /dev/null and b/data/bookshelf.png differ diff --git a/data/brick.png b/data/brick.png new file mode 100644 index 0000000..32d77f3 Binary files /dev/null and b/data/brick.png differ diff --git a/data/cactus_side.png b/data/cactus_side.png new file mode 100644 index 0000000..fc479fd Binary files /dev/null and b/data/cactus_side.png differ diff --git a/data/cactus_top.png b/data/cactus_top.png new file mode 100644 index 0000000..f9e68df Binary files /dev/null and b/data/cactus_top.png differ diff --git a/data/clay.png b/data/clay.png new file mode 100644 index 0000000..3557429 Binary files /dev/null and b/data/clay.png differ diff --git a/data/clay_brick.png b/data/clay_brick.png new file mode 100644 index 0000000..e36648e Binary files /dev/null and b/data/clay_brick.png differ diff --git a/data/fence.png b/data/fence.png new file mode 100644 index 0000000..0b99f0e Binary files /dev/null and b/data/fence.png differ diff --git a/data/glass.png b/data/glass.png index 8598ce6..35ea596 100644 Binary files a/data/glass.png and b/data/glass.png differ diff --git a/data/lump_of_clay.png b/data/lump_of_clay.png new file mode 100644 index 0000000..be0bab9 Binary files /dev/null and b/data/lump_of_clay.png differ diff --git a/data/menulogo.png b/data/menulogo.png index 76595c4..cb6983e 100644 Binary files a/data/menulogo.png and b/data/menulogo.png differ diff --git a/data/oerkki1.png b/data/oerkki1.png index c32fb99..aad2ddb 100644 Binary files a/data/oerkki1.png and b/data/oerkki1.png differ diff --git a/data/paper.png b/data/paper.png new file mode 100644 index 0000000..ae5c06b Binary files /dev/null and b/data/paper.png differ diff --git a/data/papyrus.png b/data/papyrus.png new file mode 100644 index 0000000..bf0dec7 Binary files /dev/null and b/data/papyrus.png differ diff --git a/data/player.png b/data/player.png index 90adf97..60ac485 100644 Binary files a/data/player.png and b/data/player.png differ diff --git a/data/player_back.png b/data/player_back.png index 530aa75..447c1fd 100644 Binary files a/data/player_back.png and b/data/player_back.png differ diff --git a/data/rail.png b/data/rail.png new file mode 100644 index 0000000..18176d9 Binary files /dev/null and b/data/rail.png differ diff --git a/data/rail_crossing.png b/data/rail_crossing.png new file mode 100644 index 0000000..9846405 Binary files /dev/null and b/data/rail_crossing.png differ diff --git a/data/rail_curved.png b/data/rail_curved.png new file mode 100644 index 0000000..62afa3d Binary files /dev/null and b/data/rail_curved.png differ diff --git a/data/rail_t_junction.png b/data/rail_t_junction.png new file mode 100644 index 0000000..9985f63 Binary files /dev/null and b/data/rail_t_junction.png differ diff --git a/data/rat.png b/data/rat.png index d1a0e2a..96d44c3 100644 Binary files a/data/rat.png and b/data/rat.png differ diff --git a/data/sandstone.png b/data/sandstone.png new file mode 100644 index 0000000..c4759b4 Binary files /dev/null and b/data/sandstone.png differ diff --git a/genmap.py b/genmap.py new file mode 100755 index 0000000..a605094 --- /dev/null +++ b/genmap.py @@ -0,0 +1,271 @@ +#!/usr/bin/python2 + +# This is an example script that generates some valid map data. + +import struct +import random +import os +import sys +import zlib +import array +from pnoise import pnoise + +# Old directory format: +# world/sectors/XXXXZZZZ/YYYY +# XXXX,YYYY,ZZZZ = coordinates in hexadecimal +# fffe = -2 +# ffff = -1 +# 0000 = 0 +# 0001 = 1 +# +# New directory format: +# world/sectors2/XXX/ZZZ/YYYY +# XXX,YYYY,ZZZ = coordinates in hexadecimal +# fffe = -2 +# ffff = -1 +# 0000 = 0 +# 0001 = 1 +# ffe = -2 +# fff = -1 +# 000 = 0 +# 001 = 1 +# +# For more proper file format documentation, refer to mapformat.txt +# For node type documentation, refer to mapnode.h +# NodeMetadata documentation is not complete, refer to nodemeta.cpp +# + +# Seed for generating terrain +SEED = 0 + +# 0=old, 1=new +SECTOR_DIR_FORMAT = 1 + +mapdir = "world" + +def to4h(i): + s = ""; + s += '{0:1x}'.format((i>>12) & 0x000f) + s += '{0:1x}'.format((i>>8) & 0x000f) + s += '{0:1x}'.format((i>>4) & 0x000f) + s += '{0:1x}'.format((i>>0) & 0x000f) + return s + +def to3h(i): + s = ""; + s += '{0:1x}'.format((i>>8) & 0x000f) + s += '{0:1x}'.format((i>>4) & 0x000f) + s += '{0:1x}'.format((i>>0) & 0x000f) + return s + +def get_sector_dir(px, pz): + global SECTOR_DIR_FORMAT + if SECTOR_DIR_FORMAT == 0: + return "/sectors/"+to4h(px)+to4h(pz) + elif SECTOR_DIR_FORMAT == 1: + return "/sectors2/"+to3h(px)+"/"+to3h(pz) + else: + assert(0) + +def getrand_air_stone(): + i = random.randrange(0,2) + if i==0: + return 0 + return 254 + +# 3-dimensional vector (position) +class v3: + def __init__(self, x=0, y=0, z=0): + self.X = x + self.Y = y + self.Z = z + +class NodeMeta: + def __init__(self, type_id, data): + self.type_id = type_id + self.data = data + +class StaticObject: + def __init__(self): + self.type_id = 0 + self.data = "" + +def ser_u16(i): + return chr((i>>8)&0xff) + chr((i>>0)&0xff) +def ser_u32(i): + return (chr((i>>24)&0xff) + chr((i>>16)&0xff) + + chr((i>>8)&0xff) + chr((i>>0)&0xff)) + +# A 16x16x16 chunk of map +class MapBlock: + def __init__(self): + self.content = array.array('B') + self.param1 = array.array('B') + self.param2 = array.array('B') + for i in range(16*16*16): + # Initialize to air + self.content.append(254) + # Full light on sunlight, none when no sunlight + self.param1.append(15) + # No additional parameters + self.param2.append(0) + + # key = v3 pos + # value = NodeMeta + self.nodemeta = {} + + # key = v3 pos + # value = StaticObject + self.static_objects = {} + + def set_content(self, v3, b): + self.content[v3.Z*16*16+v3.Y*16+v3.X] = b + def set_param1(self, v3, b): + self.param1[v3.Z*16*16+v3.Y*16+v3.X] = b + def set_param2(self, v3, b): + self.param2[v3.Z*16*16+v3.Y*16+v3.X] = b + + # Get data for serialization. Returns a string. + def serialize_data(self): + s = "" + for i in range(16*16*16): + s += chr(self.content[i]) + for i in range(16*16*16): + s += chr(self.param1[i]) + for i in range(16*16*16): + s += chr(self.param2[i]) + return s + + def serialize_nodemeta(self): + s = "" + s += ser_u16(1) + s += ser_u16(len(self.nodemeta)) + for pos, meta in self.nodemeta.items(): + pos_i = pos.Z*16*16 + pos.Y*16 + pos.X + s += ser_u16(pos_i) + s += ser_u16(meta.type_id) + s += ser_u16(len(meta.data)) + s += meta.data + return s + + def serialize_staticobj(self): + s = "" + s += chr(0) + s += ser_u16(len(self.static_objects)) + for pos, obj in self.static_objects.items(): + pos_i = pos.Z*16*16 + pos.Y*16 + pos.X + s += ser_s32(pos.X*1000) + s += ser_s32(pos.Y*1000) + s += ser_s32(pos.Z*1000) + s += ser_u16(obj.type_id) + s += ser_u16(len(obj.data)) + s += obj.data + return s + +def writeblock(mapdir, px,py,pz, block): + + sectordir = mapdir + get_sector_dir(px, pz); + + try: + os.makedirs(sectordir) + except OSError: + pass + + path = sectordir+"/"+to4h(py) + + print("writing block file "+path) + + f = open(sectordir+"/"+to4h(py), "wb") + + if f == None: + return + + # version + version = 17 + f.write(struct.pack('B', version)) + + # flags + # 0x01=is_undg, 0x02=dn_diff, 0x04=lighting_expired + flags = 0 + 0x02 + 0x04 + f.write(struct.pack('B', flags)) + + # data + c_obj = zlib.compressobj() + c_obj.compress(block.serialize_data()) + f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number + f.write(c_obj.flush()) + + # node metadata + c_obj = zlib.compressobj() + c_obj.compress(block.serialize_nodemeta()) + f.write(struct.pack('BB', 0x78, 0x9c)) # zlib magic number + f.write(c_obj.flush()) + + # mapblockobject count + f.write(ser_u16(0)) + + # static objects + f.write(block.serialize_staticobj()) + + # timestamp + f.write(ser_u32(0xffffffff)) + + f.close() + +for z0 in range(-1,3): + for x0 in range(-1,3): + for y0 in range(-1,3): + print("generating block "+str(x0)+","+str(y0)+","+str(z0)) + #v3 blockp = v3(x0,y0,z0) + + # Create a MapBlock + block = MapBlock() + + # Generate stuff in it + for z in range(0,16): + for x in range(0,16): + h = 20.0*pnoise((x0*16+x)/100.,(z0*16+z)/100.,SEED+0) + h += 5.0*pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+0) + if pnoise((x0*16+x)/25.,(z0*16+z)/25.,SEED+92412) > 0.05: + h += 10 + #print("r="+str(r)) + # This enables comparison by == + h = int(h) + for y in range(0,16): + p = v3(x,y,z) + b = 254 + y1 = y0*16+y + if y1 <= h-3: + b = 0 #stone + elif y1 <= h and y1 <= 0: + b = 8 #mud + elif y1 == h: + b = 1 #grass + elif y1 < h: + b = 8 #mud + elif y1 <= 1: + b = 9 #water + + # Material content + block.set_content(p, b) + + # Place a sign at the center at surface level. + # Placing a sign means placing the sign node and + # adding node metadata to the mapblock. + if x == 8 and z == 8 and y0*16 <= h-1 and (y0+1)*16-1 > h: + p = v3(8,h+1-y0*16,8) + # 14 = Sign + content_type = 14 + block.set_content(p, content_type) + # This places the sign to the bottom of the cube. + # Working values: 0x01, 0x02, 0x04, 0x08, 0x10, 0x20 + block.set_param2(p, 0x08) + # Then add metadata to hold the text of the sign + s = "Hello at sector ("+str(x0)+","+str(z0)+")" + meta = NodeMeta(content_type, ser_u16(len(s))+s) + block.nodemeta[p] = meta + + # Write it on disk + writeblock(mapdir, x0,y0,z0, block) + +#END diff --git a/heart.png b/heart.png new file mode 100644 index 0000000..bea1aef Binary files /dev/null and b/heart.png differ diff --git a/minetestmapper/colors.txt b/minetestmapper/colors.txt new file mode 100644 index 0000000..e70f56e --- /dev/null +++ b/minetestmapper/colors.txt @@ -0,0 +1,25 @@ +0 128 128 128 +1 107 134 51 +2 39 66 106 +3 255 255 0 +4 86 58 31 +5 48 95 8 +6 102 129 38 +7 178 178 0 +8 101 84 36 +9 39 66 106 +12 104 78 42 +13 210 194 156 +14 117 86 41 +15 128 79 0 +16 118 118 118 +18 123 123 123 +19 199 199 199 +20 183 183 222 +21 103 78 42 +22 219 202 178 +23 78 154 6 +24 204 0 0 +25 211 215 207 +26 138 226 52 +27 104 78 42 diff --git a/minetestmapper/minetestmapper2.py b/minetestmapper/minetestmapper2.py new file mode 100755 index 0000000..8dc3de2 --- /dev/null +++ b/minetestmapper/minetestmapper2.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Made by j0gge, modified by celeron55 + +# This program is free software. It comes without any warranty, to +# the extent permitted by applicable law. You can redistribute it +# and/or modify it under the terms of the Do What The Fuck You Want +# To Public License, Version 2, as published by Sam Hocevar. See +# http://sam.zoy.org/wtfpl/COPYING for more details. + +# Requires Python Imaging Library: http://www.pythonware.com/products/pil/ + +# Some speed-up: ...lol, actually it slows it down. +#import psyco ; psyco.full() +#from psyco.classes import * + +import zlib +import Image, ImageDraw +import os +import string +import time + +def hex_to_int(h): + i = int(h,16) + if(i > 2047): + i-=4096 + return i + +def hex4_to_int(h): + i = int(h,16) + if(i > 32767): + i-=65536 + return i + +def int_to_hex3(i): + if(i < 0): + return "%03X" % (i + 4096) + else: + return "%03X" % i + +def int_to_hex4(i): + if(i < 0): + return "%04X" % (i + 65536) + else: + return "%04X" % i + +def limit(i,l,h): + if(i>h): + i=h + if(i sector_xmax: + continue + if z < sector_zmin or z > sector_zmax: + continue + xlist.append(x) + zlist.append(z) + +if os.path.exists(path + "sectors"): + for filename in os.listdir(path + "sectors"): + x = hex4_to_int(filename[:4]) + z = hex4_to_int(filename[-4:]) + if x < sector_xmin or x > sector_xmax: + continue + if z < sector_zmin or z > sector_zmax: + continue + xlist.append(x) + zlist.append(z) + +w = (max(xlist) - min(xlist)) * 16 + 16 +h = (max(zlist) - min(zlist)) * 16 + 16 + +print "w="+str(w)+" h="+str(h) + +im = Image.new("RGB", (w, h), "white") +impix = im.load() + +stuff={} + +starttime = time.time() + +# Go through all sectors. +for n in range(len(xlist)): + #if n > 500: + # break + if n % 200 == 0: + nowtime = time.time() + dtime = nowtime - starttime + n_per_second = 1.0 * n / dtime + if n_per_second != 0: + seconds_per_n = 1.0 / n_per_second + time_guess = seconds_per_n * len(xlist) + remaining_s = time_guess - dtime + remaining_minutes = int(remaining_s / 60) + remaining_s -= remaining_minutes * 60; + print("Processing sector "+str(n)+" of "+str(len(xlist)) + +" ("+str(round(100.0*n/len(xlist), 1))+"%)" + +" (ETA: "+str(remaining_minutes)+"m " + +str(int(remaining_s))+"s)") + + xpos = xlist[n] + zpos = zlist[n] + + xhex = int_to_hex3(xpos) + zhex = int_to_hex3(zpos) + xhex4 = int_to_hex4(xpos) + zhex4 = int_to_hex4(zpos) + + sector1 = xhex4.lower() + zhex4.lower() + sector2 = xhex.lower() + "/" + zhex.lower() + + ylist=[] + + sectortype = "" + + try: + for filename in os.listdir(path + "sectors/" + sector1): + if(filename != "meta"): + pos = int(filename,16) + if(pos > 32767): + pos-=65536 + ylist.append(pos) + sectortype = "old" + except OSError: + pass + + if sectortype != "old": + try: + for filename in os.listdir(path + "sectors2/" + sector2): + if(filename != "meta"): + pos = int(filename,16) + if(pos > 32767): + pos-=65536 + ylist.append(pos) + sectortype = "new" + except OSError: + pass + + if sectortype == "": + continue + + ylist.sort() + + # Make a list of pixels of the sector that are to be looked for. + pixellist = [] + for x in range(16): + for y in range(16): + pixellist.append((x,y)) + + # Go through the Y axis from top to bottom. + for ypos in reversed(ylist): + + yhex = int_to_hex4(ypos) + + filename = "" + if sectortype == "old": + filename = path + "sectors/" + sector1 + "/" + yhex.lower() + else: + filename = path + "sectors2/" + sector2 + "/" + yhex.lower() + + f = file(filename, "rb") + + # Let's just memorize these even though it's not really necessary. + version = f.read(1) + flags = f.read(1) + + dec_o = zlib.decompressobj() + try: + mapdata = dec_o.decompress(f.read()) + except: + mapdata = [] + + f.close() + + if(len(mapdata)<4096): + print "bad: " + xhex+zhex+"/"+yhex + " " + len(mapdata) + else: + chunkxpos=xpos*16 + chunkypos=ypos*16 + chunkzpos=zpos*16 + for (x,z) in reversed(pixellist): + for y in reversed(range(16)): + datapos=x+y*16+z*256 + if(ord(mapdata[datapos])!=254): + try: + pixellist.remove((x,z)) + # Memorize information on the type and height of the block and for drawing the picture. + stuff[(chunkxpos+x,chunkzpos+z)]=(chunkypos+y,ord(mapdata[datapos])) + break + except: + print "strange block: " + xhex+zhex+"/"+yhex + " x: " + str(x) + " y: " + str(y) + " z: " + str(z) + " block: " + str(ord(mapdata[datapos])) + + # After finding all the pixeld in the sector, we can move on to the next sector without having to continue the Y axis. + if(len(pixellist)==0): + break + +print "Drawing image" +# Drawing the picture +starttime = time.time() +n = 0 +minx = min(xlist) +minz = min(zlist) +for (x,z) in stuff.iterkeys(): + if n % 500000 == 0: + nowtime = time.time() + dtime = nowtime - starttime + n_per_second = 1.0 * n / dtime + if n_per_second != 0: + listlen = len(stuff) + seconds_per_n = 1.0 / n_per_second + time_guess = seconds_per_n * listlen + remaining_s = time_guess - dtime + remaining_minutes = int(remaining_s / 60) + remaining_s -= remaining_minutes * 60; + print("Drawing pixel "+str(n)+" of "+str(listlen) + +" ("+str(round(100.0*n/listlen, 1))+"%)" + +" (ETA: "+str(remaining_minutes)+"m " + +str(int(remaining_s))+"s)") + n += 1 + + (r,g,b)=colors[stuff[(x,z)][1]] + + # Comparing heights of a couple of adjacent blocks and changing brightness accordingly. + try: + y1=stuff[(x-1,z)][0] + y2=stuff[(x,z-1)][0] + y=stuff[(x,z)][0] + + d=(y-y1+y-y2)*12 + + if(d>36): + d=36 + + r=limit(r+d,0,255) + g=limit(g+d,0,255) + b=limit(b+d,0,255) + except: + pass + #impix[w-1-(x-minx*16),h-1-(z-minz*16)]=(r,g,b) + impix[x-minx*16,h-1-(z-minz*16)]=(r,g,b) + +# Flip the picture to make it right and save. +#print "Transposing" +#im=im.transpose(Image.FLIP_TOP_BOTTOM) +print "Saving" +im.save(output) diff --git a/pnoise.py b/pnoise.py new file mode 100644 index 0000000..fcab5ac --- /dev/null +++ b/pnoise.py @@ -0,0 +1,102 @@ +# +# A python perlin noise implementation, from +# http://www.fundza.com/c4serious/noise/perlin/perlin.html +# +# This is used for testing how to create maps with a python script. +# + +import math +p = ( +151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103, +30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197, +62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20, +125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231, +83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102, +143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200, +196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226, +250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16, +58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70, +221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113, +224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144, +12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181, +199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236, +205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, +151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103, +30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197, +62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20, +125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231, +83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102, +143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200, +196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226, +250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16, +58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70, +221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113, +224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144, +12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181, +199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236, +205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180) + +def lerp(t, a, b): + return a + t * (b - a) + +def fade(t): + return t * t * t * (t * (t * 6 - 15) + 10) + +def grad(hash, x, y, z): + h = hash & 15 + if h < 8: + u = x + else: + u = y + if h < 4: + v = y + elif h == 12 or h == 14: + v = x + else: + v = z + if h & 1 != 0: + u = -u + if h & 2 != 0: + v = -v + return u + v + +def pnoise(x, y, z): + global p + X = int(math.floor(x)) & 255 + Y = int(math.floor(y)) & 255 + Z = int(math.floor(z)) & 255 + x -= math.floor(x) + y -= math.floor(y) + z -= math.floor(z) + + u = fade(x) + v = fade(y) + w = fade(z) + + A = p[X] + Y + AA = p[A] + Z + AB = p[A + 1] + Z + B = p[X + 1] + Y + BA = p[B] + Z + BB = p[B + 1] + Z + + pAA = p[AA] + pAB = p[AB] + pBA = p[BA] + pBB = p[BB] + pAA1 = p[AA + 1] + pBA1 = p[BA + 1] + pAB1 = p[AB + 1] + pBB1 = p[BB + 1] + + gradAA = grad(pAA, x, y, z) + gradBA = grad(pBA, x-1, y, z) + gradAB = grad(pAB, x, y-1, z) + gradBB = grad(pBB, x-1, y-1, z) + gradAA1 = grad(pAA1,x, y, z-1) + gradBA1 = grad(pBA1,x-1, y, z-1) + gradAB1 = grad(pAB1,x, y-1, z-1) + gradBB1 = grad(pBB1,x-1, y-1, z-1) + return lerp(w, + lerp(v, lerp(u, gradAA, gradBA), lerp(u, gradAB, gradBB)), + lerp(v, lerp(u, gradAA1,gradBA1),lerp(u, gradAB1,gradBB1))) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 73a960e..f62a862 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -108,6 +108,7 @@ set(minetest_SRCS clouds.cpp clientobject.cpp guiMainMenu.cpp + guiKeyChangeMenu.cpp guiMessageMenu.cpp guiTextInputMenu.cpp guiInventoryMenu.cpp diff --git a/src/client.cpp b/src/client.cpp index abc0565..e86b3a4 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -722,6 +722,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) */ //dstream<<"Updating"<deSerialize(istr, ser_version); + //block->setChangedFlag(); } catch(InvalidPositionException &e) { @@ -732,6 +733,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) block = new MapBlock(&m_env.getMap(), p); block->deSerialize(istr, ser_version); sector->insertBlock(block); + //block->setChangedFlag(); //DEBUG /*NodeMod mod; @@ -742,6 +744,27 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) block->setTempMod(v3s16(8,8,8), mod); block->setTempMod(v3s16(8,7,8), mod); block->setTempMod(v3s16(8,6,8), mod);*/ +#if 0 + /* + Add some coulds + Well, this is a dumb way to do it, they should just + be drawn as separate objects. But the looks of them + can be tested this way. + */ + if(p.Y == 3) + { + NodeMod mod; + mod.type = NODEMOD_CHANGECONTENT; + mod.param = CONTENT_CLOUD; + v3s16 p2; + p2.Y = 8; + for(p2.X=3; p2.X<=13; p2.X++) + for(p2.Z=3; p2.Z<=13; p2.Z++) + { + block->setTempMod(p2, mod); + } + } +#endif } } //envlock @@ -772,7 +795,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id) */ //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio()); - /* Add it to mesh update queue and set it to be acknowledged after update. */ diff --git a/src/content_craft.cpp b/src/content_craft.cpp index 32d2e6d..069e683 100644 --- a/src/content_craft.cpp +++ b/src/content_craft.cpp @@ -261,6 +261,24 @@ InventoryItem *craft_get_result(InventoryItem **items) } } + // Rail + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[1] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_RAIL, 15); + } + } + // Chest { ItemSpec specs[9]; @@ -313,6 +331,87 @@ InventoryItem *craft_get_result(InventoryItem **items) } } + // Sandstone + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_SANDSTONE, 1); + } + } + + // Clay + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + specs[4] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + specs[6] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + specs[7] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_CLAY, 1); + } + } + + // Brick + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_CRAFT, "clay_brick"); + specs[4] = ItemSpec(ITEM_CRAFT, "clay_brick"); + specs[6] = ItemSpec(ITEM_CRAFT, "clay_brick"); + specs[7] = ItemSpec(ITEM_CRAFT, "clay_brick"); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_BRICK, 1); + } + } + + // Paper + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS); + specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS); + specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS); + if(checkItemCombination(items, specs)) + { + return new CraftItem("paper", 1); + } + } + + // Book + { + ItemSpec specs[9]; + specs[1] = ItemSpec(ITEM_CRAFT, "paper"); + specs[4] = ItemSpec(ITEM_CRAFT, "paper"); + specs[7] = ItemSpec(ITEM_CRAFT, "paper"); + if(checkItemCombination(items, specs)) + { + return new CraftItem("book", 1); + } + } + + // Book shelf + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[3] = ItemSpec(ITEM_CRAFT, "book"); + specs[4] = ItemSpec(ITEM_CRAFT, "book"); + specs[5] = ItemSpec(ITEM_CRAFT, "book"); + specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_BOOKSHELF, 1); + } + } + return NULL; } @@ -353,10 +452,17 @@ void craft_set_creative_inventory(Player *player) CONTENT_MUD, CONTENT_STONE, CONTENT_SAND, + CONTENT_SANDSTONE, + CONTENT_CLAY, + CONTENT_BRICK, CONTENT_TREE, CONTENT_LEAVES, + CONTENT_CACTUS, + CONTENT_PAPYRUS, + CONTENT_BOOKSHELF, CONTENT_GLASS, CONTENT_FENCE, + CONTENT_RAIL, CONTENT_MESE, CONTENT_WATERSOURCE, CONTENT_CLOUD, diff --git a/src/content_inventory.cpp b/src/content_inventory.cpp index 3b72b31..357c8ef 100644 --- a/src/content_inventory.cpp +++ b/src/content_inventory.cpp @@ -48,12 +48,20 @@ std::string item_craft_get_image_name(const std::string &subname) { if(subname == "Stick") return "stick.png"; + else if(subname == "paper") + return "paper.png"; + else if(subname == "book") + return "book.png"; else if(subname == "lump_of_coal") return "lump_of_coal.png"; else if(subname == "lump_of_iron") return "lump_of_iron.png"; + else if(subname == "lump_of_clay") + return "lump_of_clay.png"; else if(subname == "steel_ingot") return "steel_ingot.png"; + else if(subname == "clay_brick") + return "clay_brick.png"; else if(subname == "rat") return "rat.png"; else @@ -82,7 +90,7 @@ s16 item_craft_get_drop_count(const std::string &subname) bool item_craft_is_cookable(const std::string &subname) { - if(subname == "lump_of_iron") + if(subname == "lump_of_iron" || subname == "lump_of_clay") return true; return false; @@ -92,6 +100,8 @@ InventoryItem* item_craft_create_cook_result(const std::string &subname) { if(subname == "lump_of_iron") return new CraftItem("steel_ingot", 1); + else if(subname == "lump_of_clay") + return new CraftItem("clay_brick", 1); return NULL; } diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index bc701aa..9ef0599 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -188,6 +188,16 @@ void mapblock_mesh_generate_special(MeshMakeData *data, material_general.setFlag(video::EMF_FOG_ENABLE, true); material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + + // Papyrus material + video::SMaterial material_papyrus; + material_papyrus.setFlag(video::EMF_LIGHTING, false); + material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false); + material_papyrus.setFlag(video::EMF_FOG_ENABLE, true); + material_papyrus.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + AtlasPointer pa_papyrus = g_texturesource->getTexture( + g_texturesource->getTextureId("papyrus.png")); + material_papyrus.setTexture(0, pa_papyrus.atlas); for(s16 z=0; zm_daynight_ratio))); + video::SColor c(255,l,l,l); + for(u32 j=0; j<4; j++) + { + video::S3DVertex vertices[4] = + { + video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, + pa_papyrus.x0(), pa_papyrus.y1()), + video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, + pa_papyrus.x1(), pa_papyrus.y1()), + video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, + pa_papyrus.x1(), pa_papyrus.y0()), + video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, + pa_papyrus.x0(), pa_papyrus.y0()), + }; + + if(j == 0) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(45); + } + else if(j == 1) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(-45); + } + else if(j == 2) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(135); + } + else if(j == 3) + { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(-135); + } + + for(u16 i=0; i<4; i++) + { + vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + } + + u16 indices[] = {0,1,2,2,3,0}; + // Add to mesh collector + collector.append(material_papyrus, vertices, 4, indices, 6); + } + } + else if(n.d == CONTENT_RAIL) + { + u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); + video::SColor c(255,l,l,l); + + bool is_rail_x [] = { false, false }; /* x-1, x+1 */ + bool is_rail_z [] = { false, false }; /* z-1, z+1 */ + + MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z)); + MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z)); + MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1)); + MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1)); + + if(n_minus_x.d == CONTENT_RAIL) + is_rail_x[0] = true; + if(n_plus_x.d == CONTENT_RAIL) + is_rail_x[1] = true; + if(n_minus_z.d == CONTENT_RAIL) + is_rail_z[0] = true; + if(n_plus_z.d == CONTENT_RAIL) + is_rail_z[1] = true; + + float d = (float)BS/16; + video::S3DVertex vertices[4] = + { + video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c, + 0, 1), + video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c, + 1, 1), + video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c, + 1, 0), + video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c, + 0, 0), + }; + + video::SMaterial material_rail; + material_rail.setFlag(video::EMF_LIGHTING, false); + material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false); + material_rail.setFlag(video::EMF_BILINEAR_FILTER, false); + material_rail.setFlag(video::EMF_FOG_ENABLE, true); + material_rail.MaterialType + = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + + int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1]; + + // Assign textures + if(adjacencies < 2) + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png")); + else if(adjacencies == 2) + { + if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1])) + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png")); + else + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_curved.png")); + } + else if(adjacencies == 3) + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_t_junction.png")); + else if(adjacencies == 4) + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_crossing.png")); + + // Rotate textures + int angle = 0; + + if(adjacencies == 1) + { + if(is_rail_x[0] || is_rail_x[1]) + angle = 90; + } + else if(adjacencies == 2) + { + if(is_rail_x[0] && is_rail_x[1]) + angle = 90; + else if(is_rail_x[0] && is_rail_z[0]) + angle = 270; + else if(is_rail_x[0] && is_rail_z[1]) + angle = 180; + else if(is_rail_x[1] && is_rail_z[1]) + angle = 90; + } + else if(adjacencies == 3) + { + if(!is_rail_x[0]) + angle=0; + if(!is_rail_x[1]) + angle=180; + if(!is_rail_z[0]) + angle=90; + if(!is_rail_z[1]) + angle=270; + } + + if(angle != 0) { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(angle); + } + + for(s32 i=0; i<4; i++) + { + vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + } + + u16 indices[] = {0,1,2,2,3,0}; + collector.append(material_rail, vertices, 4, indices, 6); + } } } #endif diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp index 403fb66..2e7a240 100644 --- a/src/content_mapnode.cpp +++ b/src/content_mapnode.cpp @@ -99,6 +99,33 @@ void content_mapnode_init() f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; setDirtLikeDiggingProperties(f->digging_properties, 1.75); + i = CONTENT_SANDSTONE; + f = &content_features(i); + f->setAllTextures("sandstone.png"); + f->setInventoryTextureCube("sandstone.png", "sandstone.png", "sandstone.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(CONTENT_SAND)+" 1"; + setDirtLikeDiggingProperties(f->digging_properties, 1.0); + + i = CONTENT_CLAY; + f = &content_features(i); + f->setAllTextures("clay.png"); + f->setInventoryTextureCube("clay.png", "clay.png", "clay.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + f->dug_item = std::string("CraftItem lump_of_clay 4"); + setDirtLikeDiggingProperties(f->digging_properties, 1.0); + + i = CONTENT_BRICK; + f = &content_features(i); + f->setAllTextures("brick.png"); + f->setInventoryTextureCube("brick.png", "brick.png", "brick.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + f->dug_item = std::string("CraftItem clay_brick 4"); + setStoneLikeDiggingProperties(f->digging_properties, 1.0); + i = CONTENT_TREE; f = &content_features(i); f->setAllTextures("tree.png"); @@ -127,6 +154,40 @@ void content_mapnode_init() f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; setWoodLikeDiggingProperties(f->digging_properties, 0.15); + i = CONTENT_CACTUS; + f = &content_features(i); + f->setAllTextures("cactus_side.png"); + f->setTexture(0, "cactus_top.png"); + f->setTexture(1, "cactus_top.png"); + f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + setWoodLikeDiggingProperties(f->digging_properties, 0.75); + + i = CONTENT_PAPYRUS; + f = &content_features(i); + f->setInventoryTexture("papyrus.png"); + f->light_propagates = true; + f->param_type = CPT_LIGHT; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + f->solidness = 0; // drawn separately, makes no faces + f->walkable = false; + setWoodLikeDiggingProperties(f->digging_properties, 0.25); + + i = CONTENT_BOOKSHELF; + f = &content_features(i); + f->setAllTextures("bookshelf.png"); + f->setTexture(0, "wood.png"); + f->setTexture(1, "wood.png"); + // FIXME: setInventoryTextureCube() only cares for the first texture + f->setInventoryTextureCube("bookshelf.png", "bookshelf.png", "bookshelf.png"); + //f->setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + setWoodLikeDiggingProperties(f->digging_properties, 0.75); + i = CONTENT_GLASS; f = &content_features(i); f->light_propagates = true; @@ -148,6 +209,18 @@ void content_mapnode_init() f->setInventoryTexture("item_fence.png"); setWoodLikeDiggingProperties(f->digging_properties, 0.75); + i = CONTENT_RAIL; + f = &content_features(i); + f->setInventoryTexture("rail.png"); + f->light_propagates = true; + f->param_type = CPT_LIGHT; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + f->solidness = 0; // drawn separately, makes no faces + f->air_equivalent = true; // grass grows underneath + f->walkable = false; + setDirtLikeDiggingProperties(f->digging_properties, 0.75); + // Deprecated i = CONTENT_COALSTONE; f = &content_features(i); diff --git a/src/content_mapnode.h b/src/content_mapnode.h index e314807..e53624c 100644 --- a/src/content_mapnode.h +++ b/src/content_mapnode.h @@ -50,6 +50,13 @@ void content_mapnode_init(); #define CONTENT_FENCE 21 #define CONTENT_MOSSYCOBBLE 22 #define CONTENT_GRAVEL 23 +#define CONTENT_SANDSTONE 24 +#define CONTENT_CACTUS 25 +#define CONTENT_BRICK 26 +#define CONTENT_CLAY 27 +#define CONTENT_PAPYRUS 28 +#define CONTENT_BOOKSHELF 29 +#define CONTENT_RAIL 30 #endif diff --git a/src/environment.cpp b/src/environment.cpp index cd25534..e2c7042 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -592,7 +592,7 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime) block->setTimestamp(m_game_time); //dstream<<"Block is "<getBlockNoCreateNoEx(p); if(block==NULL) continue; - // Set current time as timestamp (and let it set ChangedFlag) + block->setTimestamp(m_game_time); } @@ -776,7 +776,75 @@ void ServerEnvironment::step(float dtime) if(block==NULL) continue; - activateBlock(block); + // Get time difference + u32 dtime_s = 0; + u32 stamp = block->getTimestamp(); + if(m_game_time > stamp && stamp != BLOCK_TIMESTAMP_UNDEFINED) + dtime_s = m_game_time - block->getTimestamp(); + + // Set current time as timestamp (and let it set ChangedFlag) + block->setTimestamp(m_game_time); + + //dstream<<"Block is "<m_node_metadata.step((float)dtime_s); + if(changed) + { + MapEditEvent event; + event.type = MEET_BLOCK_NODE_METADATA_CHANGED; + event.p = p; + m_map->dispatchEvent(&event); + + block->setChangedFlag(); + } + + // TODO: Do something + // TODO: Implement usage of ActiveBlockModifier + + // Here's a quick demonstration + v3s16 p0; + for(p0.X=0; p0.XgetPosRelative(); + MapNode n = block->getNodeNoEx(p0); + // Test something: + // Convert all mud under proper day lighting to grass + if(n.d == CONTENT_MUD) + { + if(dtime_s > 300) + { + MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0)); + if(content_features(n_top.d).air_equivalent && + n_top.getLight(LIGHTBANK_DAY) >= 13) + { + n.d = CONTENT_GRASS; + m_map->addNodeWithEvent(p, n); + } + } + } + /* + Convert grass into mud if under something else than air + */ + else if(n.d == CONTENT_GRASS) + { + //if(myrand()%20 == 0) + { + MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0)); + if(n_top.d != CONTENT_AIR + && n_top.d != CONTENT_IGNORE) + { + n.d = CONTENT_MUD; + m_map->addNodeWithEvent(p, n); + } + } + } + } } } @@ -889,8 +957,8 @@ void ServerEnvironment::step(float dtime) n.d = CONTENT_MUD; m_map->addNodeWithEvent(p, n); } + } } - } } } } diff --git a/src/game.cpp b/src/game.cpp index f3fac0c..5632c18 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -534,6 +534,43 @@ void getPointedNode(Client *client, v3f player_position, } } } + else if(n.d == CONTENT_RAIL) + { + v3s16 dir = unpackDir(n.dir); + v3f dir_f = v3f(dir.X, dir.Y, dir.Z); + dir_f *= BS/2 - BS/6 - BS/20; + v3f cpf = npf + dir_f; + f32 distance = (cpf - camera_position).getLength(); + + float d = (float)BS/16; + v3f vertices[4] = + { + v3f(BS/2, -BS/2+d, -BS/2), + v3f(-BS/2, -BS/2, BS/2), + }; + + for(s32 i=0; i<2; i++) + { + vertices[i] += npf; + } + + core::aabbox3d box; + + box = core::aabbox3d(vertices[0]); + box.addInternalPoint(vertices[1]); + + if(distance < mindistance) + { + if(box.intersectsWithLine(shootline)) + { + nodefound = true; + nodepos = np; + neighbourpos = np; + mindistance = distance; + nodehilightbox = box; + } + } + } /* Regular blocks */ diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp index ef0a013..cea3286 100644 --- a/src/guiMainMenu.cpp +++ b/src/guiMainMenu.cpp @@ -18,10 +18,13 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "guiMainMenu.h" +#include "guiKeyChangeMenu.h" #include "debug.h" #include "serialization.h" #include + + GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, @@ -34,6 +37,10 @@ GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env, m_gamecallback(gamecallback) { assert(m_data); + this->env = env; + this->parent = parent; + this->id = id; + this->menumgr = menumgr; } GUIMainMenu::~GUIMainMenu() @@ -70,35 +77,35 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) // Client options { - gui::IGUIElement *e = getElementFromId(258); + gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT); if(e != NULL) text_name = e->getText(); else text_name = m_data->name; } { - gui::IGUIElement *e = getElementFromId(256); + gui::IGUIElement *e = getElementFromId(GUI_ID_ADDRESS_INPUT); if(e != NULL) text_address = e->getText(); else text_address = m_data->address; } { - gui::IGUIElement *e = getElementFromId(257); + gui::IGUIElement *e = getElementFromId(GUI_ID_PORT_INPUT); if(e != NULL) text_port = e->getText(); else text_port = m_data->port; } { - gui::IGUIElement *e = getElementFromId(263); + gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) fancy_trees = ((gui::IGUICheckBox*)e)->isChecked(); else fancy_trees = m_data->fancy_trees; } { - gui::IGUIElement *e = getElementFromId(262); + gui::IGUIElement *e = getElementFromId(GUI_ID_SMOOTH_LIGHTING_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked(); else @@ -107,14 +114,14 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) // Server options { - gui::IGUIElement *e = getElementFromId(259); + gui::IGUIElement *e = getElementFromId(GUI_ID_CREATIVE_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) creative_mode = ((gui::IGUICheckBox*)e)->isChecked(); else creative_mode = m_data->creative_mode; } { - gui::IGUIElement *e = getElementFromId(261); + gui::IGUIElement *e = getElementFromId(GUI_ID_DAMAGE_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) enable_damage = ((gui::IGUICheckBox*)e)->isChecked(); else @@ -175,7 +182,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) core::rect rect(0, 0, 230, 30); rect += topleft_client + v2s32(160, 50); gui::IGUIElement *e = - Environment->addEditBox(text_name.c_str(), rect, true, this, 258); + Environment->addEditBox(text_name.c_str(), rect, true, this, GUI_ID_NAME_INPUT); if(text_name == L"") Environment->setFocus(e); } @@ -198,7 +205,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) core::rect rect(0, 0, 230, 30); rect += topleft_client + v2s32(160, 100); gui::IGUIElement *e = - Environment->addEditBox(text_address.c_str(), rect, true, this, 256); + Environment->addEditBox(text_address.c_str(), rect, true, this, GUI_ID_ADDRESS_INPUT); if(text_name != L"") Environment->setFocus(e); } @@ -206,7 +213,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) core::rect rect(0, 0, 120, 30); //rect += topleft_client + v2s32(160+250+20, 125); rect += topleft_client + v2s32(size_client.X-60-100, 100); - Environment->addEditBox(text_port.c_str(), rect, true, this, 257); + Environment->addEditBox(text_port.c_str(), rect, true, this, GUI_ID_PORT_INPUT); } { core::rect rect(0, 0, 400, 20); @@ -217,13 +224,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) { core::rect rect(0, 0, 250, 30); rect += topleft_client + v2s32(35, 150); - Environment->addCheckBox(fancy_trees, rect, this, 263, + Environment->addCheckBox(fancy_trees, rect, this, GUI_ID_FANCYTREE_CB, L"Fancy trees"); } { core::rect rect(0, 0, 250, 30); rect += topleft_client + v2s32(35, 150+30); - Environment->addCheckBox(smooth_lighting, rect, this, 262, + Environment->addCheckBox(smooth_lighting, rect, this, GUI_ID_SMOOTH_LIGHTING_CB, L"Smooth Lighting"); } // Start game button @@ -231,9 +238,16 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) core::rect rect(0, 0, 180, 30); //rect += topleft_client + v2s32(size_client.X/2-180/2, 225-30/2); rect += topleft_client + v2s32(size_client.X-180-40, 150+25); - Environment->addButton(rect, this, 257, L"Start Game / Connect"); + Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON, L"Start Game / Connect"); } + // Key change button + { + core::rect rect(0, 0, 100, 30); + //rect += topleft_client + v2s32(size_client.X/2-180/2, 225-30/2); + rect += topleft_client + v2s32(size_client.X-180-40-100-20, 150+25); + Environment->addButton(rect, this, GUI_ID_CHANGE_KEYS_BUTTON, L"Change keys"); + } /* Server section */ @@ -254,19 +268,19 @@ void GUIMainMenu::regenerateGui(v2u32 screensize) { core::rect rect(0, 0, 250, 30); rect += topleft_server + v2s32(35, 30); - Environment->addCheckBox(creative_mode, rect, this, 259, L"Creative Mode"); + Environment->addCheckBox(creative_mode, rect, this, GUI_ID_CREATIVE_CB, L"Creative Mode"); } { core::rect rect(0, 0, 250, 30); rect += topleft_server + v2s32(35, 60); - Environment->addCheckBox(enable_damage, rect, this, 261, L"Enable Damage"); + Environment->addCheckBox(enable_damage, rect, this, GUI_ID_DAMAGE_CB, L"Enable Damage"); } // Map delete button { core::rect rect(0, 0, 130, 30); //rect += topleft_server + v2s32(size_server.X-40-130, 100+25); rect += topleft_server + v2s32(40, 100+25); - Environment->addButton(rect, this, 260, L"Delete world"); + Environment->addButton(rect, this, GUI_ID_DELETE_MAP_BUTTON, L"Delete map"); } } @@ -300,7 +314,7 @@ void GUIMainMenu::drawMenu() void GUIMainMenu::acceptInput() { { - gui::IGUIElement *e = getElementFromId(258); + gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT); if(e != NULL) m_data->name = e->getText(); } @@ -310,32 +324,32 @@ void GUIMainMenu::acceptInput() m_data->password = e->getText(); } { - gui::IGUIElement *e = getElementFromId(256); + gui::IGUIElement *e = getElementFromId(GUI_ID_ADDRESS_INPUT); if(e != NULL) m_data->address = e->getText(); } { - gui::IGUIElement *e = getElementFromId(257); + gui::IGUIElement *e = getElementFromId(GUI_ID_PORT_INPUT); if(e != NULL) m_data->port = e->getText(); } { - gui::IGUIElement *e = getElementFromId(259); + gui::IGUIElement *e = getElementFromId(GUI_ID_CREATIVE_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) m_data->creative_mode = ((gui::IGUICheckBox*)e)->isChecked(); } { - gui::IGUIElement *e = getElementFromId(261); + gui::IGUIElement *e = getElementFromId(GUI_ID_DAMAGE_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) m_data->enable_damage = ((gui::IGUICheckBox*)e)->isChecked(); } { - gui::IGUIElement *e = getElementFromId(262); + gui::IGUIElement *e = getElementFromId(GUI_ID_SMOOTH_LIGHTING_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) m_data->smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked(); } { - gui::IGUIElement *e = getElementFromId(263); + gui::IGUIElement *e = getElementFromId(GUI_ID_FANCYTREE_CB); if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) m_data->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked(); } @@ -377,11 +391,16 @@ bool GUIMainMenu::OnEvent(const SEvent& event) { switch(event.GUIEvent.Caller->getID()) { - case 257: // Start game + case GUI_ID_JOIN_GAME_BUTTON: // Start game acceptInput(); quitMenu(); return true; - case 260: // Delete map + case GUI_ID_CHANGE_KEYS_BUTTON: { + GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(env, parent, -1,menumgr); + kmenu->drop(); + return true; + } + case GUI_ID_DELETE_MAP_BUTTON: // Delete map // Don't accept input data, just set deletion request m_data->delete_map = true; m_accepted = true; @@ -393,7 +412,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event) { switch(event.GUIEvent.Caller->getID()) { - case 256: case 257: case 258: case 264: + case GUI_ID_ADDRESS_INPUT: case GUI_ID_PORT_INPUT: case GUI_ID_NAME_INPUT: case 264: acceptInput(); quitMenu(); return true; diff --git a/src/guiMainMenu.h b/src/guiMainMenu.h index edd5190..87561f7 100644 --- a/src/guiMainMenu.h +++ b/src/guiMainMenu.h @@ -27,6 +27,21 @@ with this program; if not, write to the Free Software Foundation, Inc., // For IGameCallback #include "guiPauseMenu.h" +enum +{ + GUI_ID_QUIT_BUTTON = 101, + GUI_ID_NAME_INPUT, + GUI_ID_ADDRESS_INPUT, + GUI_ID_PORT_INPUT, + GUI_ID_FANCYTREE_CB, + GUI_ID_SMOOTH_LIGHTING_CB, + GUI_ID_DAMAGE_CB, + GUI_ID_CREATIVE_CB, + GUI_ID_JOIN_GAME_BUTTON, + GUI_ID_CHANGE_KEYS_BUTTON, + GUI_ID_DELETE_MAP_BUTTON +}; + struct MainMenuData { MainMenuData(): @@ -87,6 +102,11 @@ private: MainMenuData *m_data; bool m_accepted; IGameCallback *m_gamecallback; + + gui::IGUIEnvironment* env; + gui::IGUIElement* parent; + s32 id; + IMenuManager *menumgr; }; #endif diff --git a/src/keycode.cpp b/src/keycode.cpp index ad3c0b4..f014914 100644 --- a/src/keycode.cpp +++ b/src/keycode.cpp @@ -171,6 +171,46 @@ irr::EKEY_CODE keyname_to_keycode(const char *name) return irr::KEY_KEY_CODES_COUNT; } +static const char *KeyNames[] = +{ "-", "KEY_LBUTTON", "KEY_RBUTTON", "Cancel", "Middle Button", "X Button 1", + "X Button 2", "-", "Back", "Tab", "-", "-", "Clear", "Return", "-", + "-", "KEY_SHIFT", "Control", "Menu", "Pause", "Capital", "Kana", "-", + "Junja", "Final", "Kanji", "-", "Escape", "Convert", "Nonconvert", + "Accept", "Mode Change", "KEY_SPACE", "Priot", "Next", "KEY_END", + "KEY_HOME", "Left", "Up", "Right", "Down", "Select", "KEY_PRINT", + "Execute", "Snapshot", "Insert", "Delete", "Help", "KEY_KEY_0", + "KEY_KEY_1", "KEY_KEY_2", "KEY_KEY_3", "KEY_KEY_4", "KEY_KEY_5", + "KEY_KEY_6", "KEY_KEY_7", "KEY_KEY_8", "KEY_KEY_9", "-", "-", "-", "-", + "-", "-", "-", "KEY_KEY_A", "KEY_KEY_B", "KEY_KEY_C", "KEY_KEY_D", + "KEY_KEY_E", "KEY_KEY_F", "KEY_KEY_G", "KEY_KEY_H", "KEY_KEY_I", + "KEY_KEY_J", "KEY_KEY_K", "KEY_KEY_L", "KEY_KEY_M", "KEY_KEY_N", + "KEY_KEY_O", "KEY_KEY_P", "KEY_KEY_Q", "KEY_KEY_R", "KEY_KEY_S", + "KEY_KEY_T", "KEY_KEY_U", "KEY_KEY_V", "KEY_KEY_W", "KEY_KEY_X", + "KEY_KEY_Y", "KEY_KEY_Z", "Left Windows", "Right Windows", "Apps", "-", + "Sleep", "KEY_NUMPAD0", "KEY_NUMPAD1", "KEY_NUMPAD2", "KEY_NUMPAD3", + "KEY_NUMPAD4", "KEY_NUMPAD5", "KEY_NUMPAD6", "KEY_NUMPAD7", + "KEY_NUMPAD8", "KEY_NUMPAD9", "Numpad *", "Numpad +", "Numpad /", + "Numpad -", "Numpad .", "Numpad /", "KEY_F1", "KEY_F2", "KEY_F3", + "KEY_F4", "KEY_F5", "KEY_F6", "KEY_F7", "KEY_F8", "KEY_F9", "KEY_F10", + "KEY_F11", "KEY_F12", "KEY_F13", "KEY_F14", "KEY_F15", "KEY_F16", + "KEY_F17", "KEY_F18", "KEY_F19", "KEY_F20", "KEY_F21", "KEY_F22", + "KEY_F23", "KEY_F24", "-", "-", "-", "-", "-", "-", "-", "-", + "Num Lock", "Scroll Lock", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "KEY_LSHIFT", "KEY_RSHIFT", "Left Control", + "Right Control", "Left Menu", "Right Menu", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "Plus", "Comma", "Minus", "Period", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "Attn", "CrSel", "ExSel", + "Erase OEF", "Play", "Zoom", "PA1", "OEM Clear", "-" }; + +std::string keycode_to_keyname(s32 keycode) +{ + return KeyNames[keycode]; +} + /* Key config */ @@ -189,4 +229,7 @@ irr::EKEY_CODE getKeySetting(const char *settingname) return c; } - +void clearKeyCache() +{ + g_key_setting_cache.clear(); +} diff --git a/src/keycode.h b/src/keycode.h index f19fe34..9c62004 100644 --- a/src/keycode.h +++ b/src/keycode.h @@ -21,11 +21,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #define KEYCODE_HEADER #include "common_irrlicht.h" +#include irr::EKEY_CODE keyname_to_keycode(const char *name); // Key configuration getter irr::EKEY_CODE getKeySetting(const char *settingname); +std::string keycode_to_keyname(s32 keycode); +void clearCache(); #endif