Merge branch 'master' of https://github.com/erlehmann/minetest-delta.git into upstream_merge

Conflicts:
	.gitignore
	CMakeLists.txt
	data/heart.png
	src/CMakeLists.txt
	src/game.cpp
	src/guiMainMenu.cpp
	src/inventory.cpp
	src/map.cpp
	src/mapblock.cpp
	src/mapnode.cpp
	src/mapnode.h
	src/materials.cpp
	src/server.cpp

Signed-off-by: Sebastian Rühl <bahamada_basti@yahoo.de>
This commit is contained in:
Sebastian Rühl 2011-06-26 12:24:32 +02:00
commit 033ae0dcae
43 changed files with 1312 additions and 48 deletions

2
.gitignore vendored

@ -19,4 +19,4 @@ cmake_install.cmake
src/jthread/libjthread.a src/jthread/libjthread.a
debug.txt debug.txt
bin/debug.txt bin/debug.txt
minetestmapper/map.png

@ -59,7 +59,7 @@ elseif(UNIX) # Linux, BSD etc
set(EXAMPLE_CONF_DIR "share/doc/minetest") set(EXAMPLE_CONF_DIR "share/doc/minetest")
endif() endif()
install(FILES "README.txt" DESTINATION "${DOCDIR}") install(FILES "doc/README.txt" DESTINATION "${DOCDIR}")
install(FILES "minetest.conf.example" DESTINATION "${DOCDIR}") install(FILES "minetest.conf.example" DESTINATION "${DOCDIR}")
# #
@ -104,7 +104,7 @@ elseif(APPLE)
set(CPACK_BUNDLE_ICON "") set(CPACK_BUNDLE_ICON "")
set(CPACK_BUNDLE_PLIST "") set(CPACK_BUNDLE_PLIST "")
set(CPACK_BUNDLE_STARTUP_COMMAND "Contents/MacOS/minetest") set(CPACK_BUNDLE_STARTUP_COMMAND "Contents/MacOS/minetest")
set(CPACK_GENERATOR Bundle) set(CPACK_GENERATOR "Bundle")
else() else()
set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-linux") set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-linux")
set(CPACK_GENERATOR TGZ) set(CPACK_GENERATOR TGZ)

29
README Normal file

@ -0,0 +1,29 @@
Minetest Δ (“Minetest Delta”) is a fork of Minetest-c55 <http://celeron.55.lt/~celeron55/minetest/>, 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

BIN
data/book.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

BIN
data/bookshelf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

BIN
data/brick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

BIN
data/cactus_side.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

BIN
data/cactus_top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

BIN
data/clay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

BIN
data/clay_brick.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

BIN
data/fence.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 381 B

BIN
data/lump_of_clay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 270 B

BIN
data/paper.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

BIN
data/papyrus.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 B

After

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 292 B

BIN
data/rail.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

BIN
data/rail_crossing.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 B

BIN
data/rail_curved.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 545 B

BIN
data/rail_t_junction.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 920 B

After

Width:  |  Height:  |  Size: 276 B

BIN
data/sandstone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 772 B

271
genmap.py Executable file

@ -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

BIN
heart.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 B

25
minetestmapper/colors.txt Normal file

@ -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

275
minetestmapper/minetestmapper2.py Executable file

@ -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<l):
i=l
return i
# Fix these!
path="../map/"
output="map.png"
sector_xmin = -1000/16
sector_xmax = 1000/16
sector_zmin = -1000/16
sector_zmax = 1000/16
# Load color information for the blocks.
colors = {}
f = file("colors.txt")
for line in f:
values = string.split(line)
colors[int(values[0])] = (int(values[1]), int(values[2]), int(values[3]))
f.close()
xlist = []
zlist = []
# List all sectors to memory and calculate the width and heigth of the resulting picture.
if os.path.exists(path + "sectors2"):
for filename in os.listdir(path + "sectors2"):
for filename2 in os.listdir(path + "sectors2/" + filename):
x = hex_to_int(filename)
z = hex_to_int(filename2)
if x < sector_xmin or x > 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)

102
pnoise.py Normal file

@ -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)))

