diff options
70 files changed, 3691 insertions, 358 deletions
diff --git a/.gitignore b/.gitignore index ce00d585e..f0c372ab7 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,4 @@ cmake_install.cmake src/jthread/libjthread.a debug.txt bin/debug.txt - +minetestmapper/map.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 6403a9dd9..15f4a6453 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,7 +59,7 @@ elseif(UNIX) # Linux, BSD etc set(EXAMPLE_CONF_DIR "share/doc/minetest") endif() -install(FILES "README.txt" DESTINATION "${DOCDIR}") +install(FILES "doc/README.txt" DESTINATION "${DOCDIR}") install(FILES "minetest.conf.example" DESTINATION "${DOCDIR}") # @@ -104,7 +104,7 @@ elseif(APPLE) set(CPACK_BUNDLE_ICON "") set(CPACK_BUNDLE_PLIST "") set(CPACK_BUNDLE_STARTUP_COMMAND "Contents/MacOS/minetest") - set(CPACK_GENERATOR Bundle) + set(CPACK_GENERATOR "Bundle") else() set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-${VERSION_STRING}-linux") set(CPACK_GENERATOR TGZ) @@ -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 (changes apply after restart) +* 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). diff --git a/README.txt b/README.txt index 41048992e..662f2770b 100644 --- a/README.txt +++ b/README.txt @@ -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/FindJthread.cmake b/cmake/Modules/FindJthread.cmake new file mode 100644 index 000000000..302a3c22f --- /dev/null +++ b/cmake/Modules/FindJthread.cmake @@ -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 index 000000000..ecce6e38e --- /dev/null +++ b/cmake/Modules/FindSqlite3.cmake @@ -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 Binary files differnew file mode 100644 index 000000000..176fb6aa9 --- /dev/null +++ b/data/book.png diff --git a/data/bookshelf.png b/data/bookshelf.png Binary files differnew file mode 100644 index 000000000..5ecc50ff3 --- /dev/null +++ b/data/bookshelf.png diff --git a/data/brick.png b/data/brick.png Binary files differnew file mode 100644 index 000000000..32d77f347 --- /dev/null +++ b/data/brick.png diff --git a/data/cactus_side.png b/data/cactus_side.png Binary files differnew file mode 100644 index 000000000..fc479fde6 --- /dev/null +++ b/data/cactus_side.png diff --git a/data/cactus_top.png b/data/cactus_top.png Binary files differnew file mode 100644 index 000000000..f9e68df51 --- /dev/null +++ b/data/cactus_top.png diff --git a/data/clay.png b/data/clay.png Binary files differnew file mode 100644 index 000000000..3557429d8 --- /dev/null +++ b/data/clay.png diff --git a/data/clay_brick.png b/data/clay_brick.png Binary files differnew file mode 100644 index 000000000..e36648e48 --- /dev/null +++ b/data/clay_brick.png diff --git a/data/fence.png b/data/fence.png Binary files differnew file mode 100644 index 000000000..0b99f0eb5 --- /dev/null +++ b/data/fence.png diff --git a/data/firefly.png b/data/firefly.png Binary files differnew file mode 100644 index 000000000..d5a444b03 --- /dev/null +++ b/data/firefly.png diff --git a/data/lump_of_clay.png b/data/lump_of_clay.png Binary files differnew file mode 100644 index 000000000..be0bab9d7 --- /dev/null +++ b/data/lump_of_clay.png diff --git a/data/paper.png b/data/paper.png Binary files differnew file mode 100644 index 000000000..ae5c06bc6 --- /dev/null +++ b/data/paper.png diff --git a/data/papyrus.png b/data/papyrus.png Binary files differnew file mode 100644 index 000000000..bf0dec7fe --- /dev/null +++ b/data/papyrus.png diff --git a/data/player.png b/data/player.png Binary files differindex 90adf9747..60ac4854b 100644 --- a/data/player.png +++ b/data/player.png diff --git a/data/player_back.png b/data/player_back.png Binary files differindex 530aa7519..447c1fd8f 100644 --- a/data/player_back.png +++ b/data/player_back.png diff --git a/data/rail.png b/data/rail.png Binary files differnew file mode 100644 index 000000000..18176d9f3 --- /dev/null +++ b/data/rail.png diff --git a/data/rail_crossing.png b/data/rail_crossing.png Binary files differnew file mode 100644 index 000000000..984640577 --- /dev/null +++ b/data/rail_crossing.png diff --git a/data/rail_curved.png b/data/rail_curved.png Binary files differnew file mode 100644 index 000000000..62afa3d2b --- /dev/null +++ b/data/rail_curved.png diff --git a/data/rail_t_junction.png b/data/rail_t_junction.png Binary files differnew file mode 100644 index 000000000..9985f63cd --- /dev/null +++ b/data/rail_t_junction.png diff --git a/data/rat.png b/data/rat.png Binary files differindex d1a0e2ae2..96d44c3fa 100644 --- a/data/rat.png +++ b/data/rat.png diff --git a/data/sandstone.png b/data/sandstone.png Binary files differnew file mode 100644 index 000000000..c4759b4d0 --- /dev/null +++ b/data/sandstone.png diff --git a/doc/README.txt b/doc/README.txt new file mode 100644 index 000000000..645e2a560 --- /dev/null +++ b/doc/README.txt @@ -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 index 000000000..a60509403 --- /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 index 000000000..f00ec608c --- /dev/null +++ b/makepackage_binary.sh @@ -0,0 +1,63 @@ +#!/bin/sh + +PACKAGEDIR=../minetest-packages +PACKAGENAME=minetest-c55-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 + +cp minetest.conf.example $PACKAGEPATH/ + +cp bin/minetest.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 + +cd $PACKAGEDIR +rm $PACKAGENAME.zip +zip -r $PACKAGENAME.zip $PACKAGENAME + diff --git a/minetest-icon.svg b/minetest-icon.svg new file mode 100644 index 000000000..46c9ac702 --- /dev/null +++ b/minetest-icon.svg @@ -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 index 000000000..e70f56e1e --- /dev/null +++ b/minetestmapper/colors.txt @@ -0,0 +1,25 @@ +0 128 128 128
+1 107 134 51
+2 39 66 106
+3 255 255 0
+4 86 58 31
+5 48 95 8
+6 102 129 38
+7 178 178 0
+8 101 84 36
+9 39 66 106
+12 104 78 42
+13 210 194 156
+14 117 86 41
+15 128 79 0
+16 118 118 118
+18 123 123 123
+19 199 199 199
+20 183 183 222
+21 103 78 42
+22 219 202 178
+23 78 154 6
+24 204 0 0
+25 211 215 207
+26 138 226 52
+27 104 78 42
diff --git a/minetestmapper/minetestmapper2.py b/minetestmapper/minetestmapper2.py new file mode 100755 index 000000000..8dc3de2f4 --- /dev/null +++ b/minetestmapper/minetestmapper2.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Made by j0gge, modified by celeron55
+
+# This program is free software. It comes without any warranty, to
+# the extent permitted by applicable law. You can redistribute it
+# and/or modify it under the terms of the Do What The Fuck You Want
+# To Public License, Version 2, as published by Sam Hocevar. See
+# http://sam.zoy.org/wtfpl/COPYING for more details.
+
+# Requires Python Imaging Library: http://www.pythonware.com/products/pil/
+
+# Some speed-up: ...lol, actually it slows it down.
+#import psyco ; psyco.full()
+#from psyco.classes import *
+
+import zlib
+import Image, ImageDraw
+import os
+import string
+import time
+
+def hex_to_int(h):
+ i = int(h,16)
+ if(i > 2047):
+ i-=4096
+ return i
+
+def hex4_to_int(h):
+ i = int(h,16)
+ if(i > 32767):
+ i-=65536
+ return i
+
+def int_to_hex3(i):
+ if(i < 0):
+ return "%03X" % (i + 4096)
+ else:
+ return "%03X" % i
+
+def int_to_hex4(i):
+ if(i < 0):
+ return "%04X" % (i + 65536)
+ else:
+ return "%04X" % i
+
+def limit(i,l,h):
+ if(i>h):
+ i=h
+ if(i<l):
+ i=l
+ return i
+
+# Fix these!
+path="../map/"
+output="map.png"
+
+sector_xmin = -1000/16
+sector_xmax = 1000/16
+sector_zmin = -1000/16
+sector_zmax = 1000/16
+
+# Load color information for the blocks.
+colors = {}
+f = file("colors.txt")
+for line in f:
+ values = string.split(line)
+ colors[int(values[0])] = (int(values[1]), int(values[2]), int(values[3]))
+f.close()
+
+xlist = []
+zlist = []
+
+# List all sectors to memory and calculate the width and heigth of the resulting picture.
+if os.path.exists(path + "sectors2"):
+ for filename in os.listdir(path + "sectors2"):
+ for filename2 in os.listdir(path + "sectors2/" + filename):
+ x = hex_to_int(filename)
+ z = hex_to_int(filename2)
+ if x < sector_xmin or x > sector_xmax:
+ continue
+ if z < sector_zmin or z > sector_zmax:
+ continue
+ xlist.append(x)
+ zlist.append(z)
+
+if os.path.exists(path + "sectors"):
+ for filename in os.listdir(path + "sectors"):
+ x = hex4_to_int(filename[:4])
+ z = hex4_to_int(filename[-4:])
+ if x < sector_xmin or x > sector_xmax:
+ continue
+ if z < sector_zmin or z > sector_zmax:
+ continue
+ xlist.append(x)
+ zlist.append(z)
+
+w = (max(xlist) - min(xlist)) * 16 + 16
+h = (max(zlist) - min(zlist)) * 16 + 16
+
+print "w="+str(w)+" h="+str(h)
+
+im = Image.new("RGB", (w, h), "white")
+impix = im.load()
+
+stuff={}
+
+starttime = time.time()
+
+# Go through all sectors.
+for n in range(len(xlist)):
+ #if n > 500:
+ # break
+ if n % 200 == 0:
+ nowtime = time.time()
+ dtime = nowtime - starttime
+ n_per_second = 1.0 * n / dtime
+ if n_per_second != 0:
+ seconds_per_n = 1.0 / n_per_second
+ time_guess = seconds_per_n * len(xlist)
+ remaining_s = time_guess - dtime
+ remaining_minutes = int(remaining_s / 60)
+ remaining_s -= remaining_minutes * 60;
+ print("Processing sector "+str(n)+" of "+str(len(xlist))
+ +" ("+str(round(100.0*n/len(xlist), 1))+"%)"
+ +" (ETA: "+str(remaining_minutes)+"m "
+ +str(int(remaining_s))+"s)")
+
+ xpos = xlist[n]
+ zpos = zlist[n]
+
+ xhex = int_to_hex3(xpos)
+ zhex = int_to_hex3(zpos)
+ xhex4 = int_to_hex4(xpos)
+ zhex4 = int_to_hex4(zpos)
+
+ sector1 = xhex4.lower() + zhex4.lower()
+ sector2 = xhex.lower() + "/" + zhex.lower()
+
+ ylist=[]
+
+ sectortype = ""
+
+ try:
+ for filename in os.listdir(path + "sectors/" + sector1):
+ if(filename != "meta"):
+ pos = int(filename,16)
+ if(pos > 32767):
+ pos-=65536
+ ylist.append(pos)
+ sectortype = "old"
+ except OSError:
+ pass
+
+ if sectortype != "old":
+ try:
+ for filename in os.listdir(path + "sectors2/" + sector2):
+ if(filename != "meta"):
+ pos = int(filename,16)
+ if(pos > 32767):
+ pos-=65536
+ ylist.append(pos)
+ sectortype = "new"
+ except OSError:
+ pass
+
+ if sectortype == "":
+ continue
+
+ ylist.sort()
+
+ # Make a list of pixels of the sector that are to be looked for.
+ pixellist = []
+ for x in range(16):
+ for y in range(16):
+ pixellist.append((x,y))
+
+ # Go through the Y axis from top to bottom.
+ for ypos in reversed(ylist):
+
+ yhex = int_to_hex4(ypos)
+
+ filename = ""
+ if sectortype == "old":
+ filename = path + "sectors/" + sector1 + "/" + yhex.lower()
+ else:
+ filename = path + "sectors2/" + sector2 + "/" + yhex.lower()
+
+ f = file(filename, "rb")
+
+ # Let's just memorize these even though it's not really necessary.
+ version = f.read(1)
+ flags = f.read(1)
+
+ dec_o = zlib.decompressobj()
+ try:
+ mapdata = dec_o.decompress(f.read())
+ except:
+ mapdata = []
+
+ f.close()
+
+ if(len(mapdata)<4096):
+ print "bad: " + xhex+zhex+"/"+yhex + " " + len(mapdata)
+ else:
+ chunkxpos=xpos*16
+ chunkypos=ypos*16
+ chunkzpos=zpos*16
+ for (x,z) in reversed(pixellist):
+ for y in reversed(range(16)):
+ datapos=x+y*16+z*256
+ if(ord(mapdata[datapos])!=254):
+ try:
+ pixellist.remove((x,z))
+ # Memorize information on the type and height of the block and for drawing the picture.
+ stuff[(chunkxpos+x,chunkzpos+z)]=(chunkypos+y,ord(mapdata[datapos]))
+ break
+ except:
+ print "strange block: " + xhex+zhex+"/"+yhex + " x: " + str(x) + " y: " + str(y) + " z: " + str(z) + " block: " + str(ord(mapdata[datapos]))
+
+ # After finding all the pixeld in the sector, we can move on to the next sector without having to continue the Y axis.
+ if(len(pixellist)==0):
+ break
+
+print "Drawing image"
+# Drawing the picture
+starttime = time.time()
+n = 0
+minx = min(xlist)
+minz = min(zlist)
+for (x,z) in stuff.iterkeys():
+ if n % 500000 == 0:
+ nowtime = time.time()
+ dtime = nowtime - starttime
+ n_per_second = 1.0 * n / dtime
+ if n_per_second != 0:
+ listlen = len(stuff)
+ seconds_per_n = 1.0 / n_per_second
+ time_guess = seconds_per_n * listlen
+ remaining_s = time_guess - dtime
+ remaining_minutes = int(remaining_s / 60)
+ remaining_s -= remaining_minutes * 60;
+ print("Drawing pixel "+str(n)+" of "+str(listlen)
+ +" ("+str(round(100.0*n/listlen, 1))+"%)"
+ +" (ETA: "+str(remaining_minutes)+"m "
+ +str(int(remaining_s))+"s)")
+ n += 1
+
+ (r,g,b)=colors[stuff[(x,z)][1]]
+
+ # Comparing heights of a couple of adjacent blocks and changing brightness accordingly.
+ try:
+ y1=stuff[(x-1,z)][0]
+ y2=stuff[(x,z-1)][0]
+ y=stuff[(x,z)][0]
+
+ d=(y-y1+y-y2)*12
+
+ if(d>36):
+ d=36
+
+ r=limit(r+d,0,255)
+ g=limit(g+d,0,255)
+ b=limit(b+d,0,255)
+ except:
+ pass
+ #impix[w-1-(x-minx*16),h-1-(z-minz*16)]=(r,g,b)
+ impix[x-minx*16,h-1-(z-minz*16)]=(r,g,b)
+
+# Flip the picture to make it right and save.
+#print "Transposing"
+#im=im.transpose(Image.FLIP_TOP_BOTTOM)
+print "Saving"
+im.save(output)
diff --git a/pnoise.py b/pnoise.py new file mode 100644 index 000000000..fcab5ac15 --- /dev/null +++ b/pnoise.py @@ -0,0 +1,102 @@ +# +# A python perlin noise implementation, from +# http://www.fundza.com/c4serious/noise/perlin/perlin.html +# +# This is used for testing how to create maps with a python script. +# + +import math +p = ( +151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103, +30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197, +62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20, +125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231, +83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102, +143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200, +196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226, +250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16, +58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70, +221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113, +224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144, +12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181, +199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236, +205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, +151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103, +30,69,142,8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197, +62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,174,20, +125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231, +83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,102, +143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200, +196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226, +250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16, +58,17,182,189,28,42,223,183,170,213,119,248,152,2,44,154,163,70, +221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113, +224,232,178,185,112,104,218,246,97,228,251,34,242,193,238,210,144, +12,191,179,162,241,81,51,145,235,249,14,239,107,49,192,214,31,181, +199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236, +205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180) + +def lerp(t, a, b): + return a + t * (b - a) + +def fade(t): + return t * t * t * (t * (t * 6 - 15) + 10) + +def grad(hash, x, y, z): + h = hash & 15 + if h < 8: + u = x + else: + u = y + if h < 4: + v = y + elif h == 12 or h == 14: + v = x + else: + v = z + if h & 1 != 0: + u = -u + if h & 2 != 0: + v = -v + return u + v + +def pnoise(x, y, z): + global p + X = int(math.floor(x)) & 255 + Y = int(math.floor(y)) & 255 + Z = int(math.floor(z)) & 255 + x -= math.floor(x) + y -= math.floor(y) + z -= math.floor(z) + + u = fade(x) + v = fade(y) + w = fade(z) + + A = p[X] + Y + AA = p[A] + Z + AB = p[A + 1] + Z + B = p[X + 1] + Y + BA = p[B] + Z + BB = p[B + 1] + Z + + pAA = p[AA] + pAB = p[AB] + pBA = p[BA] + pBB = p[BB] + pAA1 = p[AA + 1] + pBA1 = p[BA + 1] + pAB1 = p[AB + 1] + pBB1 = p[BB + 1] + + gradAA = grad(pAA, x, y, z) + gradBA = grad(pBA, x-1, y, z) + gradAB = grad(pAB, x, y-1, z) + gradBB = grad(pBB, x-1, y-1, z) + gradAA1 = grad(pAA1,x, y, z-1) + gradBA1 = grad(pBA1,x-1, y, z-1) + gradAB1 = grad(pAB1,x, y-1, z-1) + gradBB1 = grad(pBB1,x-1, y-1, z-1) + return lerp(w, + lerp(v, lerp(u, gradAA, gradBA), lerp(u, gradAB, gradBB)), + lerp(v, lerp(u, gradAA1,gradBA1),lerp(u, gradAB1,gradBB1))) diff --git a/po/de/minetest-c55.po b/po/de/minetest-c55.po new file mode 100644 index 000000000..c5ec1c7a0 --- /dev/null +++ b/po/de/minetest-c55.po @@ -0,0 +1,125 @@ +# 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-20 16:57+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:202 +msgid "Address/Port" +msgstr "Adresse / Port" + +#: src/guiMainMenu.cpp:220 +msgid "Leave address blank to start a local server." +msgstr "Lasse die Adresse frei um einen eigenen Server zu starten" + +#: src/guiMainMenu.cpp:226 +msgid "Fancy trees" +msgstr "Schöne Bäume" + +#: src/guiMainMenu.cpp:232 +msgid "Smooth Lighting" +msgstr "Besseres Licht" + +#: src/guiMainMenu.cpp:239 +msgid "Start Game / Connect" +msgstr "Spiel starten / Verbinden" + +#: src/guiMainMenu.cpp:247 +msgid "Change keys" +msgstr "Tastenbelegung ändern" + +#: src/guiMainMenu.cpp:269 +msgid "Creative Mode" +msgstr "Kreativitätsmodus" + +#: src/guiMainMenu.cpp:274 +msgid "Enable Damage" +msgstr "Schaden einschalten" + +#: src/guiMainMenu.cpp:281 +msgid "Delete map" +msgstr "Karte löschen" + +#: src/guiMessageMenu.cpp:92 +#: src/guiTextInputMenu.cpp:110 +msgid "Proceed" +msgstr "Fortsetzen" + +#: src/guiPasswordChange.cpp:102 +msgid "Old Password" +msgstr "Altes Passwort" + +#: src/guiPasswordChange.cpp:116 +msgid "New Password" +msgstr "Neues Passwort" + +#: src/guiPasswordChange.cpp:129 +msgid "Confirm Password" +msgstr "Passwort wiederholen" + +#: src/guiPasswordChange.cpp:143 +msgid "Change" +msgstr "Ändern" + +#: src/guiPasswordChange.cpp:151 +msgid "Passwords do not match!" +msgstr "Passwörter passen nicht zusammen" + +#: src/guiPauseMenu.cpp:109 +msgid "Continue" +msgstr "Weiter" + +#: src/guiPauseMenu.cpp:115 +msgid "Change Password" +msgstr "Passwort ändern" + +#: src/guiPauseMenu.cpp:121 +msgid "Disconnect" +msgstr "Verbindung trennen" + +#: src/guiPauseMenu.cpp:127 +msgid "Exit to OS" +msgstr "Programm beenden" + +#: src/guiPauseMenu.cpp:134 +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/fr/minetest-c55.po b/po/fr/minetest-c55.po new file mode 100644 index 000000000..cfb76ae1a --- /dev/null +++ b/po/fr/minetest-c55.po @@ -0,0 +1,125 @@ +# 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-21 02: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:202 +msgid "Address/Port" +msgstr "Adresse / Port" + +#: src/guiMainMenu.cpp:220 +msgid "Leave address blank to start a local server." +msgstr "Laisser l'adresse vide pour lancer un serveur local." + +#: src/guiMainMenu.cpp:226 +msgid "Fancy trees" +msgstr "Arbres spéciaux" + +#: src/guiMainMenu.cpp:232 +msgid "Smooth Lighting" +msgstr "Lumière douce" + +#: src/guiMainMenu.cpp:239 +msgid "Start Game / Connect" +msgstr "Démarrer / Connecter" + +#: src/guiMainMenu.cpp:247 +msgid "Change keys" +msgstr "Changer touches" + +#: src/guiMainMenu.cpp:269 +msgid "Creative Mode" +msgstr "Mode créatif" + +#: src/guiMainMenu.cpp:274 +msgid "Enable Damage" +msgstr "Activer blessures" + +#: src/guiMainMenu.cpp:281 +msgid "Delete map" +msgstr "Supprimer carte" + +#: src/guiMessageMenu.cpp:92 +#: src/guiTextInputMenu.cpp:110 +msgid "Proceed" +msgstr "OK" + +#: src/guiPasswordChange.cpp:102 +msgid "Old Password" +msgstr "Ancien mot de passe" + +#: src/guiPasswordChange.cpp:116 +msgid "New Password" +msgstr "Nouveau mot de passe" + +#: src/guiPasswordChange.cpp:129 +msgid "Confirm Password" +msgstr "Confirmer mot de passe" + +#: src/guiPasswordChange.cpp:143 +msgid "Change" +msgstr "Changer" + +#: src/guiPasswordChange.cpp:151 +msgid "Passwords do not match!" +msgstr "Mauvaise correspondance!" + +#: src/guiPauseMenu.cpp:109 +msgid "Continue" +msgstr "Continuer" + +#: src/guiPauseMenu.cpp:115 +msgid "Change Password" +msgstr "Changer mot de passe" + +#: src/guiPauseMenu.cpp:121 +msgid "Disconnect" +msgstr "Déconnection" + +#: src/guiPauseMenu.cpp:127 +msgid "Exit to OS" +msgstr "Quitter le jeu" + +#: src/guiPauseMenu.cpp:134 +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" + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 847269456..532ac9fee 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,14 @@ 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(GETTEXT_INCLUDE_DIR "${PROJECT_SOURCE_DIR}/../../gettext/include" + CACHE PATH "gettext include directory") + set(GETTEXT_BIN_DIR "${PROJECT_SOURCE_DIR}/../../gettext/bin" + CACHE PATH "gettext bin directory") + set(GETTEXT_LIBRARIES "${PROJECT_SOURCE_DIR}/../../gettext/lib/intl.lib" + CACHE FILEPATH "gettext intl.lib") + set(IRRLICHT_SOURCE_DIR "${PROJECT_SOURCE_DIR}/../../irrlicht-1.7.2" + CACHE PATH "irrlicht dir") else() # Unix probably if(BUILD_CLIENT) @@ -55,6 +63,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 +121,7 @@ set(minetest_SRCS clouds.cpp clientobject.cpp guiMainMenu.cpp + guiKeyChangeMenu.cpp guiMessageMenu.cpp guiTextInputMenu.cpp guiInventoryMenu.cpp @@ -133,8 +145,9 @@ 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) @@ -150,10 +163,11 @@ if(BUILD_CLIENT) ${BZIP2_LIBRARIES} ${PNG_LIBRARIES} ${X11_LIBRARIES} + ${GETTEXT_LIBRARIES} ${PLATFORM_LIBS} ${CLIENT_PLATFORM_LIBS} - jthread - sqlite3 + ${JTHREAD_LIBRARY} + ${SQLITE3_LIBRARY} ) endif(BUILD_CLIENT) @@ -163,8 +177,8 @@ if(BUILD_SERVER) minetestserver ${ZLIB_LIBRARIES} ${PLATFORM_LIBS} - jthread - sqlite3 + ${JTHREAD_LIBRARY} + ${SQLITE3_LIBRARY} ) endif(BUILD_SERVER) @@ -207,6 +221,10 @@ else() set(ARCH i386) endif() + if(WIN32) + set(CMAKE_EXE_LINKER_FLAGS "-lintl -L ${GETTEXT_BIN_DIR}") + endif() + set(CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG ${RELEASE_WARNING_FLAGS} ${WARNING_FLAGS} -O3 -ffast-math -Wall -fomit-frame-pointer -pipe -funroll-loops") set(CMAKE_CXX_FLAGS_DEBUG "-g -O1 -Wall ${WARNING_FLAGS}") @@ -238,6 +256,9 @@ if(BUILD_CLIENT) install(FILES ${images} DESTINATION ${DATADIR}) + install(FILES ${CMAKE_BINARY_DIR}/locale/de/LC_MESSAGES/minetest-c55.mo DESTINATION locale/de/LC_MESSAGES) + install(FILES ${CMAKE_BINARY_DIR}/locale/fr/LC_MESSAGES/minetest-c55.mo DESTINATION locale/fr/LC_MESSAGES) + if(WIN32) if(DEFINED IRRLICHT_DLL) install(FILES ${IRRLICHT_DLL} DESTINATION ${BINDIR}) @@ -245,6 +266,10 @@ if(BUILD_CLIENT) if(DEFINED ZLIB_DLL) install(FILES ${ZLIB_DLL} DESTINATION ${BINDIR}) endif() + if(DEFINED GETTEXT_BIN_DIR) + install(FILES ${GETTEXT_BIN_DIR}/libintl3.dll DESTINATION ${BINDIR}) + install(FILES ${GETTEXT_BIN_DIR}/libiconv2.dll DESTINATION ${BINDIR}) + endif() endif() endif(BUILD_CLIENT) @@ -252,9 +277,50 @@ if(BUILD_SERVER) install(TARGETS minetestserver DESTINATION ${BINDIR}) endif(BUILD_SERVER) +if(WIN32) + set(GETTEXT_MSGFMT "${GETTEXT_BIN_DIR}/msgfmt" CACHE FILEPATH "path to msgfmt") +elseif(APPLE) + set(GETTEXT_MSGFMT "${GETTEXT_BIN_DIR}/msgfmt" CACHE FILEPATH "path to msgfmt") +else() + set(GETTEXT_MSGFMT "msgfmt") +endif() + +add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/locale/de/LC_MESSAGES COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/locale/de/LC_MESSAGES COMMENT "mo-update [de]: Creating locale directory.") +add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/locale/fr/LC_MESSAGES COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/locale/fr/LC_MESSAGES COMMENT "mo-update [fr]: Creating locale directory.") + +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/locale/de/LC_MESSAGES/minetest-c55.mo + COMMAND ${GETTEXT_MSGFMT} -o ${CMAKE_BINARY_DIR}/locale/de/LC_MESSAGES/minetest-c55.mo ${CMAKE_SOURCE_DIR}/po/de/minetest-c55.po + DEPENDS + ${CMAKE_BINARY_DIR}/locale/de/LC_MESSAGES + ${CMAKE_SOURCE_DIR}/po/de/minetest-c55.po + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/po/de + COMMENT "mo-update [de]: Creating mo file." + ) +add_custom_command( + OUTPUT ${CMAKE_BINARY_DIR}/locale/fr/LC_MESSAGES/minetest-c55.mo + COMMAND ${GETTEXT_MSGFMT} -o ${CMAKE_BINARY_DIR}/locale/fr/LC_MESSAGES/minetest-c55.mo ${CMAKE_SOURCE_DIR}/po/fr/minetest-c55.po + DEPENDS + ${CMAKE_BINARY_DIR}/locale/fr/LC_MESSAGES + ${CMAKE_SOURCE_DIR}/po/fr/minetest-c55.po + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/po/fr + COMMENT "mo-update [fr]: Creating mo file." + ) + +add_custom_target(translation_de ALL COMMENT "mo update [de]" DEPENDS ${CMAKE_BINARY_DIR}/locale/de/LC_MESSAGES/minetest-c55.mo) +add_custom_target(translation_fr ALL COMMENT "mo update [fr]" DEPENDS ${CMAKE_BINARY_DIR}/locale/fr/LC_MESSAGES/minetest-c55.mo) + + # 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 diff --git a/src/client.cpp b/src/client.cpp index 585fce11c..7ebb30fba 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -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 diff --git a/src/clouds.cpp b/src/clouds.cpp index 122beedac..d754cc15e 100644 --- a/src/clouds.cpp +++ b/src/clouds.cpp @@ -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); + } + } } diff --git a/src/content_cao.cpp b/src/content_cao.cpp index dc5ac400f..dfeaea85a 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -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(); +} diff --git a/src/content_cao.h b/src/content_cao.h index 146e23b0c..b984be136 100644 --- a/src/content_cao.h +++ b/src/content_cao.h @@ -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 diff --git a/src/content_craft.cpp b/src/content_craft.cpp index 32d2e6d48..069e68300 100644 --- a/src/content_craft.cpp +++ b/src/content_craft.cpp @@ -261,6 +261,24 @@ InventoryItem *craft_get_result(InventoryItem **items) } } + // Rail + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[1] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[2] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[3] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[4] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[5] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[6] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + specs[7] = ItemSpec(ITEM_CRAFT, "Stick"); + specs[8] = ItemSpec(ITEM_CRAFT, "steel_ingot"); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_RAIL, 15); + } + } + // Chest { ItemSpec specs[9]; @@ -313,6 +331,87 @@ InventoryItem *craft_get_result(InventoryItem **items) } } + // Sandstone + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_SAND); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_SANDSTONE, 1); + } + } + + // Clay + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + specs[4] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + specs[6] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + specs[7] = ItemSpec(ITEM_CRAFT, "lump_of_clay"); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_CLAY, 1); + } + } + + // Brick + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_CRAFT, "clay_brick"); + specs[4] = ItemSpec(ITEM_CRAFT, "clay_brick"); + specs[6] = ItemSpec(ITEM_CRAFT, "clay_brick"); + specs[7] = ItemSpec(ITEM_CRAFT, "clay_brick"); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_BRICK, 1); + } + } + + // Paper + { + ItemSpec specs[9]; + specs[3] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS); + specs[4] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS); + specs[5] = ItemSpec(ITEM_MATERIAL, CONTENT_PAPYRUS); + if(checkItemCombination(items, specs)) + { + return new CraftItem("paper", 1); + } + } + + // Book + { + ItemSpec specs[9]; + specs[1] = ItemSpec(ITEM_CRAFT, "paper"); + specs[4] = ItemSpec(ITEM_CRAFT, "paper"); + specs[7] = ItemSpec(ITEM_CRAFT, "paper"); + if(checkItemCombination(items, specs)) + { + return new CraftItem("book", 1); + } + } + + // Book shelf + { + ItemSpec specs[9]; + specs[0] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[1] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[2] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[3] = ItemSpec(ITEM_CRAFT, "book"); + specs[4] = ItemSpec(ITEM_CRAFT, "book"); + specs[5] = ItemSpec(ITEM_CRAFT, "book"); + specs[6] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[7] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + specs[8] = ItemSpec(ITEM_MATERIAL, CONTENT_WOOD); + if(checkItemCombination(items, specs)) + { + return new MaterialItem(CONTENT_BOOKSHELF, 1); + } + } + return NULL; } @@ -353,10 +452,17 @@ void craft_set_creative_inventory(Player *player) CONTENT_MUD, CONTENT_STONE, CONTENT_SAND, + CONTENT_SANDSTONE, + CONTENT_CLAY, + CONTENT_BRICK, CONTENT_TREE, CONTENT_LEAVES, + CONTENT_CACTUS, + CONTENT_PAPYRUS, + CONTENT_BOOKSHELF, CONTENT_GLASS, CONTENT_FENCE, + CONTENT_RAIL, CONTENT_MESE, CONTENT_WATERSOURCE, CONTENT_CLOUD, diff --git a/src/content_inventory.cpp b/src/content_inventory.cpp index ac48a6195..1068defb5 100644 --- a/src/content_inventory.cpp +++ b/src/content_inventory.cpp @@ -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; } diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index bdc9baa2a..d8bf71dc0 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -188,6 +188,16 @@ void mapblock_mesh_generate_special(MeshMakeData *data, material_general.setFlag(video::EMF_FOG_ENABLE, true); material_general.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + + // Papyrus material + video::SMaterial material_papyrus; + material_papyrus.setFlag(video::EMF_LIGHTING, false); + material_papyrus.setFlag(video::EMF_BILINEAR_FILTER, false); + material_papyrus.setFlag(video::EMF_FOG_ENABLE, true); + material_papyrus.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + AtlasPointer pa_papyrus = g_texturesource->getTexture( + g_texturesource->getTextureId("papyrus.png")); + material_papyrus.setTexture(0, pa_papyrus.atlas); for(s16 z=0; z<MAP_BLOCKSIZE; z++) for(s16 y=0; y<MAP_BLOCKSIZE; y++) for(s16 x=0; x<MAP_BLOCKSIZE; x++) @@ -365,7 +375,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data, if(n2.d == CONTENT_WATERSOURCE) level = (-0.5+node_water_level) * BS; else if(n2.d == CONTENT_WATER) - level = (-0.5 + ((float)n2.param2 + 0.5) / 8.0 + level = (-0.5 + ((float)(n2.param2 & LIQUID_LEVEL_MASK) + 0.5) / 8.0 * node_water_level) * BS; // Check node above neighbor. @@ -857,9 +867,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data, TileSpec ts = n.getTile(dir); AtlasPointer ap = ts.texture; material_general.setTexture(0, ap.atlas); - video::S3DVertex vertices[4] = - { + { /*video::S3DVertex(-BS/2,-BS/2,BS/2, 0,0,0, c, 0,1), video::S3DVertex(BS/2,-BS/2,BS/2, 0,0,0, c, 1,1), video::S3DVertex(BS/2,BS/2,BS/2, 0,0,0, c, 1,0), @@ -895,14 +904,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.d == CONTENT_PAPYRUS) + { + u8 l = decode_light(undiminish_light(n.getLightBlend(data->m_daynight_ratio))); + video::SColor c(255,l,l,l); + + for(u32 j=0; j<4; j++) + { + video::S3DVertex vertices[4] = + { + video::S3DVertex(-BS/2,-BS/2,0, 0,0,0, c, + pa_papyrus.x0(), pa_papyrus.y1()), + video::S3DVertex(BS/2,-BS/2,0, 0,0,0, c, + pa_papyrus.x1(), pa_papyrus.y1()), + video::S3DVertex(BS/2,BS/2,0, 0,0,0, c, + pa_papyrus.x1(), pa_papyrus.y0()), + video::S3DVertex(-BS/2,BS/2,0, 0,0,0, c, + pa_papyrus.x0(), pa_papyrus.y0()), + }; + + if(j == 0) { for(u16 i=0; i<4; i++) - vertices[i].Pos.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 +963,113 @@ 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.d == CONTENT_RAIL) + { + u8 l = decode_light(n.getLightBlend(data->m_daynight_ratio)); + video::SColor c(255,l,l,l); + + bool is_rail_x [] = { false, false }; /* x-1, x+1 */ + bool is_rail_z [] = { false, false }; /* z-1, z+1 */ + + MapNode n_minus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x-1,y,z)); + MapNode n_plus_x = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x+1,y,z)); + MapNode n_minus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z-1)); + MapNode n_plus_z = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y,z+1)); + + if(n_minus_x.d == CONTENT_RAIL) + is_rail_x[0] = true; + if(n_plus_x.d == CONTENT_RAIL) + is_rail_x[1] = true; + if(n_minus_z.d == CONTENT_RAIL) + is_rail_z[0] = true; + if(n_plus_z.d == CONTENT_RAIL) + is_rail_z[1] = true; + + float d = (float)BS/16; + video::S3DVertex vertices[4] = + { + video::S3DVertex(-BS/2,-BS/2+d,-BS/2, 0,0,0, c, + 0, 1), + video::S3DVertex(BS/2,-BS/2+d,-BS/2, 0,0,0, c, + 1, 1), + video::S3DVertex(BS/2,-BS/2+d,BS/2, 0,0,0, c, + 1, 0), + video::S3DVertex(-BS/2,-BS/2+d,BS/2, 0,0,0, c, + 0, 0), + }; + + video::SMaterial material_rail; + material_rail.setFlag(video::EMF_LIGHTING, false); + material_rail.setFlag(video::EMF_BACK_FACE_CULLING, false); + material_rail.setFlag(video::EMF_BILINEAR_FILTER, false); + material_rail.setFlag(video::EMF_FOG_ENABLE, true); + material_rail.MaterialType + = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + + int adjacencies = is_rail_x[0] + is_rail_x[1] + is_rail_z[0] + is_rail_z[1]; + + // Assign textures + if(adjacencies < 2) + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png")); + else if(adjacencies == 2) + { + if((is_rail_x[0] && is_rail_x[1]) || (is_rail_z[0] && is_rail_z[1])) + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail.png")); + else + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_curved.png")); + } + else if(adjacencies == 3) + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_t_junction.png")); + else if(adjacencies == 4) + material_rail.setTexture(0, g_texturesource->getTextureRaw("rail_crossing.png")); + // Rotate textures + int angle = 0; + + if(adjacencies == 1) + { + if(is_rail_x[0] || is_rail_x[1]) + angle = 90; + } + else if(adjacencies == 2) + { + if(is_rail_x[0] && is_rail_x[1]) + angle = 90; + else if(is_rail_x[0] && is_rail_z[0]) + angle = 270; + else if(is_rail_x[0] && is_rail_z[1]) + angle = 180; + else if(is_rail_x[1] && is_rail_z[1]) + angle = 90; + } + else if(adjacencies == 3) + { + if(!is_rail_x[0]) + angle=0; + if(!is_rail_x[1]) + angle=180; + if(!is_rail_z[0]) + angle=90; + if(!is_rail_z[1]) + angle=270; + } + + if(angle != 0) { + for(u16 i=0; i<4; i++) + vertices[i].Pos.rotateXZBy(angle); + } + + for(s32 i=0; i<4; i++) + { + vertices[i].Pos += intToFloat(p + blockpos_nodes, BS); + } + + u16 indices[] = {0,1,2,2,3,0}; + collector.append(material_rail, vertices, 4, indices, 6); + } } } #endif diff --git a/src/content_mapnode.cpp b/src/content_mapnode.cpp index d82ccc5c9..79e10fd61 100644 --- a/src/content_mapnode.cpp +++ b/src/content_mapnode.cpp @@ -99,6 +99,33 @@ void content_mapnode_init() f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; setDirtLikeDiggingProperties(f->digging_properties, 1.75); + i = CONTENT_SANDSTONE; + f = &content_features(i); + f->setAllTextures("sandstone.png"); + f->setInventoryTextureCube("sandstone.png", "sandstone.png", "sandstone.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(CONTENT_SAND)+" 1"; + setDirtLikeDiggingProperties(f->digging_properties, 1.0); + + i = CONTENT_CLAY; + f = &content_features(i); + f->setAllTextures("clay.png"); + f->setInventoryTextureCube("clay.png", "clay.png", "clay.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + f->dug_item = std::string("CraftItem lump_of_clay 4"); + setDirtLikeDiggingProperties(f->digging_properties, 1.0); + + i = CONTENT_BRICK; + f = &content_features(i); + f->setAllTextures("brick.png"); + f->setInventoryTextureCube("brick.png", "brick.png", "brick.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + f->dug_item = std::string("CraftItem clay_brick 4"); + setStoneLikeDiggingProperties(f->digging_properties, 1.0); + i = CONTENT_TREE; f = &content_features(i); f->setAllTextures("tree.png"); @@ -127,6 +154,40 @@ void content_mapnode_init() f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; setWoodLikeDiggingProperties(f->digging_properties, 0.15); + i = CONTENT_CACTUS; + f = &content_features(i); + f->setAllTextures("cactus_side.png"); + f->setTexture(0, "cactus_top.png"); + f->setTexture(1, "cactus_top.png"); + f->setInventoryTextureCube("cactus_top.png", "cactus_side.png", "cactus_side.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + setWoodLikeDiggingProperties(f->digging_properties, 0.75); + + i = CONTENT_PAPYRUS; + f = &content_features(i); + f->setInventoryTexture("papyrus.png"); + f->light_propagates = true; + f->param_type = CPT_LIGHT; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + f->solidness = 0; // drawn separately, makes no faces + f->walkable = false; + setWoodLikeDiggingProperties(f->digging_properties, 0.25); + + i = CONTENT_BOOKSHELF; + f = &content_features(i); + f->setAllTextures("bookshelf.png"); + f->setTexture(0, "wood.png"); + f->setTexture(1, "wood.png"); + // FIXME: setInventoryTextureCube() only cares for the first texture + f->setInventoryTextureCube("bookshelf.png", "bookshelf.png", "bookshelf.png"); + //f->setInventoryTextureCube("wood.png", "bookshelf.png", "bookshelf.png"); + f->param_type = CPT_MINERAL; + f->is_ground_content = true; + setWoodLikeDiggingProperties(f->digging_properties, 0.75); + i = CONTENT_GLASS; f = &content_features(i); f->light_propagates = true; @@ -148,6 +209,18 @@ void content_mapnode_init() f->setInventoryTexture("item_fence.png"); setWoodLikeDiggingProperties(f->digging_properties, 0.75); + i = CONTENT_RAIL; + f = &content_features(i); + f->setInventoryTexture("rail.png"); + f->light_propagates = true; + f->param_type = CPT_LIGHT; + f->is_ground_content = true; + f->dug_item = std::string("MaterialItem ")+itos(i)+" 1"; + f->solidness = 0; // drawn separately, makes no faces + f->air_equivalent = true; // grass grows underneath + f->walkable = false; + setDirtLikeDiggingProperties(f->digging_properties, 0.75); + // Deprecated i = CONTENT_COALSTONE; f = &content_features(i); @@ -202,6 +275,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 +307,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); diff --git a/src/content_mapnode.h b/src/content_mapnode.h index e314807f9..e53624c21 100644 --- a/src/content_mapnode.h +++ b/src/content_mapnode.h @@ -50,6 +50,13 @@ void content_mapnode_init(); #define CONTENT_FENCE 21 #define CONTENT_MOSSYCOBBLE 22 #define CONTENT_GRAVEL 23 +#define CONTENT_SANDSTONE 24 +#define CONTENT_CACTUS 25 +#define CONTENT_BRICK 26 +#define CONTENT_CLAY 27 +#define CONTENT_PAPYRUS 28 +#define CONTENT_BOOKSHELF 29 +#define CONTENT_RAIL 30 #endif diff --git a/src/content_object.h b/src/content_object.h index ecabd8a38..47f93d7d4 100644 --- a/src/content_object.h +++ b/src/content_object.h @@ -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 diff --git a/src/content_sao.cpp b/src/content_sao.cpp index c41f4ed78..0b81855c1 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -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; +} diff --git a/src/content_sao.h b/src/content_sao.h index 030232a9e..e5b1223d4 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -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 diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index cda9eb79a..cbc78ad3f 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -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", "."); diff --git a/src/environment.cpp b/src/environment.cpp index d55aa38d1..df41dc63f 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -976,7 +976,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 diff --git a/src/farmesh.cpp b/src/farmesh.cpp index 8f91e3a1a..2cd922434 100644 --- a/src/farmesh.cpp +++ b/src/farmesh.cpp @@ -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; } diff --git a/src/farmesh.h b/src/farmesh.h index 0a30a8aef..577224e15 100644 --- a/src/farmesh.h +++ b/src/farmesh.h @@ -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 diff --git a/src/game.cpp b/src/game.cpp index faadd0fe7..0f858e879 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -538,6 +538,43 @@ void getPointedNode(Client *client, v3f player_position, } } } + else if(n.d == CONTENT_RAIL) + { + v3s16 dir = unpackDir(n.dir); + v3f dir_f = v3f(dir.X, dir.Y, dir.Z); + dir_f *= BS/2 - BS/6 - BS/20; + v3f cpf = npf + dir_f; + f32 distance = (cpf - camera_position).getLength(); + + float d = (float)BS/16; + v3f vertices[4] = + { + v3f(BS/2, -BS/2+d, -BS/2), + v3f(-BS/2, -BS/2, BS/2), + }; + + for(s32 i=0; i<2; i++) + { + vertices[i] += npf; + } + + core::aabbox3d<f32> box; + + box = core::aabbox3d<f32>(vertices[0]); + box.addInternalPoint(vertices[1]); + + if(distance < mindistance) + { + if(box.intersectsWithLine(shootline)) + { + nodefound = true; + nodepos = np; + neighbourpos = np; + mindistance = distance; + nodehilightbox = box; + } + } + } /* Regular blocks */ @@ -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 index 000000000..7f5f56e49 --- /dev/null +++ b/src/gettext.h @@ -0,0 +1,12 @@ +#include <libintl.h> +#define _(String) gettext(String) +#define gettext_noop(String) String +#define N_(String) gettext_noop (String) + +inline wchar_t* chartowchar_t(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 index 000000000..3e594aeca --- /dev/null +++ b/src/guiKeyChangeMenu.cpp @@ -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(); Y U NO SCOPE?! + 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 index 000000000..389ce7aee --- /dev/null +++ b/src/guiKeyChangeMenu.h @@ -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 + diff --git a/src/guiMainMenu.cpp b/src/guiMainMenu.cpp index ef0a013f1..f557f4dc0 100644 --- a/src/guiMainMenu.cpp +++ b/src/guiMainMenu.cpp @@ -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,13 @@ 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 +199,13 @@ 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 +213,39 @@ 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 +266,19 @@ 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 +312,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 +322,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 +389,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 +410,7 @@ bool GUIMainMenu::OnEvent(const SEvent& event) { switch(event.GUIEvent.Caller->getID()) { - case 256: case 257: case 258: case 264: + case GUI_ID_ADDRESS_INPUT: case GUI_ID_PORT_INPUT: case GUI_ID_NAME_INPUT: case 264: acceptInput(); quitMenu(); return true; diff --git a/src/guiMainMenu.h b/src/guiMainMenu.h index edd519024..87561f797 100644 --- a/src/guiMainMenu.h +++ b/src/guiMainMenu.h @@ -27,6 +27,21 @@ with this program; if not, write to the Free Software Foundation, Inc., // For IGameCallback #include "guiPauseMenu.h" +enum +{ + GUI_ID_QUIT_BUTTON = 101, + GUI_ID_NAME_INPUT, + GUI_ID_ADDRESS_INPUT, + GUI_ID_PORT_INPUT, + GUI_ID_FANCYTREE_CB, + GUI_ID_SMOOTH_LIGHTING_CB, + GUI_ID_DAMAGE_CB, + GUI_ID_CREATIVE_CB, + GUI_ID_JOIN_GAME_BUTTON, + GUI_ID_CHANGE_KEYS_BUTTON, + GUI_ID_DELETE_MAP_BUTTON +}; + struct MainMenuData { MainMenuData(): @@ -87,6 +102,11 @@ private: MainMenuData *m_data; bool m_accepted; IGameCallback *m_gamecallback; + + gui::IGUIEnvironment* env; + gui::IGUIElement* parent; + s32 id; + IMenuManager *menumgr; }; #endif diff --git a/src/guiMessageMenu.cpp b/src/guiMessageMenu.cpp index 192911355..e4e582ab1 100644 --- a/src/guiMessageMenu.cpp +++ b/src/guiMessageMenu.cpp @@ -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,7 @@ 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); } } diff --git a/src/guiPasswordChange.cpp b/src/guiPasswordChange.cpp index ec1cd029a..79601a99f 100644 --- a/src/guiPasswordChange.cpp +++ b/src/guiPasswordChange.cpp @@ -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,7 @@ 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 +113,7 @@ 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 +126,7 @@ 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 +140,15 @@ 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); } diff --git a/src/guiPauseMenu.cpp b/src/guiPauseMenu.cpp index d32d1a10b..5f40a4820 100644 --- a/src/guiPauseMenu.cpp +++ b/src/guiPauseMenu.cpp @@ -24,6 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "config.h"
#include "main.h"
+#include "gettext.h"
+
GUIPauseMenu::GUIPauseMenu(gui::IGUIEnvironment* env,
gui::IGUIElement* parent, s32 id,
IGameCallback *gamecallback,
@@ -104,43 +106,43 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize) {
core::rect<s32> rect(0, 0, 140, btn_height);
rect = rect + v2s32(size.X/2-140/2, btn_y);
- Environment->addButton(rect, this, 256, L"Continue");
+ Environment->addButton(rect, this, 256, chartowchar_t(gettext("Continue")));
}
btn_y += btn_height + btn_gap;
{
core::rect<s32> rect(0, 0, 140, btn_height);
rect = rect + v2s32(size.X/2-140/2, btn_y);
- Environment->addButton(rect, this, 261, L"Change Password");
+ Environment->addButton(rect, this, 261, chartowchar_t(gettext("Change Password")));
}
btn_y += btn_height + btn_gap;
{
core::rect<s32> rect(0, 0, 140, btn_height);
rect = rect + v2s32(size.X/2-140/2, btn_y);
- Environment->addButton(rect, this, 260, L"Disconnect");
+ Environment->addButton(rect, this, 260, chartowchar_t(gettext("Disconnect")));
}
btn_y += btn_height + btn_gap;
{
core::rect<s32> rect(0, 0, 140, btn_height);
rect = rect + v2s32(size.X/2-140/2, btn_y);
- Environment->addButton(rect, this, 257, L"Exit to OS");
+ Environment->addButton(rect, this, 257, chartowchar_t(gettext("Exit to OS")));
}
{
core::rect<s32> rect(0, 0, 180, 240);
rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2);
- const wchar_t *text =
- L"Keys:\n"
- L"- WASD: Walk\n"
- L"- Mouse left: dig blocks\n"
- L"- Mouse right: place blocks\n"
- L"- Mouse wheel: select item\n"
- L"- 0...9: select item\n"
- L"- Shift: sneak\n"
- L"- R: Toggle viewing all loaded chunks\n"
- L"- I: Inventory menu\n"
- L"- ESC: This menu\n"
- L"- T: Chat\n";
- Environment->addStaticText(text, rect, false, true, this, 258);
+ Environment->addStaticText(chartowchar_t(gettext(
+ "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"
+ )), rect, false, true, this, 258);
}
{
core::rect<s32> rect(0, 0, 180, 220);
@@ -166,8 +168,8 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize) );*/
std::ostringstream os;
- os<<"Minetest-c55\n";
- os<<"by Perttu Ahola\n";
+ os<<"Minetest-delta\n";
+ os<<"by Perttu Ahola and contributors\n";
os<<"celeron55@gmail.com\n";
os<<BUILD_INFO<<"\n";
os<<"ud_path = "<<wrap_rows(porting::path_userdata, 20)<<"\n";
diff --git a/src/guiTextInputMenu.cpp b/src/guiTextInputMenu.cpp index 2cb8cae62..b15f8bc07 100644 --- a/src/guiTextInputMenu.cpp +++ b/src/guiTextInputMenu.cpp @@ -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,7 @@ 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"))); } } diff --git a/src/keycode.cpp b/src/keycode.cpp index ad3c0b401..f014914d0 100644 --- a/src/keycode.cpp +++ b/src/keycode.cpp @@ -171,6 +171,46 @@ irr::EKEY_CODE keyname_to_keycode(const char *name) return irr::KEY_KEY_CODES_COUNT; } +static const char *KeyNames[] = +{ "-", "KEY_LBUTTON", "KEY_RBUTTON", "Cancel", "Middle Button", "X Button 1", + "X Button 2", "-", "Back", "Tab", "-", "-", "Clear", "Return", "-", + "-", "KEY_SHIFT", "Control", "Menu", "Pause", "Capital", "Kana", "-", + "Junja", "Final", "Kanji", "-", "Escape", "Convert", "Nonconvert", + "Accept", "Mode Change", "KEY_SPACE", "Priot", "Next", "KEY_END", + "KEY_HOME", "Left", "Up", "Right", "Down", "Select", "KEY_PRINT", + "Execute", "Snapshot", "Insert", "Delete", "Help", "KEY_KEY_0", + "KEY_KEY_1", "KEY_KEY_2", "KEY_KEY_3", "KEY_KEY_4", "KEY_KEY_5", + "KEY_KEY_6", "KEY_KEY_7", "KEY_KEY_8", "KEY_KEY_9", "-", "-", "-", "-", + "-", "-", "-", "KEY_KEY_A", "KEY_KEY_B", "KEY_KEY_C", "KEY_KEY_D", + "KEY_KEY_E", "KEY_KEY_F", "KEY_KEY_G", "KEY_KEY_H", "KEY_KEY_I", + "KEY_KEY_J", "KEY_KEY_K", "KEY_KEY_L", "KEY_KEY_M", "KEY_KEY_N", + "KEY_KEY_O", "KEY_KEY_P", "KEY_KEY_Q", "KEY_KEY_R", "KEY_KEY_S", + "KEY_KEY_T", "KEY_KEY_U", "KEY_KEY_V", "KEY_KEY_W", "KEY_KEY_X", + "KEY_KEY_Y", "KEY_KEY_Z", "Left Windows", "Right Windows", "Apps", "-", + "Sleep", "KEY_NUMPAD0", "KEY_NUMPAD1", "KEY_NUMPAD2", "KEY_NUMPAD3", + "KEY_NUMPAD4", "KEY_NUMPAD5", "KEY_NUMPAD6", "KEY_NUMPAD7", + "KEY_NUMPAD8", "KEY_NUMPAD9", "Numpad *", "Numpad +", "Numpad /", + "Numpad -", "Numpad .", "Numpad /", "KEY_F1", "KEY_F2", "KEY_F3", + "KEY_F4", "KEY_F5", "KEY_F6", "KEY_F7", "KEY_F8", "KEY_F9", "KEY_F10", + "KEY_F11", "KEY_F12", "KEY_F13", "KEY_F14", "KEY_F15", "KEY_F16", + "KEY_F17", "KEY_F18", "KEY_F19", "KEY_F20", "KEY_F21", "KEY_F22", + "KEY_F23", "KEY_F24", "-", "-", "-", "-", "-", "-", "-", "-", + "Num Lock", "Scroll Lock", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "KEY_LSHIFT", "KEY_RSHIFT", "Left Control", + "Right Control", "Left Menu", "Right Menu", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "Plus", "Comma", "Minus", "Period", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", + "-", "-", "-", "-", "-", "-", "-", "-", "Attn", "CrSel", "ExSel", + "Erase OEF", "Play", "Zoom", "PA1", "OEM Clear", "-" }; + +std::string keycode_to_keyname(s32 keycode) +{ + return KeyNames[keycode]; +} + /* Key config */ @@ -189,4 +229,7 @@ irr::EKEY_CODE getKeySetting(const char *settingname) return c; } - +void clearKeyCache() +{ + g_key_setting_cache.clear(); +} diff --git a/src/keycode.h b/src/keycode.h index f19fe3442..9c62004d8 100644 --- a/src/keycode.h +++ b/src/keycode.h @@ -21,11 +21,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #define KEYCODE_HEADER #include "common_irrlicht.h" +#include <string> irr::EKEY_CODE keyname_to_keycode(const char *name); // Key configuration getter irr::EKEY_CODE getKeySetting(const char *settingname); +std::string keycode_to_keyname(s32 keycode); +void clearCache(); #endif diff --git a/src/main.cpp b/src/main.cpp index 698c5fc71..505f82fc7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -339,6 +339,12 @@ TODO: Merge bahamada's audio stuff (clean patch available) TODO: Merge key configuration menu (no clean patch available)
+TODO: Add some kind of content range validation to mapnode serialization
+
+TODO: Make sure menu text position is fixed
+
+TODO: Fix sector over limits error
+
Making it more portable:
------------------------
@@ -401,6 +407,8 @@ Doing currently: #include "keycode.h"
#include "tile.h"
+#include "gettext.h"
+
// This makes textures
ITextureSource *g_texturesource = NULL;
@@ -1130,6 +1138,10 @@ int main(int argc, char *argv[]) // Create user data directory
fs::CreateDir(porting::path_userdata);
+
+ setlocale(LC_ALL, "");
+ bindtextdomain("minetest-c55", (porting::path_userdata+"/locale").c_str());
+ textdomain("minetest-c55");
// Initialize debug streams
#ifdef RUN_IN_PLACE
@@ -1345,6 +1357,9 @@ int main(int argc, char *argv[]) // 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);
diff --git a/src/map.cpp b/src/map.cpp index 2a3e9f760..e1769b8ef 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -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.d) || n2.d == CONTENT_AIR) { m_transforming_liquid.push_back(p2); } @@ -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.d) || n2.d == CONTENT_AIR) { m_transforming_liquid.push_back(p2); } @@ -1538,6 +1540,17 @@ void Map::PrintInfo(std::ostream &out) #define WATER_DROP_BOOST 4 +enum NeighborType { + NEIGHBOR_UPPER, + NEIGHBOR_SAME_LEVEL, + NEIGHBOR_LOWER +}; +struct NodeNeighbor { + MapNode n; + NeighborType t; + v3s16 p; +}; + void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks) { DSTACK(__FUNCTION_NAME); @@ -1557,240 +1570,220 @@ void Map::transformLiquids(core::map<v3s16, MapBlock*> & modified_blocks) v3s16 p0 = m_transforming_liquid.pop_front(); MapNode n0 = getNodeNoEx(p0); - - // Don't deal with non-liquids - if(content_liquid(n0.d) == false) - continue; - - bool is_source = !content_flowing_liquid(n0.d); - - 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); - + /* - If not source, check that some node flows into this one - and what is the level of liquid in this one - */ - if(is_source == false) - { - s8 new_liquid_level_max = -1; - - v3s16 dirs_from[5] = { - v3s16(0,1,0), // top - v3s16(0,0,1), // back - v3s16(1,0,0), // right - v3s16(0,0,-1), // front - v3s16(-1,0,0), // left - }; - for(u16 i=0; i<5; i++) - { - bool from_top = (i==0); - - v3s16 p2 = p0 + dirs_from[i]; - MapNode n2 = getNodeNoEx(p2); - - if(content_liquid(n2.d)) - { - u8 n2_nonsource_c = make_liquid_flowing(n2.d); - // Check that the liquids are the same type - if(n2_nonsource_c != nonsource_c) - { - dstream<<"WARNING: Not handling: different liquids" - " collide"<<std::endl; - continue; + Collect information about current node + */ + s8 liquid_level = -1; + u8 liquid_kind = CONTENT_IGNORE; + LiquidType liquid_type = content_features(n0.d).liquid_type; + switch (liquid_type) { + case LIQUID_SOURCE: + liquid_level = 8; + liquid_kind = content_features(n0.d).liquid_alternative_flowing; + break; + case LIQUID_FLOWING: + liquid_level = (n0.param2 & LIQUID_LEVEL_MASK); + liquid_kind = n0.d; + break; + case LIQUID_NONE: + // if this is an air node, it *could* be transformed into a liquid. otherwise, + // continue with the next node. + if (n0.d != CONTENT_AIR) + continue; + liquid_kind = CONTENT_AIR; + break; + } + + /* + Collect information about the environment + */ + v3s16 dirs[6] = { + v3s16( 0, 1, 0), // top + v3s16( 0,-1, 0), // bottom + v3s16( 1, 0, 0), // right + v3s16(-1, 0, 0), // left + v3s16( 0, 0, 1), // back + v3s16( 0, 0,-1), // front + }; + NodeNeighbor sources[6]; // surrounding sources + int num_sources = 0; + NodeNeighbor flows[6]; // surrounding flowing liquid nodes + int num_flows = 0; + NodeNeighbor airs[6]; // surrounding air + int num_airs = 0; + NodeNeighbor neutrals[6]; // nodes that are solid or another kind of liquid + int num_neutrals = 0; + bool flowing_down = false; + for (u16 i = 0; i < 6; i++) { + NeighborType nt = NEIGHBOR_SAME_LEVEL; + switch (i) { + case 0: + nt = NEIGHBOR_UPPER; + break; + case 1: + nt = NEIGHBOR_LOWER; + break; + } + v3s16 npos = p0 + dirs[i]; + NodeNeighbor nb = {getNodeNoEx(npos), nt, npos}; + switch (content_features(nb.n.d).liquid_type) { + case LIQUID_NONE: + if (nb.n.d == CONTENT_AIR) { + airs[num_airs++] = nb; + // if the current node happens to be a flowing node, it will start to flow down here. + if (nb.t == NEIGHBOR_LOWER) + flowing_down = true; + } else { + neutrals[num_neutrals++] = nb; } - bool n2_is_source = !content_flowing_liquid(n2.d); - s8 n2_liquid_level = 8; - if(n2_is_source == false) - n2_liquid_level = n2.param2 & 0x07; - - s8 new_liquid_level = -1; - if(from_top) - { - //new_liquid_level = 7; - if(n2_liquid_level >= 7 - WATER_DROP_BOOST) - new_liquid_level = 7; - else - new_liquid_level = n2_liquid_level + WATER_DROP_BOOST; + break; + case LIQUID_SOURCE: + // if this node is not (yet) of a liquid type, choose the first liquid type we encounter + if (liquid_kind == CONTENT_AIR) + liquid_kind = content_features(nb.n.d).liquid_alternative_flowing; + if (content_features(nb.n.d).liquid_alternative_flowing !=liquid_kind) { + neutrals[num_neutrals++] = nb; + } else { + sources[num_sources++] = nb; } - else if(n2_liquid_level > 0) - { - new_liquid_level = n2_liquid_level - 1; + break; + case LIQUID_FLOWING: + // if this node is not (yet) of a liquid type, choose the first liquid type we encounter + if (liquid_kind == CONTENT_AIR) + liquid_kind = content_features(nb.n.d).liquid_alternative_flowing; + if (content_features(nb.n.d).liquid_alternative_flowing != liquid_kind) { + neutrals[num_neutrals++] = nb; + } else { + flows[num_flows++] = nb; + if (nb.t == NEIGHBOR_LOWER) + flowing_down = true; } - - if(new_liquid_level > new_liquid_level_max) - new_liquid_level_max = new_liquid_level; - } - } //for - - /* - If liquid level should be something else, update it and - add all the neighboring water nodes to the transform queue. - */ - if(new_liquid_level_max != liquid_level) - { - if(new_liquid_level_max == -1) - { - // Remove water alltoghether - n0.d = CONTENT_AIR; - n0.param2 = 0; - setNode(p0, n0); - } - else - { - n0.param2 = new_liquid_level_max; - setNode(p0, n0); - } - - // Block has been modified - { - v3s16 blockpos = getNodeBlockPos(p0); - MapBlock *block = getBlockNoCreateNoEx(blockpos); - if(block != NULL) - modified_blocks.insert(blockpos, block); + break; + } + } + + /* + decide on the type (and possibly level) of the current node + */ + u8 new_node_content; + s8 new_node_level = -1; + if (num_sources >= 2 || liquid_type == LIQUID_SOURCE) { + // liquid_kind will be set to either the flowing alternative of the node (if it's a liquid) + // or the flowing alternative of the first of the surrounding sources (if it's air), so + // it's perfectly safe to use liquid_kind here to determine the new node content. + new_node_content = content_features(liquid_kind).liquid_alternative_source; + } else if (num_sources == 1 && sources[0].t != NEIGHBOR_LOWER) { + // liquid_kind is set properly, see above + new_node_content = liquid_kind; + new_node_level = 7; + } else { + // no surrounding sources, so get the maximum level that can flow into this node + for (u16 i = 0; i < num_flows; i++) { + u8 nb_liquid_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK); + switch (flows[i].t) { + case NEIGHBOR_UPPER: + if (nb_liquid_level + WATER_DROP_BOOST > new_node_level) { + new_node_level = 7; + if (nb_liquid_level + WATER_DROP_BOOST < 7) + new_node_level = nb_liquid_level + WATER_DROP_BOOST; + } + break; + case NEIGHBOR_LOWER: + break; + case NEIGHBOR_SAME_LEVEL: + if ((flows[i].n.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK && + nb_liquid_level > 0 && nb_liquid_level - 1 > new_node_level) { + new_node_level = nb_liquid_level - 1; + } + break; } - - /* - Add neighboring non-source liquid nodes to transform queue. - */ - v3s16 dirs[6] = { - 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 - }; - for(u16 i=0; i<6; i++) - { - v3s16 p2 = p0 + dirs[i]; - - MapNode n2 = getNodeNoEx(p2); - if(content_flowing_liquid(n2.d)) - { - m_transforming_liquid.push_back(p2); + } + // don't flow as far in open terrain - if there isn't at least one adjacent solid block, + // substract another unit from the resulting water level. + if (!flowing_down && new_node_level >= 1) { + bool at_wall = false; + for (u16 i = 0; i < num_neutrals; i++) { + if (neutrals[i].t == NEIGHBOR_SAME_LEVEL) { + at_wall = true; + break; } } + if (!at_wall) + new_node_level -= 1; } + + if (new_node_level >= 0) + new_node_content = liquid_kind; + else + new_node_content = CONTENT_AIR; } - - // Get a new one from queue if the node has turned into non-water - if(content_liquid(n0.d) == false) + + /* + check if anything has changed. if not, just continue with the next node. + */ + if (new_node_content == n0.d && (content_features(n0.d).liquid_type != LIQUID_FLOWING || + ((n0.param2 & LIQUID_LEVEL_MASK) == (u8)new_node_level && + ((n0.param2 & LIQUID_FLOW_DOWN_MASK) == LIQUID_FLOW_DOWN_MASK) + == flowing_down))) continue; - + + /* - Flow water from this node - */ - v3s16 dirs_to[5] = { - v3s16(0,-1,0), // bottom - v3s16(0,0,1), // back - v3s16(1,0,0), // right - v3s16(0,0,-1), // front - v3s16(-1,0,0), // left - }; - for(u16 i=0; i<5; i++) - { - bool to_bottom = (i == 0); - - // If liquid is at lowest possible height, it's not going - // anywhere except down - if(liquid_level == 0 && to_bottom == false) - continue; - - u8 liquid_next_level = 0; - // If going to bottom - if(to_bottom) - { - //liquid_next_level = 7; - if(liquid_level >= 7 - WATER_DROP_BOOST) - liquid_next_level = 7; - else - liquid_next_level = liquid_level + WATER_DROP_BOOST; - } - else - liquid_next_level = liquid_level - 1; - - bool n2_changed = false; - bool flowed = false; - - v3s16 p2 = p0 + dirs_to[i]; - - MapNode n2 = getNodeNoEx(p2); - //dstream<<"[1] n2.param="<<(int)n2.param<<std::endl; - - if(content_liquid(n2.d)) - { - u8 n2_nonsource_c = make_liquid_flowing(n2.d); - // Check that the liquids are the same type - if(n2_nonsource_c != nonsource_c) - { - dstream<<"WARNING: Not handling: different liquids" - " collide"<<std::endl; - continue; - } - bool n2_is_source = !content_flowing_liquid(n2.d); - u8 n2_liquid_level = 8; - if(n2_is_source == false) - n2_liquid_level = n2.param2 & 0x07; - - if(to_bottom) - { - flowed = true; + update the current node + */ + bool flow_down_enabled = (flowing_down && ((n0.param2 & LIQUID_FLOW_DOWN_MASK) != LIQUID_FLOW_DOWN_MASK)); + n0.d = new_node_content; + if (content_features(n0.d).liquid_type == LIQUID_FLOWING) { + // set level to last 3 bits, flowing down bit to 4th bit + n0.param2 = (flowing_down ? LIQUID_FLOW_DOWN_MASK : 0x00) | (new_node_level & LIQUID_LEVEL_MASK); + } else { + n0.param2 = 0; + } + setNode(p0, n0); + v3s16 blockpos = getNodeBlockPos(p0); + MapBlock *block = getBlockNoCreateNoEx(blockpos); + if(block != NULL) + modified_blocks.insert(blockpos, block); + + /* + enqueue neighbors for update if neccessary + */ + switch (content_features(n0.d).liquid_type) { + case LIQUID_SOURCE: + // make sure source flows into all neighboring nodes + for (u16 i = 0; i < num_flows; i++) + if (flows[i].t != NEIGHBOR_UPPER) + m_transforming_liquid.push_back(flows[i].p); + for (u16 i = 0; i < num_airs; i++) + if (airs[i].t != NEIGHBOR_UPPER) + m_transforming_liquid.push_back(airs[i].p); + break; + case LIQUID_NONE: + // this flow has turned to air; neighboring flows might need to do the same + for (u16 i = 0; i < num_flows; i++) + m_transforming_liquid.push_back(flows[i].p); + break; + case LIQUID_FLOWING: + for (u16 i = 0; i < num_flows; i++) { + u8 flow_level = (flows[i].n.param2 & LIQUID_LEVEL_MASK); + // liquid_level is still the ORIGINAL level of this node. + if (flows[i].t != NEIGHBOR_UPPER && ((flow_level < liquid_level || flow_level < new_node_level) || + flow_down_enabled)) + m_transforming_liquid.push_back(flows[i].p); } - - if(n2_is_source) - { - // Just flow into the source, nothing changes. - // n2_changed is not set because destination didn't change - flowed = true; + for (u16 i = 0; i < num_airs; i++) { + if (airs[i].t != NEIGHBOR_UPPER && (airs[i].t == NEIGHBOR_LOWER || new_node_level > 0)) + m_transforming_liquid.push_back(airs[i].p); } - else - { - if(liquid_next_level > liquid_level) - { - n2.param2 = liquid_next_level; - setNode(p2, n2); - - n2_changed = true; - flowed = true; - } - } - } - else if(n2.d == CONTENT_AIR) - { - n2.d = nonsource_c; - n2.param2 = liquid_next_level; - setNode(p2, n2); - - n2_changed = true; - flowed = true; - } - - //dstream<<"[2] n2.param="<<(int)n2.param<<std::endl; - - if(n2_changed) - { - m_transforming_liquid.push_back(p2); - - v3s16 blockpos = getNodeBlockPos(p2); - MapBlock *block = getBlockNoCreateNoEx(blockpos); - if(block != NULL) - modified_blocks.insert(blockpos, block); - } - - // If n2_changed to bottom, don't flow anywhere else - if(to_bottom && flowed && !is_source) break; } - + loopcount++; //if(loopcount >= 100000) - if(loopcount >= initial_size * 1) + if(loopcount >= initial_size * 10) { break; + } } //dstream<<"Map::transformLiquids(): loopcount="<<loopcount<<std::endl; } diff --git a/src/mapgen.cpp b/src/mapgen.cpp index acff3b963..8dda93c96 100644 --- a/src/mapgen.cpp +++ b/src/mapgen.cpp @@ -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++) @@ -152,6 +152,34 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0) } } +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) { @@ -909,8 +937,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 +973,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) @@ -1345,7 +1373,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. */ @@ -1379,6 +1408,7 @@ void make_block(BlockMakeData *data) // We're done return; } + #endif /* If block is deep underground, this is set to true and ground @@ -1808,6 +1838,8 @@ 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(); @@ -1834,7 +1866,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 @@ -1894,7 +1938,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->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE && n->d != CONTENT_IGNORE) { found = true; break; @@ -1903,19 +1947,33 @@ 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) - continue; + + if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS && n->d != CONTENT_SAND) + continue; + + // Papyrus grows only on mud and in water + if(n->d == CONTENT_MUD && y <= WATER_LEVEL) + { + p.Y++; + make_papyrus(vmanip, p); + } + // Trees grow only on mud and grass, on land + else if((n->d == CONTENT_MUD || n->d == CONTENT_GRASS) && y > WATER_LEVEL + 2) + { + p.Y++; + make_tree(vmanip, p); + } + // Cactii grow only on sand, on land + else if(n->d == CONTENT_SAND && y > WATER_LEVEL + 2) + { + p.Y++; + make_cactus(vmanip, p); + } } - // Tree will be placed one higher - p.Y++; - // Make a tree - make_tree(vmanip, p); } #if 0 diff --git a/src/mapnode.h b/src/mapnode.h index 36d48fb9e..33128049a 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -150,8 +150,10 @@ struct ContentFeatures NodeMetadata *initial_metadata; // If the content is liquid, this is the flowing version of the liquid. - // If content is liquid, this is the same content. + // If content is flowing liquid, this is the same content. u8 liquid_alternative_flowing; + // If the content is liquid, this is the source version of the liquid. + u8 liquid_alternative_source; // Amount of light the node emits u8 light_source; @@ -403,9 +405,16 @@ enum LightBank }; /* + Masks for MapNode.param2 of flowing liquids + */ +#define LIQUID_LEVEL_MASK 0x07 +#define LIQUID_FLOW_DOWN_MASK 0x08 + +/* This is the stuff what the whole world consists of. */ + struct MapNode { /* diff --git a/src/porting.cpp b/src/porting.cpp index 7de042ab5..ff8cb3862 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -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; diff --git a/updatelocales.sh b/updatelocales.sh new file mode 100755 index 000000000..e84145107 --- /dev/null +++ b/updatelocales.sh @@ -0,0 +1,5 @@ +#! /bin/bash +xgettext -n -o minetest-c55.pot ./src/*.cpp ./src/*.h +msgmerge -U ./po/de/minetest-c55.po minetest-c55.pot +msgmerge -U ./po/fr/minetest-c55.po minetest-c55.pot +rm minetest-c55.pot |