forked from MTSR/techage_modpack
built on 06/08/2022 15:09:51
This commit is contained in:
parent
5a39e9f0a6
commit
09584b8a2d
@ -1,7 +1,7 @@
|
||||
# Modpack Tech Age [techage]
|
||||
|
||||
This modpack covers all necessary and useful mods to be able to use techage.
|
||||
All mods have the own README.txt. For further information please consult these files.
|
||||
All mods have their own README.txt. For further information please consult these files.
|
||||
|
||||
This modpack contains:
|
||||
- techage: The main mod
|
||||
|
@ -1,4 +0,0 @@
|
||||
default
|
||||
moreblocks?
|
||||
techage?
|
||||
minecart?
|
@ -1 +0,0 @@
|
||||
Street mod for faster travelling.
|
@ -1 +1,5 @@
|
||||
name=autobahn
|
||||
title=Autobahn
|
||||
description=Street mod for faster travelling.
|
||||
depends=default
|
||||
optional_depends=moreblocks, techage, minecart
|
@ -1 +0,0 @@
|
||||
|
2
datastorage/mod.conf
Normal file
2
datastorage/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name=datastorage
|
||||
description=Helper mod to manage players data.
|
@ -115,10 +115,10 @@ local generate_texture = function(lines)
|
||||
end
|
||||
|
||||
local lcds = {
|
||||
[2] = {delta = {x = 0.437, y = 0, z = 0}, yaw = math.pi / -2},
|
||||
[3] = {delta = {x = -0.437, y = 0, z = 0}, yaw = math.pi / 2},
|
||||
[4] = {delta = {x = 0, y = 0, z = 0.437}, yaw = 0},
|
||||
[5] = {delta = {x = 0, y = 0, z = -0.437}, yaw = math.pi},
|
||||
[2] = {delta = {x = 0.425, y = 0, z = 0}, yaw = math.pi / -2},
|
||||
[3] = {delta = {x = -0.425, y = 0, z = 0}, yaw = math.pi / 2},
|
||||
[4] = {delta = {x = 0, y = 0, z = 0.425}, yaw = 0},
|
||||
[5] = {delta = {x = 0, y = 0, z = -0.425}, yaw = math.pi},
|
||||
}
|
||||
|
||||
local clearscreen = function(pos)
|
||||
|
@ -1,4 +0,0 @@
|
||||
SaferLua [safer_lua], a subset of the language Lua for safe and secure Lua sandboxes
|
||||
|
||||
|
||||
|
@ -1 +1,2 @@
|
||||
name=safer_lua
|
||||
description = SaferLua [safer_lua], a subset of the language Lua for safe and secure Lua sandboxes
|
||||
|
@ -11,7 +11,7 @@ and by the historical game Lunar Lander.
|
||||
Instructions:
|
||||
- Craft TA4 Jetpack, Jetpack Controller and Training Mat
|
||||
- Use the armor extension (3d_armor) of the player menu to strap the Jetpack on your back
|
||||
- You can refuel the jetpack by left-clicking with the controller on a hydrogen tank
|
||||
- You can refuel the jetpack by left-clicking with the controller on a TA3/TA4 tank previously charged with hydrogen
|
||||
- Turn the controller on by right-click and check the fuel tank level (the small colored bar below the controller icon)
|
||||
- Use the space bar to activate the Jetpack and the WASD keys to control the direction
|
||||
- Before your first flight you should do some training starts and landings on the Training Mat
|
||||
|
@ -1,80 +1,476 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Script to generate the template file and update the translation files.
|
||||
# Copy the script into the mod or modpack root folder and run it there.
|
||||
#
|
||||
# Copyright (C) 2019 Joachim Stolberg
|
||||
# Copyright (C) 2019 Joachim Stolberg, 2020 FaceDeer, 2020 Louis Royer
|
||||
# LGPLv2.1+
|
||||
#
|
||||
# Copy the script into the mod root folder and adapt the last code lines to you needs.
|
||||
#
|
||||
# See https://github.com/minetest-tools/update_translations for
|
||||
# potential future updates to this script.
|
||||
|
||||
from __future__ import print_function
|
||||
import os, fnmatch, re, shutil
|
||||
import os, fnmatch, re, shutil, errno
|
||||
from sys import argv as _argv
|
||||
from sys import stderr as _stderr
|
||||
|
||||
pattern_lua = re.compile(r'[ \.=^\t]S\("(.+?)"\)', re.DOTALL)
|
||||
pattern_tr = re.compile(r'(.+?[^@])=(.+)')
|
||||
# Running params
|
||||
params = {"recursive": False,
|
||||
"help": False,
|
||||
"mods": False,
|
||||
"verbose": False,
|
||||
"folders": [],
|
||||
"no-old-file": False,
|
||||
"break-long-lines": False,
|
||||
"sort": False,
|
||||
"print-source": False,
|
||||
"truncate-unused": False,
|
||||
}
|
||||
# Available CLI options
|
||||
options = {"recursive": ['--recursive', '-r'],
|
||||
"help": ['--help', '-h'],
|
||||
"mods": ['--installed-mods', '-m'],
|
||||
"verbose": ['--verbose', '-v'],
|
||||
"no-old-file": ['--no-old-file', '-O'],
|
||||
"break-long-lines": ['--break-long-lines', '-b'],
|
||||
"sort": ['--sort', '-s'],
|
||||
"print-source": ['--print-source', '-p'],
|
||||
"truncate-unused": ['--truncate-unused', '-t'],
|
||||
}
|
||||
|
||||
def gen_template(templ_file, lkeyStrings):
|
||||
lOut = []
|
||||
lkeyStrings.sort()
|
||||
for s in lkeyStrings:
|
||||
lOut.append("%s=" % s)
|
||||
open(templ_file, "wt").write("\n".join(lOut))
|
||||
# Strings longer than this will have extra space added between
|
||||
# them in the translation files to make it easier to distinguish their
|
||||
# beginnings and endings at a glance
|
||||
doublespace_threshold = 80
|
||||
|
||||
def set_params_folders(tab: list):
|
||||
'''Initialize params["folders"] from CLI arguments.'''
|
||||
# Discarding argument 0 (tool name)
|
||||
for param in tab[1:]:
|
||||
stop_param = False
|
||||
for option in options:
|
||||
if param in options[option]:
|
||||
stop_param = True
|
||||
break
|
||||
if not stop_param:
|
||||
params["folders"].append(os.path.abspath(param))
|
||||
|
||||
def set_params(tab: list):
|
||||
'''Initialize params from CLI arguments.'''
|
||||
for option in options:
|
||||
for option_name in options[option]:
|
||||
if option_name in tab:
|
||||
params[option] = True
|
||||
break
|
||||
|
||||
def print_help(name):
|
||||
'''Prints some help message.'''
|
||||
print(f'''SYNOPSIS
|
||||
{name} [OPTIONS] [PATHS...]
|
||||
DESCRIPTION
|
||||
{', '.join(options["help"])}
|
||||
prints this help message
|
||||
{', '.join(options["recursive"])}
|
||||
run on all subfolders of paths given
|
||||
{', '.join(options["mods"])}
|
||||
run on locally installed modules
|
||||
{', '.join(options["no-old-file"])}
|
||||
do not create *.old files
|
||||
{', '.join(options["sort"])}
|
||||
sort output strings alphabetically
|
||||
{', '.join(options["break-long-lines"])}
|
||||
add extra line breaks before and after long strings
|
||||
{', '.join(options["print-source"])}
|
||||
add comments denoting the source file
|
||||
{', '.join(options["verbose"])}
|
||||
add output information
|
||||
{', '.join(options["truncate-unused"])}
|
||||
delete unused strings from files
|
||||
''')
|
||||
|
||||
|
||||
def main():
|
||||
'''Main function'''
|
||||
set_params(_argv)
|
||||
set_params_folders(_argv)
|
||||
if params["help"]:
|
||||
print_help(_argv[0])
|
||||
elif params["recursive"] and params["mods"]:
|
||||
print("Option --installed-mods is incompatible with --recursive")
|
||||
else:
|
||||
# Add recursivity message
|
||||
print("Running ", end='')
|
||||
if params["recursive"]:
|
||||
print("recursively ", end='')
|
||||
# Running
|
||||
if params["mods"]:
|
||||
print(f"on all locally installed modules in {os.path.expanduser('~/.minetest/mods/')}")
|
||||
run_all_subfolders(os.path.expanduser("~/.minetest/mods"))
|
||||
elif len(params["folders"]) >= 2:
|
||||
print("on folder list:", params["folders"])
|
||||
for f in params["folders"]:
|
||||
if params["recursive"]:
|
||||
run_all_subfolders(f)
|
||||
else:
|
||||
update_folder(f)
|
||||
elif len(params["folders"]) == 1:
|
||||
print("on folder", params["folders"][0])
|
||||
if params["recursive"]:
|
||||
run_all_subfolders(params["folders"][0])
|
||||
else:
|
||||
update_folder(params["folders"][0])
|
||||
else:
|
||||
print("on folder", os.path.abspath("./"))
|
||||
if params["recursive"]:
|
||||
run_all_subfolders(os.path.abspath("./"))
|
||||
else:
|
||||
update_folder(os.path.abspath("./"))
|
||||
|
||||
#group 2 will be the string, groups 1 and 3 will be the delimiters (" or ')
|
||||
#See https://stackoverflow.com/questions/46967465/regex-match-text-in-either-single-or-double-quote
|
||||
pattern_lua_s = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL)
|
||||
pattern_lua_fs = re.compile(r'[\.=^\t,{\(\s]N?FS\(\s*(["\'])((?:\\\1|(?:(?!\1)).)*)(\1)[\s,\)]', re.DOTALL)
|
||||
pattern_lua_bracketed_s = re.compile(r'[\.=^\t,{\(\s]N?S\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL)
|
||||
pattern_lua_bracketed_fs = re.compile(r'[\.=^\t,{\(\s]N?FS\(\s*\[\[(.*?)\]\][\s,\)]', re.DOTALL)
|
||||
|
||||
# Handles "concatenation" .. " of strings"
|
||||
pattern_concat = re.compile(r'["\'][\s]*\.\.[\s]*["\']', re.DOTALL)
|
||||
|
||||
pattern_tr = re.compile(r'(.*?[^@])=(.*)')
|
||||
pattern_name = re.compile(r'^name[ ]*=[ ]*([^ \n]*)')
|
||||
pattern_tr_filename = re.compile(r'\.tr$')
|
||||
pattern_po_language_code = re.compile(r'(.*)\.po$')
|
||||
|
||||
#attempt to read the mod's name from the mod.conf file or folder name. Returns None on failure
|
||||
def get_modname(folder):
|
||||
try:
|
||||
with open(os.path.join(folder, "mod.conf"), "r", encoding='utf-8') as mod_conf:
|
||||
for line in mod_conf:
|
||||
match = pattern_name.match(line)
|
||||
if match:
|
||||
return match.group(1)
|
||||
except FileNotFoundError:
|
||||
if not os.path.isfile(os.path.join(folder, "modpack.txt")):
|
||||
folder_name = os.path.basename(folder)
|
||||
# Special case when run in Minetest's builtin directory
|
||||
if folder_name == "builtin":
|
||||
return "__builtin"
|
||||
else:
|
||||
return folder_name
|
||||
else:
|
||||
return None
|
||||
return None
|
||||
|
||||
#If there are already .tr files in /locale, returns a list of their names
|
||||
def get_existing_tr_files(folder):
|
||||
out = []
|
||||
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
|
||||
for name in files:
|
||||
if pattern_tr_filename.search(name):
|
||||
out.append(name)
|
||||
return out
|
||||
|
||||
# A series of search and replaces that massage a .po file's contents into
|
||||
# a .tr file's equivalent
|
||||
def process_po_file(text):
|
||||
# The first three items are for unused matches
|
||||
text = re.sub(r'#~ msgid "', "", text)
|
||||
text = re.sub(r'"\n#~ msgstr ""\n"', "=", text)
|
||||
text = re.sub(r'"\n#~ msgstr "', "=", text)
|
||||
# comment lines
|
||||
text = re.sub(r'#.*\n', "", text)
|
||||
# converting msg pairs into "=" pairs
|
||||
text = re.sub(r'msgid "', "", text)
|
||||
text = re.sub(r'"\nmsgstr ""\n"', "=", text)
|
||||
text = re.sub(r'"\nmsgstr "', "=", text)
|
||||
# various line breaks and escape codes
|
||||
text = re.sub(r'"\n"', "", text)
|
||||
text = re.sub(r'"\n', "\n", text)
|
||||
text = re.sub(r'\\"', '"', text)
|
||||
text = re.sub(r'\\n', '@n', text)
|
||||
# remove header text
|
||||
text = re.sub(r'=Project-Id-Version:.*\n', "", text)
|
||||
# remove double-spaced lines
|
||||
text = re.sub(r'\n\n', '\n', text)
|
||||
return text
|
||||
|
||||
# Go through existing .po files and, if a .tr file for that language
|
||||
# *doesn't* exist, convert it and create it.
|
||||
# The .tr file that results will subsequently be reprocessed so
|
||||
# any "no longer used" strings will be preserved.
|
||||
# Note that "fuzzy" tags will be lost in this process.
|
||||
def process_po_files(folder, modname):
|
||||
for root, dirs, files in os.walk(os.path.join(folder, 'locale/')):
|
||||
for name in files:
|
||||
code_match = pattern_po_language_code.match(name)
|
||||
if code_match == None:
|
||||
continue
|
||||
language_code = code_match.group(1)
|
||||
tr_name = f'{modname}.{language_code}.tr'
|
||||
tr_file = os.path.join(root, tr_name)
|
||||
if os.path.exists(tr_file):
|
||||
if params["verbose"]:
|
||||
print(f"{tr_name} already exists, ignoring {name}")
|
||||
continue
|
||||
fname = os.path.join(root, name)
|
||||
with open(fname, "r", encoding='utf-8') as po_file:
|
||||
if params["verbose"]:
|
||||
print(f"Importing translations from {name}")
|
||||
text = process_po_file(po_file.read())
|
||||
with open(tr_file, "wt", encoding='utf-8') as tr_out:
|
||||
tr_out.write(text)
|
||||
|
||||
# from https://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python/600612#600612
|
||||
# Creates a directory if it doesn't exist, silently does
|
||||
# nothing if it already exists
|
||||
def mkdir_p(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as exc: # Python >2.5
|
||||
if exc.errno == errno.EEXIST and os.path.isdir(path):
|
||||
pass
|
||||
else: raise
|
||||
|
||||
# Converts the template dictionary to a text to be written as a file
|
||||
# dKeyStrings is a dictionary of localized string to source file sets
|
||||
# dOld is a dictionary of existing translations and comments from
|
||||
# the previous version of this text
|
||||
def strings_to_text(dkeyStrings, dOld, mod_name, header_comments):
|
||||
lOut = [f"# textdomain: {mod_name}"]
|
||||
if header_comments is not None:
|
||||
lOut.append(header_comments)
|
||||
|
||||
dGroupedBySource = {}
|
||||
|
||||
for key in dkeyStrings:
|
||||
sourceList = list(dkeyStrings[key])
|
||||
if params["sort"]:
|
||||
sourceList.sort()
|
||||
sourceString = "\n".join(sourceList)
|
||||
listForSource = dGroupedBySource.get(sourceString, [])
|
||||
listForSource.append(key)
|
||||
dGroupedBySource[sourceString] = listForSource
|
||||
|
||||
lSourceKeys = list(dGroupedBySource.keys())
|
||||
lSourceKeys.sort()
|
||||
for source in lSourceKeys:
|
||||
localizedStrings = dGroupedBySource[source]
|
||||
if params["sort"]:
|
||||
localizedStrings.sort()
|
||||
if params["print-source"]:
|
||||
if lOut[-1] != "":
|
||||
lOut.append("")
|
||||
lOut.append(source)
|
||||
for localizedString in localizedStrings:
|
||||
val = dOld.get(localizedString, {})
|
||||
translation = val.get("translation", "")
|
||||
comment = val.get("comment")
|
||||
if params["break-long-lines"] and len(localizedString) > doublespace_threshold and not lOut[-1] == "":
|
||||
lOut.append("")
|
||||
if comment != None and comment != "" and not comment.startswith("# textdomain:"):
|
||||
lOut.append(comment)
|
||||
lOut.append(f"{localizedString}={translation}")
|
||||
if params["break-long-lines"] and len(localizedString) > doublespace_threshold:
|
||||
lOut.append("")
|
||||
|
||||
|
||||
unusedExist = False
|
||||
if not params["truncate-unused"]:
|
||||
for key in dOld:
|
||||
if key not in dkeyStrings:
|
||||
val = dOld[key]
|
||||
translation = val.get("translation")
|
||||
comment = val.get("comment")
|
||||
# only keep an unused translation if there was translated
|
||||
# text or a comment associated with it
|
||||
if translation != None and (translation != "" or comment):
|
||||
if not unusedExist:
|
||||
unusedExist = True
|
||||
lOut.append("\n\n##### not used anymore #####\n")
|
||||
if params["break-long-lines"] and len(key) > doublespace_threshold and not lOut[-1] == "":
|
||||
lOut.append("")
|
||||
if comment != None:
|
||||
lOut.append(comment)
|
||||
lOut.append(f"{key}={translation}")
|
||||
if params["break-long-lines"] and len(key) > doublespace_threshold:
|
||||
lOut.append("")
|
||||
return "\n".join(lOut) + '\n'
|
||||
|
||||
# Writes a template.txt file
|
||||
# dkeyStrings is the dictionary returned by generate_template
|
||||
def write_template(templ_file, dkeyStrings, mod_name):
|
||||
# read existing template file to preserve comments
|
||||
existing_template = import_tr_file(templ_file)
|
||||
|
||||
text = strings_to_text(dkeyStrings, existing_template[0], mod_name, existing_template[2])
|
||||
mkdir_p(os.path.dirname(templ_file))
|
||||
with open(templ_file, "wt", encoding='utf-8') as template_file:
|
||||
template_file.write(text)
|
||||
|
||||
|
||||
# Gets all translatable strings from a lua file
|
||||
def read_lua_file_strings(lua_file):
|
||||
lOut = []
|
||||
text = open(lua_file).read()
|
||||
for s in pattern_lua.findall(text):
|
||||
s = re.sub(r'"\.\.\s+"', "", s)
|
||||
s = re.sub("@[^@=n]", "@@", s)
|
||||
s = s.replace("\n", "@n")
|
||||
s = s.replace("\\n", "@n")
|
||||
s = s.replace("=", "@=")
|
||||
lOut.append(s)
|
||||
with open(lua_file, encoding='utf-8') as text_file:
|
||||
text = text_file.read()
|
||||
#TODO remove comments here
|
||||
|
||||
text = re.sub(pattern_concat, "", text)
|
||||
|
||||
strings = []
|
||||
for s in pattern_lua_s.findall(text):
|
||||
strings.append(s[1])
|
||||
for s in pattern_lua_bracketed_s.findall(text):
|
||||
strings.append(s)
|
||||
for s in pattern_lua_fs.findall(text):
|
||||
strings.append(s[1])
|
||||
for s in pattern_lua_bracketed_fs.findall(text):
|
||||
strings.append(s)
|
||||
|
||||
for s in strings:
|
||||
s = re.sub(r'"\.\.\s+"', "", s)
|
||||
s = re.sub("@[^@=0-9]", "@@", s)
|
||||
s = s.replace('\\"', '"')
|
||||
s = s.replace("\\'", "'")
|
||||
s = s.replace("\n", "@n")
|
||||
s = s.replace("\\n", "@n")
|
||||
s = s.replace("=", "@=")
|
||||
lOut.append(s)
|
||||
return lOut
|
||||
|
||||
def inport_tr_file(tr_file):
|
||||
# Gets strings from an existing translation file
|
||||
# returns both a dictionary of translations
|
||||
# and the full original source text so that the new text
|
||||
# can be compared to it for changes.
|
||||
# Returns also header comments in the third return value.
|
||||
def import_tr_file(tr_file):
|
||||
dOut = {}
|
||||
text = None
|
||||
header_comment = None
|
||||
if os.path.exists(tr_file):
|
||||
for line in open(tr_file, "r").readlines():
|
||||
s = line.strip()
|
||||
if s == "" or s[0] == "#":
|
||||
continue
|
||||
match = pattern_tr.match(s)
|
||||
if match:
|
||||
dOut[match.group(1)] = match.group(2)
|
||||
return dOut
|
||||
with open(tr_file, "r", encoding='utf-8') as existing_file :
|
||||
# save the full text to allow for comparison
|
||||
# of the old version with the new output
|
||||
text = existing_file.read()
|
||||
existing_file.seek(0)
|
||||
# a running record of the current comment block
|
||||
# we're inside, to allow preceeding multi-line comments
|
||||
# to be retained for a translation line
|
||||
latest_comment_block = None
|
||||
for line in existing_file.readlines():
|
||||
line = line.rstrip('\n')
|
||||
if line.startswith("###"):
|
||||
if header_comment is None and not latest_comment_block is None:
|
||||
# Save header comments
|
||||
header_comment = latest_comment_block
|
||||
# Strip textdomain line
|
||||
tmp_h_c = ""
|
||||
for l in header_comment.split('\n'):
|
||||
if not l.startswith("# textdomain:"):
|
||||
tmp_h_c += l + '\n'
|
||||
header_comment = tmp_h_c
|
||||
|
||||
def generate_template(templ_file):
|
||||
lOut = []
|
||||
for root, dirs, files in os.walk('./'):
|
||||
# Reset comment block if we hit a header
|
||||
latest_comment_block = None
|
||||
continue
|
||||
elif line.startswith("#"):
|
||||
# Save the comment we're inside
|
||||
if not latest_comment_block:
|
||||
latest_comment_block = line
|
||||
else:
|
||||
latest_comment_block = latest_comment_block + "\n" + line
|
||||
continue
|
||||
match = pattern_tr.match(line)
|
||||
if match:
|
||||
# this line is a translated line
|
||||
outval = {}
|
||||
outval["translation"] = match.group(2)
|
||||
if latest_comment_block:
|
||||
# if there was a comment, record that.
|
||||
outval["comment"] = latest_comment_block
|
||||
latest_comment_block = None
|
||||
dOut[match.group(1)] = outval
|
||||
return (dOut, text, header_comment)
|
||||
|
||||
# Walks all lua files in the mod folder, collects translatable strings,
|
||||
# and writes it to a template.txt file
|
||||
# Returns a dictionary of localized strings to source file sets
|
||||
# that can be used with the strings_to_text function.
|
||||
def generate_template(folder, mod_name):
|
||||
dOut = {}
|
||||
for root, dirs, files in os.walk(folder):
|
||||
for name in files:
|
||||
if fnmatch.fnmatch(name, "*.lua"):
|
||||
fname = os.path.join(root, name)
|
||||
found = read_lua_file_strings(fname)
|
||||
print(fname, len(found))
|
||||
lOut.extend(found)
|
||||
lOut = list(set(lOut))
|
||||
lOut.sort()
|
||||
gen_template(templ_file, lOut)
|
||||
return lOut
|
||||
if params["verbose"]:
|
||||
print(f"{fname}: {str(len(found))} translatable strings")
|
||||
|
||||
def update_tr_file(lNew, mod_name, tr_file):
|
||||
lOut = ["# textdomain: %s\n" % mod_name]
|
||||
if os.path.exists(tr_file):
|
||||
shutil.copyfile(tr_file, tr_file+".old")
|
||||
dOld = inport_tr_file(tr_file)
|
||||
for key in lNew:
|
||||
val = dOld.get(key, "")
|
||||
lOut.append("%s=%s" % (key, val))
|
||||
lOut.append("##### not used anymore #####")
|
||||
for key in dOld:
|
||||
if key not in lNew:
|
||||
lOut.append("%s=%s" % (key, dOld[key]))
|
||||
open(tr_file, "w").write("\n".join(lOut))
|
||||
|
||||
data = generate_template("./locale/template.txt")
|
||||
update_tr_file(data, "ta4_jetpack", "./locale/ta4_jetpack.de.tr")
|
||||
print("Done.\n")
|
||||
for s in found:
|
||||
sources = dOut.get(s, set())
|
||||
sources.add(f"### {os.path.basename(fname)} ###")
|
||||
dOut[s] = sources
|
||||
|
||||
if len(dOut) == 0:
|
||||
return None
|
||||
templ_file = os.path.join(folder, "locale/template.txt")
|
||||
write_template(templ_file, dOut, mod_name)
|
||||
return dOut
|
||||
|
||||
# Updates an existing .tr file, copying the old one to a ".old" file
|
||||
# if any changes have happened
|
||||
# dNew is the data used to generate the template, it has all the
|
||||
# currently-existing localized strings
|
||||
def update_tr_file(dNew, mod_name, tr_file):
|
||||
if params["verbose"]:
|
||||
print(f"updating {tr_file}")
|
||||
|
||||
tr_import = import_tr_file(tr_file)
|
||||
dOld = tr_import[0]
|
||||
textOld = tr_import[1]
|
||||
|
||||
textNew = strings_to_text(dNew, dOld, mod_name, tr_import[2])
|
||||
|
||||
if textOld and textOld != textNew:
|
||||
print(f"{tr_file} has changed.")
|
||||
if not params["no-old-file"]:
|
||||
shutil.copyfile(tr_file, f"{tr_file}.old")
|
||||
|
||||
with open(tr_file, "w", encoding='utf-8') as new_tr_file:
|
||||
new_tr_file.write(textNew)
|
||||
|
||||
# Updates translation files for the mod in the given folder
|
||||
def update_mod(folder):
|
||||
modname = get_modname(folder)
|
||||
if modname is not None:
|
||||
process_po_files(folder, modname)
|
||||
print(f"Updating translations for {modname}")
|
||||
data = generate_template(folder, modname)
|
||||
if data == None:
|
||||
print(f"No translatable strings found in {modname}")
|
||||
else:
|
||||
for tr_file in get_existing_tr_files(folder):
|
||||
update_tr_file(data, modname, os.path.join(folder, "locale/", tr_file))
|
||||
else:
|
||||
print(f"\033[31mUnable to find modname in folder {folder}.\033[0m", file=_stderr)
|
||||
exit(1)
|
||||
|
||||
# Determines if the folder being pointed to is a mod or a mod pack
|
||||
# and then runs update_mod accordingly
|
||||
def update_folder(folder):
|
||||
is_modpack = os.path.exists(os.path.join(folder, "modpack.txt")) or os.path.exists(os.path.join(folder, "modpack.conf"))
|
||||
if is_modpack:
|
||||
subfolders = [f.path for f in os.scandir(folder) if f.is_dir() and not f.name.startswith('.')]
|
||||
for subfolder in subfolders:
|
||||
update_mod(subfolder)
|
||||
else:
|
||||
update_mod(folder)
|
||||
print("Done.")
|
||||
|
||||
def run_all_subfolders(folder):
|
||||
for modfolder in [f.path for f in os.scandir(folder) if f.is_dir() and not f.name.startswith('.')]:
|
||||
update_folder(modfolder)
|
||||
|
||||
|
||||
main()
|
||||
|
@ -320,6 +320,10 @@ end
|
||||
|
||||
minetest.after(WEAR_CYCLE, jetpack_wearout)
|
||||
|
||||
local function round(val)
|
||||
return math.floor((val * 10) + 0.5) / 10.0
|
||||
end
|
||||
|
||||
local function load_fuel(itemstack, user, pointed_thing)
|
||||
local pos = pointed_thing.under
|
||||
if pos then
|
||||
@ -340,11 +344,11 @@ local function load_fuel(itemstack, user, pointed_thing)
|
||||
newvalue = value - (amount - rest)
|
||||
else
|
||||
local amount = math.max(math.min(FUEL_UNIT, MAX_FUEL - value), 0)
|
||||
local taken = liquid.srv_take(nvm, "techage:hydrogen", amount)
|
||||
local taken = liquid.srv_take(nvm, "techage:hydrogen", math.floor(amount))
|
||||
newvalue = value + taken
|
||||
end
|
||||
set_fuel_value(name, newvalue)
|
||||
minetest.chat_send_player(name, S("[Jetpack]") .. ": " .. newvalue .. "/" .. MAX_FUEL)
|
||||
minetest.chat_send_player(name, S("[Jetpack]") .. ": " .. round(newvalue) .. "/" .. MAX_FUEL)
|
||||
end
|
||||
end
|
||||
return itemstack
|
||||
@ -417,7 +421,7 @@ minetest.register_tool("ta4_jetpack:controller_off", {
|
||||
stack_max = 1,
|
||||
})
|
||||
|
||||
armor:register_armor("ta4_jetpack:jetpack", {
|
||||
armor:register_armor("ta4_jetpack:jetpack_material", {
|
||||
description = S("TA4 Jetpack"),
|
||||
texture = "ta4_jetpack_jetpack.png",
|
||||
inventory_image = "ta4_jetpack_jetpack_inv.png",
|
||||
@ -441,6 +445,8 @@ armor:register_armor("ta4_jetpack:jetpack", {
|
||||
end
|
||||
})
|
||||
|
||||
minetest.register_alias("ta4_jetpack:jetpack", "ta4_jetpack:jetpack_material")
|
||||
|
||||
-- For some reason, prevent to move/put/take a running controller
|
||||
minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info)
|
||||
if inventory_info.stack and inventory_info.stack:get_name() == "ta4_jetpack:controller_on" then
|
||||
|
@ -1,15 +1,13 @@
|
||||
# textdomain: ta4_jetpack
|
||||
|
||||
Jetpack Training Mat=Jetpack Trainingsmatte
|
||||
TA4 Jetpack=TA4 Jetpac
|
||||
TA4 Jetpack Controller Off=TA4 Jetpack Controller Aus
|
||||
TA4 Jetpack Controller On=TA4 Jetpack Controller An
|
||||
Use the controller (left click) to fill the tank with hydrogen=Benutze den Controller (linksklick) um den Tank mit Wasserstoff zu füllen
|
||||
You are too heavy: Check your bags!=Du bist zu schwer: Prüfe deine Rucksäcke!
|
||||
You are too heavy: Check your crafting menu!=Du bist zu schwer: Prüfe dein Crafting Menü!
|
||||
You are too heavy: Check your inventory!=Du bist zu schwer: Prüfe dein Inventar!
|
||||
You may not transport @1 with a jetpack!=Du darfst @1 nicht mit dem Jetpack transportieren!
|
||||
[Jetpack]=[Jetpack]
|
||||
[Jetpack] You don't have your jetpack on your back!=[Jetpack] Du hast dein Jetpack nicht auf dem Rücken!
|
||||
[Jetpack]=[Jetpack]
|
||||
[Jetpack] Your tank is empty!=[Jetpack] Dein Tank ist leer!
|
||||
##### not used anymore #####
|
||||
Use the controller (left click) to fill the tank with hydrogen=Benutze den Controller (linksklick) um den Tank mit Wasserstoff zu füllen
|
||||
TA4 Jetpack Controller On=TA4 Jetpack Controller An
|
||||
TA4 Jetpack Controller Off=TA4 Jetpack Controller Aus
|
||||
TA4 Jetpack=TA4 Jetpac
|
||||
Jetpack Training Mat=Jetpack Trainingsmatte
|
||||
|
@ -1,13 +1,13 @@
|
||||
Jetpack Training Mat=
|
||||
TA4 Jetpack=
|
||||
TA4 Jetpack Controller Off=
|
||||
TA4 Jetpack Controller On=
|
||||
Use the controller (left click) to fill the tank with hydrogen=
|
||||
# textdomain: ta4_jetpack
|
||||
You are too heavy: Check your bags!=
|
||||
You are too heavy: Check your crafting menu!=
|
||||
You are too heavy: Check your inventory!=
|
||||
You may not transport @1 with a jetpack!=
|
||||
[Jetpack]=
|
||||
[Jetpack] You don't have your jetpack on your back!=
|
||||
[Jetpack]=
|
||||
[Jetpack] Your tank is empty!=
|
||||
##### not used anymore #####
|
||||
Use the controller (left click) to fill the tank with hydrogen=
|
||||
TA4 Jetpack Controller On=
|
||||
TA4 Jetpack Controller Off=
|
||||
TA4 Jetpack=
|
||||
Jetpack Training Mat=
|
||||
|
@ -9,7 +9,7 @@ Das Jetpack ist inspiriert vom Jetpack von spirit689 (https://github.com/spirit6
|
||||
|
||||
- TA4 Jetpack, Jetpack Controller und Trainingsmatte herstellen (craften)
|
||||
- Verwende die '3d_armor' Erweiterung des Spielermenüs, um das Jetpack auf deinem Rücken zu schnallen
|
||||
- Du kannst das Jetpack auftanken, indem du mit dem Controller und mit der linken Maustaste auf einen Wasserstofftanks klickst
|
||||
- Du kannst das Jetpack auftanken, indem du mit dem Controller und mit der linken Maustaste auf einen TA3/TA4 Tank mit Wasserstoff klickst
|
||||
- Schalte den Controller mit der rechten Maustaste ein und überprüfe den Füllstand des Kraftstofftanks (der kleine farbige Balken unter dem Reglersymbol).
|
||||
- Verwende die Leertaste, um das Jetpack zu aktivieren und die WASD-Tasten, um die Richtung zu steuern
|
||||
- Vor dem ersten Flug solltest du einige Trainingsstarts und Landungen auf der Trainingsmatte durchführen
|
||||
|
@ -10,7 +10,7 @@ and by the historical game Lunar Lander.
|
||||
|
||||
- Craft TA4 Jetpack, Jetpack Controller and Training Mat
|
||||
- Use the armor extension (3d_armor) of the player menu to strap the Jetpack on your back
|
||||
- You can refuel the jetpack by left-clicking with the controller on a hydrogen tank
|
||||
- You can refuel the jetpack by left-clicking with the controller on a TA3/TA4 tank previously charged with hydrogen
|
||||
- Turn the controller on by right-click and check the fuel tank level (the small colored bar below the controller icon)
|
||||
- Use the space bar to activate the Jetpack and the WASD keys to control the direction
|
||||
- Before your first flight you should do some training starts and landings on the Training Mat
|
||||
|
43
techage/.test/testblock.lua
Normal file
43
techage/.test/testblock.lua
Normal file
@ -0,0 +1,43 @@
|
||||
local M = minetest.get_meta
|
||||
|
||||
minetest.register_node("techage:testblock", {
|
||||
description = "Testblock",
|
||||
tiles = {
|
||||
"techage_top_ta4.png",
|
||||
"techage_filling_ta4.png^techage_frame_ta4.png",
|
||||
},
|
||||
paramtype2 = "facedir",
|
||||
groups = {cracky=2, crumbly=2, choppy=2},
|
||||
is_ground_content = false,
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
nvm.test_val = 1
|
||||
M(pos):set_int("test_val", 1)
|
||||
M(pos):set_string("infotext", "Value = " .. 1)
|
||||
end,
|
||||
})
|
||||
|
||||
minetest.register_lbm({
|
||||
label = "Update testblock",
|
||||
name = "techage:update_testblock",
|
||||
|
||||
nodenames = {
|
||||
"techage:testblock",
|
||||
},
|
||||
|
||||
run_at_every_load = true,
|
||||
|
||||
action = function(pos, node)
|
||||
local nvm = techage.get_nvm(pos)
|
||||
if M(pos):get_int("test_val") == nvm.test_val then
|
||||
nvm.test_val = nvm.test_val + 1
|
||||
M(pos):set_int("test_val", nvm.test_val)
|
||||
M(pos):set_string("infotext", "Value = " .. nvm.test_val)
|
||||
else
|
||||
minetest.log("error", "[techage] Memory error at " .. minetest.pos_to_string(pos))
|
||||
M(pos):set_string("infotext", "Error")
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
@ -336,7 +336,7 @@ local function entity_to_node(pos, obj)
|
||||
meta:set_string("ta_move_block", minetest.serialize({name=name, param2=param2}))
|
||||
return
|
||||
end
|
||||
minetest.add_item(pos, ItemStack(name))
|
||||
--minetest.add_item(pos, ItemStack(name))
|
||||
elseif ndef1 then
|
||||
minetest.add_item(pos, ItemStack(name))
|
||||
end
|
||||
|
@ -97,7 +97,9 @@ minetest.register_globalstep(function(dtime)
|
||||
SystemTime = SystemTime + dtime
|
||||
local key = pop()
|
||||
if key and NvmStore[key] then
|
||||
--debug(key, NvmStore[key])
|
||||
-- minetest.log("warning",
|
||||
-- string.format("[TA Storage] SystemTime = %.3f, #JobQueue = %d, in_use = %s",
|
||||
-- SystemTime, last - first, NvmStore[key].in_use))
|
||||
local t = minetest.get_us_time()
|
||||
if NvmStore[key].in_use then
|
||||
NvmStore[key].in_use = nil
|
||||
|
@ -20,6 +20,7 @@ local M = minetest.get_meta
|
||||
-------------------------------------------------------------------
|
||||
local MN = minetest.get_current_modname()
|
||||
local WP = minetest.get_worldpath()
|
||||
local use_marshal = minetest.settings:get_bool('techage_use_marshal', false)
|
||||
local MAR_MAGIC = 0x8e
|
||||
|
||||
if not techage.IE then
|
||||
@ -55,7 +56,6 @@ local function set_block(key, data)
|
||||
set:bind(1, key)
|
||||
set:bind_blob(2, data)
|
||||
set:step()
|
||||
return true
|
||||
end
|
||||
|
||||
local function get_block(key)
|
||||
@ -72,10 +72,11 @@ end
|
||||
local api = {}
|
||||
|
||||
function api.store_mapblock_data(key, mapblock_data)
|
||||
-- deactivated due to weird server crashes without error logs
|
||||
--local s = marshal.encode(mapblock_data)
|
||||
local s = minetest.serialize(mapblock_data)
|
||||
return set_block(key, s)
|
||||
if use_marshal then
|
||||
set_block(key, marshal.encode(mapblock_data))
|
||||
else
|
||||
set_block(key, minetest.serialize(mapblock_data))
|
||||
end
|
||||
end
|
||||
|
||||
function api.get_mapblock_data(key)
|
||||
|
@ -1800,7 +1800,7 @@ techage.manual_DE.aText = {
|
||||
"Ein Teilchenbeschleuniger besteht aus einem \"Ring\" aus Röhren und Magneten sowie dem Detektor mit Kühlanlage. \n"..
|
||||
"\n"..
|
||||
" - Der Detektor ist das Herz der Anlage. Hier finden die wissenschaftlichen Experimente statt. Der Detektor ist 3x3x7 Blöcke groß.\n"..
|
||||
" - Die TA4 Collider Detector Magnete (22 Stück) müssen über jeweils 5 Blöcken der TA4 Vakuumröhre miteinander verbunden werden. Jeder Magnet benötigt zusätzlich Strom und einen Gasanschluss für die Kühlung. Das ganze bildet (wie rechts im Plan abgebildet) ein Quadrat mit einer Kantenlänge von 37 Metern.\n"..
|
||||
" - 22 TA4 Collider Magnete (nicht die TA4 Collider Detector Magnete!) müssen über jeweils 5 Blöcken der TA4 Vakuumröhre miteinander verbunden werden. Jeder Magnet benötigt zusätzlich Strom und einen Gasanschluss für die Kühlung. Das ganze bildet (wie rechts im Plan abgebildet) ein Quadrat mit einer Kantenlänge von 37 Metern.\n"..
|
||||
" - Zusätzlich wird eine Kühlung benötigt\\, welche zusätzlich beim Detektor aufgebaut werden muss. Für die Kühlung wird Isobutan benötigt.\n"..
|
||||
" - Die Anlage benötigt einiges an Strom. Daher ist eine eigene Stromversorgung sinnvoll.\n"..
|
||||
"\n"..
|
||||
|
@ -1796,7 +1796,7 @@ techage.manual_EN.aText = {
|
||||
"A collider consists of a \"ring\" made of tubes and magnets as well as a detector with a cooling system.\n"..
|
||||
"\n"..
|
||||
" - The detector is the heart of the system. This is where the scientific experiments take place. The detector is 3x3x7 blocks in size.\n"..
|
||||
" - The TA4 Collider Detector magnets (22 pieces) must be connected to each other via 5 blocks of the TA4 vacuum tube. Each magnet also requires electricity and a gas connection for cooling. The whole thing forms (as shown in the plan on the right) a square with an edge length of 37 meters.\n"..
|
||||
" - 22 TA4 Collider Magnets (not the TA4 Collider Detector Magnets!) must be connected to each other via 5 blocks of the TA4 vacuum tube. Each magnet also requires electricity and a gas connection for cooling. The whole thing forms (as shown in the plan on the right) a square with an edge length of 37 meters.\n"..
|
||||
" - In addition\\, cooling is required\\, which must also be installed at the detector. Isobutane is required for cooling.\n"..
|
||||
" - The system requires quite a bit of electricity. Therefore\\, it makes sense to have your own power supply.\n"..
|
||||
"\n"..
|
||||
|
@ -56,6 +56,7 @@ techage.basalt_stone_enabled = minetest.settings:get_bool("techage_basalt_stone_
|
||||
techage.ore_rarity = tonumber(minetest.settings:get("techage_ore_rarity")) or 1
|
||||
techage.modified_recipes_enabled = minetest.settings:get_bool("techage_modified_recipes_enabled") ~= false
|
||||
techage.collider_min_depth = tonumber(minetest.settings:get("techage_collider_min_depth")) or -28
|
||||
techage.recipe_checker_enabled = minetest.settings:get_bool("techage_recipe_checker_enabled") ~= false
|
||||
|
||||
-- allow to load marshal and sqlite3
|
||||
techage.IE = minetest.request_insecure_environment()
|
||||
@ -310,8 +311,11 @@ dofile(MP.."/move_controller/soundblock.lua")
|
||||
|
||||
|
||||
-- Test
|
||||
dofile(MP.."/recipe_checker.lua")
|
||||
if techage.recipe_checker_enabled then
|
||||
dofile(MP.."/recipe_checker.lua")
|
||||
end
|
||||
dofile(MP.."/.test/sink.lua")
|
||||
dofile(MP.."/.test/testblock.lua")
|
||||
|
||||
-- Solar
|
||||
dofile(MP.."/solar/minicell.lua")
|
||||
|
@ -692,7 +692,7 @@ Pro Spieler kann nur ein Teilchenbeschleuniger betrieben werden. Es macht also k
|
||||
Ein Teilchenbeschleuniger besteht aus einem "Ring" aus Röhren und Magneten sowie dem Detektor mit Kühlanlage.
|
||||
|
||||
- Der Detektor ist das Herz der Anlage. Hier finden die wissenschaftlichen Experimente statt. Der Detektor ist 3x3x7 Blöcke groß.
|
||||
- Die TA4 Collider Detector Magnete (22 Stück) müssen über jeweils 5 Blöcken der TA4 Vakuumröhre miteinander verbunden werden. Jeder Magnet benötigt zusätzlich Strom und einen Gasanschluss für die Kühlung. Das ganze bildet (wie rechts im Plan abgebildet) ein Quadrat mit einer Kantenlänge von 37 Metern.
|
||||
- 22 TA4 Collider Magnete (nicht die TA4 Collider Detector Magnete!) müssen über jeweils 5 Blöcken der TA4 Vakuumröhre miteinander verbunden werden. Jeder Magnet benötigt zusätzlich Strom und einen Gasanschluss für die Kühlung. Das ganze bildet (wie rechts im Plan abgebildet) ein Quadrat mit einer Kantenlänge von 37 Metern.
|
||||
- Zusätzlich wird eine Kühlung benötigt, welche zusätzlich beim Detektor aufgebaut werden muss. Für die Kühlung wird Isobutan benötigt.
|
||||
- Die Anlage benötigt einiges an Strom. Daher ist eine eigene Stromversorgung sinnvoll.
|
||||
|
||||
|
@ -684,7 +684,7 @@ Only one collider can be operated per player. So it makes no sense to set up two
|
||||
A collider consists of a "ring" made of tubes and magnets as well as a detector with a cooling system.
|
||||
|
||||
- The detector is the heart of the system. This is where the scientific experiments take place. The detector is 3x3x7 blocks in size.
|
||||
- The TA4 Collider Detector magnets (22 pieces) must be connected to each other via 5 blocks of the TA4 vacuum tube. Each magnet also requires electricity and a gas connection for cooling. The whole thing forms (as shown in the plan on the right) a square with an edge length of 37 meters.
|
||||
- 22 TA4 Collider Magnets (not the TA4 Collider Detector Magnets!) must be connected to each other via 5 blocks of the TA4 vacuum tube. Each magnet also requires electricity and a gas connection for cooling. The whole thing forms (as shown in the plan on the right) a square with an edge length of 37 meters.
|
||||
- In addition, cooling is required, which must also be installed at the detector. Isobutane is required for cooling.
|
||||
- The system requires quite a bit of electricity. Therefore, it makes sense to have your own power supply.
|
||||
|
||||
|
@ -274,9 +274,9 @@ techage.register_node({"techage:ta4_movecontroller"}, {
|
||||
end
|
||||
elseif move_xyz and topic == 18 then -- move xyz
|
||||
local line = {
|
||||
x = techage.in_range(techage.beduino_signed_var(payload[1]), -10, 10),
|
||||
y = techage.in_range(techage.beduino_signed_var(payload[2]), -10, 10),
|
||||
z = techage.in_range(techage.beduino_signed_var(payload[3]), -10, 10),
|
||||
x = techage.in_range(techage.beduino_signed_var(payload[1]), -100, 100),
|
||||
y = techage.in_range(techage.beduino_signed_var(payload[2]), -100, 100),
|
||||
z = techage.in_range(techage.beduino_signed_var(payload[3]), -100, 100),
|
||||
}
|
||||
nvm.running = true
|
||||
nvm.controller_mode = true
|
||||
|
@ -200,6 +200,7 @@ minetest.register_node("techage:power_pole2", {
|
||||
if not Cable:after_place_tube(pos, placer, pointed_thing) then
|
||||
minetest.chat_send_player(placer:get_player_name(), "invalid pole position ")
|
||||
minetest.remove_node(pos)
|
||||
Cable:after_dig_node(pos)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
|
@ -3,6 +3,7 @@
|
||||
--
|
||||
local Recipes = {}
|
||||
|
||||
|
||||
local function recipe_key(items)
|
||||
local tbl = {}
|
||||
for idx = 1,9 do
|
||||
@ -34,3 +35,5 @@ minetest.after(1, function()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
print ("[techage] Recipe checker loaded")
|
||||
|
@ -37,4 +37,7 @@ techage_collider_min_depth (Min. depth to build a TA4 Collider) int -30
|
||||
|
||||
# Average waiting time in minutes to get one Collider expoint.
|
||||
# Default value is 60, which means one point per hour.
|
||||
techage_expoint_rate_in_min (average waiting time for one expoint) int 60
|
||||
techage_expoint_rate_in_min (average waiting time for one expoint) int 60
|
||||
|
||||
# For testing purpuses only
|
||||
techage_recipe_checker_enabled (test techage recipes) bool false
|
@ -1,2 +0,0 @@
|
||||
default
|
||||
|
@ -1,2 +0,0 @@
|
||||
Simple stairways and bridges for your machines.
|
||||
|
@ -1,2 +1,4 @@
|
||||
name=techpack_stairway
|
||||
|
||||
title=Techpack stairway
|
||||
description=Simple stairways and bridges for your machines.
|
||||
depends=default
|
||||
|
@ -7,17 +7,17 @@ Bag @1=背包@1
|
||||
Small Bag=小背包
|
||||
Medium Bag=中背包
|
||||
Large Bag=大背包
|
||||
All Items=
|
||||
Misc. Items=
|
||||
Plant Life=
|
||||
Building Materials=
|
||||
Tools=
|
||||
Minerals and Metals=
|
||||
Environment and Worldgen=
|
||||
Lighting=
|
||||
All Items=所有物品
|
||||
Misc. Items=杂项
|
||||
Plant Life=植物
|
||||
Building Materials=建材
|
||||
Tools=工具
|
||||
Minerals and Metals=矿物与金属
|
||||
Environment and Worldgen=自然环境
|
||||
Lighting=光源
|
||||
and = 和
|
||||
Scroll categories left=
|
||||
Scroll categories right=
|
||||
Scroll categories left=向左滚动分类栏
|
||||
Scroll categories right=向右滚动分类栏
|
||||
Search=搜索
|
||||
Reset search and display everything=重置搜索并显示所有物品
|
||||
First page=第一页
|
||||
@ -32,7 +32,7 @@ Page=页面
|
||||
@1 of @2=第@1页,共@2页
|
||||
Filter=过滤器
|
||||
Can use the creative inventory=可以使用创造背包
|
||||
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
|
||||
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=如果轻量模式被全局配置,强迫Unified Inventory以完全模式展现。
|
||||
Crafting Grid=合成表
|
||||
Crafting Guide=合成指南
|
||||
Set home position=设置家的位置
|
||||
@ -45,7 +45,7 @@ You don't have the settime privilege!=你没有“settime”权限!
|
||||
Set time to night=设置时间到晚上
|
||||
Time of day set to 9pm=时间设置到晚上9点
|
||||
Clear inventory=清空背包
|
||||
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
|
||||
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=此按钮已在非创造模式中禁用以防止意外的背包清空。@n请使用垃圾桶栏。
|
||||
Inventory cleared!=清空背包
|
||||
Trash:=丢弃:
|
||||
Refill:=填满:
|
||||
@ -57,13 +57,13 @@ No recipes=没有配方
|
||||
No usages=没有用法
|
||||
Result=结果
|
||||
Ingredient=原料
|
||||
Show next recipe=
|
||||
Show next usage=
|
||||
Show previous recipe=
|
||||
Show previous usage=
|
||||
@1 (@2)=
|
||||
Show next recipe=显示下一个配方
|
||||
Show next usage=显示下一个用法
|
||||
Show previous recipe=显示前一个配方
|
||||
Show previous usage=显示前一个用法
|
||||
@1 (@2)=@1 (@2)
|
||||
Give me:=给予:
|
||||
This recipe is too@@large to be displayed.=
|
||||
This recipe is too@@large to be displayed.=该配方太@@大,不能显示。
|
||||
To craft grid:=填充物品到合成表
|
||||
All=全部
|
||||
Crafting=合成
|
||||
@ -76,10 +76,10 @@ Waypoints=航路点
|
||||
Select Waypoint #@1=查询航路点 #@1
|
||||
Waypoint @1=航路点 @1
|
||||
Set waypoint to current location=将航路点设置到当前位置
|
||||
Hide waypoint=
|
||||
Show waypoint=
|
||||
Hide coordinates=
|
||||
Show coordinates=
|
||||
Hide waypoint=隐藏航路点
|
||||
Show waypoint=显示航路点
|
||||
Hide coordinates=隐藏坐标
|
||||
Show coordinates=显示坐标
|
||||
Change color of waypoint display=改变航路点显示的颜色
|
||||
Edit waypoint name=编辑航路点名称
|
||||
Waypoint active=航路点已激活
|
||||
|
@ -7,17 +7,17 @@ Bag @1=揹包@1
|
||||
Small Bag=小揹包
|
||||
Medium Bag=中揹包
|
||||
Large Bag=大揹包
|
||||
All Items=
|
||||
Misc. Items=
|
||||
Plant Life=
|
||||
Building Materials=
|
||||
Tools=
|
||||
Minerals and Metals=
|
||||
Environment and Worldgen=
|
||||
Lighting=
|
||||
All Items=所有物品
|
||||
Misc. Items=雜項
|
||||
Plant Life=植物
|
||||
Building Materials=建材
|
||||
Tools=工具
|
||||
Minerals and Metals=礦物與金屬
|
||||
Environment and Worldgen=自然環境
|
||||
Lighting=光源
|
||||
and = 和
|
||||
Scroll categories left=
|
||||
Scroll categories right=
|
||||
Scroll categories left=向左滾動分類欄
|
||||
Scroll categories right=向右滾動分類欄
|
||||
Search=搜索
|
||||
Reset search and display everything=重置搜索並顯示所有物品
|
||||
First page=第一頁
|
||||
@ -32,7 +32,7 @@ Page=頁面
|
||||
@1 of @2=第@1頁,共@2頁
|
||||
Filter=過濾器
|
||||
Can use the creative inventory=可以使用創造揹包
|
||||
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=
|
||||
Forces Unified Inventory to be displayed in Full mode if Lite mode is configured globally=如果輕量模式被全局配置,強迫Unified Inventory以完全模式展現。
|
||||
Crafting Grid=合成表
|
||||
Crafting Guide=合成指南
|
||||
Set home position=設置家的位置
|
||||
@ -45,7 +45,7 @@ You don't have the settime privilege!=你沒有“settime”權限!
|
||||
Set time to night=設置時間到晚上
|
||||
Time of day set to 9pm=時間設置到晚上9點
|
||||
Clear inventory=清空揹包
|
||||
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=
|
||||
This button has been disabled outside of creative mode to prevent accidental inventory trashing.@nUse the trash slot instead.=此按鈕已在非創造模式中禁用以防止意外的背包清空。@n請使用垃圾桶欄。
|
||||
Inventory cleared!=清空揹包
|
||||
Trash:=丟棄:
|
||||
Refill:=填滿:
|
||||
@ -57,13 +57,13 @@ No recipes=沒有配方
|
||||
No usages=沒有用法
|
||||
Result=結果
|
||||
Ingredient=原料
|
||||
Show next recipe=
|
||||
Show next usage=
|
||||
Show previous recipe=
|
||||
Show previous usage=
|
||||
@1 (@2)=
|
||||
Show next recipe=顯示下一個配方
|
||||
Show next usage=顯示下一個用法
|
||||
Show previous recipe=顯示上一個配方
|
||||
Show previous usage=顯示上一個用法
|
||||
@1 (@2)=@1 (@2)
|
||||
Give me:=給予:
|
||||
This recipe is too@@large to be displayed.=
|
||||
This recipe is too@@large to be displayed.=該配方太@@大,不能顯示。
|
||||
To craft grid:=填充物品到合成表
|
||||
All=全部
|
||||
Crafting=合成
|
||||
@ -76,10 +76,10 @@ Waypoints=航路點
|
||||
Select Waypoint #@1=查詢航路點 #@1
|
||||
Waypoint @1=航路點 @1
|
||||
Set waypoint to current location=將航路點設置到當前位置
|
||||
Hide waypoint=
|
||||
Show waypoint=
|
||||
Hide coordinates=
|
||||
Show coordinates=
|
||||
Hide waypoint=隱藏航路點
|
||||
Show waypoint=顯示航路點
|
||||
Hide coordinates=隱藏坐標
|
||||
Show coordinates=顯示坐標
|
||||
Change color of waypoint display=改變航路點顯示的顏色
|
||||
Edit waypoint name=編輯航路點名稱
|
||||
Waypoint active=航路點已激活
|
||||
|
Loading…
Reference in New Issue
Block a user