@ -108,6 +108,7 @@ set(minetest_SRCS
clouds.cpp clouds.cpp
clientobject.cpp clientobject.cpp
guiMainMenu.cpp guiMainMenu.cpp
guiKeyChangeMenu.cpp
guiMessageMenu.cpp guiMessageMenu.cpp
guiTextInputMenu.cpp guiTextInputMenu.cpp
guiInventoryMenu.cpp guiInventoryMenu.cpp

@ -722,6 +722,7 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
*/ */
//dstream<<"Updating"<<std::endl; //dstream<<"Updating"<<std::endl;
block->deSerialize(istr, ser_version); block->deSerialize(istr, ser_version);
//block->setChangedFlag();
} }
catch(InvalidPositionException &e) 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 = new MapBlock(&m_env.getMap(), p);
block->deSerialize(istr, ser_version); block->deSerialize(istr, ser_version);
sector->insertBlock(block); sector->insertBlock(block);
//block->setChangedFlag();
//DEBUG //DEBUG
/*NodeMod mod; /*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,8,8), mod);
block->setTempMod(v3s16(8,7,8), mod); block->setTempMod(v3s16(8,7,8), mod);
block->setTempMod(v3s16(8,6,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 } //envlock
@ -772,7 +795,6 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
*/ */
//m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio()); //m_env.getClientMap().updateMeshes(block->getPos(), getDayNightRatio());
/* /*
Add it to mesh update queue and set it to be acknowledged after update. Add it to mesh update queue and set it to be acknowledged after update.
*/ */

@ -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 // Chest
{ {
ItemSpec specs[9]; 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; return NULL;
} }
@ -353,10 +452,17 @@ void craft_set_creative_inventory(Player *player)
CONTENT_MUD, CONTENT_MUD,
CONTENT_STONE, CONTENT_STONE,
CONTENT_SAND, CONTENT_SAND,
CONTENT_SANDSTONE,
CONTENT_CLAY,
CONTENT_BRICK,
CONTENT_TREE, CONTENT_TREE,
CONTENT_LEAVES, CONTENT_LEAVES,
CONTENT_CACTUS,
CONTENT_PAPYRUS,
CONTENT_BOOKSHELF,
CONTENT_GLASS, CONTENT_GLASS,
CONTENT_FENCE, CONTENT_FENCE,
CONTENT_RAIL,
CONTENT_MESE, CONTENT_MESE,
CONTENT_WATERSOURCE, CONTENT_WATERSOURCE,
CONTENT_CLOUD, CONTENT_CLOUD,

