Compare commits
10 Commits
5eec978cdc
...
9b390b836f
Author | SHA1 | Date | |
---|---|---|---|
|
9b390b836f | ||
|
8e03a1c6cd | ||
|
ba1d429d81 | ||
|
7aca5e49b5 | ||
|
7aa8ef5c94 | ||
|
d8b7ac83cc | ||
|
4b931bbe48 | ||
|
1a063b3fb1 | ||
|
178309f392 | ||
|
44844720aa |
78
README.md
Normal file
@ -0,0 +1,78 @@
|
||||
![](./screenshot.jpg)
|
||||
|
||||
This mod makes soil and soil-like nodes capable of holding temporary "footprint" impressions, and if they're walked on repeatedly turning into hard-packed trails.
|
||||
|
||||
It also allows players to flatten plants by walking on them.
|
||||
|
||||
It includes definitions for footprint-capable nodes in the "default" mod, and has an API for allowing nodes in other mods to use the same system.
|
||||
|
||||
## API
|
||||
|
||||
New trampled nodes can be registered with this API:
|
||||
|
||||
```
|
||||
footprints.register_trample_node(trampleable_node_name, trample_def)
|
||||
|
||||
trample_def:
|
||||
{
|
||||
trampled_node_name = , -- If this is not defined it defaults to the
|
||||
-- trampleable node name with "_trampled" appended.
|
||||
trampled_node_def_override = {}, -- If trampled_node_name doesn't exist a new
|
||||
-- node will be registered based on the definition of
|
||||
-- trampleable_node_name. Any properties in this table
|
||||
-- will be used to override properties. Ignored if
|
||||
-- trampled_node_name is a node that already exists.
|
||||
probability = 1, -- chance that stepping on this node will cause it to turn
|
||||
-- into the trampled version (range is 0.0 to 1.0)
|
||||
trample_count = 1, -- The number of times this node needs to be stepped on
|
||||
-- (and pass the probability check) to transition to
|
||||
-- the trampled state
|
||||
randomize_trampled_param2 = nil, -- if true, sets param2 of trampled node to math.random(0,3)
|
||||
-- This is used for trampled wheat, for example, to randomize the thatch's
|
||||
-- direction.
|
||||
erodes = true, -- sets the trampled node to erode back into the non-trampled
|
||||
-- version over time, if erosion is enabled in this mod's settings.
|
||||
-- Ignored if trampled_node_name is a node that already
|
||||
-- exists, since that may already have an erosion target established.
|
||||
add_footprint_overlay = true, -- Applies the footprint texture over the +Y tile of the
|
||||
-- trampleable node. ignored if trampled_node_name is a node that already exists
|
||||
footprint_overlay_texture = "footprints_footprint.png",
|
||||
footprint_opacity = 64, -- defaults to 64 (0 is transparent, 255 is fully opaque)
|
||||
hard_pack_node_name = nil, -- If the trampled node is walked on again this is the
|
||||
-- node that it can get further packed down into. ignored if
|
||||
-- trampled_node_name is a node that already exists, since
|
||||
-- it's expected this has already been established
|
||||
hard_pack_probability = 0.9, -- The probability that walking on a trampled node
|
||||
-- will turn it into the hard-packed node (0.0 to 1.0).
|
||||
-- ignored if trampled_node_name is a node that already exists
|
||||
hard_pack_count = 10, -- The number of times the trampled node needs to be stepped on
|
||||
-- (and pass the probability check) to turn to the hard packed state
|
||||
}
|
||||
```
|
||||
|
||||
Note that all of the parameters in trample_def have default values, so if you want you can just pass in nil and the footprints mod will create a footstep-marked version of the node and set it all up for you with no further information needed. "footprints.register_trample_node("modname:dirt")" will work.
|
||||
|
||||
### Eroding hardpack back to soil over time
|
||||
|
||||
If you've defined a hard_pack_node and want to have it able to erode back to base soil, you can use this callback to manually add it to the erosion system:
|
||||
|
||||
```
|
||||
footprints.register_erosion(starting_node_name, restored_node_name)
|
||||
```
|
||||
Note that the source_node should be in group footprints_erodes or an error will be thrown.
|
||||
|
||||
### Using a hoe to convert hardpack back to soil
|
||||
|
||||
If you've got the `farming` mod installed you can allow hardpack nodes to be restored back to soil using a hoe with the following function:
|
||||
|
||||
```
|
||||
footprints.register_hoe_converts(starting_node_name, restored_node_name)
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
Licenses: Source code MIT. Textures CC BY-SA (3.0)
|
||||
|
||||
- This mod was developed by paramat from 'desire path' mod by Casimir: https://forum.minetest.net/viewtopic.php?id=3390
|
||||
- Trail 0.3.1 by paramat: https://forum.minetest.net/viewtopic.php?f=11&t=6773
|
||||
- Version 0.4 for Minetest 0.5 was developed by FaceDeer and renamed "footprints"
|
35
README.txt
@ -1,35 +0,0 @@
|
||||
Licenses: Source code MIT. Textures CC BY-SA (3.0)
|
||||
|
||||
This mod was developed by paramat from 'desire path' mod by Casimir
|
||||
https://forum.minetest.net/viewtopic.php?id=3390
|
||||
Trail 0.3.1 by paramat
|
||||
Version 0.4 for Minetest 0.5 was developed by FaceDeer
|
||||
|
||||
New trampled nodes can be registered with this API:
|
||||
|
||||
trail.register_trample_node(trampleable_node_name, trample_def)
|
||||
|
||||
trample_def:
|
||||
{
|
||||
trampled_node_name = , -- If this is not defined it defaults to the trampleable node name with "_trampled" appended.
|
||||
trampled_node_def_override = {}, -- If trampled_node_name doesn't exist a new node will be registered based on the definition of trampleable_node_name. Any properties in this table will be used to override properties ignored if trampled_node_name is a node that already exists.
|
||||
probability = 1, -- chance that stepping on this node will cause it to turn into the trampled version (0.0 to 1.0)
|
||||
trample_count = 1, -- The number of times this node needs to be stepped on (and pass the probability check) to transition to the trampled state
|
||||
randomize_trampled_param2 = nil, -- if true, sets param2 of trampled node to math.random(0,3)
|
||||
erodes = true, -- sets the trampled node up to erode back into the non-trampled verison. ignored if trampled_node_name is a node that already exists, since that may already have an erosion target established
|
||||
add_footprint_overlay = true, -- Applies the footprint texture over the +Y tile of the trampleable node. ignored if trampled_node_name is a node that already exists
|
||||
footprint_overlay_texture = "trail_footprint.png",
|
||||
footprint_opacity = 64, -- defaults to 64 (0 is transparent, 255 is fully opaque)
|
||||
hard_pack_node_name = nil, -- If the trampled node is walked on again this is the node that it can get trampled into further. ignored if trampled_node_name is a node that already exists, since it's expected this has already been established
|
||||
hard_pack_probability = 0.1, -- The probability that walking on a trampled node will turn it into the hard-packed node (0.0 to 1.0). ignored if trampled_node_name is a node that already exists
|
||||
hard_pack_count = 1, -- The number of times the trampled node needs to be stepped on (and pass the probability check) to turn to the hard packed state
|
||||
}
|
||||
|
||||
Note that all of the parameters in trample_def have default values, so if you want you can just pass in nil and the trail mod will create a footstep-marked version of the node and set it all up for you with no further information needed. "trail.register_trample_node("modname:dirt")" will work.
|
||||
|
||||
|
||||
If you've defined a hard_pack_node and want to have it able to erode back to base soil, you can use this callback to manually add it to the erosion system:
|
||||
|
||||
trail.register_erosion(source_node_name, destination_node_name)
|
||||
|
||||
Note that the source_node should be in group trail_erodes or an error will be thrown.
|
448
i18n.py
Normal file
@ -0,0 +1,448 @@
|
||||
#!/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, 2020 FaceDeer, 2020 Louis Royer
|
||||
# LGPLv2.1+
|
||||
#
|
||||
# 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, errno
|
||||
from sys import argv as _argv
|
||||
from sys import stderr as _stderr
|
||||
|
||||
# Running params
|
||||
params = {"recursive": False,
|
||||
"help": False,
|
||||
"mods": False,
|
||||
"verbose": False,
|
||||
"folders": [],
|
||||
"no-old-file": False
|
||||
}
|
||||
# Available CLI options
|
||||
options = {"recursive": ['--recursive', '-r'],
|
||||
"help": ['--help', '-h'],
|
||||
"mods": ['--installed-mods'],
|
||||
"verbose": ['--verbose', '-v'],
|
||||
"no-old-file": ['--no-old-file']
|
||||
}
|
||||
|
||||
# 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 = 60
|
||||
|
||||
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["verbose"])}
|
||||
add output information
|
||||
''')
|
||||
|
||||
|
||||
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.abspath('~/.minetest/mods/')}")
|
||||
run_all_subfolders("~/.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. 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:
|
||||
pass
|
||||
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 = 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}\n"]
|
||||
if header_comments is not None:
|
||||
lOut.append(header_comments)
|
||||
|
||||
dGroupedBySource = {}
|
||||
|
||||
for key in dkeyStrings:
|
||||
sourceList = list(dkeyStrings[key])
|
||||
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]
|
||||
localizedStrings.sort()
|
||||
lOut.append("")
|
||||
lOut.append(source)
|
||||
lOut.append("")
|
||||
for localizedString in localizedStrings:
|
||||
val = dOld.get(localizedString, {})
|
||||
translation = val.get("translation", "")
|
||||
comment = val.get("comment")
|
||||
if len(localizedString) > doublespace_threshold and not lOut[-1] == "":
|
||||
lOut.append("")
|
||||
if comment != None:
|
||||
lOut.append(comment)
|
||||
lOut.append(f"{localizedString}={translation}")
|
||||
if len(localizedString) > doublespace_threshold:
|
||||
lOut.append("")
|
||||
|
||||
|
||||
unusedExist = False
|
||||
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 len(key) > doublespace_threshold and not lOut[-1] == "":
|
||||
lOut.append("")
|
||||
if comment != None:
|
||||
lOut.append(comment)
|
||||
lOut.append(f"{key}={translation}")
|
||||
if 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 = []
|
||||
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
|
||||
|
||||
# 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):
|
||||
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[:3] == "###":
|
||||
if header_comment is None:
|
||||
# Save header comments
|
||||
header_comment = latest_comment_block
|
||||
# Stip 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
|
||||
|
||||
# Reset comment block if we hit a header
|
||||
latest_comment_block = None
|
||||
continue
|
||||
if line[:1] == "#":
|
||||
# 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)
|
||||
if params["verbose"]:
|
||||
print(f"{fname}: {str(len(found))} translatable strings")
|
||||
|
||||
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()]
|
||||
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()]:
|
||||
update_folder(modfolder + "/")
|
||||
|
||||
|
||||
main()
|
471
init.lua
@ -1,20 +1,20 @@
|
||||
-- global callbacks
|
||||
trail = {}
|
||||
footprints = {}
|
||||
|
||||
local default_modpath = minetest.get_modpath("default")
|
||||
|
||||
local S = minetest.get_translator(minetest.get_current_modname())
|
||||
|
||||
-- Parameters
|
||||
|
||||
local FOO = true -- Enable footprints.
|
||||
local GLOBALSTEP_INTERVAL = 0.2 -- Function cycle in seconds.
|
||||
|
||||
local HARDPACK_PROBABILITY = minetest.settings:get("trail_hardpack_probability") or 0.5 -- Chance walked dirt/grass is worn and compacted to trail:trail.
|
||||
local HARDPACK_COUNT = minetest.settings:get("trail_hardpack_count") or 5 -- Number of times the above chance needs to be passed for soil to compact.
|
||||
local ICE_PROBABILITY = minetest.settings:get("trail_ice_probability") or 0.05 -- Chance walked snowblock is compacted to ice.
|
||||
local EROSION = minetest.settings:get_bool("trail_erosion", true) -- Enable footprint erosion.
|
||||
local TRAIL_EROSION = minetest.settings:get_bool("trail_trail_erosion", true) -- Allow hard-packed soil to erode back to dirt
|
||||
local EROSION_INTERVAL = minetest.settings:get("trail_erosion_interval") or 16 -- Erosion interval.
|
||||
local EROSION_CHANCE = minetest.settings:get("trail_erosion_chance") or 128 -- Erosion 1/x chance.
|
||||
local HARDPACK_PROBABILITY = minetest.settings:get("footprints_hardpack_probability") or 0.9 -- Chance walked dirt/grass is worn and compacted to footprints:trail.
|
||||
local HARDPACK_COUNT = minetest.settings:get("footprints_hardpack_count") or 10 -- Number of times the above chance needs to be passed for soil to compact.
|
||||
local EROSION = minetest.settings:get_bool("footprints_erosion", true) -- Enable footprint erosion.
|
||||
local FOOTPRINTS_EROSION = minetest.settings:get_bool("footprints_trail_erosion", false) -- Allow hard-packed soil to erode back to dirt
|
||||
local EROSION_INTERVAL = minetest.settings:get("footprints_erosion_interval") or 128 -- Erosion interval.
|
||||
local EROSION_CHANCE = minetest.settings:get("footprints_erosion_chance") or 2 -- Erosion 1/x chance.
|
||||
|
||||
-- Utility
|
||||
|
||||
@ -31,30 +31,30 @@ end
|
||||
|
||||
-- Player positions
|
||||
|
||||
local player_pos_previous = {}
|
||||
local player_pos_previous_map = {}
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
player_pos_previous[player:get_player_name()] = {x = 0, y = 0, z = 0}
|
||||
player_pos_previous_map[player:get_player_name()] = {x = 0, y = 0, z = 0}
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
player_pos_previous[player:get_player_name()] = nil
|
||||
player_pos_previous_map[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
local trails = {}
|
||||
local trampleable_nodes = {}
|
||||
local erosion = {}
|
||||
|
||||
trail.register_trample_node = function(trampleable_node_name, trample_def)
|
||||
footprints.register_trample_node = function(trampleable_node_name, trample_def)
|
||||
trample_def = trample_def or {} -- Everything has defaults, so if no trample_def is passed in just use an empty table.
|
||||
|
||||
if trails[trampleable_node_name] then
|
||||
minetest.log("error", "[trail] Attempted to call trail.register_trample_node to register trampleable node "
|
||||
if trampleable_nodes[trampleable_node_name] then
|
||||
minetest.log("error", "[footprints] Attempted to call footprints.register_trample_node to register trampleable node "
|
||||
.. trampleable_node_name ..", which has already been registered as trampleable.")
|
||||
return
|
||||
end
|
||||
local trampleable_node_def = minetest.registered_nodes[trampleable_node_name]
|
||||
if trampleable_node_def == nil then
|
||||
minetest.log("error", "[trail] Attempted to call trail.register_trample_node with the trampleable node "
|
||||
minetest.log("error", "[footprints] Attempted to call footprints.register_trample_node with the trampleable node "
|
||||
.. trampleable_node_name ..", which has not yet been registered as a node.")
|
||||
return
|
||||
end
|
||||
@ -71,7 +71,7 @@ trail.register_trample_node = function(trampleable_node_name, trample_def)
|
||||
-- Set up the erosion ABM group
|
||||
if EROSION and trample_def.erodes ~= false then
|
||||
local groups = trampled_node_def.groups or {}
|
||||
groups.trail_erodes = 1
|
||||
groups.footprints_erodes = 1
|
||||
trampled_node_def.groups = groups
|
||||
erosion[trampled_node_name] = trampleable_node_name
|
||||
end
|
||||
@ -83,7 +83,7 @@ trail.register_trample_node = function(trampleable_node_name, trample_def)
|
||||
|
||||
-- Modify the +Y tile with a footprint overlay
|
||||
if trample_def.add_footprint_overlay ~= false then
|
||||
local footprint_overlay = trample_def.footprint_overlay or "trail_footprint.png"
|
||||
local footprint_overlay = trample_def.footprint_overlay or "footprints_footprint.png"
|
||||
local footprint_opacity = trample_def.footprint_opacity or 64
|
||||
local overlay_texture = "^(" .. footprint_overlay .. "^[opacity:" .. tostring(footprint_opacity) .. ")"
|
||||
|
||||
@ -105,38 +105,38 @@ trail.register_trample_node = function(trampleable_node_name, trample_def)
|
||||
|
||||
minetest.register_node(":"..trampled_node_name, trampled_node_def)
|
||||
|
||||
-- If hard pack has been defined for this trail type, add it
|
||||
-- If hard pack has been defined for this footprints type, add it
|
||||
local hard_pack_node_name = trample_def.hard_pack_node_name
|
||||
if hard_pack_node_name then
|
||||
local hard_pack_probability = trample_def.hard_pack_probability or 0.1
|
||||
local hard_pack_count = trample_def.hard_pack_count or 1
|
||||
trails[trampled_node_name] = {name=hard_pack_node_name, probability=hard_pack_probability, count = hard_pack_count}
|
||||
trampleable_nodes[trampled_node_name] = {name=hard_pack_node_name, probability=hard_pack_probability, count = hard_pack_count}
|
||||
end
|
||||
end
|
||||
|
||||
local probability = trample_def.probability or 1
|
||||
local trample_count = trample_def.trample_count or 1
|
||||
trails[trampleable_node_name] = {name=trampled_node_name, probability=probability, randomize_trampled_param2 = trample_def.randomize_trampled_param2, count = trample_count}
|
||||
trampleable_nodes[trampleable_node_name] = {name=trampled_node_name, probability=probability, randomize_trampled_param2 = trample_def.randomize_trampled_param2, count = trample_count}
|
||||
end
|
||||
|
||||
trail.register_erosion = function(source_node_name, destination_node_name)
|
||||
footprints.register_erosion = function(source_node_name, destination_node_name)
|
||||
if not EROSION then
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.registered_nodes[source_node_name] == nil then
|
||||
minetest.log("error", "[trail] attempted to call trail.register_erosion with unregistered source node "
|
||||
minetest.log("error", "[footprints] attempted to call footprints.register_erosion with unregistered source node "
|
||||
.. source_node_name)
|
||||
return
|
||||
end
|
||||
if minetest.registered_nodes[destination_node_name] == nil then
|
||||
minetest.log("error", "[trail] attempted to call trail.register_erosion with unregistered destination node "
|
||||
minetest.log("error", "[footprints] attempted to call footprints.register_erosion with unregistered destination node "
|
||||
.. destination_node_name)
|
||||
return
|
||||
end
|
||||
if minetest.get_item_group(source_node_name, "trail_erodes") == 0 then
|
||||
minetest.log("error", "[trail] attempted to call trail.register_erosion with source node "
|
||||
.. destination_node_name .. " that wasn't in group trail_erodes.")
|
||||
if minetest.get_item_group(source_node_name, "footprints_erodes") == 0 then
|
||||
minetest.log("error", "[footprints] attempted to call footprints.register_erosion with source node "
|
||||
.. destination_node_name .. " that wasn't in group footprints_erodes.")
|
||||
return
|
||||
end
|
||||
|
||||
@ -145,106 +145,105 @@ end
|
||||
|
||||
-- Nodes
|
||||
|
||||
local default_modpath = minetest.get_modpath("default")
|
||||
|
||||
if default_modpath then
|
||||
-- hard-packed soil
|
||||
local trail_trail_def = {
|
||||
tiles = {"trail_trailtop.png", "default_dirt.png",
|
||||
"default_dirt.png^trail_trailside.png"},
|
||||
local footprints_trail_def = {
|
||||
tiles = {"footprints_trailtop.png", "default_dirt.png",
|
||||
"default_dirt.png^footprints_trailside.png"},
|
||||
groups = {crumbly = 2},
|
||||
drop = "default:dirt",
|
||||
sounds = default.node_sound_dirt_defaults(),
|
||||
}
|
||||
if TRAIL_EROSION then
|
||||
trail_trail_def.groups.trail_erodes = 1
|
||||
if FOOTPRINTS_EROSION then
|
||||
footprints_trail_def.groups.footprints_erodes = 1
|
||||
end
|
||||
minetest.register_node("trail:trail", trail_trail_def)
|
||||
if TRAIL_EROSION then
|
||||
trail.register_erosion("trail:trail", "default:dirt")
|
||||
minetest.register_node("footprints:trail", footprints_trail_def)
|
||||
if FOOTPRINTS_EROSION then
|
||||
footprints.register_erosion("footprints:trail", "default:dirt")
|
||||
end
|
||||
|
||||
-- hard-packed dry soil
|
||||
local trail_dry_trail_def = {
|
||||
tiles = {"trail_trailtop.png", "default_dry_dirt.png",
|
||||
"default_dry_dirt.png^trail_trailside.png"},
|
||||
local footprints_dry_trail_def = {
|
||||
tiles = {"footprints_trailtop.png", "default_dry_dirt.png",
|
||||
"default_dry_dirt.png^footprints_trailside.png"},
|
||||
groups = {crumbly = 2},
|
||||
drop = "default:dry_dirt",
|
||||
sounds = default.node_sound_dirt_defaults(),
|
||||
}
|
||||
if TRAIL_EROSION then
|
||||
trail_dry_trail_def.groups.trail_erodes = 1
|
||||
if FOOTPRINTS_EROSION then
|
||||
footprints_dry_trail_def.groups.footprints_erodes = 1
|
||||
end
|
||||
minetest.register_node("trail:dry_trail", trail_dry_trail_def)
|
||||
if TRAIL_EROSION then
|
||||
trail.register_erosion("trail:dry_trail", "default:dry_dirt")
|
||||
minetest.register_node("footprints:dry_trail", footprints_dry_trail_def)
|
||||
if FOOTPRINTS_EROSION then
|
||||
footprints.register_erosion("footprints:dry_trail", "default:dry_dirt")
|
||||
end
|
||||
|
||||
-- Default dirt
|
||||
|
||||
trail.register_trample_node("default:dirt", {
|
||||
trampled_node_name = "trail:dirt",
|
||||
footprints.register_trample_node("default:dirt", {
|
||||
trampled_node_name = "footprints:dirt",
|
||||
trampled_node_def_override = {description = S("Dirt with Footprint"),},
|
||||
hard_pack_node_name = "trail:trail",
|
||||
hard_pack_node_name = "footprints:trail",
|
||||
footprint_opacity = 96,
|
||||
hard_pack_probability = HARDPACK_PROBABILITY,
|
||||
hard_pack_count = HARDPACK_COUNT,
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:dirt_with_grass", {
|
||||
trampled_node_name = "trail:dirt_with_grass",
|
||||
footprints.register_trample_node("default:dirt_with_grass", {
|
||||
trampled_node_name = "footprints:dirt_with_grass",
|
||||
trampled_node_def_override = {description = S("Dirt with Grass and Footprint"),},
|
||||
hard_pack_node_name = "trail:trail",
|
||||
hard_pack_node_name = "footprints:trail",
|
||||
hard_pack_probability = HARDPACK_PROBABILITY,
|
||||
hard_pack_count = HARDPACK_COUNT,
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:dirt_with_dry_grass", {
|
||||
trampled_node_name = "trail:dirt_with_dry_grass",
|
||||
footprints.register_trample_node("default:dirt_with_dry_grass", {
|
||||
trampled_node_name = "footprints:dirt_with_dry_grass",
|
||||
trampled_node_def_override = {description = S("Dirt with Dry Grass and Footprint"),},
|
||||
hard_pack_node_name = "trail:trail",
|
||||
hard_pack_node_name = "footprints:trail",
|
||||
hard_pack_probability = HARDPACK_PROBABILITY,
|
||||
hard_pack_count = HARDPACK_COUNT,
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:dirt_with_snow", {
|
||||
trampled_node_name = "trail:dirt_with_snow",
|
||||
footprints.register_trample_node("default:dirt_with_snow", {
|
||||
trampled_node_name = "footprints:dirt_with_snow",
|
||||
trampled_node_def_override = {description = S("Dirt with Snow and Footprint"),},
|
||||
hard_pack_node_name = "trail:trail",
|
||||
hard_pack_node_name = "footprints:trail",
|
||||
hard_pack_probability = HARDPACK_PROBABILITY,
|
||||
hard_pack_count = HARDPACK_COUNT,
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:dirt_with_rainforest_litter", {
|
||||
trampled_node_name = "trail:dirt_with_rainforest_litter",
|
||||
footprints.register_trample_node("default:dirt_with_rainforest_litter", {
|
||||
trampled_node_name = "footprints:dirt_with_rainforest_litter",
|
||||
trampled_node_def_override = {description = S("Dirt with Rainforest Litter and Footprint"),},
|
||||
hard_pack_node_name = "trail:trail",
|
||||
hard_pack_node_name = "footprints:trail",
|
||||
footprint_opacity = 96,
|
||||
hard_pack_probability = HARDPACK_PROBABILITY,
|
||||
hard_pack_count = HARDPACK_COUNT,
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:dirt_with_coniferous_litter", {
|
||||
trampled_node_name = "trail:dirt_with_coniferous_litter",
|
||||
footprints.register_trample_node("default:dirt_with_coniferous_litter", {
|
||||
trampled_node_name = "footprints:dirt_with_coniferous_litter",
|
||||
trampled_node_def_override = {description = S("Dirt with Coniferous Litter and Footprint"),},
|
||||
hard_pack_node_name = "trail:trail",
|
||||
hard_pack_node_name = "footprints:trail",
|
||||
footprint_opacity = 128,
|
||||
hard_pack_probability = HARDPACK_PROBABILITY,
|
||||
hard_pack_count = HARDPACK_COUNT,
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:dry_dirt", {
|
||||
trampled_node_name = "trail:dry_dirt",
|
||||
footprints.register_trample_node("default:dry_dirt", {
|
||||
trampled_node_name = "footprints:dry_dirt",
|
||||
trampled_node_def_override = {description = S("Dry Dirt with Footprint"),},
|
||||
hard_pack_node_name = "trail:dry_trail",
|
||||
hard_pack_node_name = "footprints:dry_trail",
|
||||
footprint_opacity = 96,
|
||||
hard_pack_probability = HARDPACK_PROBABILITY,
|
||||
hard_pack_count = HARDPACK_COUNT,
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:dry_dirt_with_dry_grass", {
|
||||
trampled_node_name = "trail:dry_dirt_with_dry_grass",
|
||||
footprints.register_trample_node("default:dry_dirt_with_dry_grass", {
|
||||
trampled_node_name = "footprints:dry_dirt_with_dry_grass",
|
||||
trampled_node_def_override = {description = S("Dry Dirt with Dry Grass and Footprint"),},
|
||||
hard_pack_node_name = "trail:dry_trail",
|
||||
hard_pack_node_name = "footprints:dry_trail",
|
||||
footprint_opacity = 96,
|
||||
hard_pack_probability = HARDPACK_PROBABILITY,
|
||||
hard_pack_count = HARDPACK_COUNT,
|
||||
@ -252,52 +251,55 @@ if default_modpath then
|
||||
|
||||
-- Default sand
|
||||
|
||||
trail.register_trample_node("default:sand", {
|
||||
trampled_node_name = "trail:sand",
|
||||
footprints.register_trample_node("default:sand", {
|
||||
trampled_node_name = "footprints:sand",
|
||||
trampled_node_def_override = {description = S("Sand with Footprint"),},
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:desert_sand", {
|
||||
trampled_node_name = "trail:desert_sand",
|
||||
footprints.register_trample_node("default:desert_sand", {
|
||||
trampled_node_name = "footprints:desert_sand",
|
||||
trampled_node_def_override = {description = S("Desert Sand with Footprint"),},
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:silver_sand", {
|
||||
trampled_node_name = "trail:silver_sand",
|
||||
footprints.register_trample_node("default:silver_sand", {
|
||||
trampled_node_name = "footprints:silver_sand",
|
||||
trampled_node_def_override = {description = S("Silver Sand with Footprint"),},
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:gravel", {
|
||||
trampled_node_name = "trail:gravel",
|
||||
footprints.register_trample_node("default:gravel", {
|
||||
trampled_node_name = "footprints:gravel",
|
||||
trampled_node_def_override = {description = S("Gravel with Footprint"),},
|
||||
footprint_opacity = 128,
|
||||
})
|
||||
|
||||
-- Default snow
|
||||
|
||||
trail.register_trample_node("default:snowblock", {
|
||||
trampled_node_name = "trail:snowblock",
|
||||
footprints.register_trample_node("default:snowblock", {
|
||||
trampled_node_name = "footprints:snowblock",
|
||||
trampled_node_def_override = {description = S("Snow Block with Footprint"),},
|
||||
hard_pack_node_name = "default:ice",
|
||||
hard_pack_probability = ICE_PROBABILITY,
|
||||
hard_pack_probability = HARDPACK_PROBABILITY,
|
||||
hard_pack_count = HARDPACK_COUNT,
|
||||
})
|
||||
|
||||
trail.register_trample_node("default:snow", {
|
||||
trampled_node_name = "trail:snow",
|
||||
footprints.register_trample_node("default:snow", {
|
||||
trampled_node_name = "footprints:snow",
|
||||
trampled_node_def_override = {description = S("Snow with Footprint"),},
|
||||
})
|
||||
end
|
||||
|
||||
if minetest.get_modpath("farming") then
|
||||
local hoe_converts_nodes = {}
|
||||
|
||||
local sounds
|
||||
if default_modpath then
|
||||
sounds = default.node_sound_leaves_defaults()
|
||||
end
|
||||
-- Flattened wheat
|
||||
minetest.register_node("trail:wheat", {
|
||||
minetest.register_node("footprints:wheat", {
|
||||
description = S("Flattened Wheat"),
|
||||
tiles = {"trail_flat_wheat.png"},
|
||||
inventory_image = "trail_flat_wheat.png",
|
||||
tiles = {"footprints_flat_wheat.png"},
|
||||
inventory_image = "footprints_flat_wheat.png",
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
@ -313,27 +315,27 @@ if minetest.get_modpath("farming") then
|
||||
sounds = sounds,
|
||||
})
|
||||
|
||||
trail.register_trample_node("farming:wheat_5", {
|
||||
trampled_node_name = "trail:wheat",
|
||||
footprints.register_trample_node("farming:wheat_5", {
|
||||
trampled_node_name = "footprints:wheat",
|
||||
randomize_trampled_param2 = true,
|
||||
})
|
||||
trail.register_trample_node("farming:wheat_6", {
|
||||
trampled_node_name = "trail:wheat",
|
||||
footprints.register_trample_node("farming:wheat_6", {
|
||||
trampled_node_name = "footprints:wheat",
|
||||
randomize_trampled_param2 = true,
|
||||
})
|
||||
trail.register_trample_node("farming:wheat_7", {
|
||||
trampled_node_name = "trail:wheat",
|
||||
footprints.register_trample_node("farming:wheat_7", {
|
||||
trampled_node_name = "footprints:wheat",
|
||||
randomize_trampled_param2 = true,
|
||||
})
|
||||
trail.register_trample_node("farming:wheat_8", {
|
||||
trampled_node_name = "trail:wheat",
|
||||
footprints.register_trample_node("farming:wheat_8", {
|
||||
trampled_node_name = "footprints:wheat",
|
||||
randomize_trampled_param2 = true,
|
||||
})
|
||||
|
||||
minetest.register_node("trail:cotton", {
|
||||
minetest.register_node("footprints:cotton", {
|
||||
description = S("Flattened Cotton"),
|
||||
tiles = {"trail_flat_cotton.png"},
|
||||
inventory_image = "trail_flat_cotton.png",
|
||||
tiles = {"footprints_flat_cotton.png"},
|
||||
inventory_image = "footprints_flat_cotton.png",
|
||||
drawtype = "nodebox",
|
||||
paramtype = "light",
|
||||
paramtype2 = "facedir",
|
||||
@ -349,130 +351,192 @@ if minetest.get_modpath("farming") then
|
||||
sounds = sounds,
|
||||
})
|
||||
|
||||
trail.register_trample_node("farming:cotton_5", {
|
||||
trampled_node_name = "trail:cotton",
|
||||
footprints.register_trample_node("farming:cotton_5", {
|
||||
trampled_node_name = "footprints:cotton",
|
||||
randomize_trampled_param2 = true,
|
||||
})
|
||||
trail.register_trample_node("farming:cotton_6", {
|
||||
trampled_node_name = "trail:cotton",
|
||||
footprints.register_trample_node("farming:cotton_6", {
|
||||
trampled_node_name = "footprints:cotton",
|
||||
randomize_trampled_param2 = true,
|
||||
})
|
||||
trail.register_trample_node("farming:cotton_7", {
|
||||
trampled_node_name = "trail:cotton",
|
||||
footprints.register_trample_node("farming:cotton_7", {
|
||||
trampled_node_name = "footprints:cotton",
|
||||
randomize_trampled_param2 = true,
|
||||
})
|
||||
trail.register_trample_node("farming:cotton_8", {
|
||||
trampled_node_name = "trail:cotton",
|
||||
footprints.register_trample_node("farming:cotton_8", {
|
||||
trampled_node_name = "footprints:cotton",
|
||||
randomize_trampled_param2 = true,
|
||||
})
|
||||
|
||||
-- Allow hoes to turn hardpack back into bare dirt
|
||||
footprints.register_hoe_converts = function(target_node, converted_node)
|
||||
hoe_converts_nodes[target_node] = converted_node
|
||||
end
|
||||
|
||||
local old_hoe_on_use = farming.hoe_on_use
|
||||
if not old_hoe_on_use then
|
||||
-- Something's wrong, don't override
|
||||
return
|
||||
end
|
||||
|
||||
local new_hoe_on_use = function(itemstack, user, pointed_thing, uses)
|
||||
local pt = pointed_thing
|
||||
-- check if pointing at a node
|
||||
if not pt then
|
||||
return
|
||||
end
|
||||
if pt.type ~= "node" then
|
||||
return
|
||||
end
|
||||
|
||||
local under_node = minetest.get_node(pt.under)
|
||||
local restore_node = hoe_converts_nodes[under_node.name]
|
||||
|
||||
-- check if pointing at hardpack
|
||||
if restore_node then
|
||||
if minetest.is_protected(pt.under, user:get_player_name()) then
|
||||
minetest.record_protection_violation(pt.under, user:get_player_name())
|
||||
return
|
||||
end
|
||||
|
||||
-- turn the node into soil and play sound
|
||||
minetest.set_node(pt.under, {name = restore_node})
|
||||
minetest.sound_play("default_dig_crumbly", {
|
||||
pos = pt.under,
|
||||
gain = 0.5,
|
||||
})
|
||||
if not (creative and creative.is_enabled_for
|
||||
and creative.is_enabled_for(user:get_player_name())) then
|
||||
-- wear tool
|
||||
local wdef = itemstack:get_definition()
|
||||
itemstack:add_wear(65535/(uses-1))
|
||||
-- tool break sound
|
||||
if itemstack:get_count() == 0 and wdef.sound and wdef.sound.breaks then
|
||||
minetest.sound_play(wdef.sound.breaks, {pos = pt.above, gain = 0.5})
|
||||
end
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
|
||||
return old_hoe_on_use(itemstack, user, pointed_thing, uses)
|
||||
end
|
||||
|
||||
farming.hoe_on_use = new_hoe_on_use
|
||||
else
|
||||
footprints.register_hoe_converts = function(target_node, converted_node)
|
||||
end
|
||||
end
|
||||
|
||||
if default_modpath then
|
||||
footprints.register_hoe_converts("footprints:trail", "default:dirt")
|
||||
footprints.register_hoe_converts("footprints:dry_trail", "default:dry_dirt")
|
||||
end
|
||||
|
||||
-- Globalstep function
|
||||
|
||||
if FOO then
|
||||
local timer = 0
|
||||
|
||||
local get_param2 = function(trail_def)
|
||||
if trail_def.randomize_trampled_param2 then
|
||||
return math.random(0,3)
|
||||
end
|
||||
return 0
|
||||
local timer = 0
|
||||
|
||||
local get_param2 = function(footprints_def)
|
||||
if footprints_def.randomize_trampled_param2 then
|
||||
return math.random(0,3)
|
||||
end
|
||||
|
||||
local test_trample_count = function(trail_def, pos)
|
||||
local target_count = trail_def.count
|
||||
if target_count <= 1 then
|
||||
return true
|
||||
end
|
||||
local meta = minetest.get_meta(pos)
|
||||
local trampled_count = meta:get_int("trail_trample_count")
|
||||
trampled_count = trampled_count + 1
|
||||
if trampled_count >= target_count then
|
||||
return true
|
||||
end
|
||||
meta:set_int("trail_trample_count", trampled_count)
|
||||
return false
|
||||
return 0
|
||||
end
|
||||
|
||||
local test_trample_count = function(footprints_def, pos)
|
||||
local target_count = footprints_def.count
|
||||
if target_count <= 1 then
|
||||
return true
|
||||
end
|
||||
|
||||
local math_floor = math.floor
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime
|
||||
if timer > GLOBALSTEP_INTERVAL then
|
||||
timer = 0
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
local pos = player:getpos()
|
||||
local player_name = player:get_player_name()
|
||||
local pos_x_plus_half = math_floor(pos.x + 0.5)
|
||||
local pos_z_plus_half = math_floor(pos.z + 0.5)
|
||||
local pos_y = pos.y
|
||||
local current_player_pos = {
|
||||
local meta = minetest.get_meta(pos)
|
||||
local trampled_count = meta:get_int("footprints_trample_count")
|
||||
trampled_count = trampled_count + 1
|
||||
if trampled_count >= target_count then
|
||||
return true
|
||||
end
|
||||
meta:set_int("footprints_trample_count", trampled_count)
|
||||
return false
|
||||
end
|
||||
|
||||
local math_floor = math.floor
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
timer = timer + dtime
|
||||
if timer > GLOBALSTEP_INTERVAL then
|
||||
timer = 0
|
||||
for _, player in ipairs(minetest.get_connected_players()) do
|
||||
local pos = player:get_pos()
|
||||
local player_name = player:get_player_name()
|
||||
local pos_x_plus_half = math_floor(pos.x + 0.5)
|
||||
local pos_z_plus_half = math_floor(pos.z + 0.5)
|
||||
local pos_y = pos.y
|
||||
local current_player_pos = {
|
||||
x = pos_x_plus_half,
|
||||
y = math_floor(pos_y + 0.2),
|
||||
z = pos_z_plus_half
|
||||
}
|
||||
|
||||
local player_pos_previous = player_pos_previous_map[player_name]
|
||||
|
||||
if player_pos_previous == nil then
|
||||
break
|
||||
end
|
||||
|
||||
if current_player_pos.x ~= player_pos_previous.x or
|
||||
current_player_pos.y < player_pos_previous.y or
|
||||
current_player_pos.z ~= player_pos_previous.z then
|
||||
|
||||
local pos_ground_cover = {
|
||||
x = pos_x_plus_half,
|
||||
y = math_floor(pos_y + 0.2),
|
||||
y = math_floor(pos_y + 1.2),
|
||||
z = pos_z_plus_half
|
||||
}
|
||||
local name_ground_cover = minetest.get_node(pos_ground_cover).name
|
||||
|
||||
--if player_pos_previous[player_name] == nil then
|
||||
--break
|
||||
--end
|
||||
|
||||
if current_player_pos.x ~= player_pos_previous[player_name].x or
|
||||
current_player_pos.y < player_pos_previous[player_name].y or
|
||||
current_player_pos.z ~= player_pos_previous[player_name].z then
|
||||
|
||||
local p_snow = {
|
||||
x = pos_x_plus_half,
|
||||
y = math_floor(pos_y + 1.2),
|
||||
z = pos_z_plus_half
|
||||
}
|
||||
local n_snow = minetest.get_node(p_snow).name
|
||||
|
||||
-- test ground cover first (snow, wheat)
|
||||
local trail_def = trails[n_snow]
|
||||
if trail_def then
|
||||
if math.random() <= trail_def.probability then
|
||||
local p_snowpl = {
|
||||
x = pos_x_plus_half,
|
||||
y = math_floor(pos_y + 0.5),
|
||||
z = pos_z_plus_half
|
||||
}
|
||||
if test_trample_count(trail_def, p_snowpl) then
|
||||
minetest.set_node(p_snowpl, {name = trail_def.name, param2 = get_param2(trail_def)})
|
||||
end
|
||||
end
|
||||
else
|
||||
local p_ground = {
|
||||
-- test ground cover first (snow, wheat)
|
||||
local footprints_def = trampleable_nodes[name_ground_cover]
|
||||
if footprints_def then
|
||||
if math.random() <= footprints_def.probability then
|
||||
local pos_ground_cover_plus = {
|
||||
x = pos_x_plus_half,
|
||||
y = math_floor(pos_y + 0.4),
|
||||
y = math_floor(pos_y + 0.5),
|
||||
z = pos_z_plus_half
|
||||
}
|
||||
local n_ground = minetest.get_node(p_ground).name
|
||||
trail_def = trails[n_ground]
|
||||
if trail_def and math.random() <= trail_def.probability then
|
||||
local p_groundpl = {
|
||||
x = pos_x_plus_half,
|
||||
y = math_floor(pos_y - 0.5),
|
||||
z =pos_z_plus_half
|
||||
}
|
||||
if test_trample_count(trail_def, p_groundpl) then
|
||||
minetest.set_node(p_groundpl, {name = trail_def.name, param2 = get_param2(trail_def)})
|
||||
end
|
||||
if test_trample_count(footprints_def, pos_ground_cover_plus) then
|
||||
minetest.set_node(pos_ground_cover_plus, {name = footprints_def.name, param2 = get_param2(footprints_def)})
|
||||
end
|
||||
end
|
||||
else
|
||||
local pos_ground = {
|
||||
x = pos_x_plus_half,
|
||||
y = math_floor(pos_y + 0.4),
|
||||
z = pos_z_plus_half
|
||||
}
|
||||
local name_ground = minetest.get_node(pos_ground).name
|
||||
footprints_def = trampleable_nodes[name_ground]
|
||||
if footprints_def and math.random() <= footprints_def.probability then
|
||||
local pos_groundpl = {
|
||||
x = pos_x_plus_half,
|
||||
y = math_floor(pos_y - 0.5),
|
||||
z =pos_z_plus_half
|
||||
}
|
||||
if test_trample_count(footprints_def, pos_groundpl) then
|
||||
minetest.set_node(pos_groundpl, {name = footprints_def.name, param2 = get_param2(footprints_def)})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
player_pos_previous[player_name] = current_player_pos
|
||||
end
|
||||
|
||||
player_pos_previous_map[player_name] = current_player_pos
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- ABM
|
||||
|
||||
if EROSION then
|
||||
minetest.register_abm({
|
||||
nodenames = {"group:trail_erodes"},
|
||||
nodenames = {"group:footprints_erodes"},
|
||||
interval = EROSION_INTERVAL,
|
||||
chance = EROSION_CHANCE,
|
||||
catch_up = true,
|
||||
@ -480,11 +544,36 @@ if EROSION then
|
||||
local nodename = node.name
|
||||
local erodes_to = erosion[nodename]
|
||||
if erodes_to then
|
||||
minetest.set_node(pos, {name = erodes_to})
|
||||
local meta = minetest.get_meta(pos)
|
||||
local trampled_count = meta:get_int("footprints_trample_count") - 1
|
||||
if trampled_count <= 0 then
|
||||
minetest.set_node(pos, {name = erodes_to})
|
||||
else
|
||||
meta:set_int("footprints_trample_count", trampled_count)
|
||||
end
|
||||
else
|
||||
minetest.log("error", "[trail] The node " .. nodename .. " is in group trail_erodes but "
|
||||
minetest.log("error", "[footprints] The node " .. nodename .. " is in group footprints_erodes but "
|
||||
.. " didn't have an erosion target node defined.")
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_alias("trail:cotton", "footprints:cotton")
|
||||
minetest.register_alias("trail:desert_sand", "footprints:desert_sand")
|
||||
minetest.register_alias("trail:dirt", "footprints:dirt")
|
||||
minetest.register_alias("trail:dirt_with_coniferous_litter","footprints:dirt_with_coniferous_litter")
|
||||
minetest.register_alias("trail:dirt_with_dry_grass", "footprints:dirt_with_dry_grass")
|
||||
minetest.register_alias("trail:dirt_with_grass", "footprints:dirt_with_grass")
|
||||
minetest.register_alias("trail:dirt_with_rainforest_litter","footprints:dirt_with_rainforest_litter")
|
||||
minetest.register_alias("trail:dirt_with_snow", "footprints:dirt_with_snow")
|
||||
minetest.register_alias("trail:dry_dirt", "footprints:dry_dirt")
|
||||
minetest.register_alias("trail:dry_dirt_with_dry_grass", "footprints:dry_dirt_with_dry_grass")
|
||||
minetest.register_alias("trail:dry_trail", "footprints:dry_trail")
|
||||
minetest.register_alias("trail:gravel", "footprints:gravel")
|
||||
minetest.register_alias("trail:sand", "footprints:sand")
|
||||
minetest.register_alias("trail:silver_sand", "footprints:silver_sand")
|
||||
minetest.register_alias("trail:snow", "footprints:snow")
|
||||
minetest.register_alias("trail:snowblock", "footprints:snowblock")
|
||||
minetest.register_alias("trail:trail", "footprints:trail")
|
||||
minetest.register_alias("trail:wheat", "footprints:wheat")
|
12
license.txt
@ -3,7 +3,7 @@ License of source code
|
||||
|
||||
The MIT License (MIT)
|
||||
Copyright (C) 2013-2017 paramat
|
||||
Copyright (C) 2019 FaceDeer
|
||||
Copyright (C) 2020 FaceDeer
|
||||
|
||||
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
|
||||
@ -26,12 +26,12 @@ https://opensource.org/licenses/MIT
|
||||
|
||||
License of media (textures)
|
||||
|
||||
trail_flat_wheat.png by paramat
|
||||
trail_footprint.png (from https://github.com/minetest/minetest_game/commit/c7b9e734ffd815e9b86b1fcceba2293e3067785e by paramat)
|
||||
trail_trailside.png by paramat
|
||||
trail_trailtop.png by paramat
|
||||
footprints_flat_wheat.png by paramat
|
||||
footprints_footprint.png (from https://github.com/minetest/minetest_game/commit/c7b9e734ffd815e9b86b1fcceba2293e3067785e by paramat)
|
||||
footprints_trailside.png by paramat
|
||||
footprints_trailtop.png by paramat
|
||||
|
||||
trail_flat_cotton.png by FaceDeer (C) 2019
|
||||
footprints_flat_cotton.png by FaceDeer (C) 2019
|
||||
---------------------------
|
||||
|
||||
Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
|
||||
|
@ -1,3 +1,9 @@
|
||||
# textdomain: footprints
|
||||
|
||||
|
||||
|
||||
### init.lua ###
|
||||
|
||||
Desert Sand with Footprint=
|
||||
Dirt with Coniferous Litter and Footprint=
|
||||
Dirt with Dry Grass and Footprint=
|
||||
@ -13,4 +19,4 @@ Gravel with Footprint=
|
||||
Sand with Footprint=
|
||||
Silver Sand with Footprint=
|
||||
Snow Block with Footprint=
|
||||
Snow with Footprint=
|
||||
Snow with Footprint=
|
||||
|
2
mod.conf
@ -1,3 +1,3 @@
|
||||
name = trail
|
||||
name = footprints
|
||||
description = Players walking over various types of terrain will leave footprints, and optionally pack the soil down into trails
|
||||
optional_depends = default, farming
|
BIN
screenshot.jpg
Normal file
After Width: | Height: | Size: 90 KiB |
@ -1,15 +1,14 @@
|
||||
trail_erosion (Erode footsteps back to original soil type) bool true
|
||||
footprints_erosion (Erode footsteps back to original soil type) bool true
|
||||
#This setting only has an effect if footstep erosion is also set to true
|
||||
trail_trail_erosion (Erode hard-packed trails back to dirt) bool true
|
||||
trail_erosion_interval (Erosion ABM interval) int 16
|
||||
trail_erosion_chance (Erosion ABM 1/x chance) int 128
|
||||
#This setting works in combination with trail_hardpack_count. It gives the
|
||||
footprints_trail_erosion (Erode hard-packed trails back to dirt) bool false
|
||||
footprints_erosion_interval (Erosion ABM interval) int 128
|
||||
footprints_erosion_chance (Erosion ABM 1/x chance) int 2
|
||||
#This setting works in combination with footprints_hardpack_count. It gives the
|
||||
#probability that a player stepping on a footprint will increment the hardpack
|
||||
#counter. So by default, every time you step on a footprint there's a 1/2
|
||||
#chance the counter increments for that node.
|
||||
trail_hardpack_probability (Probability footprints in dirt turn to hardpacked soil) float 0.5
|
||||
#This setting works in combination with trail_hardpack_probability. By default,
|
||||
footprints_hardpack_probability (Probability footprints in dirt turn to hardpacked soil) float 0.9
|
||||
#This setting works in combination with footprints_hardpack_probability. By default,
|
||||
#once a footprint has been stepped on enough to increment its counter 5 times
|
||||
#it'll turn the soil hard-packed.
|
||||
trail_hardpack_count (Number of times the hardpack check needs to pass) int 3
|
||||
trail_ice_probability (Chance footprints in snow turn to ice) float 0.05
|
||||
footprints_hardpack_count (Number of times the hardpack check needs to pass) int 10
|
Before Width: | Height: | Size: 621 B After Width: | Height: | Size: 621 B |
Before Width: | Height: | Size: 189 B After Width: | Height: | Size: 189 B |
Before Width: | Height: | Size: 114 B After Width: | Height: | Size: 114 B |
Before Width: | Height: | Size: 461 B After Width: | Height: | Size: 461 B |
Before Width: | Height: | Size: 272 B After Width: | Height: | Size: 272 B |