MultiCraft 1.0.2

This commit is contained in:
Maksim Gamarnik 2015-12-27 22:55:32 +02:00
parent b05a829924
commit a2251f0f79
43 changed files with 383 additions and 201 deletions

View File

@ -13,12 +13,6 @@ PATHCFGFILE = path.cfg
ROOT = $(shell pwd)
# this string will be written to Files.zip in ver.txt
VER_TEXT = 1.1
GAMES_TO_COPY = MultiCraft_game
MODS_TO_COPY =
VERSION_MAJOR := $(shell cat $(ROOT)/../../CMakeLists.txt | \
grep ^set\(VERSION_MAJOR\ | sed 's/)/ /' | cut -f2 -d' ')
VERSION_MINOR := $(shell cat $(ROOT)/../../CMakeLists.txt | \
@ -87,7 +81,7 @@ IRRLICHT_TIMESTAMP = $(IRRLICHT_DIR)timestamp
IRRLICHT_TIMESTAMP_INT = $(ROOT)/deps/irrlicht_timestamp
IRRLICHT_URL_SVN = http://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@$(IRRLICHT_REVISION)
OPENSSL_VERSION = 1.0.1p
OPENSSL_VERSION = 1.0.2e
OPENSSL_BASEDIR = openssl-$(OPENSSL_VERSION)
OPENSSL_DIR = $(ROOT)/deps/$(OPENSSL_BASEDIR)/
OPENSSL_LIB = $(OPENSSL_DIR)/libssl.so.1.0.0
@ -144,7 +138,7 @@ endif
$(ASSETS_TIMESTAMP) $(LEVELDB_TIMESTAMP) \
$(OPENAL_TIMESTAMP) $(OGG_TIMESTAMP) \
$(IRRLICHT_TIMESTAMP) $(CURL_TIMESTAMP) \
$(OPENSSL_TIMESTAMP) curl_binary \
$(OPENSSL_TIMESTAMP) \
$(ROOT)/jni/src/android_version.h \
$(ROOT)/jni/src/android_version_githash.h
@ -205,7 +199,7 @@ openal_download :
openal : $(OPENAL_LIB)
$(OPENAL_LIB): $(OPENAL_TIMESTAMP)
@REFRESH=0; \
+ @REFRESH=0; \
if [ ! -e ${OPENAL_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
@ -250,7 +244,7 @@ ogg_download :
ogg : $(OGG_LIB)
$(OGG_LIB): $(OGG_TIMESTAMP)
@REFRESH=0; \
+ @REFRESH=0; \
if [ ! -e ${OGG_TIMESTAMP_INT} ] ; then \
echo "${OGG_TIMESTAMP_INT} doesn't exist"; \
REFRESH=1; \
@ -295,7 +289,7 @@ openssl_download :
openssl : $(OPENSSL_LIB)
$(OPENSSL_LIB): $(OPENSSL_TIMESTAMP)
$(OPENSSL_LIB): $(OPENSSL_TIMESTAMP) $(GMP_LIB)
@REFRESH=0; \
if [ ! -e ${OPENSSL_TIMESTAMP_INT} ] ; then \
echo "${OPENSSL_TIMESTAMP_INT} doesn't exist"; \
@ -313,7 +307,8 @@ $(OPENSSL_LIB): $(OPENSSL_TIMESTAMP)
--toolchain=${TARGET_TOOLCHAIN}${COMPILER_VERSION} \
--install-dir=$${TOOLCHAIN}; \
export PATH="$${TOOLCHAIN}/bin:$${PATH}"; \
CC=${CROSS_PREFIX}gcc ./Configure android-${TARGET_ARCH} no-idea no-seed -no-sha0 -DL_ENDIAN;\
CC=${CROSS_PREFIX}gcc ./Configure enable-gmp -DL_ENDIAN -I${GMP_DIR} -L${GMP_DIR}/usr/lib android-${TARGET_ARCH};\
CC=${CROSS_PREFIX}gcc ANDROID_DEV=/tmp/ndk-${TARGET_HOST} make depend; \
CC=${CROSS_PREFIX}gcc ANDROID_DEV=/tmp/ndk-${TARGET_HOST} make build_libs; \
touch ${OPENSSL_TIMESTAMP}; \
touch ${OPENSSL_TIMESTAMP_INT}; \
@ -395,7 +390,7 @@ freetype_download :
freetype : $(FREETYPE_LIB)
$(FREETYPE_LIB) : $(FREETYPE_TIMESTAMP)
@REFRESH=0; \
+ @REFRESH=0; \
if [ ! -e ${FREETYPE_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
@ -424,6 +419,7 @@ $(FREETYPE_LIB) : $(FREETYPE_TIMESTAMP)
clean_freetype :
$(RM) -rf ${FREETYPE_DIR}
$(ICONV_TIMESTAMP) : iconv_download
@LAST_MODIF=$$(find ${ICONV_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
@ -511,7 +507,7 @@ $(IRRLICHT_TIMESTAMP) : irrlicht_download
irrlicht : $(IRRLICHT_LIB)
$(IRRLICHT_LIB): $(IRRLICHT_TIMESTAMP) $(FREETYPE_LIB)
@REFRESH=0; \
+ @REFRESH=0; \
if [ ! -e ${IRRLICHT_TIMESTAMP_INT} ] ; then \
REFRESH=1; \
fi; \
@ -585,7 +581,7 @@ $(CURL_LIB): $(CURL_TIMESTAMP) $(OPENSSL_LIB)
export CXX=${CROSS_PREFIX}g++; \
export TARGET_OS=OS_ANDROID_CROSSCOMPILE; \
export CPPFLAGS="$${CPPFLAGS} -I${OPENSSL_DIR}/include \
-L${OPENSSL_DIR} ${TARGET_CFLAGS_ADDON}"; \
${TARGET_CFLAGS_ADDON}"; \
export CFLAGS="$${CFLAGS} ${TARGET_CFLAGS_ADDON}"; \
export LDFLAGS="$${LDFLAGS} -L${OPENSSL_DIR} ${TARGET_LDFLAGS_ADDON}"; \
./configure --host=${TARGET_HOST} --disable-shared --enable-static --with-ssl; \
@ -601,18 +597,6 @@ clean_curl :
$(RM) -rf deps/curl-${CURL_VERSION} \
$(RM) -f deps/curl
curl_binary:
@if [ ! -d "deps/curl-${CURL_VERSION_BINARY}" ] ; then \
echo "curl binary missing, downloading..."; \
mkdir -p ${ROOT}/deps; \
cd deps; \
wget http://curl.haxx.se/gknw.net/7.34.0/dist-android/curl-7.34.0-rtmp-ssh2-ssl-zlib-static-bin-android.tar.gz || exit 1;\
tar -xzf curl-7.34.0-rtmp-ssh2-ssl-zlib-static-bin-android.tar.gz || exit 1;\
mv curl-7.34.0-rtmp-ssh2-ssl-zlib-static-bin-android curl-${CURL_VERSION_BINARY};\
rm curl-7.34.0-rtmp-ssh2-ssl-zlib-static-bin-android.tar.gz; \
fi
$(GMP_TIMESTAMP) : gmp_download
@LAST_MODIF=$$(find ${GMP_DIR} -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" "); \
if [ $$(basename $$LAST_MODIF) != "timestamp" ] ; then \
@ -723,25 +707,14 @@ assets : $(ASSETS_TIMESTAMP)
if [ $$REFRESH -ne 0 ] ; then \
echo "assets changed, refreshing..."; \
$(MAKE) clean_assets; \
mkdir -p ${ROOT}/assets/Minetest; \
cp ${ROOT}/../../multicraft.conf.example ${ROOT}/assets/Minetest; \
cp ${ROOT}/../../README.md ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../builtin ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../client ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../doc ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../fonts ${ROOT}/assets/Minetest; \
mkdir ${ROOT}/assets/Minetest/games; \
for game in ${GAMES_TO_COPY}; do \
cp -r ${ROOT}/../../games/$$game ${ROOT}/assets/Minetest/games/; \
done; \
mkdir ${ROOT}/assets/Minetest/mods; \
for mod in ${MODS_TO_COPY}; do \
cp -r ${ROOT}/../../mods/$$mod ${ROOT}/assets/Minetest/mods/; \
done; \
cp -r ${ROOT}/../../po ${ROOT}/assets/Minetest; \
cp -r ${ROOT}/../../textures ${ROOT}/assets/Minetest; \
mkdir -p ${ROOT}/assets/Minetest/media; \
cp -r ${IRRLICHT_DIR}/media/Shaders ${ROOT}/assets/Minetest/media; \
mkdir -p ${ROOT}/assets/MultiCraft; \
cp ${ROOT}/../../multicraft.conf.example ${ROOT}/assets/MultiCraft; \
cp ${ROOT}/../../README.md ${ROOT}/assets/MultiCraft; \
cp -r ${ROOT}/../../builtin ${ROOT}/assets/MultiCraft; \
mkdir ${ROOT}/assets/MultiCraft/fonts; \
cp -r ${ROOT}/../../fonts/*.ttf ${ROOT}/assets/MultiCraft/fonts/; \
cp -r ${ROOT}/../../games ${ROOT}/assets/MultiCraft; \
cp -r ${ROOT}/../../textures ${ROOT}/assets/MultiCraft; \
cd ${ROOT}/assets || exit 1; \
find . -name "timestamp" -exec rm {} \; ; \
find . -name "*.blend" -exec rm {} \; ; \
@ -750,14 +723,10 @@ assets : $(ASSETS_TIMESTAMP)
find . -type d -path "*.svn" -exec rm -rf {} \; ; \
find . -type f -path "*.gitignore" -exec rm -rf {} \; ; \
ls -R | grep ":$$" | sed -e 's/:$$//' -e 's/\.//' -e 's/^\///' > "index.txt"; \
find Minetest >"filelist.txt"; \
find MultiCraft >"filelist.txt"; \
cp ${ROOT}/${ASSETS_TIMESTAMP} ${ROOT}/${ASSETS_TIMESTAMP}.old; \
cd ${ROOT}/assets/Minetest; \
echo "Creating Files.zip"; \
zip -r -X -q ../Files.zip *; \
cd ${ROOT}/assets; \
rm ${ROOT}/assets/index.txt; \
rm ${ROOT}/assets/filelist.txt; \
zip -r Files.zip MultiCraft; \
else \
echo "nothing to be done for assets"; \
fi
@ -779,10 +748,9 @@ apk: $(PATHCFGFILE) assets $(ICONV_LIB) $(IRRLICHT_LIB) $(CURL_LIB) $(GMP_LIB) $
TARGET_CFLAGS+="${TARGET_CFLAGS_ADDON}" \
TARGET_LDFLAGS+="${TARGET_LDFLAGS_ADDON}" \
TARGET_CXXFLAGS+="${TARGET_CXXFLAGS_ADDON}" && \
ant $$BUILD_TYPE && \
echo "++ Success!" && \
echo "APK: bin/MultiCraft-$$BUILD_TYPE.apk" && \
echo "You can install it with \`adb install -r bin/MultiCraft-$$BUILD_TYPE.apk\`"
# ant $$BUILD_TYPE && \
echo " Success! =)" \
# echo "APK: bin/MultiCraft-$$BUILD_TYPE.apk" && \
prep_srcdir :
@if [ ! -e ${ROOT}/jni/src ]; then \

View File

@ -1,11 +1,13 @@
--- openssl-1.0.1j/Configure.orig 2014-10-15 14:53:39.000000000 +0200
+++ openssl-1.0.1j/Configure 2015-01-03 22:41:43.505749921 +0100
@@ -407,6 +407,8 @@
--- openssl-1.0.2e.orig/Configure 2015-12-03 15:04:23.000000000 +0100
+++ openssl-1.0.2e/Configure 2015-12-14 21:01:40.351265968 +0100
@@ -464,8 +464,10 @@
# Android: linux-* but without pointers to headers and libs.
"android","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${no_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
"android-x86","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG ${x86_gcc_des} ${x86_gcc_opts}:".eval{my $asm=${x86_elf_asm};$asm=~s/:elf/:android/;$asm}.":dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
"android-armv7","gcc:-march=armv7-a -mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${armv4_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+"android-arm","gcc:-march=armv4 -mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${armv4_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+"android-mips32","gcc:-march=mips32 -mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${mips32_asm}:o32:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
"android-armv7","gcc:-march=armv7-a -mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -fomit-frame-pointer -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${armv4_asm}:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
"android-mips","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${mips32_asm}:o32:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
+"android-mips32","gcc:-mandroid -I\$(ANDROID_DEV)/include -B\$(ANDROID_DEV)/lib -O3 -Wall::-D_REENTRANT::-ldl:BN_LLONG RC4_CHAR RC4_CHUNK DES_INT DES_UNROLL BF_PTR:${mips32_asm}:o32:dlfcn:linux-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
#### *BSD [do see comment about ${BSDthreads} above!]
"BSD-generic32","gcc:-DTERMIOS -O3 -fomit-frame-pointer -Wall::${BSDthreads}:::BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL:${no_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",
"BSD-generic32","gcc:-O3 -fomit-frame-pointer -Wall::${BSDthreads}:::BN_LLONG RC2_CHAR RC4_INDEX DES_INT DES_UNROLL:${no_asm}:dlfcn:bsd-gcc-shared:-fPIC::.so.\$(SHLIB_MAJOR).\$(SHLIB_MINOR)",

View File

@ -27,19 +27,11 @@ function core.get_pointed_thing_position(pointed_thing, above)
if above then
-- The position where a node would be placed
return pointed_thing.above
else
-- The position where a node would be dug
return pointed_thing.under
end
-- The position where a node would be dug
return pointed_thing.under
elseif pointed_thing.type == "object" then
obj = pointed_thing.ref
if obj ~= nil then
return obj:getpos()
else
return nil
end
else
return nil
return pointed_thing.ref and pointed_thing.ref:getpos()
end
end

View File

@ -20,7 +20,7 @@ local function create_world_formspec(dialogdata)
mm_texture.clear("header")
mm_texture.clear("footer")
minetest.set_clouds(false)
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.png')
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.jpg')
--minetest.set_background("header",minetest.formspec_escape(mm_texture.basetexturedir)..'header.png')
@ -111,7 +111,7 @@ local function create_world_buttonhandler(this, fields)
core.setting_set("fixed_map_seed", fields["te_seed"])
if not menudata.worldlist:uid_exists_raw(worldname) then
core.setting_set("mg_name","v7")
core.setting_set("mg_name","v6")
message = core.create_world(worldname,gameindex)
else
message = fgettext("A world named \"$1\" already exists", worldname)

View File

@ -21,7 +21,7 @@ local function delete_world_formspec(dialogdata)
mm_texture.clear("header")
mm_texture.clear("footer")
minetest.set_clouds(false)
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.png')
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.jpg')
--minetest.set_background("header",minetest.formspec_escape(mm_texture.basetexturedir)..'header.png')
local retval =

View File

@ -121,7 +121,7 @@ local function init_globals()
mm_texture.clear("header")
mm_texture.clear("footer")
minetest.set_clouds(false)
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.png')
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.jpg')
--minetest.set_background("header",minetest.formspec_escape(mm_texture.basetexturedir)..'header.png')
end

View File

@ -21,7 +21,7 @@ tab_credits = {
name = "credits",
caption = fgettext("Credits"),
cbf_formspec = function (tabview, name, tabdata)
local logofile = defaulttexturedir .. "logo.png"
local logofile = defaulttexturedir .. "smoke_puff.png"
return "label[0.5,3.2;Minetest " .. core.get_version() .. "]" ..
"label[0.5,3.5;http://minetest.net]" ..
"image[0.5,1;" .. core.formspec_escape(logofile) .. "]" ..

View File

@ -21,7 +21,7 @@ local function get_formspec(tabview, name, tabdata)
mm_texture.clear("header")
mm_texture.clear("footer")
minetest.set_clouds(false)
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.png')
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.jpg')
--minetest.set_background("header",minetest.formspec_escape(mm_texture.basetexturedir)..'header.png')
local render_details = core.is_yes(core.setting_getbool("public_serverlist"))

View File

@ -21,7 +21,7 @@ local function get_formspec(tabview, name, tabdata)
mm_texture.clear("header")
mm_texture.clear("footer")
minetest.set_clouds(false)
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.png')
minetest.set_background("background",minetest.formspec_escape(mm_texture.basetexturedir)..'background.jpg')
--minetest.set_background("header",minetest.formspec_escape(mm_texture.basetexturedir)..'header.png')
local index = menudata.worldlist:get_current_index(

View File

@ -158,5 +158,4 @@ tab_singleplayer = {
caption = fgettext("Single Player"),
cbf_formspec = get_formspec,
cbf_button_handler = main_button_handler,
on_change = on_change
}

View File

@ -970,49 +970,60 @@ mgflat_np_cave2 (Mapgen flat cave2 noise parameters) noise_params 0, 12, (128, 1
[***Mapgen fractal]
# Choice of 8 4-dimensional fractals.
# 1 = "Roundy" mandelbrot set.
# 2 = "Roundy" julia set.
# 3 = "Squarry" mandelbrot set.
# 4 = "Squarry" julia set.
# 5 = "Mandy Cousin" mandelbrot set.
# 6 = "Mandy Cousin" julia set.
# 7 = "Variation" mandelbrot set.
# 8 = "Variation" julia set.
mgfractal_formula (Mapgen fractal formula) int 1 1 8
# Choice of 18 fractals from 9 formulas.
# 1 = 4D "Roundy" mandelbrot set.
# 2 = 4D "Roundy" julia set.
# 3 = 4D "Squarry" mandelbrot set.
# 4 = 4D "Squarry" julia set.
# 5 = 4D "Mandy Cousin" mandelbrot set.
# 6 = 4D "Mandy Cousin" julia set.
# 7 = 4D "Variation" mandelbrot set.
# 8 = 4D "Variation" julia set.
# 9 = 3D "Mandelbrot/Mandelbar" mandelbrot set.
# 10 = 3D "Mandelbrot/Mandelbar" julia set.
# 11 = 3D "Christmas Tree" mandelbrot set.
# 12 = 3D "Christmas Tree" julia set.
# 13 = 3D "Mandelbulb" mandelbrot set.
# 14 = 3D "Mandelbulb" julia set.
# 15 = 3D "Cosine Mandelbulb" mandelbrot set.
# 16 = 3D "Cosine Mandelbulb" julia set.
# 17 = 4D "Mandelbulb" mandelbrot set.
# 18 = 4D "Mandelbulb" julia set.
mgfractal_fractal (Mapgen fractal fractal) int 1 1 18
# Iterations of the recursive function.
# Controls scale of finest detail.
# Controls the amount of fine detail.
mgfractal_iterations (Mapgen fractal iterations) int 11
# Approximate (X,Y,Z) scale of fractal in nodes.
mgfractal_scale (Mapgen fractal scale) v3f (4096.0, 1024.0, 4096.0)
# (X,Y,Z) offset of fractal from world centre.
# (X,Y,Z) offset of fractal from world centre in units of 'scale'.
# Used to move a suitable spawn area of low land close to (0, 0).
# The default is suitable for mandelbrot sets, it needs to be edited for julia sets,
# do this by greatly reducing 'scale' and setting 'offset' initially to (0, 0, 0).
# The default is suitable for mandelbrot sets, it needs to be edited for julia sets.
# Range roughly -2 to 2. Multiply by 'scale' for offset in nodes.
mgfractal_offset (Mapgen fractal offset) v3f (1.79, 0.0, 0.0)
# W co-ordinate of the generated 3D slice of the 4D shape.
# Alters the generated 3D shape.
# W co-ordinate of the generated 3D slice of a 4D fractal.
# Determines which 3D slice of the 4D shape is generated.
# Has no effect on 3D fractals.
# Range roughly -2 to 2.
mgfractal_slice_w (Mapgen fractal slice w) float 0.0
# Julia set only: X value determining the 4D shape.
# Julia set only: X component of hypercomplex constant determining julia shape.
# Range roughly -2 to 2.
mgfractal_julia_x (Mapgen fractal julia x) float 0.33
# Julia set only: Y value determining the 4D shape.
# Julia set only: Y component of hypercomplex constant determining julia shape.
# Range roughly -2 to 2.
mgfractal_julia_y (Mapgen fractal julia y) float 0.33
# Julia set only: Z value determining the 4D shape.
# Julia set only: Z component of hypercomplex constant determining julia shape.
# Range roughly -2 to 2.
mgfractal_julia_z (Mapgen fractal julia z) float 0.33
# Julia set only: W value determining the 4D shape.
# Julia set only: W component of hypercomplex constant determining julia shape.
# Has no effect on 3D fractals.
# Range roughly -2 to 2.
mgfractal_julia_w (Mapgen fractal julia w) float 0.33

130
doc/README.android.txt Normal file
View File

@ -0,0 +1,130 @@
Minetest Android port
=====================
Date: 2015 12 16
Controls
--------
The Android port doesn't support everything you can do on PC due to the
limited capabilities of common devices. What can be done is described
below:
While you're playing the game normally (that is, no menu or inventory is
shown), the following controls are available:
* Look around: touch screen and slide finger
* double tap: place a node or use selected item
* long tap: dig node
* touch shown buttons: press button
* Buttons:
** left upper corner: chat
** right lower corner: jump
** right lower corner: crouch
** left lower corner: walk/step...
left up right
down
** left lower corner: display inventory
When a menu or inventory is displayed:
* double tap outside menu area: close menu
* tap on an item stack: select that stack
* tap on an empty slot: if you selected a stack already, that stack is placed here
* drag and drop: touch stack and hold finger down, move the stack to another
slot, tap another finger while keeping first finger on screen
--> places a single item from dragged stack into current (first touched) slot
Special settings
----------------
There are some settings especially useful for Android users. Minetest's config
file can usually be found at /mnt/sdcard/Minetest.
* gui_scaling: this is a user-specified scaling factor for the GUI- In case
main menu is too big or small on your device, try changing this
value.
* inventory_image_hack: if your inventory items are messed up, try setting
this to true
Known issues
------------
Not all issues are fixed by now:
* Unable to exit from volume menu -- don't use the volume menu, use Android's
volume controls instead.
* 512 MB RAM seems to be inadequate -- this depends on the server you join.
Try to play on more lightweight servers.
Versioning
----------
Android version numbers are 4 digits instead of Minetest's 3 digits. The last
number of Android's version represents the Android internal version code. This
version code is strictly incremental. It's incremented for each official
Minetest Android build.
E.g. prerelease Minetest Android builds have been 0.4.9.3, while the first
official version most likely will be 0.4.10.4
Requirements
------------
In order to build, your PC has to be set up to build Minetest in the usual
manner (see the regular Minetest documentation for how to get this done).
In addition to what is required for Minetest in general, you will need the
following software packages. The version number in parenthesis denotes the
version that was tested at the time this README was drafted; newer/older
versions may or may not work.
* android SDK (24.4.1)
* android NDK (r10e)
* wget (1.13.4)
Additionally, you'll need to have an Internet connection available on the
build system, as the Android build will download some source packages.
Build
-----
Debug build:
* Enter "build/android" subdirectory
* Execute "make"
* Answer the questions about where SDK and NDK are located on your filesystem
* Wait for build to finish
After the build is finished, the resulting apk can be fond in
build/android/bin/. It will be called Minetest-debug.apk
Release build:
* In order to make a release build you'll have to have a keystore setup to sign
the resulting apk package. How this is done is not part of this README. There
are different tutorials on the web explaining how to do it
- choose one yourself.
* Once your keystore is setup, enter build/android subdirectory and create a new
file "ant.properties" there. Add following lines to that file:
> key.store=<path to your keystore>
> key.alias=Minetest
* Execute "make release"
* Enter your keystore as well as your Mintest key password once asked. Be
careful it's shown on console in clear text!
* The result can be found at "bin/Minetest-release.apk"
Other things that may be nice to know
------------
* The environment for Android development tools is saved within Android build
build folder. If you want direct access to it do:
> make envpaths
> . and_env
After you've done this you'll have your path and path variables set correct
to use adb and all other Android development tools
* You can build a single dependency by calling make and the dependency's name,
e.g.:
> make irrlicht
* You can completely cleanup a dependency by calling make and the "clean" target,
e.g.:
> make clean_irrlicht

Binary file not shown.

View File

@ -4,7 +4,7 @@ Copyright (C) 2015 est31 <MTest31@outlook.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

View File

@ -4,7 +4,7 @@ Copyright (C) 2010-2013 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 Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

View File

@ -1261,8 +1261,18 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
if (getParent() == NULL && m_prop.automatic_face_movement_dir &&
(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001))
{
m_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI
float optimal_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI
+ m_prop.automatic_face_movement_dir_offset;
float max_rotation_delta =
dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
if ((m_prop.automatic_face_movement_max_rotation_per_sec > 0) &&
(fabs(m_yaw - optimal_yaw) > max_rotation_delta)) {
m_yaw = optimal_yaw < m_yaw ? m_yaw - max_rotation_delta : m_yaw + max_rotation_delta;
} else {
m_yaw = optimal_yaw;
}
updateNodePos();
}
}

View File

@ -283,8 +283,20 @@ void LuaEntitySAO::step(float dtime, bool send_recommended)
}
if((m_prop.automatic_face_movement_dir) &&
(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)){
m_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI + m_prop.automatic_face_movement_dir_offset;
(fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001))
{
float optimal_yaw = atan2(m_velocity.Z,m_velocity.X) * 180 / M_PI
+ m_prop.automatic_face_movement_dir_offset;
float max_rotation_delta =
dtime * m_prop.automatic_face_movement_max_rotation_per_sec;
if ((m_prop.automatic_face_movement_max_rotation_per_sec > 0) &&
(fabs(m_yaw - optimal_yaw) > max_rotation_delta)) {
m_yaw = optimal_yaw < m_yaw ? m_yaw - max_rotation_delta : m_yaw + max_rotation_delta;
} else {
m_yaw = optimal_yaw;
}
}
}

View File

@ -245,7 +245,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("default_privs", "interact, shout");
settings->setDefault("player_transfer_distance", "0");
settings->setDefault("enable_pvp", "true");
settings->setDefault("vertical_spawn_range", "16");
settings->setDefault("vertical_spawn_range", "128");
settings->setDefault("disallow_empty_password", "false");
settings->setDefault("disable_anticheat", "false");
settings->setDefault("enable_rollback_recording", "false");
@ -340,8 +340,8 @@ void set_default_settings(Settings *settings)
settings->setDefault("TMPFolder","/sdcard/tmp/");
settings->setDefault("touchscreen_threshold","20");
settings->setDefault("smooth_lighting", "false");
settings->setDefault("emergequeue_limit_diskonly", "8");
settings->setDefault("emergequeue_limit_generate", "8");
settings->setDefault("emergequeue_limit_diskonly", "4");
settings->setDefault("emergequeue_limit_generate", "4");
settings->setDefault("max_block_generate_distance", "3");
settings->setDefault("preload_item_visuals", "false");
settings->setDefault("viewing_range_nodes_max", "50");

View File

@ -2580,7 +2580,17 @@ void Game::processUserInput(VolatileRunFlags *flags,
|| noMenuActive() == false
|| guienv->hasFocus(gui_chat_console)) {
input->clear();
#ifdef HAVE_TOUCHSCREENGUI
g_touchscreengui->Hide();
#endif
}
#ifdef HAVE_TOUCHSCREENGUI
else if (g_touchscreengui) {
/* on touchscreengui step may generate own input events which ain't
* what we want in case we just did clear them */
g_touchscreengui->step(dtime);
}
#endif
if (!guienv->hasFocus(gui_chat_console) && gui_chat_console->isOpen()) {
gui_chat_console->closeConsoleAtOnce();
@ -2589,13 +2599,6 @@ void Game::processUserInput(VolatileRunFlags *flags,
// Input handler step() (used by the random input generator)
input->step(dtime);
#ifdef HAVE_TOUCHSCREENGUI
if (g_touchscreengui) {
g_touchscreengui->step(dtime);
}
#endif
#ifdef __ANDROID__
if (current_formspec != 0)
@ -4219,13 +4222,11 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
guitext->setVisible(true);
} else if (flags.show_hud || flags.show_chat) {
#ifdef ANDROID
u16 fps = 1.0 / stats.dtime_jitter.avg;
std::ostringstream os(std::ios_base::binary);
os << std::setprecision(1) << std::fixed
<< "FPS = " << fps
<< " (" << (player_position.X / BS)
<< ", " << (player_position.Y / BS)
<< ", " << (player_position.Z / BS)
<< "(X: " << (player_position.X / BS)
<< ", Y: " << (player_position.Y / BS)
<< ", Z: " << (player_position.Z / BS)
<< ")";
guitext->setText(utf8_to_wide(os.str()).c_str());
guitext->setVisible(true);
@ -4234,6 +4235,7 @@ void Game::updateGui(float *statustext_time, const RunStats &stats,
os << PROJECT_NAME_C " " << g_version_hash;
guitext->setText(utf8_to_wide(os.str()).c_str());
guitext->setVisible(true);
#endif
} else {
guitext->setVisible(false);
}

View File

@ -172,8 +172,7 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev,
m_sound_manager = &dummySoundManager;
//create topleft header
//std::wstring t = utf8_to_wide(std::string(PROJECT_NAME_C " ") +
//g_version_hash);
std::wstring t = utf8_to_wide(std::string(""));
core::rect<s32> rect(0, 0, g_fontengine->getTextWidth(t), g_fontengine->getTextHeight());
rect += v2s32(4, 0);

View File

@ -5,7 +5,7 @@ Copyright (C) 2010-2015 paramat, Matt Gregory
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

View File

@ -5,7 +5,7 @@ Copyright (C) 2010-2015 paramat, Matt Gregory
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

View File

@ -5,7 +5,7 @@ Copyright (C) 2010-2015 paramat, Matt Gregory
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

View File

@ -5,7 +5,7 @@ Copyright (C) 2010-2015 paramat, Matt Gregory
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

View File

@ -43,7 +43,10 @@ ObjectProperties::ObjectProperties():
stepheight(0),
automatic_face_movement_dir(false),
automatic_face_movement_dir_offset(0.0),
backface_culling(true)
backface_culling(true),
nametag(""),
nametag_color(255, 255, 255, 255),
automatic_face_movement_max_rotation_per_sec(-1)
{
textures.push_back("unknown_object.png");
colors.push_back(video::SColor(255,255,255,255));
@ -76,6 +79,9 @@ std::string ObjectProperties::dump()
os<<", makes_footstep_sound="<<makes_footstep_sound;
os<<", automatic_rotate="<<automatic_rotate;
os<<", backface_culling="<<backface_culling;
os << ", nametag=" << nametag;
os << ", nametag_color=" << "\"" << nametag_color.getAlpha() << "," << nametag_color.getRed()
<< "," << nametag_color.getGreen() << "," << nametag_color.getBlue() << "\" ";
return os.str();
}
@ -109,6 +115,10 @@ void ObjectProperties::serialize(std::ostream &os) const
writeU8(os, automatic_face_movement_dir);
writeF1000(os, automatic_face_movement_dir_offset);
writeU8(os, backface_culling);
os << serializeString(nametag);
writeARGB8(os, nametag_color);
writeF1000(os, automatic_face_movement_max_rotation_per_sec);
// Add stuff only at the bottom.
// Never remove anything, because we don't want new versions of this
}
@ -146,6 +156,9 @@ void ObjectProperties::deSerialize(std::istream &is)
automatic_face_movement_dir = readU8(is);
automatic_face_movement_dir_offset = readF1000(is);
backface_culling = readU8(is);
nametag = deSerializeString(is);
nametag_color = readARGB8(is);
automatic_face_movement_max_rotation_per_sec = readF1000(is);
}catch(SerializationError &e){}
}
else

View File

@ -48,7 +48,9 @@ struct ObjectProperties
bool automatic_face_movement_dir;
f32 automatic_face_movement_dir_offset;
bool backface_culling;
std::string nametag;
video::SColor nametag_color;
f32 automatic_face_movement_max_rotation_per_sec;
ObjectProperties();
std::string dump();

View File

@ -217,8 +217,8 @@ void initializePathsAndroid()
cls_File, mt_getAbsPath, "getCacheDir");
path_storage = getAndroidPath(cls_Env, NULL, cls_File, mt_getAbsPath,
"getExternalStorageDirectory");
path_user = path_storage + DIR_DELIM + "Android/data/net.MultiCraft.Official/Files";
path_share = path_storage + DIR_DELIM + "Android/data/net.MultiCraft.Official/Files";
path_user = path_storage + DIR_DELIM + "Android/data/ua.MultiCraft/Files";
path_share = path_storage + DIR_DELIM + "Android/data/ua.MultiCraft/Files";
migrateCachePath();
}

View File

@ -201,6 +201,21 @@ void read_object_properties(lua_State *L, int index,
}
lua_pop(L, 1);
getboolfield(L, -1, "backface_culling", prop->backface_culling);
getstringfield(L, -1, "nametag", prop->nametag);
lua_getfield(L, -1, "nametag_color");
if (!lua_isnil(L, -1)) {
video::SColor color = prop->nametag_color;
if (read_color(L, -1, &color))
prop->nametag_color = color;
}
lua_pop(L, 1);
lua_getfield(L, -1, "automatic_face_movement_max_rotation_per_sec");
if (lua_isnumber(L, -1)) {
prop->automatic_face_movement_max_rotation_per_sec = luaL_checknumber(L, -1);
}
lua_pop(L, 1);
}
/******************************************************************************/
@ -261,6 +276,12 @@ void push_object_properties(lua_State *L, ObjectProperties *prop)
lua_setfield(L, -2, "automatic_face_movement_dir");
lua_pushboolean(L, prop->backface_culling);
lua_setfield(L, -2, "backface_culling");
lua_pushlstring(L, prop->nametag.c_str(), prop->nametag.size());
lua_setfield(L, -2, "nametag");
push_ARGB8(L, prop->nametag_color);
lua_setfield(L, -2, "nametag_color");
lua_pushnumber(L, prop->automatic_face_movement_max_rotation_per_sec);
lua_setfield(L, -2, "automatic_face_movement_max_rotation_per_sec");
}
/******************************************************************************/

View File

@ -4,7 +4,7 @@ Copyright (C) 2015 est31 <MTest31@outlook.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

View File

@ -4,7 +4,7 @@ Copyright (C) 2015 est31 <MTest31@outlook.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

View File

@ -459,6 +459,73 @@ void TouchScreenGUI::ButtonEvent(touch_gui_button_id button,
delete translated;
}
void TouchScreenGUI::handleReleaseEvent(int evt_id)
{
touch_gui_button_id button = getButtonID(evt_id);
/* handle button events */
if (button != after_last_element_id) {
ButtonEvent(button, evt_id, false);
}
/* handle hud button events */
else if (isReleaseHUDButton(evt_id)) {
/* nothing to do here */
}
/* handle the point used for moving view */
else if (evt_id == m_move_id) {
m_move_id = -1;
/* if this pointer issued a mouse event issue symmetric release here */
if (m_move_sent_as_mouse_event) {
SEvent* translated = new SEvent;
memset(translated,0,sizeof(SEvent));
translated->EventType = EET_MOUSE_INPUT_EVENT;
translated->MouseInput.X = m_move_downlocation.X;
translated->MouseInput.Y = m_move_downlocation.Y;
translated->MouseInput.Shift = false;
translated->MouseInput.Control = false;
translated->MouseInput.ButtonStates = 0;
translated->MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
m_receiver->OnEvent(*translated);
delete translated;
} else if (m_control_pad_rect.isPointInside(v2s32(m_move_downlocation.X, m_move_downlocation.Y))) {
// ignore events inside the control pad not already handled
} else if (!m_move_has_really_moved) {
SEvent* translated = new SEvent;
memset(translated,0,sizeof(SEvent));
translated->EventType = EET_MOUSE_INPUT_EVENT;
translated->MouseInput.X = m_move_downlocation.X;
translated->MouseInput.Y = m_move_downlocation.Y;
translated->MouseInput.Shift = false;
translated->MouseInput.Control = false;
translated->MouseInput.ButtonStates = 0;
translated->MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
m_receiver->OnEvent(*translated);
delete translated;
doubleTapDetection();
m_shootline = m_device
->getSceneManager()
->getSceneCollisionManager()
->getRayFromScreenCoordinates(
v2s32(m_move_downlocation.X,m_move_downlocation.Y));
}
}
else {
infostream
<< "TouchScreenGUI::translateEvent released unknown button: "
<< evt_id << std::endl;
}
for (std::vector<id_status>::iterator iter = m_known_ids.begin();
iter != m_known_ids.end(); ++iter) {
if (iter->id == evt_id) {
m_known_ids.erase(iter);
break;
}
}
}
void TouchScreenGUI::translateEvent(const SEvent &event)
{
if (!m_visible) {
@ -513,70 +580,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event)
}
else if (event.TouchInput.Event == ETIE_LEFT_UP) {
verbosestream << "Up event for pointerid: " << event.TouchInput.ID << std::endl;
touch_gui_button_id button = getButtonID(event.TouchInput.ID);
/* handle button events */
if (button != after_last_element_id) {
ButtonEvent(button,event.TouchInput.ID,false);
}
/* handle hud button events */
else if (isReleaseHUDButton(event.TouchInput.ID)) {
/* nothing to do here */
}
/* handle the point used for moving view */
else if (event.TouchInput.ID == m_move_id) {
m_move_id = -1;
/* if this pointer issued a mouse event issue symmetric release here */
if (m_move_sent_as_mouse_event) {
SEvent* translated = new SEvent;
memset(translated,0,sizeof(SEvent));
translated->EventType = EET_MOUSE_INPUT_EVENT;
translated->MouseInput.X = m_move_downlocation.X;
translated->MouseInput.Y = m_move_downlocation.Y;
translated->MouseInput.Shift = false;
translated->MouseInput.Control = false;
translated->MouseInput.ButtonStates = 0;
translated->MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
m_receiver->OnEvent(*translated);
delete translated;
} else if (m_control_pad_rect.isPointInside(v2s32(m_move_downlocation.X, m_move_downlocation.Y))) {
// ignore events inside the control pad not already handled
} else if (!m_move_has_really_moved) {
SEvent* translated = new SEvent;
memset(translated,0,sizeof(SEvent));
translated->EventType = EET_MOUSE_INPUT_EVENT;
translated->MouseInput.X = m_move_downlocation.X;
translated->MouseInput.Y = m_move_downlocation.Y;
translated->MouseInput.Shift = false;
translated->MouseInput.Control = false;
translated->MouseInput.ButtonStates = 0;
translated->MouseInput.Event = EMIE_LMOUSE_LEFT_UP;
m_receiver->OnEvent(*translated);
delete translated;
doubleTapDetection();
m_shootline = m_device
->getSceneManager()
->getSceneCollisionManager()
->getRayFromScreenCoordinates(
v2s32(event.TouchInput.X,event.TouchInput.Y));
}
}
else {
infostream
<< "TouchScreenGUI::translateEvent released unknown button: "
<< event.TouchInput.ID << std::endl;
}
for (std::vector<id_status>::iterator iter = m_known_ids.begin();
iter != m_known_ids.end(); ++iter) {
if (iter->id == event.TouchInput.ID) {
m_known_ids.erase(iter);
break;
}
}
handleReleaseEvent(event.TouchInput.ID);
}
else {
assert(event.TouchInput.Event == ETIE_MOVED);
@ -826,14 +830,28 @@ void TouchScreenGUI::Toggle(bool visible)
btn->guibutton->setVisible(visible);
}
}
/* clear all active buttons */
if (!visible) {
while (m_known_ids.size() > 0) {
handleReleaseEvent(m_known_ids.begin()->id);
}
}
}
void TouchScreenGUI::Hide()
{
if (!m_visible)
return;
Toggle(false);
}
void TouchScreenGUI::Show()
{
if (m_visible)
return;
Toggle(true);
}

View File

@ -159,6 +159,9 @@ private:
/* handle double taps */
bool doubleTapDetection();
/* handle release event */
void handleReleaseEvent(int evt_id);
/* doubleclick detection variables */
struct key_event {
unsigned int down_time;

View File

@ -4,7 +4,7 @@ Copyright (C) 2015 est31 <MTest31@outlook.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

View File

@ -4,7 +4,7 @@ Copyright (C) 2010-2013 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 Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 835 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 485 B

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 B

After

Width:  |  Height:  |  Size: 671 B