@ -48,12 +48,20 @@ std::string item_craft_get_image_name(const std::string &subname)
{ {
if(subname == "Stick") if(subname == "Stick")
return "stick.png"; return "stick.png";
else if(subname == "paper")
return "paper.png";
else if(subname == "book")
return "book.png";
else if(subname == "lump_of_coal") else if(subname == "lump_of_coal")
return "lump_of_coal.png"; return "lump_of_coal.png";
else if(subname == "lump_of_iron") else if(subname == "lump_of_iron")
return "lump_of_iron.png"; return "lump_of_iron.png";
else if(subname == "lump_of_clay")
return "lump_of_clay.png";
else if(subname == "steel_ingot") else if(subname == "steel_ingot")
return "steel_ingot.png"; return "steel_ingot.png";
else if(subname == "clay_brick")
return "clay_brick.png";
else if(subname == "rat") else if(subname == "rat")
return "rat.png"; return "rat.png";
else else
@ -82,7 +90,7 @@ s16 item_craft_get_drop_count(const std::string &subname)
bool item_craft_is_cookable(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 true;
return false; return false;
@ -92,6 +100,8 @@ InventoryItem* item_craft_create_cook_result(const std::string &subname)
{ {
if(subname == "lump_of_iron") if(subname == "lump_of_iron")
return new CraftItem("steel_ingot", 1); return new CraftItem("steel_ingot", 1);
else if(subname == "lump_of_clay")
return new CraftItem("clay_brick", 1);
return NULL; return NULL;
} }

@ -188,6 +188,16 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
material_general.setFlag(video::EMF_FOG_ENABLE, true); material_general.setFlag(video::EMF_FOG_ENABLE, true);
material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; 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; z<MAP_BLOCKSIZE; z++) for(s16 z=0; z<MAP_BLOCKSIZE; z++)
for(s16 y=0; y<MAP_BLOCKSIZE; y++) for(s16 y=0; y<MAP_BLOCKSIZE; y++)
for(s16 x=0; x<MAP_BLOCKSIZE; x++) for(s16 x=0; x<MAP_BLOCKSIZE; x++)
@ -857,9 +867,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
TileSpec ts = n.getTile(dir); TileSpec ts = n.getTile(dir);
AtlasPointer ap = ts.texture; AtlasPointer ap = ts.texture;
material_general.setTexture(0, ap.atlas); material_general.setTexture(0, ap.atlas);
video::S3DVertex vertices[4] = video::S3DVertex vertices[4] =
{ {
/*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1), /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1),
video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1), video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1),
video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0), video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0),
@ -895,15 +904,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
vertices[i].Pos.rotateXZBy(90); vertices[i].Pos.rotateXZBy(90);
} }
else if(j == 4) else if(j == 4)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateYZBy(-90);
}
else if(j == 5)
{
for(u16 i=0; i<4; i++)
vertices[i].Pos.rotateYZBy(90);
}
for(u16 i=0; i<4; i++) for(u16 i=0; i<4; i++)
{ {
@ -916,7 +916,160 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
} }
} }
#endif #endif
else if(n.d == CONTENT_PAPYRUS)
{
u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_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 #endif

@ -99,6 +99,33 @@ void content_mapnode_init()
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
setDirtLikeDiggingProperties(f->digging_properties, 1.75); 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; i = CONTENT_TREE;
f = &content_features(i); f = &content_features(i);
f->setAllTextures("tree.png"); f->setAllTextures("tree.png");
@ -127,6 +154,40 @@ void content_mapnode_init()
f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
setWoodLikeDiggingProperties(f->digging_properties, 0.15); 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; i = CONTENT_GLASS;
f = &content_features(i); f = &content_features(i);
f->light_propagates = true; f->light_propagates = true;
@ -148,6 +209,18 @@ void content_mapnode_init()
f->setInventoryTexture("item_fence.png"); f->setInventoryTexture("item_fence.png");
setWoodLikeDiggingProperties(f->digging_properties, 0.75); 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 // Deprecated
i = CONTENT_COALSTONE; i = CONTENT_COALSTONE;
f = &content_features(i); f = &content_features(i);

@ -50,6 +50,13 @@ void content_mapnode_init();
#define CONTENT_FENCE 21 #define CONTENT_FENCE 21
#define CONTENT_MOSSYCOBBLE 22 #define CONTENT_MOSSYCOBBLE 22
#define CONTENT_GRAVEL 23 #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 #endif

@ -754,8 +754,8 @@ void ServerEnvironment::step(float dtime)
MapBlock *block = m_map->getBlockNoCreateNoEx(p); MapBlock *block = m_map->getBlockNoCreateNoEx(p);
if(block==NULL) if(block==NULL)
continue; continue;
// Set current time as timestamp (and let it set ChangedFlag) // Set current time as timestamp (and let it set ChangedFlag)
block->setTimestamp(m_game_time); block->setTimestamp(m_game_time);
} }
@ -776,7 +776,75 @@ void ServerEnvironment::step(float dtime)
if(block==NULL) if(block==NULL)
continue; 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 "<<dtime_s<<" seconds old."<<std::endl;
// Activate stored objects
activateObjects(block);
// Run node metadata
bool changed = block->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.X<MAP_BLOCKSIZE; p0.X++)
for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
{
v3s16 p = p0 + block->getPosRelative();
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; n.d = CONTENT_MUD;
m_map->addNodeWithEvent(p, n); m_map->addNodeWithEvent(p, n);
} }
}
} }
}
} }
} }
} }

@ -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<f32> box;
box = core::aabbox3d<f32>(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 Regular blocks
*/ */

@ -18,10 +18,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/ */
#include "guiMainMenu.h" #include "guiMainMenu.h"
#include "guiKeyChangeMenu.h"
#include "debug.h" #include "debug.h"
#include "serialization.h" #include "serialization.h"
#include <string> #include <string>
GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env, GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id, gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr, IMenuManager *menumgr,
@ -34,6 +37,10 @@ GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env,
m_gamecallback(gamecallback) m_gamecallback(gamecallback)
{ {
assert(m_data); assert(m_data);
this->env = env;
this->parent = parent;
this->id = id;
this->menumgr = menumgr;
} }
GUIMainMenu::~GUIMainMenu() GUIMainMenu::~GUIMainMenu()
@ -70,35 +77,35 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
// Client options // Client options
{ {
gui::IGUIElement *e = getElementFromId(258); gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT);
if(e != NULL) if(e != NULL)
text_name = e->getText(); text_name = e->getText();
else else
text_name = m_data->name; text_name = m_data->name;
} }
{ {
gui::IGUIElement *e = getElementFromId(256); gui::IGUIElement *e = getElementFromId(GUI_ID_ADDRESS_INPUT);
if(e != NULL) if(e != NULL)
text_address = e->getText(); text_address = e->getText();
else else
text_address = m_data->address; text_address = m_data->address;
} }
{ {
gui::IGUIElement *e = getElementFromId(257); gui::IGUIElement *e = getElementFromId(GUI_ID_PORT_INPUT);
if(e != NULL) if(e != NULL)
text_port = e->getText(); text_port = e->getText();
else else
text_port = m_data->port; 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) if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
fancy_trees = ((gui::IGUICheckBox*)e)->isChecked(); fancy_trees = ((gui::IGUICheckBox*)e)->isChecked();
else else
fancy_trees = m_data->fancy_trees; 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) if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked(); smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked();
else else
@ -107,14 +114,14 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
// Server options // Server options
{ {
gui::IGUIElement *e = getElementFromId(259); gui::IGUIElement *e = getElementFromId(GUI_ID_CREATIVE_CB);
if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX) if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
creative_mode = ((gui::IGUICheckBox*)e)->isChecked(); creative_mode = ((gui::IGUICheckBox*)e)->isChecked();
else else
creative_mode = m_data->creative_mode; 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) if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
enable_damage = ((gui::IGUICheckBox*)e)->isChecked(); enable_damage = ((gui::IGUICheckBox*)e)->isChecked();
else else
@ -175,7 +182,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 230, 30); core::rect<s32> rect(0, 0, 230, 30);
rect += topleft_client + v2s32(160, 50); rect += topleft_client + v2s32(160, 50);
gui::IGUIElement *e = 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"") if(text_name == L"")
Environment->setFocus(e); Environment->setFocus(e);
} }
@ -198,7 +205,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 230, 30); core::rect<s32> rect(0, 0, 230, 30);
rect += topleft_client + v2s32(160, 100); rect += topleft_client + v2s32(160, 100);
gui::IGUIElement *e = 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"") if(text_name != L"")
Environment->setFocus(e); Environment->setFocus(e);
} }
@ -206,7 +213,7 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 120, 30); core::rect<s32> rect(0, 0, 120, 30);
//rect += topleft_client + v2s32(160+250+20, 125); //rect += topleft_client + v2s32(160+250+20, 125);
rect += topleft_client + v2s32(size_client.X-60-100, 100); 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<s32> rect(0, 0, 400, 20); core::rect<s32> rect(0, 0, 400, 20);
@ -217,13 +224,13 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
{ {
core::rect<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_client + v2s32(35, 150); 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"); L"Fancy trees");
} }
{ {
core::rect<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_client + v2s32(35, 150+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"); L"Smooth Lighting");
} }
// Start game button // Start game button
@ -231,9 +238,16 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
core::rect<s32> rect(0, 0, 180, 30); core::rect<s32> 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/2-180/2, 225-30/2);
rect += topleft_client + v2s32(size_client.X-180-40, 150+25); 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<s32> 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 Server section
*/ */
@ -254,19 +268,19 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
{ {
core::rect<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_server + v2s32(35, 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<s32> rect(0, 0, 250, 30); core::rect<s32> rect(0, 0, 250, 30);
rect += topleft_server + v2s32(35, 60); 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 // Map delete button
{ {
core::rect<s32> rect(0, 0, 130, 30); core::rect<s32> rect(0, 0, 130, 30);
//rect += topleft_server + v2s32(size_server.X-40-130, 100+25); //rect += topleft_server + v2s32(size_server.X-40-130, 100+25);
rect += topleft_server + v2s32(40, 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() void GUIMainMenu::acceptInput()
{ {
{ {
gui::IGUIElement *e = getElementFromId(258); gui::IGUIElement *e = getElementFromId(GUI_ID_NAME_INPUT);
if(e != NULL) if(e != NULL)
m_data->name = e->getText(); m_data->name = e->getText();
} }
@ -310,32 +324,32 @@ void GUIMainMenu::acceptInput()
m_data->password = e->getText(); m_data->password = e->getText();
} }
{ {
gui::IGUIElement *e = getElementFromId(256); gui::IGUIElement *e = getElementFromId(GUI_ID_ADDRESS_INPUT);
if(e != NULL) if(e != NULL)
m_data->address = e->getText(); m_data->address = e->getText();
} }
{ {
gui::IGUIElement *e = getElementFromId(257); gui::IGUIElement *e = getElementFromId(GUI_ID_PORT_INPUT);
if(e != NULL) if(e != NULL)
m_data->port = e->getText(); 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) if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
m_data->creative_mode = ((gui::IGUICheckBox*)e)->isChecked(); 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) if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
m_data->enable_damage = ((gui::IGUICheckBox*)e)->isChecked(); 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) if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
m_data->smooth_lighting = ((gui::IGUICheckBox*)e)->isChecked(); 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) if(e != NULL && e->getType() == gui::EGUIET_CHECK_BOX)
m_data->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked(); m_data->fancy_trees = ((gui::IGUICheckBox*)e)->isChecked();
} }
@ -377,11 +391,16 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
{ {
switch(event.GUIEvent.Caller->getID()) switch(event.GUIEvent.Caller->getID())
{ {
case 257: // Start game case GUI_ID_JOIN_GAME_BUTTON: // Start game
acceptInput(); acceptInput();
quitMenu(); quitMenu();
return true; 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 // Don't accept input data, just set deletion request
m_data->delete_map = true; m_data->delete_map = true;
m_accepted = true; m_accepted = true;
@ -393,7 +412,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event)
{ {
switch(event.GUIEvent.Caller->getID()) 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(); acceptInput();
quitMenu(); quitMenu();
return true; return true;

@ -27,6 +27,21 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// For IGameCallback // For IGameCallback
#include "guiPauseMenu.h" #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 struct MainMenuData
{ {
MainMenuData(): MainMenuData():
@ -87,6 +102,11 @@ private:
MainMenuData *m_data; MainMenuData *m_data;
bool m_accepted; bool m_accepted;
IGameCallback *m_gamecallback; IGameCallback *m_gamecallback;
gui::IGUIEnvironment* env;
gui::IGUIElement* parent;
s32 id;
IMenuManager *menumgr;
}; };
#endif #endif

@ -171,6 +171,46 @@ irr::EKEY_CODE keyname_to_keycode(const char *name)
return irr::KEY_KEY_CODES_COUNT; 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 Key config
*/ */
@ -189,4 +229,7 @@ irr::EKEY_CODE getKeySetting(const char *settingname)
return c; return c;
} }
void clearKeyCache()
{
g_key_setting_cache.clear();
}

@ -21,11 +21,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define KEYCODE_HEADER #define KEYCODE_HEADER
#include "common_irrlicht.h" #include "common_irrlicht.h"
#include <string>
irr::EKEY_CODE keyname_to_keycode(const char *name); irr::EKEY_CODE keyname_to_keycode(const char *name);
// Key configuration getter // Key configuration getter
irr::EKEY_CODE getKeySetting(const char *settingname); irr::EKEY_CODE getKeySetting(const char *settingname);
std::string keycode_to_keyname(s32 keycode);
void clearCache();
#endif #endif