merged fix to decapitated trees; other bugs now exists
authorPerttu Ahola <celeron55@gmail.com>
Sun, 24 Jul 2011 08:39:13 +0000 (11:39 +0300)
committerPerttu Ahola <celeron55@gmail.com>
Sun, 24 Jul 2011 08:39:13 +0000 (11:39 +0300)
88 files changed:
.gitignore
CMakeLists.txt
README [new file with mode: 0644]
README.txt
cmake/Modules/FindGettextLib.cmake [new file with mode: 0644]
cmake/Modules/FindJthread.cmake [new file with mode: 0644]
cmake/Modules/FindSqlite3.cmake [new file with mode: 0644]
data/book.png [new file with mode: 0644]
data/bookshelf.png [new file with mode: 0644]
data/brick.png [new file with mode: 0644]
data/cactus_side.png [new file with mode: 0644]
data/cactus_top.png [new file with mode: 0644]
data/clay.png [new file with mode: 0644]
data/clay_brick.png [new file with mode: 0644]
data/fence.png [new file with mode: 0644]
data/firefly.png [new file with mode: 0644]
data/junglegrass.png [new file with mode: 0644]
data/jungletree.png [new file with mode: 0644]
data/jungletree_top.png [new file with mode: 0644]
data/lump_of_clay.png [new file with mode: 0644]
data/paper.png [new file with mode: 0644]
data/papyrus.png [new file with mode: 0644]
data/rail.png [new file with mode: 0644]
data/rail_crossing.png [new file with mode: 0644]
data/rail_curved.png [new file with mode: 0644]
data/rail_t_junction.png [new file with mode: 0644]
data/sandstone.png [new file with mode: 0644]
doc/README.txt [new file with mode: 0644]
genmap.py [new file with mode: 0755]
makepackage_binary.sh [new file with mode: 0755]
minetest-icon.svg [new file with mode: 0644]
minetestmapper/colors.txt [new file with mode: 0644]
minetestmapper/minetestmapper2.py [new file with mode: 0755]
po/de/minetest.po [new file with mode: 0644]
po/en/minetest.pot [new file with mode: 0644]
po/fr/minetest.po [new file with mode: 0644]
src/CMakeLists.txt
src/client.cpp
src/clouds.cpp
src/collision.cpp
src/content_cao.cpp
src/content_cao.h
src/content_craft.cpp
src/content_inventory.cpp
src/content_inventory.h
src/content_mapblock.cpp
src/content_mapnode.cpp
src/content_mapnode.h
src/content_object.h
src/content_sao.cpp
src/content_sao.h
src/defaultsettings.cpp
src/environment.cpp
src/farmesh.cpp
src/farmesh.h
src/game.cpp
src/gettext.h [new file with mode: 0644]
src/guiKeyChangeMenu.cpp [new file with mode: 0644]
src/guiKeyChangeMenu.h [new file with mode: 0644]
src/guiMainMenu.cpp
src/guiMainMenu.h
src/guiMessageMenu.cpp
src/guiPasswordChange.cpp
src/guiPauseMenu.cpp
src/guiTextInputMenu.cpp
src/inventory.cpp
src/inventory.h
src/keycode.cpp
src/keycode.h
src/main.cpp
src/map.cpp
src/mapblock.cpp
src/mapblock_mesh.cpp
src/mapblock_mesh.h
src/mapblockobject.cpp
src/mapgen.cpp
src/mapnode.cpp
src/mapnode.h
src/materials.cpp
src/materials.h
src/player.cpp
src/porting.cpp
src/serialization.h
src/server.cpp
src/test.cpp
src/tile.cpp
src/voxel.cpp
util/minetestmapper.py

index ce00d585ed9ee5194fd8b81b0a99ab1f4ede0d19..f0c372ab7785cc160eeee597a15285a4b0ed26dc 100644 (file)
@@ -19,4 +19,4 @@ cmake_install.cmake
 src/jthread/libjthread.a
 debug.txt
 bin/debug.txt
-
+minetestmapper/map.png
index 6403a9dd94ec3d562607fc1e16c5dd02d2211e0b..b4a5bb02eedf06ff78b9afebdc997f3d2c725d5f 100644 (file)
@@ -9,7 +9,7 @@ project(minetest)
 
 set(VERSION_MAJOR 0)
 set(VERSION_MINOR 2)
-set(VERSION_PATCH 20110704_0)
+set(VERSION_PATCH 20110720_0)
 set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
 
 # Configuration options
@@ -48,18 +48,18 @@ if(WIN32)
        set(EXAMPLE_CONF_DIR ".")
 elseif(APPLE)
        # random placeholders
-       set(DATADIR "share/minetest")
+       set(DATADIR "share/${PROJECT_NAME}")
        set(BINDIR "bin")
-       set(DOCDIR "share/doc/minetest")
+       set(DOCDIR "share/doc/${PROJECT_NAME}")
        set(EXAMPLE_CONF_DIR ".")
 elseif(UNIX) # Linux, BSD etc
-       set(DATADIR "share/minetest")
+       set(DATADIR "share/${PROJECT_NAME}")
        set(BINDIR "bin")
-       set(DOCDIR "share/doc/minetest")
-       set(EXAMPLE_CONF_DIR "share/doc/minetest")
+       set(DOCDIR "share/doc/${PROJECT_NAME}")
+       set(EXAMPLE_CONF_DIR "share/doc/${PROJECT_NAME}")
 endif()
 
-install(FILES "README.txt" DESTINATION "${DOCDIR}")
+install(FILES "doc/README.txt" DESTINATION "${DOCDIR}")
 install(FILES "minetest.conf.example" DESTINATION "${DOCDIR}")
 
 #
@@ -103,8 +103,8 @@ elseif(APPLE)
        set(CPACK_BUNDLE_NAME ${PROJECT_NAME})
        set(CPACK_BUNDLE_ICON "")
        set(CPACK_BUNDLE_PLIST "")
-       set(CPACK_BUNDLE_STARTUP_COMMAND "Contents/MacOS/minetest")
-       set(CPACK_GENERATOR Bundle)
+       set(CPACK_BUNDLE_STARTUP_COMMAND "Contents/MacOS/${PROJECT_NAME}")
+       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 (file)
index 0000000..82fcdd3
--- /dev/null
+++ b/README
@@ -0,0 +1,41 @@
+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
+* configurable far mesh tree display (boolean)
+* configurable far mesh rendering distance
+* volumetric clouds (using fake shading)
+* translation support (including questionable translation into german)
+* build system uses local jthread & sqlite libraries if available
+
+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)
+* 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 (made from 3 papyrus horizontally)
+* Book (made from 3 paper vertically)
+
+Alternate graphics:
+* Player
+* Omsk birds (instead of Oerkki ghosts)
+* Rat
+* Glass
+* Heart
+
+Building on GNU/Linux or OS X:
+    cmake . -DRUN_IN_PLACE=1
+    make -j2
+
+The “upstream” branch contains vanilla minetest-c55, created using:
+    hg-fast-export -r ~/share/src/games/minetest -o upstream
+    git push origin upstream/master:upstream -f
+
+All new/replaced graphics done by erlehmann are dual-licensed under GPL (version 2 or, at your option, any later version) and CC-BY-SA (version 3.0 or, at your option, any later version).
index 41048992e98e10d083b9f413d6789c7005be11e7..662f2770b0734d0ca2a6212959cae376b890f4db 100644 (file)
@@ -90,6 +90,8 @@ Compiling on Windows:
                http://www.winimage.com/zLibDll/index.html
        * Zlib library (zlibwapi.lib and zlibwapi.dll from zlib125dll.zip):
                http://www.winimage.com/zLibDll/index.html
+       * gettext bibrary and tools:
+               http://gnuwin32.sourceforge.net/downlinks/gettext.php
        * And, of course, Minetest-c55:
                http://celeron.55.lt/~celeron55/minetest/download
 - Steps:
@@ -117,6 +119,10 @@ Compiling on Windows:
                        + lib
                        + include
                        ...
+               + gettext
+                       +bin
+                       +include
+                       +lib
                + minetest
                        + src
                        + doc
@@ -145,6 +151,10 @@ Compiling on Windows:
        ZLIB_DLL                 DIR/zlib125dll/dll32/zlibwapi.dll
        ZLIB_INCLUDE_DIR         DIR/zlib-1.2.5
        ZLIB_LIBRARIES           DIR/zlib125dll/dll32/zlibwapi.lib
+       GETTEXT_BIN_DIR          DIR/gettext/bin
+       GETTEXT_INCLUDE_DIR      DIR/gettext/include
+       GETTEXT_LIBRARIES        DIR/gettext/lib/intl.lib
+       GETTEXT_MSGFMT           DIR/gettext/bin/msgfmt
        -----------------
        - Hit "Configure"
        - Hit "Generate"
diff --git a/cmake/Modules/FindGettextLib.cmake b/cmake/Modules/FindGettextLib.cmake
new file mode 100644 (file)
index 0000000..b99fd33
--- /dev/null
@@ -0,0 +1,80 @@
+# Package finder for gettext libs and include files
+
+SET(CUSTOM_GETTEXT_PATH "${PROJECT_SOURCE_DIR}/../../gettext"
+       CACHE FILEPATH "path to custom gettext")
+
+# by default
+SET(GETTEXT_FOUND FALSE)
+
+FIND_PATH(GETTEXT_INCLUDE_DIR
+       NAMES libintl.h
+       PATHS "${CUSTOM_GETTEXT_PATH}/include"
+       DOC "gettext include directory")
+
+FIND_PROGRAM(GETTEXT_MSGFMT
+       NAMES msgfmt
+       PATHS "${CUSTOM_GETTEXT_PATH}/bin"
+       DOC "path to msgfmt")
+
+FIND_PROGRAM(GETTEXT_MSGMERGE
+       NAMES msgmerge
+       PATHS "${CUSTOM_GETTEXT_PATH}/bin"
+       DOC "path to msgmerge")
+
+FIND_PROGRAM(GETTEXT_MSGEN
+       NAMES msgen
+       PATHS "${CUSTOM_GETTEXT_PATH}/bin"
+       DOC "path to msgen")
+
+FIND_PROGRAM(GETTEXT_EXTRACT
+       NAMES xgettext
+       PATHS "${CUSTOM_GETTEXT_PATH}/bin"
+       DOC "path to xgettext")
+
+# modern Linux, as well as Mac, seem to not need require special linking
+# they do not because gettext is part of glibc
+# TODO check the requirements on other BSDs and older Linux
+IF (WIN32)
+       IF(MSVC)
+               SET(GETTEXT_LIB_NAMES
+                       libintl.lib intl.lib libintl3.lib intl3.lib)
+       ELSE()
+               SET(GETTEXT_LIB_NAMES
+                       libintl.dll.a intl.dll.a libintl3.dll.a intl3.dll.a)
+       ENDIF()
+       FIND_LIBRARY(GETTEXT_LIBRARY
+               NAMES ${GETTEXT_LIB_NAMES}
+               PATHS "${CUSTOM_GETTEXT_PATH}/lib"
+               DOC "gettext *intl*.lib")
+       FIND_FILE(GETTEXT_DLL
+               NAMES libintl.dll intl.dll libintl3.dll intl3.dll
+               PATHS "${CUSTOM_GETTEXT_PATH}/bin" "${CUSTOM_GETTEXT_PATH}/lib" 
+               DOC "gettext *intl*.dll")
+       FIND_FILE(GETTEXT_ICONV_DLL
+               NAMES libiconv2.dll
+               PATHS "${CUSTOM_GETTEXT_PATH}/bin" "${CUSTOM_GETTEXT_PATH}/lib"
+               DOC "gettext *iconv*.lib")
+ENDIF(WIN32)
+
+
+IF(GETTEXT_INCLUDE_DIR AND GETTEXT_MSGFMT)
+       IF (WIN32)
+               # in the Win32 case check also for the extra linking requirements
+               IF(GETTEXT_LIBRARY AND GETTEXT_DLL AND GETTEXT_ICONV_DLL)
+                       SET(GETTEXT_FOUND TRUE)
+               ENDIF()
+       ELSE(WIN32)
+               SET(GETTEXT_FOUND TRUE)
+       ENDIF(WIN32)
+ENDIF()
+
+IF(GETTEXT_FOUND)
+       SET(GETTEXT_PO_PATH ${CMAKE_SOURCE_DIR}/po)
+       SET(GETTEXT_MO_BUILD_PATH ${CMAKE_BINARY_DIR}/locale/<locale>/LC_MESSAGES)
+       SET(GETTEXT_MO_DEST_PATH locale/<locale>/LC_MESSAGES)
+       FILE(GLOB GETTEXT_AVAILABLE_LOCALES RELATIVE ${GETTEXT_PO_PATH} "${GETTEXT_PO_PATH}/*")
+       MACRO(SET_MO_PATHS _buildvar _destvar _locale)
+               STRING(REPLACE "<locale>" ${_locale} ${_buildvar} ${GETTEXT_MO_BUILD_PATH})
+               STRING(REPLACE "<locale>" ${_locale} ${_destvar} ${GETTEXT_MO_DEST_PATH})
+       ENDMACRO(SET_MO_PATHS)
+ENDIF()
diff --git a/cmake/Modules/FindJthread.cmake b/cmake/Modules/FindJthread.cmake
new file mode 100644 (file)
index 0000000..302a3c2
--- /dev/null
@@ -0,0 +1,18 @@
+# Look for jthread, use our own if not found
+
+FIND_PATH(JTHREAD_INCLUDE_DIR jthread.h)
+
+FIND_LIBRARY(JTHREAD_LIBRARY NAMES jthread)
+
+IF(JTHREAD_LIBRARY AND JTHREAD_INCLUDE_DIR)
+       SET( JTHREAD_FOUND TRUE )
+ENDIF(JTHREAD_LIBRARY AND JTHREAD_INCLUDE_DIR)
+
+IF(JTHREAD_FOUND)
+       MESSAGE(STATUS "Found system jthread header file in ${JTHREAD_INCLUDE_DIR}")
+       MESSAGE(STATUS "Found system jthread library ${JTHREAD_LIBRARY}")
+ELSE(JTHREAD_FOUND)
+       SET(JTHREAD_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/jthread)
+       SET(JTHREAD_LIBRARY jthread)
+       MESSAGE(STATUS "Using project jthread library")
+ENDIF(JTHREAD_FOUND)
diff --git a/cmake/Modules/FindSqlite3.cmake b/cmake/Modules/FindSqlite3.cmake
new file mode 100644 (file)
index 0000000..ecce6e3
--- /dev/null
@@ -0,0 +1,18 @@
+# Look for sqlite3, use our own if not found
+
+FIND_PATH(SQLITE3_INCLUDE_DIR sqlite3.h)
+
+FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3)
+
+IF(SQLITE3_LIBRARY AND SQLITE3_INCLUDE_DIR)
+       SET( SQLITE3_FOUND TRUE )
+ENDIF(SQLITE3_LIBRARY AND SQLITE3_INCLUDE_DIR)
+
+IF(SQLITE3_FOUND)
+       MESSAGE(STATUS "Found system sqlite3 header file in ${SQLITE3_INCLUDE_DIR}")
+       MESSAGE(STATUS "Found system sqlite3 library ${SQLITE3_LIBRARY}")
+ELSE(SQLITE3_FOUND)
+       SET(SQLITE3_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/sqlite)
+       SET(SQLITE3_LIBRARY sqlite3)
+       MESSAGE(STATUS "Using project sqlite3 library")
+ENDIF(SQLITE3_FOUND)
diff --git a/data/book.png b/data/book.png
new file mode 100644 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
index 0000000..0b99f0e
Binary files /dev/null and b/data/fence.png differ
diff --git a/data/firefly.png b/data/firefly.png
new file mode 100644 (file)
index 0000000..40df7fa
Binary files /dev/null and b/data/firefly.png differ
diff --git a/data/junglegrass.png b/data/junglegrass.png
new file mode 100644 (file)
index 0000000..eea87c0
Binary files /dev/null and b/data/junglegrass.png differ
diff --git a/data/jungletree.png b/data/jungletree.png
new file mode 100644 (file)
index 0000000..ccd20ac
Binary files /dev/null and b/data/jungletree.png differ
diff --git a/data/jungletree_top.png b/data/jungletree_top.png
new file mode 100644 (file)
index 0000000..2a9b513
Binary files /dev/null and b/data/jungletree_top.png differ
diff --git a/data/lump_of_clay.png b/data/lump_of_clay.png
new file mode 100644 (file)
index 0000000..be0bab9
Binary files /dev/null and b/data/lump_of_clay.png differ
diff --git a/data/paper.png b/data/paper.png
new file mode 100644 (file)
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 (file)
index 0000000..bf0dec7
Binary files /dev/null and b/data/papyrus.png differ
diff --git a/data/rail.png b/data/rail.png
new file mode 100644 (file)
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 (file)
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 (file)
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 (file)
index 0000000..9985f63
Binary files /dev/null and b/data/rail_t_junction.png differ
diff --git a/data/sandstone.png b/data/sandstone.png
new file mode 100644 (file)
index 0000000..c4759b4
Binary files /dev/null and b/data/sandstone.png differ
diff --git a/doc/README.txt b/doc/README.txt
new file mode 100644 (file)
index 0000000..645e2a5
--- /dev/null
@@ -0,0 +1,238 @@
+Minetest-c55
+---------------
+An InfiniMiner/Minecraft inspired game.
+Copyright (c) 2010-2011 Perttu Ahola <celeron55@gmail.com>
+
+Further documentation:
+----------------------
+- Website: http://celeron.55.lt/~celeron55/minetest/
+- Wiki: http://celeron.55.lt/~celeron55/minetest/wiki/
+- Forum: http://celeron.55.lt/~celeron55/minetest/forum/
+
+This is a development version:
+------------------------------
+- Don't expect it to work as well as a finished game will.
+- Please report any bugs to me. That way I can fix them to the next release.
+       - debug.txt is useful when the game crashes.
+
+Controls:
+---------
+- See the in-game pause menu
+- Settable in the configuration file, see the section below.
+
+Map directory:
+--------------
+- Map is stored in a directory, which can be removed to generate a new map.
+- There is a command-line option for it: --map-dir
+- For a RUN_IN_PLACE build, it is located in:
+               ../map
+- Otherwise something like this:
+       Windows: C:\Documents and Settings\user\Application Data\minetest\map
+       Linux: ~/.minetest/map
+       OS X: ~/Library/Application Support/minetest/map
+
+Configuration file:
+-------------------
+- An optional configuration file can be used. See minetest.conf.example.
+- Path to file can be passed as a parameter to the executable:
+       --config <path-to-file>
+- Defaults:
+       - If built with -DRUN_IN_PLACE=1:
+               ../minetest.conf
+               ../../minetest.conf
+       - Otherwise something like this:
+               Windows: C:\Documents and Settings\user\Application Data\minetest\minetest.conf
+               Linux: ~/.minetest/minetest.conf
+               OS X: ~/Library/Application Support/minetest.conf
+
+Command-line options:
+---------------------
+- Use --help
+
+Compiling on GNU/Linux:
+-----------------------
+
+Install dependencies. Here's an example for Debian/Ubuntu:
+$ apt-get install build-essential libirrlicht-dev cmake libbz2-dev libpng12-dev libjpeg8-dev libxxf86vm-dev libgl1-mesa-dev
+
+Download source, extract (this is the URL to the latest of source repository, which might not work at all times):
+$ wget https://bitbucket.org/celeron55/minetest/get/tip.tar.gz
+$ tar xf tip.tar.gz
+$ cd minetest
+
+Build a version that runs directly from the source directory:
+$ cmake . -DRUN_IN_PLACE=1
+$ make -j2
+
+Run it:
+$ cd bin
+$ ./minetest
+
+- Use cmake . -LH to see all CMake options and their current state
+- If you want to install it system-wide (or are making a distribution package), you will want to use -DRUN_IN_PLACE=0
+- You can build a bare server or a bare client by specifying -DBUILD_CLIENT=0 or -DBUILD_SERVER=0
+- You can select between Release and Debug build by -DCMAKE_BUILD_TYPE=<Debug or Release>
+  - Note that the Debug build is considerably slower
+
+Compiling on Windows:
+---------------------
+
+- You need:
+       * CMake:
+               http://www.cmake.org/cmake/resources/software.html
+       * MinGW or Visual Studio
+               http://www.mingw.org/
+               http://msdn.microsoft.com/en-us/vstudio/default
+       * Irrlicht SDK 1.7:
+               http://irrlicht.sourceforge.net/downloads.html
+       * Zlib headers (zlib125.zip)
+               http://www.winimage.com/zLibDll/index.html
+       * Zlib library (zlibwapi.lib and zlibwapi.dll from zlib125dll.zip):
+               http://www.winimage.com/zLibDll/index.html
+       * And, of course, Minetest-c55:
+               http://celeron.55.lt/~celeron55/minetest/download
+- Steps:
+       - Select a directory called DIR hereafter in which you will operate.
+       - Make sure you have CMake and a compiler installed.
+       - Download all the other stuff to DIR and extract them into there. All those
+         packages contain a nice base directory in them, which should end up being
+         the direct subdirectories of DIR.
+       - You will end up with a directory structure like this (+=dir, -=file):
+       -----------------
+       + DIR
+               - zlib-1.2.5.tar.gz
+               - zlib125dll.zip
+               - irrlicht-1.7.1.zip
+               - 110214175330.zip (or whatever, this is the minetest source)
+               + zlib-1.2.5
+                       - zlib.h
+                       + win32
+                       ...
+               + zlib125dll
+                       - readme.txt
+                       + dll32
+                       ...
+               + irrlicht-1.7.1
+                       + lib
+                       + include
+                       ...
+               + minetest
+                       + src
+                       + doc
+                       - CMakeLists.txt
+                       ...
+       -----------------
+       - Start up the CMake GUI
+       - Select "Browse Source..." and select DIR/minetest
+       - Now, if using MSVC:
+               - Select "Browse Build..." and select DIR/minetest-build
+       - Else if using MinGW:
+               - Select "Browse Build..." and select DIR/minetest
+       - Select "Configure"
+       - Select your compiler
+       - It will warn about missing stuff, ignore that at this point. (later don't)
+       - Make sure the configuration is as follows
+         (note that the versions may differ for you):
+       -----------------
+       BUILD_CLIENT             [X]
+       BUILD_SERVER             [ ]
+       CMAKE_BUILD_TYPE         Release
+       CMAKE_INSTALL_PREFIX     DIR/minetest-install
+       IRRLICHT_SOURCE_DIR      DIR/irrlicht-1.7.1
+       RUN_IN_PLACE             [X]
+       WARN_ALL                 [ ]
+       ZLIB_DLL                 DIR/zlib125dll/dll32/zlibwapi.dll
+       ZLIB_INCLUDE_DIR         DIR/zlib-1.2.5
+       ZLIB_LIBRARIES           DIR/zlib125dll/dll32/zlibwapi.lib
+       -----------------
+       - Hit "Configure"
+       - Hit "Generate"
+       If using MSVC:
+               - Open the generated minetest.sln
+               - The project defaults to the "Debug" configuration. Make very sure to
+                 select "Release", unless you want to debug some stuff (it's slower)
+               - Build the ALL_BUILD project
+               - Build the INSTALL project
+               - You should now have a working game with the executable in
+                       DIR/minetest-install/bin/minetest.exe
+               - Additionally you may create a zip package by building the PACKAGE
+                 project.
+       If using MinGW:
+               - Using the command line, browse to the build directory and run 'make'
+                 (or mingw32-make or whatever it happens to be)
+               - You should now have a working game with the executable in
+                       DIR/minetest/bin/minetest.exe
+
+License of Minetest-c55
+-----------------------
+
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Irrlicht
+---------------
+
+This program uses the Irrlicht Engine. http://irrlicht.sourceforge.net/
+
+ The Irrlicht Engine License
+
+Copyright © 2002-2005 Nikolaus Gebhardt
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute
+it freely, subject to the following restrictions:
+
+   1. The origin of this software must not be misrepresented; you
+      must not claim that you wrote the original software. If you use
+         this software in a product, an acknowledgment in the product
+         documentation would be appreciated but is not required.
+   2. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+   3. This notice may not be removed or altered from any source
+      distribution.
+
+
+JThread
+---------------
+
+This program uses the JThread library. License for JThread follows:
+
+Copyright (c) 2000-2006  Jori Liesenborgs (jori.liesenborgs@gmail.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+
diff --git a/genmap.py b/genmap.py
new file mode 100755 (executable)
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/makepackage_binary.sh b/makepackage_binary.sh
new file mode 100755 (executable)
index 0000000..32d1986
--- /dev/null
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+PROJECT_NAME=minetest-delta
+PACKAGEDIR=../$PROJECT_NAME-packages
+PACKAGENAME=$PROJECT_NAME-binary-`date +%y%m%d%H%M%S`
+PACKAGEPATH=$PACKAGEDIR/$PACKAGENAME
+
+mkdir -p $PACKAGEPATH
+mkdir -p $PACKAGEPATH/bin
+mkdir -p $PACKAGEPATH/data
+mkdir -p $PACKAGEPATH/doc
+mkdir -p $PACKAGEPATH/locale/de/LC_MESSAGES/
+
+cp minetest.conf.example $PACKAGEPATH/
+
+cp bin/$PROJECT_NAME.exe $PACKAGEPATH/bin/
+cp bin/Irrlicht.dll $PACKAGEPATH/bin/
+cp bin/zlibwapi.dll $PACKAGEPATH/bin/
+#cp bin/test $PACKAGEPATH/bin/
+#cp bin/fasttest $PACKAGEPATH/bin/
+#cp bin/server $PACKAGEPATH/bin/
+#cp ../irrlicht/irrlicht-1.7.1/lib/Linux/libIrrlicht.a $PACKAGEPATH/bin/
+#cp ../jthread/jthread-1.2.1/src/.libs/libjthread-1.2.1.so $PACKAGEPATH/bin/
+
+cp -r data/fontlucida.png $PACKAGEPATH/data/
+cp -r data/player.png $PACKAGEPATH/data/
+cp -r data/player_back.png $PACKAGEPATH/data/
+cp -r data/stone.png $PACKAGEPATH/data/
+cp -r data/grass.png $PACKAGEPATH/data/
+cp -r data/grass_footsteps.png $PACKAGEPATH/data/
+cp -r data/water.png $PACKAGEPATH/data/
+cp -r data/tree.png $PACKAGEPATH/data/
+cp -r data/leaves.png $PACKAGEPATH/data/
+cp -r data/mese.png $PACKAGEPATH/data/
+cp -r data/cloud.png $PACKAGEPATH/data/
+cp -r data/sign.png $PACKAGEPATH/data/
+cp -r data/sign_back.png $PACKAGEPATH/data/
+cp -r data/rat.png $PACKAGEPATH/data/
+cp -r data/mud.png $PACKAGEPATH/data/
+cp -r data/torch.png $PACKAGEPATH/data/
+cp -r data/torch_on_floor.png $PACKAGEPATH/data/
+cp -r data/torch_on_ceiling.png $PACKAGEPATH/data/
+cp -r data/tree_top.png $PACKAGEPATH/data/
+cp -r data/coalstone.png $PACKAGEPATH/data/
+cp -r data/crack.png $PACKAGEPATH/data/
+cp -r data/wood.png $PACKAGEPATH/data/
+cp -r data/stick.png $PACKAGEPATH/data/
+cp -r data/tool_wpick.png $PACKAGEPATH/data/
+cp -r data/tool_stpick.png $PACKAGEPATH/data/
+cp -r data/tool_mesepick.png $PACKAGEPATH/data/
+cp -r data/grass_side.png $PACKAGEPATH/data/
+cp -r data/lump_of_coal.png $PACKAGEPATH/data/
+cp -r data/lump_of_iron.png $PACKAGEPATH/data/
+cp -r data/mineral_coal.png $PACKAGEPATH/data/
+cp -r data/mineral_iron.png $PACKAGEPATH/data/
+cp -r data/sand.png $PACKAGEPATH/data/
+
+#cp -r data/pauseMenu.gui $PACKAGEPATH/data/
+
+cp -r doc/README.txt $PACKAGEPATH/doc/README.txt
+
+cp -r locale/de/LC_MESSAGES/$PROJECT_NAME.mo $PACKAGEPATH/locale/de/LC_MESSAGES/
+
+cd $PACKAGEDIR
+rm $PACKAGENAME.zip
+zip -r $PACKAGENAME.zip $PACKAGENAME
+
diff --git a/minetest-icon.svg b/minetest-icon.svg
new file mode 100644 (file)
index 0000000..46c9ac7
--- /dev/null
@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48px"
+   height="48px"
+   id="svg2856"
+   version="1.1"
+   inkscape:version="0.47 r22583"
+   sodipodi:docname="minetest-icon.svg"
+   inkscape:export-filename="/home/erlehmann/pics/icons/minetest/minetest-icon-24x24.png"
+   inkscape:export-xdpi="45"
+   inkscape:export-ydpi="45">
+  <defs
+     id="defs2858">
+    <filter
+       inkscape:collect="always"
+       id="filter3864">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="0.20490381"
+         id="feGaussianBlur3866" />
+    </filter>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="12.083333"
+     inkscape:cx="24"
+     inkscape:cy="24"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:grid-bbox="true"
+     inkscape:document-units="px"
+     inkscape:window-width="1233"
+     inkscape:window-height="755"
+     inkscape:window-x="0"
+     inkscape:window-y="25"
+     inkscape:window-maximized="1">
+    <inkscape:grid
+       type="xygrid"
+       id="grid2866"
+       empspacing="2"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       spacingx="0.5px"
+       spacingy="10px"
+       color="#ff0000"
+       opacity="0.1254902"
+       empcolor="#ff0000"
+       empopacity="0.25098039"
+       dotted="false" />
+    <inkscape:grid
+       type="axonomgrid"
+       id="grid2870"
+       units="px"
+       empspacing="1"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true"
+       spacingy="1px"
+       originx="0px" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata2861">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       style="fill:#e9b96e;fill-opacity:1;stroke:#573a0d;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="M 6.1513775e-7,16 3.2110204e-7,28 21.035899,40.145082 l 21,-12.414519 0,-11.461126 L 20.78461,4 6.1513775e-7,16 z"
+       id="path3047"
+       transform="translate(3.4641013,6)"
+       sodipodi:nodetypes="ccccccc" />
+    <path
+       style="fill:#2e3436;fill-opacity:1;stroke:#2e3436;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 8.5,30.907477 -2,-1.1547 0,6 L 17.320508,42 l 0,-2 -1.732051,-1 0,-2 L 13.5,35.794229 l 0,-4 -5,-2.886752 0,2 z"
+       id="path3831"
+       sodipodi:nodetypes="ccccccccccc" />
+    <path
+       style="opacity:1;fill:#555753;fill-opacity:1;stroke:#2e3436;stroke-linejoin:miter"
+       d="m 6.9282032,36 3.4641018,-2 3.464101,2 1.643594,0.948929 0,2 2,1.154701 0,2 L 6.9282032,36 z"
+       id="path3870"
+       sodipodi:nodetypes="cccccccc" />
+    <path
+       style="fill:#fce94f;fill-opacity:1;stroke:#625802;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="M 25.980762,19 31.5,22.186533 l 0,2 L 38.09375,28 41.5625,26 45.5,23.730563 l 0,2.538874 0,-4 L 32.908965,15 25.980762,19 z"
+       id="path3851"
+       sodipodi:nodetypes="cccccccccc" />
+    <path
+       style="fill:#e9b96e;fill-opacity:1;stroke:#573a0d;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.50000000000000000"
+       d="m 24.839746,18.341234 8.660254,-5 0,2 -8.660254,5 0,-2 z"
+       id="path5684"
+       sodipodi:nodetypes="ccccc" />
+    <path
+       style="fill:#73d216;fill-opacity:1;stroke:#325b09;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="M 25.980762,5 3.4641016,18 17.5,26.10363 31.5,18.186533 24.839746,14.341234 33.5,9.341234 25.980762,5 z"
+       id="path3821"
+       sodipodi:nodetypes="ccccccc"
+       transform="translate(0,4)" />
+    <path
+       style="fill:#729fcf;fill-opacity:1;stroke:#19314b;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+       d="m 17.5,28.10363 0,2 1.552559,0.89637 0,2 5.447441,3.145082 12,-7.071797 0,-2.14657 2,-1.1547 0,-1.54403 -7,-4.041452 -14,7.917097 z"
+       id="path3825"
+       sodipodi:nodetypes="ccccccccccc"
+       transform="translate(0,4)" />
+    <g
+       id="g5691"
+       style="stroke-linejoin:miter">
+      <path
+         sodipodi:nodetypes="ccccc"
+         id="path3862"
+         d="m 13.856406,20 6.928204,4 -6.928204,4 -6.9282028,-4 6.9282028,-4 z"
+         style="fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;filter:url(#filter3864);opacity:0.25000000000000000" />
+      <g
+         id="g3858"
+         style="stroke-linejoin:miter">
+        <path
+           style="fill:#c17d11;fill-opacity:1;stroke:#8f5902;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+           d="m 15.588457,21 1.732051,1 1.732051,-1 0,-6 -1.732051,-1 -1.732051,1 0,6 z"
+           id="path3833"
+           sodipodi:nodetypes="ccccccc"
+           transform="translate(-3.4641015,2)" />
+        <path
+           style="fill:#4e9a06;fill-opacity:1;stroke:#316004;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+           d="M 9.9641015,13.752777 17.320508,18 l 6.643593,-3.835681 0,-8.3286385 L 17.320508,2 9.9641015,6.2472233 l 0,7.5055537 z"
+           id="path3837"
+           transform="translate(-3.4641015,2)"
+           sodipodi:nodetypes="ccccccc" />
+      </g>
+    </g>
+    <g
+       id="g5686"
+       transform="translate(-4.2591582e-7,2)"
+       style="stroke-linejoin:miter">
+      <path
+         transform="translate(24.248712,-2)"
+         style="opacity:0.25000000000000000;fill:#2e3436;fill-opacity:1;stroke:none;filter:url(#filter3864);stroke-linejoin:miter"
+         d="m 13.856406,20 5.196153,3 -5.196153,3 -5.196152,-3 5.196152,-3 z"
+         id="path3868"
+         sodipodi:nodetypes="ccccc" />
+      <path
+         style="fill:#4e9a06;fill-opacity:1;stroke:#316004;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+         d="M 15.71539,21.073285 17.320508,22 l 1.394882,-0.805336 0,-8.389328 L 17.320508,12 l -1.605118,1.073285 0,8 z"
+         id="path3853"
+         sodipodi:nodetypes="ccccccc"
+         transform="translate(20.78461,0)" />
+    </g>
+    <path
+       style="fill:none;fill-opacity:1;stroke:#ef2929;stroke-width:0.50000000000000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:0.50000000000000000, 0.50000000000000000;stroke-dashoffset:0.25000000000000000"
+       d="M 12.124356,33 11.25833,32.5"
+       id="path3872"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:#888a85;stroke:#2e3436;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0.50000000000000000"
+       d="m 45.5,26.730563 -4,2.309401 0,1 -2,1.1547 0,2 -2,1.154701 0,4 8,-4.618802 0,-7 z"
+       id="path3874"
+       sodipodi:nodetypes="ccccccccc" />
+  </g>
+</svg>
diff --git a/minetestmapper/colors.txt b/minetestmapper/colors.txt
new file mode 100644 (file)
index 0000000..e70f56e
--- /dev/null
@@ -0,0 +1,25 @@
+0 128 128 128\r
+1 107 134 51\r
+2 39 66 106\r
+3 255 255 0\r
+4 86 58 31\r
+5 48 95 8\r
+6 102 129 38\r
+7 178 178 0\r
+8 101 84 36\r
+9 39 66 106\r
+12 104 78 42\r
+13 210 194 156\r
+14 117 86 41\r
+15 128 79 0\r
+16 118 118 118\r
+18 123 123 123\r
+19 199 199 199\r
+20 183 183 222\r
+21 103 78 42\r
+22 219 202 178\r
+23 78 154 6\r
+24 204 0 0\r
+25 211 215 207\r
+26 138 226 52\r
+27 104 78 42\r
diff --git a/minetestmapper/minetestmapper2.py b/minetestmapper/minetestmapper2.py
new file mode 100755 (executable)
index 0000000..8dc3de2
--- /dev/null
@@ -0,0 +1,275 @@
+#!/usr/bin/env python\r
+# -*- coding: utf-8 -*-\r
+\r
+# Made by j0gge, modified by celeron55\r
+\r
+# This program is free software. It comes without any warranty, to\r
+# the extent permitted by applicable law. You can redistribute it\r
+# and/or modify it under the terms of the Do What The Fuck You Want\r
+# To Public License, Version 2, as published by Sam Hocevar. See\r
+# http://sam.zoy.org/wtfpl/COPYING for more details.\r
+\r
+# Requires Python Imaging Library: http://www.pythonware.com/products/pil/\r
+\r
+# Some speed-up: ...lol, actually it slows it down.\r
+#import psyco ; psyco.full()\r
+#from psyco.classes import *\r
+\r
+import zlib\r
+import Image, ImageDraw\r
+import os\r
+import string\r
+import time\r
+\r
+def hex_to_int(h):\r
+    i = int(h,16)\r
+    if(i > 2047):\r
+        i-=4096\r
+    return i\r
+\r
+def hex4_to_int(h):\r
+    i = int(h,16)\r
+    if(i > 32767):\r
+        i-=65536\r
+    return i\r
+\r
+def int_to_hex3(i):\r
+    if(i < 0):\r
+        return "%03X" % (i + 4096)\r
+    else:\r
+        return "%03X" % i\r
+\r
+def int_to_hex4(i):\r
+    if(i < 0):\r
+        return "%04X" % (i + 65536)\r
+    else:\r
+        return "%04X" % i\r
+\r
+def limit(i,l,h):\r
+    if(i>h):\r
+        i=h\r
+    if(i<l):\r
+        i=l\r
+    return i\r
+\r
+# Fix these!\r
+path="../map/"\r
+output="map.png"\r
+\r
+sector_xmin = -1000/16\r
+sector_xmax = 1000/16\r
+sector_zmin = -1000/16\r
+sector_zmax = 1000/16\r
+\r
+# Load color information for the blocks.\r
+colors = {}\r
+f = file("colors.txt")\r
+for line in f:\r
+    values = string.split(line)\r
+    colors[int(values[0])] = (int(values[1]), int(values[2]), int(values[3]))\r
+f.close()\r
+\r
+xlist = []\r
+zlist = []\r
+\r
+# List all sectors to memory and calculate the width and heigth of the resulting picture.\r
+if os.path.exists(path + "sectors2"):\r
+    for filename in os.listdir(path + "sectors2"):\r
+        for filename2 in os.listdir(path + "sectors2/" + filename):\r
+            x = hex_to_int(filename)\r
+            z = hex_to_int(filename2)\r
+            if x < sector_xmin or x > sector_xmax:\r
+                continue\r
+            if z < sector_zmin or z > sector_zmax:\r
+                continue\r
+            xlist.append(x)\r
+            zlist.append(z)\r
+\r
+if os.path.exists(path + "sectors"):\r
+    for filename in os.listdir(path + "sectors"):\r
+        x = hex4_to_int(filename[:4])\r
+        z = hex4_to_int(filename[-4:])\r
+        if x < sector_xmin or x > sector_xmax:\r
+            continue\r
+        if z < sector_zmin or z > sector_zmax:\r
+            continue\r
+        xlist.append(x)\r
+        zlist.append(z)\r
+\r
+w = (max(xlist) - min(xlist)) * 16 + 16\r
+h = (max(zlist) - min(zlist)) * 16 + 16\r
+\r
+print "w="+str(w)+" h="+str(h)\r
+\r
+im = Image.new("RGB", (w, h), "white")\r
+impix = im.load()\r
+\r
+stuff={}\r
+\r
+starttime = time.time()\r
+\r
+# Go through all sectors.\r
+for n in range(len(xlist)):\r
+    #if n > 500:\r
+    #   break\r
+    if n % 200 == 0:\r
+        nowtime = time.time()\r
+        dtime = nowtime - starttime\r
+        n_per_second = 1.0 * n / dtime\r
+        if n_per_second != 0:\r
+            seconds_per_n = 1.0 / n_per_second\r
+            time_guess = seconds_per_n * len(xlist)\r
+            remaining_s = time_guess - dtime\r
+            remaining_minutes = int(remaining_s / 60)\r
+            remaining_s -= remaining_minutes * 60;\r
+            print("Processing sector "+str(n)+" of "+str(len(xlist))\r
+                    +" ("+str(round(100.0*n/len(xlist), 1))+"%)"\r
+                    +" (ETA: "+str(remaining_minutes)+"m "\r
+                    +str(int(remaining_s))+"s)")\r
+\r
+    xpos = xlist[n]\r
+    zpos = zlist[n]\r
+\r
+    xhex = int_to_hex3(xpos)\r
+    zhex = int_to_hex3(zpos)\r
+    xhex4 = int_to_hex4(xpos)\r
+    zhex4 = int_to_hex4(zpos)\r
+\r
+    sector1 = xhex4.lower() + zhex4.lower()\r
+    sector2 = xhex.lower() + "/" + zhex.lower()\r
+\r
+    ylist=[]\r
+\r
+    sectortype = ""\r
+\r
+    try:\r
+        for filename in os.listdir(path + "sectors/" + sector1):\r
+            if(filename != "meta"):\r
+                pos = int(filename,16)\r
+                if(pos > 32767):\r
+                    pos-=65536\r
+                ylist.append(pos)\r
+                sectortype = "old"\r
+    except OSError:\r
+        pass\r
+\r
+    if sectortype != "old":\r
+        try:\r
+            for filename in os.listdir(path + "sectors2/" + sector2):\r
+                if(filename != "meta"):\r
+                    pos = int(filename,16)\r
+                    if(pos > 32767):\r
+                        pos-=65536\r
+                    ylist.append(pos)\r
+                    sectortype = "new"\r
+        except OSError:\r
+            pass\r
+\r
+    if sectortype == "":\r
+        continue\r
+\r
+    ylist.sort()\r
+\r
+    # Make a list of pixels of the sector that are to be looked for.\r
+    pixellist = []\r
+    for x in range(16):\r
+        for y in range(16):\r
+            pixellist.append((x,y))\r
+\r
+    # Go through the Y axis from top to bottom.\r
+    for ypos in reversed(ylist):\r
+\r
+        yhex = int_to_hex4(ypos)\r
+\r
+        filename = ""\r
+        if sectortype == "old":\r
+            filename = path + "sectors/" + sector1 + "/" + yhex.lower()\r
+        else:\r
+            filename = path + "sectors2/" + sector2 + "/" + yhex.lower()\r
+\r
+        f = file(filename, "rb")\r
+\r
+        # Let's just memorize these even though it's not really necessary.\r
+        version = f.read(1)\r
+        flags = f.read(1)\r
+\r
+        dec_o = zlib.decompressobj()\r
+        try:\r
+            mapdata = dec_o.decompress(f.read())\r
+        except:\r
+            mapdata = []\r
+\r
+        f.close()\r
+\r
+        if(len(mapdata)<4096):\r
+            print "bad: " + xhex+zhex+"/"+yhex + " " + len(mapdata)\r
+        else:\r
+            chunkxpos=xpos*16\r
+            chunkypos=ypos*16\r
+            chunkzpos=zpos*16\r
+            for (x,z) in reversed(pixellist):\r
+                for y in reversed(range(16)):\r
+                    datapos=x+y*16+z*256\r
+                    if(ord(mapdata[datapos])!=254):\r
+                        try:\r
+                            pixellist.remove((x,z))\r
+                            # Memorize information on the type and height of the block and for drawing the picture.\r
+                            stuff[(chunkxpos+x,chunkzpos+z)]=(chunkypos+y,ord(mapdata[datapos]))\r
+                            break\r
+                        except:\r
+                            print "strange block: " + xhex+zhex+"/"+yhex + " x: " + str(x) + " y: " + str(y) + " z: " + str(z) + " block: " + str(ord(mapdata[datapos]))\r
+\r
+        # After finding all the pixeld in the sector, we can move on to the next sector without having to continue the Y axis.\r
+        if(len(pixellist)==0):\r
+            break\r
+\r
+print "Drawing image"\r
+# Drawing the picture\r
+starttime = time.time()\r
+n = 0\r
+minx = min(xlist)\r
+minz = min(zlist)\r
+for (x,z) in stuff.iterkeys():\r
+    if n % 500000 == 0:\r
+        nowtime = time.time()\r
+        dtime = nowtime - starttime\r
+        n_per_second = 1.0 * n / dtime\r
+        if n_per_second != 0:\r
+            listlen = len(stuff)\r
+            seconds_per_n = 1.0 / n_per_second\r
+            time_guess = seconds_per_n * listlen\r
+            remaining_s = time_guess - dtime\r
+            remaining_minutes = int(remaining_s / 60)\r
+            remaining_s -= remaining_minutes * 60;\r
+            print("Drawing pixel "+str(n)+" of "+str(listlen)\r
+                    +" ("+str(round(100.0*n/listlen, 1))+"%)"\r
+                    +" (ETA: "+str(remaining_minutes)+"m "\r
+                    +str(int(remaining_s))+"s)")\r
+    n += 1\r
+\r
+    (r,g,b)=colors[stuff[(x,z)][1]]\r
+\r
+    # Comparing heights of a couple of adjacent blocks and changing brightness accordingly.\r
+    try:\r
+        y1=stuff[(x-1,z)][0]\r
+        y2=stuff[(x,z-1)][0]\r
+        y=stuff[(x,z)][0]\r
+\r
+        d=(y-y1+y-y2)*12\r
+\r
+        if(d>36):\r
+            d=36\r
+\r
+        r=limit(r+d,0,255)\r
+        g=limit(g+d,0,255)\r
+        b=limit(b+d,0,255)\r
+    except:\r
+        pass\r
+    #impix[w-1-(x-minx*16),h-1-(z-minz*16)]=(r,g,b)\r
+    impix[x-minx*16,h-1-(z-minz*16)]=(r,g,b)\r
+\r
+# Flip the picture to make it right and save.\r
+#print "Transposing"\r
+#im=im.transpose(Image.FLIP_TOP_BOTTOM)\r
+print "Saving"\r
+im.save(output)\r
diff --git a/po/de/minetest.po b/po/de/minetest.po
new file mode 100644 (file)
index 0000000..69b57fd
--- /dev/null
@@ -0,0 +1,123 @@
+# German translations for minetest-c55 package.
+# Copyright (C) 2011 celeron
+# This file is distributed under the same license as the minetest-c55 package.
+# Constantin Wenger <constantin.wenger@googlemail.com>, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: 0.0.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-07-22 11:00+0200\n"
+"PO-Revision-Date: 2011-07-20 16:58+0100\n"
+"Last-Translator: Constantin Wenger <constantin.wenger@googlemail.com>\n"
+"Language-Team: Deutsch <>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
+
+#: src/guiMainMenu.cpp:180
+msgid "Name/Password"
+msgstr "Name/Passwort"
+
+#: src/guiMainMenu.cpp:203
+msgid "Address/Port"
+msgstr "Adresse / Port"
+
+#: src/guiMainMenu.cpp:223
+msgid "Leave address blank to start a local server."
+msgstr "Lasse die Adresse frei um einen eigenen Server zu starten"
+
+#: src/guiMainMenu.cpp:230
+msgid "Fancy trees"
+msgstr "Schöne Bäume"
+
+#: src/guiMainMenu.cpp:236
+msgid "Smooth Lighting"
+msgstr "Besseres Licht"
+
+#: src/guiMainMenu.cpp:244
+msgid "Start Game / Connect"
+msgstr "Spiel starten / Verbinden"
+
+#: src/guiMainMenu.cpp:253
+msgid "Change keys"
+msgstr "Tastenbelegung ändern"
+
+#: src/guiMainMenu.cpp:276
+msgid "Creative Mode"
+msgstr "Kreativitätsmodus"
+
+#: src/guiMainMenu.cpp:282
+msgid "Enable Damage"
+msgstr "Schaden einschalten"
+
+#: src/guiMainMenu.cpp:290
+msgid "Delete map"
+msgstr "Karte löschen"
+
+#: src/guiMessageMenu.cpp:93 src/guiTextInputMenu.cpp:111
+msgid "Proceed"
+msgstr "Fortsetzen"
+
+#: src/guiPasswordChange.cpp:102
+msgid "Old Password"
+msgstr "Altes Passwort"
+
+#: src/guiPasswordChange.cpp:117
+msgid "New Password"
+msgstr "Neues Passwort"
+
+#: src/guiPasswordChange.cpp:131
+msgid "Confirm Password"
+msgstr "Passwort wiederholen"
+
+#: src/guiPasswordChange.cpp:146
+msgid "Change"
+msgstr "Ändern"
+
+#: src/guiPasswordChange.cpp:155
+msgid "Passwords do not match!"
+msgstr "Passwörter passen nicht zusammen"
+
+#: src/guiPauseMenu.cpp:110
+msgid "Continue"
+msgstr "Weiter"
+
+#: src/guiPauseMenu.cpp:117
+msgid "Change Password"
+msgstr "Passwort ändern"
+
+#: src/guiPauseMenu.cpp:124
+msgid "Disconnect"
+msgstr "Verbindung trennen"
+
+#: src/guiPauseMenu.cpp:131
+msgid "Exit to OS"
+msgstr "Programm beenden"
+
+#: src/guiPauseMenu.cpp:138
+msgid ""
+"Keys:\n"
+"- WASD: Walk\n"
+"- Mouse left: dig blocks\n"
+"- Mouse right: place blocks\n"
+"- Mouse wheel: select item\n"
+"- 0...9: select item\n"
+"- Shift: sneak\n"
+"- R: Toggle viewing all loaded chunks\n"
+"- I: Inventory menu\n"
+"- ESC: This menu\n"
+"- T: Chat\n"
+msgstr ""
+"Tastenkürzel:\n"
+"- WASD: Gehen\n"
+"- linke Maustaste: dig blocks\n"
+"- rechte Maustaste: place blocks\n"
+"- Mausrad: Item auswählen\n"
+"- 0...9: Item auswählen\n"
+"- Shift: ducken\n"
+"- R: Alle geladenen Kartenteile anzeigen, umschalten\n"
+"- I: Inventarmenü\n"
+"- T: Chat\n"
diff --git a/po/en/minetest.pot b/po/en/minetest.pot
new file mode 100644 (file)
index 0000000..8fbac78
--- /dev/null
@@ -0,0 +1,113 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-07-24 11:32+0300\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: src/guiMainMenu.cpp:180
+msgid "Name/Password"
+msgstr ""
+
+#: src/guiMainMenu.cpp:203
+msgid "Address/Port"
+msgstr ""
+
+#: src/guiMainMenu.cpp:223
+msgid "Leave address blank to start a local server."
+msgstr ""
+
+#: src/guiMainMenu.cpp:230
+msgid "Fancy trees"
+msgstr ""
+
+#: src/guiMainMenu.cpp:236
+msgid "Smooth Lighting"
+msgstr ""
+
+#: src/guiMainMenu.cpp:244
+msgid "Start Game / Connect"
+msgstr ""
+
+#: src/guiMainMenu.cpp:253
+msgid "Change keys"
+msgstr ""
+
+#: src/guiMainMenu.cpp:276
+msgid "Creative Mode"
+msgstr ""
+
+#: src/guiMainMenu.cpp:282
+msgid "Enable Damage"
+msgstr ""
+
+#: src/guiMainMenu.cpp:290
+msgid "Delete map"
+msgstr ""
+
+#: src/guiMessageMenu.cpp:93 src/guiTextInputMenu.cpp:111
+msgid "Proceed"
+msgstr ""
+
+#: src/guiPasswordChange.cpp:102
+msgid "Old Password"
+msgstr ""
+
+#: src/guiPasswordChange.cpp:117
+msgid "New Password"
+msgstr ""
+
+#: src/guiPasswordChange.cpp:131
+msgid "Confirm Password"
+msgstr ""
+
+#: src/guiPasswordChange.cpp:146
+msgid "Change"
+msgstr ""
+
+#: src/guiPasswordChange.cpp:155
+msgid "Passwords do not match!"
+msgstr ""
+
+#: src/guiPauseMenu.cpp:110
+msgid "Continue"
+msgstr ""
+
+#: src/guiPauseMenu.cpp:117
+msgid "Change Password"
+msgstr ""
+
+#: src/guiPauseMenu.cpp:124
+msgid "Disconnect"
+msgstr ""
+
+#: src/guiPauseMenu.cpp:131
+msgid "Exit to OS"
+msgstr ""
+
+#: src/guiPauseMenu.cpp:138
+msgid ""
+"Keys:\n"
+"- WASD: Walk\n"
+"- Mouse left: dig blocks\n"
+"- Mouse right: place blocks\n"
+"- Mouse wheel: select item\n"
+"- 0...9: select item\n"
+"- Shift: sneak\n"
+"- R: Toggle viewing all loaded chunks\n"
+"- I: Inventory menu\n"
+"- ESC: This menu\n"
+"- T: Chat\n"
+msgstr ""
diff --git a/po/fr/minetest.po b/po/fr/minetest.po
new file mode 100644 (file)
index 0000000..b060c42
--- /dev/null
@@ -0,0 +1,123 @@
+# French translations for minetest-c55 package.
+# Copyright (C) 2011 celeron
+# This file is distributed under the same license as the minetest-c55 package.
+# Cyriaque 'Cisoun' Skrapits <cysoun@gmail.com>, 2011
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: 0.0.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2011-07-22 11:00+0200\n"
+"PO-Revision-Date: 2011-07-21 15:48+0200\n"
+"Last-Translator: Cyriaque 'Cisoun' Skrapits <cysoun@gmail.com>\n"
+"Language-Team: Français <>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
+
+#: src/guiMainMenu.cpp:180
+msgid "Name/Password"
+msgstr "Nom / MdP"
+
+#: src/guiMainMenu.cpp:203
+msgid "Address/Port"
+msgstr "Adresse / Port"
+
+#: src/guiMainMenu.cpp:223
+msgid "Leave address blank to start a local server."
+msgstr "Laisser l'adresse vide pour lancer un serveur local."
+
+#: src/guiMainMenu.cpp:230
+msgid "Fancy trees"
+msgstr "Arbres spéciaux"
+
+#: src/guiMainMenu.cpp:236
+msgid "Smooth Lighting"
+msgstr "Lumière douce"
+
+#: src/guiMainMenu.cpp:244
+msgid "Start Game / Connect"
+msgstr "Démarrer / Connecter"
+
+#: src/guiMainMenu.cpp:253
+msgid "Change keys"
+msgstr "Changer touches"
+
+#: src/guiMainMenu.cpp:276
+msgid "Creative Mode"
+msgstr "Mode créatif"
+
+#: src/guiMainMenu.cpp:282
+msgid "Enable Damage"
+msgstr "Activer blessures"
+
+#: src/guiMainMenu.cpp:290
+msgid "Delete map"
+msgstr "Supprimer carte"
+
+#: src/guiMessageMenu.cpp:93 src/guiTextInputMenu.cpp:111
+msgid "Proceed"
+msgstr "OK"
+
+#: src/guiPasswordChange.cpp:102
+msgid "Old Password"
+msgstr "Ancien mot de passe"
+
+#: src/guiPasswordChange.cpp:117
+msgid "New Password"
+msgstr "Nouveau mot de passe"
+
+#: src/guiPasswordChange.cpp:131
+msgid "Confirm Password"
+msgstr "Confirmer mot de passe"
+
+#: src/guiPasswordChange.cpp:146
+msgid "Change"
+msgstr "Changer"
+
+#: src/guiPasswordChange.cpp:155
+msgid "Passwords do not match!"
+msgstr "Mauvaise correspondance!"
+
+#: src/guiPauseMenu.cpp:110
+msgid "Continue"
+msgstr "Continuer"
+
+#: src/guiPauseMenu.cpp:117
+msgid "Change Password"
+msgstr "Changer mot de passe"
+
+#: src/guiPauseMenu.cpp:124
+msgid "Disconnect"
+msgstr "Déconnection"
+
+#: src/guiPauseMenu.cpp:131
+msgid "Exit to OS"
+msgstr "Quitter le jeu"
+
+#: src/guiPauseMenu.cpp:138
+msgid ""
+"Keys:\n"
+"- WASD: Walk\n"
+"- Mouse left: dig blocks\n"
+"- Mouse right: place blocks\n"
+"- Mouse wheel: select item\n"
+"- 0...9: select item\n"
+"- Shift: sneak\n"
+"- R: Toggle viewing all loaded chunks\n"
+"- I: Inventory menu\n"
+"- ESC: This menu\n"
+"- T: Chat\n"
+msgstr ""
+"Touches:\n"
+"- WASD: Marcher\n"
+"- Clic gauche: Creuser bloc\n"
+"- Clic droite: Insérer bloc\n"
+"- Roulette: Sélection élément\n"
+"- 0...9: Sélection élément\n"
+"- Shift: S'accroupir\n"
+"- R: Active la vue de tous les blocs\n"
+"- I: Inventaire\n"
+"- T: Chat\n"
index 84726945691261aaacbcba5f5a772cb8af8ef42a..8ce69b2adf8945e02a9a48c047ffce90ce1398d0 100644 (file)
@@ -1,10 +1,33 @@
-project(minetest)
 cmake_minimum_required( VERSION 2.6 )
 
+project(minetest)
+
 if(RUN_IN_PLACE)
        add_definitions ( -DRUN_IN_PLACE )
 endif(RUN_IN_PLACE)
 
+OPTION(USE_GETTEXT "Use GetText for internationalization" OFF)
+
+if(USE_GETTEXT)
+       find_package(GettextLib REQUIRED)
+       message(STATUS "gettext include path: ${GETTEXT_INCLUDE_DIR}")
+       message(STATUS "gettext msgfmt path: ${GETTEXT_MSGFMT}")
+       if(WIN32)
+               message(STATUS "gettext library: ${GETTEXT_LIBRARY}")
+               message(STATUS "gettext dll: ${GETTEXT_DLL}")
+               message(STATUS "gettext iconv dll: ${GETTEXT_ICONV_DLL}")
+       endif()
+       if (GETTEXT_FOUND)
+               add_definitions( -DUSE_GETTEXT )
+               message(STATUS "GetText enabled; locales found: ${GETTEXT_AVAILABLE_LOCALES}")
+       else()
+               message(STATUS "ERROR: GetText enabled but not found, disabling")
+               set(USE_GETTEXT FALSE)
+       endif(GETTEXT_FOUND)
+else(USE_GETTEXT)
+       message(STATUS "GetText disabled")
+endif(USE_GETTEXT)
+
 if(NOT MSVC)
        set(USE_GPROF 0 CACHE BOOL "Use -pg flag for g++")
 endif()
@@ -27,6 +50,8 @@ if(WIN32)
                        CACHE FILEPATH "Path to zlibwapi.lib")
        set(ZLIB_DLL "${PROJECT_SOURCE_DIR}/../../zlib125dll/dll32/zlibwapi.dll"
                        CACHE FILEPATH "Path to zlibwapi.dll (for installation)")
+       set(IRRLICHT_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../../irrlicht-1.7.2"
+                       CACHE PATH "irrlicht dir")
 else()
        # Unix probably
        if(BUILD_CLIENT)
@@ -55,6 +80,9 @@ else()
        set(CLIENT_PLATFORM_LIBS ${CLIENT_PLATFORM_LIBS} ${XXF86VM_LIBRARY})
 endif()
 
+find_package(Jthread REQUIRED)
+find_package(Sqlite3 REQUIRED)
+
 configure_file(
        "${PROJECT_SOURCE_DIR}/cmake_config.h.in"
        "${PROJECT_BINARY_DIR}/cmake_config.h"
@@ -110,6 +138,7 @@ set(minetest_SRCS
        clouds.cpp
        clientobject.cpp
        guiMainMenu.cpp
+       guiKeyChangeMenu.cpp
        guiMessageMenu.cpp
        guiTextInputMenu.cpp
        guiInventoryMenu.cpp
@@ -133,16 +162,17 @@ include_directories(
        ${ZLIB_INCLUDE_DIR}
        ${CMAKE_BUILD_TYPE}
        ${PNG_INCLUDE_DIR}
-       "${PROJECT_SOURCE_DIR}/jthread"
-       "${PROJECT_SOURCE_DIR}/sqlite"
+       ${GETTEXT_INCLUDE_DIR}
+       ${JTHREAD_INCLUDE_DIR}
+       ${SQLITE3_INCLUDE_DIR}
 )
 
 set(EXECUTABLE_OUTPUT_PATH ../bin)
 
 if(BUILD_CLIENT)
-       add_executable(minetest ${minetest_SRCS})
+       add_executable(${PROJECT_NAME} ${minetest_SRCS})
        target_link_libraries(
-               minetest
+               ${PROJECT_NAME}
                ${ZLIB_LIBRARIES}
                ${IRRLICHT_LIBRARY}
                ${OPENGL_LIBRARIES}
@@ -150,21 +180,22 @@ if(BUILD_CLIENT)
                ${BZIP2_LIBRARIES}
                ${PNG_LIBRARIES}
                ${X11_LIBRARIES}
+               ${GETTEXT_LIBRARY}
                ${PLATFORM_LIBS}
                ${CLIENT_PLATFORM_LIBS}
-               jthread
-               sqlite3
+               ${JTHREAD_LIBRARY}
+               ${SQLITE3_LIBRARY}
        )
 endif(BUILD_CLIENT)
 
 if(BUILD_SERVER)
-       add_executable(minetestserver ${minetestserver_SRCS})
+       add_executable(${PROJECT_NAME}server ${minetestserver_SRCS})
        target_link_libraries(
-               minetestserver
+               ${PROJECT_NAME}server
                ${ZLIB_LIBRARIES}
                ${PLATFORM_LIBS}
-               jthread
-               sqlite3
+               ${JTHREAD_LIBRARY}
+               ${SQLITE3_LIBRARY}
        )
 endif(BUILD_SERVER)
 
@@ -185,7 +216,7 @@ if(MSVC)
        set(CMAKE_CXX_FLAGS_DEBUG "/MDd /Zi /Ob0 /Od /RTC1")
        
        if(BUILD_SERVER)
-               set_target_properties(minetestserver PROPERTIES
+               set_target_properties(${PROJECT_NAME}server PROPERTIES
                                COMPILE_DEFINITIONS "SERVER")
        endif(BUILD_SERVER)
 
@@ -215,7 +246,7 @@ else()
        endif()
        
        if(BUILD_SERVER)
-               set_target_properties(minetestserver PROPERTIES
+               set_target_properties(${PROJECT_NAME}server PROPERTIES
                                COMPILE_DEFINITIONS "SERVER")
        endif(BUILD_SERVER)
 
@@ -232,12 +263,20 @@ endif()
 install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../minetest.conf.example" DESTINATION ${EXAMPLE_CONF_DIR})
 
 if(BUILD_CLIENT)
-       install(TARGETS minetest DESTINATION ${BINDIR})
+       install(TARGETS ${PROJECT_NAME} DESTINATION ${BINDIR})
 
        file(GLOB images "${CMAKE_CURRENT_SOURCE_DIR}/../data/*.png")
 
        install(FILES ${images} DESTINATION ${DATADIR})
 
+       if (USE_GETTEXT)
+               foreach(LOCALE ${GETTEXT_AVAILABLE_LOCALES})
+                       set_mo_paths(MO_BUILD_PATH MO_DEST_PATH ${LOCALE})
+                       set(MO_BUILD_PATH "${MO_BUILD_PATH}/${PROJECT_NAME}.mo")
+                       install(FILES ${MO_BUILD_PATH} DESTINATION ${MO_DEST_PATH})
+               endforeach(LOCALE ${GETTEXT_AVAILABLE_LOCALES})
+       endif()
+
        if(WIN32)
                if(DEFINED IRRLICHT_DLL)
                        install(FILES ${IRRLICHT_DLL} DESTINATION ${BINDIR})
@@ -245,16 +284,82 @@ if(BUILD_CLIENT)
                if(DEFINED ZLIB_DLL)
                        install(FILES ${ZLIB_DLL} DESTINATION ${BINDIR})
                endif()
+               if(USE_GETTEXT)
+                       if(DEFINED GETTEXT_DLL)
+                               install(FILES ${GETTEXT_DLL} DESTINATION ${BINDIR})
+                       endif()
+                       if(DEFINED GETTEXT_ICONV_DLL)
+                               install(FILES ${GETTEXT_ICONV_DLL} DESTINATION ${BINDIR})
+                       endif()
+               endif(USE_GETTEXT)
        endif()
 endif(BUILD_CLIENT)
 
 if(BUILD_SERVER)
-       install(TARGETS minetestserver DESTINATION ${BINDIR})
+       install(TARGETS ${PROJECT_NAME}server DESTINATION ${BINDIR})
 endif(BUILD_SERVER)
 
+if (USE_GETTEXT)
+       add_custom_command(OUTPUT "${GETTEXT_PO_PATH}/en"
+               COMMAND ${CMAKE_COMMAND} -E make_directory "${GETTEXT_PO_PATH}/en"
+               COMMENT "po-update [en]: creating translation template base directory")
+       set(POT_FILE "${GETTEXT_PO_PATH}/en/minetest.pot")
+       file(GLOB GETTEXT_POT_DEPS *.cpp *.h)
+       file(GLOB GETTEXT_POT_DEPS_REL RELATIVE ${CMAKE_SOURCE_DIR} *.cpp *.h)
+       add_custom_command(OUTPUT ${POT_FILE}
+               COMMAND ${GETTEXT_EXTRACT} -F -n -o ${POT_FILE} ${GETTEXT_POT_DEPS_REL}
+               DEPENDS "${GETTEXT_PO_PATH}/en" ${GETTEXT_POT_DEPS}
+               WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+               COMMENT "po-update [en]: updating translation template")
+
+       set(PO_FILES)
+       set(MO_FILES)
+
+       foreach(LOCALE ${GETTEXT_AVAILABLE_LOCALES})
+               # skip the 'en' locale which is treated separately
+               if (NOT LOCALE STREQUAL "en")
+                       set(PO_FILE_PATH "${GETTEXT_PO_PATH}/${LOCALE}/minetest.po")
+                       add_custom_command(OUTPUT ${PO_FILE_PATH}
+                               COMMAND ${GETTEXT_MSGMERGE} -F -U ${PO_FILE_PATH} ${POT_FILE}
+                               DEPENDS ${POT_FILE}
+                               WORKING_DIRECTORY "${GETTEXT_PO_PATH}/${LOCALE}"
+                               COMMENT "po-update [${LOCALE}]: updating strings")
+
+
+                       set_mo_paths(MO_BUILD_PATH MO_DEST_PATH ${LOCALE})
+                       add_custom_command(OUTPUT ${MO_BUILD_PATH}
+                               COMMAND ${CMAKE_COMMAND} -E make_directory ${MO_BUILD_PATH}
+                               COMMENT "mo-update [${LOCALE}]: Creating locale directory.")
+
+                       set(MO_FILE_PATH "${MO_BUILD_PATH}/minetest.mo")
+
+                       add_custom_command(
+                               OUTPUT ${MO_FILE_PATH}
+                               COMMAND ${GETTEXT_MSGFMT} -o ${MO_FILE_PATH} ${PO_FILE_PATH}
+                               DEPENDS ${MO_BUILD_PATH} ${PO_FILE_PATH}
+                               WORKING_DIRECTORY "${GETTEXT_PO_PATH}/${LOCALE}"
+                               COMMENT "mo-update [${LOCALE}]: Creating mo file."
+                               )
+
+                       set(MO_FILES ${MO_FILES} ${MO_FILE_PATH})
+                       set(PO_FILES ${PO_FILES} ${PO_FILE_PATH})
+               endif(NOT LOCALE STREQUAL "en")
+       endforeach(LOCALE ${GETTEXT_AVAILABLE_LOCALES})
+
+       add_custom_target(translations ALL COMMENT "mo update" DEPENDS ${MO_FILES})
+       add_custom_target(updatepo COMMENT "po update" DEPENDS ${PO_FILES})
+endif(USE_GETTEXT)
+
 # Subdirectories
 
-add_subdirectory(jthread)
+if (JTHREAD_FOUND)
+else (JTHREAD_FOUND)
+       add_subdirectory(jthread)
+endif (JTHREAD_FOUND)
+
+if (SQLITE3_FOUND)
+else (SQLITE3_FOUND)
 add_subdirectory(sqlite)
+endif (SQLITE3_FOUND)
 
 #end
index 585fce11c3557624ac14ae72ef80e23f1da2bb67..7ebb30fbacd952495fe10f9948713c54e80c16c5 100644 (file)
@@ -5,7 +5,7 @@ Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
-MeshUpdateQueue::(at your option) any later version.
+(at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -328,7 +328,8 @@ void Client::step(float dtime)
 
                        core::list<v3s16> deleted_blocks;
 
-                               g_settings.getFloat("client_unload_unused_data_timeout");
+                       float delete_unused_sectors_timeout = 
+                               g_settings.getFloat("client_delete_unused_sectors_timeout");
        
                        // Delete sector blocks
                        /*u32 num = m_env.getMap().unloadUnusedData
index 122beedacd47133c6468c84d8c75725873c68089..d754cc15e2f0b93972a517037c233b720f8c6d7c 100644 (file)
@@ -84,7 +84,7 @@ void Clouds::render()
        */
 
        const s16 cloud_radius_i = 12;
-       const float cloud_size = BS*50;
+       const float cloud_size = BS*48;
        const v2f cloud_speed(-BS*2, 0);
        
        // Position of cloud noise origin in world coordinates
@@ -123,24 +123,88 @@ void Clouds::render()
                                (float)p_in_noise_i.X*cloud_size/BS/200,
                                (float)p_in_noise_i.Y*cloud_size/BS/200,
                                m_seed, 3, 0.4);
-               if(noise < 0.8)
+               if(noise < 0.95)
                        continue;
-               
-               v2f p1 = p0 + v2f(1,1)*cloud_size;
 
-               //video::SColor c(128,255,255,255);
                float b = m_brightness;
-               video::SColor c(128,b*230,b*230,b*255);
-               video::S3DVertex vertices[4] =
+               video::SColor c_top(128,b*240,b*240,b*255);
+               video::SColor c_side_1(128,b*230,b*230,b*255);
+               video::SColor c_side_2(128,b*220,b*220,b*245);
+               video::SColor c_bottom(128,b*205,b*205,b*230);
+
+               video::S3DVertex v[4] =
                {
-                       video::S3DVertex(p0.X,m_cloud_y,p0.Y, 0,0,0, c, 0,1),
-                       video::S3DVertex(p0.X,m_cloud_y,p1.Y, 0,0,0, c, 1,1),
-                       video::S3DVertex(p1.X,m_cloud_y,p1.Y, 0,0,0, c, 1,0),
-                       video::S3DVertex(p1.X,m_cloud_y,p0.Y, 0,0,0, c, 0,0),
+                       video::S3DVertex(0,0,0, 0,0,0, c_top, 0, 1),
+                       video::S3DVertex(0,0,0, 0,0,0, c_top, 1, 1),
+                       video::S3DVertex(0,0,0, 0,0,0, c_top, 1, 0),
+                       video::S3DVertex(0,0,0, 0,0,0, c_top, 0, 0)
                };
-               u16 indices[] = {0,1,2,2,3,0};
-               driver->drawVertexPrimitiveList(vertices, 4, indices, 2,
-                               video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
+
+               f32 rx = cloud_size;
+               f32 ry = 8*BS;
+               f32 rz = cloud_size;
+
+               for(int i=0;i<6;i++)
+               {
+                       switch(i)
+                       {
+                               case 0: // top
+                                       v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
+                                       v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
+                                       v[2].Pos.X= rx; v[2].Pos.Y= ry; v[2].Pos.Z= rz;
+                                       v[3].Pos.X= rx; v[3].Pos.Y= ry, v[3].Pos.Z=-rz;
+                                       break;
+                               case 1: // back
+                                       for(int j=0;j<4;j++)
+                                               v[j].Color=c_side_1;
+                                       v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
+                                       v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
+                                       v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
+                                       v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
+                                       break;
+                               case 2: //right
+                                       for(int j=0;j<4;j++)
+                                               v[j].Color=c_side_2;
+                                       v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z=-rz;
+                                       v[1].Pos.X= rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
+                                       v[2].Pos.X= rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
+                                       v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
+                                       break;
+                               case 3: // front
+                                       for(int j=0;j<4;j++)
+                                               v[j].Color=c_side_1;
+                                       v[0].Pos.X= rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
+                                       v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z= rz;
+                                       v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z= rz;
+                                       v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
+                                       break;
+                               case 4: // left
+                                       for(int j=0;j<4;j++)
+                                               v[j].Color=c_side_2;
+                                       v[0].Pos.X=-rx; v[0].Pos.Y= ry; v[0].Pos.Z= rz;
+                                       v[1].Pos.X=-rx; v[1].Pos.Y= ry; v[1].Pos.Z=-rz;
+                                       v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
+                                       v[3].Pos.X=-rx; v[3].Pos.Y=-ry, v[3].Pos.Z= rz;
+                                       break;
+                               case 5: // bottom
+                                       for(int j=0;j<4;j++)
+                                               v[j].Color=c_bottom;
+                                       v[0].Pos.X= rx; v[0].Pos.Y=-ry; v[0].Pos.Z= rz;
+                                       v[1].Pos.X=-rx; v[1].Pos.Y=-ry; v[1].Pos.Z= rz;
+                                       v[2].Pos.X=-rx; v[2].Pos.Y=-ry; v[2].Pos.Z=-rz;
+                                       v[3].Pos.X= rx; v[3].Pos.Y=-ry, v[3].Pos.Z=-rz;
+                                       break;
+                       }
+
+                       v3f pos = v3f(p0.X,m_cloud_y,p0.Y);
+
+                       for(u16 i=0; i<4; i++)
+                               v[i].Pos += pos;
+                       u16 indices[] = {0,1,2,2,3,0};
+                       driver->drawVertexPrimitiveList(v, 4, indices, 2,
+                                       video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
+               }
+
        }
 }
 
index 01d5462847134f952626b4ea315dc83910b02286..3d322cf0c4baee77342ab5026e652e639e01ecb4 100644 (file)
@@ -78,7 +78,8 @@ collisionMoveResult collisionMoveSimple(Map *map, f32 pos_max_d,
        {
                try{
                        // Object collides into walkable nodes
-                       if(content_walkable(map->getNode(v3s16(x,y,z)).d) == false)
+                       MapNode n = map->getNode(v3s16(x,y,z));
+                       if(content_features(n).walkable == false)
                                continue;
                }
                catch(InvalidPositionException &e)
index dc5ac400f5da3f05f400291ade4911ab7f220866..dfeaea85ab09babf8d62f7a07b22a058046ea353 100644 (file)
@@ -752,4 +752,161 @@ void Oerkki1CAO::initialize(const std::string &data)
        updateNodePos();
 }
 
+/*
+       FireflyCAO
+*/
+
+// Prototype
+FireflyCAO proto_FireflyCAO;
+
+FireflyCAO::FireflyCAO():
+       ClientActiveObject(0),
+       m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS/2.,BS/3.),
+       m_node(NULL),
+       m_position(v3f(0,10*BS,0)),
+       m_yaw(0)
+{
+       ClientActiveObject::registerType(getType(), create);
+}
 
+FireflyCAO::~FireflyCAO()
+{
+}
+
+ClientActiveObject* FireflyCAO::create()
+{
+       return new FireflyCAO();
+}
+
+void FireflyCAO::addToScene(scene::ISceneManager *smgr)
+{
+       if(m_node != NULL)
+               return;
+       
+       video::IVideoDriver* driver = smgr->getVideoDriver();
+       
+       scene::SMesh *mesh = new scene::SMesh();
+       scene::IMeshBuffer *buf = new scene::SMeshBuffer();
+       video::SColor c(255,255,255,255);
+       video::S3DVertex vertices[4] =
+       {
+               video::S3DVertex(0,0,0, 0,0,0, c, 0,1),
+               video::S3DVertex(BS/2,0,0, 0,0,0, c, 1,1),
+               video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, 1,0),
+               video::S3DVertex(0,BS/2,0, 0,0,0, c, 0,0),
+       };
+       u16 indices[] = {0,1,2,2,3,0};
+       buf->append(vertices, 4, indices, 6);
+       // Set material
+       buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
+       buf->getMaterial().setFlag(video::EMF_BACK_FACE_CULLING, false);
+       //buf->getMaterial().setTexture(0, NULL);
+       buf->getMaterial().setTexture
+                       (0, driver->getTexture(getTexturePath("firefly.png").c_str()));
+       buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
+       buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
+       buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+       // Add to mesh
+       mesh->addMeshBuffer(buf);
+       buf->drop();
+       m_node = smgr->addMeshSceneNode(mesh, NULL);
+       mesh->drop();
+       // Set it to use the materials of the meshbuffers directly.
+       // This is needed for changing the texture in the future
+       m_node->setReadOnlyMaterials(true);
+       updateNodePos();
+}
+
+void FireflyCAO::removeFromScene()
+{
+       if(m_node == NULL)
+               return;
+
+       m_node->remove();
+       m_node = NULL;
+}
+
+void FireflyCAO::updateLight(u8 light_at_pos)
+{
+       if(m_node == NULL)
+               return;
+
+       u8 li = 255;
+       video::SColor color(255,li,li,li);
+
+       scene::IMesh *mesh = m_node->getMesh();
+       if(mesh == NULL)
+               return;
+       
+       u16 mc = mesh->getMeshBufferCount();
+       for(u16 j=0; j<mc; j++)
+       {
+               scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+               video::S3DVertex *vertices = (video::S3DVertex*)buf->getVertices();
+               u16 vc = buf->getVertexCount();
+               for(u16 i=0; i<vc; i++)
+               {
+                       vertices[i].Color = color;
+               }
+       }
+}
+
+v3s16 FireflyCAO::getLightPosition()
+{
+       return floatToInt(m_position+v3f(0,BS*0.5,0), BS);
+}
+
+void FireflyCAO::updateNodePos()
+{
+       if(m_node == NULL)
+               return;
+
+       //m_node->setPosition(m_position);
+       m_node->setPosition(pos_translator.vect_show);
+
+       v3f rot = m_node->getRotation();
+       rot.Y = 180.0 - m_yaw;
+       m_node->setRotation(rot);
+}
+
+void FireflyCAO::step(float dtime, ClientEnvironment *env)
+{
+       pos_translator.translate(dtime);
+       updateNodePos();
+}
+
+void FireflyCAO::processMessage(const std::string &data)
+{
+       //dstream<<"FireflyCAO: Got message"<<std::endl;
+       std::istringstream is(data, std::ios::binary);
+       // command
+       u8 cmd = readU8(is);
+       if(cmd == 0)
+       {
+               // pos
+               m_position = readV3F1000(is);
+               pos_translator.update(m_position);
+               // yaw
+               m_yaw = readF1000(is);
+               updateNodePos();
+       }
+}
+
+void FireflyCAO::initialize(const std::string &data)
+{
+       //dstream<<"FireflyCAO: Got init data"<<std::endl;
+       
+       {
+               std::istringstream is(data, std::ios::binary);
+               // version
+               u8 version = readU8(is);
+               // check version
+               if(version != 0)
+                       return;
+               // pos
+               m_position = readV3F1000(is);
+               pos_translator.init(m_position);
+       }
+       
+       updateNodePos();
+}
index 146e23b0c985f0db3bd7f5fa0071866bbd88e543..b984be1361cb79d98fbf016659058cec538f65dd 100644 (file)
@@ -243,6 +243,48 @@ private:
        bool m_damage_texture_enabled;
 };
 
+/*
+       FireflyCAO
+*/
+
+class FireflyCAO : public ClientActiveObject
+{
+public:
+       FireflyCAO();
+       virtual ~FireflyCAO();
+       
+       u8 getType() const
+       {
+               return ACTIVEOBJECT_TYPE_FIREFLY;
+       }
+       
+       static ClientActiveObject* create();
+
+       void addToScene(scene::ISceneManager *smgr);
+       void removeFromScene();
+       void updateLight(u8 light_at_pos);
+       v3s16 getLightPosition();
+       void updateNodePos();
+
+       void step(float dtime, ClientEnvironment *env);
+
+       void processMessage(const std::string &data);
+
+       void initialize(const std::string &data);
+       
+       core::aabbox3d<f32>* getSelectionBox()
+               {return &m_selection_box;}
+       v3f getPosition()
+               {return m_position;}
+
+private:
+       core::aabbox3d<f32> m_selection_box;
+       scene::IMeshSceneNode *m_node;
+       v3f m_position;
+       float m_yaw;
+       SmoothTranslator pos_translator;
+};
+
 
 #endif
 
index 32d2e6d489b6f4d5cdff8ff952463a6e77822268..b5a1dc7761795deeee13cabf022ef920f15859f9 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "inventory.h"
 #include "content_mapnode.h"
 #include "player.h"
+#include "mapnode.h" // For content_t
 
 /*
        items: actually *items[9]
@@ -261,6 +262,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 +332,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;
 }
 
@@ -347,16 +447,23 @@ void craft_set_creative_inventory(Player *player)
        */
        
        // CONTENT_IGNORE-terminated list
-       u8 material_items[] = {
+       content_t material_items[] = {
                CONTENT_TORCH,
                CONTENT_COBBLE,
                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,
@@ -366,7 +473,7 @@ void craft_set_creative_inventory(Player *player)
                CONTENT_IGNORE
        };
        
-       u8 *mip = material_items;
+       content_t *mip = material_items;
        for(u16 i=0; i<PLAYER_INVENTORY_SIZE; i++)
        {
                if(*mip == CONTENT_IGNORE)
index ac48a619550fe414118626e9f56c515824093074..3222506067169eb5af7be5805162fdc34dde07f8 100644 (file)
@@ -23,7 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 //#include "serverobject.h"
 #include "content_sao.h"
 
-bool item_material_is_cookable(u8 content)
+bool item_material_is_cookable(content_t content)
 {
        if(content == CONTENT_TREE)
                return true;
@@ -34,7 +34,7 @@ bool item_material_is_cookable(u8 content)
        return false;
 }
 
-InventoryItem* item_material_create_cook_result(u8 content)
+InventoryItem* item_material_create_cook_result(content_t content)
 {
        if(content == CONTENT_TREE)
                return new CraftItem("lump_of_coal", 1);
@@ -49,14 +49,24 @@ 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 if(subname == "firefly")
+               return "firefly.png";
        else
                return "cloud.png"; // just something
 }
@@ -69,13 +79,18 @@ ServerActiveObject* item_craft_create_object(const std::string &subname,
                ServerActiveObject *obj = new RatSAO(env, id, pos);
                return obj;
        }
+       else if(subname == "firefly")
+       {
+               ServerActiveObject *obj = new FireflySAO(env, id, pos);
+               return obj;
+       }
 
        return NULL;
 }
 
 s16 item_craft_get_drop_count(const std::string &subname)
 {
-       if(subname == "rat")
+       if(subname == "rat" || subname == "firefly")
                return 1;
 
        return -1;
@@ -83,7 +98,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;
@@ -93,6 +108,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;
 }
index 54aa2151a92a5592f20369fdca2b6b6d8a64f7de..0f410128ba2aed04ddab8f0985f2b321d06ff482 100644 (file)
@@ -22,13 +22,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "common_irrlicht.h" // For u8, s16
 #include <string>
+#include "mapnode.h" // For content_t
 
 class InventoryItem;
 class ServerActiveObject;
 class ServerEnvironment;
 
-bool           item_material_is_cookable(u8 content);
-InventoryItem* item_material_create_cook_result(u8 content);
+bool           item_material_is_cookable(content_t content);
+InventoryItem* item_material_create_cook_result(content_t content);
 
 std::string         item_craft_get_image_name(const std::string &subname);
 ServerActiveObject* item_craft_create_object(const std::string &subname,
index bdc9baa2aac09767ecc497a280e05e81c02c202a..3044c8b359102c8c55293d48ecd62fb1b1509b4f 100644 (file)
@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "content_mapnode.h"
 #include "main.h" // For g_settings and g_texturesource
 #include "mineral.h"
+#include "mapblock_mesh.h" // For MapBlock_LightColor()
 
 #ifndef SERVER
 // Create a cuboid.
@@ -188,6 +189,27 @@ 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);
+
+       // junglegrass material
+       video::SMaterial material_junglegrass;
+       material_junglegrass.setFlag(video::EMF_LIGHTING, false);
+       material_junglegrass.setFlag(video::EMF_BILINEAR_FILTER, false);
+       material_junglegrass.setFlag(video::EMF_FOG_ENABLE, true);
+       material_junglegrass.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+       AtlasPointer pa_junglegrass = g_texturesource->getTexture(
+                       g_texturesource->getTextureId("junglegrass.png"));
+       material_junglegrass.setTexture(0, pa_junglegrass.atlas);
+
        for(s16 z=0; z<MAP_BLOCKSIZE; z++)
        for(s16 y=0; y<MAP_BLOCKSIZE; y++)
        for(s16 x=0; x<MAP_BLOCKSIZE; x++)
@@ -199,7 +221,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                /*
                        Add torches to mesh
                */
-               if(n.d == CONTENT_TORCH)
+               if(n.getContent() == CONTENT_TORCH)
                {
                        video::SColor c(255,255,255,255);
 
@@ -212,7 +234,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, 0,0),
                        };
 
-                       v3s16 dir = unpackDir(n.dir);
+                       v3s16 dir = unpackDir(n.param2);
 
                        for(s32 i=0; i<4; i++)
                        {
@@ -262,10 +284,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                /*
                        Signs on walls
                */
-               else if(n.d == CONTENT_SIGN_WALL)
+               else if(n.getContent() == CONTENT_SIGN_WALL)
                {
                        u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
-                       video::SColor c(255,l,l,l);
+                       video::SColor c = MapBlock_LightColor(255, l);
                                
                        float d = (float)BS/16;
                        // Wall at X+ of node
@@ -277,7 +299,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                video::S3DVertex(BS/2-d,BS/2,-BS/2, 0,0,0, c, 0,0),
                        };
 
-                       v3s16 dir = unpackDir(n.dir);
+                       v3s16 dir = unpackDir(n.param2);
 
                        for(s32 i=0; i<4; i++)
                        {
@@ -317,26 +339,26 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                /*
                        Add flowing water to mesh
                */
-               else if(n.d == CONTENT_WATER)
+               else if(n.getContent() == CONTENT_WATER)
                {
                        bool top_is_water = false;
                        MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
-                       if(ntop.d == CONTENT_WATER || ntop.d == CONTENT_WATERSOURCE)
+                       if(ntop.getContent() == CONTENT_WATER || ntop.getContent() == CONTENT_WATERSOURCE)
                                top_is_water = true;
                        
                        u8 l = 0;
                        // Use the light of the node on top if possible
-                       if(content_features(ntop.d).param_type == CPT_LIGHT)
+                       if(content_features(ntop).param_type == CPT_LIGHT)
                                l = decode_light(ntop.getLightBlend(data->m_daynight_ratio));
                        // Otherwise use the light of this node (the water)
                        else
                                l = decode_light(n.getLightBlend(data->m_daynight_ratio));
-                       video::SColor c(WATER_ALPHA,l,l,l);
+                       video::SColor c = MapBlock_LightColor(WATER_ALPHA, l);
                        
                        // Neighbor water levels (key = relative position)
                        // Includes current node
                        core::map<v3s16, f32> neighbor_levels;
-                       core::map<v3s16, u8> neighbor_contents;
+                       core::map<v3s16, content_t> neighbor_contents;
                        core::map<v3s16, u8> neighbor_flags;
                        const u8 neighborflag_top_is_water = 0x01;
                        v3s16 neighbor_dirs[9] = {
@@ -358,13 +380,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                // Check neighbor
                                v3s16 p2 = p + neighbor_dirs[i];
                                MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
-                               if(n2.d != CONTENT_IGNORE)
+                               if(n2.getContent() != CONTENT_IGNORE)
                                {
-                                       content = n2.d;
+                                       content = n2.getContent();
 
-                                       if(n2.d == CONTENT_WATERSOURCE)
+                                       if(n2.getContent() == CONTENT_WATERSOURCE)
                                                level = (-0.5+node_water_level) * BS;
-                                       else if(n2.d == CONTENT_WATER)
+                                       else if(n2.getContent() == CONTENT_WATER)
                                                level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0
                                                                * node_water_level) * BS;
 
@@ -373,7 +395,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                        //       doesn't exist
                                        p2.Y += 1;
                                        n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
-                                       if(n2.d == CONTENT_WATERSOURCE || n2.d == CONTENT_WATER)
+                                       if(n2.getContent() == CONTENT_WATERSOURCE || n2.getContent() == CONTENT_WATER)
                                                flags |= neighborflag_top_is_water;
                                }
                                
@@ -581,14 +603,14 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                /*
                        Add water sources to mesh if using new style
                */
-               else if(n.d == CONTENT_WATERSOURCE && new_style_water)
+               else if(n.getContent() == CONTENT_WATERSOURCE && new_style_water)
                {
                        //bool top_is_water = false;
                        bool top_is_air = false;
                        MapNode n = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
-                       /*if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
+                       /*if(n.getContent() == CONTENT_WATER || n.getContent() == CONTENT_WATERSOURCE)
                                top_is_water = true;*/
-                       if(n.d == CONTENT_AIR)
+                       if(n.getContent() == CONTENT_AIR)
                                top_is_air = true;
                        
                        /*if(top_is_water == true)
@@ -597,7 +619,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                continue;
 
                        u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
-                       video::SColor c(WATER_ALPHA,l,l,l);
+                       video::SColor c = MapBlock_LightColor(WATER_ALPHA, l);
                        
                        video::S3DVertex vertices[4] =
                        {
@@ -628,11 +650,11 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                /*
                        Add leaves if using new style
                */
-               else if(n.d == CONTENT_LEAVES && new_style_leaves)
+               else if(n.getContent() == CONTENT_LEAVES && new_style_leaves)
                {
                        /*u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));*/
                        u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
-                       video::SColor c(255,l,l,l);
+                       video::SColor c = MapBlock_LightColor(255, l);
 
                        for(u32 j=0; j<6; j++)
                        {
@@ -696,10 +718,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                /*
                        Add glass
                */
-               else if(n.d == CONTENT_GLASS)
+               else if(n.getContent() == CONTENT_GLASS)
                {
                        u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
-                       video::SColor c(255,l,l,l);
+                       video::SColor c = MapBlock_LightColor(255, l);
 
                        for(u32 j=0; j<6; j++)
                        {
@@ -759,10 +781,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                /*
                        Add fence
                */
-               else if(n.d == CONTENT_FENCE)
+               else if(n.getContent() == CONTENT_FENCE)
                {
                        u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
-                       video::SColor c(255,l,l,l);
+                       video::SColor c = MapBlock_LightColor(255, l);
 
                        const f32 post_rad=(f32)BS/10;
                        const f32 bar_rad=(f32)BS/20;
@@ -785,7 +807,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                        v3s16 p2 = p;
                        p2.X++;
                        MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
-                       if(n2.d == CONTENT_FENCE)
+                       if(n2.getContent() == CONTENT_FENCE)
                        {
                                pos = intToFloat(p+blockpos_nodes, BS);
                                pos.X += BS/2;
@@ -811,7 +833,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                        p2 = p;
                        p2.Z++;
                        n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
-                       if(n2.d == CONTENT_FENCE)
+                       if(n2.getContent() == CONTENT_FENCE)
                        {
                                pos = intToFloat(p+blockpos_nodes, BS);
                                pos.Z += BS/2;
@@ -838,7 +860,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                /*
                        Add stones with minerals if stone is invisible
                */
-               else if(n.d == CONTENT_STONE && invisible_stone && n.getMineral() != MINERAL_NONE)
+               else if(n.getContent() == CONTENT_STONE && invisible_stone && n.getMineral() != MINERAL_NONE)
                {
                        for(u32 j=0; j<6; j++)
                        {
@@ -846,12 +868,12 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                v3s16 dir = g_6dirs[j];
                                /*u8 l = 0;
                                MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + dir);
-                               if(content_features(n2.d).param_type == CPT_LIGHT)
+                               if(content_features(n2).param_type == CPT_LIGHT)
                                        l = decode_light(n2.getLightBlend(data->m_daynight_ratio));
                                else
                                        l = 255;*/
                                u8 l = 255;
-                               video::SColor c(255,l,l,l);
+                               video::SColor c = MapBlock_LightColor(255, l);
                                
                                // Get the right texture
                                TileSpec ts = n.getTile(dir);
@@ -895,14 +917,56 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
                                                vertices[i].Pos.rotateXZBy(90);
                                }
                                else if(j == 4)
+
+                               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_general, vertices, 4, indices, 6);
+                       }
+               }
+#endif
+               else if(n.getContent() == CONTENT_PAPYRUS)
+               {
+                       u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
+                       video::SColor c = MapBlock_LightColor(255, 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.rotateYZBy(-90);
+                                               vertices[i].Pos.rotateXZBy(45);
                                }
-                               else if(j == 5)
+                               else if(j == 1)
                                {
                                        for(u16 i=0; i<4; i++)
-                                               vertices[i].Pos.rotateYZBy(90);
+                                               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++)
@@ -912,11 +976,164 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
 
                                u16 indices[] = {0,1,2,2,3,0};
                                // Add to mesh collector
-                               collector.append(material_general, vertices, 4, indices, 6);
+                               collector.append(material_papyrus, vertices, 4, indices, 6);
                        }
                }
-#endif
+               else if(n.getContent() == CONTENT_JUNGLEGRASS)
+               {
+                       u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio)));
+                       video::SColor c = MapBlock_LightColor(255, 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/1,0, 0,0,0, c,
+                                               pa_papyrus.x1(), pa_papyrus.y0()),
+                                       video::S3DVertex(-BS/2,BS/1,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 *= 1.3;
+                                       vertices[i].Pos += intToFloat(p + blockpos_nodes, BS);
+                               }
+
+                               u16 indices[] = {0,1,2,2,3,0};
+                               // Add to mesh collector
+                               collector.append(material_junglegrass, vertices, 4, indices, 6);
+                       }
+               }
+               else if(n.getContent() == CONTENT_RAIL)
+               {
+                       u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio));
+                       video::SColor c = MapBlock_LightColor(255, 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.getContent() == CONTENT_RAIL)
+                               is_rail_x[0] = true;
+                       if(n_plus_x.getContent() == CONTENT_RAIL)
+                               is_rail_x[1] = true;
+                       if(n_minus_z.getContent() == CONTENT_RAIL)
+                               is_rail_z[0] = true;
+                       if(n_plus_z.getContent() == 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
index d82ccc5c9c7eb48882f34b47ff2b78412304f5cb..db036ebd9a6c9a43e7462a635ee739a66bfd7141 100644 (file)
@@ -31,6 +31,65 @@ void setStoneLikeDiggingProperties(DiggingPropertiesList &list, float toughness)
 void setDirtLikeDiggingProperties(DiggingPropertiesList &list, float toughness);
 void setWoodLikeDiggingProperties(DiggingPropertiesList &list, float toughness);
 
+content_t trans_table_19[][2] = {
+       {CONTENT_GRASS, 1},
+       {CONTENT_TREE, 4},
+       {CONTENT_LEAVES, 5},
+       {CONTENT_GRASS_FOOTSTEPS, 6},
+       {CONTENT_MESE, 7},
+       {CONTENT_MUD, 8},
+       {CONTENT_CLOUD, 10},
+       {CONTENT_COALSTONE, 11},
+       {CONTENT_WOOD, 12},
+       {CONTENT_SAND, 13},
+       {CONTENT_COBBLE, 18},
+       {CONTENT_STEEL, 19},
+       {CONTENT_GLASS, 20},
+       {CONTENT_MOSSYCOBBLE, 22},
+       {CONTENT_GRAVEL, 23},
+       {CONTENT_SANDSTONE, 24},
+       {CONTENT_CACTUS, 25},
+       {CONTENT_BRICK, 26},
+       {CONTENT_CLAY, 27},
+       {CONTENT_PAPYRUS, 28},
+       {CONTENT_BOOKSHELF, 29},
+};
+
+MapNode mapnode_translate_from_internal(MapNode n_from, u8 version)
+{
+       MapNode result = n_from;
+       if(version <= 19)
+       {
+               content_t c_from = n_from.getContent();
+               for(u32 i=0; i<sizeof(trans_table_19)/sizeof(trans_table_19[0]); i++)
+               {
+                       if(trans_table_19[i][0] == c_from)
+                       {
+                               result.setContent(trans_table_19[i][1]);
+                               break;
+                       }
+               }
+       }
+       return result;
+}
+MapNode mapnode_translate_to_internal(MapNode n_from, u8 version)
+{
+       MapNode result = n_from;
+       if(version <= 19)
+       {
+               content_t c_from = n_from.getContent();
+               for(u32 i=0; i<sizeof(trans_table_19)/sizeof(trans_table_19[0]); i++)
+               {
+                       if(trans_table_19[i][1] == c_from)
+                       {
+                               result.setContent(trans_table_19[i][0]);
+                               break;
+                       }
+               }
+       }
+       return result;
+}
+
 void content_mapnode_init()
 {
        // Read some settings
@@ -38,7 +97,7 @@ void content_mapnode_init()
        bool new_style_leaves = g_settings.getBool("new_style_leaves");
        bool invisible_stone = g_settings.getBool("invisible_stone");
 
-       u8 i;
+       content_t i;
        ContentFeatures *f = NULL;
 
        i = CONTENT_STONE;
@@ -99,6 +158,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");
@@ -109,12 +195,34 @@ void content_mapnode_init()
        f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
        setWoodLikeDiggingProperties(f->digging_properties, 1.0);
        
+       i = CONTENT_JUNGLETREE;
+       f = &content_features(i);
+       f->setAllTextures("jungletree.png");
+       f->setTexture(0, "jungletree_top.png");
+       f->setTexture(1, "jungletree_top.png");
+       f->param_type = CPT_MINERAL;
+       //f->is_ground_content = true;
+       f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
+       setWoodLikeDiggingProperties(f->digging_properties, 1.0);
+       
+       i = CONTENT_JUNGLEGRASS;
+       f = &content_features(i);
+       f->setInventoryTexture("junglegrass.png");
+       f->light_propagates = true;
+       f->param_type = CPT_LIGHT;
+       //f->is_ground_content = true;
+       f->air_equivalent = false; // grass grows underneath
+       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.10);
+
        i = CONTENT_LEAVES;
        f = &content_features(i);
        f->light_propagates = true;
        //f->param_type = CPT_MINERAL;
        f->param_type = CPT_LIGHT;
-       f->is_ground_content = true;
+       //f->is_ground_content = true;
        if(new_style_leaves)
        {
                f->solidness = 0; // drawn separately, makes no faces
@@ -127,9 +235,44 @@ 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;
+       f->sunlight_propagates = true;
        f->param_type = CPT_LIGHT;
        f->is_ground_content = true;
        f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
@@ -148,6 +291,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);
@@ -202,6 +357,7 @@ void content_mapnode_init()
        f->buildable_to = true;
        f->liquid_type = LIQUID_FLOWING;
        f->liquid_alternative_flowing = CONTENT_WATER;
+       f->liquid_alternative_source = CONTENT_WATERSOURCE;
        
        i = CONTENT_WATERSOURCE;
        f = &content_features(i);
@@ -233,6 +389,7 @@ void content_mapnode_init()
        f->liquid_type = LIQUID_SOURCE;
        f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
        f->liquid_alternative_flowing = CONTENT_WATER;
+       f->liquid_alternative_source = CONTENT_WATERSOURCE;
        
        i = CONTENT_TORCH;
        f = &content_features(i);
index e314807f94dc7c92a37c8871a068a1f1b0b2187c..51cf06496df1b3be76f3d3770e80189cd0e8e37b 100644 (file)
@@ -20,36 +20,57 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #ifndef CONTENT_MAPNODE_HEADER
 #define CONTENT_MAPNODE_HEADER
 
+#include "mapnode.h"
+
 void content_mapnode_init();
 
+MapNode mapnode_translate_from_internal(MapNode n_from, u8 version);
+MapNode mapnode_translate_to_internal(MapNode n_from, u8 version);
+
 /*
        Node content type IDs
+       Ranges:
 */
+
+// 0x000...0x07f (0...127): param2 is fully usable
+// 126 and 127 are reserved.
+// Use these sparingly, only when the extra space in param2 might be needed.
 #define CONTENT_STONE 0
-#define CONTENT_GRASS 1
 #define CONTENT_WATER 2
 #define CONTENT_TORCH 3
-#define CONTENT_TREE 4
-#define CONTENT_LEAVES 5
-#define CONTENT_GRASS_FOOTSTEPS 6
-#define CONTENT_MESE 7
-#define CONTENT_MUD 8
 #define CONTENT_WATERSOURCE 9
-// Pretty much useless, clouds won't be drawn this way
-#define CONTENT_CLOUD 10
-#define CONTENT_COALSTONE 11
-#define CONTENT_WOOD 12
-#define CONTENT_SAND 13
 #define CONTENT_SIGN_WALL 14
 #define CONTENT_CHEST 15
 #define CONTENT_FURNACE 16
-//#define CONTENT_WORKBENCH 17
-#define CONTENT_COBBLE 18
-#define CONTENT_STEEL 19
-#define CONTENT_GLASS 20
 #define CONTENT_FENCE 21
-#define CONTENT_MOSSYCOBBLE 22
-#define CONTENT_GRAVEL 23
+#define CONTENT_RAIL 30
+#define CONTENT_JUNGLETREE 31
+#define CONTENT_JUNGLEGRASS 32
+
+// 0x800...0xfff (2048...4095): higher 4 bytes of param2 are not usable
+#define CONTENT_GRASS 0x800 //1
+#define CONTENT_TREE 0x801 //4
+#define CONTENT_LEAVES 0x802 //5
+#define CONTENT_GRASS_FOOTSTEPS 0x803 //6
+#define CONTENT_MESE 0x804 //7
+#define CONTENT_MUD 0x805 //8
+// Pretty much useless, clouds won't be drawn this way
+#define CONTENT_CLOUD 0x806 //10
+#define CONTENT_COALSTONE 0x807 //11
+#define CONTENT_WOOD 0x808 //12
+#define CONTENT_SAND 0x809 //13
+#define CONTENT_COBBLE 0x80a //18
+#define CONTENT_STEEL 0x80b //19
+#define CONTENT_GLASS 0x80c //20
+#define CONTENT_MOSSYCOBBLE 0x80d //22
+#define CONTENT_GRAVEL 0x80e //23
+#define CONTENT_SANDSTONE 0x80f //24
+#define CONTENT_CACTUS 0x810 //25
+#define CONTENT_BRICK 0x811 //26
+#define CONTENT_CLAY 0x812 //27
+#define CONTENT_PAPYRUS 0x813 //28
+#define CONTENT_BOOKSHELF 0x814 //29
+
 
 #endif
 
index ecabd8a3877ab5eaf850857564df86a5b06a3ee0..47f93d7d4ad492828609f671d139613d00f2aa02 100644 (file)
@@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define ACTIVEOBJECT_TYPE_ITEM 2
 #define ACTIVEOBJECT_TYPE_RAT 3
 #define ACTIVEOBJECT_TYPE_OERKKI1 4
+#define ACTIVEOBJECT_TYPE_FIREFLY 5
 
 #endif
 
index c41f4ed784297e0aaf08efb5ac6dc1f0bba0a07c..0b81855c16aec55f0c9fffaa685e9ed411ba86ca 100644 (file)
@@ -693,4 +693,179 @@ void Oerkki1SAO::doDamage(u16 d)
        }
 }
 
+/*
+       FireflySAO
+*/
+
+// Prototype
+FireflySAO proto_FireflySAO(NULL, 0, v3f(0,0,0));
 
+FireflySAO::FireflySAO(ServerEnvironment *env, u16 id, v3f pos):
+       ServerActiveObject(env, id, pos),
+       m_is_active(false),
+       m_speed_f(0,0,0)
+{
+       ServerActiveObject::registerType(getType(), create);
+
+       m_oldpos = v3f(0,0,0);
+       m_last_sent_position = v3f(0,0,0);
+       m_yaw = 0;
+       m_counter1 = 0;
+       m_counter2 = 0;
+       m_age = 0;
+       m_touching_ground = false;
+}
+
+ServerActiveObject* FireflySAO::create(ServerEnvironment *env, u16 id, v3f pos,
+               const std::string &data)
+{
+       std::istringstream is(data, std::ios::binary);
+       char buf[1];
+       // read version
+       is.read(buf, 1);
+       u8 version = buf[0];
+       // check if version is supported
+       if(version != 0)
+               return NULL;
+       return new FireflySAO(env, id, pos);
+}
+
+void FireflySAO::step(float dtime, bool send_recommended)
+{
+       assert(m_env);
+
+       if(m_is_active == false)
+       {
+               if(m_inactive_interval.step(dtime, 0.5)==false)
+                       return;
+       }
+
+       /*
+               The AI
+       */
+
+       // Apply (less) gravity
+       m_speed_f.Y -= dtime*3*BS;
+
+       /*
+               Move around if some player is close
+       */
+       bool player_is_close = false;
+       // Check connected players
+       core::list<Player*> players = m_env->getPlayers(true);
+       core::list<Player*>::Iterator i;
+       for(i = players.begin();
+                       i != players.end(); i++)
+       {
+               Player *player = *i;
+               v3f playerpos = player->getPosition();
+               if(m_base_position.getDistanceFrom(playerpos) < BS*10.0)
+               {
+                       player_is_close = true;
+                       break;
+               }
+       }
+
+       m_is_active = player_is_close;
+       
+       if(player_is_close == false)
+       {
+               m_speed_f.X = 0;
+               m_speed_f.Z = 0;
+       }
+       else
+       {
+               // Move around
+               v3f dir(cos(m_yaw/180*PI),0,sin(m_yaw/180*PI));
+               f32 speed = BS/2;
+               m_speed_f.X = speed * dir.X;
+               m_speed_f.Z = speed * dir.Z;
+
+               if(m_touching_ground && (m_oldpos - m_base_position).getLength()
+                               < dtime*speed/2)
+               {
+                       m_counter1 -= dtime;
+                       if(m_counter1 < 0.0)
+                       {
+                               m_counter1 += 1.0;
+                               m_speed_f.Y = 5.0*BS;
+                       }
+               }
+
+               {
+                       m_counter2 -= dtime;
+                       if(m_counter2 < 0.0)
+                       {
+                               m_counter2 += (float)(myrand()%100)/100*3.0;
+                               m_yaw += ((float)(myrand()%200)-100)/100*180;
+                               m_yaw = wrapDegrees(m_yaw);
+                       }
+               }
+       }
+       
+       m_oldpos = m_base_position;
+
+       /*
+               Move it, with collision detection
+       */
+
+       core::aabbox3d<f32> box(-BS/3.,-BS*2/3.0,-BS/3., BS/3.,BS*4./3.,BS/3.);
+       collisionMoveResult moveresult;
+       // Maximum movement without glitches
+       f32 pos_max_d = BS*0.25;
+       // Limit speed
+       if(m_speed_f.getLength()*dtime > pos_max_d)
+               m_speed_f *= pos_max_d / (m_speed_f.getLength()*dtime);
+       v3f pos_f = getBasePosition();
+       v3f pos_f_old = pos_f;
+       moveresult = collisionMoveSimple(&m_env->getMap(), pos_max_d,
+                       box, dtime, pos_f, m_speed_f);
+       m_touching_ground = moveresult.touching_ground;
+       
+       setBasePosition(pos_f);
+
+       if(send_recommended == false)
+               return;
+
+       if(pos_f.getDistanceFrom(m_last_sent_position) > 0.05*BS)
+       {
+               m_last_sent_position = pos_f;
+
+               std::ostringstream os(std::ios::binary);
+               // command (0 = update position)
+               writeU8(os, 0);
+               // pos
+               writeV3F1000(os, m_base_position);
+               // yaw
+               writeF1000(os, m_yaw);
+               // create message and add to list
+               ActiveObjectMessage aom(getId(), false, os.str());
+               m_messages_out.push_back(aom);
+       }
+}
+
+std::string FireflySAO::getClientInitializationData()
+{
+       std::ostringstream os(std::ios::binary);
+       // version
+       writeU8(os, 0);
+       // pos
+       writeV3F1000(os, m_base_position);
+       return os.str();
+}
+
+std::string FireflySAO::getStaticData()
+{
+       //dstream<<__FUNCTION_NAME<<std::endl;
+       std::ostringstream os(std::ios::binary);
+       // version
+       writeU8(os, 0);
+       return os.str();
+}
+
+InventoryItem* FireflySAO::createPickedUpItem()
+{
+       std::istringstream is("CraftItem firefly 1", std::ios_base::binary);
+       InventoryItem *item = InventoryItem::deSerialize(is);
+       return item;
+}
index 030232a9ee05317fc8e0173d1a58984968645041..e5b1223d466c68c54bf221d6ceff5c1beb2dde85 100644 (file)
@@ -113,6 +113,30 @@ private:
        float m_after_jump_timer;
 };
 
+class FireflySAO : public ServerActiveObject
+{
+public:
+       FireflySAO(ServerEnvironment *env, u16 id, v3f pos);
+       u8 getType() const
+               {return ACTIVEOBJECT_TYPE_FIREFLY;}
+       static ServerActiveObject* create(ServerEnvironment *env, u16 id, v3f pos,
+                       const std::string &data);
+       void step(float dtime, bool send_recommended);
+       std::string getClientInitializationData();
+       std::string getStaticData();
+       InventoryItem* createPickedUpItem();
+private:
+       bool m_is_active;
+       IntervalLimiter m_inactive_interval;
+       v3f m_speed_f;
+       v3f m_oldpos;
+       v3f m_last_sent_position;
+       float m_yaw;
+       float m_counter1;
+       float m_counter2;
+       float m_age;
+       bool m_touching_ground;
+};
 
 #endif
 
index cda9eb79a613723e2cf6796fa29349f10b995a57..cbc78ad3f51a70773a17658618fa0e32d5728812 100644 (file)
@@ -70,6 +70,8 @@ void set_default_settings()
        g_settings.setDefault("fast_move", "false");
        g_settings.setDefault("invert_mouse", "false");
        g_settings.setDefault("enable_farmesh", "false");
+       g_settings.setDefault("farmesh_trees", "true");
+       g_settings.setDefault("farmesh_distance", "40");
        g_settings.setDefault("enable_clouds", "true");
        g_settings.setDefault("invisible_stone", "false");
        g_settings.setDefault("screenshot_path", ".");
index d55aa38d172bc96eda77f07c0e217687afa10778..d723696209c32a1cdee54e564ba1018898b416e5 100644 (file)
@@ -543,11 +543,11 @@ void spawnRandomObjects(MapBlock *block)
                {
                        v3s16 p(x0,y0,z0);
                        MapNode n = block->getNodeNoEx(p);
-                       if(n.d == CONTENT_IGNORE)
+                       if(n.getContent() == CONTENT_IGNORE)
                                continue;
-                       if(content_features(n.d).liquid_type != LIQUID_NONE)
+                       if(content_features(n).liquid_type != LIQUID_NONE)
                                continue;
-                       if(content_features(n.d).walkable)
+                       if(content_features(n).walkable)
                        {
                                last_node_walkable = true;
                                continue;
@@ -555,7 +555,7 @@ void spawnRandomObjects(MapBlock *block)
                        if(last_node_walkable)
                        {
                                // If block contains light information
-                               if(content_features(n.d).param_type == CPT_LIGHT)
+                               if(content_features(n).param_type == CPT_LIGHT)
                                {
                                        if(n.getLight(LIGHTBANK_DAY) <= 5)
                                        {
@@ -624,15 +624,15 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
 #if 1
                // Test something:
                // Convert all mud under proper day lighting to grass
-               if(n.d == CONTENT_MUD)
+               if(n.getContent() == CONTENT_MUD)
                {
                        if(dtime_s > 300)
                        {
                                MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
-                               if(content_features(n_top.d).air_equivalent &&
+                               if(content_features(n_top).air_equivalent &&
                                                n_top.getLight(LIGHTBANK_DAY) >= 13)
                                {
-                                       n.d = CONTENT_GRASS;
+                                       n.setContent(CONTENT_GRASS);
                                        m_map->addNodeWithEvent(p, n);
                                }
                        }
@@ -686,9 +686,9 @@ void ServerEnvironment::step(float dtime)
                        v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
                        try{
                                MapNode n = m_map->getNode(bottompos);
-                               if(n.d == CONTENT_GRASS)
+                               if(n.getContent() == CONTENT_GRASS)
                                {
-                                       n.d = CONTENT_GRASS_FOOTSTEPS;
+                                       n.setContent(CONTENT_GRASS_FOOTSTEPS);
                                        m_map->setNode(bottompos, n);
                                }
                        }
@@ -859,15 +859,15 @@ void ServerEnvironment::step(float dtime)
                                        Test something:
                                        Convert mud under proper lighting to grass
                                */
-                               if(n.d == CONTENT_MUD)
+                               if(n.getContent() == CONTENT_MUD)
                                {
                                        if(myrand()%20 == 0)
                                        {
-                                               MapNode n_top = block->getNodeNoEx(p0+v3s16(0,1,0));
-                                               if(content_features(n_top.d).air_equivalent &&
+                                               MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
+                                               if(content_features(n_top).air_equivalent &&
                                                                n_top.getLightBlend(getDayNightRatio()) >= 13)
                                                {
-                                                       n.d = CONTENT_GRASS;
+                                                       n.setContent(CONTENT_GRASS);
                                                        m_map->addNodeWithEvent(p, n);
                                                }
                                        }
@@ -875,15 +875,14 @@ void ServerEnvironment::step(float dtime)
                                /*
                                        Convert grass into mud if under something else than air
                                */
-                               else if(n.d == CONTENT_GRASS)
+                               else if(n.getContent() == 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)
+                                               MapNode n_top = m_map->getNodeNoEx(p+v3s16(0,1,0));
+                        if(content_features(n_top).air_equivalent == false)
                                                {
-                                                       n.d = CONTENT_MUD;
+                                                       n.setContent(CONTENT_MUD);
                                                        m_map->addNodeWithEvent(p, n);
                                                }
                                        }
@@ -976,7 +975,8 @@ void ServerEnvironment::step(float dtime)
                //TestSAO *obj = new TestSAO(this, 0, pos);
                //ServerActiveObject *obj = new ItemSAO(this, 0, pos, "CraftItem Stick 1");
                //ServerActiveObject *obj = new RatSAO(this, 0, pos);
-               ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
+               //ServerActiveObject *obj = new Oerkki1SAO(this, 0, pos);
+               ServerActiveObject *obj = new FireflySAO(this, 0, pos);
                addActiveObject(obj);
        }
 #endif
@@ -1632,9 +1632,9 @@ void ClientEnvironment::step(float dtime)
                        v3s16 bottompos = floatToInt(playerpos + v3f(0,-BS/4,0), BS);
                        try{
                                MapNode n = m_map->getNode(bottompos);
-                               if(n.d == CONTENT_GRASS)
+                               if(n.getContent() == CONTENT_GRASS)
                                {
-                                       n.d = CONTENT_GRASS_FOOTSTEPS;
+                                       n.setContent(CONTENT_GRASS_FOOTSTEPS);
                                        m_map->setNode(bottompos, n);
                                        // Update mesh on client
                                        if(m_map->mapType() == MAPTYPE_CLIENT)
@@ -1873,7 +1873,7 @@ void ClientEnvironment::drawPostFx(video::IVideoDriver* driver, v3f camera_pos)
        v3f pos_f = camera_pos;
        v3s16 p_nodes = floatToInt(pos_f, BS);
        MapNode n = m_map->getNodeNoEx(p_nodes);
-       if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
+       if(n.getContent() == CONTENT_WATER || n.getContent() == CONTENT_WATERSOURCE)
        {
                v2u32 ss = driver->getScreenSize();
                core::rect<s32> rect(0,0, ss.X, ss.Y);
index 8f91e3a1ab4ddc427cf05a3032acb04e16549d1c..2cd92243425c7d3c8a11212ac4288d882d291127 100644 (file)
@@ -70,6 +70,7 @@ FarMesh::FarMesh(
        m_box = core::aabbox3d<f32>(-BS*1000000,-BS*31000,-BS*1000000,
                        BS*1000000,BS*31000,BS*1000000);
 
+    trees = g_settings.getBool("farmesh_trees");
 }
 
 FarMesh::~FarMesh()
@@ -313,12 +314,11 @@ void FarMesh::render()
                                }
                                else
                                {
-                                       /*// Trees if there are over 0.01 trees per MapNode
-                                       if(tree_amount_avg > 0.01)
+                                       // Trees if there are over 0.01 trees per MapNode
+                                       if(trees && tree_amount_avg > 0.01)
                                                c = video::SColor(255,50,128,50);
                                        else
-                                               c = video::SColor(255,107,134,51);*/
-                                       c = video::SColor(255,107,134,51);
+                                               c = video::SColor(255,107,134,51);
                                        ground_is_mud = true;
                                }
                        }
@@ -351,7 +351,7 @@ void FarMesh::render()
                                video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
 
                // Add some trees if appropriate
-               if(tree_amount_avg >= 0.0065 && steepness < 1.4
+               if(trees && tree_amount_avg >= 0.0065 && steepness < 1.4
                                && ground_is_mud == true)
                {
                        driver->setMaterial(m_materials[1]);
@@ -404,11 +404,11 @@ void FarMesh::step(float dtime)
        m_time += dtime;
 }
 
-void FarMesh::update(v2f camera_p, float brightness, s16 render_range)
+void FarMesh::update(v2f camera_p, float brightness)
 {
        m_camera_pos = camera_p;
        m_brightness = brightness;
-       m_render_range = render_range;
+       m_render_range = g_settings.getS16("farmesh_distance")*10;
 }
 
 
index 0a30a8aefe348a000186f6f2213333c65ab13eb3..577224e152bad3ba24a5b7043cca9d4d1e38e96a 100644 (file)
@@ -67,7 +67,7 @@ public:
 
        void step(float dtime);
 
-       void update(v2f camera_p, float brightness, s16 render_range);
+       void update(v2f camera_p, float brightness);
 
 private:
        video::SMaterial m_materials[FARMESH_MATERIAL_COUNT];
@@ -79,6 +79,7 @@ private:
        float m_time;
        Client *m_client;
        s16 m_render_range;
+    bool trees;
 };
 
 #endif
index faadd0fe70a8be168f6b0651a4164519a47b6aa1..b3069d6f98002e617d2c6fc86f6a29b1c8e35054 100644 (file)
@@ -417,7 +417,7 @@ void getPointedNode(Client *client, v3f player_position,
                try
                {
                        n = client->getNode(v3s16(x,y,z));
-                       if(content_pointable(n.d) == false)
+                       if(content_pointable(n.getContent()) == false)
                                continue;
                }
                catch(InvalidPositionException &e)
@@ -442,9 +442,9 @@ void getPointedNode(Client *client, v3f player_position,
                /*
                        Meta-objects
                */
-               if(n.d == CONTENT_TORCH)
+               if(n.getContent() == CONTENT_TORCH)
                {
-                       v3s16 dir = unpackDir(n.dir);
+                       v3s16 dir = unpackDir(n.param2);
                        v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
                        dir_f *= BS/2 - BS/6 - BS/20;
                        v3f cpf = npf + dir_f;
@@ -489,9 +489,9 @@ void getPointedNode(Client *client, v3f player_position,
                                }
                        }
                }
-               else if(n.d == CONTENT_SIGN_WALL)
+               else if(n.getContent() == CONTENT_SIGN_WALL)
                {
-                       v3s16 dir = unpackDir(n.dir);
+                       v3s16 dir = unpackDir(n.param2);
                        v3f dir_f = v3f(dir.X, dir.Y, dir.Z);
                        dir_f *= BS/2 - BS/6 - BS/20;
                        v3f cpf = npf + dir_f;
@@ -538,6 +538,43 @@ void getPointedNode(Client *client, v3f player_position,
                                }
                        }
                }
+               else if(n.getContent() == CONTENT_RAIL)
+               {
+                       v3s16 dir = unpackDir(n.param0);
+                       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
                */
@@ -1001,9 +1038,9 @@ void the_game(
                //bool screensize_changed = screensize != last_screensize;
 
                // Resize hotbar
-               if(screensize.Y <= 600)
+               if(screensize.Y <= 800)
                        hotbar_imagesize = 32;
-               else if(screensize.Y <= 1024)
+               else if(screensize.Y <= 1280)
                        hotbar_imagesize = 48;
                else
                        hotbar_imagesize = 64;
@@ -1722,7 +1759,7 @@ void the_game(
                                        }
 
                                        // Get digging properties for material and tool
-                                       u8 material = n.d;
+                                       content_t material = n.getContent();
                                        DiggingProperties prop =
                                                        getDiggingProperties(material, toolname);
                                        
@@ -1915,15 +1952,9 @@ void the_game(
                */
                if(farmesh)
                {
-                       farmesh_range = draw_control.wanted_range * 10;
-                       if(draw_control.range_all && farmesh_range < 500)
-                               farmesh_range = 500;
-                       if(farmesh_range > 1000)
-                               farmesh_range = 1000;
-
                        farmesh->step(dtime);
                        farmesh->update(v2f(player_position.X, player_position.Z),
-                                       0.05+brightness*0.95, farmesh_range);
+                                       0.05+brightness*0.95);
                }
                
                // Store brightness value
@@ -1990,7 +2021,7 @@ void the_game(
                        endscenetime_avg = endscenetime_avg * 0.95 + (float)endscenetime*0.05;
                        
                        char temptext[300];
-                       snprintf(temptext, 300, "Minetest-c55 %s ("
+                       snprintf(temptext, 300, "Minetest-delta %s ("
                                        "R: range_all=%i"
                                        ")"
                                        " drawtime=%.0f, beginscenetime=%.0f"
diff --git a/src/gettext.h b/src/gettext.h
new file mode 100644 (file)
index 0000000..8ddb953
--- /dev/null
@@ -0,0 +1,19 @@
+#ifdef USE_GETTEXT
+#include <libintl.h>
+#else
+#define gettext(String) String
+#define bindtextdomain(domain, dir) /* */
+#define textdomain(domain) /* */
+#endif
+
+#define _(String) gettext(String)
+#define gettext_noop(String) String
+#define N_(String) gettext_noop (String)
+
+inline wchar_t* chartowchar_t(const char *str)
+{
+       size_t l = strlen(str)+1;
+       wchar_t* nstr = new wchar_t[l];
+       mbstowcs(nstr, str, l);
+       return nstr;
+}
diff --git a/src/guiKeyChangeMenu.cpp b/src/guiKeyChangeMenu.cpp
new file mode 100644 (file)
index 0000000..4a11cf9
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ Minetest-delta
+ Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
+ Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
+ Copyright (C) 2011 teddydestodes <derkomtur@schattengang.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "guiKeyChangeMenu.h"
+#include "debug.h"
+#include "serialization.h"
+#include "keycode.h"
+#include "main.h"
+#include <string>
+
+GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
+               gui::IGUIElement* parent, s32 id, IMenuManager *menumgr) :
+       GUIModalMenu(env, parent, id, menumgr)
+{
+       activeKey = -1;
+       init_keys();
+}
+
+GUIKeyChangeMenu::~GUIKeyChangeMenu()
+{
+       removeChildren();
+}
+
+void GUIKeyChangeMenu::removeChildren()
+{
+       const core::list<gui::IGUIElement*> &children = getChildren();
+       core::list<gui::IGUIElement*> children_copy;
+       for (core::list<gui::IGUIElement*>::ConstIterator i = children.begin(); i
+                       != children.end(); i++)
+       {
+               children_copy.push_back(*i);
+       }
+       for (core::list<gui::IGUIElement*>::Iterator i = children_copy.begin(); i
+                       != children_copy.end(); i++)
+       {
+               (*i)->remove();
+       }
+}
+
+void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
+{
+       /*
+        Remove stuff
+        */
+       removeChildren();
+
+       /*
+        Calculate new sizes and positions
+        */
+
+       v2s32 size(620, 430);
+
+       core::rect < s32 > rect(screensize.X / 2 - size.X / 2,
+                       screensize.Y / 2 - size.Y / 2, screensize.X / 2 + size.X / 2,
+                       screensize.Y / 2 + size.Y / 2);
+
+       DesiredRect = rect;
+       recalculateAbsolutePosition(false);
+
+       v2s32 topleft(0, 0);
+
+       {
+               core::rect < s32 > rect(0, 0, 125, 20);
+               rect += topleft + v2s32(25, 3);
+               const wchar_t *text = L"KEYBINDINGS";
+               //gui::IGUIStaticText *t =
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+       v2s32 offset(25, 40);
+       // buttons
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Forward";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->forward = Environment->addButton(rect, this,
+                               GUI_ID_KEY_FORWARD_BUTTON,
+                               narrow_to_wide(KeyNames[key_forward]).c_str());
+       }
+
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Backward";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->backward = Environment->addButton(rect, this,
+                               GUI_ID_KEY_BACKWARD_BUTTON,
+                               narrow_to_wide(KeyNames[key_backward]).c_str());
+       }
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Left";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->left = Environment->addButton(rect, this, GUI_ID_KEY_LEFT_BUTTON,
+                               narrow_to_wide(KeyNames[key_left]).c_str());
+       }
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Right";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->right = Environment->addButton(rect, this,
+                               GUI_ID_KEY_RIGHT_BUTTON,
+                               narrow_to_wide(KeyNames[key_right]).c_str());
+       }
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Use";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->use = Environment->addButton(rect, this, GUI_ID_KEY_USE_BUTTON,
+                               narrow_to_wide(KeyNames[key_use]).c_str());
+       }
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Sneak";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->sneak = Environment->addButton(rect, this,
+                               GUI_ID_KEY_SNEAK_BUTTON,
+                               narrow_to_wide(KeyNames[key_sneak]).c_str());
+       }
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Jump";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->jump = Environment->addButton(rect, this, GUI_ID_KEY_JUMP_BUTTON,
+                               narrow_to_wide(KeyNames[key_jump]).c_str());
+       }
+
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Inventory";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->inventory = Environment->addButton(rect, this,
+                               GUI_ID_KEY_INVENTORY_BUTTON,
+                               narrow_to_wide(KeyNames[key_inventory]).c_str());
+       }
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Chat";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->chat = Environment->addButton(rect, this, GUI_ID_KEY_CHAT_BUTTON,
+                               narrow_to_wide(KeyNames[key_chat]).c_str());
+       }
+
+       //next col
+       offset = v2s32(250, 40);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Toggle fly";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->fly = Environment->addButton(rect, this, GUI_ID_KEY_FLY_BUTTON,
+                               narrow_to_wide(KeyNames[key_fly]).c_str());
+       }
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Toggle fast";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->fast = Environment->addButton(rect, this, GUI_ID_KEY_FAST_BUTTON,
+                               narrow_to_wide(KeyNames[key_fast]).c_str());
+       }
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Range select";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->range = Environment->addButton(rect, this,
+                               GUI_ID_KEY_RANGE_BUTTON,
+                               narrow_to_wide(KeyNames[key_range]).c_str());
+       }
+
+       offset += v2s32(0, 25);
+       {
+               core::rect < s32 > rect(0, 0, 100, 20);
+               rect += topleft + v2s32(offset.X, offset.Y);
+               const wchar_t *text = L"Print stacks";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+               //t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT);
+       }
+
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(offset.X + 105, offset.Y - 5);
+               this->dump = Environment->addButton(rect, this, GUI_ID_KEY_DUMP_BUTTON,
+                               narrow_to_wide(KeyNames[key_dump]).c_str());
+       }
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(size.X - 100 - 20, size.Y - 40);
+               Environment->addButton(rect, this, GUI_ID_BACK_BUTTON, L"Save");
+       }
+       {
+               core::rect < s32 > rect(0, 0, 100, 30);
+               rect += topleft + v2s32(size.X - 100 - 20 - 100 - 20, size.Y - 40);
+               Environment->addButton(rect, this, GUI_ID_ABORT_BUTTON, L"Cancel");
+       }
+}
+
+void GUIKeyChangeMenu::drawMenu()
+{
+       gui::IGUISkin* skin = Environment->getSkin();
+       if (!skin)
+               return;
+       video::IVideoDriver* driver = Environment->getVideoDriver();
+
+       video::SColor bgcolor(140, 0, 0, 0);
+
+       {
+               core::rect < s32 > rect(0, 0, 620, 620);
+               rect += AbsoluteRect.UpperLeftCorner;
+               driver->draw2DRectangle(bgcolor, rect, &AbsoluteClippingRect);
+       }
+
+       gui::IGUIElement::draw();
+}
+
+bool GUIKeyChangeMenu::acceptInput()
+{
+       g_settings.set("keymap_forward", keycode_to_keyname(key_forward));
+       g_settings.set("keymap_backward", keycode_to_keyname(key_backward));
+       g_settings.set("keymap_left", keycode_to_keyname(key_left));
+       g_settings.set("keymap_right", keycode_to_keyname(key_right));
+       g_settings.set("keymap_jump", keycode_to_keyname(key_jump));
+       g_settings.set("keymap_sneak", keycode_to_keyname(key_sneak));
+       g_settings.set("keymap_inventory", keycode_to_keyname(key_inventory));
+       g_settings.set("keymap_chat", keycode_to_keyname(key_chat));
+       g_settings.set("keymap_rangeselect", keycode_to_keyname(key_range));
+       g_settings.set("keymap_freemove", keycode_to_keyname(key_fly));
+       g_settings.set("keymap_fastmove", keycode_to_keyname(key_fast));
+       g_settings.set("keymap_special1", keycode_to_keyname(key_use));
+       g_settings.set("keymap_print_debug_stacks", keycode_to_keyname(key_dump));
+       clearKeyCache();
+       return true;
+}
+void GUIKeyChangeMenu::init_keys()
+{
+       key_forward = getKeySetting("keymap_forward");
+       key_backward = getKeySetting("keymap_backward");
+       key_left = getKeySetting("keymap_left");
+       key_right = getKeySetting("keymap_right");
+       key_jump = getKeySetting("keymap_jump");
+       key_sneak = getKeySetting("keymap_sneak");
+       key_inventory = getKeySetting("keymap_inventory");
+       key_chat = getKeySetting("keymap_chat");
+       key_range = getKeySetting("keymap_rangeselect");
+       key_fly = getKeySetting("keymap_freemove");
+       key_fast = getKeySetting("keymap_fastmove");
+       key_use = getKeySetting("keymap_special1");
+       key_dump = getKeySetting("keymap_print_debug_stacks");
+}
+
+bool GUIKeyChangeMenu::resetMenu()
+{
+       if (activeKey >= 0)
+       {
+               switch (activeKey)
+               {
+               case GUI_ID_KEY_FORWARD_BUTTON:
+                       this->forward->setText(
+                                       narrow_to_wide(KeyNames[key_forward]).c_str());
+                       break;
+               case GUI_ID_KEY_BACKWARD_BUTTON:
+                       this->backward->setText(
+                                       narrow_to_wide(KeyNames[key_backward]).c_str());
+                       break;
+               case GUI_ID_KEY_LEFT_BUTTON:
+                       this->left->setText(narrow_to_wide(KeyNames[key_left]).c_str());
+                       break;
+               case GUI_ID_KEY_RIGHT_BUTTON:
+                       this->right->setText(narrow_to_wide(KeyNames[key_right]).c_str());
+                       break;
+               case GUI_ID_KEY_JUMP_BUTTON:
+                       this->jump->setText(narrow_to_wide(KeyNames[key_jump]).c_str());
+                       break;
+               case GUI_ID_KEY_SNEAK_BUTTON:
+                       this->sneak->setText(narrow_to_wide(KeyNames[key_sneak]).c_str());
+                       break;
+               case GUI_ID_KEY_INVENTORY_BUTTON:
+                       this->inventory->setText(
+                                       narrow_to_wide(KeyNames[key_inventory]).c_str());
+                       break;
+               case GUI_ID_KEY_CHAT_BUTTON:
+                       this->chat->setText(narrow_to_wide(KeyNames[key_chat]).c_str());
+                       break;
+               case GUI_ID_KEY_RANGE_BUTTON:
+                       this->range->setText(narrow_to_wide(KeyNames[key_range]).c_str());
+                       break;
+               case GUI_ID_KEY_FLY_BUTTON:
+                       this->fly->setText(narrow_to_wide(KeyNames[key_fly]).c_str());
+                       break;
+               case GUI_ID_KEY_FAST_BUTTON:
+                       this->fast->setText(narrow_to_wide(KeyNames[key_fast]).c_str());
+                       break;
+               case GUI_ID_KEY_USE_BUTTON:
+                       this->use->setText(narrow_to_wide(KeyNames[key_use]).c_str());
+                       break;
+               case GUI_ID_KEY_DUMP_BUTTON:
+                       this->dump->setText(narrow_to_wide(KeyNames[key_dump]).c_str());
+                       break;
+               }
+               activeKey = -1;
+               return false;
+       }
+       return true;
+}
+bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
+{
+       if (event.EventType == EET_KEY_INPUT_EVENT && activeKey >= 0
+                       && event.KeyInput.PressedDown)
+       {
+               if (activeKey == GUI_ID_KEY_FORWARD_BUTTON)
+               {
+                       this->forward->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_forward = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_BACKWARD_BUTTON)
+               {
+                       this->backward->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_backward = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_LEFT_BUTTON)
+               {
+                       this->left->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_left = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_RIGHT_BUTTON)
+               {
+                       this->right->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_right = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_JUMP_BUTTON)
+               {
+                       this->jump->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_jump = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_SNEAK_BUTTON)
+               {
+                       this->sneak->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_sneak = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_INVENTORY_BUTTON)
+               {
+                       this->inventory->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_inventory = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_CHAT_BUTTON)
+               {
+                       this->chat->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_chat = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_RANGE_BUTTON)
+               {
+                       this->range->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_range = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_FLY_BUTTON)
+               {
+                       this->fly->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_fly = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_FAST_BUTTON)
+               {
+                       this->fast->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_fast = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_USE_BUTTON)
+               {
+                       this->use->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_use = event.KeyInput.Key;
+               }
+               else if (activeKey == GUI_ID_KEY_DUMP_BUTTON)
+               {
+                       this->dump->setText(
+                                       narrow_to_wide(KeyNames[event.KeyInput.Key]).c_str());
+                       this->key_dump = event.KeyInput.Key;
+               }
+
+               activeKey = -1;
+               return true;
+       }
+       if (event.EventType == EET_GUI_EVENT)
+       {
+               if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST
+                               && isVisible())
+               {
+                       if (!canTakeFocus(event.GUIEvent.Element))
+                       {
+                               dstream << "GUIMainMenu: Not allowing focus change."
+                                               << std::endl;
+                               // Returning true disables focus change
+                               return true;
+                       }
+               }
+               if (event.GUIEvent.EventType == gui::EGET_BUTTON_CLICKED)
+               {
+                       switch (event.GUIEvent.Caller->getID())
+                       {
+                       case GUI_ID_BACK_BUTTON: //back
+                               acceptInput();
+                               quitMenu();
+                               return true;
+                       case GUI_ID_ABORT_BUTTON: //abort
+                               quitMenu();
+                               return true;
+                       case GUI_ID_KEY_FORWARD_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->forward->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_BACKWARD_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->backward->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_LEFT_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->left->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_RIGHT_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->right->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_USE_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->use->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_FLY_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->fly->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_FAST_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->fast->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_JUMP_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->jump->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_CHAT_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->chat->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_SNEAK_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->sneak->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_INVENTORY_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->inventory->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_DUMP_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->dump->setText(L"press Key");
+                               break;
+                       case GUI_ID_KEY_RANGE_BUTTON:
+                               resetMenu();
+                               activeKey = event.GUIEvent.Caller->getID();
+                               this->range->setText(L"press Key");
+                               break;
+                       }
+                       //Buttons
+
+               }
+       }
+       return Parent ? Parent->OnEvent(event) : false;
+}
+
diff --git a/src/guiKeyChangeMenu.h b/src/guiKeyChangeMenu.h
new file mode 100644 (file)
index 0000000..389ce7a
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ Minetest-delta
+ Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
+ Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
+ Copyright (C) 2011 teddydestodes <derkomtur@schattengang.net>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef GUIKEYCHANGEMENU_HEADER
+#define GUIKEYCHANGEMENU_HEADER
+
+#include "common_irrlicht.h"
+#include "utility.h"
+#include "modalMenu.h"
+#include "client.h"
+#include <string>
+
+static const char *KeyNames[] =
+       { "-", "Left Button", "Right Button", "Cancel", "Middle Button", "X Button 1",
+                       "X Button 2", "-", "Back", "Tab", "-", "-", "Clear", "Return", "-",
+                       "-", "Shift", "Control", "Menu", "Pause", "Capital", "Kana", "-",
+                       "Junja", "Final", "Kanji", "-", "Escape", "Convert", "Nonconvert",
+                       "Accept", "Mode Change", "Space", "Priot", "Next", "End", "Home",
+                       "Left", "Up", "Right", "Down", "Select", "Print", "Execute",
+                       "Snapshot", "Insert", "Delete", "Help", "0", "1", "2", "3", "4", "5",
+                       "6", "7", "8", "9", "-", "-", "-", "-", "-", "-", "-", "A", "B", "C",
+                       "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
+                       "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "Left Windows",
+                       "Right Windows", "Apps", "-", "Sleep", "Numpad 0", "Numpad 1",
+                       "Numpad 2", "Numpad 3", "Numpad 4", "Numpad 5", "Numpad 6", "Numpad 7",
+                       "Numpad 8", "Numpad 9", "Numpad *", "Numpad +", "Numpad /", "Numpad -",
+                       "Numpad .", "Numpad /", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8",
+                       "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18",
+                       "F19", "F20", "F21", "F22", "F23", "F24", "-", "-", "-", "-", "-", "-",
+                       "-", "-", "Num Lock", "Scroll Lock", "-", "-", "-", "-", "-", "-", "-",
+                       "-", "-", "-", "-", "-", "-", "-", "Left Shift", "Right Shight",
+                       "Left Control", "Right Control", "Left Menu", "Right Menu", "-", "-",
+                       "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-",
+                       "-", "-", "-", "-", "-", "Plus", "Comma", "Minus", "Period", "-", "-",
+                       "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-",
+                       "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-",
+                       "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-",
+                       "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "Attn", "CrSel",
+                       "ExSel", "Erase OEF", "Play", "Zoom", "PA1", "OEM Clear", "-" };
+       enum
+       {
+               GUI_ID_BACK_BUTTON = 101, GUI_ID_ABORT_BUTTON, GUI_ID_SCROLL_BAR,
+               //buttons
+               GUI_ID_KEY_FORWARD_BUTTON,
+               GUI_ID_KEY_BACKWARD_BUTTON,
+               GUI_ID_KEY_LEFT_BUTTON,
+               GUI_ID_KEY_RIGHT_BUTTON,
+               GUI_ID_KEY_USE_BUTTON,
+               GUI_ID_KEY_FLY_BUTTON,
+               GUI_ID_KEY_FAST_BUTTON,
+               GUI_ID_KEY_JUMP_BUTTON,
+               GUI_ID_KEY_CHAT_BUTTON,
+               GUI_ID_KEY_SNEAK_BUTTON,
+               GUI_ID_KEY_INVENTORY_BUTTON,
+               GUI_ID_KEY_DUMP_BUTTON,
+               GUI_ID_KEY_RANGE_BUTTON
+       };
+
+class GUIKeyChangeMenu: public GUIModalMenu
+{
+public:
+       GUIKeyChangeMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent,
+                       s32 id, IMenuManager *menumgr);
+       ~GUIKeyChangeMenu();
+
+       void removeChildren();
+       /*
+        Remove and re-add (or reposition) stuff
+        */
+       void regenerateGui(v2u32 screensize);
+
+       void drawMenu();
+
+       bool acceptInput();
+
+       bool OnEvent(const SEvent& event);
+
+private:
+
+       void init_keys();
+
+       bool resetMenu();
+
+       gui::IGUIButton *forward;
+       gui::IGUIButton *backward;
+       gui::IGUIButton *left;
+       gui::IGUIButton *right;
+       gui::IGUIButton *use;
+       gui::IGUIButton *sneak;
+       gui::IGUIButton *jump;
+       gui::IGUIButton *inventory;
+       gui::IGUIButton *fly;
+       gui::IGUIButton *fast;
+       gui::IGUIButton *range;
+       gui::IGUIButton *dump;
+       gui::IGUIButton *chat;
+
+       u32 activeKey;
+       u32 key_forward;
+       u32 key_backward;
+       u32 key_left;
+       u32 key_right;
+       u32 key_use;
+       u32 key_sneak;
+       u32 key_jump;
+       u32 key_inventory;
+       u32 key_fly;
+       u32 key_fast;
+       u32 key_range;
+       u32 key_chat;
+       u32 key_dump;
+};
+
+#endif
+
index ef0a013f14e850403e5be8b65332d0426e01943a..1d7f224f614fa3bf3af6be185414f09fbd7f85f5 100644 (file)
@@ -18,10 +18,15 @@ 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 <string>
 
+
+
+#include "gettext.h"
+
 GUIMainMenu::GUIMainMenu(gui::IGUIEnvironment* env,
                gui::IGUIElement* parent, s32 id,
                IMenuManager *menumgr,
@@ -34,6 +39,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 +79,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 +116,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
@@ -168,14 +177,14 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
        {
                core::rect<s32> rect(0, 0, 110, 20);
                rect += topleft_client + v2s32(35, 50+6);
-               const wchar_t *text = L"Name/Password";
-               Environment->addStaticText(text, rect, false, true, this, -1);
+               Environment->addStaticText(chartowchar_t(gettext("Name/Password")), 
+                       rect, false, true, this, -1);
        }
        {
                core::rect<s32> 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);
        }
@@ -191,14 +200,14 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
        {
                core::rect<s32> rect(0, 0, 110, 20);
                rect += topleft_client + v2s32(35, 100+6);
-               const wchar_t *text = L"Address/Port";
-               Environment->addStaticText(text, rect, false, true, this, -1);
+               Environment->addStaticText(chartowchar_t(gettext("Address/Port")),
+                       rect, false, true, this, -1);
        }
        {
                core::rect<s32> 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,34 +215,43 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
                core::rect<s32> 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<s32> rect(0, 0, 400, 20);
                rect += topleft_client + v2s32(160, 100+35);
-               const wchar_t *text = L"Leave address blank to start a local server.";
-               Environment->addStaticText(text, rect, false, true, this, -1);
+               Environment->addStaticText(chartowchar_t(gettext("Leave address blank to start a local server.")),
+                       rect, false, true, this, -1);
        }
        {
                core::rect<s32> rect(0, 0, 250, 30);
                rect += topleft_client + v2s32(35, 150);
-               Environment->addCheckBox(fancy_trees, rect, this, 263,
-                               L"Fancy trees");
+               Environment->addCheckBox(fancy_trees, rect, this, GUI_ID_FANCYTREE_CB,
+                       chartowchar_t(gettext("Fancy trees"))); 
        }
        {
                core::rect<s32> rect(0, 0, 250, 30);
                rect += topleft_client + v2s32(35, 150+30);
-               Environment->addCheckBox(smooth_lighting, rect, this, 262,
-                               L"Smooth Lighting");
+               Environment->addCheckBox(smooth_lighting, rect, this, GUI_ID_SMOOTH_LIGHTING_CB,
+                               chartowchar_t(gettext("Smooth Lighting")));
        }
        // Start game button
        {
                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-180-40, 150+25);
-               Environment->addButton(rect, this, 257, L"Start Game / Connect");
+               Environment->addButton(rect, this, GUI_ID_JOIN_GAME_BUTTON,
+                       chartowchar_t(gettext("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,
+                       chartowchar_t(gettext("Change keys")));
+       }
        /*
                Server section
        */
@@ -254,19 +272,22 @@ void GUIMainMenu::regenerateGui(v2u32 screensize)
        {
                core::rect<s32> 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,
+                       chartowchar_t(gettext("Creative Mode")));
        }
        {
                core::rect<s32> 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,
+                       chartowchar_t(gettext("Enable Damage")));
        }
        // Map delete button
        {
                core::rect<s32> 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,
+                         chartowchar_t(gettext("Delete map")));
        }
 }
 
@@ -300,7 +321,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 +331,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 +398,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 +419,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;
index edd519024fb6a56879538d6cf144183f92f4c18b..87561f7974fd075dd4bea9c6fc440a5470fffcfb 100644 (file)
@@ -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
index 192911355151a7afdf7fe4a672798fa712d10571..155be6029c8b0f08174a121e8bb50c4d44617853 100644 (file)
@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serialization.h"
 #include <string>
 
+#include "gettext.h"
+
 GUIMessageMenu::GUIMessageMenu(gui::IGUIEnvironment* env,
                gui::IGUIElement* parent, s32 id,
                IMenuManager *menumgr,
@@ -87,7 +89,8 @@ void GUIMessageMenu::regenerateGui(v2u32 screensize)
                core::rect<s32> rect(0, 0, 140, 30);
                rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+25);
                gui::IGUIElement *e = 
-               Environment->addButton(rect, this, 257, L"Proceed");
+               Environment->addButton(rect, this, 257,
+                       chartowchar_t(gettext("Proceed")));
                Environment->setFocus(e);
        }
 }
index ec1cd029ab321165df02086198bc0b71240316b1..fabe7511013d8ccd56394c1626859793b4a19d3e 100644 (file)
@@ -21,6 +21,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 #include "serialization.h"
 #include <string>
 
+#include "gettext.h"
+
 const int ID_oldPassword = 256;
 const int ID_newPassword1 = 257;
 const int ID_newPassword2 = 258;
@@ -97,8 +99,8 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
        {
                core::rect<s32> rect(0, 0, 110, 20);
                rect += topleft_client + v2s32(35, ypos+6);
-               const wchar_t *text = L"Old Password";
-               Environment->addStaticText(text, rect, false, true, this, -1);
+               Environment->addStaticText(chartowchar_t(gettext("Old Password")),
+                       rect, false, true, this, -1);
        }
        {
                core::rect<s32> rect(0, 0, 230, 30);
@@ -112,8 +114,8 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
        {
                core::rect<s32> rect(0, 0, 110, 20);
                rect += topleft_client + v2s32(35, ypos+6);
-               const wchar_t *text = L"New Password";
-               Environment->addStaticText(text, rect, false, true, this, -1);
+               Environment->addStaticText(chartowchar_t(gettext("New Password")),
+                       rect, false, true, this, -1);
        }
        {
                core::rect<s32> rect(0, 0, 230, 30);
@@ -126,8 +128,8 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
        {
                core::rect<s32> rect(0, 0, 110, 20);
                rect += topleft_client + v2s32(35, ypos+6);
-               const wchar_t *text = L"Confirm Password";
-               Environment->addStaticText(text, rect, false, true, this, -1);
+               Environment->addStaticText(chartowchar_t(gettext("Confirm Password")),
+                       rect, false, true, this, -1);
        }
        {
                core::rect<s32> rect(0, 0, 230, 30);
@@ -141,16 +143,17 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
        {
                core::rect<s32> rect(0, 0, 140, 30);
                rect = rect + v2s32(size.X/2-140/2, ypos);
-               Environment->addButton(rect, this, ID_change, L"Change");
+               Environment->addButton(rect, this, ID_change, chartowchar_t(gettext("Change")));
        }
 
        ypos += 50;
        {
                core::rect<s32> rect(0, 0, 300, 20);
                rect += topleft_client + v2s32(35, ypos);
-               const wchar_t *text = L"Passwords do not match!";
                IGUIElement *e = 
-               Environment->addStaticText(text, rect, false, true, this, ID_message);
+               Environment->addStaticText(
+                       chartowchar_t(gettext("Passwords do not match!")),
+                       rect, false, true, this, ID_message);
                e->setVisible(false);
        }
 
index d32d1a10b375024d48fd9de457c695ef3956b110..c10bcf0398c130caa68eff6802c19a0ec1742708 100644 (file)
@@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "config.h"\r
 #include "main.h"\r
 \r
+#include "gettext.h"\r
+\r
 GUIPauseMenu::GUIPauseMenu(gui::IGUIEnvironment* env,\r
                gui::IGUIElement* parent, s32 id,\r
                IGameCallback *gamecallback,\r
@@ -104,43 +106,47 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
        {\r
                core::rect<s32> rect(0, 0, 140, btn_height);\r
                rect = rect + v2s32(size.X/2-140/2, btn_y);\r
-               Environment->addButton(rect, this, 256, L"Continue");\r
+               Environment->addButton(rect, this, 256,\r
+                       chartowchar_t(gettext("Continue")));\r
        }\r
        btn_y += btn_height + btn_gap;\r
        {\r
                core::rect<s32> rect(0, 0, 140, btn_height);\r
                rect = rect + v2s32(size.X/2-140/2, btn_y);\r
-               Environment->addButton(rect, this, 261, L"Change Password");\r
+               Environment->addButton(rect, this, 261,\r
+                       chartowchar_t(gettext("Change Password")));\r
        }\r
        btn_y += btn_height + btn_gap;\r
        {\r
                core::rect<s32> rect(0, 0, 140, btn_height);\r
                rect = rect + v2s32(size.X/2-140/2, btn_y);\r
-               Environment->addButton(rect, this, 260, L"Disconnect");\r
+               Environment->addButton(rect, this, 260,\r
+                       chartowchar_t(gettext("Disconnect")));\r
        }\r
        btn_y += btn_height + btn_gap;\r
        {\r
                core::rect<s32> rect(0, 0, 140, btn_height);\r
                rect = rect + v2s32(size.X/2-140/2, btn_y);\r
-               Environment->addButton(rect, this, 257, L"Exit to OS");\r
+               Environment->addButton(rect, this, 257,\r
+                       chartowchar_t(gettext("Exit to OS")));\r
        }\r
 \r
        {\r
                core::rect<s32> rect(0, 0, 180, 240);\r
                rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2);\r
-               const wchar_t *text =\r
-               L"Keys:\n"\r
-               L"- WASD: Walk\n"\r
-               L"- Mouse left: dig blocks\n"\r
-               L"- Mouse right: place blocks\n"\r
-               L"- Mouse wheel: select item\n"\r
-               L"- 0...9: select item\n"\r
-               L"- Shift: sneak\n"\r
-               L"- R: Toggle viewing all loaded chunks\n"\r
-               L"- I: Inventory menu\n"\r
-               L"- ESC: This menu\n"\r
-               L"- T: Chat\n";\r
-               Environment->addStaticText(text, rect, false, true, this, 258);\r
+               Environment->addStaticText(chartowchar_t(gettext(\r
+               "Keys:\n"\r
+               "- WASD: Walk\n"\r
+               "- Mouse left: dig blocks\n"\r
+               "- Mouse right: place blocks\n"\r
+               "- Mouse wheel: select item\n"\r
+               "- 0...9: select item\n"\r
+               "- Shift: sneak\n"\r
+               "- R: Toggle viewing all loaded chunks\n"\r
+               "- I: Inventory menu\n"\r
+               "- ESC: This menu\n"\r
+               "- T: Chat\n"\r
+               )), rect, false, true, this, 258);\r
        }\r
        {\r
                core::rect<s32> rect(0, 0, 180, 220);\r
@@ -167,7 +173,7 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
 \r
                std::ostringstream os;\r
                os<<"Minetest-c55\n";\r
-               os<<"by Perttu Ahola\n";\r
+               os<<"by Perttu Ahola and contributors\n";\r
                os<<"celeron55@gmail.com\n";\r
                os<<BUILD_INFO<<"\n";\r
                os<<"ud_path = "<<wrap_rows(porting::path_userdata, 20)<<"\n";\r
index 2cb8cae6295b3e5417989408d650d959986e10b3..252e452f5d30f690c86c24abd2340b51c506c613 100644 (file)
@@ -22,6 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serialization.h"
 #include <string>
 
+#include "gettext.h"
+
 GUITextInputMenu::GUITextInputMenu(gui::IGUIEnvironment* env,
                gui::IGUIElement* parent, s32 id,
                IMenuManager *menumgr,
@@ -105,7 +107,8 @@ void GUITextInputMenu::regenerateGui(v2u32 screensize)
        {
                core::rect<s32> rect(0, 0, 140, 30);
                rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+25);
-               Environment->addButton(rect, this, 257, L"Proceed");
+               Environment->addButton(rect, this, 257,
+                       chartowchar_t(gettext("Proceed")));
        }
 }
 
index fec51a759e581617db89f43eef9bb494ef82f949..7ef7f0138ab89a88b53929cb98e05d81b5d0838e 100644 (file)
@@ -61,7 +61,7 @@ InventoryItem* InventoryItem::deSerialize(std::istream &is)
                is>>material;
                u16 count;
                is>>count;
-               if(material > 255)
+               if(material > MAX_CONTENT)
                        throw SerializationError("Too large material number");
                return new MaterialItem(material, count);
        }
index 07d81a3f7eecb77c8575616bd87a763d447357f4..5c64f89bb20e9bb65fe084da289493fb7309f08a 100644 (file)
@@ -30,8 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "common_irrlicht.h"
 #include "debug.h"
 #include "mapblockobject.h"
-// For g_materials
-#include "main.h"
+#include "main.h" // For g_materials
+#include "mapnode.h" // For content_t
 
 #define QUANTITY_ITEM_MAX_COUNT 99
 
@@ -113,7 +113,7 @@ protected:
 class MaterialItem : public InventoryItem
 {
 public:
-       MaterialItem(u8 content, u16 count):
+       MaterialItem(content_t content, u16 count):
                InventoryItem(count)
        {
                m_content = content;
@@ -175,12 +175,12 @@ public:
        /*
                Special methods
        */
-       u8 getMaterial()
+       content_t getMaterial()
        {
                return m_content;
        }
 private:
-       u8 m_content;
+       content_t m_content;
 };
 
 //TODO: Remove
index ad3c0b4018bf074dabf120eb5bb18f479fe50fe8..d6472d2eaa7e0e780f4dc42ecca7ed02fc9ad2f1 100644 (file)
@@ -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,8 @@ irr::EKEY_CODE getKeySetting(const char *settingname)
        return c;
 }
 
+void clearKeyCache()
+{
+       g_key_setting_cache.clear();
+}
 
index f19fe344282c77c8f999b2ddffe7cbb286a9d38b..300682b121d7fded978b9638bdfebde227b46bfe 100644 (file)
@@ -21,11 +21,16 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define KEYCODE_HEADER
 
 #include "common_irrlicht.h"
+#include <string>
 
 irr::EKEY_CODE keyname_to_keycode(const char *name);
+std::string keycode_to_keyname(s32 keycode);
 
 // Key configuration getter
 irr::EKEY_CODE getKeySetting(const char *settingname);
 
+// Clear fast lookup cache
+void clearKeyCache();
+
 #endif
 
index 698c5fc712d416b8c1317d80ba84561e98118243..3bc7ca5f6a7cd126be56823582c91d17a562f75f 100644 (file)
-/*\r
-Minetest-c55\r
-Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>\r
-\r
-This program is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-This program is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License along\r
-with this program; if not, write to the Free Software Foundation, Inc.,\r
-51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
-*/\r
-\r
-/*\r
-=============================== NOTES ==============================\r
-NOTE: Things starting with TODO are sometimes only suggestions.\r
-\r
-NOTE: iostream.imbue(std::locale("C")) is very slow\r
-NOTE: Global locale is now set at initialization\r
-\r
-NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the\r
-      hardware buffer (it is not freed automatically)\r
-\r
-NOTE: A random to-do list saved here as documentation:\r
-A list of "active blocks" in which stuff happens. (+=done)\r
-       + Add a never-resetted game timer to the server\r
-       + Add a timestamp value to blocks\r
-       + The simple rule: All blocks near some player are "active"\r
-       - Do stuff in real time in active blocks\r
-               + Handle objects\r
-               - Grow grass, delete leaves without a tree\r
-               - Spawn some mobs based on some rules\r
-               - Transform cobble to mossy cobble near water\r
-               - Run a custom script\r
-               - ...And all kinds of other dynamic stuff\r
-       + Keep track of when a block becomes active and becomes inactive\r
-       + When a block goes inactive:\r
-               + Store objects statically to block\r
-               + Store timer value as the timestamp\r
-       + When a block goes active:\r
-               + Create active objects out of static objects\r
-               - Simulate the results of what would have happened if it would have\r
-                 been active for all the time\r
-                       - Grow a lot of grass and so on\r
-       + Initially it is fine to send information about every active object\r
-         to every player. Eventually it should be modified to only send info\r
-         about the nearest ones.\r
-               + This was left to be done by the old system and it sends only the\r
-                 nearest ones.\r
-\r
-Old, wild and random suggestions that probably won't be done:\r
--------------------------------------------------------------\r
-\r
-SUGG: If player is on ground, mainly fetch ground-level blocks\r
-\r
-SUGG: Expose Connection's seqnums and ACKs to server and client.\r
-      - This enables saving many packets and making a faster connection\r
-         - This also enables server to check if client has received the\r
-           most recent block sent, for example.\r
-SUGG: Add a sane bandwidth throttling system to Connection\r
-\r
-SUGG: More fine-grained control of client's dumping of blocks from\r
-      memory\r
-         - ...What does this mean in the first place?\r
-\r
-SUGG: A map editing mode (similar to dedicated server mode)\r
-\r
-SUGG: Transfer more blocks in a single packet\r
-SUGG: A blockdata combiner class, to which blocks are added and at\r
-      destruction it sends all the stuff in as few packets as possible.\r
-SUGG: Make a PACKET_COMBINED which contains many subpackets. Utilize\r
-      it by sending more stuff in a single packet.\r
-         - Add a packet queue to RemoteClient, from which packets will be\r
-           combined with object data packets\r
-               - This is not exactly trivial: the object data packets are\r
-                 sometimes very big by themselves\r
-         - This might not give much network performance gain though.\r
-\r
-SUGG: Precalculate lighting translation table at runtime (at startup)\r
-      - This is not doable because it is currently hand-made and not\r
-           based on some mathematical function.\r
-               - Note: This has been changing lately\r
-\r
-SUGG: A version number to blocks, which increments when the block is\r
-      modified (node add/remove, water update, lighting update)\r
-         - This can then be used to make sure the most recent version of\r
-           a block has been sent to client, for example\r
-\r
-SUGG: Make the amount of blocks sending to client and the total\r
-         amount of blocks dynamically limited. Transferring blocks is the\r
-         main network eater of this system, so it is the one that has\r
-         to be throttled so that RTTs stay low.\r
-\r
-SUGG: Meshes of blocks could be split into 6 meshes facing into\r
-      different directions and then only those drawn that need to be\r
-\r
-SUGG: Background music based on cellular automata?\r
-      http://www.earslap.com/projectslab/otomata\r
-\r
-SUGG: Simple light color information to air\r
-\r
-SUGG: Server-side objects could be moved based on nodes to enable very\r
-      lightweight operation and simple AI\r
-       - Not practical; client would still need to show smooth movement.\r
-\r
-SUGG: Make a system for pregenerating quick information for mapblocks, so\r
-         that the client can show them as cubes before they are actually sent\r
-         or even generated.\r
-\r
-SUGG: Erosion simulation at map generation time\r
-    - This might be plausible if larger areas of map were pregenerated\r
-         without lighting (which is slow)\r
-       - Simulate water flows, which would carve out dirt fast and\r
-         then turn stone into gravel and sand and relocate it.\r
-       - How about relocating minerals, too? Coal and gold in\r
-         downstream sand and gravel would be kind of cool\r
-         - This would need a better way of handling minerals, mainly\r
-               to have mineral content as a separate field. the first\r
-               parameter field is free for this.\r
-       - Simulate rock falling from cliffs when water has removed\r
-         enough solid rock from the bottom\r
-\r
-SUGG: For non-mapgen FarMesh: Add a per-sector database to store surface\r
-      stuff as simple flags/values\r
-      - Light?\r
-         - A building?\r
-         And at some point make the server send this data to the client too,\r
-         instead of referring to the noise functions\r
-         - Ground height\r
-         - Surface ground type\r
-         - Trees?\r
-\r
-Gaming ideas:\r
--------------\r
-\r
-- Aim for something like controlling a single dwarf in Dwarf Fortress\r
-- The player could go faster by a crafting a boat, or riding an animal\r
-- Random NPC traders. what else?\r
-\r
-Game content:\r
--------------\r
-\r
-- When furnace is destroyed, move items to player's inventory\r
-- Add lots of stuff\r
-- Glass blocks\r
-- Growing grass, decaying leaves\r
-       - This can be done in the active blocks I guess.\r
-       - Lots of stuff can be done in the active blocks.\r
-       - Uh, is there an active block list somewhere? I think not. Add it.\r
-- Breaking weak structures\r
-       - This can probably be accomplished in the same way as grass\r
-- Player health points\r
-       - When player dies, throw items on map (needs better item-on-map\r
-         implementation)\r
-- Cobble to get mossy if near water\r
-- More slots in furnace source list, so that multiple ingredients\r
-  are possible.\r
-- Keys to chests?\r
-\r
-- The Treasure Guard; a big monster with a hammer\r
-       - The hammer does great damage, shakes the ground and removes a block\r
-       - You can drop on top of it, and have some time to attack there\r
-         before he shakes you off\r
-\r
-- Maybe the difficulty could come from monsters getting tougher in\r
-  far-away places, and the player starting to need something from\r
-  there when time goes by.\r
-  - The player would have some of that stuff at the beginning, and\r
-    would need new supplies of it when it runs out\r
-\r
-- A bomb\r
-- A spread-items-on-map routine for the bomb, and for dying players\r
-\r
-- Fighting:\r
-  - Proper sword swing simulation\r
-  - Player should get damage from colliding to a wall at high speed\r
-\r
-Documentation:\r
---------------\r
-\r
-Build system / running:\r
------------------------\r
-\r
-Networking and serialization:\r
------------------------------\r
-\r
-SUGG: Fix address to be ipv6 compatible\r
-\r
-User Interface:\r
----------------\r
-\r
-Graphics:\r
----------\r
-\r
-SUGG: Combine MapBlock's face caches to so big pieces that VBO\r
-      can be used\r
-      - That is >500 vertices\r
-         - This is not easy; all the MapBlocks close to the player would\r
-           still need to be drawn separately and combining the blocks\r
-               would have to happen in a background thread\r
-\r
-SUGG: Make fetching sector's blocks more efficient when rendering\r
-      sectors that have very large amounts of blocks (on client)\r
-         - Is this necessary at all?\r
-\r
-SUGG: Draw cubes in inventory directly with 3D drawing commands, so that\r
-      animating them is easier.\r
-\r
-SUGG: Option for enabling proper alpha channel for textures\r
-\r
-TODO: Flowing water animation\r
-\r
-TODO: A setting for enabling bilinear filtering for textures\r
-\r
-TODO: Better control of draw_control.wanted_max_blocks\r
-\r
-TODO: Further investigate the use of GPU lighting in addition to the\r
-      current one\r
-\r
-TODO: Artificial (night) light could be more yellow colored than sunlight.\r
-      - This is technically doable.\r
-         - Also the actual colors of the textures could be made less colorful\r
-           in the dark but it's a bit more difficult.\r
-\r
-SUGG: Somehow make the night less colorful\r
-\r
-TODO: Occlusion culling\r
-      - At the same time, move some of the renderMap() block choosing code\r
-        to the same place as where the new culling happens.\r
-      - Shoot some rays per frame and when ready, make a new list of\r
-           blocks for usage of renderMap and give it a new pointer to it.\r
-\r
-Configuration:\r
---------------\r
-\r
-Client:\r
--------\r
-\r
-TODO: Untie client network operations from framerate\r
-      - Needs some input queues or something\r
-         - This won't give much performance boost because calculating block\r
-           meshes takes so long\r
-\r
-SUGG: Make morning and evening transition more smooth and maybe shorter\r
-\r
-TODO: Don't update all meshes always on single node changes, but\r
-      check which ones should be updated\r
-         - implement Map::updateNodeMeshes() and the usage of it\r
-         - It will give almost always a 4x boost in mesh update performance.\r
-\r
-- A weapon engine\r
-\r
-- Tool/weapon visualization\r
-\r
-FIXME: When disconnected to the menu, memory is not freed properly\r
-\r
-TODO: Investigate how much the mesh generator thread gets used when\r
-      transferring map data\r
-\r
-Server:\r
--------\r
-\r
-SUGG: Make an option to the server to disable building and digging near\r
-      the starting position\r
-\r
-FIXME: Server sometimes goes into some infinite PeerNotFoundException loop\r
-\r
-* Fix the problem with the server constantly saving one or a few\r
-  blocks? List the first saved block, maybe it explains.\r
-  - It is probably caused by oscillating water\r
-  - TODO: Investigate if this still happens (this is a very old one)\r
-* Make a small history check to transformLiquids to detect and log\r
-  continuous oscillations, in such detail that they can be fixed.\r
-\r
-FIXME: The new optimized map sending doesn't sometimes send enough blocks\r
-       from big caves and such\r
-FIXME: Block send distance configuration does not take effect for some reason\r
-\r
-Environment:\r
-------------\r
-\r
-TODO: Add proper hooks to when adding and removing active blocks\r
-\r
-TODO: Finish the ActiveBlockModifier stuff and use it for something\r
-\r
-Objects:\r
---------\r
-\r
-TODO: Get rid of MapBlockObjects and use only ActiveObjects\r
-       - Skipping the MapBlockObject data is nasty - there is no "total\r
-         length" stored; have to make a SkipMBOs function which contains\r
-         enough of the current code to skip them properly.\r
-\r
-SUGG: MovingObject::move and Player::move are basically the same.\r
-      combine them.\r
-       - NOTE: This is a bit tricky because player has the sneaking ability\r
-       - NOTE: Player::move is more up-to-date.\r
-       - NOTE: There is a simple move implementation now in collision.{h,cpp}\r
-       - NOTE: MovingObject will be deleted (MapBlockObject)\r
-\r
-TODO: Add a long step function to objects that is called with the time\r
-      difference when block activates\r
-\r
-Map:\r
-----\r
-\r
-TODO: Mineral and ground material properties\r
-      - This way mineral ground toughness can be calculated with just\r
-           some formula, as well as tool strengths\r
-         - There are TODOs in appropriate files: material.h, content_mapnode.h\r
-\r
-TODO: Flowing water to actually contain flow direction information\r
-      - There is a space for this - it just has to be implemented.\r
-\r
-TODO: Consider smoothening cave floors after generating them\r
-\r
-Misc. stuff:\r
-------------\r
-TODO: Make sure server handles removing grass when a block is placed (etc)\r
-      - The client should not do it by itself\r
-         - NOTE: I think nobody does it currently...\r
-TODO: Block cube placement around player's head\r
-TODO: Protocol version field\r
-TODO: Think about using same bits for material for fences and doors, for\r
-         example\r
-TODO: Move mineral to param2, increment map serialization version, add\r
-      conversion\r
-\r
-TODO: Restart irrlicht completely when coming back to main menu from game.\r
-       - This gets rid of everything that is stored in irrlicht's caches.\r
-\r
-TODO: Merge bahamada's audio stuff (clean patch available)\r
-\r
-TODO: Merge key configuration menu (no clean patch available)\r
-\r
-Making it more portable:\r
-------------------------\r
\r
-Stuff to do before release:\r
----------------------------\r
-\r
-Fixes to the current release:\r
------------------------------\r
-\r
-Stuff to do after release:\r
----------------------------\r
-\r
-Doing currently:\r
-----------------\r
-\r
-======================================================================\r
-\r
-*/\r
-\r
-#ifdef NDEBUG\r
-       #ifdef _WIN32\r
-               #pragma message ("Disabling unit tests")\r
-       #else\r
-               #warning "Disabling unit tests"\r
-       #endif\r
-       // Disable unit tests\r
-       #define ENABLE_TESTS 0\r
-#else\r
-       // Enable unit tests\r
-       #define ENABLE_TESTS 1\r
-#endif\r
-\r
-#ifdef _MSC_VER\r
-       #pragma comment(lib, "Irrlicht.lib")\r
-       //#pragma comment(lib, "jthread.lib")\r
-       #pragma comment(lib, "zlibwapi.lib")\r
-       #pragma comment(lib, "Shell32.lib")\r
-       // This would get rid of the console window\r
-       //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")\r
-#endif\r
-\r
-#include <iostream>\r
-#include <fstream>\r
-#include <locale.h>\r
-#include "main.h"\r
-#include "common_irrlicht.h"\r
-#include "debug.h"\r
-#include "test.h"\r
-#include "server.h"\r
-#include "constants.h"\r
-#include "porting.h"\r
-#include "gettime.h"\r
-#include "guiMessageMenu.h"\r
-#include "filesys.h"\r
-#include "config.h"\r
-#include "guiMainMenu.h"\r
-#include "mineral.h"\r
-#include "materials.h"\r
-#include "game.h"\r
-#include "keycode.h"\r
-#include "tile.h"\r
-\r
-// This makes textures\r
-ITextureSource *g_texturesource = NULL;\r
-\r
-/*\r
-       Settings.\r
-       These are loaded from the config file.\r
-*/\r
-\r
-Settings g_settings;\r
-// This is located in defaultsettings.cpp\r
-extern void set_default_settings();\r
-\r
-// Global profiler\r
-Profiler g_profiler;\r
-\r
-/*\r
-       Random stuff\r
-*/\r
-\r
-/*\r
-       GUI Stuff\r
-*/\r
-\r
-gui::IGUIEnvironment* guienv = NULL;\r
-gui::IGUIStaticText *guiroot = NULL;\r
-\r
-MainMenuManager g_menumgr;\r
-\r
-bool noMenuActive()\r
-{\r
-       return (g_menumgr.menuCount() == 0);\r
-}\r
-\r
-// Passed to menus to allow disconnecting and exiting\r
-\r
-MainGameCallback *g_gamecallback = NULL;\r
-\r
-/*\r
-       Debug streams\r
-*/\r
-\r
-// Connection\r
-std::ostream *dout_con_ptr = &dummyout;\r
-std::ostream *derr_con_ptr = &dstream_no_stderr;\r
-//std::ostream *dout_con_ptr = &dstream_no_stderr;\r
-//std::ostream *derr_con_ptr = &dstream_no_stderr;\r
-//std::ostream *dout_con_ptr = &dstream;\r
-//std::ostream *derr_con_ptr = &dstream;\r
-\r
-// Server\r
-std::ostream *dout_server_ptr = &dstream;\r
-std::ostream *derr_server_ptr = &dstream;\r
-\r
-// Client\r
-std::ostream *dout_client_ptr = &dstream;\r
-std::ostream *derr_client_ptr = &dstream;\r
-\r
-/*\r
-       gettime.h implementation\r
-*/\r
-\r
-// A small helper class\r
-class TimeGetter\r
-{\r
-public:\r
-       virtual u32 getTime() = 0;\r
-};\r
-\r
-// A precise irrlicht one\r
-class IrrlichtTimeGetter: public TimeGetter\r
-{\r
-public:\r
-       IrrlichtTimeGetter(IrrlichtDevice *device):\r
-               m_device(device)\r
-       {}\r
-       u32 getTime()\r
-       {\r
-               if(m_device == NULL)\r
-                       return 0;\r
-               return m_device->getTimer()->getRealTime();\r
-       }\r
-private:\r
-       IrrlichtDevice *m_device;\r
-};\r
-// Not so precise one which works without irrlicht\r
-class SimpleTimeGetter: public TimeGetter\r
-{\r
-public:\r
-       u32 getTime()\r
-       {\r
-               return porting::getTimeMs();\r
-       }\r
-};\r
-\r
-// A pointer to a global instance of the time getter\r
-// TODO: why?\r
-TimeGetter *g_timegetter = NULL;\r
-\r
-u32 getTimeMs()\r
-{\r
-       if(g_timegetter == NULL)\r
-               return 0;\r
-       return g_timegetter->getTime();\r
-}\r
-\r
-/*\r
-       Event handler for Irrlicht\r
-\r
-       NOTE: Everything possible should be moved out from here,\r
-             probably to InputHandler and the_game\r
-*/\r
-\r
-class MyEventReceiver : public IEventReceiver\r
-{\r
-public:\r
-       // This is the one method that we have to implement\r
-       virtual bool OnEvent(const SEvent& event)\r
-       {\r
-               /*\r
-                       React to nothing here if a menu is active\r
-               */\r
-               if(noMenuActive() == false)\r
-               {\r
-                       return false;\r
-               }\r
-\r
-               // Remember whether each key is down or up\r
-               if(event.EventType == irr::EET_KEY_INPUT_EVENT)\r
-               {\r
-                       keyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;\r
-\r
-                       if(event.KeyInput.PressedDown)\r
-                               keyWasDown[event.KeyInput.Key] = true;\r
-               }\r
-\r
-               if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)\r
-               {\r
-                       if(noMenuActive() == false)\r
-                       {\r
-                               left_active = false;\r
-                               middle_active = false;\r
-                               right_active = false;\r
-                       }\r
-                       else\r
-                       {\r
-                               //dstream<<"MyEventReceiver: mouse input"<<std::endl;\r
-                               left_active = event.MouseInput.isLeftPressed();\r
-                               middle_active = event.MouseInput.isMiddlePressed();\r
-                               right_active = event.MouseInput.isRightPressed();\r
-\r
-                               if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)\r
-                               {\r
-                                       leftclicked = true;\r
-                               }\r
-                               if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)\r
-                               {\r
-                                       rightclicked = true;\r
-                               }\r
-                               if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)\r
-                               {\r
-                                       leftreleased = true;\r
-                               }\r
-                               if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)\r
-                               {\r
-                                       rightreleased = true;\r
-                               }\r
-                               if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)\r
-                               {\r
-                                       mouse_wheel += event.MouseInput.Wheel;\r
-                               }\r
-                       }\r
-               }\r
-\r
-               return false;\r
-       }\r
-\r
-       bool IsKeyDown(EKEY_CODE keyCode) const\r
-       {\r
-               return keyIsDown[keyCode];\r
-       }\r
-       \r
-       // Checks whether a key was down and resets the state\r
-       bool WasKeyDown(EKEY_CODE keyCode)\r
-       {\r
-               bool b = keyWasDown[keyCode];\r
-               keyWasDown[keyCode] = false;\r
-               return b;\r
-       }\r
-\r
-       s32 getMouseWheel()\r
-       {\r
-               s32 a = mouse_wheel;\r
-               mouse_wheel = 0;\r
-               return a;\r
-       }\r
-\r
-       void clearInput()\r
-       {\r
-               for(u32 i=0; i<KEY_KEY_CODES_COUNT; i++)\r
-               {\r
-                       keyIsDown[i] = false;\r
-                       keyWasDown[i] = false;\r
-               }\r
-               \r
-               leftclicked = false;\r
-               rightclicked = false;\r
-               leftreleased = false;\r
-               rightreleased = false;\r
-\r
-               left_active = false;\r
-               middle_active = false;\r
-               right_active = false;\r
-\r
-               mouse_wheel = 0;\r
-       }\r
-\r
-       MyEventReceiver()\r
-       {\r
-               clearInput();\r
-       }\r
-\r
-       bool leftclicked;\r
-       bool rightclicked;\r
-       bool leftreleased;\r
-       bool rightreleased;\r
-\r
-       bool left_active;\r
-       bool middle_active;\r
-       bool right_active;\r
-\r
-       s32 mouse_wheel;\r
-\r
-private:\r
-       IrrlichtDevice *m_device;\r
-       \r
-       // The current state of keys\r
-       bool keyIsDown[KEY_KEY_CODES_COUNT];\r
-       // Whether a key has been pressed or not\r
-       bool keyWasDown[KEY_KEY_CODES_COUNT];\r
-};\r
-\r
-/*\r
-       Separated input handler\r
-*/\r
-\r
-class RealInputHandler : public InputHandler\r
-{\r
-public:\r
-       RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):\r
-               m_device(device),\r
-               m_receiver(receiver)\r
-       {\r
-       }\r
-       virtual bool isKeyDown(EKEY_CODE keyCode)\r
-       {\r
-               return m_receiver->IsKeyDown(keyCode);\r
-       }\r
-       virtual bool wasKeyDown(EKEY_CODE keyCode)\r
-       {\r
-               return m_receiver->WasKeyDown(keyCode);\r
-       }\r
-       virtual v2s32 getMousePos()\r
-       {\r
-               return m_device->getCursorControl()->getPosition();\r
-       }\r
-       virtual void setMousePos(s32 x, s32 y)\r
-       {\r
-               m_device->getCursorControl()->setPosition(x, y);\r
-       }\r
-\r
-       virtual bool getLeftState()\r
-       {\r
-               return m_receiver->left_active;\r
-       }\r
-       virtual bool getRightState()\r
-       {\r
-               return m_receiver->right_active;\r
-       }\r
-       \r
-       virtual bool getLeftClicked()\r
-       {\r
-               return m_receiver->leftclicked;\r
-       }\r
-       virtual bool getRightClicked()\r
-       {\r
-               return m_receiver->rightclicked;\r
-       }\r
-       virtual void resetLeftClicked()\r
-       {\r
-               m_receiver->leftclicked = false;\r
-       }\r
-       virtual void resetRightClicked()\r
-       {\r
-               m_receiver->rightclicked = false;\r
-       }\r
-\r
-       virtual bool getLeftReleased()\r
-       {\r
-               return m_receiver->leftreleased;\r
-       }\r
-       virtual bool getRightReleased()\r
-       {\r
-               return m_receiver->rightreleased;\r
-       }\r
-       virtual void resetLeftReleased()\r
-       {\r
-               m_receiver->leftreleased = false;\r
-       }\r
-       virtual void resetRightReleased()\r
-       {\r
-               m_receiver->rightreleased = false;\r
-       }\r
-\r
-       virtual s32 getMouseWheel()\r
-       {\r
-               return m_receiver->getMouseWheel();\r
-       }\r
-\r
-       void clear()\r
-       {\r
-               m_receiver->clearInput();\r
-       }\r
-private:\r
-       IrrlichtDevice *m_device;\r
-       MyEventReceiver *m_receiver;\r
-};\r
-\r
-class RandomInputHandler : public InputHandler\r
-{\r
-public:\r
-       RandomInputHandler()\r
-       {\r
-               leftdown = false;\r
-               rightdown = false;\r
-               leftclicked = false;\r
-               rightclicked = false;\r
-               leftreleased = false;\r
-               rightreleased = false;\r
-               for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)\r
-                       keydown[i] = false;\r
-       }\r
-       virtual bool isKeyDown(EKEY_CODE keyCode)\r
-       {\r
-               return keydown[keyCode];\r
-       }\r
-       virtual bool wasKeyDown(EKEY_CODE keyCode)\r
-       {\r
-               return false;\r
-       }\r
-       virtual v2s32 getMousePos()\r
-       {\r
-               return mousepos;\r
-       }\r
-       virtual void setMousePos(s32 x, s32 y)\r
-       {\r
-               mousepos = v2s32(x,y);\r
-       }\r
-\r
-       virtual bool getLeftState()\r
-       {\r
-               return leftdown;\r
-       }\r
-       virtual bool getRightState()\r
-       {\r
-               return rightdown;\r
-       }\r
-\r
-       virtual bool getLeftClicked()\r
-       {\r
-               return leftclicked;\r
-       }\r
-       virtual bool getRightClicked()\r
-       {\r
-               return rightclicked;\r
-       }\r
-       virtual void resetLeftClicked()\r
-       {\r
-               leftclicked = false;\r
-       }\r
-       virtual void resetRightClicked()\r
-       {\r
-               rightclicked = false;\r
-       }\r
-\r
-       virtual bool getLeftReleased()\r
-       {\r
-               return leftreleased;\r
-       }\r
-       virtual bool getRightReleased()\r
-       {\r
-               return rightreleased;\r
-       }\r
-       virtual void resetLeftReleased()\r
-       {\r
-               leftreleased = false;\r
-       }\r
-       virtual void resetRightReleased()\r
-       {\r
-               rightreleased = false;\r
-       }\r
-\r
-       virtual s32 getMouseWheel()\r
-       {\r
-               return 0;\r
-       }\r
-\r
-       virtual void step(float dtime)\r
-       {\r
-               {\r
-                       static float counter1 = 0;\r
-                       counter1 -= dtime;\r
-                       if(counter1 < 0.0)\r
-                       {\r
-                               counter1 = 0.1*Rand(1, 40);\r
-                               keydown[getKeySetting("keymap_jump")] =\r
-                                               !keydown[getKeySetting("keymap_jump")];\r
-                       }\r
-               }\r
-               {\r
-                       static float counter1 = 0;\r
-                       counter1 -= dtime;\r
-                       if(counter1 < 0.0)\r
-                       {\r
-                               counter1 = 0.1*Rand(1, 40);\r
-                               keydown[getKeySetting("keymap_special1")] =\r
-                                               !keydown[getKeySetting("keymap_special1")];\r
-                       }\r
-               }\r
-               {\r
-                       static float counter1 = 0;\r
-                       counter1 -= dtime;\r
-                       if(counter1 < 0.0)\r
-                       {\r
-                               counter1 = 0.1*Rand(1, 40);\r
-                               keydown[getKeySetting("keymap_forward")] =\r
-                                               !keydown[getKeySetting("keymap_forward")];\r
-                       }\r
-               }\r
-               {\r
-                       static float counter1 = 0;\r
-                       counter1 -= dtime;\r
-                       if(counter1 < 0.0)\r
-                       {\r
-                               counter1 = 0.1*Rand(1, 40);\r
-                               keydown[getKeySetting("keymap_left")] =\r
-                                               !keydown[getKeySetting("keymap_left")];\r
-                       }\r
-               }\r
-               {\r
-                       static float counter1 = 0;\r
-                       counter1 -= dtime;\r
-                       if(counter1 < 0.0)\r
-                       {\r
-                               counter1 = 0.1*Rand(1, 20);\r
-                               mousespeed = v2s32(Rand(-20,20), Rand(-15,20));\r
-                       }\r
-               }\r
-               {\r
-                       static float counter1 = 0;\r
-                       counter1 -= dtime;\r
-                       if(counter1 < 0.0)\r
-                       {\r
-                               counter1 = 0.1*Rand(1, 30);\r
-                               leftdown = !leftdown;\r
-                               if(leftdown)\r
-                                       leftclicked = true;\r
-                               if(!leftdown)\r
-                                       leftreleased = true;\r
-                       }\r
-               }\r
-               {\r
-                       static float counter1 = 0;\r
-                       counter1 -= dtime;\r
-                       if(counter1 < 0.0)\r
-                       {\r
-                               counter1 = 0.1*Rand(1, 15);\r
-                               rightdown = !rightdown;\r
-                               if(rightdown)\r
-                                       rightclicked = true;\r
-                               if(!rightdown)\r
-                                       rightreleased = true;\r
-                       }\r
-               }\r
-               mousepos += mousespeed;\r
-       }\r
-\r
-       s32 Rand(s32 min, s32 max)\r
-       {\r
-               return (myrand()%(max-min+1))+min;\r
-       }\r
-private:\r
-       bool keydown[KEY_KEY_CODES_COUNT];\r
-       v2s32 mousepos;\r
-       v2s32 mousespeed;\r
-       bool leftdown;\r
-       bool rightdown;\r
-       bool leftclicked;\r
-       bool rightclicked;\r
-       bool leftreleased;\r
-       bool rightreleased;\r
-};\r
-\r
-// These are defined global so that they're not optimized too much.\r
-// Can't change them to volatile.\r
-s16 temp16;\r
-f32 tempf;\r
-v3f tempv3f1;\r
-v3f tempv3f2;\r
-std::string tempstring;\r
-std::string tempstring2;\r
-\r
-void SpeedTests()\r
-{\r
-       {\r
-               dstream<<"The following test should take around 20ms."<<std::endl;\r
-               TimeTaker timer("Testing std::string speed");\r
-               const u32 jj = 10000;\r
-               for(u32 j=0; j<jj; j++)\r
-               {\r
-                       tempstring = "";\r
-                       tempstring2 = "";\r
-                       const u32 ii = 10;\r
-                       for(u32 i=0; i<ii; i++){\r
-                               tempstring2 += "asd";\r
-                       }\r
-                       for(u32 i=0; i<ii+1; i++){\r
-                               tempstring += "asd";\r
-                               if(tempstring == tempstring2)\r
-                                       break;\r
-                       }\r
-               }\r
-       }\r
-       \r
-       dstream<<"All of the following tests should take around 100ms each."\r
-                       <<std::endl;\r
-\r
-       {\r
-               TimeTaker timer("Testing floating-point conversion speed");\r
-               tempf = 0.001;\r
-               for(u32 i=0; i<4000000; i++){\r
-                       temp16 += tempf;\r
-                       tempf += 0.001;\r
-               }\r
-       }\r
-       \r
-       {\r
-               TimeTaker timer("Testing floating-point vector speed");\r
-\r
-               tempv3f1 = v3f(1,2,3);\r
-               tempv3f2 = v3f(4,5,6);\r
-               for(u32 i=0; i<10000000; i++){\r
-                       tempf += tempv3f1.dotProduct(tempv3f2);\r
-                       tempv3f2 += v3f(7,8,9);\r
-               }\r
-       }\r
-\r
-       {\r
-               TimeTaker timer("Testing core::map speed");\r
-               \r
-               core::map<v2s16, f32> map1;\r
-               tempf = -324;\r
-               const s16 ii=300;\r
-               for(s16 y=0; y<ii; y++){\r
-                       for(s16 x=0; x<ii; x++){\r
-                               map1.insert(v2s16(x,y), tempf);\r
-                               tempf += 1;\r
-                       }\r
-               }\r
-               for(s16 y=ii-1; y>=0; y--){\r
-                       for(s16 x=0; x<ii; x++){\r
-                               tempf = map1[v2s16(x,y)];\r
-                       }\r
-               }\r
-       }\r
-\r
-       {\r
-               dstream<<"Around 5000/ms should do well here."<<std::endl;\r
-               TimeTaker timer("Testing mutex speed");\r
-               \r
-               JMutex m;\r
-               m.Init();\r
-               u32 n = 0;\r
-               u32 i = 0;\r
-               do{\r
-                       n += 10000;\r
-                       for(; i<n; i++){\r
-                               m.Lock();\r
-                               m.Unlock();\r
-                       }\r
-               }\r
-               // Do at least 10ms\r
-               while(timer.getTime() < 10);\r
-\r
-               u32 dtime = timer.stop();\r
-               u32 per_ms = n / dtime;\r
-               std::cout<<"Done. "<<dtime<<"ms, "\r
-                               <<per_ms<<"/ms"<<std::endl;\r
-       }\r
-}\r
-\r
-void drawMenuBackground(video::IVideoDriver* driver)\r
-{\r
-       core::dimension2d<u32> screensize = driver->getScreenSize();\r
-               \r
-       video::ITexture *bgtexture =\r
-                       driver->getTexture(getTexturePath("mud.png").c_str());\r
-       if(bgtexture)\r
-       {\r
-               s32 texturesize = 128;\r
-               s32 tiled_y = screensize.Height / texturesize + 1;\r
-               s32 tiled_x = screensize.Width / texturesize + 1;\r
-               \r
-               for(s32 y=0; y<tiled_y; y++)\r
-               for(s32 x=0; x<tiled_x; x++)\r
-               {\r
-                       core::rect<s32> rect(0,0,texturesize,texturesize);\r
-                       rect += v2s32(x*texturesize, y*texturesize);\r
-                       driver->draw2DImage(bgtexture, rect,\r
-                               core::rect<s32>(core::position2d<s32>(0,0),\r
-                               core::dimension2di(bgtexture->getSize())),\r
-                               NULL, NULL, true);\r
-               }\r
-       }\r
-       \r
-       video::ITexture *logotexture =\r
-                       driver->getTexture(getTexturePath("menulogo.png").c_str());\r
-       if(logotexture)\r
-       {\r
-               v2s32 logosize(logotexture->getOriginalSize().Width,\r
-                               logotexture->getOriginalSize().Height);\r
-               logosize *= 4;\r
-\r
-               video::SColor bgcolor(255,50,50,50);\r
-               core::rect<s32> bgrect(0, screensize.Height-logosize.Y-20,\r
-                               screensize.Width, screensize.Height);\r
-               driver->draw2DRectangle(bgcolor, bgrect, NULL);\r
-\r
-               core::rect<s32> rect(0,0,logosize.X,logosize.Y);\r
-               rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y);\r
-               rect -= v2s32(logosize.X/2, 0);\r
-               driver->draw2DImage(logotexture, rect,\r
-                       core::rect<s32>(core::position2d<s32>(0,0),\r
-                       core::dimension2di(logotexture->getSize())),\r
-                       NULL, NULL, true);\r
-       }\r
-}\r
-\r
-int main(int argc, char *argv[])\r
-{\r
-       /*\r
-               Initialization\r
-       */\r
-\r
-       // Set locale. This is for forcing '.' as the decimal point.\r
-       std::locale::global(std::locale("C"));\r
-       // This enables printing all characters in bitmap font\r
-       setlocale(LC_CTYPE, "en_US");\r
-\r
-       /*\r
-               Parse command line\r
-       */\r
-       \r
-       // List all allowed options\r
-       core::map<std::string, ValueSpec> allowed_options;\r
-       allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));\r
-       allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,\r
-                       "Run server directly"));\r
-       allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,\r
-                       "Load configuration from specified file"));\r
-       allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));\r
-       allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));\r
-       allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));\r
-       allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));\r
-       allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));\r
-       allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));\r
-#ifdef _WIN32\r
-       allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));\r
-#endif\r
-       allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));\r
-\r
-       Settings cmd_args;\r
-       \r
-       bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);\r
-\r
-       if(ret == false || cmd_args.getFlag("help"))\r
-       {\r
-               dstream<<"Allowed options:"<<std::endl;\r
-               for(core::map<std::string, ValueSpec>::Iterator\r
-                               i = allowed_options.getIterator();\r
-                               i.atEnd() == false; i++)\r
-               {\r
-                       dstream<<"  --"<<i.getNode()->getKey();\r
-                       if(i.getNode()->getValue().type == VALUETYPE_FLAG)\r
-                       {\r
-                       }\r
-                       else\r
-                       {\r
-                               dstream<<" <value>";\r
-                       }\r
-                       dstream<<std::endl;\r
-\r
-                       if(i.getNode()->getValue().help != NULL)\r
-                       {\r
-                               dstream<<"      "<<i.getNode()->getValue().help\r
-                                               <<std::endl;\r
-                       }\r
-               }\r
-\r
-               return cmd_args.getFlag("help") ? 0 : 1;\r
-       }\r
-       \r
-       /*\r
-               Low-level initialization\r
-       */\r
-\r
-       bool disable_stderr = false;\r
-#ifdef _WIN32\r
-       if(cmd_args.getFlag("dstream-on-stderr") == false)\r
-               disable_stderr = true;\r
-#endif\r
-\r
-       porting::signal_handler_init();\r
-       bool &kill = *porting::signal_handler_killstatus();\r
-       \r
-       // Initialize porting::path_data and porting::path_userdata\r
-       porting::initializePaths();\r
-\r
-       // Create user data directory\r
-       fs::CreateDir(porting::path_userdata);\r
-       \r
-       // Initialize debug streams\r
-#ifdef RUN_IN_PLACE\r
-       std::string debugfile = DEBUGFILE;\r
-#else\r
-       std::string debugfile = porting::path_userdata+"/"+DEBUGFILE;\r
-#endif\r
-       debugstreams_init(disable_stderr, debugfile.c_str());\r
-       // Initialize debug stacks\r
-       debug_stacks_init();\r
-\r
-       DSTACK(__FUNCTION_NAME);\r
-\r
-       // Init material properties table\r
-       //initializeMaterialProperties();\r
-\r
-       // Debug handler\r
-       BEGIN_DEBUG_EXCEPTION_HANDLER\r
-\r
-       // Print startup message\r
-       dstream<<DTIME<<"minetest-c55"\r
-                       " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST\r
-                       <<", "<<BUILD_INFO\r
-                       <<std::endl;\r
-       \r
-       /*\r
-               Basic initialization\r
-       */\r
-\r
-       // Initialize default settings\r
-       set_default_settings();\r
-       \r
-       // Initialize sockets\r
-       sockets_init();\r
-       atexit(sockets_cleanup);\r
-       \r
-       /*\r
-               Read config file\r
-       */\r
-       \r
-       // Path of configuration file in use\r
-       std::string configpath = "";\r
-       \r
-       if(cmd_args.exists("config"))\r
-       {\r
-               bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());\r
-               if(r == false)\r
-               {\r
-                       dstream<<"Could not read configuration from \""\r
-                                       <<cmd_args.get("config")<<"\""<<std::endl;\r
-                       return 1;\r
-               }\r
-               configpath = cmd_args.get("config");\r
-       }\r
-       else\r
-       {\r
-               core::array<std::string> filenames;\r
-               filenames.push_back(porting::path_userdata + "/minetest.conf");\r
-#ifdef RUN_IN_PLACE\r
-               filenames.push_back(porting::path_userdata + "/../minetest.conf");\r
-#endif\r
-\r
-               for(u32 i=0; i<filenames.size(); i++)\r
-               {\r
-                       bool r = g_settings.readConfigFile(filenames[i].c_str());\r
-                       if(r)\r
-                       {\r
-                               configpath = filenames[i];\r
-                               break;\r
-                       }\r
-               }\r
-               \r
-               // If no path found, use the first one (menu creates the file)\r
-               if(configpath == "")\r
-                       configpath = filenames[0];\r
-       }\r
-\r
-       // Initialize random seed\r
-       srand(time(0));\r
-       mysrand(time(0));\r
-\r
-       /*\r
-               Pre-initialize some stuff with a dummy irrlicht wrapper.\r
-\r
-               These are needed for unit tests at least.\r
-       */\r
-       \r
-       // Initial call with g_texturesource not set.\r
-       init_mapnode();\r
-\r
-       /*\r
-               Run unit tests\r
-       */\r
-\r
-       if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)\r
-                       || cmd_args.getFlag("enable-unittests") == true)\r
-       {\r
-               run_tests();\r
-       }\r
-       \r
-       /*for(s16 y=-100; y<100; y++)\r
-       for(s16 x=-100; x<100; x++)\r
-       {\r
-               std::cout<<noise2d_gradient((double)x/10,(double)y/10, 32415)<<std::endl;\r
-       }\r
-       return 0;*/\r
-       \r
-       /*\r
-               Game parameters\r
-       */\r
-\r
-       // Port\r
-       u16 port = 30000;\r
-       if(cmd_args.exists("port"))\r
-               port = cmd_args.getU16("port");\r
-       else if(g_settings.exists("port"))\r
-               port = g_settings.getU16("port");\r
-       if(port == 0)\r
-               port = 30000;\r
-       \r
-       // Map directory\r
-       std::string map_dir = porting::path_userdata+"/world";\r
-       if(cmd_args.exists("map-dir"))\r
-               map_dir = cmd_args.get("map-dir");\r
-       else if(g_settings.exists("map-dir"))\r
-               map_dir = g_settings.get("map-dir");\r
-       \r
-       // Run dedicated server if asked to\r
-       if(cmd_args.getFlag("server"))\r
-       {\r
-               DSTACK("Dedicated server branch");\r
-\r
-               // Create time getter\r
-               g_timegetter = new SimpleTimeGetter();\r
-               \r
-               // Create server\r
-               Server server(map_dir.c_str());\r
-               server.start(port);\r
-               \r
-               // Run server\r
-               dedicated_server_loop(server, kill);\r
-\r
-               return 0;\r
-       }\r
-\r
-\r
-       /*\r
-               More parameters\r
-       */\r
-       \r
-       // Address to connect to\r
-       std::string address = "";\r
-       \r
-       if(cmd_args.exists("address"))\r
-       {\r
-               address = cmd_args.get("address");\r
-       }\r
-       else\r
-       {\r
-               address = g_settings.get("address");\r
-       }\r
-       \r
-       std::string playername = g_settings.get("name");\r
-\r
-       /*\r
-               Device initialization\r
-       */\r
-\r
-       // Resolution selection\r
-       \r
-       bool fullscreen = false;\r
-       u16 screenW = g_settings.getU16("screenW");\r
-       u16 screenH = g_settings.getU16("screenH");\r
-\r
-       // Determine driver\r
-\r
-       video::E_DRIVER_TYPE driverType;\r
-       \r
-       std::string driverstring = g_settings.get("video_driver");\r
-\r
-       if(driverstring == "null")\r
-               driverType = video::EDT_NULL;\r
-       else if(driverstring == "software")\r
-               driverType = video::EDT_SOFTWARE;\r
-       else if(driverstring == "burningsvideo")\r
-               driverType = video::EDT_BURNINGSVIDEO;\r
-       else if(driverstring == "direct3d8")\r
-               driverType = video::EDT_DIRECT3D8;\r
-       else if(driverstring == "direct3d9")\r
-               driverType = video::EDT_DIRECT3D9;\r
-       else if(driverstring == "opengl")\r
-               driverType = video::EDT_OPENGL;\r
-       else\r
-       {\r
-               dstream<<"WARNING: Invalid video_driver specified; defaulting "\r
-                               "to opengl"<<std::endl;\r
-               driverType = video::EDT_OPENGL;\r
-       }\r
-\r
-       /*\r
-               Create device and exit if creation failed\r
-       */\r
-\r
-       MyEventReceiver receiver;\r
-\r
-       IrrlichtDevice *device;\r
-       device = createDevice(driverType,\r
-                       core::dimension2d<u32>(screenW, screenH),\r
-                       16, fullscreen, false, false, &receiver);\r
-\r
-       if (device == 0)\r
-               return 1; // could not create selected driver.\r
-       \r
-       // Set device in game parameters\r
-       device = device;\r
-       \r
-       // Create time getter\r
-       g_timegetter = new IrrlichtTimeGetter(device);\r
-       \r
-       // Create game callback for menus\r
-       g_gamecallback = new MainGameCallback(device);\r
-       \r
-       // Create texture source\r
-       g_texturesource = new TextureSource(device);\r
-\r
-       /*\r
-               Speed tests (done after irrlicht is loaded to get timer)\r
-       */\r
-       if(cmd_args.getFlag("speedtests"))\r
-       {\r
-               dstream<<"Running speed tests"<<std::endl;\r
-               SpeedTests();\r
-               return 0;\r
-       }\r
-       \r
-       device->setResizable(true);\r
-\r
-       bool random_input = g_settings.getBool("random_input")\r
-                       || cmd_args.getFlag("random-input");\r
-       InputHandler *input = NULL;\r
-       if(random_input)\r
-               input = new RandomInputHandler();\r
-       else\r
-               input = new RealInputHandler(device, &receiver);\r
-       \r
-       /*\r
-               Continue initialization\r
-       */\r
-\r
-       //video::IVideoDriver* driver = device->getVideoDriver();\r
-\r
-       /*\r
-               This changes the minimum allowed number of vertices in a VBO.\r
-               Default is 500.\r
-       */\r
-       //driver->setMinHardwareBufferVertexCount(50);\r
-\r
-       scene::ISceneManager* smgr = device->getSceneManager();\r
-\r
-       guienv = device->getGUIEnvironment();\r
-       gui::IGUISkin* skin = guienv->getSkin();\r
-       gui::IGUIFont* font = guienv->getFont(getTexturePath("fontlucida.png").c_str());\r
-       if(font)\r
-               skin->setFont(font);\r
-       else\r
-               dstream<<"WARNING: Font file was not found."\r
-                               " Using default font."<<std::endl;\r
-       // If font was not found, this will get us one\r
-       font = skin->getFont();\r
-       assert(font);\r
-       \r
-       u32 text_height = font->getDimension(L"Hello, world!").Height;\r
-       dstream<<"text_height="<<text_height<<std::endl;\r
-\r
-       //skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));\r
-       skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));\r
-       //skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0));\r
-       //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0));\r
-       skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0));\r
-       skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));\r
-       \r
-       /*\r
-               Preload some textures and stuff\r
-       */\r
-\r
-       init_mapnode(); // Second call with g_texturesource set\r
-       init_mineral();\r
-\r
-       /*\r
-               GUI stuff\r
-       */\r
-\r
-       /*\r
-               If an error occurs, this is set to something and the\r
-               menu-game loop is restarted. It is then displayed before\r
-               the menu.\r
-       */\r
-       std::wstring error_message = L"";\r
-\r
-       // The password entered during the menu screen,\r
-       std::string password;\r
-\r
-       /*\r
-               Menu-game loop\r
-       */\r
-       while(device->run() && kill == false)\r
-       {\r
-\r
-               // This is used for catching disconnects\r
-               try\r
-               {\r
-\r
-                       /*\r
-                               Clear everything from the GUIEnvironment\r
-                       */\r
-                       guienv->clear();\r
-                       \r
-                       /*\r
-                               We need some kind of a root node to be able to add\r
-                               custom gui elements directly on the screen.\r
-                               Otherwise they won't be automatically drawn.\r
-                       */\r
-                       guiroot = guienv->addStaticText(L"",\r
-                                       core::rect<s32>(0, 0, 10000, 10000));\r
-                       \r
-                       /*\r
-                               Out-of-game menu loop.\r
-\r
-                               Loop quits when menu returns proper parameters.\r
-                       */\r
-                       while(kill == false)\r
-                       {\r
-                               // Cursor can be non-visible when coming from the game\r
-                               device->getCursorControl()->setVisible(true);\r
-                               // Some stuff are left to scene manager when coming from the game\r
-                               // (map at least?)\r
-                               smgr->clear();\r
-                               // Reset or hide the debug gui texts\r
-                               /*guitext->setText(L"Minetest-c55");\r
-                               guitext2->setVisible(false);\r
-                               guitext_info->setVisible(false);\r
-                               guitext_chat->setVisible(false);*/\r
-                               \r
-                               // Initialize menu data\r
-                               MainMenuData menudata;\r
-                               menudata.address = narrow_to_wide(address);\r
-                               menudata.name = narrow_to_wide(playername);\r
-                               menudata.port = narrow_to_wide(itos(port));\r
-                               menudata.fancy_trees = g_settings.getBool("new_style_leaves");\r
-                               menudata.smooth_lighting = g_settings.getBool("smooth_lighting");\r
-                               menudata.creative_mode = g_settings.getBool("creative_mode");\r
-                               menudata.enable_damage = g_settings.getBool("enable_damage");\r
-\r
-                               GUIMainMenu *menu =\r
-                                               new GUIMainMenu(guienv, guiroot, -1, \r
-                                                       &g_menumgr, &menudata, g_gamecallback);\r
-                               menu->allowFocusRemoval(true);\r
-\r
-                               if(error_message != L"")\r
-                               {\r
-                                       dstream<<"WARNING: error_message = "\r
-                                                       <<wide_to_narrow(error_message)<<std::endl;\r
-\r
-                                       GUIMessageMenu *menu2 =\r
-                                                       new GUIMessageMenu(guienv, guiroot, -1, \r
-                                                               &g_menumgr, error_message.c_str());\r
-                                       menu2->drop();\r
-                                       error_message = L"";\r
-                               }\r
-\r
-                               video::IVideoDriver* driver = device->getVideoDriver();\r
-                               \r
-                               dstream<<"Created main menu"<<std::endl;\r
-\r
-                               while(device->run() && kill == false)\r
-                               {\r
-                                       if(menu->getStatus() == true)\r
-                                               break;\r
-\r
-                                       //driver->beginScene(true, true, video::SColor(255,0,0,0));\r
-                                       driver->beginScene(true, true, video::SColor(255,128,128,128));\r
-\r
-                                       drawMenuBackground(driver);\r
-\r
-                                       guienv->drawAll();\r
-                                       \r
-                                       driver->endScene();\r
-                                       \r
-                                       // On some computers framerate doesn't seem to be\r
-                                       // automatically limited\r
-                                       sleep_ms(25);\r
-                               }\r
-                               \r
-                               // Break out of menu-game loop to shut down cleanly\r
-                               if(device->run() == false || kill == true)\r
-                                       break;\r
-                               \r
-                               dstream<<"Dropping main menu"<<std::endl;\r
-\r
-                               menu->drop();\r
-                               \r
-                               // Delete map if requested\r
-                               if(menudata.delete_map)\r
-                               {\r
-                                       bool r = fs::RecursiveDeleteContent(map_dir);\r
-                                       if(r == false)\r
-                                               error_message = L"Delete failed";\r
-                                       continue;\r
-                               }\r
-\r
-                               playername = wide_to_narrow(menudata.name);\r
-\r
-                               password = translatePassword(playername, menudata.password);\r
-\r
-                               address = wide_to_narrow(menudata.address);\r
-                               int newport = stoi(wide_to_narrow(menudata.port));\r
-                               if(newport != 0)\r
-                                       port = newport;\r
-                               g_settings.set("new_style_leaves", itos(menudata.fancy_trees));\r
-                               g_settings.set("smooth_lighting", itos(menudata.smooth_lighting));\r
-                               g_settings.set("creative_mode", itos(menudata.creative_mode));\r
-                               g_settings.set("enable_damage", itos(menudata.enable_damage));\r
-                               \r
-                               // NOTE: These are now checked server side; no need to do it\r
-                               //       here, so let's not do it here.\r
-                               /*// Check for valid parameters, restart menu if invalid.\r
-                               if(playername == "")\r
-                               {\r
-                                       error_message = L"Name required.";\r
-                                       continue;\r
-                               }\r
-                               // Check that name has only valid chars\r
-                               if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)\r
-                               {\r
-                                       error_message = L"Characters allowed: "\r
-                                                       +narrow_to_wide(PLAYERNAME_ALLOWED_CHARS);\r
-                                       continue;\r
-                               }*/\r
-\r
-                               // Save settings\r
-                               g_settings.set("name", playername);\r
-                               g_settings.set("address", address);\r
-                               g_settings.set("port", itos(port));\r
-                               // Update configuration file\r
-                               if(configpath != "")\r
-                                       g_settings.updateConfigFile(configpath.c_str());\r
-                       \r
-                               // Continue to game\r
-                               break;\r
-                       }\r
-                       \r
-                       // Break out of menu-game loop to shut down cleanly\r
-                       if(device->run() == false)\r
-                               break;\r
-                       \r
-                       // Initialize mapnode again to enable changed graphics settings\r
-                       init_mapnode();\r
-\r
-                       /*\r
-                               Run game\r
-                       */\r
-                       the_game(\r
-                               kill,\r
-                               random_input,\r
-                               input,\r
-                               device,\r
-                               font,\r
-                               map_dir,\r
-                               playername,\r
-                               password,\r
-                               address,\r
-                               port,\r
-                               error_message\r
-                       );\r
-\r
-               } //try\r
-               catch(con::PeerNotFoundException &e)\r
-               {\r
-                       dstream<<DTIME<<"Connection error (timed out?)"<<std::endl;\r
-                       error_message = L"Connection error (timed out?)";\r
-               }\r
-               catch(SocketException &e)\r
-               {\r
-                       dstream<<DTIME<<"Socket error (port already in use?)"<<std::endl;\r
-                       error_message = L"Socket error (port already in use?)";\r
-               }\r
-#ifdef NDEBUG\r
-               catch(std::exception &e)\r
-               {\r
-                       std::string narrow_message = "Some exception, what()=\"";\r
-                       narrow_message += e.what();\r
-                       narrow_message += "\"";\r
-                       dstream<<DTIME<<narrow_message<<std::endl;\r
-                       error_message = narrow_to_wide(narrow_message);\r
-               }\r
-#endif\r
-\r
-       } // Menu-game loop\r
-       \r
-       delete input;\r
-\r
-       /*\r
-               In the end, delete the Irrlicht device.\r
-       */\r
-       device->drop();\r
-       \r
-       END_DEBUG_EXCEPTION_HANDLER\r
-       \r
-       debugstreams_deinit();\r
-       \r
-       return 0;\r
-}\r
-\r
-//END\r
+/*
+Minetest-c55
+Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+/*
+=============================== NOTES ==============================
+NOTE: Things starting with TODO are sometimes only suggestions.
+
+NOTE: iostream.imbue(std::locale("C")) is very slow
+NOTE: Global locale is now set at initialization
+
+NOTE: If VBO (EHM_STATIC) is used, remember to explicitly free the
+      hardware buffer (it is not freed automatically)
+
+NOTE: A random to-do list saved here as documentation:
+A list of "active blocks" in which stuff happens. (+=done)
+       + Add a never-resetted game timer to the server
+       + Add a timestamp value to blocks
+       + The simple rule: All blocks near some player are "active"
+       - Do stuff in real time in active blocks
+               + Handle objects
+               - Grow grass, delete leaves without a tree
+               - Spawn some mobs based on some rules
+               - Transform cobble to mossy cobble near water
+               - Run a custom script
+               - ...And all kinds of other dynamic stuff
+       + Keep track of when a block becomes active and becomes inactive
+       + When a block goes inactive:
+               + Store objects statically to block
+               + Store timer value as the timestamp
+       + When a block goes active:
+               + Create active objects out of static objects
+               - Simulate the results of what would have happened if it would have
+                 been active for all the time
+                       - Grow a lot of grass and so on
+       + Initially it is fine to send information about every active object
+         to every player. Eventually it should be modified to only send info
+         about the nearest ones.
+               + This was left to be done by the old system and it sends only the
+                 nearest ones.
+
+Vim conversion regexpes for moving to extended content type storage:
+%s/\(\.\|->\)d \([!=]=\)/\1getContent() \2/g
+%s/content_features(\([^.]*\)\.d)/content_features(\1)/g
+%s/\(\.\|->\)d = \([^;]*\);/\1setContent(\2);/g
+%s/\(getNodeNoExNoEmerge([^)]*)\)\.d/\1.getContent()/g
+%s/\(getNodeNoExNoEmerge(.*)\)\.d/\1.getContent()/g
+%s/\.d;/.getContent();/g
+%s/\(content_liquid\|content_flowing_liquid\|make_liquid_flowing\|content_pointable\)(\([^.]*\).d)/\1(\2.getContent())/g
+Other things to note:
+- node.d = node.param0 (only in raw serialization; use getContent() otherwise)
+- node.param = node.param1
+- node.dir = node.param2
+- content_walkable(node.d) etc should be changed to
+  content_features(node).walkable etc
+- Also check for lines that store the result of getContent to a 8-bit
+  variable and fix them (result of getContent() must be stored in
+  content_t, which is 16-bit)
+
+Old, wild and random suggestions that probably won't be done:
+-------------------------------------------------------------
+
+SUGG: If player is on ground, mainly fetch ground-level blocks
+
+SUGG: Expose Connection's seqnums and ACKs to server and client.
+      - This enables saving many packets and making a faster connection
+         - This also enables server to check if client has received the
+           most recent block sent, for example.
+SUGG: Add a sane bandwidth throttling system to Connection
+
+SUGG: More fine-grained control of client's dumping of blocks from
+      memory
+         - ...What does this mean in the first place?
+
+SUGG: A map editing mode (similar to dedicated server mode)
+
+SUGG: Transfer more blocks in a single packet
+SUGG: A blockdata combiner class, to which blocks are added and at
+      destruction it sends all the stuff in as few packets as possible.
+SUGG: Make a PACKET_COMBINED which contains many subpackets. Utilize
+      it by sending more stuff in a single packet.
+         - Add a packet queue to RemoteClient, from which packets will be
+           combined with object data packets
+               - This is not exactly trivial: the object data packets are
+                 sometimes very big by themselves
+         - This might not give much network performance gain though.
+
+SUGG: Precalculate lighting translation table at runtime (at startup)
+      - This is not doable because it is currently hand-made and not
+           based on some mathematical function.
+               - Note: This has been changing lately
+
+SUGG: A version number to blocks, which increments when the block is
+      modified (node add/remove, water update, lighting update)
+         - This can then be used to make sure the most recent version of
+           a block has been sent to client, for example
+
+SUGG: Make the amount of blocks sending to client and the total
+         amount of blocks dynamically limited. Transferring blocks is the
+         main network eater of this system, so it is the one that has
+         to be throttled so that RTTs stay low.
+
+SUGG: Meshes of blocks could be split into 6 meshes facing into
+      different directions and then only those drawn that need to be
+
+SUGG: Background music based on cellular automata?
+      http://www.earslap.com/projectslab/otomata
+
+SUGG: Simple light color information to air
+
+SUGG: Server-side objects could be moved based on nodes to enable very
+      lightweight operation and simple AI
+       - Not practical; client would still need to show smooth movement.
+
+SUGG: Make a system for pregenerating quick information for mapblocks, so
+         that the client can show them as cubes before they are actually sent
+         or even generated.
+
+SUGG: Erosion simulation at map generation time
+    - This might be plausible if larger areas of map were pregenerated
+         without lighting (which is slow)
+       - Simulate water flows, which would carve out dirt fast and
+         then turn stone into gravel and sand and relocate it.
+       - How about relocating minerals, too? Coal and gold in
+         downstream sand and gravel would be kind of cool
+         - This would need a better way of handling minerals, mainly
+               to have mineral content as a separate field. the first
+               parameter field is free for this.
+       - Simulate rock falling from cliffs when water has removed
+         enough solid rock from the bottom
+
+SUGG: For non-mapgen FarMesh: Add a per-sector database to store surface
+      stuff as simple flags/values
+      - Light?
+         - A building?
+         And at some point make the server send this data to the client too,
+         instead of referring to the noise functions
+         - Ground height
+         - Surface ground type
+         - Trees?
+
+Gaming ideas:
+-------------
+
+- Aim for something like controlling a single dwarf in Dwarf Fortress
+- The player could go faster by a crafting a boat, or riding an animal
+- Random NPC traders. what else?
+
+Game content:
+-------------
+
+- When furnace is destroyed, move items to player's inventory
+- Add lots of stuff
+- Glass blocks
+- Growing grass, decaying leaves
+       - This can be done in the active blocks I guess.
+       - Lots of stuff can be done in the active blocks.
+       - Uh, is there an active block list somewhere? I think not. Add it.
+- Breaking weak structures
+       - This can probably be accomplished in the same way as grass
+- Player health points
+       - When player dies, throw items on map (needs better item-on-map
+         implementation)
+- Cobble to get mossy if near water
+- More slots in furnace source list, so that multiple ingredients
+  are possible.
+- Keys to chests?
+
+- The Treasure Guard; a big monster with a hammer
+       - The hammer does great damage, shakes the ground and removes a block
+       - You can drop on top of it, and have some time to attack there
+         before he shakes you off
+
+- Maybe the difficulty could come from monsters getting tougher in
+  far-away places, and the player starting to need something from
+  there when time goes by.
+  - The player would have some of that stuff at the beginning, and
+    would need new supplies of it when it runs out
+
+- A bomb
+- A spread-items-on-map routine for the bomb, and for dying players
+
+- Fighting:
+  - Proper sword swing simulation
+  - Player should get damage from colliding to a wall at high speed
+
+Documentation:
+--------------
+
+Build system / running:
+-----------------------
+
+Networking and serialization:
+-----------------------------
+
+SUGG: Fix address to be ipv6 compatible
+
+User Interface:
+---------------
+
+Graphics:
+---------
+
+SUGG: Combine MapBlock's face caches to so big pieces that VBO
+      can be used
+      - That is >500 vertices
+         - This is not easy; all the MapBlocks close to the player would
+           still need to be drawn separately and combining the blocks
+               would have to happen in a background thread
+
+SUGG: Make fetching sector's blocks more efficient when rendering
+      sectors that have very large amounts of blocks (on client)
+         - Is this necessary at all?
+
+SUGG: Draw cubes in inventory directly with 3D drawing commands, so that
+      animating them is easier.
+
+SUGG: Option for enabling proper alpha channel for textures
+
+TODO: Flowing water animation
+
+TODO: A setting for enabling bilinear filtering for textures
+
+TODO: Better control of draw_control.wanted_max_blocks
+
+TODO: Further investigate the use of GPU lighting in addition to the
+      current one
+
+TODO: Artificial (night) light could be more yellow colored than sunlight.
+      - This is technically doable.
+         - Also the actual colors of the textures could be made less colorful
+           in the dark but it's a bit more difficult.
+
+SUGG: Somehow make the night less colorful
+
+TODO: Occlusion culling
+      - At the same time, move some of the renderMap() block choosing code
+        to the same place as where the new culling happens.
+      - Shoot some rays per frame and when ready, make a new list of
+           blocks for usage of renderMap and give it a new pointer to it.
+
+Configuration:
+--------------
+
+Client:
+-------
+
+TODO: Untie client network operations from framerate
+      - Needs some input queues or something
+         - This won't give much performance boost because calculating block
+           meshes takes so long
+
+SUGG: Make morning and evening transition more smooth and maybe shorter
+
+TODO: Don't update all meshes always on single node changes, but
+      check which ones should be updated
+         - implement Map::updateNodeMeshes() and the usage of it
+         - It will give almost always a 4x boost in mesh update performance.
+
+- A weapon engine
+
+- Tool/weapon visualization
+
+FIXME: When disconnected to the menu, memory is not freed properly
+
+TODO: Investigate how much the mesh generator thread gets used when
+      transferring map data
+
+Server:
+-------
+
+SUGG: Make an option to the server to disable building and digging near
+      the starting position
+
+FIXME: Server sometimes goes into some infinite PeerNotFoundException loop
+
+* Fix the problem with the server constantly saving one or a few
+  blocks? List the first saved block, maybe it explains.
+  - It is probably caused by oscillating water
+  - TODO: Investigate if this still happens (this is a very old one)
+* Make a small history check to transformLiquids to detect and log
+  continuous oscillations, in such detail that they can be fixed.
+
+FIXME: The new optimized map sending doesn't sometimes send enough blocks
+       from big caves and such
+FIXME: Block send distance configuration does not take effect for some reason
+
+Environment:
+------------
+
+TODO: Add proper hooks to when adding and removing active blocks
+
+TODO: Finish the ActiveBlockModifier stuff and use it for something
+
+Objects:
+--------
+
+TODO: Get rid of MapBlockObjects and use only ActiveObjects
+       - Skipping the MapBlockObject data is nasty - there is no "total
+         length" stored; have to make a SkipMBOs function which contains
+         enough of the current code to skip them properly.
+
+SUGG: MovingObject::move and Player::move are basically the same.
+      combine them.
+       - NOTE: This is a bit tricky because player has the sneaking ability
+       - NOTE: Player::move is more up-to-date.
+       - NOTE: There is a simple move implementation now in collision.{h,cpp}
+       - NOTE: MovingObject will be deleted (MapBlockObject)
+
+TODO: Add a long step function to objects that is called with the time
+      difference when block activates
+
+Map:
+----
+
+TODO: Mineral and ground material properties
+      - This way mineral ground toughness can be calculated with just
+           some formula, as well as tool strengths. Sounds too.
+         - There are TODOs in appropriate files: material.h, content_mapnode.h
+
+TODO: Flowing water to actually contain flow direction information
+      - There is a space for this - it just has to be implemented.
+
+TODO: Consider smoothening cave floors after generating them
+
+TODO: Fix make_tree, make_* to use seed-position-consistent pseudorandom
+         - delta also
+
+Misc. stuff:
+------------
+TODO: Make sure server handles removing grass when a block is placed (etc)
+      - The client should not do it by itself
+         - NOTE: I think nobody does it currently...
+TODO: Block cube placement around player's head
+TODO: Protocol version field
+TODO: Think about using same bits for material for fences and doors, for
+         example
+TODO: Move mineral to param2, increment map serialization version, add
+      conversion
+
+SUGG: Restart irrlicht completely when coming back to main menu from game.
+       - This gets rid of everything that is stored in irrlicht's caches.
+       - This might be needed for texture pack selection in menu
+
+TODO: Merge bahamada's audio stuff (clean patch available)
+
+TODO: Move content_features to mapnode_content_features.{h,cpp} or so
+
+Making it more portable:
+------------------------
+Stuff to do before release:
+---------------------------
+
+Fixes to the current release:
+-----------------------------
+
+Stuff to do after release:
+---------------------------
+
+Doing currently:
+----------------
+
+======================================================================
+
+*/
+
+#ifdef NDEBUG
+       #ifdef _WIN32
+               #pragma message ("Disabling unit tests")
+       #else
+               #warning "Disabling unit tests"
+       #endif
+       // Disable unit tests
+       #define ENABLE_TESTS 0
+#else
+       // Enable unit tests
+       #define ENABLE_TESTS 1
+#endif
+
+#ifdef _MSC_VER
+       #pragma comment(lib, "Irrlicht.lib")
+       //#pragma comment(lib, "jthread.lib")
+       #pragma comment(lib, "zlibwapi.lib")
+       #pragma comment(lib, "Shell32.lib")
+       // This would get rid of the console window
+       //#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <locale.h>
+#include "main.h"
+#include "common_irrlicht.h"
+#include "debug.h"
+#include "test.h"
+#include "server.h"
+#include "constants.h"
+#include "porting.h"
+#include "gettime.h"
+#include "guiMessageMenu.h"
+#include "filesys.h"
+#include "config.h"
+#include "guiMainMenu.h"
+#include "mineral.h"
+#include "materials.h"
+#include "game.h"
+#include "keycode.h"
+#include "tile.h"
+
+#include "gettext.h"
+
+// This makes textures
+ITextureSource *g_texturesource = NULL;
+
+/*
+       Settings.
+       These are loaded from the config file.
+*/
+
+Settings g_settings;
+// This is located in defaultsettings.cpp
+extern void set_default_settings();
+
+// Global profiler
+Profiler g_profiler;
+
+/*
+       Random stuff
+*/
+
+/*
+       GUI Stuff
+*/
+
+gui::IGUIEnvironment* guienv = NULL;
+gui::IGUIStaticText *guiroot = NULL;
+
+MainMenuManager g_menumgr;
+
+bool noMenuActive()
+{
+       return (g_menumgr.menuCount() == 0);
+}
+
+// Passed to menus to allow disconnecting and exiting
+
+MainGameCallback *g_gamecallback = NULL;
+
+/*
+       Debug streams
+*/
+
+// Connection
+std::ostream *dout_con_ptr = &dummyout;
+std::ostream *derr_con_ptr = &dstream_no_stderr;
+//std::ostream *dout_con_ptr = &dstream_no_stderr;
+//std::ostream *derr_con_ptr = &dstream_no_stderr;
+//std::ostream *dout_con_ptr = &dstream;
+//std::ostream *derr_con_ptr = &dstream;
+
+// Server
+std::ostream *dout_server_ptr = &dstream;
+std::ostream *derr_server_ptr = &dstream;
+
+// Client
+std::ostream *dout_client_ptr = &dstream;
+std::ostream *derr_client_ptr = &dstream;
+
+/*
+       gettime.h implementation
+*/
+
+// A small helper class
+class TimeGetter
+{
+public:
+       virtual u32 getTime() = 0;
+};
+
+// A precise irrlicht one
+class IrrlichtTimeGetter: public TimeGetter
+{
+public:
+       IrrlichtTimeGetter(IrrlichtDevice *device):
+               m_device(device)
+       {}
+       u32 getTime()
+       {
+               if(m_device == NULL)
+                       return 0;
+               return m_device->getTimer()->getRealTime();
+       }
+private:
+       IrrlichtDevice *m_device;
+};
+// Not so precise one which works without irrlicht
+class SimpleTimeGetter: public TimeGetter
+{
+public:
+       u32 getTime()
+       {
+               return porting::getTimeMs();
+       }
+};
+
+// A pointer to a global instance of the time getter
+// TODO: why?
+TimeGetter *g_timegetter = NULL;
+
+u32 getTimeMs()
+{
+       if(g_timegetter == NULL)
+               return 0;
+       return g_timegetter->getTime();
+}
+
+/*
+       Event handler for Irrlicht
+
+       NOTE: Everything possible should be moved out from here,
+             probably to InputHandler and the_game
+*/
+
+class MyEventReceiver : public IEventReceiver
+{
+public:
+       // This is the one method that we have to implement
+       virtual bool OnEvent(const SEvent& event)
+       {
+               /*
+                       React to nothing here if a menu is active
+               */
+               if(noMenuActive() == false)
+               {
+                       return false;
+               }
+
+               // Remember whether each key is down or up
+               if(event.EventType == irr::EET_KEY_INPUT_EVENT)
+               {
+                       keyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
+
+                       if(event.KeyInput.PressedDown)
+                               keyWasDown[event.KeyInput.Key] = true;
+               }
+
+               if(event.EventType == irr::EET_MOUSE_INPUT_EVENT)
+               {
+                       if(noMenuActive() == false)
+                       {
+                               left_active = false;
+                               middle_active = false;
+                               right_active = false;
+                       }
+                       else
+                       {
+                               //dstream<<"MyEventReceiver: mouse input"<<std::endl;
+                               left_active = event.MouseInput.isLeftPressed();
+                               middle_active = event.MouseInput.isMiddlePressed();
+                               right_active = event.MouseInput.isRightPressed();
+
+                               if(event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
+                               {
+                                       leftclicked = true;
+                               }
+                               if(event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
+                               {
+                                       rightclicked = true;
+                               }
+                               if(event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
+                               {
+                                       leftreleased = true;
+                               }
+                               if(event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
+                               {
+                                       rightreleased = true;
+                               }
+                               if(event.MouseInput.Event == EMIE_MOUSE_WHEEL)
+                               {
+                                       mouse_wheel += event.MouseInput.Wheel;
+                               }
+                       }
+               }
+
+               return false;
+       }
+
+       bool IsKeyDown(EKEY_CODE keyCode) const
+       {
+               return keyIsDown[keyCode];
+       }
+       
+       // Checks whether a key was down and resets the state
+       bool WasKeyDown(EKEY_CODE keyCode)
+       {
+               bool b = keyWasDown[keyCode];
+               keyWasDown[keyCode] = false;
+               return b;
+       }
+
+       s32 getMouseWheel()
+       {
+               s32 a = mouse_wheel;
+               mouse_wheel = 0;
+               return a;
+       }
+
+       void clearInput()
+       {
+               for(u32 i=0; i<KEY_KEY_CODES_COUNT; i++)
+               {
+                       keyIsDown[i] = false;
+                       keyWasDown[i] = false;
+               }
+               
+               leftclicked = false;
+               rightclicked = false;
+               leftreleased = false;
+               rightreleased = false;
+
+               left_active = false;
+               middle_active = false;
+               right_active = false;
+
+               mouse_wheel = 0;
+       }
+
+       MyEventReceiver()
+       {
+               clearInput();
+       }
+
+       bool leftclicked;
+       bool rightclicked;
+       bool leftreleased;
+       bool rightreleased;
+
+       bool left_active;
+       bool middle_active;
+       bool right_active;
+
+       s32 mouse_wheel;
+
+private:
+       IrrlichtDevice *m_device;
+       
+       // The current state of keys
+       bool keyIsDown[KEY_KEY_CODES_COUNT];
+       // Whether a key has been pressed or not
+       bool keyWasDown[KEY_KEY_CODES_COUNT];
+};
+
+/*
+       Separated input handler
+*/
+
+class RealInputHandler : public InputHandler
+{
+public:
+       RealInputHandler(IrrlichtDevice *device, MyEventReceiver *receiver):
+               m_device(device),
+               m_receiver(receiver)
+       {
+       }
+       virtual bool isKeyDown(EKEY_CODE keyCode)
+       {
+               return m_receiver->IsKeyDown(keyCode);
+       }
+       virtual bool wasKeyDown(EKEY_CODE keyCode)
+       {
+               return m_receiver->WasKeyDown(keyCode);
+       }
+       virtual v2s32 getMousePos()
+       {
+               return m_device->getCursorControl()->getPosition();
+       }
+       virtual void setMousePos(s32 x, s32 y)
+       {
+               m_device->getCursorControl()->setPosition(x, y);
+       }
+
+       virtual bool getLeftState()
+       {
+               return m_receiver->left_active;
+       }
+       virtual bool getRightState()
+       {
+               return m_receiver->right_active;
+       }
+       
+       virtual bool getLeftClicked()
+       {
+               return m_receiver->leftclicked;
+       }
+       virtual bool getRightClicked()
+       {
+               return m_receiver->rightclicked;
+       }
+       virtual void resetLeftClicked()
+       {
+               m_receiver->leftclicked = false;
+       }
+       virtual void resetRightClicked()
+       {
+               m_receiver->rightclicked = false;
+       }
+
+       virtual bool getLeftReleased()
+       {
+               return m_receiver->leftreleased;
+       }
+       virtual bool getRightReleased()
+       {
+               return m_receiver->rightreleased;
+       }
+       virtual void resetLeftReleased()
+       {
+               m_receiver->leftreleased = false;
+       }
+       virtual void resetRightReleased()
+       {
+               m_receiver->rightreleased = false;
+       }
+
+       virtual s32 getMouseWheel()
+       {
+               return m_receiver->getMouseWheel();
+       }
+
+       void clear()
+       {
+               m_receiver->clearInput();
+       }
+private:
+       IrrlichtDevice *m_device;
+       MyEventReceiver *m_receiver;
+};
+
+class RandomInputHandler : public InputHandler
+{
+public:
+       RandomInputHandler()
+       {
+               leftdown = false;
+               rightdown = false;
+               leftclicked = false;
+               rightclicked = false;
+               leftreleased = false;
+               rightreleased = false;
+               for(u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
+                       keydown[i] = false;
+       }
+       virtual bool isKeyDown(EKEY_CODE keyCode)
+       {
+               return keydown[keyCode];
+       }
+       virtual bool wasKeyDown(EKEY_CODE keyCode)
+       {
+               return false;
+       }
+       virtual v2s32 getMousePos()
+       {
+               return mousepos;
+       }
+       virtual void setMousePos(s32 x, s32 y)
+       {
+               mousepos = v2s32(x,y);
+       }
+
+       virtual bool getLeftState()
+       {
+               return leftdown;
+       }
+       virtual bool getRightState()
+       {
+               return rightdown;
+       }
+
+       virtual bool getLeftClicked()
+       {
+               return leftclicked;
+       }
+       virtual bool getRightClicked()
+       {
+               return rightclicked;
+       }
+       virtual void resetLeftClicked()
+       {
+               leftclicked = false;
+       }
+       virtual void resetRightClicked()
+       {
+               rightclicked = false;
+       }
+
+       virtual bool getLeftReleased()
+       {
+               return leftreleased;
+       }
+       virtual bool getRightReleased()
+       {
+               return rightreleased;
+       }
+       virtual void resetLeftReleased()
+       {
+               leftreleased = false;
+       }
+       virtual void resetRightReleased()
+       {
+               rightreleased = false;
+       }
+
+       virtual s32 getMouseWheel()
+       {
+               return 0;
+       }
+
+       virtual void step(float dtime)
+       {
+               {
+                       static float counter1 = 0;
+                       counter1 -= dtime;
+                       if(counter1 < 0.0)
+                       {
+                               counter1 = 0.1*Rand(1, 40);
+                               keydown[getKeySetting("keymap_jump")] =
+                                               !keydown[getKeySetting("keymap_jump")];
+                       }
+               }
+               {
+                       static float counter1 = 0;
+                       counter1 -= dtime;
+                       if(counter1 < 0.0)
+                       {
+                               counter1 = 0.1*Rand(1, 40);
+                               keydown[getKeySetting("keymap_special1")] =
+                                               !keydown[getKeySetting("keymap_special1")];
+                       }
+               }
+               {
+                       static float counter1 = 0;
+                       counter1 -= dtime;
+                       if(counter1 < 0.0)
+                       {
+                               counter1 = 0.1*Rand(1, 40);
+                               keydown[getKeySetting("keymap_forward")] =
+                                               !keydown[getKeySetting("keymap_forward")];
+                       }
+               }
+               {
+                       static float counter1 = 0;
+                       counter1 -= dtime;
+                       if(counter1 < 0.0)
+                       {
+                               counter1 = 0.1*Rand(1, 40);
+                               keydown[getKeySetting("keymap_left")] =
+                                               !keydown[getKeySetting("keymap_left")];
+                       }
+               }
+               {
+                       static float counter1 = 0;
+                       counter1 -= dtime;
+                       if(counter1 < 0.0)
+                       {
+                               counter1 = 0.1*Rand(1, 20);
+                               mousespeed = v2s32(Rand(-20,20), Rand(-15,20));
+                       }
+               }
+               {
+                       static float counter1 = 0;
+                       counter1 -= dtime;
+                       if(counter1 < 0.0)
+                       {
+                               counter1 = 0.1*Rand(1, 30);
+                               leftdown = !leftdown;
+                               if(leftdown)
+                                       leftclicked = true;
+                               if(!leftdown)
+                                       leftreleased = true;
+                       }
+               }
+               {
+                       static float counter1 = 0;
+                       counter1 -= dtime;
+                       if(counter1 < 0.0)
+                       {
+                               counter1 = 0.1*Rand(1, 15);
+                               rightdown = !rightdown;
+                               if(rightdown)
+                                       rightclicked = true;
+                               if(!rightdown)
+                                       rightreleased = true;
+                       }
+               }
+               mousepos += mousespeed;
+       }
+
+       s32 Rand(s32 min, s32 max)
+       {
+               return (myrand()%(max-min+1))+min;
+       }
+private:
+       bool keydown[KEY_KEY_CODES_COUNT];
+       v2s32 mousepos;
+       v2s32 mousespeed;
+       bool leftdown;
+       bool rightdown;
+       bool leftclicked;
+       bool rightclicked;
+       bool leftreleased;
+       bool rightreleased;
+};
+
+// These are defined global so that they're not optimized too much.
+// Can't change them to volatile.
+s16 temp16;
+f32 tempf;
+v3f tempv3f1;
+v3f tempv3f2;
+std::string tempstring;
+std::string tempstring2;
+
+void SpeedTests()
+{
+       {
+               dstream<<"The following test should take around 20ms."<<std::endl;
+               TimeTaker timer("Testing std::string speed");
+               const u32 jj = 10000;
+               for(u32 j=0; j<jj; j++)
+               {
+                       tempstring = "";
+                       tempstring2 = "";
+                       const u32 ii = 10;
+                       for(u32 i=0; i<ii; i++){
+                               tempstring2 += "asd";
+                       }
+                       for(u32 i=0; i<ii+1; i++){
+                               tempstring += "asd";
+                               if(tempstring == tempstring2)
+                                       break;
+                       }
+               }
+       }
+       
+       dstream<<"All of the following tests should take around 100ms each."
+                       <<std::endl;
+
+       {
+               TimeTaker timer("Testing floating-point conversion speed");
+               tempf = 0.001;
+               for(u32 i=0; i<4000000; i++){
+                       temp16 += tempf;
+                       tempf += 0.001;
+               }
+       }
+       
+       {
+               TimeTaker timer("Testing floating-point vector speed");
+
+               tempv3f1 = v3f(1,2,3);
+               tempv3f2 = v3f(4,5,6);
+               for(u32 i=0; i<10000000; i++){
+                       tempf += tempv3f1.dotProduct(tempv3f2);
+                       tempv3f2 += v3f(7,8,9);
+               }
+       }
+
+       {
+               TimeTaker timer("Testing core::map speed");
+               
+               core::map<v2s16, f32> map1;
+               tempf = -324;
+               const s16 ii=300;
+               for(s16 y=0; y<ii; y++){
+                       for(s16 x=0; x<ii; x++){
+                               map1.insert(v2s16(x,y), tempf);
+                               tempf += 1;
+                       }
+               }
+               for(s16 y=ii-1; y>=0; y--){
+                       for(s16 x=0; x<ii; x++){
+                               tempf = map1[v2s16(x,y)];
+                       }
+               }
+       }
+
+       {
+               dstream<<"Around 5000/ms should do well here."<<std::endl;
+               TimeTaker timer("Testing mutex speed");
+               
+               JMutex m;
+               m.Init();
+               u32 n = 0;
+               u32 i = 0;
+               do{
+                       n += 10000;
+                       for(; i<n; i++){
+                               m.Lock();
+                               m.Unlock();
+                       }
+               }
+               // Do at least 10ms
+               while(timer.getTime() < 10);
+
+               u32 dtime = timer.stop();
+               u32 per_ms = n / dtime;
+               std::cout<<"Done. "<<dtime<<"ms, "
+                               <<per_ms<<"/ms"<<std::endl;
+       }
+}
+
+void drawMenuBackground(video::IVideoDriver* driver)
+{
+       core::dimension2d<u32> screensize = driver->getScreenSize();
+               
+       video::ITexture *bgtexture =
+                       driver->getTexture(getTexturePath("mud.png").c_str());
+       if(bgtexture)
+       {
+               s32 texturesize = 128;
+               s32 tiled_y = screensize.Height / texturesize + 1;
+               s32 tiled_x = screensize.Width / texturesize + 1;
+               
+               for(s32 y=0; y<tiled_y; y++)
+               for(s32 x=0; x<tiled_x; x++)
+               {
+                       core::rect<s32> rect(0,0,texturesize,texturesize);
+                       rect += v2s32(x*texturesize, y*texturesize);
+                       driver->draw2DImage(bgtexture, rect,
+                               core::rect<s32>(core::position2d<s32>(0,0),
+                               core::dimension2di(bgtexture->getSize())),
+                               NULL, NULL, true);
+               }
+       }
+       
+       video::ITexture *logotexture =
+                       driver->getTexture(getTexturePath("menulogo.png").c_str());
+       if(logotexture)
+       {
+               v2s32 logosize(logotexture->getOriginalSize().Width,
+                               logotexture->getOriginalSize().Height);
+               logosize *= 4;
+
+               video::SColor bgcolor(255,50,50,50);
+               core::rect<s32> bgrect(0, screensize.Height-logosize.Y-20,
+                               screensize.Width, screensize.Height);
+               driver->draw2DRectangle(bgcolor, bgrect, NULL);
+
+               core::rect<s32> rect(0,0,logosize.X,logosize.Y);
+               rect += v2s32(screensize.Width/2,screensize.Height-10-logosize.Y);
+               rect -= v2s32(logosize.X/2, 0);
+               driver->draw2DImage(logotexture, rect,
+                       core::rect<s32>(core::position2d<s32>(0,0),
+                       core::dimension2di(logotexture->getSize())),
+                       NULL, NULL, true);
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       /*
+               Initialization
+       */
+
+       // Set locale. This is for forcing '.' as the decimal point.
+       std::locale::global(std::locale("C"));
+       // This enables printing all characters in bitmap font
+       setlocale(LC_CTYPE, "en_US");
+
+       /*
+               Parse command line
+       */
+       
+       // List all allowed options
+       core::map<std::string, ValueSpec> allowed_options;
+       allowed_options.insert("help", ValueSpec(VALUETYPE_FLAG));
+       allowed_options.insert("server", ValueSpec(VALUETYPE_FLAG,
+                       "Run server directly"));
+       allowed_options.insert("config", ValueSpec(VALUETYPE_STRING,
+                       "Load configuration from specified file"));
+       allowed_options.insert("port", ValueSpec(VALUETYPE_STRING));
+       allowed_options.insert("address", ValueSpec(VALUETYPE_STRING));
+       allowed_options.insert("random-input", ValueSpec(VALUETYPE_FLAG));
+       allowed_options.insert("disable-unittests", ValueSpec(VALUETYPE_FLAG));
+       allowed_options.insert("enable-unittests", ValueSpec(VALUETYPE_FLAG));
+       allowed_options.insert("map-dir", ValueSpec(VALUETYPE_STRING));
+#ifdef _WIN32
+       allowed_options.insert("dstream-on-stderr", ValueSpec(VALUETYPE_FLAG));
+#endif
+       allowed_options.insert("speedtests", ValueSpec(VALUETYPE_FLAG));
+
+       Settings cmd_args;
+       
+       bool ret = cmd_args.parseCommandLine(argc, argv, allowed_options);
+
+       if(ret == false || cmd_args.getFlag("help"))
+       {
+               dstream<<"Allowed options:"<<std::endl;
+               for(core::map<std::string, ValueSpec>::Iterator
+                               i = allowed_options.getIterator();
+                               i.atEnd() == false; i++)
+               {
+                       dstream<<"  --"<<i.getNode()->getKey();
+                       if(i.getNode()->getValue().type == VALUETYPE_FLAG)
+                       {
+                       }
+                       else
+                       {
+                               dstream<<" <value>";
+                       }
+                       dstream<<std::endl;
+
+                       if(i.getNode()->getValue().help != NULL)
+                       {
+                               dstream<<"      "<<i.getNode()->getValue().help
+                                               <<std::endl;
+                       }
+               }
+
+               return cmd_args.getFlag("help") ? 0 : 1;
+       }
+       
+       /*
+               Low-level initialization
+       */
+
+       bool disable_stderr = false;
+#ifdef _WIN32
+       if(cmd_args.getFlag("dstream-on-stderr") == false)
+               disable_stderr = true;
+#endif
+
+       porting::signal_handler_init();
+       bool &kill = *porting::signal_handler_killstatus();
+       
+       // Initialize porting::path_data and porting::path_userdata
+       porting::initializePaths();
+
+       // Create user data directory
+       fs::CreateDir(porting::path_userdata);
+
+       setlocale(LC_MESSAGES, "");
+       bindtextdomain("minetest", (porting::path_userdata+"/locale").c_str());
+       textdomain("minetest");
+       
+       // Initialize debug streams
+#ifdef RUN_IN_PLACE
+       std::string debugfile = DEBUGFILE;
+#else
+       std::string debugfile = porting::path_userdata+"/"+DEBUGFILE;
+#endif
+       debugstreams_init(disable_stderr, debugfile.c_str());
+       // Initialize debug stacks
+       debug_stacks_init();
+
+       DSTACK(__FUNCTION_NAME);
+
+       // Init material properties table
+       //initializeMaterialProperties();
+
+       // Debug handler
+       BEGIN_DEBUG_EXCEPTION_HANDLER
+
+       // Print startup message
+       dstream<<DTIME<<"minetest-c55"
+                       " with SER_FMT_VER_HIGHEST="<<(int)SER_FMT_VER_HIGHEST
+                       <<", "<<BUILD_INFO
+                       <<std::endl;
+       
+       /*
+               Basic initialization
+       */
+
+       // Initialize default settings
+       set_default_settings();
+       
+       // Initialize sockets
+       sockets_init();
+       atexit(sockets_cleanup);
+       
+       /*
+               Read config file
+       */
+       
+       // Path of configuration file in use
+       std::string configpath = "";
+       
+       if(cmd_args.exists("config"))
+       {
+               bool r = g_settings.readConfigFile(cmd_args.get("config").c_str());
+               if(r == false)
+               {
+                       dstream<<"Could not read configuration from \""
+                                       <<cmd_args.get("config")<<"\""<<std::endl;
+                       return 1;
+               }
+               configpath = cmd_args.get("config");
+       }
+       else
+       {
+               core::array<std::string> filenames;
+               filenames.push_back(porting::path_userdata + "/minetest.conf");
+#ifdef RUN_IN_PLACE
+               filenames.push_back(porting::path_userdata + "/../minetest.conf");
+#endif
+
+               for(u32 i=0; i<filenames.size(); i++)
+               {
+                       bool r = g_settings.readConfigFile(filenames[i].c_str());
+                       if(r)
+                       {
+                               configpath = filenames[i];
+                               break;
+                       }
+               }
+               
+               // If no path found, use the first one (menu creates the file)
+               if(configpath == "")
+                       configpath = filenames[0];
+       }
+
+       // Initialize random seed
+       srand(time(0));
+       mysrand(time(0));
+
+       /*
+               Pre-initialize some stuff with a dummy irrlicht wrapper.
+
+               These are needed for unit tests at least.
+       */
+       
+       // Initial call with g_texturesource not set.
+       init_mapnode();
+
+       /*
+               Run unit tests
+       */
+
+       if((ENABLE_TESTS && cmd_args.getFlag("disable-unittests") == false)
+                       || cmd_args.getFlag("enable-unittests") == true)
+       {
+               run_tests();
+       }
+       
+       /*for(s16 y=-100; y<100; y++)
+       for(s16 x=-100; x<100; x++)
+       {
+               std::cout<<noise2d_gradient((double)x/10,(double)y/10, 32415)<<std::endl;
+       }
+       return 0;*/
+       
+       /*
+               Game parameters
+       */
+
+       // Port
+       u16 port = 30000;
+       if(cmd_args.exists("port"))
+               port = cmd_args.getU16("port");
+       else if(g_settings.exists("port"))
+               port = g_settings.getU16("port");
+       if(port == 0)
+               port = 30000;
+       
+       // Map directory
+       std::string map_dir = porting::path_userdata+"/world";
+       if(cmd_args.exists("map-dir"))
+               map_dir = cmd_args.get("map-dir");
+       else if(g_settings.exists("map-dir"))
+               map_dir = g_settings.get("map-dir");
+       
+       // Run dedicated server if asked to
+       if(cmd_args.getFlag("server"))
+       {
+               DSTACK("Dedicated server branch");
+
+               // Create time getter
+               g_timegetter = new SimpleTimeGetter();
+               
+               // Create server
+               Server server(map_dir.c_str());
+               server.start(port);
+               
+               // Run server
+               dedicated_server_loop(server, kill);
+
+               return 0;
+       }
+
+
+       /*
+               More parameters
+       */
+       
+       // Address to connect to
+       std::string address = "";
+       
+       if(cmd_args.exists("address"))
+       {
+               address = cmd_args.get("address");
+       }
+       else
+       {
+               address = g_settings.get("address");
+       }
+       
+       std::string playername = g_settings.get("name");
+
+       /*
+               Device initialization
+       */
+
+       // Resolution selection
+       
+       bool fullscreen = false;
+       u16 screenW = g_settings.getU16("screenW");
+       u16 screenH = g_settings.getU16("screenH");
+
+       // Determine driver
+
+       video::E_DRIVER_TYPE driverType;
+       
+       std::string driverstring = g_settings.get("video_driver");
+
+       if(driverstring == "null")
+               driverType = video::EDT_NULL;
+       else if(driverstring == "software")
+               driverType = video::EDT_SOFTWARE;
+       else if(driverstring == "burningsvideo")
+               driverType = video::EDT_BURNINGSVIDEO;
+       else if(driverstring == "direct3d8")
+               driverType = video::EDT_DIRECT3D8;
+       else if(driverstring == "direct3d9")
+               driverType = video::EDT_DIRECT3D9;
+       else if(driverstring == "opengl")
+               driverType = video::EDT_OPENGL;
+       else
+       {
+               dstream<<"WARNING: Invalid video_driver specified; defaulting "
+                               "to opengl"<<std::endl;
+               driverType = video::EDT_OPENGL;
+       }
+
+       /*
+               Create device and exit if creation failed
+       */
+
+       MyEventReceiver receiver;
+
+       IrrlichtDevice *device;
+       device = createDevice(driverType,
+                       core::dimension2d<u32>(screenW, screenH),
+                       16, fullscreen, false, false, &receiver);
+
+       if (device == 0)
+               return 1; // could not create selected driver.
+       
+       // Set device in game parameters
+       device = device;
+
+       // Set the window caption
+       device->setWindowCaption(L"Minetest [Main Menu]");
+       
+       // Create time getter
+       g_timegetter = new IrrlichtTimeGetter(device);
+       
+       // Create game callback for menus
+       g_gamecallback = new MainGameCallback(device);
+       
+       // Create texture source
+       g_texturesource = new TextureSource(device);
+
+       /*
+               Speed tests (done after irrlicht is loaded to get timer)
+       */
+       if(cmd_args.getFlag("speedtests"))
+       {
+               dstream<<"Running speed tests"<<std::endl;
+               SpeedTests();
+               return 0;
+       }
+       
+       device->setResizable(true);
+
+       bool random_input = g_settings.getBool("random_input")
+                       || cmd_args.getFlag("random-input");
+       InputHandler *input = NULL;
+       if(random_input)
+               input = new RandomInputHandler();
+       else
+               input = new RealInputHandler(device, &receiver);
+       
+       /*
+               Continue initialization
+       */
+
+       //video::IVideoDriver* driver = device->getVideoDriver();
+
+       /*
+               This changes the minimum allowed number of vertices in a VBO.
+               Default is 500.
+       */
+       //driver->setMinHardwareBufferVertexCount(50);
+
+       scene::ISceneManager* smgr = device->getSceneManager();
+
+       guienv = device->getGUIEnvironment();
+       gui::IGUISkin* skin = guienv->getSkin();
+       gui::IGUIFont* font = guienv->getFont(getTexturePath("fontlucida.png").c_str());
+       if(font)
+               skin->setFont(font);
+       else
+               dstream<<"WARNING: Font file was not found."
+                               " Using default font."<<std::endl;
+       // If font was not found, this will get us one
+       font = skin->getFont();
+       assert(font);
+       
+       u32 text_height = font->getDimension(L"Hello, world!").Height;
+       dstream<<"text_height="<<text_height<<std::endl;
+
+       //skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,0,0,0));
+       skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255,255,255,255));
+       //skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(0,0,0,0));
+       //skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(0,0,0,0));
+       skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255,0,0,0));
+       skin->setColor(gui::EGDC_3D_SHADOW, video::SColor(255,0,0,0));
+       
+       /*
+               Preload some textures and stuff
+       */
+
+       init_mapnode(); // Second call with g_texturesource set
+       init_mineral();
+
+       /*
+               GUI stuff
+       */
+
+       /*
+               If an error occurs, this is set to something and the
+               menu-game loop is restarted. It is then displayed before
+               the menu.
+       */
+       std::wstring error_message = L"";
+
+       // The password entered during the menu screen,
+       std::string password;
+
+       /*
+               Menu-game loop
+       */
+       while(device->run() && kill == false)
+       {
+
+               // This is used for catching disconnects
+               try
+               {
+
+                       /*
+                               Clear everything from the GUIEnvironment
+                       */
+                       guienv->clear();
+                       
+                       /*
+                               We need some kind of a root node to be able to add
+                               custom gui elements directly on the screen.
+                               Otherwise they won't be automatically drawn.
+                       */
+                       guiroot = guienv->addStaticText(L"",
+                                       core::rect<s32>(0, 0, 10000, 10000));
+                       
+                       /*
+                               Out-of-game menu loop.
+
+                               Loop quits when menu returns proper parameters.
+                       */
+                       while(kill == false)
+                       {
+                               // Cursor can be non-visible when coming from the game
+                               device->getCursorControl()->setVisible(true);
+                               // Some stuff are left to scene manager when coming from the game
+                               // (map at least?)
+                               smgr->clear();
+                               // Reset or hide the debug gui texts
+                               /*guitext->setText(L"Minetest-c55");
+                               guitext2->setVisible(false);
+                               guitext_info->setVisible(false);
+                               guitext_chat->setVisible(false);*/
+                               
+                               // Initialize menu data
+                               MainMenuData menudata;
+                               menudata.address = narrow_to_wide(address);
+                               menudata.name = narrow_to_wide(playername);
+                               menudata.port = narrow_to_wide(itos(port));
+                               menudata.fancy_trees = g_settings.getBool("new_style_leaves");
+                               menudata.smooth_lighting = g_settings.getBool("smooth_lighting");
+                               menudata.creative_mode = g_settings.getBool("creative_mode");
+                               menudata.enable_damage = g_settings.getBool("enable_damage");
+
+                               GUIMainMenu *menu =
+                                               new GUIMainMenu(guienv, guiroot, -1, 
+                                                       &g_menumgr, &menudata, g_gamecallback);
+                               menu->allowFocusRemoval(true);
+
+                               if(error_message != L"")
+                               {
+                                       dstream<<"WARNING: error_message = "
+                                                       <<wide_to_narrow(error_message)<<std::endl;
+
+                                       GUIMessageMenu *menu2 =
+                                                       new GUIMessageMenu(guienv, guiroot, -1, 
+                                                               &g_menumgr, error_message.c_str());
+                                       menu2->drop();
+                                       error_message = L"";
+                               }
+
+                               video::IVideoDriver* driver = device->getVideoDriver();
+                               
+                               dstream<<"Created main menu"<<std::endl;
+
+                               while(device->run() && kill == false)
+                               {
+                                       if(menu->getStatus() == true)
+                                               break;
+
+                                       //driver->beginScene(true, true, video::SColor(255,0,0,0));
+                                       driver->beginScene(true, true, video::SColor(255,128,128,128));
+
+                                       drawMenuBackground(driver);
+
+                                       guienv->drawAll();
+                                       
+                                       driver->endScene();
+                                       
+                                       // On some computers framerate doesn't seem to be
+                                       // automatically limited
+                                       sleep_ms(25);
+                               }
+                               
+                               // Break out of menu-game loop to shut down cleanly
+                               if(device->run() == false || kill == true)
+                                       break;
+                               
+                               dstream<<"Dropping main menu"<<std::endl;
+
+                               menu->drop();
+                               
+                               // Delete map if requested
+                               if(menudata.delete_map)
+                               {
+                                       bool r = fs::RecursiveDeleteContent(map_dir);
+                                       if(r == false)
+                                               error_message = L"Delete failed";
+                                       continue;
+                               }
+
+                               playername = wide_to_narrow(menudata.name);
+
+                               password = translatePassword(playername, menudata.password);
+
+                               address = wide_to_narrow(menudata.address);
+                               int newport = stoi(wide_to_narrow(menudata.port));
+                               if(newport != 0)
+                                       port = newport;
+                               g_settings.set("new_style_leaves", itos(menudata.fancy_trees));
+                               g_settings.set("smooth_lighting", itos(menudata.smooth_lighting));
+                               g_settings.set("creative_mode", itos(menudata.creative_mode));
+                               g_settings.set("enable_damage", itos(menudata.enable_damage));
+                               
+                               // NOTE: These are now checked server side; no need to do it
+                               //       here, so let's not do it here.
+                               /*// Check for valid parameters, restart menu if invalid.
+                               if(playername == "")
+                               {
+                                       error_message = L"Name required.";
+                                       continue;
+                               }
+                               // Check that name has only valid chars
+                               if(string_allowed(playername, PLAYERNAME_ALLOWED_CHARS)==false)
+                               {
+                                       error_message = L"Characters allowed: "
+                                                       +narrow_to_wide(PLAYERNAME_ALLOWED_CHARS);
+                                       continue;
+                               }*/
+
+                               // Save settings
+                               g_settings.set("name", playername);
+                               g_settings.set("address", address);
+                               g_settings.set("port", itos(port));
+                               // Update configuration file
+                               if(configpath != "")
+                                       g_settings.updateConfigFile(configpath.c_str());
+                       
+                               // Continue to game
+                               break;
+                       }
+                       
+                       // Break out of menu-game loop to shut down cleanly
+                       if(device->run() == false)
+                               break;
+                       
+                       // Initialize mapnode again to enable changed graphics settings
+                       init_mapnode();
+
+                       /*
+                               Run game
+                       */
+                       the_game(
+                               kill,
+                               random_input,
+                               input,
+                               device,
+                               font,
+                               map_dir,
+                               playername,
+                               password,
+                               address,
+                               port,
+                               error_message
+                       );
+
+               } //try
+               catch(con::PeerNotFoundException &e)
+               {
+                       dstream<<DTIME<<"Connection error (timed out?)"<<std::endl;
+                       error_message = L"Connection error (timed out?)";
+               }
+               catch(SocketException &e)
+               {
+                       dstream<<DTIME<<"Socket error (port already in use?)"<<std::endl;
+                       error_message = L"Socket error (port already in use?)";
+               }
+#ifdef NDEBUG
+               catch(std::exception &e)
+               {
+                       std::string narrow_message = "Some exception, what()=\"";
+                       narrow_message += e.what();
+                       narrow_message += "\"";
+                       dstream<<DTIME<<narrow_message<<std::endl;
+                       error_message = narrow_to_wide(narrow_message);
+               }
+#endif
+
+       } // Menu-game loop
+       
+       delete input;
+
+       /*
+               In the end, delete the Irrlicht device.
+       */
+       device->drop();
+       
+       END_DEBUG_EXCEPTION_HANDLER
+       
+       debugstreams_deinit();
+       
+       return 0;
+}
+
+//END
+
index 8bce36f2530113541c2cbd47c037f627309849e5..f0ea2f6f1f84f346b8988c0ce7ab56a79baca625 100644 (file)
@@ -630,9 +630,9 @@ s16 Map::propagateSunlight(v3s16 start,
                else
                {
                        /*// Turn mud into grass
-                       if(n.d == CONTENT_MUD)
+                       if(n.getContent() == CONTENT_MUD)
                        {
-                               n.d = CONTENT_GRASS;
+                               n.setContent(CONTENT_GRASS);
                                block->setNode(relpos, n);
                                modified_blocks.insert(blockpos, block);
                        }*/
@@ -920,15 +920,15 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
        /*
                If the new node is solid and there is grass below, change it to mud
        */
-       if(content_features(n.d).walkable == true)
+       if(content_features(n).walkable == true)
        {
                try{
                        MapNode bottomnode = getNode(bottompos);
 
-                       if(bottomnode.d == CONTENT_GRASS
-                                       || bottomnode.d == CONTENT_GRASS_FOOTSTEPS)
+                       if(bottomnode.getContent() == CONTENT_GRASS
+                                       || bottomnode.getContent() == CONTENT_GRASS_FOOTSTEPS)
                        {
-                               bottomnode.d = CONTENT_MUD;
+                               bottomnode.setContent(CONTENT_MUD);
                                setNode(bottompos, bottomnode);
                        }
                }
@@ -943,9 +943,9 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                If the new node is mud and it is under sunlight, change it
                to grass
        */
-       if(n.d == CONTENT_MUD && node_under_sunlight)
+       if(n.getContent() == CONTENT_MUD && node_under_sunlight)
        {
-               n.d = CONTENT_GRASS;
+               n.setContent(CONTENT_GRASS);
        }
 #endif
 
@@ -986,7 +986,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                If node lets sunlight through and is under sunlight, it has
                sunlight too.
        */
-       if(node_under_sunlight && content_features(n.d).sunlight_propagates)
+       if(node_under_sunlight && content_features(n).sunlight_propagates)
        {
                n.setLight(LIGHTBANK_DAY, LIGHT_SUN);
        }
@@ -1001,7 +1001,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                Add intial metadata
        */
 
-       NodeMetadata *meta_proto = content_features(n.d).initial_metadata;
+       NodeMetadata *meta_proto = content_features(n).initial_metadata;
        if(meta_proto)
        {
                NodeMetadata *meta = meta_proto->clone();
@@ -1015,7 +1015,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                TODO: This could be optimized by mass-unlighting instead
                          of looping
        */
-       if(node_under_sunlight && !content_features(n.d).sunlight_propagates)
+       if(node_under_sunlight && !content_features(n).sunlight_propagates)
        {
                s16 y = p.Y - 1;
                for(;; y--){
@@ -1086,7 +1086,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
                v3s16 p2 = p + dirs[i];
 
                MapNode n2 = getNode(p2);
-               if(content_liquid(n2.d))
+               if(content_liquid(n2.getContent()))
                {
                        m_transforming_liquid.push_back(p2);
                }
@@ -1111,7 +1111,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
        v3s16 toppos = p + v3s16(0,1,0);
 
        // Node will be replaced with this
-       u8 replace_material = CONTENT_AIR;
+       content_t replace_material = CONTENT_AIR;
 
        /*
                If there is a node at top and it doesn't have sunlight,
@@ -1158,7 +1158,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
        */
 
        MapNode n;
-       n.d = replace_material;
+       n.setContent(replace_material);
        setNode(p, n);
 
        for(s32 i=0; i<2; i++)
@@ -1240,17 +1240,19 @@ void Map::removeNodeAndUpdate(v3s16 p,
        }
 
        /*
-               Add neighboring liquid nodes to transform queue.
+               Add neighboring liquid nodes and this node to transform queue.
+               (it's vital for the node itself to get updated last.)
        */
-       v3s16 dirs[6] = {
+       v3s16 dirs[7] = {
                v3s16(0,0,1), // back
                v3s16(0,1,0), // top
                v3s16(1,0,0), // right
                v3s16(0,0,-1), // front
                v3s16(0,-1,0), // bottom
                v3s16(-1,0,0), // left
+               v3s16(0,0,0), // self
        };
-       for(u16 i=0; i<6; i++)
+       for(u16 i=0; i<7; i++)
        {
                try
                {
@@ -1258,7 +1260,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
                v3s16 p2 = p + dirs[i];
 
                MapNode n2 = getNode(p2);
-               if(content_liquid(n2.d))
+               if(content_liquid(n2.getContent()))
                {
                        m_transforming_liquid.push_back(p2);
                }
@@ -1559,17 +1561,17 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                MapNode n0 = getNodeNoEx(p0);
 
                // Don't deal with non-liquids
-               if(content_liquid(n0.d) == false)
+               if(content_liquid(n0.getContent()) == false)
                        continue;
 
-               bool is_source = !content_flowing_liquid(n0.d);
+               bool is_source = !content_flowing_liquid(n0.getContent());
 
                u8 liquid_level = 8;
                if(is_source == false)
                        liquid_level = n0.param2 & 0x0f;
 
                // Turn possible source into non-source
-               u8 nonsource_c = make_liquid_flowing(n0.d);
+               u8 nonsource_c = make_liquid_flowing(n0.getContent());
 
                /*
                        If not source, check that some node flows into this one
@@ -1593,9 +1595,9 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                                v3s16 p2 = p0 + dirs_from[i];
                                MapNode n2 = getNodeNoEx(p2);
 
-                               if(content_liquid(n2.d))
+                               if(content_liquid(n2.getContent()))
                                {
-                                       u8 n2_nonsource_c = make_liquid_flowing(n2.d);
+                                       u8 n2_nonsource_c = make_liquid_flowing(n2.getContent());
                                        // Check that the liquids are the same type
                                        if(n2_nonsource_c != nonsource_c)
                                        {
@@ -1603,7 +1605,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                                                                " collide"<<std::endl;
                                                continue;
                                        }
-                                       bool n2_is_source = !content_flowing_liquid(n2.d);
+                                       bool n2_is_source = !content_flowing_liquid(n2.getContent());
                                        s8 n2_liquid_level = 8;
                                        if(n2_is_source == false)
                                                n2_liquid_level = n2.param2 & 0x07;
@@ -1636,7 +1638,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                                if(new_liquid_level_max == -1)
                                {
                                        // Remove water alltoghether
-                                       n0.d = CONTENT_AIR;
+                                       n0.setContent(CONTENT_AIR);
                                        n0.param2 = 0;
                                        setNode(p0, n0);
                                }
@@ -1670,7 +1672,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                                        v3s16 p2 = p0 + dirs[i];
 
                                        MapNode n2 = getNodeNoEx(p2);
-                                       if(content_flowing_liquid(n2.d))
+                                       if(content_flowing_liquid(n2.getContent()))
                                        {
                                                m_transforming_liquid.push_back(p2);
                                        }
@@ -1679,7 +1681,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                }
 
                // Get a new one from queue if the node has turned into non-water
-               if(content_liquid(n0.d) == false)
+               if(content_liquid(n0.getContent()) == false)
                        continue;
 
                /*
@@ -1722,9 +1724,9 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                        MapNode n2 = getNodeNoEx(p2);
                        //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl;
 
-                       if(content_liquid(n2.d))
+                       if(content_liquid(n2.getContent()))
                        {
-                               u8 n2_nonsource_c = make_liquid_flowing(n2.d);
+                               u8 n2_nonsource_c = make_liquid_flowing(n2.getContent());
                                // Check that the liquids are the same type
                                if(n2_nonsource_c != nonsource_c)
                                {
@@ -1732,7 +1734,7 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                                                        " collide"<<std::endl;
                                        continue;
                                }
-                               bool n2_is_source = !content_flowing_liquid(n2.d);
+                               bool n2_is_source = !content_flowing_liquid(n2.getContent());
                                u8 n2_liquid_level = 8;
                                if(n2_is_source == false)
                                        n2_liquid_level = n2.param2 & 0x07;
@@ -1760,9 +1762,9 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks)
                                        }
                                }
                        }
-                       else if(n2.d == CONTENT_AIR)
+                       else if(n2.getContent() == CONTENT_AIR)
                        {
-                               n2.d = nonsource_c;
+                               n2.setContent(nonsource_c);
                                n2.param2 = liquid_next_level;
                                setNode(p2, n2);
 
@@ -2010,9 +2012,17 @@ ServerMap::~ServerMap()
 
 void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
 {
-       /*dstream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
-                       <<blockpos.Z<<")"<<std::endl;*/
-
+       dstream<<"initBlockMake(): ("<<blockpos.X<<","<<blockpos.Y<<","
+                       <<blockpos.Z<<")"<<std::endl;
+       
+       // Do nothing if not inside limits (+-1 because of neighbors)
+       if(blockpos_over_limit(blockpos - v3s16(1,1,1)) ||
+               blockpos_over_limit(blockpos + v3s16(1,1,1)))
+       {
+               data->no_op = true;
+               return;
+       }
+       
        data->no_op = false;
        data->seed = m_seed;
        data->blockpos = blockpos;
@@ -2066,6 +2076,7 @@ void ServerMap::initBlockMake(mapgen::BlockMakeData *data, v3s16 blockpos)
                neighboring blocks
        */
        
+       // The area that contains this block and it's neighbors
        v3s16 bigarea_blocks_min = blockpos - v3s16(1,1,1);
        v3s16 bigarea_blocks_max = blockpos + v3s16(1,1,1);
        
@@ -2090,7 +2101,7 @@ MapBlock* ServerMap::finishBlockMake(mapgen::BlockMakeData *data,
 
        if(data->no_op)
        {
-               dstream<<"finishBlockMake(): no-op"<<std::endl;
+               //dstream<<"finishBlockMake(): no-op"<<std::endl;
                return NULL;
        }
 
@@ -2373,49 +2384,54 @@ MapBlock * ServerMap::generateBlock(
                Get central block
        */
        MapBlock *block = getBlockNoCreateNoEx(p);
-       assert(block);
 
 #if 0
        /*
                Check result
        */
-       bool erroneus_content = false;
-       for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
-       for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
-       for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
-       {
-               v3s16 p(x0,y0,z0);
-               MapNode n = block->getNode(p);
-               if(n.d == CONTENT_IGNORE)
+       if(block)
+       {
+               bool erroneus_content = false;
+               for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+               for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+               for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+               {
+                       v3s16 p(x0,y0,z0);
+                       MapNode n = block->getNode(p);
+                       if(n.getContent() == CONTENT_IGNORE)
+                       {
+                               dstream<<"CONTENT_IGNORE at "
+                                               <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
+                                               <<std::endl;
+                               erroneus_content = true;
+                               assert(0);
+                       }
+               }
+               if(erroneus_content)
                {
-                       dstream<<"CONTENT_IGNORE at "
-                                       <<"("<<p.X<<","<<p.Y<<","<<p.Z<<")"
-                                       <<std::endl;
-                       erroneus_content = true;
                        assert(0);
                }
        }
-       if(erroneus_content)
-       {
-               assert(0);
-       }
 #endif
 
 #if 0
        /*
                Generate a completely empty block
        */
-       for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
-       for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
+       if(block)
        {
-               for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+               for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
+               for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
                {
-                       MapNode n;
-                       if(y0%2==0)
-                               n.d = CONTENT_AIR;
-                       else
-                               n.d = CONTENT_STONE;
-                       block->setNode(v3s16(x0,y0,z0), n);
+                       for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
+                       {
+                               MapNode n;
+                               if(y0%2==0)
+                                       n.setContent(CONTENT_AIR);
+                               else
+                                       n.setContent(CONTENT_STONE);
+                               block->setNode(v3s16(x0,y0,z0), n);
+                       }
                }
        }
 #endif
@@ -2694,19 +2710,19 @@ s16 ServerMap::findGroundLevel(v2s16 p2d)
        for(; p.Y>min; p.Y--)
        {
                MapNode n = getNodeNoEx(p);
-               if(n.d != CONTENT_IGNORE)
+               if(n.getContent() != CONTENT_IGNORE)
                        break;
        }
        if(p.Y == min)
                goto plan_b;
        // If this node is not air, go to plan b
-       if(getNodeNoEx(p).d != CONTENT_AIR)
+       if(getNodeNoEx(p).getContent() != CONTENT_AIR)
                goto plan_b;
        // Search existing walkable and return it
        for(; p.Y>min; p.Y--)
        {
                MapNode n = getNodeNoEx(p);
-               if(content_walkable(n.d) && n.d != CONTENT_IGNORE)
+               if(content_walkable(n.d) && n.getContent() != CONTENT_IGNORE)
                        return p.Y;
        }
 
index cdbd54525a418709dfaa2bafa91043da1bec381f..49d215bf6d5b2f14a7a1eff78a4595533b9fd57d 100644 (file)
@@ -242,7 +242,7 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
                        // Check if node above block has sunlight
                        try{
                                MapNode n = getNodeParent(v3s16(x, MAP_BLOCKSIZE, z));
-                               if(n.d == CONTENT_IGNORE)
+                               if(n.getContent() == CONTENT_IGNORE)
                                {
                                        // Trust heuristics
                                        no_sunlight = is_underground;
@@ -265,8 +265,8 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
                                else
                                {
                                        MapNode n = getNode(v3s16(x, MAP_BLOCKSIZE-1, z));
-                                       //if(n.d == CONTENT_WATER || n.d == CONTENT_WATERSOURCE)
-                                       if(content_features(n.d).sunlight_propagates == false)
+                                       //if(n.getContent() == CONTENT_WATER || n.getContent() == CONTENT_WATERSOURCE)
+                                       if(content_features(n).sunlight_propagates == false)
                                        {
                                                no_sunlight = true;
                                        }
@@ -327,14 +327,14 @@ bool MapBlock::propagateSunlight(core::map<v3s16, bool> & light_sources,
                                                bool upper_is_air = false;
                                                try
                                                {
-                                                       if(getNodeParent(pos+v3s16(0,1,0)).d == CONTENT_AIR)
+                                                       if(getNodeParent(pos+v3s16(0,1,0)).getContent() == CONTENT_AIR)
                                                                upper_is_air = true;
                                                }
                                                catch(InvalidPositionException &e)
                                                {
                                                }
                                                // Turn mud into grass
-                                               if(upper_is_air && n.d == CONTENT_MUD
+                                               if(upper_is_air && n.getContent() == CONTENT_MUD
                                                                && current_light == LIGHT_SUN)
                                                {
                                                        n.d = CONTENT_GRASS;
@@ -478,7 +478,7 @@ void MapBlock::updateDayNightDiff()
                for(u32 i=0; i<MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE; i++)
                {
                        MapNode &n = data[i];
-                       if(n.d != CONTENT_AIR)
+                       if(n.getContent() != CONTENT_AIR)
                        {
                                only_air = false;
                                break;
@@ -501,8 +501,8 @@ s16 MapBlock::getGroundLevel(v2s16 p2d)
                s16 y = MAP_BLOCKSIZE-1;
                for(; y>=0; y--)
                {
-                       //if(is_ground_content(getNodeRef(p2d.X, y, p2d.Y).d))
-                       if(content_features(getNodeRef(p2d.X, y, p2d.Y).d).walkable)
+                       MapNode n = getNodeRef(p2d.X, y, p2d.Y);
+                       if(content_features(n).walkable)
                        {
                                if(y == MAP_BLOCKSIZE-1)
                                        return -2;
@@ -565,7 +565,7 @@ void MapBlock::serialize(std::ostream &os, u8 version)
                SharedBuffer<u8> materialdata(nodecount);
                for(u32 i=0; i<nodecount; i++)
                {
-                       materialdata[i] = data[i].d;
+                       materialdata[i] = data[i].param0;
                }
                compress(materialdata, os, version);
 
@@ -573,7 +573,7 @@ void MapBlock::serialize(std::ostream &os, u8 version)
                SharedBuffer<u8> lightdata(nodecount);
                for(u32 i=0; i<nodecount; i++)
                {
-                       lightdata[i] = data[i].param;
+                       lightdata[i] = data[i].param1;
                }
                compress(lightdata, os, version);
                
@@ -720,7 +720,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
                                                ("MapBlock::deSerialize: invalid format");
                        for(u32 i=0; i<s.size(); i++)
                        {
-                               data[i].d = s[i];
+                               data[i].param0 = s[i];
                        }
                }
                {
@@ -733,7 +733,7 @@ void MapBlock::deSerialize(std::istream &is, u8 version)
                                                ("MapBlock::deSerialize: invalid format");
                        for(u32 i=0; i<s.size(); i++)
                        {
-                               data[i].param = s[i];
+                               data[i].param1 = s[i];
                        }
                }
        
index 447716d0059d44e53f6681af8c3dda1b8314b6aa..c625983b059c906558ba97010ee61e63a6c68073 100644 (file)
@@ -140,9 +140,24 @@ void getNodeVertexDirs(v3s16 dir, v3s16 *vertex_dirs)
        }
 }
 
-inline video::SColor lightColor(u8 alpha, u8 light)
+video::SColor MapBlock_LightColor(u8 alpha, u8 light)
 {
+#if 0
        return video::SColor(alpha,light,light,light);
+#endif
+       //return video::SColor(alpha,light,light,MYMAX(0, (s16)light-25)+25);
+       /*return video::SColor(alpha,light,light,MYMAX(0,
+                       pow((float)light/255.0, 0.8)*255.0));*/
+#if 1
+       // Emphase blue a bit in darker places
+       float lim = 80;
+       float power = 0.8;
+       if(light > lim)
+               return video::SColor(alpha,light,light,light);
+       else
+               return video::SColor(alpha,light,light,MYMAX(0,
+                               pow((float)light/lim, power)*lim));
+#endif
 }
 
 struct FastFace
@@ -198,7 +213,7 @@ void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
        float w = tile.texture.size.X;
        float h = tile.texture.size.Y;
 
-       /*video::SColor c = lightColor(alpha, li);
+       /*video::SColor c = MapBlock_LightColor(alpha, li);
 
        face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0), c,
                        core::vector2d<f32>(x0+w*abs_scale, y0+h));
@@ -210,16 +225,16 @@ void makeFastFace(TileSpec tile, u8 li0, u8 li1, u8 li2, u8 li3, v3f p,
                        core::vector2d<f32>(x0+w*abs_scale, y0));*/
 
        face.vertices[0] = video::S3DVertex(vertex_pos[0], v3f(0,1,0),
-                       lightColor(alpha, li0),
+                       MapBlock_LightColor(alpha, li0),
                        core::vector2d<f32>(x0+w*abs_scale, y0+h));
        face.vertices[1] = video::S3DVertex(vertex_pos[1], v3f(0,1,0),
-                       lightColor(alpha, li1),
+                       MapBlock_LightColor(alpha, li1),
                        core::vector2d<f32>(x0, y0+h));
        face.vertices[2] = video::S3DVertex(vertex_pos[2], v3f(0,1,0),
-                       lightColor(alpha, li2),
+                       MapBlock_LightColor(alpha, li2),
                        core::vector2d<f32>(x0, y0));
        face.vertices[3] = video::S3DVertex(vertex_pos[3], v3f(0,1,0),
-                       lightColor(alpha, li3),
+                       MapBlock_LightColor(alpha, li3),
                        core::vector2d<f32>(x0+w*abs_scale, y0));
 
        face.tile = tile;
@@ -285,7 +300,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 face_dir,
        return spec;
 }
 
-u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
+content_t getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
 {
        /*
                Check temporary modifications on this node
@@ -320,7 +335,7 @@ u8 getNodeContent(v3s16 p, MapNode mn, NodeModMap &temp_mods)
                }
        }
 
-       return mn.d;
+       return mn.getContent();
 }
 
 v3s16 dirs8[8] = {
@@ -343,16 +358,16 @@ u8 getSmoothLight(v3s16 p, VoxelManipulator &vmanip, u32 daynight_ratio)
        for(u32 i=0; i<8; i++)
        {
                MapNode n = vmanip.getNodeNoEx(p - dirs8[i]);
-               if(content_features(n.d).param_type == CPT_LIGHT
+               if(content_features(n).param_type == CPT_LIGHT
                                // Fast-style leaves look better this way
-                               && content_features(n.d).solidness != 2)
+                               && content_features(n).solidness != 2)
                {
                        light += decode_light(n.getLightBlend(daynight_ratio));
                        light_count++;
                }
                else
                {
-                       if(n.d != CONTENT_IGNORE)
+                       if(n.getContent() != CONTENT_IGNORE)
                                ambient_occlusion++;
                }
        }
@@ -408,8 +423,8 @@ void getTileInfo(
        TileSpec tile1 = getNodeTile(n1, p + face_dir, -face_dir, temp_mods);
        
        // This is hackish
-       u8 content0 = getNodeContent(p, n0, temp_mods);
-       u8 content1 = getNodeContent(p + face_dir, n1, temp_mods);
+       content_t content0 = getNodeContent(p, n0, temp_mods);
+       content_t content1 = getNodeContent(p + face_dir, n1, temp_mods);
        u8 mf = face_contents(content0, content1);
 
        if(mf == 0)
index 591172bc90e0ea8eac8ed46a78957a9a8629d939..d43c19a253f53cc020d122714ca093ab77293829 100644 (file)
@@ -121,6 +121,9 @@ private:
        core::array<PreMeshBuffer> m_prebuffers;
 };
 
+// Helper functions
+video::SColor MapBlock_LightColor(u8 alpha, u8 light);
+
 class MapBlock;
 
 struct MeshMakeData
@@ -137,6 +140,7 @@ struct MeshMakeData
        void fill(u32 daynight_ratio, MapBlock *block);
 };
 
+// This is the highest-level function in here
 scene::SMesh* makeMapBlockMesh(MeshMakeData *data);
 
 #endif
index ab1c20267dfd39687446f991fa797c26ef6cb150..071a14b0cdb3b497d586f057fb6a1503377b0f20 100644 (file)
@@ -161,8 +161,8 @@ void MovingObject::move(float dtime, v3f acceleration)
                for(s16 x = oldpos_i.X - 1; x <= oldpos_i.X + 1; x++)
                {
                        try{
-                               if(content_walkable(m_block->getNodeParent(v3s16(x,y,z)).d)
-                                               == false)
+                               MapNode n = m_block->getNodeParent(v3s16(x,y,z));
+                               if(content_features(n).walkable == false)
                                        continue;
                        }
                        catch(InvalidPositionException &e)
index 4a2a39aec7b63b4170fa46435765bf91c933d2d1..0ba7f91abadb9d71178f0ed4bab29f84b04e553b 100644 (file)
@@ -67,8 +67,8 @@ static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
        {
                MapNode &n = vmanip.m_data[i];
                if(content_walkable(n.d)
-                               && n.d != CONTENT_TREE
-                               && n.d != CONTENT_LEAVES)
+                               && n.getContent() != CONTENT_TREE
+                               && n.getContent() != CONTENT_LEAVES)
                        break;
 
                vmanip.m_area.add_y(em, i, -1);
@@ -85,7 +85,7 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
        MapNode treenode(CONTENT_TREE);
        MapNode leavesnode(CONTENT_LEAVES);
 
-       s16 trunk_h = myrand_range(3, 6);
+       s16 trunk_h = myrand_range(4, 5);
        v3s16 p1 = p0;
        for(s16 ii=0; ii<trunk_h; ii++)
        {
@@ -97,7 +97,7 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
        // p1 is now the last piece of the trunk
        p1.Y -= 1;
 
-       VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
+       VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
        //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
        Buffer<u8> leaves_d(leaves_a.getVolume());
        for(s32 i=0; i<leaves_a.getVolume(); i++)
@@ -143,8 +143,8 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
                if(vmanip.m_area.contains(p) == false)
                        continue;
                u32 vi = vmanip.m_area.index(p);
-               if(vmanip.m_data[vi].d != CONTENT_AIR
-                               && vmanip.m_data[vi].d != CONTENT_IGNORE)
+               if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+                               && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
                        continue;
                u32 i = leaves_a.index(x,y,z);
                if(leaves_d[i] == 1)
@@ -152,6 +152,120 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
        }
 }
 
+static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0)
+{
+       MapNode treenode(CONTENT_JUNGLETREE);
+       MapNode leavesnode(CONTENT_LEAVES);
+
+       for(s16 x=-1; x<=1; x++)
+       for(s16 z=-1; z<=1; z++)
+       {
+               if(myrand_range(0, 2) == 0)
+                       continue;
+               v3s16 p1 = p0 + v3s16(x,0,z);
+               v3s16 p2 = p0 + v3s16(x,-1,z);
+               if(vmanip.m_area.contains(p2)
+                               && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
+                       vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
+               else if(vmanip.m_area.contains(p1))
+                       vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+       }
+
+       s16 trunk_h = myrand_range(8, 12);
+       v3s16 p1 = p0;
+       for(s16 ii=0; ii<trunk_h; ii++)
+       {
+               if(vmanip.m_area.contains(p1))
+                       vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+               p1.Y++;
+       }
+
+       // p1 is now the last piece of the trunk
+       p1.Y -= 1;
+
+       VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
+       //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
+       Buffer<u8> leaves_d(leaves_a.getVolume());
+       for(s32 i=0; i<leaves_a.getVolume(); i++)
+               leaves_d[i] = 0;
+
+       // Force leaves at near the end of the trunk
+       {
+               s16 d = 1;
+               for(s16 z=-d; z<=d; z++)
+               for(s16 y=-d; y<=d; y++)
+               for(s16 x=-d; x<=d; x++)
+               {
+                       leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
+               }
+       }
+
+       // Add leaves randomly
+       for(u32 iii=0; iii<30; iii++)
+       {
+               s16 d = 1;
+
+               v3s16 p(
+                       myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
+                       myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
+                       myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
+               );
+
+               for(s16 z=0; z<=d; z++)
+               for(s16 y=0; y<=d; y++)
+               for(s16 x=0; x<=d; x++)
+               {
+                       leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
+               }
+       }
+
+       // Blit leaves to vmanip
+       for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
+       for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
+       for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
+       {
+               v3s16 p(x,y,z);
+               p += p1;
+               if(vmanip.m_area.contains(p) == false)
+                       continue;
+               u32 vi = vmanip.m_area.index(p);
+               if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+                               && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+                       continue;
+               u32 i = leaves_a.index(x,y,z);
+               if(leaves_d[i] == 1)
+                       vmanip.m_data[vi] = leavesnode;
+       }
+}
+
+void make_papyrus(VoxelManipulator &vmanip, v3s16 p0)
+{
+       MapNode papyrusnode(CONTENT_PAPYRUS);
+
+       s16 trunk_h = myrand_range(2, 3);
+       v3s16 p1 = p0;
+       for(s16 ii=0; ii<trunk_h; ii++)
+       {
+               if(vmanip.m_area.contains(p1))
+                       vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
+               p1.Y++;
+       }
+}
+
+void make_cactus(VoxelManipulator &vmanip, v3s16 p0)
+{
+       MapNode cactusnode(CONTENT_CACTUS);
+
+       s16 trunk_h = 3;
+       v3s16 p1 = p0;
+       for(s16 ii=0; ii<trunk_h; ii++)
+       {
+               if(vmanip.m_area.contains(p1))
+                       vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
+               p1.Y++;
+       }
+}
+
 #if 0
 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
 {
@@ -223,8 +337,8 @@ static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
                if(vmanip.m_area.contains(p) == false)
                        continue;
                u32 vi = vmanip.m_area.index(p);
-               if(vmanip.m_data[vi].d != CONTENT_AIR
-                               && vmanip.m_data[vi].d != CONTENT_IGNORE)
+               if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+                               && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
                        continue;
                u32 i = stone_a.index(x,y,z);
                if(stone_d[i] == 1)
@@ -307,8 +421,8 @@ static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
                if(vmanip.m_area.contains(p) == false)
                        continue;
                u32 vi = vmanip.m_area.index(p);
-               /*if(vmanip.m_data[vi].d != CONTENT_AIR
-                               && vmanip.m_data[vi].d != CONTENT_IGNORE)
+               /*if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+                               && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
                        continue;*/
                u32 i = stone_a.index(x,y,z);
                if(stone_d[i] == 1)
@@ -516,9 +630,9 @@ static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
                        p.Y += make_stairs;
 
                /*// If already empty
-               if(vmanip.getNodeNoExNoEmerge(p).d
+               if(vmanip.getNodeNoExNoEmerge(p).getContent()
                                == CONTENT_AIR
-               && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
+               && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
                                == CONTENT_AIR)
                {
                }*/
@@ -614,9 +728,9 @@ public:
                                randomizeDir();
                                continue;
                        }
-                       if(vmanip.getNodeNoExNoEmerge(p).d
+                       if(vmanip.getNodeNoExNoEmerge(p).getContent()
                                        == CONTENT_COBBLE
-                       && vmanip.getNodeNoExNoEmerge(p1).d
+                       && vmanip.getNodeNoExNoEmerge(p1).getContent()
                                        == CONTENT_COBBLE)
                        {
                                // Found wall, this is a good place!
@@ -630,25 +744,25 @@ public:
                                Determine where to move next
                        */
                        // Jump one up if the actual space is there
-                       if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
+                       if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
                                        == CONTENT_COBBLE
-                       && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
+                       && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
                                        == CONTENT_AIR
-                       && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).d
+                       && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
                                        == CONTENT_AIR)
                                p += v3s16(0,1,0);
                        // Jump one down if the actual space is there
-                       if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
+                       if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
                                        == CONTENT_COBBLE
-                       && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
+                       && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
                                        == CONTENT_AIR
-                       && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).d
+                       && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
                                        == CONTENT_AIR)
                                p += v3s16(0,-1,0);
                        // Check if walking is now possible
-                       if(vmanip.getNodeNoExNoEmerge(p).d
+                       if(vmanip.getNodeNoExNoEmerge(p).getContent()
                                        != CONTENT_AIR
-                       || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
+                       || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
                                        != CONTENT_AIR)
                        {
                                // Cannot continue walking here
@@ -770,7 +884,7 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
                                fits = false;
                                break;
                        }
-                       if(vmanip.m_data[vi].d == CONTENT_IGNORE)
+                       if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
                        {
                                fits = false;
                                break;
@@ -909,8 +1023,8 @@ NoiseParams get_cave_noise2_params(u64 seed)
 
 NoiseParams get_ground_noise1_params(u64 seed)
 {
-       return NoiseParams(NOISE_PERLIN, seed+983240, 5,
-                       0.60, 100.0, 30.0);
+       return NoiseParams(NOISE_PERLIN, seed+983240, 4,
+                       0.55, 80.0, 40.0);
 }
 
 NoiseParams get_ground_crumbleness_params(u64 seed)
@@ -945,7 +1059,7 @@ bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
 
        double f = 0.55 + noise2d_perlin(
                        0.5+(float)p.X/250, 0.5+(float)p.Z/250,
-                       seed+920381, 3, 0.5);
+                       seed+920381, 3, 0.45);
        if(f < 0.01)
                f = 0.01;
        else if(f >= 1.0)
@@ -976,13 +1090,26 @@ double tree_amount_2d(u64 seed, v2s16 p)
        double noise = noise2d_perlin(
                        0.5+(float)p.X/125, 0.5+(float)p.Y/125,
                        seed+2, 4, 0.66);
-       double zeroval = -0.35;
+       double zeroval = -0.39;
        if(noise < zeroval)
                return 0;
        else
                return 0.04 * (noise-zeroval) / (1.0-zeroval);
 }
 
+double surface_humidity_2d(u64 seed, v2s16 p)
+{
+       double noise = noise2d_perlin(
+                       0.5+(float)p.X/500, 0.5+(float)p.Y/500,
+                       seed+72384, 4, 0.66);
+       noise = (noise + 1.0)/2.0;
+       if(noise < 0.0)
+               noise = 0.0;
+       if(noise > 1.0)
+               noise = 1.0;
+       return noise;
+}
+
 #if 0
 double randomstone_amount_2d(u64 seed, v2s16 p)
 {
@@ -1245,11 +1372,11 @@ void add_random_objects(MapBlock *block)
                {
                        v3s16 p(x0,y0,z0);
                        MapNode n = block->getNodeNoEx(p);
-                       if(n.d == CONTENT_IGNORE)
+                       if(n.getContent() == CONTENT_IGNORE)
                                continue;
-                       if(content_features(n.d).liquid_type != LIQUID_NONE)
+                       if(content_features(n).liquid_type != LIQUID_NONE)
                                continue;
-                       if(content_features(n.d).walkable)
+                       if(content_features(n).walkable)
                        {
                                last_node_walkable = true;
                                continue;
@@ -1257,7 +1384,7 @@ void add_random_objects(MapBlock *block)
                        if(last_node_walkable)
                        {
                                // If block contains light information
-                               if(content_features(n.d).param_type == CPT_LIGHT)
+                               if(content_features(n).param_type == CPT_LIGHT)
                                {
                                        if(n.getLight(LIGHTBANK_DAY) <= 3)
                                        {
@@ -1303,7 +1430,7 @@ void make_block(BlockMakeData *data)
 {
        if(data->no_op)
        {
-               dstream<<"makeBlock: no-op"<<std::endl;
+               //dstream<<"makeBlock: no-op"<<std::endl;
                return;
        }
 
@@ -1345,7 +1472,8 @@ void make_block(BlockMakeData *data)
                        data->seed, v2s16(blockpos.X, blockpos.Z), 1);
        // Maximum amount of ground above the bottom of the central block
        s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
-       
+
+       #if 0
        /*
                Special case for high air or water: Just fill with air and water.
        */
@@ -1363,7 +1491,7 @@ void make_block(BlockMakeData *data)
                                for(s16 y=node_min.Y; y<=node_max.Y; y++)
                                {
                                        // Only modify places that have no content
-                                       if(vmanip.m_data[i].d == CONTENT_IGNORE)
+                                       if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
                                        {
                                                if(y <= WATER_LEVEL)
                                                        vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
@@ -1379,6 +1507,7 @@ void make_block(BlockMakeData *data)
                // We're done
                return;
        }
+       #endif
 
        /*
                If block is deep underground, this is set to true and ground
@@ -1468,7 +1597,7 @@ void make_block(BlockMakeData *data)
                        for(s16 y=node_min.Y; y<=node_max.Y; y++)
                        {
                                // Only modify places that have no content
-                               if(vmanip.m_data[i].d == CONTENT_IGNORE)
+                               if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
                                {
                                        // First priority: make air and water.
                                        // This avoids caves inside water.
@@ -1513,7 +1642,7 @@ void make_block(BlockMakeData *data)
                                {
                                        v3s16 p = v3s16(x,y,z) + g_27dirs[i];
                                        u32 vi = vmanip.m_area.index(p);
-                                       if(vmanip.m_data[vi].d == CONTENT_STONE)
+                                       if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
                                                if(mineralrandom.next()%8 == 0)
                                                        vmanip.m_data[vi] = MapNode(CONTENT_MESE);
                                }
@@ -1554,13 +1683,13 @@ void make_block(BlockMakeData *data)
                                {
                                }*/
 
-                               if(new_content.d != CONTENT_IGNORE)
+                               if(new_content.getContent() != CONTENT_IGNORE)
                                {
                                        for(u16 i=0; i<27; i++)
                                        {
                                                v3s16 p = v3s16(x,y,z) + g_27dirs[i];
                                                u32 vi = vmanip.m_area.index(p);
-                                               if(vmanip.m_data[vi].d == base_content)
+                                               if(vmanip.m_data[vi].getContent() == base_content)
                                                {
                                                        if(mineralrandom.next()%sparseness == 0)
                                                                vmanip.m_data[vi] = new_content;
@@ -1591,7 +1720,7 @@ void make_block(BlockMakeData *data)
                                {
                                        v3s16 p = v3s16(x,y,z) + g_27dirs[i];
                                        u32 vi = vmanip.m_area.index(p);
-                                       if(vmanip.m_data[vi].d == CONTENT_STONE)
+                                       if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
                                                if(mineralrandom.next()%8 == 0)
                                                        vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
                                }
@@ -1617,7 +1746,7 @@ void make_block(BlockMakeData *data)
                                {
                                        v3s16 p = v3s16(x,y,z) + g_27dirs[i];
                                        u32 vi = vmanip.m_area.index(p);
-                                       if(vmanip.m_data[vi].d == CONTENT_STONE)
+                                       if(vmanip.m_data[vi].getContent() == CONTENT_STONE)
                                                if(mineralrandom.next()%8 == 0)
                                                        vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
                                }
@@ -1640,7 +1769,7 @@ void make_block(BlockMakeData *data)
                        u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
                        for(s16 y=node_max.Y; y>=node_min.Y; y--)
                        {
-                               if(vmanip.m_data[i].d == CONTENT_STONE)
+                               if(vmanip.m_data[i].getContent() == CONTENT_STONE)
                                {
                                        if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
                                        {
@@ -1692,9 +1821,9 @@ void make_block(BlockMakeData *data)
                                u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
                                for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
                                {
-                                       if(vmanip.m_data[i].d == CONTENT_AIR)
+                                       if(vmanip.m_data[i].getContent() == CONTENT_AIR)
                                                vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
-                                       else if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
+                                       else if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
                                                vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
                                        data->vmanip->m_area.add_y(em, i, -1);
                                }
@@ -1725,17 +1854,17 @@ void make_block(BlockMakeData *data)
                                        double d = noise3d_perlin((float)x/2.5,
                                                        (float)y/2.5,(float)z/2.5,
                                                        blockseed, 2, 1.4);
-                                       if(vmanip.m_data[i].d == CONTENT_COBBLE)
+                                       if(vmanip.m_data[i].getContent() == CONTENT_COBBLE)
                                        {
                                                if(d < wetness/3.0)
                                                {
-                                                       vmanip.m_data[i].d = CONTENT_MOSSYCOBBLE;
+                                                       vmanip.m_data[i].setContent(CONTENT_MOSSYCOBBLE);
                                                }
                                        }
                                        /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
                                        {
                                                if(wetness > 1.2)
-                                                       vmanip.m_data[i].d = CONTENT_MUD;
+                                                       vmanip.m_data[i].setContent(CONTENT_MUD);
                                        }*/
                                        data->vmanip->m_area.add_y(em, i, -1);
                                }
@@ -1761,7 +1890,7 @@ void make_block(BlockMakeData *data)
                        {
                                if(water_found == false)
                                {
-                                       if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
+                                       if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
                                        {
                                                v3s16 p = v3s16(p2d.X, y, p2d.Y);
                                                data->transforming_liquid.push_back(p);
@@ -1773,7 +1902,7 @@ void make_block(BlockMakeData *data)
                                        // This can be done because water_found can only
                                        // turn to true and end up here after going through
                                        // a single block.
-                                       if(vmanip.m_data[i+1].d != CONTENT_WATERSOURCE)
+                                       if(vmanip.m_data[i+1].getContent() != CONTENT_WATERSOURCE)
                                        {
                                                v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
                                                data->transforming_liquid.push_back(p);
@@ -1808,22 +1937,24 @@ void make_block(BlockMakeData *data)
                                u32 current_depth = 0;
                                bool air_detected = false;
                                bool water_detected = false;
+                               bool have_clay = false;
+
                                // Use fast index incrementing
                                s16 start_y = node_max.Y+2;
                                v3s16 em = vmanip.m_area.getExtent();
                                u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
                                for(s16 y=start_y; y>=node_min.Y-3; y--)
                                {
-                                       if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
+                                       if(vmanip.m_data[i].getContent() == CONTENT_WATERSOURCE)
                                                water_detected = true;
-                                       if(vmanip.m_data[i].d == CONTENT_AIR)
+                                       if(vmanip.m_data[i].getContent() == CONTENT_AIR)
                                                air_detected = true;
 
-                                       if((vmanip.m_data[i].d == CONTENT_STONE
-                                                       || vmanip.m_data[i].d == CONTENT_GRASS
-                                                       || vmanip.m_data[i].d == CONTENT_MUD
-                                                       || vmanip.m_data[i].d == CONTENT_SAND
-                                                       || vmanip.m_data[i].d == CONTENT_GRAVEL
+                                       if((vmanip.m_data[i].getContent() == CONTENT_STONE
+                                                       || vmanip.m_data[i].getContent() == CONTENT_GRASS
+                                                       || vmanip.m_data[i].getContent() == CONTENT_MUD
+                                                       || vmanip.m_data[i].getContent() == CONTENT_SAND
+                                                       || vmanip.m_data[i].getContent() == CONTENT_GRAVEL
                                                        ) && (air_detected || water_detected))
                                        {
                                                if(current_depth == 0 && y <= WATER_LEVEL+2
@@ -1834,7 +1965,19 @@ void make_block(BlockMakeData *data)
                                                {
                                                        if(have_sand)
                                                        {
-                                                               vmanip.m_data[i] = MapNode(CONTENT_SAND);
+                                                               // Determine whether to have clay in the sand here
+                                                               double claynoise = noise2d_perlin(
+                                                                               0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
+                                                                               data->seed+4321, 6, 0.95) + 0.5;
+                               
+                                                               have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
+                                                                       ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
+                                                                       ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
+                                                                       );
+                                                               if (have_clay)
+                                                                       vmanip.m_data[i] = MapNode(CONTENT_CLAY);
+                                                               else
+                                                                       vmanip.m_data[i] = MapNode(CONTENT_SAND);
                                                        }
                                                        #if 1
                                                        else if(current_depth==0 && !water_detected
@@ -1846,8 +1989,8 @@ void make_block(BlockMakeData *data)
                                                }
                                                else
                                                {
-                                                       if(vmanip.m_data[i].d == CONTENT_MUD
-                                                               || vmanip.m_data[i].d == CONTENT_GRASS)
+                                                       if(vmanip.m_data[i].getContent() == CONTENT_MUD
+                                                               || vmanip.m_data[i].getContent() == CONTENT_GRASS)
                                                                vmanip.m_data[i] = MapNode(CONTENT_STONE);
                                                }
 
@@ -1865,11 +2008,19 @@ void make_block(BlockMakeData *data)
                }
 
                /*
-                       Add trees
+                       Calculate some stuff
                */
                
+               float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
+               bool is_jungle = surface_humidity > 0.75;
                // Amount of trees
                u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
+               if(is_jungle)
+                       tree_count *= 5;
+
+               /*
+                       Add trees
+               */
                PseudoRandom treerandom(blockseed);
                // Put trees in random places on part of division
                for(u32 i=0; i<tree_count; i++)
@@ -1894,7 +2045,7 @@ void make_block(BlockMakeData *data)
                        {
                                u32 i = data->vmanip->m_area.index(p);
                                MapNode *n = &data->vmanip->m_data[i];
-                               if(n->d != CONTENT_AIR && n->d != CONTENT_IGNORE)
+                               if(n->getContent() != CONTENT_AIR && n->getContent() != CONTENT_WATERSOURCE && n->getContent() != CONTENT_IGNORE)
                                {
                                        found = true;
                                        break;
@@ -1903,19 +2054,85 @@ void make_block(BlockMakeData *data)
                        // If not found, handle next one
                        if(found == false)
                                continue;
-                       /*
-                               Trees grow only on mud and grass
-                       */
+
                        {
                                u32 i = data->vmanip->m_area.index(p);
                                MapNode *n = &data->vmanip->m_data[i];
-                               if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
+
+                               if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS && n->getContent() != CONTENT_SAND)
+                                               continue;
+
+                               // Papyrus grows only on mud and in water
+                               if(n->getContent() == CONTENT_MUD && y <= WATER_LEVEL)
+                               {
+                                       p.Y++;
+                                       make_papyrus(vmanip, p);
+                               }
+                               // Trees grow only on mud and grass, on land
+                               else if((n->getContent() == CONTENT_MUD || n->getContent() == CONTENT_GRASS) && y > WATER_LEVEL + 2)
+                               {
+                                       p.Y++;
+                                       //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
+                                       if(is_jungle == false)
+                                               make_tree(vmanip, p);
+                                       else
+                                               make_jungletree(vmanip, p);
+                               }
+                               // Cactii grow only on sand, on land
+                               else if(n->getContent() == CONTENT_SAND && y > WATER_LEVEL + 2)
+                               {
+                                       p.Y++;
+                                       make_cactus(vmanip, p);
+                               }
+                       }
+               }
+
+               /*
+                       Add jungle grass
+               */
+               if(is_jungle)
+               {
+                       PseudoRandom grassrandom(blockseed);
+                       for(u32 i=0; i<surface_humidity*5*tree_count; i++)
+                       {
+                               s16 x = grassrandom.range(node_min.X, node_max.X);
+                               s16 z = grassrandom.range(node_min.Z, node_max.Z);
+                               s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
+                               if(y < WATER_LEVEL)
+                                       continue;
+                               if(y < node_min.Y || y > node_max.Y)
+                                       continue;
+                               /*
+                                       Find exact ground level
+                               */
+                               v3s16 p(x,y+6,z);
+                               bool found = false;
+                               for(; p.Y >= y-6; p.Y--)
+                               {
+                                       u32 i = data->vmanip->m_area.index(p);
+                                       MapNode *n = &data->vmanip->m_data[i];
+                                       if(content_features(*n).is_ground_content
+                                                       || n->getContent() == CONTENT_JUNGLETREE)
+                                       {
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                               // If not found, handle next one
+                               if(found == false)
                                        continue;
+                               p.Y++;
+                               if(vmanip.m_area.contains(p) == false)
+                                       continue;
+                               if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
+                                       continue;
+                               /*p.Y--;
+                               if(vmanip.m_area.contains(p))
+                                       vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_MUD;
+                               p.Y++;*/
+                               if(vmanip.m_area.contains(p))
+                                       vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_JUNGLEGRASS;
                        }
-                       // Tree will be placed one higher
-                       p.Y++;
-                       // Make a tree
-                       make_tree(vmanip, p);
                }
 
 #if 0
@@ -1942,7 +2159,7 @@ void make_block(BlockMakeData *data)
                        /*{
                                u32 i = data->vmanip->m_area.index(v3s16(p));
                                MapNode *n = &data->vmanip->m_data[i];
-                               if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
+                               if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
                                        continue;
                        }*/
                        // Will be placed one higher
@@ -1977,7 +2194,7 @@ void make_block(BlockMakeData *data)
                        /*{
                                u32 i = data->vmanip->m_area.index(v3s16(p));
                                MapNode *n = &data->vmanip->m_data[i];
-                               if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
+                               if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
                                        continue;
                        }*/
                        // Will be placed one lower
index 391e593f9548b9715de7f733169e88a50eb44f78..c9f85c303ddd35698f795c7e365972b3dd60a85d 100644 (file)
@@ -30,8 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 ContentFeatures::~ContentFeatures()
 {
-       /*if(translate_to)
-               delete translate_to;*/
        if(initial_metadata)
                delete initial_metadata;
 }
@@ -83,12 +81,16 @@ void ContentFeatures::setInventoryTextureCube(std::string top,
        inventory_texture = g_texturesource->getTextureRaw(imgname_full);
 }
 
-struct ContentFeatures g_content_features[256];
+struct ContentFeatures g_content_features[MAX_CONTENT+1];
 
-ContentFeatures & content_features(u8 i)
+ContentFeatures & content_features(content_t i)
 {
        return g_content_features[i];
 }
+ContentFeatures & content_features(MapNode &n)
+{
+       return content_features(n.getContent());
+}
 
 /*
        See mapnode.h for description.
@@ -128,7 +130,7 @@ void init_mapnode()
                initial_material_type = MATERIAL_ALPHA_SIMPLE;
        else
                initial_material_type = MATERIAL_ALPHA_NONE;*/
-       for(u16 i=0; i<256; i++)
+       for(u16 i=0; i<MAX_CONTENT+1; i++)
        {
                ContentFeatures *f = &g_content_features[i];
                // Re-initialize
@@ -142,8 +144,10 @@ void init_mapnode()
                Initially set every block to be shown as an unknown block.
                Don't touch CONTENT_IGNORE or CONTENT_AIR.
        */
-       for(u16 i=0; i<=253; i++)
+       for(u16 i=0; i<MAX_CONTENT+1; i++)
        {
+               if(i == CONTENT_IGNORE || i == CONTENT_AIR)
+                       continue;
                ContentFeatures *f = &g_content_features[i];
                f->setAllTextures("unknown_block.png");
                f->dug_item = std::string("MaterialItem ")+itos(i)+" 1";
@@ -181,7 +185,7 @@ v3s16 facedir_rotate(u8 facedir, v3s16 dir)
 
 TileSpec MapNode::getTile(v3s16 dir)
 {
-       if(content_features(d).param_type == CPT_FACEDIR_SIMPLE)
+       if(content_features(*this).param_type == CPT_FACEDIR_SIMPLE)
                dir = facedir_rotate(param1, dir);
        
        TileSpec spec;
@@ -205,16 +209,16 @@ TileSpec MapNode::getTile(v3s16 dir)
        
        if(dir_i == -1)
                // Non-directional
-               spec = content_features(d).tiles[0];
+               spec = content_features(*this).tiles[0];
        else 
-               spec = content_features(d).tiles[dir_i];
+               spec = content_features(*this).tiles[dir_i];
        
        /*
                If it contains some mineral, change texture id
        */
-       if(content_features(d).param_type == CPT_MINERAL && g_texturesource)
+       if(content_features(*this).param_type == CPT_MINERAL && g_texturesource)
        {
-               u8 mineral = param & 0x1f;
+               u8 mineral = getMineral();
                std::string mineral_texture_name = mineral_block_texture(mineral);
                if(mineral_texture_name != "")
                {
@@ -233,9 +237,9 @@ TileSpec MapNode::getTile(v3s16 dir)
 
 u8 MapNode::getMineral()
 {
-       if(content_features(d).param_type == CPT_MINERAL)
+       if(content_features(*this).param_type == CPT_MINERAL)
        {
-               return param & 0x1f;
+               return param1 & 0x0f;
        }
 
        return MINERAL_NONE;
@@ -258,33 +262,36 @@ void MapNode::serialize(u8 *dest, u8 version)
        if(!ser_ver_supported(version))
                throw VersionMismatchException("ERROR: MapNode format not supported");
                
-       u8 actual_d = d;
+       // Translate to wanted version
+       MapNode n_foreign = mapnode_translate_from_internal(*this, version);
 
-       // Convert from new version to old
+       u8 actual_param0 = n_foreign.param0;
+
+       // Convert special values from new version to old
        if(version <= 18)
        {
                // In these versions, CONTENT_IGNORE and CONTENT_AIR
                // are 255 and 254
-               if(d == CONTENT_IGNORE)
-                       d = 255;
-               else if(d == CONTENT_AIR)
-                       d = 254;
+               if(actual_param0 == CONTENT_IGNORE)
+                       actual_param0 = 255;
+               else if(actual_param0 == CONTENT_AIR)
+                       actual_param0 = 254;
        }
 
        if(version == 0)
        {
-               dest[0] = actual_d;
+               dest[0] = actual_param0;
        }
        else if(version <= 9)
        {
-               dest[0] = actual_d;
-               dest[1] = param;
+               dest[0] = actual_param0;
+               dest[1] = n_foreign.param1;
        }
        else
        {
-               dest[0] = actual_d;
-               dest[1] = param;
-               dest[2] = param2;
+               dest[0] = actual_param0;
+               dest[1] = n_foreign.param1;
+               dest[2] = n_foreign.param2;
        }
 }
 void MapNode::deSerialize(u8 *source, u8 version)
@@ -294,39 +301,50 @@ void MapNode::deSerialize(u8 *source, u8 version)
                
        if(version == 0)
        {
-               d = source[0];
+               param0 = source[0];
        }
        else if(version == 1)
        {
-               d = source[0];
+               param0 = source[0];
                // This version doesn't support saved lighting
                if(light_propagates() || light_source() > 0)
-                       param = 0;
+                       param1 = 0;
                else
-                       param = source[1];
+                       param1 = source[1];
        }
        else if(version <= 9)
        {
-               d = source[0];
-               param = source[1];
+               param0 = source[0];
+               param1 = source[1];
        }
        else
        {
-               d = source[0];
-               param = source[1];
+               param0 = source[0];
+               param1 = source[1];
                param2 = source[2];
-               
-               // Convert from old version to new
-               if(version <= 18)
-               {
-                       // In these versions, CONTENT_IGNORE and CONTENT_AIR
-                       // are 255 and 254
-                       if(d == 255)
-                               d = CONTENT_IGNORE;
-                       else if(d == 254)
-                               d = CONTENT_AIR;
-               }
        }
+       
+       // Convert special values from old version to new
+       if(version <= 18)
+       {
+               // In these versions, CONTENT_IGNORE and CONTENT_AIR
+               // are 255 and 254
+               if(param0 == 255)
+                       param0 = CONTENT_IGNORE;
+               else if(param0 == 254)
+                       param0 = CONTENT_AIR;
+       }
+       // version 19 is fucked up with sometimes the old values and sometimes not
+       if(version == 19)
+       {
+               if(param0 == 255)
+                       param0 = CONTENT_IGNORE;
+               else if(param0 == 254)
+                       param0 = CONTENT_AIR;
+       }
+
+       // Translate to our known version
+       *this = mapnode_translate_to_internal(*this, version);
 }
 
 /*
index 36d48fb9e4e6536c57bcbb67b17edf0843024ae1..956de6852d8cbb688c3b4e2ad209e4b91f3a8f03 100644 (file)
@@ -32,16 +32,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 /*
        Naming scheme:
        - Material = irrlicht's Material class
-       - Content = (u8) content of a node
+       - Content = (content_t) content of a node
        - Tile = TileSpec at some side of a node of some content type
-*/
 
-/*
-       Ranges:
+       Content ranges:
                0x000...0x07f: param2 is fully usable
                0x800...0xfff: param2 lower 4 bytes are free
 */
 typedef u16 content_t;
+#define MAX_CONTENT 0xfff
 
 /*
        Initializes all kind of stuff in here.
@@ -102,10 +101,7 @@ class NodeMetadata;
 
 struct ContentFeatures
 {
-       // If non-NULL, content is translated to this when deserialized
-       //MapNode *translate_to;
-
-       // Type of MapNode::param
+       // Type of MapNode::param1
        ContentParamType param_type;
 
        /*
@@ -119,7 +115,8 @@ struct ContentFeatures
        TileSpec tiles[6];
        
        video::ITexture *inventory_texture;
-
+       
+       // True for all ground-like things like stone and mud, false for eg. trees
        bool is_ground_content;
        bool light_propagates;
        bool sunlight_propagates;
@@ -151,7 +148,9 @@ struct ContentFeatures
        
        // If the content is liquid, this is the flowing version of the liquid.
        // If content is liquid, this is the same content.
-       u8 liquid_alternative_flowing;
+       content_t liquid_alternative_flowing;
+       // If the content is liquid, this is the source version of the liquid.
+       content_t liquid_alternative_source;
        
        // Amount of light the node emits
        u8 light_source;
@@ -163,7 +162,6 @@ struct ContentFeatures
 
        void reset()
        {
-               //translate_to = NULL;
                param_type = CPT_NONE;
                inventory_texture = NULL;
                is_ground_content = false;
@@ -228,8 +226,8 @@ struct ContentFeatures
 /*
        Call this to access the ContentFeature list
 */
-ContentFeatures & content_features(u8 i);
-
+ContentFeatures & content_features(content_t i);
+ContentFeatures & content_features(MapNode &n);
 
 /*
        Here is a bunch of DEPRECATED functions.
@@ -240,7 +238,7 @@ ContentFeatures & content_features(u8 i);
        in param.
        NOTE: Don't use, use "content_features(m).whatever" instead
 */
-inline bool light_propagates_content(u8 m)
+inline bool light_propagates_content(content_t m)
 {
        return content_features(m).light_propagates;
 }
@@ -249,7 +247,7 @@ inline bool light_propagates_content(u8 m)
        NOTE: It doesn't seem to go through torches regardlessly of this
        NOTE: Don't use, use "content_features(m).whatever" instead
 */
-inline bool sunlight_propagates_content(u8 m)
+inline bool sunlight_propagates_content(content_t m)
 {
        return content_features(m).sunlight_propagates;
 }
@@ -261,35 +259,35 @@ inline bool sunlight_propagates_content(u8 m)
        2: Opaque
        NOTE: Don't use, use "content_features(m).whatever" instead
 */
-inline u8 content_solidness(u8 m)
+inline u8 content_solidness(content_t m)
 {
        return content_features(m).solidness;
 }
 // Objects collide with walkable contents
 // NOTE: Don't use, use "content_features(m).whatever" instead
-inline bool content_walkable(u8 m)
+inline bool content_walkable(content_t m)
 {
        return content_features(m).walkable;
 }
 // NOTE: Don't use, use "content_features(m).whatever" instead
-inline bool content_liquid(u8 m)
+inline bool content_liquid(content_t m)
 {
        return content_features(m).liquid_type != LIQUID_NONE;
 }
 // NOTE: Don't use, use "content_features(m).whatever" instead
-inline bool content_flowing_liquid(u8 m)
+inline bool content_flowing_liquid(content_t m)
 {
        return content_features(m).liquid_type == LIQUID_FLOWING;
 }
 // NOTE: Don't use, use "content_features(m).whatever" instead
-inline bool content_liquid_source(u8 m)
+inline bool content_liquid_source(content_t m)
 {
        return content_features(m).liquid_type == LIQUID_SOURCE;
 }
 // CONTENT_WATER || CONTENT_WATERSOURCE -> CONTENT_WATER
 // CONTENT_LAVA || CONTENT_LAVASOURCE -> CONTENT_LAVA
 // NOTE: Don't use, use "content_features(m).whatever" instead
-inline u8 make_liquid_flowing(u8 m)
+inline content_t make_liquid_flowing(content_t m)
 {
        u8 c = content_features(m).liquid_alternative_flowing;
        assert(c != CONTENT_IGNORE);
@@ -297,17 +295,17 @@ inline u8 make_liquid_flowing(u8 m)
 }
 // Pointable contents can be pointed to in the map
 // NOTE: Don't use, use "content_features(m).whatever" instead
-inline bool content_pointable(u8 m)
+inline bool content_pointable(content_t m)
 {
        return content_features(m).pointable;
 }
 // NOTE: Don't use, use "content_features(m).whatever" instead
-inline bool content_diggable(u8 m)
+inline bool content_diggable(content_t m)
 {
        return content_features(m).diggable;
 }
 // NOTE: Don't use, use "content_features(m).whatever" instead
-inline bool content_buildable_to(u8 m)
+inline bool content_buildable_to(content_t m)
 {
        return content_features(m).buildable_to;
 }
@@ -319,7 +317,7 @@ inline bool content_buildable_to(u8 m)
                1: Face uses m1's content
                2: Face uses m2's content
 */
-inline u8 face_contents(u8 m1, u8 m2)
+inline u8 face_contents(content_t m1, content_t m2)
 {
        if(m1 == CONTENT_IGNORE || m2 == CONTENT_IGNORE)
                return 0;
@@ -416,7 +414,7 @@ struct MapNode
        union
        {
                u8 param0;
-               u8 d;
+               //u8 d;
        };
 
        /*
@@ -431,17 +429,18 @@ struct MapNode
        union
        {
                u8 param1;
-               s8 param;
+               //s8 param;
        };
        
        /*
                The second parameter. Initialized to 0.
                E.g. direction for torches and flowing water.
+               If param0 >= 0x80, bits 0xf0 of this is extended content type data
        */
        union
        {
                u8 param2;
-               u8 dir;
+               //u8 dir;
        };
 
        MapNode(const MapNode & n)
@@ -449,28 +448,44 @@ struct MapNode
                *this = n;
        }
        
-       MapNode(u8 data=CONTENT_AIR, u8 a_param=0, u8 a_param2=0)
+       MapNode(content_t content=CONTENT_AIR, u8 a_param1=0, u8 a_param2=0)
        {
-               d = data;
-               param = a_param;
+               //param0 = a_param0;
+               param1 = a_param1;
                param2 = a_param2;
+               // Set after other params because this needs to override part of param2
+               setContent(content);
        }
 
        bool operator==(const MapNode &other)
        {
-               return (d == other.d
-                               && param == other.param
+               return (param0 == other.param0
+                               && param1 == other.param1
                                && param2 == other.param2);
        }
        
        // To be used everywhere
        content_t getContent()
        {
-               return d;
+               if(param0 < 0x80)
+                       return param0;
+               else
+                       return (param0<<4) + (param2>>4);
        }
        void setContent(content_t c)
        {
-               d = c;
+               if(c < 0x80)
+               {
+                       if(param0 >= 0x80)
+                               param2 &= ~(0xf0);
+                       param0 = c;
+               }
+               else
+               {
+                       param0 = c>>4;
+                       param2 &= ~(0xf0);
+                       param2 |= (c&0x0f)<<4;
+               }
        }
        
        /*
@@ -478,19 +493,19 @@ struct MapNode
        */
        bool light_propagates()
        {
-               return light_propagates_content(d);
+               return light_propagates_content(getContent());
        }
        bool sunlight_propagates()
        {
-               return sunlight_propagates_content(d);
+               return sunlight_propagates_content(getContent());
        }
        u8 solidness()
        {
-               return content_solidness(d);
+               return content_solidness(getContent());
        }
        u8 light_source()
        {
-               return content_features(d).light_source;
+               return content_features(*this).light_source;
        }
 
        u8 getLightBanksWithSource()
@@ -498,10 +513,10 @@ struct MapNode
                // Select the brightest of [light source, propagated light]
                u8 lightday = 0;
                u8 lightnight = 0;
-               if(content_features(d).param_type == CPT_LIGHT)
+               if(content_features(*this).param_type == CPT_LIGHT)
                {
-                       lightday = param & 0x0f;
-                       lightnight = (param>>4)&0x0f;
+                       lightday = param1 & 0x0f;
+                       lightnight = (param1>>4)&0x0f;
                }
                if(light_source() > lightday)
                        lightday = light_source();
@@ -514,12 +529,12 @@ struct MapNode
        {
                // Select the brightest of [light source, propagated light]
                u8 light = 0;
-               if(content_features(d).param_type == CPT_LIGHT)
+               if(content_features(*this).param_type == CPT_LIGHT)
                {
                        if(bank == LIGHTBANK_DAY)
-                               light = param & 0x0f;
+                               light = param1 & 0x0f;
                        else if(bank == LIGHTBANK_NIGHT)
-                               light = (param>>4)&0x0f;
+                               light = (param1>>4)&0x0f;
                        else
                                assert(0);
                }
@@ -557,17 +572,17 @@ struct MapNode
        void setLight(enum LightBank bank, u8 a_light)
        {
                // If node doesn't contain light data, ignore this
-               if(content_features(d).param_type != CPT_LIGHT)
+               if(content_features(*this).param_type != CPT_LIGHT)
                        return;
                if(bank == LIGHTBANK_DAY)
                {
-                       param &= 0xf0;
-                       param |= a_light & 0x0f;
+                       param1 &= 0xf0;
+                       param1 |= a_light & 0x0f;
                }
                else if(bank == LIGHTBANK_NIGHT)
                {
-                       param &= 0x0f;
-                       param |= (a_light & 0x0f)<<4;
+                       param1 &= 0x0f;
+                       param1 |= (a_light & 0x0f)<<4;
                }
                else
                        assert(0);
index e3a24b9e34f8d16d58b5da7396e70ceabf3472cc..24f30072435915a6f701d4404b1b703b40415371 100644 (file)
@@ -3,12 +3,12 @@
 
 // NOTE: DEPRECATED
 
-DiggingPropertiesList * getDiggingPropertiesList(u8 content)
+DiggingPropertiesList * getDiggingPropertiesList(u16 content)
 {
        return &content_features(content).digging_properties;
 }
 
-DiggingProperties getDiggingProperties(u8 content, const std::string &tool)
+DiggingProperties getDiggingProperties(u16 content, const std::string &tool)
 {
        DiggingPropertiesList *mprop = getDiggingPropertiesList(content);
        if(mprop == NULL)
index f061ecbfa5eb7075c5fe0e4463fad10ff6279301..1439df194c27ea892e20d9e15ee2170fd47e2bd6 100644 (file)
@@ -97,7 +97,7 @@ private:
 };
 
 // For getting the default properties, set tool=""
-DiggingProperties getDiggingProperties(u8 material, const std::string &tool);
+DiggingProperties getDiggingProperties(u16 material, const std::string &tool);
 
 #endif
 
index 6bacb088d79578cfc493b1d569cafa51793e8738..d52d6b88f032937505e4de950e7576739f2c4b2e 100644 (file)
@@ -342,13 +342,13 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
                if(in_water)
                {
                        v3s16 pp = floatToInt(position + v3f(0,BS*0.1,0), BS);
-                       in_water = content_liquid(map.getNode(pp).d);
+                       in_water = content_liquid(map.getNode(pp).getContent());
                }
                // If not in water, the threshold of going in is at lower y
                else
                {
                        v3s16 pp = floatToInt(position + v3f(0,BS*0.5,0), BS);
-                       in_water = content_liquid(map.getNode(pp).d);
+                       in_water = content_liquid(map.getNode(pp).getContent());
                }
        }
        catch(InvalidPositionException &e)
@@ -361,7 +361,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
        */
        try{
                v3s16 pp = floatToInt(position + v3f(0,0,0), BS);
-               in_water_stable = content_liquid(map.getNode(pp).d);
+               in_water_stable = content_liquid(map.getNode(pp).getContent());
        }
        catch(InvalidPositionException &e)
        {
@@ -470,7 +470,7 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
        {
                try{
                        // Player collides into walkable nodes
-                       if(content_walkable(map.getNode(v3s16(x,y,z)).d) == false)
+                       if(content_walkable(map.getNode(v3s16(x,y,z)).getContent()) == false)
                                continue;
                }
                catch(InvalidPositionException &e)
@@ -633,10 +633,10 @@ void LocalPlayer::move(f32 dtime, Map &map, f32 pos_max_d,
 
                        try{
                                // The node to be sneaked on has to be walkable
-                               if(content_walkable(map.getNode(p).d) == false)
+                               if(content_walkable(map.getNode(p).getContent()) == false)
                                        continue;
                                // And the node above it has to be nonwalkable
-                               if(content_walkable(map.getNode(p+v3s16(0,1,0)).d) == true)
+                               if(content_walkable(map.getNode(p+v3s16(0,1,0)).getContent()) == true)
                                        continue;
                        }
                        catch(InvalidPositionException &e)
index 7de042ab571143eb1e69b8d6fd958c60c094cd83..ff8cb3862276f3c1158b8336839dc7e9643221b7 100644 (file)
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "porting.h"
 #include "config.h"
 #include "debug.h"
+#include "filesys.h"
 
 #ifdef __APPLE__
        #include "CoreFoundation/CoreFoundation.h"
@@ -210,6 +211,11 @@ void initializePaths()
 
        path_data = std::string(buf) + "/../share/" + APPNAME;
        //path_data = std::string(INSTALL_PREFIX) + "/share/" + APPNAME;
+       if (!fs::PathExists(path_data)) {
+               dstream<<"WARNING: data path " << path_data << " not found!";
+               path_data = std::string(buf) + "/../data";
+               dstream<<" Trying " << path_data << std::endl;
+       }
        
        path_userdata = std::string(getenv("HOME")) + "/." + APPNAME;
 
index 974ae95d8aa8392dabf4d31668ee16bf5256c996..d93e6189299e5dd147e36756c89ef4d7ea0a9370 100644 (file)
@@ -55,11 +55,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
        17: MapBlocks contain timestamp
        18: new generator (not really necessary, but it's there)
        19: new content type handling
+       20: many existing content types translated to extended ones
 */
 // This represents an uninitialized or invalid format
 #define SER_FMT_VER_INVALID 255
 // Highest supported serialization version
-#define SER_FMT_VER_HIGHEST 19
+#define SER_FMT_VER_HIGHEST 20
 // Lowest supported serialization version
 #define SER_FMT_VER_LOWEST 0
 
index c2433e1af033d9fdf6525f3abf60620c2f9170bd..e3c6ce4d99e516e7253b27f4f21b84e07b199f2c 100644 (file)
@@ -2494,7 +2494,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                        // Mandatory parameter; actually used for nothing
                        core::map<v3s16, MapBlock*> modified_blocks;
 
-                       u8 material = CONTENT_IGNORE;
+                       content_t material = CONTENT_IGNORE;
                        u8 mineral = MINERAL_NONE;
 
                        bool cannot_remove_node = false;
@@ -2505,7 +2505,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                // Get mineral
                                mineral = n.getMineral();
                                // Get material at position
-                               material = n.d;
+                               material = n.getContent();
                                // If not yet cancelled
                                if(cannot_remove_node == false)
                                {
@@ -2705,7 +2705,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                                        <<" because privileges are "<<getPlayerPrivs(player)
                                                        <<std::endl;
 
-                                       if(content_buildable_to(n2.d) == false
+                                       if(content_features(n2).buildable_to == false
                                                || no_enough_privs)
                                        {
                                                // Client probably has wrong data.
@@ -2736,14 +2736,14 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
                                // Create node data
                                MaterialItem *mitem = (MaterialItem*)item;
                                MapNode n;
-                               n.d = mitem->getMaterial();
+                               n.setContent(mitem->getMaterial());
 
                                // Calculate direction for wall mounted stuff
-                               if(content_features(n.d).wall_mounted)
-                                       n.dir = packDir(p_under - p_over);
+                               if(content_features(n).wall_mounted)
+                                       n.param2 = packDir(p_under - p_over);
 
                                // Calculate the direction for furnaces and chests and stuff
-                               if(content_features(n.d).param_type == CPT_FACEDIR_SIMPLE)
+                               if(content_features(n).param_type == CPT_FACEDIR_SIMPLE)
                                {
                                        v3f playerpos = player->getPosition();
                                        v3f blockpos = intToFloat(p_over, BS) - playerpos;
index 7d71552a8fbbb9f41eb83f83ba2e05288d4992ff..3ff4dc8071d6ae41baf6b45a2a93a2e366458f07 100644 (file)
@@ -61,6 +61,38 @@ struct TestUtilities
                assert(is_yes("FAlse") == false);
        }
 };
+
+struct TestSettings
+{
+       void Run()
+       {
+               Settings s;
+               // Test reading of settings
+               s.parseConfigLine("leet = 1337");
+               s.parseConfigLine("leetleet = 13371337");
+               s.parseConfigLine("leetleet_neg = -13371337");
+               s.parseConfigLine("floaty_thing = 1.1");
+               s.parseConfigLine("stringy_thing = asd /( ¤%&(/\" BLÖÄRP");
+               s.parseConfigLine("coord = (1, 2, 4.5)");
+               assert(s.getS32("leet") == 1337);
+               assert(s.getS16("leetleet") == 32767);
+               assert(s.getS16("leetleet_neg") == -32768);
+               // Not sure if 1.1 is an exact value as a float, but doesn't matter
+               assert(fabs(s.getFloat("floaty_thing") - 1.1) < 0.001);
+               assert(s.get("stringy_thing") == "asd /( ¤%&(/\" BLÖÄRP");
+               assert(fabs(s.getV3F("coord").X - 1.0) < 0.001);
+               assert(fabs(s.getV3F("coord").Y - 2.0) < 0.001);
+               assert(fabs(s.getV3F("coord").Z - 4.5) < 0.001);
+               // Test the setting of settings too
+               s.setFloat("floaty_thing_2", 1.2);
+               s.setV3F("coord2", v3f(1, 2, 3.3));
+               assert(s.get("floaty_thing_2").substr(0,3) == "1.2");
+               assert(fabs(s.getFloat("floaty_thing_2") - 1.2) < 0.001);
+               assert(fabs(s.getV3F("coord2").X - 1.0) < 0.001);
+               assert(fabs(s.getV3F("coord2").Y - 2.0) < 0.001);
+               assert(fabs(s.getV3F("coord2").Z - 3.3) < 0.001);
+       }
+};
                
 struct TestCompress
 {
@@ -187,14 +219,14 @@ struct TestMapNode
                MapNode n;
 
                // Default values
-               assert(n.d == CONTENT_AIR);
+               assert(n.getContent() == CONTENT_AIR);
                assert(n.getLight(LIGHTBANK_DAY) == 0);
                assert(n.getLight(LIGHTBANK_NIGHT) == 0);
                
                // Transparency
-               n.d = CONTENT_AIR;
+               n.setContent(CONTENT_AIR);
                assert(n.light_propagates() == true);
-               n.d = CONTENT_STONE;
+               n.setContent(CONTENT_STONE);
                assert(n.light_propagates() == false);
        }
 };
@@ -252,7 +284,7 @@ struct TestVoxelManipulator
 
                v.print(dstream);
 
-               assert(v.getNode(v3s16(-1,0,-1)).d == 2);
+               assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2);
 
                dstream<<"*** Reading from inexistent (0,0,-1) ***"<<std::endl;
 
@@ -266,7 +298,7 @@ struct TestVoxelManipulator
                
                v.print(dstream);
 
-               assert(v.getNode(v3s16(-1,0,-1)).d == 2);
+               assert(v.getNode(v3s16(-1,0,-1)).getContent() == 2);
                EXCEPTION_CHECK(InvalidPositionException, v.getNode(v3s16(0,1,1)));
 
 #if 0
@@ -299,11 +331,11 @@ struct TestVoxelManipulator
                        MapNode n;
                        //n.pressure = size.Y - y;
                        if(*p == '#')
-                               n.d = CONTENT_STONE;
+                               n.setContent(CONTENT_STONE);
                        else if(*p == '.')
-                               n.d = CONTENT_WATER;
+                               n.setContent(CONTENT_WATER);
                        else if(*p == ' ')
-                               n.d = CONTENT_AIR;
+                               n.setContent(CONTENT_AIR);
                        else
                                assert(0);
                        v.setNode(v3s16(x,y,z), n);
@@ -437,8 +469,8 @@ struct TestMapBlock
                for(u16 y=0; y<MAP_BLOCKSIZE; y++)
                for(u16 x=0; x<MAP_BLOCKSIZE; x++)
                {
-                       //assert(b.getNode(v3s16(x,y,z)).d == CONTENT_AIR);
-                       assert(b.getNode(v3s16(x,y,z)).d == CONTENT_IGNORE);
+                       //assert(b.getNode(v3s16(x,y,z)).getContent() == CONTENT_AIR);
+                       assert(b.getNode(v3s16(x,y,z)).getContent() == CONTENT_IGNORE);
                        assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_DAY) == 0);
                        assert(b.getNode(v3s16(x,y,z)).getLight(LIGHTBANK_NIGHT) == 0);
                }
@@ -457,7 +489,7 @@ struct TestMapBlock
                        Parent fetch functions
                */
                parent.position_valid = false;
-               parent.node.d = 5;
+               parent.node.setContent(5);
 
                MapNode n;
                
@@ -465,7 +497,7 @@ struct TestMapBlock
                assert(b.isValidPositionParent(v3s16(0,0,0)) == true);
                assert(b.isValidPositionParent(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1)) == true);
                n = b.getNodeParent(v3s16(0,MAP_BLOCKSIZE-1,0));
-               assert(n.d == CONTENT_AIR);
+               assert(n.getContent() == CONTENT_AIR);
 
                // ...but outside the block they should be invalid
                assert(b.isValidPositionParent(v3s16(-121,2341,0)) == false);
@@ -491,15 +523,15 @@ struct TestMapBlock
                assert(b.isValidPositionParent(v3s16(-1,0,0)) == true);
                assert(b.isValidPositionParent(v3s16(MAP_BLOCKSIZE-1,MAP_BLOCKSIZE-1,MAP_BLOCKSIZE)) == true);
                n = b.getNodeParent(v3s16(0,0,MAP_BLOCKSIZE));
-               assert(n.d == 5);
+               assert(n.getContent() == 5);
 
                /*
                        Set a node
                */
                v3s16 p(1,2,0);
-               n.d = 4;
+               n.setContent(4);
                b.setNode(p, n);
-               assert(b.getNode(p).d == 4);
+               assert(b.getNode(p).getContent() == 4);
                //TODO: Update to new system
                /*assert(b.getNodeTile(p) == 4);
                assert(b.getNodeTile(v3s16(-1,-1,0)) == 5);*/
@@ -524,7 +556,7 @@ struct TestMapBlock
                        */
                        parent.position_valid = true;
                        b.setIsUnderground(false);
-                       parent.node.d = CONTENT_AIR;
+                       parent.node.setContent(CONTENT_AIR);
                        parent.node.setLight(LIGHTBANK_DAY, LIGHT_SUN);
                        parent.node.setLight(LIGHTBANK_NIGHT, 0);
                        core::map<v3s16, bool> light_sources;
@@ -579,7 +611,7 @@ struct TestMapBlock
                                for(u16 y=0; y<MAP_BLOCKSIZE; y++){
                                        for(u16 x=0; x<MAP_BLOCKSIZE; x++){
                                                MapNode n;
-                                               n.d = CONTENT_AIR;
+                                               n.setContent(CONTENT_AIR);
                                                n.setLight(LIGHTBANK_DAY, 0);
                                                b.setNode(v3s16(x,y,z), n);
                                        }
@@ -1033,6 +1065,7 @@ void run_tests()
        DSTACK(__FUNCTION_NAME);
        dstream<<"run_tests() started"<<std::endl;
        TEST(TestUtilities);
+       TEST(TestSettings);
        TEST(TestCompress);
        TEST(TestMapNode);
        TEST(TestVoxelManipulator);
index 23fa1129da78bca05411aadacdacca0f2f99816e..27f86c732081366e986db4c5f4ffc949ac4313b0 100644 (file)
@@ -179,7 +179,7 @@ void TextureSource::processQueue()
 
                dstream<<"INFO: TextureSource::processQueue(): "
                                <<"got texture request with "
-                               <<"name="<<request.key
+                               <<"name=\""<<request.key<<"\""
                                <<std::endl;
 
                GetResult<std::string, u32, u8, u8>
@@ -194,7 +194,7 @@ void TextureSource::processQueue()
 
 u32 TextureSource::getTextureId(const std::string &name)
 {
-       //dstream<<"INFO: getTextureId(): name="<<name<<std::endl;
+       //dstream<<"INFO: getTextureId(): \""<<name<<"\""<<std::endl;
 
        {
                /*
@@ -218,7 +218,7 @@ u32 TextureSource::getTextureId(const std::string &name)
        }
        else
        {
-               dstream<<"INFO: getTextureId(): Queued: name="<<name<<std::endl;
+               dstream<<"INFO: getTextureId(): Queued: name=\""<<name<<"\""<<std::endl;
 
                // We're gonna ask the result to be put into here
                ResultQueue<std::string, u32, u8, u8> result_queue;
@@ -226,8 +226,8 @@ u32 TextureSource::getTextureId(const std::string &name)
                // Throw a request in
                m_get_texture_queue.add(name, 0, 0, &result_queue);
                
-               dstream<<"INFO: Waiting for texture from main thread, name="
-                               <<name<<std::endl;
+               dstream<<"INFO: Waiting for texture from main thread, name=\""
+                               <<name<<"\""<<std::endl;
                
                try
                {
@@ -276,7 +276,7 @@ video::IImage* generate_image_from_scratch(std::string name,
 */
 u32 TextureSource::getTextureIdDirect(const std::string &name)
 {
-       dstream<<"INFO: getTextureIdDirect(): name="<<name<<std::endl;
+       //dstream<<"INFO: getTextureIdDirect(): name=\""<<name<<"\""<<std::endl;
 
        // Empty name means texture 0
        if(name == "")
@@ -305,14 +305,14 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
                n = m_name_to_id.find(name);
                if(n != NULL)
                {
-                       dstream<<"INFO: getTextureIdDirect(): name="<<name
-                                       <<" found in cache"<<std::endl;
+                       dstream<<"INFO: getTextureIdDirect(): \""<<name
+                                       <<"\" found in cache"<<std::endl;
                        return n->getValue();
                }
        }
 
-       dstream<<"INFO: getTextureIdDirect(): name="<<name
-                       <<" NOT found in cache. Creating it."<<std::endl;
+       dstream<<"INFO: getTextureIdDirect(): \""<<name
+                       <<"\" NOT found in cache. Creating it."<<std::endl;
        
        /*
                Get the base image
@@ -346,12 +346,13 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        {
                // Construct base name
                base_image_name = name.substr(0, last_separator_position);
-               dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
-                               " to get base image, name="<<base_image_name<<std::endl;
+               /*dstream<<"INFO: getTextureIdDirect(): Calling itself recursively"
+                               " to get base image of \""<<name<<"\" = \""
+                <<base_image_name<<"\""<<std::endl;*/
                base_image_id = getTextureIdDirect(base_image_name);
        }
        
-       dstream<<"base_image_id="<<base_image_id<<std::endl;
+       //dstream<<"base_image_id="<<base_image_id<<std::endl;
        
        video::IVideoDriver* driver = m_device->getVideoDriver();
        assert(driver);
@@ -393,9 +394,9 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
                                        core::rect<s32>(pos_from, dim) // from
                        );
 
-                       dstream<<"INFO: getTextureIdDirect(): Loaded \""
+                       /*dstream<<"INFO: getTextureIdDirect(): Loaded \""
                                        <<base_image_name<<"\" from image cache"
-                                       <<std::endl;
+                                       <<std::endl;*/
                }
        }
        
@@ -405,7 +406,7 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        */
 
        std::string last_part_of_name = name.substr(last_separator_position+1);
-       dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
+       //dstream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
 
        // Generate image according to part of name
        if(generate_image(last_part_of_name, baseimg, m_device) == false)
@@ -447,8 +448,8 @@ u32 TextureSource::getTextureIdDirect(const std::string &name)
        m_atlaspointer_cache.push_back(nap);
        m_name_to_id.insert(name, id);
 
-       dstream<<"INFO: getTextureIdDirect(): name="<<name
-                       <<": succesfully returning id="<<id<<std::endl;
+       /*dstream<<"INFO: getTextureIdDirect(): "
+                       <<"Returning id="<<id<<" for name \""<<name<<"\""<<std::endl;*/
        
        return id;
 }
@@ -580,6 +581,9 @@ void TextureSource::buildMainAtlas()
                        break;
                }
                
+        dstream<<"INFO: TextureSource::buildMainAtlas(): Adding \""<<name
+                <<"\" to texture atlas"<<std::endl;
+
                // Tile it a few times in the X direction
                u16 xwise_tiling = 16;
                for(u32 j=0; j<xwise_tiling; j++)
@@ -670,8 +674,8 @@ void TextureSource::buildMainAtlas()
 video::IImage* generate_image_from_scratch(std::string name,
                IrrlichtDevice *device)
 {
-       dstream<<"INFO: generate_image_from_scratch(): "
-                       "name="<<name<<std::endl;
+       /*dstream<<"INFO: generate_image_from_scratch(): "
+                       "\""<<name<<"\""<<std::endl;*/
        
        video::IVideoDriver* driver = device->getVideoDriver();
        assert(driver);
@@ -708,8 +712,9 @@ video::IImage* generate_image_from_scratch(std::string name,
        {
                // Construct base name
                base_image_name = name.substr(0, last_separator_position);
-               dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
-                               " to get base image, name="<<base_image_name<<std::endl;
+               /*dstream<<"INFO: generate_image_from_scratch(): Calling itself recursively"
+                               " to get base image of \""<<name<<"\" = \""
+                <<base_image_name<<"\""<<std::endl;*/
                baseimg = generate_image_from_scratch(base_image_name, device);
        }
        
@@ -719,7 +724,7 @@ video::IImage* generate_image_from_scratch(std::string name,
        */
 
        std::string last_part_of_name = name.substr(last_separator_position+1);
-       dstream<<"last_part_of_name="<<last_part_of_name<<std::endl;
+       //dstream<<"last_part_of_name=\""<<last_part_of_name<<"\""<<std::endl;
        
        // Generate image according to part of name
        if(generate_image(last_part_of_name, baseimg, device) == false)
@@ -744,21 +749,21 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
        {
                // A normal texture; load it from a file
                std::string path = getTexturePath(part_of_name.c_str());
-               dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
-                               <<"\""<<std::endl;
+               /*dstream<<"INFO: generate_image(): Loading path \""<<path
+                               <<"\""<<std::endl;*/
                
                video::IImage *image = driver->createImageFromFile(path.c_str());
 
                if(image == NULL)
                {
-                       dstream<<"WARNING: Could not load image \""<<part_of_name
-                                       <<"\" from path \""<<path<<"\""
+                       dstream<<"WARNING: generate_image(): Could not load image \""
+                    <<part_of_name<<"\" from path \""<<path<<"\""
                                        <<" while building texture"<<std::endl;
 
                        //return false;
 
-                       dstream<<"WARNING: Creating a dummy"<<" image for \""
-                                       <<part_of_name<<"\""<<std::endl;
+                       dstream<<"WARNING: generate_image(): Creating a dummy"
+                    <<" image for \""<<part_of_name<<"\""<<std::endl;
 
                        // Just create a dummy image
                        //core::dimension2d<u32> dim(2,2);
@@ -782,7 +787,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                // If base image is NULL, load as base.
                if(baseimg == NULL)
                {
-                       dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
+                       //dstream<<"INFO: Setting "<<part_of_name<<" as base"<<std::endl;
                        /*
                                Copy it this way to get an alpha channel.
                                Otherwise images with alpha cannot be blitted on 
@@ -796,7 +801,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                // Else blit on base.
                else
                {
-                       dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
+                       //dstream<<"INFO: Blitting "<<part_of_name<<" on base"<<std::endl;
                        // Size of the copied area
                        core::dimension2d<u32> dim = image->getDimension();
                        //core::dimension2d<u32> dim(16,16);
@@ -817,7 +822,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
        {
                // A special texture modification
 
-               dstream<<"INFO: getTextureIdDirect(): generating special "
+               dstream<<"INFO: generate_image(): generating special "
                                <<"modification \""<<part_of_name<<"\""
                                <<std::endl;
                
@@ -840,9 +845,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                {
                        if(baseimg == NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
-                                               <<"for part_of_name="<<part_of_name
-                                               <<", cancelling."<<std::endl;
+                               dstream<<"WARNING: generate_image(): baseimg==NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
                                return false;
                        }
                        
@@ -977,9 +982,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                {
                        if(baseimg == NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): baseimg==NULL "
-                                               <<"for part_of_name="<<part_of_name
-                                               <<", cancelling."<<std::endl;
+                               dstream<<"WARNING: generate_image(): baseimg==NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
                                return false;
                        }
 
@@ -997,9 +1002,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                {
                        if(baseimg != NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
-                                               <<"for part_of_name="<<part_of_name
-                                               <<", cancelling."<<std::endl;
+                               dstream<<"WARNING: generate_image(): baseimg!=NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
                                return false;
                        }
 
@@ -1007,14 +1012,14 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 
                        std::string path = getTexturePath(filename.c_str());
 
-                       dstream<<"INFO: getTextureIdDirect(): Loading path \""<<path
+                       dstream<<"INFO: generate_image(): Loading path \""<<path
                                        <<"\""<<std::endl;
                        
                        video::IImage *image = driver->createImageFromFile(path.c_str());
                        
                        if(image == NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): Loading path \""
+                               dstream<<"WARNING: generate_image(): Loading path \""
                                                <<path<<"\" failed"<<std::endl;
                        }
                        else
@@ -1048,9 +1053,9 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                {
                        if(baseimg != NULL)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): baseimg!=NULL "
-                                               <<"for part_of_name="<<part_of_name
-                                               <<", cancelling."<<std::endl;
+                               dstream<<"WARNING: generate_image(): baseimg!=NULL "
+                                               <<"for part_of_name=\""<<part_of_name
+                                               <<"\", cancelling."<<std::endl;
                                return false;
                        }
 
@@ -1066,7 +1071,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
 
                        if(driver->queryFeature(video::EVDF_RENDER_TO_TARGET) == false)
                        {
-                               dstream<<"WARNING: getTextureIdDirect(): EVDF_RENDER_TO_TARGET"
+                               dstream<<"WARNING: generate_image(): EVDF_RENDER_TO_TARGET"
                                                " not supported. Creating fallback image"<<std::endl;
                                baseimg = generate_image_from_scratch(
                                                imagename_top, device);
@@ -1075,7 +1080,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                        
                        u32 w0 = 64;
                        u32 h0 = 64;
-                       dstream<<"INFO: inventorycube w="<<w0<<" h="<<h0<<std::endl;
+                       //dstream<<"INFO: inventorycube w="<<w0<<" h="<<h0<<std::endl;
                        core::dimension2d<u32> dim(w0,h0);
                        
                        // Generate images for the faces of the cube
@@ -1177,7 +1182,7 @@ bool generate_image(std::string part_of_name, video::IImage *& baseimg,
                }
                else
                {
-                       dstream<<"WARNING: getTextureIdDirect(): Invalid "
+                       dstream<<"WARNING: generate_image(): Invalid "
                                        " modification: \""<<part_of_name<<"\""<<std::endl;
                }
        }
index 5938f9016d7e202d161cc9c5d722c2870e9cf4ad..616a197e3abfdd79afc77ac2417201d36f596da8 100644 (file)
@@ -93,7 +93,7 @@ void VoxelManipulator::print(std::ostream &o, VoxelPrintMode mode)
                                else
                                {
                                        c = 'X';
-                                       u8 m = m_data[m_area.index(x,y,z)].d;
+                                       content_t m = m_data[m_area.index(x,y,z)].getContent();
                                        u8 pr = m_data[m_area.index(x,y,z)].param2;
                                        if(mode == VOXELPRINT_MATERIAL)
                                        {
index 5f3aab456cdcdc2b2fffc9b855cc4b156ca4b3c3..162ceb204476f1b6247a70fbc05e3bdd70489498 100755 (executable)
@@ -170,6 +170,9 @@ stuff = {}
 
 starttime = time.time()
 
+def data_is_air(d):
+       return (d == 254 or d == 126)
+
 # Go through all sectors.
 for n in range(len(xlist)):
        #if n > 500:
@@ -283,7 +286,7 @@ for n in range(len(xlist)):
                        for (x, z) in reversed(pixellist):
                                for y in reversed(range(16)):
                                        datapos = x + y * 16 + z * 256
-                                       if(ord(mapdata[datapos]) != 254 and ord(mapdata[datapos]) in colors):
+                                       if(not data_is_air(ord(mapdata[datapos])) and ord(mapdata[datapos]) in colors):
                                                if(ord(mapdata[datapos]) == 2 or ord(mapdata[datapos]) == 9):
                                                        water[(x, z)] += 1
                                                        # Add dummy stuff for drawing sea without seabed
@@ -293,7 +296,7 @@ for n in range(len(xlist)):
                                                        # 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]), water[(x, z)])
                                                        break
-                                       elif(ord(mapdata[datapos]) != 254 and ord(mapdata[datapos]) not in colors):
+                                       elif(not data_is_air(ord(mapdata[datapos])) and ord(mapdata[datapos]) not in colors):
                                                print "strange block: " + xhex + "/" + zhex + "/" + yhex + " x: " + str(x) + " y: " + str(y) + " z: " + str(z) + " palikka: " + str(ord(mapdata[datapos]))
                
                # After finding all the pixels in the sector, we can move on to the next sector without having to continue the Y axis.
@@ -324,7 +327,7 @@ for n in range(len(xlist)):
                                for (x, z) in reversed(pixellist):
                                        for y in reversed(range(16)):
                                                datapos = x + y * 16 + z * 256
-                                               if(ord(mapdata[datapos]) != 254 and ord(mapdata[datapos]) in colors):
+                                               if(not data_is_air(ord(mapdata[datapos])) and ord(mapdata[datapos]) in colors):
                                                        if(ord(mapdata[datapos]) == 2 or ord(mapdata[datapos]) == 9):
                                                                water[(x, z)] += 1
                                                                # Add dummy stuff for drawing sea without seabed
@@ -334,7 +337,7 @@ for n in range(len(xlist)):
                                                                # 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]), water[(x, z)])
                                                                break
-                                               elif(ord(mapdata[datapos]) != 254 and ord(mapdata[datapos]) not in colors):
+                                               elif(not data_is_air(ord(mapdata[datapos])) and ord(mapdata[datapos]) not in colors):
                                                        print "outo palikka: " + xhex + "/" + zhex + "/" + yhex + " x: " + str(x) + " y: " + str(y) + " z: " + str(z) + " palikka: " + str(ord(mapdata[datapos]))
                        
                        # After finding all the pixels in the sector, we can move on to the next sector without having to continue the Y axis.