Merge branch 'dev' into fancy_hotbar_9271_fixed
This commit is contained in:
commit
5b2e61be75
BIN
.cdb-alpha.jpg
Normal file
BIN
.cdb-alpha.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 414 KiB |
7
.cdb-alpha.md
Normal file
7
.cdb-alpha.md
Normal file
@ -0,0 +1,7 @@
|
||||
*This package is the **development edition** of the **NodeCore** game. It may include cutting-edge or experimental new features. It may also be unstable or buggy.*
|
||||
|
||||
Updates are released automatically, tracking the [NodeCore Dev Branch](https://gitlab.com/sztest/nodecore/commits/dev). Note that there may be some releases that don't include *any* functionality changes, since the automated process may pick up changes to embedded documentation or other things that don't end up in the game.
|
||||
|
||||
Alternatively, check out the [Official Release Edition of NodeCore](/packages/Warr1024/nodecore/).
|
||||
|
||||
Join the Discord [https://discord.gg/NNYeF6f](https://discord.gg/NNYeF6f) or IRC at **#nodecore** on [freenode](https://freenode.net/)
|
BIN
.cdb-release.jpg
Normal file
BIN
.cdb-release.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 309 KiB |
15
.cdb-release.md
Normal file
15
.cdb-release.md
Normal file
@ -0,0 +1,15 @@
|
||||
**NodeCore** is a major reconstruction of "survival" gameplay from the ground up. *Relearn much of what you thought you knew about Minetest!*
|
||||
|
||||
#### Features
|
||||
|
||||
- Immersive gameplay. Zero in-game pop-up GUIs. Minimal HUDs. All interactions take place in continuous first-person perspective. Nothing gets between you and the game world.
|
||||
- Nearly everything is on the grid. Item stacks settle onto the grid and persist. Complex machines (e.g. furnaces, storage) are built in-world and can be designed, customized, optimized.
|
||||
- In-world crafting. Assemble more complex recipes directly on the grid or in-place. Learn how to "pummel" nodes to hammer things together or break things apart.
|
||||
- Built-in player guide and hint system provides low-spoiler guidance.
|
||||
- Rich and subtle interactions. Some materials dig and transform in stages. Some materials slump into repose when stacked high. Some things transform if conditions are met, but transform faster based on environment. Experiment and see what effects what!
|
||||
- Build complex in-game systems. Design your own furnace. Construct digital logic circuits. Build gears and rotary machinery. Assemble portable storage containers.
|
||||
- Eggcorns!
|
||||
|
||||
Note that NodeCore is a _complete_ game, but new features are still actively developed. If you're looking for the latest experimental stuff, and don't mind a little instability or a few bugs, check out the [NodeCore ALPHA](/packages/Warr1024/nodecore_alpha/) early-access releases.
|
||||
|
||||
Join the Discord [https://discord.gg/NNYeF6f](https://discord.gg/NNYeF6f) or IRC at **#nodecore** on [freenode](https://freenode.net/)
|
@ -3,9 +3,34 @@ local dofile
|
||||
= dofile
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
-- luacheck: push
|
||||
-- luacheck: globals config readtext readbinary
|
||||
|
||||
local alpha = config and config.branch == "dev"
|
||||
readtext = readtext or function() end
|
||||
readbinary = readbinary or function() end
|
||||
|
||||
return {
|
||||
user = "Warr1024",
|
||||
pkg = "nodecore",
|
||||
min = "5.0",
|
||||
version = dofile("./mods/nc_api/version.lua")
|
||||
pkg = alpha and "nodecore_alpha" or "nodecore",
|
||||
min = "5.2",
|
||||
version = dofile("./mods/nc_api/version.lua"),
|
||||
path = ".",
|
||||
type = "game",
|
||||
title = "NodeCore" .. (alpha and " ALPHA" or ""),
|
||||
short_desc = (alpha
|
||||
and "Experimental early-access release of NodeCore."
|
||||
or "Original, immersive puzzle/adventure game with NO popup GUIs, minimal HUDs."),
|
||||
tags = "building, crafting, environment, inventory, machines, player vs env, puzzle",
|
||||
license = "mit",
|
||||
desc = alpha and readtext('.cdb-alpha.md') or readtext('.cdb-release.md'),
|
||||
repo = "https://gitlab.com/sztest/nodecore",
|
||||
website = "https://nodecore.mine.nu",
|
||||
issueTracker = "https://discord.gg/NNYeF6f",
|
||||
forums = "https://forum.minetest.net/viewtopic.php?f=15&t=24857",
|
||||
screenshots = alpha
|
||||
and {readbinary('.cdb-alpha.jpg'), readbinary('.cdb-release.jpg')}
|
||||
or {readbinary('.cdb-release.jpg')}
|
||||
}
|
||||
|
||||
-- luacheck: pop
|
||||
|
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -1,5 +1,4 @@
|
||||
version.lua export-subst
|
||||
.git* export-ignore
|
||||
.lua* export-ignore
|
||||
.* export-ignore
|
||||
docs export-ignore
|
||||
src export-ignore
|
||||
|
12
.luacheckrc
12
.luacheckrc
@ -1,3 +1,13 @@
|
||||
globals = {"minetest", "ItemStack", "VoxelArea", "vector", "nodecore", "include", "SecureRandom"}
|
||||
globals = {
|
||||
"minetest",
|
||||
"ItemStack",
|
||||
"VoxelArea",
|
||||
"vector",
|
||||
"nodecore",
|
||||
"include",
|
||||
"SecureRandom",
|
||||
"PcgRandom",
|
||||
"profiler"
|
||||
}
|
||||
color = false
|
||||
quiet = 1
|
||||
|
@ -6,3 +6,5 @@ vector
|
||||
nodecore
|
||||
include
|
||||
SecureRandom
|
||||
PcgRandom
|
||||
profiler
|
@ -29,6 +29,11 @@ contribution.
|
||||
|
||||
Other Guidelines:
|
||||
|
||||
- Please do not use the nc_* namespace for projects you will be
|
||||
releasing directly to the public, e.g. via ContentDB, Forums, etc.
|
||||
This namespace should only be for things that will be included in
|
||||
the base game.
|
||||
|
||||
- Non-included contributions to the project, such as hosting or other
|
||||
services, content such as videos/streams, screenshots/galleries,
|
||||
reviews, stories and other publicity do not need to follow the
|
||||
|
7
LICENSE
7
LICENSE
@ -1,9 +1,12 @@
|
||||
Copyright (C)2018-2019 Aaron Suen <warr1024@gmail.com>
|
||||
Copyright (C)2018-2020 Aaron Suen <warr1024@gmail.com>
|
||||
Portions Copyright (C)2019 LoneWolfHT <lonewolf04361@gmail.com>
|
||||
Portions Copyright (C)2019 Magik Eh
|
||||
Portions Copyright (C)2019 Terifo <terifo1590@gmail.com>
|
||||
Portions Copyright (C)2019 GreenXenith
|
||||
Portions Copyright (C)2019 Kimapr
|
||||
Portions Copyright (C)2019 Dmitriy Tillyaev (Kimapr) <dmitriy.tillyaev@gmail.com>
|
||||
Portions Copyright (C)2019 Elkien
|
||||
Portions Copyright (C)2020 WintersKnight94 <wintersknight94@gmail.com>
|
||||
Portions Copyright (C)2019 Avicennia G
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
|
4
README
4
README
@ -45,7 +45,7 @@ Features:
|
||||
|
||||
------------------------------------------------------------------------
|
||||
|
||||
NodeCore is (C)2018-2019 by Aaron Suen <warr1024@gmail.com>
|
||||
NodeCore is (C)2018-2020 by Aaron Suen <warr1024@gmail.com>
|
||||
MIT License (http://www.opensource.org/licenses/MIT)
|
||||
See included LICENSE file for full details and credits
|
||||
|
||||
@ -56,7 +56,7 @@ GitLab:
|
||||
https://gitlab.com/sztest/nodecore
|
||||
|
||||
Discord:
|
||||
https://discord.gg/SHq2tkb
|
||||
https://discord.gg/NNYeF6f
|
||||
|
||||
IRC:
|
||||
#nodecore on chat.freenode.net
|
||||
|
89
WISHLIST
89
WISHLIST
@ -4,6 +4,8 @@
|
||||
Remember, check out the CONTRIBUTING file for guidelines on contributing
|
||||
to the project!
|
||||
|
||||
- Testing and bug reports!
|
||||
|
||||
- Translations:
|
||||
- NodeCore is running Weblate:
|
||||
https://nodecore.mine.nu/trans/projects/nodecore/core/
|
||||
@ -11,23 +13,61 @@ to the project!
|
||||
want to contribute translations.
|
||||
|
||||
- Help (PRs and/or advocacy) with Minetest engine issues:
|
||||
- #9934: This bug is causing us to maintain a workaround in
|
||||
NodeCore which is fragile and keeps breaking, leading to
|
||||
significant network load for some clients.
|
||||
- #9377: This causes some annoyances when handling lux tools,
|
||||
and makes a certain mechanic blatant when it's intended to be
|
||||
subtle.
|
||||
- #7245: This is blocking making navigation challenges and
|
||||
distinguishing nodes with similar appearance into gameplay
|
||||
elements. Current open PR is #9315.
|
||||
- #7876: Causes a damage flash when a new player joins, or a
|
||||
player from before 2020-02-19 when max HP was changed.
|
||||
- TBD: It would be nice to be able to make the player neutrally
|
||||
buoyant (disable slow downward drift) in water/liquids. This
|
||||
probably needs to be supported explicitly by the MT client.
|
||||
- TBD: Bone attachment axes invert if there is any animation on
|
||||
that bone/axis. This is blocking the visible inventory
|
||||
feature. (MTG #2547, but it's probably an engine bug)
|
||||
- #7245: This is blocking making navigation challenges and
|
||||
distinguishing nodes with similar appearance into gameplay
|
||||
elements.
|
||||
- #8952: This causes hidden bases and other items to be visible
|
||||
through walls and other terrain in our MP server.
|
||||
- #8141: We want cleaner player name labels, and to move
|
||||
the touchtip from screen-space into node-space.
|
||||
- #9043: This bug requires NodeCore to maintain a workaround for
|
||||
the engine in its own code.
|
||||
- #9048: Causes player inventory sounds to be played at the wrong
|
||||
volume.
|
||||
- TBD: Engine should provide a standard way to make digparticles
|
||||
through walls when ent/player transfer distance is high; when
|
||||
low, instead it causes players/ents to be invisible even when
|
||||
terrain is loaded and visible, causing distant player activity
|
||||
to look like poltergeists.
|
||||
- #9912: Engine should provide a standard way to make digparticles
|
||||
that doesn't depend on using [combine and knowing exact source
|
||||
texture size (breaks texturepacks).
|
||||
- #6963: If this is implemented, we may have a more efficient
|
||||
way to handle "visinv" nodes, i.e. stacks, storage boxes,
|
||||
and other container nodes.
|
||||
|
||||
- Help with documentation
|
||||
- Improvements to the in-game guidance, esp. for onboarding new
|
||||
players, are wanted. Ideally we want to offer a spoiler-free
|
||||
experience by default, but want players to have options/resources
|
||||
in the event they can't figure something out.
|
||||
- Advising players where they can find external resources, or other
|
||||
sources of help, such as wikis, youtube, chatrooms, multiplayer
|
||||
servers, etc.
|
||||
- Work on improving the nodecore wiki itself.
|
||||
|
||||
- Improved versions of any art assets (sounds, textures, models).
|
||||
- All textures for base inclusion should be 16x (keep
|
||||
high-def textures to texture packs). Note that textures
|
||||
larger than 16x are allowed (and already used) in the game
|
||||
for textures that "spill over" into neighoring spaces, but
|
||||
the spatial resolution of 16 pixels per node is maintained.
|
||||
- It must be practical to maintain a consistent style for
|
||||
other assets, including future related ones, or the content
|
||||
being reworked should be mature and stable, independent of
|
||||
other content areas, and the new textures should mesh
|
||||
reasonably well with the existing style.
|
||||
- Alternatively, publish your mods, texturepacks, or soundpacks
|
||||
directly to the community, via ContentDB.
|
||||
- Replacements for nodeboxes and meshes that render faster (i.e.
|
||||
better FPS preservation when tons of them are around) on most
|
||||
or all systems are wanted.
|
||||
|
||||
- Publicity and player content:
|
||||
- Help spread NodeCore! Share your experiences, screenshots,
|
||||
@ -35,32 +75,5 @@ to the project!
|
||||
- Let the developers know if you have shared something about
|
||||
NodeCore, or would like guidance creating something to share.
|
||||
|
||||
- Improved versions of any art assets (sounds, textures, models).
|
||||
- All textures for base inclusion should be 16x (keep
|
||||
high-def textures to texture packs).
|
||||
- It must be practical to maintain a consistent style for
|
||||
other assets, including future related ones.
|
||||
- Alternatively, publish your mods, texturepacks, or soundpacks
|
||||
directly to the community, via ContentDB.
|
||||
- Nodebox replacements with significantly lower poly count
|
||||
are wanted. Pull in outer faces by 1/256 to avoid z-fighting
|
||||
under water.
|
||||
|
||||
- Help maintaining the hint system.
|
||||
- Development of hints often lags behind development of new
|
||||
features, sometimes significantly.
|
||||
- Hint organization and content is subject to improvement.
|
||||
|
||||
- Door animations.
|
||||
- These need to be relatively efficient, i.e. not involve
|
||||
a ton of node manipulation or spawning lots of entities.
|
||||
Of particular concern is network packet load on clients.
|
||||
- Something using animated entities (which could represent
|
||||
multiple nodes sharing an axis) could work well.
|
||||
- Alternatively, a reasonable particle effect? Something
|
||||
abstract is fine too, as long as it conveys a sense of
|
||||
movement to help players visualize what's moving and in
|
||||
what direction.
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
||||
|
@ -1,78 +0,0 @@
|
||||
========================================================================
|
||||
ICEBOX: Low-Priority Ideas
|
||||
------------------------------------------------------------------------
|
||||
|
||||
#### ##### #### # # ###### ##### ####
|
||||
# # # # # # # # # # #
|
||||
#### # # # # # # ##### # # ####
|
||||
# ##### # # # # # ##### #
|
||||
# # # # # # # # # # # #
|
||||
#### # #### # ###### ###### # # ####
|
||||
|
||||
- Rebuild falling_node and item entity from the ground up.
|
||||
- Refactor item_entity's scan method into scan_tunnel API for
|
||||
use by both item_entity and falling_node.
|
||||
- Add methods to settle as node or settle as stacks.
|
||||
- Add flags to force stack/item settlement.
|
||||
- Add method to try to settle item/node first, create ent only
|
||||
if settling fails.
|
||||
- On anything settling and a node being created, check space above
|
||||
for entities to early-settle.
|
||||
- Make falling_node try to find somewhere to place itself instead
|
||||
of displacing the node it landed on, convert to an item as a
|
||||
fallback.
|
||||
- Standardize collision detection, i.e. ignore node collision boxes
|
||||
and settle early based on full-node size.
|
||||
|
||||
- API for recursing through embedded inventories, e.g. in totes.
|
||||
- Lux reaction cannot sense other lux inside totes.
|
||||
|
||||
- Player APIs:
|
||||
- Physics/acceleration, for waterflow, conveyors, etc.
|
||||
|
||||
- When can we remove the issue7020 workaround?
|
||||
|
||||
- Lens strobing rate limiting of some kind?
|
||||
- Require cool-downs after a lot of toggling?
|
||||
- Could this be an accessibility issue?
|
||||
|
||||
- "Smart" optics placement?
|
||||
- Pick initial rotation automatically to have the most utility
|
||||
according to some heuristics.
|
||||
- May involve expanding or redesigning the optics API
|
||||
significantly...?
|
||||
|
||||
- Make separate walkable/non-walkable stack nodes.
|
||||
- Should sticks and eggcorns be non-walkable?
|
||||
|
||||
- Code Quality.
|
||||
- Scripts to validate dependency graph.
|
||||
- Tag deps directly in code at place of use.
|
||||
- Auto-generate mod.conf / depends.txt
|
||||
- Scripts for automatic metapackage mods?
|
||||
- Git hooks (and git hook setup scripts)?
|
||||
|
||||
- API Cleanup
|
||||
- Utils
|
||||
- Box mueller (and repeated box mueller sum) and exporand
|
||||
- Break up the nc_api monstrosity.
|
||||
- nc_api_base to create _G.nodecore and include for all.
|
||||
- nc_api metamod that just depends on ALL other api's.
|
||||
- nc_all metamod for 3rd party mod authors...?
|
||||
- Heat API
|
||||
- Unified heating/cooling number from env.
|
||||
- Proper API for burning up items
|
||||
- on_burn? burns_to?
|
||||
- Unify heat transformations into recipe system with
|
||||
cooking recipes?
|
||||
- Unify nc_items and visinv API.
|
||||
- Stack nodes are "special", get first-class support.
|
||||
|
||||
- Make neighbor/distance calcs consistent.
|
||||
- We're using scan_flood in some places, face checks in others,
|
||||
and find_nodes_in_area (cuboid) in others.
|
||||
- Diamond shape would be most consistent.
|
||||
- Should require face touching, not diagonal.
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
271
docs/ideas.txt
Normal file
271
docs/ideas.txt
Normal file
@ -0,0 +1,271 @@
|
||||
========================================================================
|
||||
IDEAS: Possible future additions/improvements to the game
|
||||
------------------------------------------------------------------------
|
||||
|
||||
#### ##### #### # # ###### ##### ####
|
||||
# # # # # # # # # # #
|
||||
#### # # # # # # ##### # # ####
|
||||
# ##### # # # # # ##### #
|
||||
# # # # # # # # # # # #
|
||||
#### # #### # ###### ###### # # ####
|
||||
|
||||
- Visual "subtitles" for sounds?
|
||||
- Use new image_waypoint HUD type; it works in new versions,
|
||||
invisible in old versions (graceful fallback).
|
||||
- An icon for each sound type.
|
||||
|
||||
- Separate air vs. node cursor?
|
||||
- Like the node vs. entity cursor, can we hide the cursor when
|
||||
pointing only at air?
|
||||
- Would server lag be too much?
|
||||
- This would integrate really well with a WAILA sort of thing.
|
||||
- Could totally revamp touchtips, and dynamic feel Lightning.
|
||||
- Use an image HUD so we can force mobile to display it too, so
|
||||
mobile players can use look dir too?
|
||||
|
||||
- Buff igniting
|
||||
- Make hot lode and other heated materials able to ignite
|
||||
- This was probably not already done just because we
|
||||
didn't have AISMs at the time, but we do now.
|
||||
- Reconsider lux fluid ignition again.
|
||||
- Maybe have rare "spark" events that can ignite?
|
||||
- Maybe have it involve proximity to other materials?
|
||||
- Water? Lava?
|
||||
- Optic beams?
|
||||
|
||||
- Chop frames, ladders, staves back down into sticks?
|
||||
|
||||
- Can we use glasslike_framed for shelves?
|
||||
- Alternate 2 versions of the registration based on y coord
|
||||
so it forces top/bottom faces to show
|
||||
|
||||
- More lode bar crafts:
|
||||
- Frames
|
||||
- Ladders?
|
||||
- Adzes?
|
||||
- chop+crumb -1 relative tier
|
||||
- cracky -2 relative tier
|
||||
- full durability
|
||||
- Should these be full lode or wood handle?
|
||||
- Rakes?
|
||||
- Return some prills after construction?
|
||||
- Make wear carry across heating/cooling recipes
|
||||
- Allow full-lode tools to be tempered
|
||||
- All these need to be recyclable.
|
||||
|
||||
- Piezo node for optics detects sounds?
|
||||
- Sounds emitted by mod stuff?
|
||||
- Footsteps?
|
||||
- Can be used as a BUD
|
||||
|
||||
- Lode tongs?
|
||||
- Craft from bars/rods (or lode adzes?).
|
||||
- Add an API to hot potato
|
||||
- Scan for all hot potato items and produce a list of slot->bool
|
||||
- If any items found with an on_hot_potato callback, pass them
|
||||
that list (and player, inv, etc) to be modified.
|
||||
- If slot is marked "safe" then no hot potato if items are in
|
||||
a slot adjacent to tongs.
|
||||
- If slot is not marked safe, mark it safe if tongs or any tool
|
||||
are wielded item.
|
||||
- Unmark safe any slots that don't contain hot things after
|
||||
hot potato check.
|
||||
|
||||
- Allow frame loose ends to be chopped off when placed next to other
|
||||
frames, so custom shapes can be made.
|
||||
|
||||
- Dungeon loot
|
||||
- Add recipe hints (prearranged nodes) as decorations?
|
||||
- Rows of shelves against walls. Very rarely lode crates.
|
||||
- Loot items in shelves, weighted pickrand(). Add a "margin" pick
|
||||
result with value of proportion of where in range the picked value
|
||||
was, and vary tool durability or stack count non-linearly by it.
|
||||
- Scattered items on floor. Most are from loot tables, some are
|
||||
crates or storeboxes.
|
||||
|
||||
- A lode "mace" tool with all dig groups?
|
||||
- Would require reevaluatng recipe priority, or tool modality.
|
||||
|
||||
- Make lava easier to find at a distance visually
|
||||
- Particles, like cherenkov?
|
||||
|
||||
- New Darkness feature:
|
||||
- Keep track of queue of recent "safe spots" for player:
|
||||
in sunlight, on solid ground or climbable etc.
|
||||
- Also check for being completely entombed in solid non-climbables.
|
||||
- Track player darkness, search for nearby light. Keep track of recent hit/miss (ring/queue).
|
||||
- If player is in TOTAL darkness for long enough to be certain, then do "fugue" teleportation.
|
||||
- Fade screen to black slowly via HUD (maybe have an API for this for skyrealms).
|
||||
- Drop all items.
|
||||
- Apply a temporary debuff...?
|
||||
- Teleport player back to recent safe spots until we find one, or run out.
|
||||
- Fade screen back from black.
|
||||
|
||||
- Should tool appearance vary based on wear?
|
||||
- Make "fresh" vs. "worn" tools (for purposes of their usability
|
||||
in crafts) have a distinct look?
|
||||
|
||||
- Tree sap
|
||||
- Stumps with air above exude, become dry stumps.
|
||||
- Use as a glue/resin in recipes.
|
||||
- Make longer-life torches?
|
||||
- Stick optics in place to prevent rotating?
|
||||
|
||||
- Straw/thatch?
|
||||
|
||||
- Domain Wall Sensor
|
||||
- Adapt from sztest?
|
||||
- Field Generator?
|
||||
- Power an annealed lode block from 2 opposite faces.
|
||||
- Generates particle effect at mapblock boundary.
|
||||
- Particle effect with lux fluid and/or cobble?
|
||||
- Create particle effect around player while carrying lux in
|
||||
inventory?
|
||||
- Maybe only if the lux is higher activation tier?
|
||||
|
||||
- Should ash and derivatives have a fertilizing effect?
|
||||
- Maybe wet/tacky stuccos?
|
||||
|
||||
- Optic locking
|
||||
- Prevent accidental rotation.
|
||||
- Use tree sap / glue?
|
||||
- Make "glued" optic node?
|
||||
- Detect adjacent glue node?
|
||||
- Apply frame, make framed optics?
|
||||
- Hammer into place with certain tool?
|
||||
|
||||
- Door Automation
|
||||
- Should have press recipes for stickcraft, i.e. staves,
|
||||
frames, ladders.
|
||||
- Press tools (or tool heads) into nodes to activate other
|
||||
pummel recipes like chopping.
|
||||
- Mount tool heads on frames to make machine tools?
|
||||
- Press recipes for digging.
|
||||
- If pushing a node (or toolhead backed by node) and there
|
||||
is a climbable walkable behind it, or a storebox, dig the
|
||||
node and push it through climable as catapult, or into
|
||||
storebox if it fits.
|
||||
- Pressing stack of 1 node places it, instead of pummeling it.
|
||||
Can pummel on the second push.
|
||||
- Should doors trigger place recipes when blocked?
|
||||
- Push players?
|
||||
- Need more door materials: lode, glasses
|
||||
|
||||
- Renewability Gap
|
||||
- Renewable but not generatable
|
||||
- Sponges: Sprout under water from peat+sand?
|
||||
- Lode
|
||||
- Lux
|
||||
- Water sources.
|
||||
- Sustainable but not renewable
|
||||
- Not sustainable
|
||||
- Lava sources.
|
||||
- Surround stone with lava to melt?
|
||||
|
||||
- Threats
|
||||
- Visceral
|
||||
- Flammable/toxic gas?
|
||||
- Monsters: stone-lurkers, mimics.
|
||||
- Complex multi-node mimic that eats tools you try to dig it with,
|
||||
stores them in core node(s) inside somewhere to be recovered.
|
||||
- Lightning, meteor strikes?
|
||||
- Creeping
|
||||
- Cellular automata hazards.
|
||||
- From exploration, delving too deep, leaving things to rot, etc.
|
||||
- Blights, Fungi
|
||||
- Termites, carpenter ants, other wood-eating inflictions?
|
||||
|
||||
- Lurk Ore
|
||||
- Moves freely among air-exposed stone while no player is looking.
|
||||
- Follows after player, attempting to cause harm.
|
||||
- Weakens nodes above/below player into falling nodes,
|
||||
e.g. loose cobble, gravel?
|
||||
- Steals items from player, drops onto ground or absorbs them
|
||||
into body? Saps tool durability?
|
||||
- Ignites flammables it passes by?
|
||||
- Downgrades or absorbs ores nearby by contact or air floodfill?
|
||||
- Creates illusionary nodes you can fall through?
|
||||
- Cannot be dug or damaged directly.
|
||||
- Digging it yields plain stone, but converts up to 2
|
||||
surrounding stone nodes into Lurk.
|
||||
- Need to dig all around it so it cannot move, then apply Some
|
||||
time-integrated process to convert it to useful form.
|
||||
|
||||
- New materials to craft with.
|
||||
- Dungeon materials, stonework?
|
||||
- Decorations for dungeons
|
||||
- Small plants? Reeds? Mallows?
|
||||
- Sea stars, anenome, coral, other underwater things?
|
||||
- Fungi, esp. tree-destroying ones, blight?
|
||||
- Oil, natural gas? Fossils and fossil fuels?
|
||||
- Geode, hydra crystals, radioactives?
|
||||
- Shipwrecks or alien tech
|
||||
- Slow-moving animals? Snails? Miniature spice worms?
|
||||
- Non-portable things, like "spawners" or wormholes
|
||||
- Tubers and taproots, cacti, and other "defensive" plantlife
|
||||
- Plant-like CA animals, like bee nests and clouds of bees?
|
||||
Termine mounds? Ant colonies? Coral?
|
||||
- Popeggcorn?
|
||||
- Ores that smelt via heating and then rapid quenching?
|
||||
- Things that cannot ever be dug, and must be moved only
|
||||
by in-world machinery?
|
||||
|
||||
- Vary player walking speed based on nodes under feet?
|
||||
|
||||
- Visual "craft guide" system?
|
||||
- Build a 3x3 work space out of wood/logs, place center node
|
||||
last and it will convert to a workbench node.
|
||||
- Workbench node will scan for potential recipe matches
|
||||
centered on the space above based on what's present
|
||||
and matches at least 1 non-air node, picks one.
|
||||
- Create display "ghost" entities representing items that
|
||||
can be placed to complete the recipe.
|
||||
|
||||
- Should tree growth rate start out faster but slow down?
|
||||
- This could make the decision to harvest trees early vs
|
||||
wait for them to mature more nuanced.
|
||||
|
||||
- Social features
|
||||
- Randomize player appearance/colors.
|
||||
- Shirt/pants, possibly w/ stripes/patterns
|
||||
- Skin color, hair color, eye color?
|
||||
- Add a "cloak" layer for cloaks, capes, over entire body
|
||||
- Make some control states / anims last a little longer, e.g.
|
||||
extend mining or waving anims to a second or so to make sure
|
||||
they're visible and not just flicker.
|
||||
|
||||
- Drop-in recipes, triggered on thrown or falling items settling?
|
||||
- Good for dangerous stuff, maybe?
|
||||
|
||||
- Compact signage via concrete/writing/stylus
|
||||
- Draw glyphs on a wall.
|
||||
- Place a lens focusing light from the wall onto a spot.
|
||||
- Put pliant concrete in that spot.
|
||||
- Make sure wall is adequately lit.
|
||||
- Etch the lens-facing side of the pliant concrete with stylus.
|
||||
- Create a "custom patterned" concrete sign block with letters etched
|
||||
onto it. Store in metadata, use ents to render, etc.
|
||||
|
||||
- Allow metalworking with wood tools?
|
||||
- Eat a lot of extra durability?
|
||||
|
||||
- Door animations.
|
||||
- These need to be relatively efficient, i.e. not involve
|
||||
a ton of node manipulation or spawning lots of entities.
|
||||
Of particular concern is network packet load on clients.
|
||||
- Something using animated entities (which could represent
|
||||
multiple nodes sharing an axis) could work well.
|
||||
- Alternatively, a reasonable particle effect? Something
|
||||
abstract is fine too, as long as it conveys a sense of
|
||||
movement to help players visualize what's moving and in
|
||||
what direction.
|
||||
|
||||
- Visual in-world hotbar
|
||||
- GreenXenith's visualbar mod
|
||||
- Replace hotbar, merge it with both bandolier and YCTIWY?
|
||||
- Players could be "pickpocketed" during normal gameplay.
|
||||
- Make a sound/visual to warn player.
|
||||
- Jordach's new first-person-attached entities feature?
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
136
docs/issues-code.txt
Normal file
136
docs/issues-code.txt
Normal file
@ -0,0 +1,136 @@
|
||||
========================================================================
|
||||
ISSUES-CODE: Issues related to code quality and APIs
|
||||
------------------------------------------------------------------------
|
||||
|
||||
#### ##### #### # # ###### ##### ####
|
||||
# # # # # # # # # # #
|
||||
#### # # # # # # ##### # # ####
|
||||
# ##### # # # # # ##### #
|
||||
# # # # # # # # # # # #
|
||||
#### # #### # ###### ###### # # ####
|
||||
|
||||
- Look into game default settings.
|
||||
- Change default ABM budget
|
||||
(https://github.com/minetest/minetest/pull/10290)
|
||||
|
||||
- Make door pusheability customizable
|
||||
- door_can_push or door_cannot_push groups/flags or something.
|
||||
- Allow override of standard falling_node check.
|
||||
|
||||
- Overhaul player health to work entirely virtual
|
||||
- Raise max up a lot to make room for fine grained falling
|
||||
damage so we can raise threshold
|
||||
- Consider falling damage add percent to all nodes?
|
||||
- Add API for doing fake damage effect using set hp
|
||||
|
||||
- Allow optics pending transaction to be flushed early
|
||||
- Optics interacting with doors are out of sync
|
||||
- May need to commit the optic state immediately when triggering
|
||||
doors so they get the correct current state.
|
||||
|
||||
- Consider full eversion of event handlers
|
||||
- Disallow (or automatically convert) traditional single-hanlders
|
||||
on all definitions
|
||||
- Use a register_on_something() method to hook pretty much
|
||||
everything
|
||||
|
||||
- Unify mkreg
|
||||
- Add validation/modifying and order comparison funcs
|
||||
- Use for recipes, mapgen_shared, playerstep, etc.
|
||||
- Consider replacing with register_generic():
|
||||
- Allow lazy registration, i.e. a register method that can
|
||||
register for things not yet defined, and allow later registration
|
||||
of the registration definition that will pick up those missed.
|
||||
- Define order for inv tabs
|
||||
|
||||
- Hint System Refactor
|
||||
- Move stats into an api layer to ensure availability
|
||||
- Simplify stats, track less detail, limit data growth.
|
||||
- Break up hints into each individual mod.
|
||||
- Add shortcuts for hint registrations, e.g. integrated with recipes.
|
||||
|
||||
- Transactional api ref localization
|
||||
- For certain large computations, like an optic processing, it may be
|
||||
worthwhile to capture some often-repeated functions like minetest.get_node
|
||||
as locals.
|
||||
- May need to test performance on a non-JIT build, where this is expected
|
||||
to have a larger impact, since JIT probably optimizes the difference away.
|
||||
|
||||
- Continue to chisel away at ABM perf issues.
|
||||
- Simplify or optimize existing ABMs
|
||||
- Convert things to DNTs.
|
||||
|
||||
- Some time-integral processes are not resetting when prereqs removed
|
||||
- Cooking resumes instead of resetting when fire removed.
|
||||
- Leaching resumes instead of resetting when water removed.
|
||||
|
||||
- Take advantage of the fact that players/inventories use a single shared
|
||||
metatable for player inventory arrangement hooks in nc_player_pickup,
|
||||
like we did for entity:set_properties.
|
||||
- Currently inv pickup logic isn't working and we're relying on
|
||||
rearrangement; need to resolve this one way or another.
|
||||
|
||||
- Make leaf decay group-driven for mod applicability.
|
||||
|
||||
- Switch some extended attributes to first-class support instead of modifying
|
||||
definition at registration time.
|
||||
- e.g. drop_in_place should hook the engine's dig event instead of
|
||||
registering an on_dig on the node, so inheritance works.
|
||||
|
||||
- Add a nodecore.inherit_node() helper that registers a node as a
|
||||
modified copy of another definition, e.g. for planted eggcorns copying
|
||||
dirt, door panels copying original materials, etc.
|
||||
|
||||
- Add an on_falling_check handler to replace check_single_for_falling custom
|
||||
hook in writing, and possibly other places.
|
||||
|
||||
- Should we create "recipe groups" to make it easier to specify
|
||||
equivalent recipes for hint purposes?
|
||||
|
||||
- Need to find a way to make AISMs work with falling_node.
|
||||
- Create ItemStack, run hooks, try to convert back to node
|
||||
(assume node and item meta map 1:1) and if it fails then
|
||||
spawn an item_ent.
|
||||
- Need this for amalgamation remelting.
|
||||
- Would it make sense to unify the item and falling_node ents?
|
||||
|
||||
- API for map-seed-deterministic scatter.
|
||||
- Given minp, maxp, seed and density, find all positions.
|
||||
- Use for sponges, lava/water springs, etc.
|
||||
|
||||
- Unify sponge growth logic so it can be used for mapgen, to ensure
|
||||
that spawned sponges match naturally-grown ones?
|
||||
|
||||
- Easier recipe API:
|
||||
- Use ascii art like ezschematic?
|
||||
- Aliases like "sides"/"corners"?
|
||||
- Make 3x3 recipes easier to define.
|
||||
|
||||
- Standardize visinv access API
|
||||
- stack_access(pos, node, dirfrom) - return booly
|
||||
whether access to inside stack is allowed.
|
||||
- Use for shelf API.
|
||||
- Use for touchtips inv access.
|
||||
- Genericize sponge logic using stack_access API
|
||||
|
||||
- Wandering fluids API for concrete, glass?
|
||||
- Configurable setting for generation count multiplier.
|
||||
|
||||
- API for recursing through embedded inventories, e.g. in totes.
|
||||
- Lux reaction cannot sense other lux inside totes.
|
||||
|
||||
- Scripts to validate dependency graph.
|
||||
- Tag deps directly in code at place of use.
|
||||
- Auto-generate mod.conf / depends.txt
|
||||
|
||||
- API Cleanup
|
||||
- Further nc_api break-up, clean up util functions.
|
||||
- Heat API
|
||||
- Quenched, Flames as numbers or nil?
|
||||
- Unify nc_items and visinv API.
|
||||
- Stack nodes are "special", get first-class support.
|
||||
- APIs for different kinds of "neighbor" scans
|
||||
- Face, edge, corner touching
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
25
docs/issues-docs.txt
Normal file
25
docs/issues-docs.txt
Normal file
@ -0,0 +1,25 @@
|
||||
========================================================================
|
||||
ISSUES-DOCS: Issues related to documentation
|
||||
------------------------------------------------------------------------
|
||||
|
||||
#### ##### #### # # ###### ##### ####
|
||||
# # # # # # # # # # #
|
||||
#### # # # # # # ##### # # ####
|
||||
# ##### # # # # # ##### #
|
||||
# # # # # # # # # # # #
|
||||
#### # #### # ###### ###### # # ####
|
||||
|
||||
- Add a code of conduct to project
|
||||
- Cover chat rules from discord, servers?
|
||||
|
||||
- Add a credits file with more extensive/specific credits, including
|
||||
non-copyrightable contributions to core project...?
|
||||
|
||||
- Design doc needs another shakedown.
|
||||
- Expecially: what has "nodecorian" come to mean?
|
||||
|
||||
- Need to clean out issues in wishlist.
|
||||
- Put some issues unlikely to be resolved on ice.
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
155
docs/issues-game.txt
Normal file
155
docs/issues-game.txt
Normal file
@ -0,0 +1,155 @@
|
||||
========================================================================
|
||||
ISSUES-GAME: Gameplay-affecting issues
|
||||
------------------------------------------------------------------------
|
||||
|
||||
#### ##### #### # # ###### ##### ####
|
||||
# # # # # # # # # # #
|
||||
#### # # # # # # ##### # # ####
|
||||
# ##### # # # # # ##### #
|
||||
# # # # # # # # # # # #
|
||||
#### # #### # ###### ###### # # ####
|
||||
|
||||
- Infuse rakes.
|
||||
- Larger radius?
|
||||
- Dig more types of stuff?
|
||||
- Silk touch?
|
||||
|
||||
- Stone softening rates feel off.
|
||||
- Once first stage of stone softens, others follow really
|
||||
quicky (exponential runaway basically).
|
||||
- If you leave stone soaking for a while, it looks like it
|
||||
basically softens all or nothing.
|
||||
- Can we smooth this out and make it less jarring?
|
||||
|
||||
- Buff wall scaling
|
||||
- Allow 1n lateral movement along wall
|
||||
- Makes outer wall corners navigable
|
||||
|
||||
- Silk Touch needs a review, possible nerf.
|
||||
- Review what materials are silk toucheable and which are not
|
||||
at this point, make adjustments if needed.
|
||||
- Maybe require some preparatory step, like a pummel into a
|
||||
prepped material before dig?
|
||||
|
||||
- Make a way to prevent crafting on place
|
||||
- Sneak? Aux?
|
||||
|
||||
- Buff lux burns significantly when touching lux.
|
||||
- Change lux burn model to operate like radiant heat instead?
|
||||
- Genericize radiant damage check to check a hook for damage
|
||||
applicability from nodes found
|
||||
- Maybe retire classic damage per second entirely
|
||||
- Maybe replace all normal damage with lux burns?
|
||||
- May need a hack to play damage effects when not altering hp.
|
||||
- Set hp lower and use 1+ delta, then let damage normalizer
|
||||
reset it?
|
||||
|
||||
- Consider changing wet/dry stack splitting
|
||||
- Currently, original stack remains in place, wetted/dried
|
||||
stack jumps out to new spot.
|
||||
- Instead, maybe wetted/dried stays in place and original
|
||||
jumps out (unless there's an adjacent wetted/dried stack to
|
||||
reuse).
|
||||
- More similar to the way flammable stack ignition works
|
||||
- Just meaner overall
|
||||
|
||||
- Consider largely retiring offline time-integral mechanics
|
||||
- Keepers:
|
||||
- Tree growth
|
||||
- Compost
|
||||
- Losers:
|
||||
- Sponge expiration
|
||||
- Torch expiration
|
||||
- Leaching
|
||||
- Repacking
|
||||
- Concrete
|
||||
- Lux renew
|
||||
- Logic: Action by a living thing (i.e. presence of player or
|
||||
microorganisms) is what keeps time ticking...?
|
||||
- Be more consistent with some non-offline mechanics like
|
||||
fire fuel consumption
|
||||
- "Fairness" issues, e.g. when sponge expiration happens before
|
||||
squeezer DNTs have had a chance to fire.
|
||||
- When we did torches via expiration metadata, the reason at the
|
||||
time was that there was no way to get them to tick reliably like
|
||||
we can with nodes; with AISMs this is no longer the case.
|
||||
|
||||
- Repose changes
|
||||
- Staves/rods should repose a lot less or not at all.
|
||||
- Rework repose to be based on amount of loose material below, not
|
||||
amount of distance available to fall? repose only needs to have a
|
||||
particular angle as measured on flat land?
|
||||
|
||||
- Hint system
|
||||
- Updates for everything since renewable ores (read changelog)
|
||||
- Agg may have been broken by concrete overhaul
|
||||
- Consider removing redundant or reverse paths, i.e. recycling
|
||||
or artificial resource recipes.
|
||||
- They complicate maintenance.
|
||||
- They are distracting for players (e.g. Emerald feeling
|
||||
COMPELLED to chop up a lode crate unnecessarily for the
|
||||
hint completion)
|
||||
- Hints could be re-expanded by 3rd party mods
|
||||
|
||||
- Delay lens full brightess?
|
||||
- Propagate optic signals immediately
|
||||
- Reach full brightness a few seconds later, to reduce map
|
||||
update work and prevent rapid strobes.
|
||||
- Strobes can cause excess lighting recalcs and block
|
||||
transfers, and can cause seizure problems for users
|
||||
|
||||
- Consider doing looktips and using a custom HUD to force crosshair
|
||||
for mobile as well.
|
||||
- Looktips can re-show any time lookdir changes, not just on
|
||||
change of target node name, so rejiggling the view can
|
||||
give more time to read tip.
|
||||
- Don't allow looktip if the "above" node is below a certain
|
||||
light level
|
||||
- Consider separating wieldtips and punch/looktips again.
|
||||
|
||||
- falling_node pillars settle out of order!
|
||||
- Also anectodal issues with falling nodes sometimes
|
||||
tunneling WAY upwards now, as observed with BXS's
|
||||
mine on NCC where gravel tunneled all the way up
|
||||
the ladder
|
||||
|
||||
- Tote issues:
|
||||
- Consider updating tote recipe.
|
||||
- Totes should do face-connected search for totables; don't pick up
|
||||
shelves only touching via a corner.
|
||||
|
||||
- Flammables should respond via AISM when bathed in fire or igniting
|
||||
liquids like molten glass or rock.
|
||||
|
||||
- Import YCTIWY as part of the base game.
|
||||
- Setting to disable entirely
|
||||
- Setting to disable compact mode
|
||||
- Setting for fresh/stale like bones; items become accessible
|
||||
only after time has passed since last login
|
||||
- Make the priv just to override any protections
|
||||
|
||||
- Shelf recipe reform
|
||||
- Add a "shelf frame" node made from wooden frames
|
||||
- Add appropriate material to shelf frame to make shelf
|
||||
- 2-stage construction should make it easier to discover
|
||||
- Shelf frame can gain its own distinct uses
|
||||
- e.g. some things can fall through it but not others.
|
||||
Items? Players? Fluids?
|
||||
|
||||
- Should there be pockets of softer stone at depth, like there is gravel?
|
||||
- Register ores for softer stone of each level
|
||||
- Maybe some ores for cobble and/or loose cobble?
|
||||
|
||||
- Consider checking for a nearby active player before running
|
||||
"fast-evolving" ABMs that don't normally work offline, like fire
|
||||
extinguishing/spreading?
|
||||
- This would make gameplay more fair for those who tend to
|
||||
go AFK suddenly and can't return for a long time.
|
||||
- This would reduce the gap between things that support the offline
|
||||
mechanic and those that don't between MP and SP.
|
||||
|
||||
- Make separate walkable/non-walkable stack nodes.
|
||||
- Should sticks and eggcorns be non-walkable?
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
@ -1,56 +0,0 @@
|
||||
========================================================================
|
||||
ISSUES: Bugs, Cleanup and Refinements
|
||||
------------------------------------------------------------------------
|
||||
|
||||
#### ##### #### # # ###### ##### ####
|
||||
# # # # # # # # # # #
|
||||
#### # # # # # # ##### # # ####
|
||||
# ##### # # # # # ##### #
|
||||
# # # # # # # # # # # #
|
||||
#### # #### # ###### ###### # # ####
|
||||
|
||||
- Hint updates:
|
||||
- Press recipe witnessing?
|
||||
- Rake.
|
||||
- Glass tank.
|
||||
- Optics states, e.g. active, shining, gated.
|
||||
- Injury/burns?
|
||||
- Full tote?
|
||||
- Dirt->sand leeching
|
||||
- Time for an audit again...
|
||||
|
||||
- Can we preserve non-buildable_to liquid sources when squashed,
|
||||
e.g. lava or glass clobbered by falling_node or item?
|
||||
|
||||
- Flammables should respond via AISM when bathed in fire or igniting
|
||||
liquids like molten glass or rock.
|
||||
|
||||
- Consider checking for a nearby active player before running
|
||||
"fast-evolving" ABMs that don't normally work offline, like fire
|
||||
extinguishing/spreading?
|
||||
- This would make gameplay more fair for those who tend to
|
||||
go AFK suddenly and can't return for a long time.
|
||||
|
||||
- Offline tick logic for spreading nodes
|
||||
- Use soaking API, calculate time to spread.
|
||||
- If actual time exceeds time to spread, pass soak depth on to
|
||||
new node that's been created, and trigger respread check.
|
||||
- Will have to do a lot of performance testing.
|
||||
|
||||
- Probably should be using hash_node_position insted of pos_to_string
|
||||
in many places where we don't support non-integer positions anyway
|
||||
|
||||
- CDB screenshot out of date.
|
||||
- Update nc_reative dependencies!
|
||||
- New optics
|
||||
- Full tote
|
||||
- Glass tank, lode crates
|
||||
- Lux
|
||||
- Torches
|
||||
|
||||
- Design doc needs another shakedown.
|
||||
|
||||
- Consider updating tote recipe.
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
56
docs/nonideas.txt
Normal file
56
docs/nonideas.txt
Normal file
@ -0,0 +1,56 @@
|
||||
========================================================================
|
||||
NONIDEAS: Ideas already considered and rejected
|
||||
------------------------------------------------------------------------
|
||||
|
||||
#### ##### #### # # ###### ##### ####
|
||||
# # # # # # # # # # #
|
||||
#### # # # # # # ##### # # ####
|
||||
# ##### # # # # # ##### #
|
||||
# # # # # # # # # # # #
|
||||
#### # #### # ###### ###### # # ####
|
||||
|
||||
- Anything Already Added
|
||||
- If something already exists in the game then it will not
|
||||
be added.
|
||||
- Please play though the game enough to understand what is
|
||||
already in the game before making suggestions.
|
||||
|
||||
- Mobs/Animals
|
||||
- Things that are "off-grid" are discouraged. Node-based
|
||||
"staybs" could at least fit the mechanics, but entity-based
|
||||
creatures that move freely do not. Use of /clearobjects
|
||||
should not remove key gameplay elements as long as the game
|
||||
is allowed to "quiesce" first.
|
||||
- Monsters that are easy to understand and deal with would not
|
||||
fit the games theme or play style. Threats need to be subtle,
|
||||
insidious, and indirect. Threats that offer no direct
|
||||
cathartic response (i.e. bashing it to death) also fit the
|
||||
theme better, as well as threats that can be turned around and
|
||||
exploited as resources once mastered (but remain a threat if
|
||||
handled carelessly).
|
||||
- NodeCore pacing requires that dangers to a player should be
|
||||
consequences of the player's own decisions, and not something
|
||||
that can be blamed on environment or chance. Having monsters
|
||||
spawn spontaneously and stalk the player would be problematic.
|
||||
- NodeCore "conservation" mechanics discourage having things
|
||||
spawn spontaneously at all, and they would need to be part of
|
||||
mapgen.
|
||||
|
||||
- Food/Hunger
|
||||
- Players are like ethereal beings who visit the world only
|
||||
temporarily and are not subject to injury or survival
|
||||
mechanics within the world.
|
||||
- Things that focus a mechanic on/through the player do not
|
||||
fit the world-centric/node-centric theme of the game.
|
||||
- Using food items to provide things like temporary buffs is
|
||||
likely to be a lot of effort and likely to be skipped by most
|
||||
players.
|
||||
|
||||
- Beds
|
||||
- There is no night to skip, and players have no need for sleep.
|
||||
- Bed-like structures can be made out of existing nodes. Purely
|
||||
decorative elements that are not fungible do not fit the
|
||||
game's design.
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
68
docs/releng.txt
Normal file
68
docs/releng.txt
Normal file
@ -0,0 +1,68 @@
|
||||
========================================================================
|
||||
RELENG: Release engineering and version support
|
||||
------------------------------------------------------------------------
|
||||
#### ##### #### # # ###### ##### ####
|
||||
# # # # # # # # # # #
|
||||
#### # # # # # # ##### # # ####
|
||||
# ##### # # # # # ##### #
|
||||
# # # # # # # # # # # #
|
||||
#### # #### # ###### ###### # # ####
|
||||
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
VERSION POLICY
|
||||
--------------
|
||||
|
||||
Version support should go as far back as:
|
||||
- One official minor release (e.g. #.#) prior to the latest across all
|
||||
platforms.
|
||||
- The latest officially supported release for each platform.
|
||||
This means that during the 5.2 release, we support 5.2, 5.1, and 5.0
|
||||
(because android is stuck on 5.0). When 5.3 is released and brings
|
||||
back current android support, we will drop 5.0 and 5.1, since all
|
||||
platforms will be at 5.3, and thus 5.2 will be the earliest.
|
||||
|
||||
Version support should go as far forward as:
|
||||
Support the current latest release at all times. Test the game out on
|
||||
dev versions so we can be prepared to support the next release as soon
|
||||
as it happens.
|
||||
|
||||
ENGINE/FORK POLICY
|
||||
------------------
|
||||
|
||||
NodeCore is only designed to fully support the official minetest.net
|
||||
game engine at this time, on all supported desktop and mobile
|
||||
platforms.
|
||||
|
||||
Forks may be unofficially supported if they are 100% API-compatible
|
||||
with an officially-supported engine, or if there is benefit to
|
||||
supporting them and they require only negligible changes/maintenance
|
||||
to get working.
|
||||
|
||||
Compatible forks will not explicitly be blocked from running NodeCore
|
||||
if they are capable of running it. Nags/warnings may be added for
|
||||
such engines, but only if they have the potential to cause significant
|
||||
disruption, such as generating excessive frivolous support issues,
|
||||
allowing cheating, or providing an altered game experience without
|
||||
indication that it does not represent the original.
|
||||
|
||||
NEW MT RELEASE PROCESS
|
||||
----------------------
|
||||
|
||||
- Wait for a grace period (standard 1 week) after new MT release before
|
||||
evaluating EOS for previous versions.
|
||||
- Reevaluate the policy and decide which version(s) need EOS
|
||||
- Check CDB for version strings and update .cdbrelease.lua
|
||||
- Check this doc for special TODO items related to release
|
||||
|
||||
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
|
||||
|
||||
- After 5.2 EOS:
|
||||
- Change bandolier slot items back to upright_sprite
|
||||
- Consider switching touchtips to waypoint HUDs now that
|
||||
hiding distance is an options.
|
||||
- Switch ents to using on_step moveresult for collision
|
||||
detection instead of checking nodes directly.
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
160
docs/roadmap.txt
160
docs/roadmap.txt
@ -1,160 +0,0 @@
|
||||
========================================================================
|
||||
ROADMAP: Large New Development Projects
|
||||
------------------------------------------------------------------------
|
||||
|
||||
#### ##### #### # # ###### ##### ####
|
||||
# # # # # # # # # # #
|
||||
#### # # # # # # ##### # # ####
|
||||
# ##### # # # # # ##### #
|
||||
# # # # # # # # # # # #
|
||||
#### # #### # ###### ###### # # ####
|
||||
|
||||
- Consider upstreaming nc_stucco, maybe into nc_concrete?
|
||||
- Credit Avicennia G a.k.a. Tereno Johnson
|
||||
- Stylus from stick+chip, stick+prill, etc. using "scratchy" group.
|
||||
- Add materials for mud+ash, sand+ash, add coal lump to agg.
|
||||
- All materials work like concrete, falling, liquefy with water.
|
||||
- All of them cure to a tacky state first, then to dry.
|
||||
- Become tacky if molded, cure to lower material otherwise.
|
||||
- Use soaking. Etching allowed to reset timer?
|
||||
- Include a few etched patterns. Separate mask and noise layers.
|
||||
- bricky, meshy, barry, icebox, enol, bordythin, gkey, bindy
|
||||
- Not relocatable
|
||||
- dry digs to cobble, dirt, sand, etc.
|
||||
- tacky undiggable until it cures (like a liquid)
|
||||
- Cheaper materials have shorter liquid, longer tacky phase
|
||||
- Standardize wandering liquid API?
|
||||
- Wander frequency, dist limit
|
||||
- Generation limit params
|
||||
- Curing time
|
||||
- Curing check (e.g. for quenching)
|
||||
- Time and gen cure methods
|
||||
|
||||
- Make stone bricks or other building materials?
|
||||
- Pummel stone w/ lux+ pick?
|
||||
|
||||
- Door Automation
|
||||
- Should have press recipes for stickcraft, i.e. staves,
|
||||
frames, ladders.
|
||||
- Press tools (or tool heads) into nodes to activate other
|
||||
pummel recipes like chopping.
|
||||
- Mount tool heads on frames to make machine tools?
|
||||
- Press recipes for digging.
|
||||
- If pushing a node (or toolhead backed by node) and there
|
||||
is a climbable walkable behind it, or a storebox, dig the
|
||||
node and push it through climable as catapult, or into
|
||||
storebox if it fits.
|
||||
- Pressing stack of 1 node places it, instead of pummeling it.
|
||||
Can pummel on the second push.
|
||||
- Should doors trigger place recipes when blocked?
|
||||
- Push players?
|
||||
- Need more door materials: lode, glasses
|
||||
|
||||
- Standardize visinv access API
|
||||
- stack_access(pos, node, dirfrom) - return booly
|
||||
whether access to inside stack is allowed.
|
||||
- Use for shelf API.
|
||||
- Use for touchtips inv access.
|
||||
- Genericize sponge logic using stack_access API
|
||||
|
||||
- Wandering fluids API for concrete, glass, lava?
|
||||
- Configurable setting for generation count multiplier.
|
||||
|
||||
- Lava quenching, new material?
|
||||
- Seepstone?
|
||||
- Lava wandering.
|
||||
- Concentrations of lava should melt nearyby stone
|
||||
- Dependent on hardness of stone
|
||||
- Lava near fringes should spontaneously quench.
|
||||
|
||||
- Should there be pockets of softer stone at depth, like there is gravel?
|
||||
|
||||
- Domain Wall Sensor
|
||||
- Adapt from sztest?
|
||||
- Field Generator?
|
||||
- Power an annealed lode block from 2 opposite faces.
|
||||
- Generates particle effect at mapblock boundary.
|
||||
- Particle effect with lux fluid and/or cobble?
|
||||
|
||||
- Water and lava surface springs.
|
||||
- Access to water for forges.
|
||||
- Access to lava for lighting, firestarting, glass?
|
||||
|
||||
- Renewability Gap
|
||||
- Renewable but not generatable
|
||||
- Sponges: Sprout under water from peat+sand?
|
||||
- Water sources.
|
||||
- Sustainable but not renewable
|
||||
- Lode: Infuse lode into eggcorns -> lodecorns -> tree-farming for lode?
|
||||
- Lux: Infuse lode cobble to make lux cobble?
|
||||
- Lava sources.
|
||||
- Completely lossy
|
||||
- Hard stone: harden using nearby heat sources?
|
||||
|
||||
- Threats
|
||||
- Visceral
|
||||
- Flammable/toxic gas?
|
||||
- Monsters: stone-lurkers, mimics.
|
||||
- Lightning, meteor strikes?
|
||||
- Creeping
|
||||
- Cellular automata hazards.
|
||||
- From exploration, delving too deep, leaving things to rot, etc.
|
||||
- Blights, Fungi
|
||||
|
||||
- Lurk Ore
|
||||
- Moves freely among air-exposed stone while no player is looking.
|
||||
- Follows after player, attempting to cause harm.
|
||||
- Weakens nodes above/below player into falling nodes,
|
||||
e.g. loose cobble, gravel?
|
||||
- Steals items from player, drops onto ground or absorbs them
|
||||
into body? Saps tool durability?
|
||||
- Ignites flammables it passes by?
|
||||
- Downgrades or absorbs ores nearby by contact or air floodfill?
|
||||
- Creates illusionary nodes you can fall through?
|
||||
- Cannot be dug or damaged directly.
|
||||
- Digging it yields plain stone, but converts up to 2
|
||||
surrounding stone nodes into Lurk.
|
||||
- Need to dig all around it so it cannot move, then apply Some
|
||||
time-integrated process to convert it to useful form.
|
||||
|
||||
- Social features
|
||||
- Randomize player appearance/colors.
|
||||
- Shirt/pants, possibly w/ stripes/patterns
|
||||
- Skin color, hair color, eye color?
|
||||
|
||||
- New materials to craft with.
|
||||
- Dungeon materials, stonework?
|
||||
- Decorations for dungeons
|
||||
- Tree sap from stumps? Resin? Rubber? Shellac?
|
||||
- Small plants? Reeds? Mallows?
|
||||
- Sea stars, anenome, coral, other underwater things?
|
||||
- Fungi, esp. tree-destroying ones, blight?
|
||||
- Oil, natural gas? Fossils and fossil fuels?
|
||||
- Geode, hydra crystals, radioactives?
|
||||
- Shipwrecks or alien tech
|
||||
- Slow-moving animals? Snails? Miniature spice worms?
|
||||
- Non-portable things, like "spawners" or wormholes
|
||||
- Tubers and taproots, cacti, and other "defensive" plantlife
|
||||
- Plant-like CA animals, like bee nests and clouds of bees?
|
||||
Termine mounds? Ant colonies? Coral?
|
||||
- Popeggcorn?
|
||||
- Ores that smelt via heating and then rapid quenching?
|
||||
- Things that cannot ever be dug, and must be moved only
|
||||
by in-world machinery?
|
||||
|
||||
- Fancy hotbar.
|
||||
- Build hotbar texture dynamically from pieces and texturemods.
|
||||
- Inventory items can have a hotbar_texture associated with them to
|
||||
override the default for that slot.
|
||||
- Make virtual items invisible on their own, use hotbar texture for them.
|
||||
- Injuries show torn/cracked slot.
|
||||
- Lux burns show partially melted slot.
|
||||
- Need to also alter the selection texture based on wield index.
|
||||
- Tick delay...
|
||||
|
||||
- Vary player walking speed based on nodes under feet?
|
||||
|
||||
- Use gravity vector to make flowing water push the player?
|
||||
|
||||
........................................................................
|
||||
========================================================================
|
1
docs/screenshot-world/.gitignore
vendored
1
docs/screenshot-world/.gitignore
vendored
@ -6,4 +6,5 @@ mod_storage
|
||||
players.*
|
||||
players
|
||||
nc_api.template.tr
|
||||
texturepack_override.template.txt
|
||||
world.mt
|
||||
|
22
docs/screenshot-world/README
Normal file
22
docs/screenshot-world/README
Normal file
@ -0,0 +1,22 @@
|
||||
------------------------------------------------------------------------
|
||||
|
||||
This world is maintained as a "standard" screenshot to show a visual
|
||||
example of a plausible game scene, including a variety of in-game
|
||||
elements. It can be used freely (MIT licensed like the rest of the
|
||||
game) for making screenshots for texture packs.
|
||||
|
||||
How To Use:
|
||||
- Copy or symlink this dir into ~/.minetest/worlds, or wherever your
|
||||
minetest worlds are stored.
|
||||
- Copy the world.mt.dist file to world.mt.
|
||||
- Enter the world (singleplayer or "host game"; either is fine).
|
||||
- Do NOT move the mouse or any other controls; keep your exact position
|
||||
and looking angle. If you mess up, leave and rejoin.
|
||||
- Hide the chat (F2) and wait for on-screen messages to fade.
|
||||
- Select the "empty" hotbar slot #6.
|
||||
- Resize your window to the largest size possible, with a ~16:9 or
|
||||
~16:10 aspect ratio.
|
||||
- Hold the zoom key (and no other key).
|
||||
- Capture an in-game screenshot (F12).
|
||||
|
||||
------------------------------------------------------------------------
|
Binary file not shown.
@ -38,37 +38,15 @@ mgv7_np_cavern = {
|
||||
octaves = 5
|
||||
persistence = 0.63
|
||||
}
|
||||
mgv7_cave_width = 0.09
|
||||
mg_biome_np_heat = {
|
||||
mgv7_np_floatland = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 50
|
||||
scale = 50
|
||||
spread = (1000,1000,1000)
|
||||
seed = 5349
|
||||
octaves = 3
|
||||
persistence = 0.5
|
||||
}
|
||||
mgv7_lava_depth = -256
|
||||
mgv7_np_mount_height = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 256
|
||||
scale = 112
|
||||
spread = (1000,1000,1000)
|
||||
seed = 72449
|
||||
octaves = 3
|
||||
persistence = 0.6
|
||||
}
|
||||
mg_biome_np_humidity_blend = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
lacunarity = 1.618
|
||||
offset = 0
|
||||
scale = 1.5
|
||||
spread = (8,8,8)
|
||||
seed = 90003
|
||||
octaves = 2
|
||||
persistence = 1
|
||||
scale = 0.7
|
||||
spread = (384,96,384)
|
||||
seed = 1009
|
||||
octaves = 4
|
||||
persistence = 0.75
|
||||
}
|
||||
mgv7_np_ridge = {
|
||||
flags = defaults
|
||||
@ -80,28 +58,61 @@ mgv7_np_ridge = {
|
||||
octaves = 4
|
||||
persistence = 0.75
|
||||
}
|
||||
mgv7_large_cave_depth = -33
|
||||
mg_biome_np_humidity = {
|
||||
mgv7_np_mountain = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 50
|
||||
scale = 50
|
||||
spread = (1000,1000,1000)
|
||||
seed = 842
|
||||
octaves = 3
|
||||
persistence = 0.5
|
||||
offset = -0.6
|
||||
scale = 1
|
||||
spread = (250,350,250)
|
||||
seed = 5333
|
||||
octaves = 5
|
||||
persistence = 0.63
|
||||
}
|
||||
mg_biome_np_heat_blend = {
|
||||
mgv7_floatland_ymax = 4096
|
||||
mgv7_np_ridge_uwater = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 0
|
||||
scale = 1
|
||||
spread = (1000,1000,1000)
|
||||
seed = 85039
|
||||
octaves = 5
|
||||
persistence = 0.6
|
||||
}
|
||||
mgv7_mount_zero_level = 0
|
||||
mg_biome_np_humidity_blend = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 0
|
||||
scale = 1.5
|
||||
spread = (8,8,8)
|
||||
seed = 13
|
||||
seed = 90003
|
||||
octaves = 2
|
||||
persistence = 1
|
||||
}
|
||||
mgv7_floatland_level = 1280
|
||||
mgv7_small_cave_num_min = 0
|
||||
mgv7_large_cave_flooded = 0.5
|
||||
mg_biome_np_heat = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 50
|
||||
scale = 50
|
||||
spread = (1000,1000,1000)
|
||||
seed = 5349
|
||||
octaves = 3
|
||||
persistence = 0.5
|
||||
}
|
||||
mgv7_np_mount_height = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 256
|
||||
scale = 112
|
||||
spread = (1000,1000,1000)
|
||||
seed = 72449
|
||||
octaves = 3
|
||||
persistence = 0.6
|
||||
}
|
||||
mgv7_small_cave_num_max = 0
|
||||
mgv7_np_terrain_base = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
@ -112,19 +123,8 @@ mgv7_np_terrain_base = {
|
||||
octaves = 5
|
||||
persistence = 0.6
|
||||
}
|
||||
mgv7_np_float_base_height = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 48
|
||||
scale = 24
|
||||
spread = (300,300,300)
|
||||
seed = 907
|
||||
octaves = 4
|
||||
persistence = 0.7
|
||||
}
|
||||
seed = 14531853857515683775
|
||||
water_level = 1
|
||||
mapgen_limit = 31000
|
||||
mg_name = v7
|
||||
mgv7_cavern_threshold = 0.7
|
||||
mgv7_dungeon_ymin = -31000
|
||||
@ -140,19 +140,36 @@ mgv7_np_height_select = {
|
||||
octaves = 6
|
||||
persistence = 0.7
|
||||
}
|
||||
mgv7_np_mountain = {
|
||||
mg_biome_np_heat_blend = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = -0.6
|
||||
scale = 1
|
||||
spread = (250,350,250)
|
||||
seed = 5333
|
||||
octaves = 5
|
||||
persistence = 0.63
|
||||
offset = 0
|
||||
scale = 1.5
|
||||
spread = (8,8,8)
|
||||
seed = 13
|
||||
octaves = 2
|
||||
persistence = 1
|
||||
}
|
||||
mgv7_shadow_limit = 1024
|
||||
mgv7_float_mount_height = 128
|
||||
mgv7_float_mount_exponent = 0.75
|
||||
mgv7_floatland_density = -0.6
|
||||
mgv7_cave_width = 0.09
|
||||
mg_biome_np_humidity = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 50
|
||||
scale = 50
|
||||
spread = (1000,1000,1000)
|
||||
seed = 842
|
||||
octaves = 3
|
||||
persistence = 0.5
|
||||
}
|
||||
mgv7_floatland_taper = 256
|
||||
mgv7_floatland_ywater = -31000
|
||||
mgv7_large_cave_depth = -33
|
||||
mgv7_floatland_ymin = 1024
|
||||
mapgen_limit = 31000
|
||||
mgv7_float_taper_exp = 2
|
||||
mgv7_large_cave_num_min = 0
|
||||
mgv7_large_cave_num_max = 2
|
||||
mgv7_np_terrain_persist = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
@ -166,7 +183,6 @@ mgv7_np_terrain_persist = {
|
||||
mgv7_cavern_limit = -256
|
||||
mgv7_cavern_taper = 256
|
||||
mgv7_dungeon_ymax = 31000
|
||||
mgv7_float_mount_density = 0.6
|
||||
mgv7_np_terrain_alt = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
@ -188,25 +204,4 @@ mgv7_np_filler_depth = {
|
||||
octaves = 3
|
||||
persistence = 0.7
|
||||
}
|
||||
mgv7_mount_zero_level = 0
|
||||
mgv7_np_ridge_uwater = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = 0
|
||||
scale = 1
|
||||
spread = (1000,1000,1000)
|
||||
seed = 85039
|
||||
octaves = 5
|
||||
persistence = 0.6
|
||||
}
|
||||
mgv7_np_floatland_base = {
|
||||
flags = defaults
|
||||
lacunarity = 2
|
||||
offset = -0.6
|
||||
scale = 1.5
|
||||
spread = (600,600,600)
|
||||
seed = 114
|
||||
octaves = 5
|
||||
persistence = 0.6
|
||||
}
|
||||
[end_of_params]
|
||||
|
@ -1,3 +1,2 @@
|
||||
gameid = nodecore
|
||||
backend = sqlite3
|
||||
load_mod_nc_reative = true
|
||||
|
18
docs/screenshot-world/worldmods/altsky/init.lua
Normal file
18
docs/screenshot-world/worldmods/altsky/init.lua
Normal file
@ -0,0 +1,18 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local nodecore
|
||||
= nodecore
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local txr
|
||||
nodecore.register_playerstep({
|
||||
label = "skyrealm skybox",
|
||||
priority = -1000,
|
||||
action = function(_, data)
|
||||
if not txr then
|
||||
if not (data.sky and data.sky.textures) then return end
|
||||
txr = data.sky.textures[1]
|
||||
txr = {txr, txr, txr, txr, txr, txr}
|
||||
end
|
||||
data.sky.textures = txr
|
||||
end
|
||||
})
|
1
docs/screenshot-world/worldmods/altsky/mod.conf
Normal file
1
docs/screenshot-world/worldmods/altsky/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
depends = nc_api_all
|
73
docs/screenshot-world/worldmods/mockinv/init.lua
Normal file
73
docs/screenshot-world/worldmods/mockinv/init.lua
Normal file
@ -0,0 +1,73 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, minetest, nodecore, pairs, vector
|
||||
= ItemStack, minetest, nodecore, pairs, vector
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname();
|
||||
|
||||
local setinv = {
|
||||
{"nc_stonework:tool_pick", 1, 0.7},
|
||||
{"nc_stonework:tool_spade", 1, 0.8},
|
||||
{"nc_stonework:tool_hatchet", 1, 0.4},
|
||||
{"nc_stonework:tool_mallet", 1, 0.2},
|
||||
{"nc_stonework:chip", 54},
|
||||
{"air", 1, nil, "[combine:1x1"},
|
||||
{"nc_terrain:sand_loose", 14},
|
||||
{"nc_terrain:dirt_loose", 47}
|
||||
}
|
||||
|
||||
for _, v in pairs(setinv) do
|
||||
local n = modname .. ":" .. v[1]:gsub(":", "_")
|
||||
if not minetest.registered_items[n] then
|
||||
local def = minetest.registered_items[v[1]]
|
||||
minetest.register_item(n, {
|
||||
["type"] = def["type"],
|
||||
tiles = def.tiles,
|
||||
inventory_image = v[4] or def.inventory_image,
|
||||
wield_image = v[4] or def.wield_image,
|
||||
on_drop = function() return ItemStack("") end,
|
||||
on_place = function() end,
|
||||
on_use = function() end
|
||||
})
|
||||
end
|
||||
v[1] = n
|
||||
end
|
||||
|
||||
local startpos = {}
|
||||
local function setup(p)
|
||||
local inv = p:get_inventory()
|
||||
for i, v in pairs(setinv) do
|
||||
if v then
|
||||
local s = ItemStack(v[1])
|
||||
s:set_count(v[2])
|
||||
if v[3] then s:set_wear(65535 * v[3]) end
|
||||
inv:set_stack("main", i, s)
|
||||
end
|
||||
end
|
||||
local pname = p:get_player_name()
|
||||
minetest.after(0, function()
|
||||
p = minetest.get_player_by_name(pname)
|
||||
if not p then return end
|
||||
startpos[pname] = p:get_pos()
|
||||
end)
|
||||
end
|
||||
nodecore.register_on_joinplayer(setup)
|
||||
nodecore.register_on_respawnplayer(setup)
|
||||
|
||||
nodecore.register_playerstep({
|
||||
label = "mock inv clear",
|
||||
action = function(p)
|
||||
local pname = p:get_player_name()
|
||||
local pos = p:get_pos()
|
||||
local spos = startpos[pname]
|
||||
if not spos or vector.distance(pos, spos) < 1 then return end
|
||||
startpos[pname] = nil
|
||||
local inv = p:get_inventory()
|
||||
for i = 1, inv:get_size("main") do
|
||||
local sn = inv:get_stack("main", i):get_name()
|
||||
if sn:sub(1, #modname + 1) == modname .. ":" then
|
||||
inv:set_stack("main", i, "")
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
1
docs/screenshot-world/worldmods/mockinv/mod.conf
Normal file
1
docs/screenshot-world/worldmods/mockinv/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
depends = nc_api_all, nc_terrain, nc_stonework
|
7
docs/screenshot-world/worldmods/mockplayer/init.lua
Normal file
7
docs/screenshot-world/worldmods/mockplayer/init.lua
Normal file
@ -0,0 +1,7 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local include
|
||||
= include
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
include("wield")
|
||||
include("model")
|
1
docs/screenshot-world/worldmods/mockplayer/mod.conf
Normal file
1
docs/screenshot-world/worldmods/mockplayer/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
depends = nc_api_all, nc_player_model, nc_player_wield
|
71
docs/screenshot-world/worldmods/mockplayer/model.lua
Normal file
71
docs/screenshot-world/worldmods/mockplayer/model.lua
Normal file
@ -0,0 +1,71 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore, pairs, vector
|
||||
= minetest, nodecore, pairs, vector
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
|
||||
local anims = {}
|
||||
do
|
||||
local raw = {0, 53, 165}
|
||||
raw[#raw + 1] = raw[1]
|
||||
for i = 1, #raw - 1 do
|
||||
anims[raw[i]] = raw[i + 1]
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_entity(modname .. ":ent", {
|
||||
initial_properties = {
|
||||
visual = "mesh",
|
||||
visual_size = {x = 0.9, y = 0.9, z = 0.9},
|
||||
mesh = "nc_player_model.b3d",
|
||||
textures = {"nc_player_model_base.png"},
|
||||
collisionbox = {-0.25, 0, -0.25, 0.25, 2, 0.25},
|
||||
physical = true
|
||||
},
|
||||
get_staticdata = function(self)
|
||||
return minetest.serialize(self.data)
|
||||
end,
|
||||
on_activate = function(self, data)
|
||||
self.data = data and minetest.deserialize(data) or {}
|
||||
local obj = self.object
|
||||
obj:set_acceleration({x = 0, y = -10, z = 0})
|
||||
local anim = self.data.anim or 0
|
||||
obj:set_animation({x = anim, y = anim}, 1)
|
||||
nodecore.mock_player_wieldview(self)
|
||||
end,
|
||||
on_punch = function(self, whom)
|
||||
if not whom then return end
|
||||
local obj = self.object
|
||||
local ctl = whom:get_player_control()
|
||||
if ctl.RMB and ctl.sneak then
|
||||
return obj:remove()
|
||||
end
|
||||
if ctl.RMB then
|
||||
local pos = obj:get_pos()
|
||||
if not pos then return end
|
||||
pos = vector.add(pos, vector.multiply(vector.direction(
|
||||
whom:get_pos(), pos), 0.25))
|
||||
pos.y = pos.y + 1
|
||||
return obj:set_pos(pos)
|
||||
end
|
||||
if ctl.sneak then
|
||||
self.data.wield = {
|
||||
inv = whom:get_inventory():get_list("main"),
|
||||
widx = whom:get_wield_index()
|
||||
}
|
||||
for k, v in pairs(self.data.wield.inv) do
|
||||
self.data.wield.inv[k] = v:get_name()
|
||||
end
|
||||
nodecore.mock_player_wieldview(self)
|
||||
return
|
||||
end
|
||||
local pos = obj:get_pos()
|
||||
if not pos then return end
|
||||
local dir = vector.direction(pos, whom:get_pos())
|
||||
obj:set_yaw(minetest.dir_to_yaw(dir))
|
||||
local anim = anims[self.data.anim or 0]
|
||||
self.data.anim = anim
|
||||
obj:set_animation({x = anim, y = anim}, 1)
|
||||
end
|
||||
})
|
134
docs/screenshot-world/worldmods/mockplayer/wield.lua
Normal file
134
docs/screenshot-world/worldmods/mockplayer/wield.lua
Normal file
@ -0,0 +1,134 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore, pairs
|
||||
= minetest, nodecore, pairs
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
nodecore.amcoremod()
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
|
||||
local xyz = function(n) return {x = n, y = n, z = n} end
|
||||
local size_w_item = xyz(0.2)
|
||||
local size_w_tool = xyz(0.3)
|
||||
local size_slot = xyz(0.075)
|
||||
local size_item = xyz(0.1)
|
||||
|
||||
local hidden = {is_visible = false}
|
||||
local selslot = {is_visible = true, visual_size = size_slot, textures = {"nc_player_wield:sel"}}
|
||||
local emptyslot = {is_visible = true, visual_size = size_slot, textures = {"nc_player_wield:slot"}}
|
||||
|
||||
local function calcprops(itemname, iswield)
|
||||
local def = minetest.registered_items[itemname]
|
||||
if def and def.virtual_item then return hidden end
|
||||
if itemname == "" then return iswield and hidden or emptyslot end
|
||||
return {
|
||||
is_visible = true,
|
||||
visual_size = iswield and (def and def.type == "tool" and size_w_tool
|
||||
or size_w_item) or (itemname == "" and size_slot) or size_item,
|
||||
textures = {itemname},
|
||||
glow = def and (def.light_source or def.glow or 0)
|
||||
}
|
||||
end
|
||||
|
||||
local propcache_item = {}
|
||||
local propcache_wield = {}
|
||||
local function itemprops(itemname, iswield)
|
||||
local cache = iswield and propcache_wield or propcache_item
|
||||
local found = cache[itemname]
|
||||
if found then return found end
|
||||
found = calcprops(itemname, iswield)
|
||||
cache[itemname] = found
|
||||
return found
|
||||
end
|
||||
|
||||
local entname = modname .. ":wv"
|
||||
|
||||
local entdef
|
||||
entdef = {
|
||||
initial_properties = {
|
||||
hp_max = 1,
|
||||
physical = false,
|
||||
collide_with_objects = false,
|
||||
collisionbox = {0, 0, 0, 0, 0, 0},
|
||||
visual = "wielditem",
|
||||
textures = {""},
|
||||
is_visible = false,
|
||||
static_save = false,
|
||||
glow = 0
|
||||
},
|
||||
on_activate = function(self)
|
||||
self.on_step = entdef.on_step
|
||||
end,
|
||||
on_step = function(self)
|
||||
local conf = self.conf
|
||||
if not conf then return self.object:remove() end
|
||||
|
||||
local pdata = self.conf.ent.data.wield
|
||||
if pdata == nil then return self.object:remove() end
|
||||
if not pdata then return self.object:set_properties(hidden) end
|
||||
|
||||
if not self.att then
|
||||
self.att = true
|
||||
return self.object:set_attach(self.conf.ent.object,
|
||||
conf.bone, conf.apos, conf.arot)
|
||||
end
|
||||
|
||||
local widx = pdata.widx
|
||||
if conf.slot == widx then
|
||||
return self.object:set_properties(selslot)
|
||||
end
|
||||
|
||||
return self.object:set_properties(itemprops(
|
||||
pdata.inv[conf.slot or widx],
|
||||
not conf.slot))
|
||||
end
|
||||
}
|
||||
minetest.register_entity(entname, entdef)
|
||||
|
||||
function nodecore.mock_player_wieldview(ent)
|
||||
local pos = ent.object:get_pos()
|
||||
if not pos then return end
|
||||
|
||||
for _, wv in pairs(minetest.luaentities) do
|
||||
if wv.name == entname and wv.conf.ent == ent then
|
||||
wv.object:remove()
|
||||
end
|
||||
end
|
||||
|
||||
local function addslot(n, b, x, y, z, rx, ry, rz)
|
||||
local obj = minetest.add_entity(pos, entname)
|
||||
obj:get_luaentity().conf = {
|
||||
ent = ent,
|
||||
slot = n,
|
||||
pos = pos,
|
||||
bone = b,
|
||||
apos = {
|
||||
x = x,
|
||||
y = y,
|
||||
z = z
|
||||
},
|
||||
arot = {
|
||||
x = rx or 0,
|
||||
y = ry or 180,
|
||||
z = rz or 0
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
addslot(nil, "Arm_Right", 0, 7, 2, -90, 200, 90)
|
||||
|
||||
local function cslot(n, x, y, z)
|
||||
return addslot(n, "Bandolier", x * 0.8,
|
||||
0.75 + y * 1.6,
|
||||
-0.25 + z)
|
||||
end
|
||||
|
||||
cslot(1, 1.75, 0, 0)
|
||||
cslot(2, -1, 1, 0.05)
|
||||
cslot(3, 1, 2, 0.1)
|
||||
cslot(4, -1.75, 3, 0.02)
|
||||
cslot(5, 1.75, 3, 0.02)
|
||||
cslot(6, -1, 2, 0.1)
|
||||
cslot(7, 1, 1, 0.05)
|
||||
cslot(8, -1.75, 0, 0)
|
||||
end
|
26
docs/screenshot-world/worldmods/mocksetup/init.lua
Normal file
26
docs/screenshot-world/worldmods/mocksetup/init.lua
Normal file
@ -0,0 +1,26 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local math, minetest, nodecore
|
||||
= math, minetest, nodecore
|
||||
local math_pi
|
||||
= math.pi
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local function setup(p)
|
||||
local n = p:get_player_name()
|
||||
|
||||
local r = minetest.get_player_privs(n)
|
||||
r.fly = true
|
||||
r.fast = true
|
||||
r.give = true
|
||||
r.interact = true
|
||||
r.nc_reative = true
|
||||
minetest.set_player_privs(n, r)
|
||||
|
||||
p:set_pos({x = -112.6, y = 5, z = -92.6})
|
||||
p:set_look_horizontal(163.8 * math_pi / 180)
|
||||
p:set_look_vertical(9 * math_pi / 180)
|
||||
|
||||
p:hud_set_flags({crosshair = false})
|
||||
end
|
||||
nodecore.register_on_joinplayer(setup)
|
||||
nodecore.register_on_respawnplayer(setup)
|
1
docs/screenshot-world/worldmods/mocksetup/mod.conf
Normal file
1
docs/screenshot-world/worldmods/mocksetup/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
depends = nc_api_all
|
@ -1,70 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, math, minetest, pairs
|
||||
= ItemStack, math, minetest, pairs
|
||||
local math_pi
|
||||
= math.pi
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname();
|
||||
|
||||
minetest.settings:set("time_speed", 0)
|
||||
minetest.after(0, function() minetest.set_timeofday(0.5) end)
|
||||
|
||||
local setinv = {
|
||||
{"nc_stonework:tool_pick", 1, 0.7},
|
||||
{"nc_stonework:tool_spade", 1, 0.8},
|
||||
{"nc_stonework:tool_hatchet", 1, 0.4},
|
||||
{"nc_stonework:tool_mallet", 1, 0.2},
|
||||
{"nc_stonework:chip", 54},
|
||||
false,
|
||||
{"nc_terrain:sand_loose", 14},
|
||||
{"nc_terrain:dirt_loose", 47}
|
||||
}
|
||||
|
||||
for _, v in pairs(setinv) do
|
||||
if v then
|
||||
local n = modname .. ":" .. v[1]:gsub(":", "_")
|
||||
if not minetest.registered_items[n] then
|
||||
print(v[1])
|
||||
local def = minetest.registered_items[v[1]]
|
||||
minetest.register_item(n, {
|
||||
["type"] = def["type"],
|
||||
tiles = def.tiles,
|
||||
inventory_image = def.inventory_image,
|
||||
wield_image = def.wield_image,
|
||||
on_drop = function() return ItemStack("") end,
|
||||
on_place = function() end,
|
||||
on_use = function() end
|
||||
})
|
||||
end
|
||||
v[1] = n
|
||||
end
|
||||
end
|
||||
|
||||
local function setup(p)
|
||||
local n = p:get_player_name()
|
||||
|
||||
local r = minetest.get_player_privs(n)
|
||||
r.fly = true
|
||||
r.fast = true
|
||||
r.give = true
|
||||
r.interact = true
|
||||
r.nc_reative = true
|
||||
minetest.set_player_privs(n, r)
|
||||
|
||||
p:set_pos({x = -112.6, y = 5, z = -92.6})
|
||||
p:set_look_horizontal(163.8 * math_pi / 180)
|
||||
p:set_look_vertical(9 * math_pi / 180)
|
||||
|
||||
local inv = p:get_inventory()
|
||||
for i, v in pairs(setinv) do
|
||||
if v then
|
||||
local s = ItemStack(v[1])
|
||||
s:set_count(v[2])
|
||||
if v[3] then s:set_wear(65535 * v[3]) end
|
||||
inv:set_stack("main", i, s)
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest.register_on_joinplayer(setup)
|
||||
minetest.register_on_respawnplayer(setup)
|
@ -1 +0,0 @@
|
||||
depends = nc_terrain, nc_stonework
|
23
docs/screenshot-world/worldmods/noanim/init.lua
Normal file
23
docs/screenshot-world/worldmods/noanim/init.lua
Normal file
@ -0,0 +1,23 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore, pairs, rawset, type
|
||||
= minetest, nodecore, pairs, rawset, type
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local function noanim(t)
|
||||
if type(t) ~= "table" then return t end
|
||||
if t.animation then
|
||||
rawset(t.animation, "length", 1000000)
|
||||
end
|
||||
for _, v in pairs(t) do noanim(v) end
|
||||
return t
|
||||
end
|
||||
|
||||
for _, v in pairs(minetest.registered_nodes) do
|
||||
noanim(v.tiles)
|
||||
noanim(v.special_tiles)
|
||||
end
|
||||
|
||||
nodecore.register_on_register_item(function(_, def)
|
||||
noanim(def.tiles)
|
||||
noanim(def.special_tiles)
|
||||
end)
|
1
docs/screenshot-world/worldmods/noanim/mod.conf
Normal file
1
docs/screenshot-world/worldmods/noanim/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
depends = nc_api_all
|
60
docs/screenshot-world/worldmods/smokegen/init.lua
Normal file
60
docs/screenshot-world/worldmods/smokegen/init.lua
Normal file
@ -0,0 +1,60 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local PcgRandom, minetest, nodecore
|
||||
= PcgRandom, minetest, nodecore
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
|
||||
local genname = modname .. ":gen"
|
||||
|
||||
minetest.register_node(genname, {
|
||||
description = "Smoke Generator",
|
||||
inventory_image = "nc_api_craft_smoke.png",
|
||||
wield_image = "nc_api_craft_smoke.png",
|
||||
drawtype = "airlike",
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
walkable = false,
|
||||
groups = {snappy = 1}
|
||||
})
|
||||
|
||||
nodecore.register_dnt({
|
||||
name = genname,
|
||||
nodenames = {genname},
|
||||
time = 2,
|
||||
loop = true,
|
||||
ignore_stasis = true,
|
||||
action = function(pos)
|
||||
local pcg = PcgRandom(minetest.hash_node_position(pos))
|
||||
local rng = function() return pcg:next() / 2 ^ 32 + 0.5 end
|
||||
for _ = 1, 10 do
|
||||
local p = {
|
||||
x = pos.x + rng() - 0.5,
|
||||
y = pos.y + rng() * 2 - 0.5,
|
||||
z = pos.z + rng() - 0.5,
|
||||
}
|
||||
minetest.add_particle({
|
||||
pos = p,
|
||||
texture = "nc_api_craft_smoke.png",
|
||||
size = rng() * 2 + 1,
|
||||
expirationtime = 2.1
|
||||
})
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
nodecore.register_abm({
|
||||
label = "smokegen",
|
||||
nodenames = {genname},
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
ignore_stasis = true,
|
||||
action = function(pos) return nodecore.dnt_set(pos, genname) end
|
||||
})
|
||||
|
||||
nodecore.register_lbm({
|
||||
name = genname,
|
||||
nodenames = {genname},
|
||||
run_at_every_load = true,
|
||||
action = function(pos) return nodecore.dnt_reset(pos, genname, 0.01) end
|
||||
})
|
1
docs/screenshot-world/worldmods/smokegen/mod.conf
Normal file
1
docs/screenshot-world/worldmods/smokegen/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
depends = nc_api_all
|
6
docs/screenshot-world/worldmods/stasis/init.lua
Normal file
6
docs/screenshot-world/worldmods/stasis/init.lua
Normal file
@ -0,0 +1,6 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local nodecore
|
||||
= nodecore
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
nodecore.stasis = true
|
1
docs/screenshot-world/worldmods/stasis/mod.conf
Normal file
1
docs/screenshot-world/worldmods/stasis/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
depends = nc_api_all
|
35
mods/nc_api/compat_issue10127.lua
Normal file
35
mods/nc_api/compat_issue10127.lua
Normal file
@ -0,0 +1,35 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local getmetatable, minetest, pairs
|
||||
= getmetatable, minetest, pairs
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local publicfields = {
|
||||
formspec = true,
|
||||
infotext = true
|
||||
}
|
||||
|
||||
local function hook(meta)
|
||||
for k, v in pairs(meta) do
|
||||
if k:sub(1, 4) == "set_" then
|
||||
meta[k] = function(data, name, ...)
|
||||
if not publicfields[name] then
|
||||
data:mark_as_private(name)
|
||||
end
|
||||
return v(data, name, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local rawmeta = minetest.get_meta
|
||||
function minetest.get_meta(...)
|
||||
local raw = rawmeta(...)
|
||||
if raw then
|
||||
local meta = getmetatable(raw)
|
||||
if meta then
|
||||
hook(meta)
|
||||
minetest.get_meta = rawmeta
|
||||
end
|
||||
end
|
||||
return raw
|
||||
end
|
8
mods/nc_api/compat_legacyent.lua
Normal file
8
mods/nc_api/compat_legacyent.lua
Normal file
@ -0,0 +1,8 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest
|
||||
= minetest
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
minetest.register_entity("nc_api:stackent", {
|
||||
on_activate = function(self) return self.object:remove() end
|
||||
})
|
@ -1,22 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local math, vector
|
||||
= math, vector
|
||||
local math_atan2
|
||||
= math.atan2
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
vector.dot = vector.dot or function(a, b)
|
||||
return a.x * b.x + a.y * b.y + a.z * b.z
|
||||
end
|
||||
|
||||
vector.cross = vector.cross or function(a, b)
|
||||
return {
|
||||
x = a.y * b.z - a.z * b.y,
|
||||
y = a.z * b.x - a.x * b.z,
|
||||
z = a.x * b.y - a.y * b.x
|
||||
}
|
||||
end
|
||||
|
||||
vector.angle = vector.angle or function(a, b)
|
||||
return math_atan2(vector.length(vector.cross(a, b)), vector.dot(a, b))
|
||||
end
|
@ -20,7 +20,7 @@ function nodecore.digparticles(nodedef, partdef)
|
||||
elseif nodedef.inventory_image then
|
||||
img[1] = nodedef.inventory_image
|
||||
end
|
||||
if #img < 1 then return minetest.log("no pummel tile images found!") end
|
||||
if #img < 1 then return nodecore.log("warning", "no pummel tile images found!") end
|
||||
img = nodecore.pickrand(img)
|
||||
if img.name then img = img.name end
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
-- SKIP: include nodecore
|
||||
local dofile, error, minetest, pairs, rawget, rawset, setmetatable,
|
||||
table, type
|
||||
= dofile, error, minetest, pairs, rawget, rawset, setmetatable,
|
||||
table, type
|
||||
local table_concat, table_insert
|
||||
= table.concat, table.insert
|
||||
local dofile, error, ipairs, minetest, pairs, rawget, rawset,
|
||||
setmetatable, table, tostring, type
|
||||
= dofile, error, ipairs, minetest, pairs, rawget, rawset,
|
||||
setmetatable, table, tostring, type
|
||||
local table_concat, table_insert, table_sort
|
||||
= table.concat, table.insert, table.sort
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local nodecore = rawget(_G, "nodecore") or {}
|
||||
@ -42,11 +42,58 @@ setmetatable(nodecore, {
|
||||
end
|
||||
})
|
||||
|
||||
include("compat_vector")
|
||||
include("issue7020")
|
||||
include("issue9043")
|
||||
minetest.register_on_mods_loaded(function()
|
||||
for _, n in pairs(minetest.get_modnames()) do
|
||||
if n == "default" then
|
||||
error(nodecore.product
|
||||
.. " cannot be loaded on top of another game!")
|
||||
error()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local levels = {none = true, error = true, warning = true, action = true, info = true, verbose = true}
|
||||
function nodecore.log(level, ...)
|
||||
if not level or not levels[level] then error("invalid log level " .. tostring(level)) end
|
||||
return minetest.log(level, ...)
|
||||
end
|
||||
|
||||
nodecore.log("action", nodecore.product .. (nodecore.version and (" Version " .. nodecore.version)
|
||||
or " DEVELOPMENT VERSION"))
|
||||
|
||||
do
|
||||
local ticked = 0
|
||||
local function regreport()
|
||||
ticked = ticked + 1
|
||||
if ticked < 5 then return minetest.after(0, regreport) end
|
||||
local reg = "registered_"
|
||||
local t = {}
|
||||
for k, v in pairs(nodecore) do
|
||||
if k:sub(1, #reg) == reg and type(v) == "table" then
|
||||
local qty = 0
|
||||
for _ in pairs(v) do qty = qty + 1 end
|
||||
t[#t + 1] = "#" .. k .. " = " .. qty
|
||||
end
|
||||
end
|
||||
table_sort(t)
|
||||
for _, x in ipairs(t) do nodecore.log("action", x) end
|
||||
end
|
||||
minetest.after(0, regreport)
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local pname = player:get_player_name()
|
||||
local pinfo = minetest.get_player_information(pname)
|
||||
if pinfo.protocol_version < 39 then
|
||||
return minetest.kick_player(pname, "Outdated client")
|
||||
end
|
||||
end)
|
||||
|
||||
include("compat_issue10127")
|
||||
include("compat_legacyent")
|
||||
|
||||
include("util_misc")
|
||||
include("util_hookmeta")
|
||||
include("util_falling")
|
||||
include("util_scan_flood")
|
||||
include("util_node_is")
|
||||
@ -58,27 +105,29 @@ include("util_sound")
|
||||
include("util_translate")
|
||||
include("util_ezschematic")
|
||||
include("util_gametime")
|
||||
include("util_settlescan")
|
||||
include("util_texturemod")
|
||||
include("match")
|
||||
|
||||
include("fx_digparticles")
|
||||
|
||||
include("register_limited_abm")
|
||||
include("register_aism")
|
||||
include("register_soaking")
|
||||
include("register_ambiance")
|
||||
include("register_mods")
|
||||
include("register_entlabels")
|
||||
|
||||
include("mapgen_limits")
|
||||
include("mapgen_shared")
|
||||
|
||||
include("item_on_register")
|
||||
include("item_drop_in_place")
|
||||
include("item_falling_repose")
|
||||
include("item_falling_settle")
|
||||
include("item_alternate_loose")
|
||||
include("item_group_visinv")
|
||||
include("item_oldnames")
|
||||
include("item_tool_wears_to")
|
||||
include("item_tool_break")
|
||||
include("item_tool_sounds")
|
||||
include("item_tool_rakes")
|
||||
include("item_punch_sounds")
|
||||
include("item_sound_pitch")
|
||||
include("item_nodebox_zfighting")
|
||||
include("item_virtual")
|
||||
include("item_stackmax")
|
||||
include("item_touch_hurt")
|
||||
include("item_txp_overlay")
|
||||
include("item_tiledump")
|
||||
|
@ -1,22 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, pairs, setmetatable, type
|
||||
= minetest, pairs, setmetatable, type
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local bifn = minetest.registered_entities["__builtin:falling_node"]
|
||||
local falling = {
|
||||
set_node = function(self, node, meta, ...)
|
||||
meta = meta or {}
|
||||
if type(meta) ~= "table" then meta = meta:to_table() end
|
||||
for _, v1 in pairs(meta.inventory or {}) do
|
||||
for k2, v2 in pairs(v1) do
|
||||
if type(v2) == "userdata" then
|
||||
v1[k2] = v2:to_string()
|
||||
end
|
||||
end
|
||||
end
|
||||
return bifn.set_node(self, node, meta, ...)
|
||||
end
|
||||
}
|
||||
setmetatable(falling, bifn)
|
||||
minetest.register_entity(":__builtin:falling_node", falling)
|
@ -1,30 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, rawset
|
||||
= minetest, rawset
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
-- minetest.rotate_node uses sneak to invert the wall/floor orientation
|
||||
-- direction, but REMOVES the use of sneak to prevent right-click on the
|
||||
-- underlying node, which is a far more important function.
|
||||
|
||||
minetest.rotate_node = function(itemstack, placer, pointed_thing)
|
||||
local invert_wall = placer and placer:get_player_control().sneak or false
|
||||
local function commit()
|
||||
return minetest.rotate_and_place(itemstack, placer, pointed_thing, false,
|
||||
{invert_wall = invert_wall}, true)
|
||||
end
|
||||
if not invert_wall then return commit() end
|
||||
|
||||
local node = minetest.get_node_or_nil(pointed_thing.under)
|
||||
if not node then return end
|
||||
local def = minetest.registered_nodes[node.name]
|
||||
if not def.on_rightclick then return commit() end
|
||||
|
||||
local oldrc = def.on_rightclick
|
||||
local function helper(...)
|
||||
rawset(def, "on_rightclick", oldrc)
|
||||
return ...
|
||||
end
|
||||
rawset(def, "on_rightclick", nil)
|
||||
return helper(commit())
|
||||
end
|
@ -13,7 +13,9 @@ nodecore.register_on_register_item(function(_, def)
|
||||
local dip = def.drop_in_place
|
||||
if dip then
|
||||
if type(dip) ~= "table" then dip = {name = dip} end
|
||||
def.drop = def.drop or ""
|
||||
def.drop_non_silktouch = def.drop_non_silktouch
|
||||
or def.drop ~= "" and def.drop
|
||||
def.drop = ""
|
||||
def.node_dig_prediction = def.node_dig_prediction or dip.name
|
||||
local st = def.silktouch
|
||||
if st == nil then
|
||||
@ -29,10 +31,16 @@ nodecore.register_on_register_item(function(_, def)
|
||||
stack = digger:get_inventory():add_item("main",
|
||||
stack:to_string())
|
||||
if stack:is_empty() then return end
|
||||
do return nodecore.item_eject(pos, stack) end
|
||||
return nodecore.item_eject(pos, stack)
|
||||
end
|
||||
dip.param2 = node.param2
|
||||
minetest.set_node(pos, dip)
|
||||
if def.drop_non_silktouch then
|
||||
local stack = digger:get_inventory():add_item("main",
|
||||
def.drop_non_silktouch)
|
||||
if stack:is_empty() then return end
|
||||
nodecore.item_eject(pos, stack)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
@ -1,59 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore, pairs, setmetatable, vector
|
||||
= minetest, nodecore, pairs, setmetatable, vector
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local function signal(pos, ...)
|
||||
pos = vector.round(pos)
|
||||
pos.y = pos.y + 1
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 2)) do
|
||||
if vector.equals(vector.round(obj:get_pos()), pos) then
|
||||
obj = obj.get_luaentity and obj:get_luaentity()
|
||||
if obj and obj.on_force_settle then
|
||||
obj:on_force_settle(pos)
|
||||
return signal(pos, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
return ...
|
||||
end
|
||||
|
||||
local bifn = minetest.registered_entities["__builtin:falling_node"]
|
||||
local falling = {
|
||||
on_force_settle = function(self, pos)
|
||||
local oldnode = minetest.get_node(pos)
|
||||
if oldnode.name == "ignore" then
|
||||
return self.object:remove()
|
||||
end
|
||||
if oldnode.name ~= "air" then
|
||||
local olddef = minetest.registered_nodes[oldnode.name]
|
||||
if olddef and (not olddef.buildable_to)
|
||||
and (olddef.liquidtype ~= "none") then
|
||||
for _, item in pairs(minetest.get_node_drops(oldnode, "")) do
|
||||
minetest.add_item(pos, item)
|
||||
end
|
||||
end
|
||||
end
|
||||
local def = minetest.registered_nodes[self.node.name]
|
||||
minetest.set_node(pos, def and self.node or {name = "air"})
|
||||
if self.meta then minetest.get_meta(pos):from_table(self.meta) end
|
||||
nodecore.node_sound(pos, "place")
|
||||
self.object:remove()
|
||||
minetest.check_for_falling(pos)
|
||||
end,
|
||||
on_step = function(self, ...)
|
||||
local oldnode = minetest.add_node
|
||||
minetest.add_node = function(pos, node, ...)
|
||||
minetest.add_node = oldnode
|
||||
return signal(self.object:get_pos(),
|
||||
oldnode(pos, node, ...))
|
||||
end
|
||||
local function helper(...)
|
||||
minetest.add_node = oldnode
|
||||
return ...
|
||||
end
|
||||
return helper(bifn.on_step(self, ...))
|
||||
end
|
||||
}
|
||||
setmetatable(falling, bifn)
|
||||
minetest.register_entity(":__builtin:falling_node", falling)
|
@ -1,197 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, math, minetest, nodecore, pairs, setmetatable, type,
|
||||
vector
|
||||
= ItemStack, math, minetest, nodecore, pairs, setmetatable, type,
|
||||
vector
|
||||
local math_floor, math_pi, math_random, math_sqrt
|
||||
= math.floor, math.pi, math.random, math.sqrt
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
--[[
|
||||
Helpers for visible inventory. Use "visinv" node group.
|
||||
Sets up on_construct, after_destruct and an ABM to manage
|
||||
the visual entities.
|
||||
--]]
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- VISIBLE STACK ENTITY
|
||||
|
||||
function nodecore.stackentprops(stack, yaw, rotate, ss)
|
||||
local props = {
|
||||
hp_max = 1,
|
||||
physical = false,
|
||||
collide_with_objects = false,
|
||||
collisionbox = {0, 0, 0, 0, 0, 0},
|
||||
visual = "wielditem",
|
||||
visual_size = {x = 0.4, y = 0.4},
|
||||
textures = {""},
|
||||
spritediv = {x = 1, y = 1},
|
||||
initial_sprite_basepos = {x = 0, y = 0},
|
||||
is_visible = false,
|
||||
static_save = ss and true or false
|
||||
}
|
||||
local scale = 0
|
||||
yaw = yaw or 0
|
||||
if stack then
|
||||
if type(stack) == "string" then stack = ItemStack(stack) end
|
||||
props.is_visible = not stack:is_empty()
|
||||
props.textures[1] = stack:get_name()
|
||||
|
||||
local ratio = stack:get_count() / stack:get_stack_max()
|
||||
if ratio > 1 then ratio = 1 end
|
||||
scale = math_sqrt(ratio) * 0.15 + 0.25
|
||||
props.visual_size = {x = scale, y = scale}
|
||||
|
||||
props.automatic_rotate = rotate
|
||||
and rotate * 2 / math_sqrt(math_sqrt(ratio)) or nil
|
||||
|
||||
if ratio == 1 then ratio = 1 - (stack:get_wear() / 65536) end
|
||||
|
||||
if ratio ~= 1 then yaw = yaw + 1/8 + 3/8 * (1 - ratio) end
|
||||
yaw = yaw - 2 * math_floor(yaw / 2)
|
||||
end
|
||||
return props, scale, yaw * math_pi / 2
|
||||
end
|
||||
|
||||
minetest.register_entity(modname .. ":stackent", {
|
||||
initial_properties = nodecore.stackentprops(),
|
||||
is_stack = true,
|
||||
itemcheck = function(self)
|
||||
local pos = self.object:get_pos()
|
||||
local stack = nodecore.stack_get(pos)
|
||||
if not stack or stack:is_empty() then return self.object:remove() end
|
||||
|
||||
local rp = vector.round(pos)
|
||||
local props, scale, yaw = nodecore.stackentprops(stack,
|
||||
rp.x * 3 + rp.y * 5 + rp.z * 7)
|
||||
rp.y = rp.y + scale - 31/64
|
||||
|
||||
local obj = self.object
|
||||
obj:set_properties(props)
|
||||
obj:set_yaw(yaw)
|
||||
obj:set_pos(rp)
|
||||
end,
|
||||
on_activate = function(self)
|
||||
self.cktime = 0.00001
|
||||
end,
|
||||
on_step = function(self, dtime)
|
||||
self.cktime = (self.cktime or 0) - dtime
|
||||
if self.cktime > 0 then return end
|
||||
self.cktime = 1
|
||||
return self:itemcheck()
|
||||
end
|
||||
})
|
||||
|
||||
function nodecore.visinv_update_ents(pos, node)
|
||||
node = node or minetest.get_node(pos)
|
||||
local def = minetest.registered_items[node.name] or {}
|
||||
local max = def.groups and def.groups.visinv and 1 or 0
|
||||
|
||||
local found = {}
|
||||
for _, v in pairs(minetest.get_objects_inside_radius(pos, 0.5)) do
|
||||
if v and v.get_luaentity and v:get_luaentity()
|
||||
and v:get_luaentity().is_stack then
|
||||
found[#found + 1] = v
|
||||
end
|
||||
end
|
||||
|
||||
if #found < max then
|
||||
minetest.add_entity(pos, modname .. ":stackent")
|
||||
else
|
||||
while #found > max do
|
||||
found[#found]:remove()
|
||||
found[#found] = nil
|
||||
end
|
||||
end
|
||||
|
||||
return found
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- ITEM ENT APPEARANCE
|
||||
|
||||
local bii = minetest.registered_entities["__builtin:item"]
|
||||
local item = {
|
||||
set_item = function(self, ...)
|
||||
local realobj = self.object
|
||||
self.object = {}
|
||||
setmetatable(self.object, {
|
||||
__index = {
|
||||
set_properties = function() end
|
||||
}
|
||||
})
|
||||
bii.set_item(self, ...)
|
||||
self.object = realobj
|
||||
|
||||
self.rotdir = self.rotdir or math_random(1, 2) * 2 - 3
|
||||
local p, s = nodecore.stackentprops(self.itemstring, 0, self.rotdir, true)
|
||||
p.physical = true
|
||||
s = s / math_sqrt(2)
|
||||
p.collisionbox = {-s, -s, -s, s, s, s}
|
||||
return realobj:set_properties(p)
|
||||
end
|
||||
}
|
||||
setmetatable(item, bii)
|
||||
minetest.register_entity(":__builtin:item", item)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- NODE REGISTRATION HELPERS
|
||||
|
||||
function nodecore.visinv_on_construct(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
inv:set_size("solo", 1)
|
||||
nodecore.visinv_update_ents(pos)
|
||||
end
|
||||
|
||||
function nodecore.visinv_after_destruct(pos)
|
||||
nodecore.visinv_update_ents(pos)
|
||||
nodecore.fallcheck(pos)
|
||||
end
|
||||
|
||||
nodecore.register_on_register_item(function(_, def)
|
||||
if def.type ~= "node" then return end
|
||||
|
||||
def.groups = def.groups or {}
|
||||
|
||||
if def.groups.visinv then
|
||||
def.on_construct = def.on_construct or nodecore.visinv_on_construct
|
||||
def.after_destruct = def.after_destruct or nodecore.visinv_after_destruct
|
||||
end
|
||||
end)
|
||||
|
||||
nodecore.register_limited_abm({
|
||||
label = "VisInv Check",
|
||||
nodenames = {"group:visinv"},
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
action = function(...) return nodecore.visinv_update_ents(...) end
|
||||
})
|
||||
|
||||
------------------------------------------------------------------------
|
||||
-- DIG INVENTORY
|
||||
|
||||
local digpos
|
||||
local old_node_dig = minetest.node_dig
|
||||
minetest.node_dig = function(pos, ...)
|
||||
nodecore.stack_sounds(pos, "dug")
|
||||
local function helper(...)
|
||||
digpos = nil
|
||||
return ...
|
||||
end
|
||||
digpos = pos
|
||||
return helper(old_node_dig(pos, ...))
|
||||
end
|
||||
local old_get_node_drops = minetest.get_node_drops
|
||||
minetest.get_node_drops = function(...)
|
||||
local drops = old_get_node_drops(...)
|
||||
if not digpos then return drops end
|
||||
drops = drops or {}
|
||||
local stack = nodecore.stack_get(digpos)
|
||||
if stack and not stack:is_empty() then
|
||||
drops[#drops + 1] = stack
|
||||
end
|
||||
return drops
|
||||
end
|
@ -10,5 +10,6 @@ nodecore.register_on_register_item(function(name, def)
|
||||
minetest.register_alias(v, name)
|
||||
end
|
||||
end
|
||||
def.oldnames = nil
|
||||
end
|
||||
end)
|
||||
|
@ -1,11 +1,34 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore
|
||||
= minetest, nodecore
|
||||
local minetest, nodecore, vector
|
||||
= minetest, nodecore, vector
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local lasthit = {}
|
||||
|
||||
minetest.register_on_punchnode(function(pos, node, puncher)
|
||||
local function wearfx(puncher, wield)
|
||||
nodecore.sound_play("nc_api_toolwear",
|
||||
{object = puncher, gain = 0.5})
|
||||
local ppos = puncher:get_pos()
|
||||
if not ppos then return end
|
||||
ppos.y = ppos.y + puncher:get_properties().eye_height - 0.1
|
||||
local look = puncher:get_look_dir()
|
||||
for _ = 1, 3 do
|
||||
nodecore.digparticles(wield:get_definition(), {
|
||||
time = 0.05,
|
||||
amount = 1,
|
||||
minpos = ppos,
|
||||
maxpos = ppos,
|
||||
minvel = vector.add(look, {x = -1, y = -1, z = -1}),
|
||||
maxvel = vector.add(look, {x = 1, y = 1, z = 1}),
|
||||
minacc = {x = 0, y = -8, z = 0},
|
||||
maxacc = {x = 0, y = -8, z = 0},
|
||||
minexptime = 0.25,
|
||||
maxexptime = 1
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
nodecore.register_on_punchnode("node punch sounds", function(pos, node, puncher)
|
||||
if not nodecore.player_visible(puncher) then return end
|
||||
|
||||
local pname = puncher:get_player_name()
|
||||
@ -25,19 +48,37 @@ minetest.register_on_punchnode(function(pos, node, puncher)
|
||||
end
|
||||
|
||||
if wield:get_wear() >= (65536 * 0.95) then
|
||||
minetest.sound_play("nc_api_toolwear",
|
||||
{object = puncher, gain = 0.5})
|
||||
wearfx(puncher, wield)
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_dignode(function(pos, node, digger)
|
||||
nodecore.register_on_dignode("other player dig sounds", function(pos, node, digger)
|
||||
if not nodecore.player_visible(digger) then return end
|
||||
return nodecore.node_sound(pos, "dug",
|
||||
{node = node, except = digger})
|
||||
end)
|
||||
|
||||
minetest.register_on_placenode(function(pos, node, placer)
|
||||
nodecore.register_on_placenode("other player place sounds", function(pos, node, placer)
|
||||
if not nodecore.player_visible(placer) then return end
|
||||
return nodecore.node_sound(pos, "place",
|
||||
{node = node, except = placer})
|
||||
end)
|
||||
|
||||
-- Work around 5.2 making dig/place sounds redundant,
|
||||
-- but not backporting support to 5.0.
|
||||
local function block_builtin_sounds(func)
|
||||
return function(...)
|
||||
local old_sound = minetest.sound_play
|
||||
function minetest.sound_play(spec, param, ephem, ...)
|
||||
if ephem and param.exclude_player then return end
|
||||
return old_sound(spec, param, ephem, ...)
|
||||
end
|
||||
local function helper(...)
|
||||
minetest.sound_play = old_sound
|
||||
return ...
|
||||
end
|
||||
return helper(func(...))
|
||||
end
|
||||
end
|
||||
minetest.item_place_node = block_builtin_sounds(minetest.item_place_node)
|
||||
minetest.node_dig = block_builtin_sounds(minetest.node_dig)
|
||||
|
37
mods/nc_api/item_sound_pitch.lua
Normal file
37
mods/nc_api/item_sound_pitch.lua
Normal file
@ -0,0 +1,37 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local nodecore, pairs
|
||||
= nodecore, pairs
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local soundadj = {
|
||||
nc_optics_glassy = -3,
|
||||
nc_lode_annealed = -3,
|
||||
nc_lode_tempered = -3
|
||||
}
|
||||
local toolgroups = {
|
||||
cracky = true,
|
||||
thumpy = true,
|
||||
choppy = true,
|
||||
crumbly = true,
|
||||
snappy = true,
|
||||
scratchy = true
|
||||
}
|
||||
|
||||
nodecore.register_on_register_item(function(_, def)
|
||||
if def.type ~= "node" then return end
|
||||
local grp = def.groups
|
||||
if not grp then return end
|
||||
local snd = def.sounds
|
||||
if (not snd) or snd.no_level_pitch then return end
|
||||
local level = 0
|
||||
for k in pairs(toolgroups) do
|
||||
local l = grp[k]
|
||||
if l and l > level then level = l end
|
||||
end
|
||||
if level <= 0 then return end
|
||||
for _, v in pairs(snd) do
|
||||
local l = level + (v.name and soundadj[v.name] or 0)
|
||||
if l > 0 then v.pitch = (v.pitch or 1) * (1 + 0.1 * l) end
|
||||
end
|
||||
snd.no_level_pitch = true
|
||||
end)
|
99
mods/nc_api/item_tiledump.lua
Normal file
99
mods/nc_api/item_tiledump.lua
Normal file
@ -0,0 +1,99 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local io, ipairs, minetest, nodecore, pairs, table, tostring, type
|
||||
= io, ipairs, minetest, nodecore, pairs, table, tostring, type
|
||||
local io_open, table_concat, table_insert, table_sort
|
||||
= io.open, table.concat, table.insert, table.sort
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
if not nodecore.infodump() then return end
|
||||
|
||||
local faces = {
|
||||
"top",
|
||||
"bottom",
|
||||
"left",
|
||||
"right",
|
||||
"front",
|
||||
"back"
|
||||
}
|
||||
|
||||
local function tilize(tiles, max)
|
||||
if not tiles then return end
|
||||
tiles = minetest.deserialize(minetest.serialize(tiles))
|
||||
if not tiles then return end
|
||||
for k2, v2 in pairs(tiles) do
|
||||
tiles[k2] = (type(v2) == "table" and v2.name or v2.image) or v2
|
||||
end
|
||||
while max and #tiles > max do tiles[#tiles] = nil end
|
||||
while (#tiles > 1) and (tiles[#tiles] == tiles[#tiles - 1]) do
|
||||
tiles[#tiles] = nil
|
||||
end
|
||||
return tiles
|
||||
end
|
||||
|
||||
minetest.after(0, function()
|
||||
local function noblank(s) return s and tostring(s):match("%S") and tostring(s) or nil end
|
||||
|
||||
local data = {}
|
||||
for k, v in pairs(minetest.registered_items) do
|
||||
local key = noblank(v.description) or k
|
||||
key = key:gsub("%W+", "_"):lower()
|
||||
data[key] = data[key] or {}
|
||||
data[key][#data[key] + 1] = {
|
||||
technical_name = k,
|
||||
drawtype = v.drawtype,
|
||||
description = v.description,
|
||||
tiles = tilize(v.tiles, #faces),
|
||||
inventory_image = noblank(v.inventory_image),
|
||||
wield_image = noblank(v.wield_image),
|
||||
special_tiles = tilize(v.special_tiles),
|
||||
}
|
||||
end
|
||||
|
||||
local ents = {}
|
||||
for _, v in pairs(data) do
|
||||
local curent = {}
|
||||
local function writeln(s) curent[#curent + 1] = s end
|
||||
table_sort(v, function(a, b) return a.technical_name < b.technical_name end)
|
||||
local mesh
|
||||
for _, t in ipairs(v) do
|
||||
mesh = mesh or t.drawtype == "mesh"
|
||||
local tn = t.technical_name
|
||||
if t.tiles then
|
||||
local tt = t.tiles
|
||||
for i = #tt, 1, -1 do
|
||||
if i == #tt and i ~= #faces then
|
||||
writeln(tn .. " * " .. tt[i])
|
||||
else
|
||||
writeln(tn .. " " .. faces[i] .. " " .. tt[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
if t.special_tiles then
|
||||
for i, st in pairs(t.special_tiles) do
|
||||
writeln(tn .. " special_" .. i .. " " .. st)
|
||||
end
|
||||
end
|
||||
if noblank(t.inventory_image) then
|
||||
writeln(tn .. " inventory " .. t.inventory_image)
|
||||
end
|
||||
if noblank(t.wield_image) then
|
||||
writeln(tn .. " wield " .. t.wield_image)
|
||||
end
|
||||
end
|
||||
if #curent > 0 then
|
||||
if mesh then
|
||||
table_insert(curent, 1, "# <!> MESH DRAWTYPE; FACES MAY"
|
||||
.. " MISMATCH NAMES")
|
||||
end
|
||||
if noblank(v[1].description) then
|
||||
table_insert(curent, 1, "# " .. v[1].description)
|
||||
end
|
||||
ents[#ents + 1] = table_concat(curent, "\n")
|
||||
end
|
||||
end
|
||||
table_sort(ents)
|
||||
|
||||
local f = io_open(minetest.get_worldpath() .. "/texturepack_override.template.txt", "wb")
|
||||
f:write(table_concat(ents, "\n\n"))
|
||||
f:close()
|
||||
end)
|
43
mods/nc_api/item_tool_break.lua
Normal file
43
mods/nc_api/item_tool_break.lua
Normal file
@ -0,0 +1,43 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, nodecore, vector
|
||||
= ItemStack, nodecore, vector
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local function breakfx(who, def)
|
||||
if def.sound and def.sound.breaks then
|
||||
nodecore.sound_play(def.sound.breaks,
|
||||
{object = who, gain = 0.5})
|
||||
end
|
||||
local pos = who:get_pos()
|
||||
if pos then
|
||||
pos.y = pos.y + who:get_properties().eye_height - 0.1
|
||||
local look = vector.multiply(who:get_look_dir(), 2)
|
||||
for _ = 1, 5 do
|
||||
nodecore.digparticles(def, {
|
||||
time = 0.05,
|
||||
amount = 10,
|
||||
minpos = pos,
|
||||
maxpos = pos,
|
||||
minvel = vector.add(look, {x = -2, y = -2, z = -2}),
|
||||
maxvel = vector.add(look, {x = 2, y = 2, z = 2}),
|
||||
minacc = {x = 0, y = -8, z = 0},
|
||||
maxacc = {x = 0, y = -8, z = 0},
|
||||
minexptime = 0.25,
|
||||
maxexptime = 1
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
nodecore.register_on_register_item(function(_, def)
|
||||
if def.tool_wears_to or def.type == "tool" then
|
||||
def.after_use = def.after_use or function(what, who, _, dp)
|
||||
what:add_wear(dp.wear)
|
||||
if what:get_count() == 0 then
|
||||
breakfx(who, def)
|
||||
return ItemStack(def.tool_wears_to or "")
|
||||
end
|
||||
return what
|
||||
end
|
||||
end
|
||||
end)
|
125
mods/nc_api/item_tool_rakes.lua
Normal file
125
mods/nc_api/item_tool_rakes.lua
Normal file
@ -0,0 +1,125 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ipairs, math, minetest, nodecore, pairs, table, vector
|
||||
= ipairs, math, minetest, nodecore, pairs, table, vector
|
||||
local math_abs, math_max, table_sort
|
||||
= math.abs, math.max, table.sort
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
-- To register a tool as a rake, provie a callback:
|
||||
-- on_rake(pos, node, user) returns volume, checkfunc
|
||||
-- volume: ordered array of relative positions to be dug by rake
|
||||
-- checkfunc(pos, node, rel): determine if item can be dug
|
||||
-- rel: relative vector taken from volume array
|
||||
-- returns true to dig, nil to not dig, false to abort loop
|
||||
|
||||
local volcache = {}
|
||||
function nodecore.rake_volume(dxmax, dymax, dzmax)
|
||||
dzmax = dzmax or dxmax
|
||||
local key = minetest.pos_to_string({x = dxmax, y = dymax, z = dzmax})
|
||||
local rakepos = volcache[key]
|
||||
if rakepos then return rakepos end
|
||||
rakepos = {}
|
||||
for dy = -dymax, dymax do
|
||||
for dx = -dxmax, dxmax do
|
||||
for dz = -dzmax, dzmax do
|
||||
local v = {x = dx, y = dy, z = dz}
|
||||
v.d = vector.length(v)
|
||||
v.rxz = math_max(math_abs(dx), math_abs(dz))
|
||||
v.ry = math_abs(dy)
|
||||
rakepos[#rakepos + 1] = v
|
||||
end
|
||||
end
|
||||
end
|
||||
table_sort(rakepos, function(a, b) return a.d < b.d end)
|
||||
volcache[key] = rakepos
|
||||
return rakepos
|
||||
end
|
||||
|
||||
function nodecore.rake_index(filterfunc)
|
||||
local rakable = {}
|
||||
minetest.after(0, function()
|
||||
for k, v in pairs(minetest.registered_nodes) do
|
||||
if filterfunc(v, k) then
|
||||
rakable[k] = true
|
||||
end
|
||||
end
|
||||
end)
|
||||
return function(_, node) return rakable[node.name] end
|
||||
end
|
||||
|
||||
local function deferfall(func, ...)
|
||||
local oldfall = minetest.check_for_falling
|
||||
minetest.check_for_falling = nodecore.fallcheck
|
||||
local function helper(...)
|
||||
minetest.check_for_falling = oldfall
|
||||
return ...
|
||||
end
|
||||
return helper(func(...))
|
||||
end
|
||||
|
||||
local laststack
|
||||
local lastraking
|
||||
local old_node_dig = minetest.node_dig
|
||||
minetest.node_dig = function(pos, node, user, ...)
|
||||
laststack = nodecore.stack_get(pos)
|
||||
local wield = user and user:is_player() and user:get_wielded_item()
|
||||
lastraking = wield and (wield:get_definition() or {}).on_rake
|
||||
if lastraking then return deferfall(old_node_dig, pos, node, user, ...) end
|
||||
return old_node_dig(pos, node, user, ...)
|
||||
end
|
||||
|
||||
local stackonly = {}
|
||||
minetest.after(0, function()
|
||||
for k, v in pairs(minetest.registered_nodes) do
|
||||
if v.groups.is_stack_only then stackonly[k] = true end
|
||||
end
|
||||
end)
|
||||
local function matching(_, na, pb, nb)
|
||||
if stackonly[na.name] then
|
||||
if not stackonly[nb.name] then return end
|
||||
return (laststack and laststack:get_name()) == nodecore.stack_get(pb):get_name()
|
||||
end
|
||||
return na.name == nb.name
|
||||
end
|
||||
|
||||
local function dorake(volume, check, pos, node, user, ...)
|
||||
local sneak = user:get_player_control().sneak
|
||||
local objpos = {}
|
||||
for _, rel in ipairs(volume) do
|
||||
local p = vector.add(pos, rel)
|
||||
local n = minetest.get_node(p)
|
||||
local allow = (rel.d > 0 or nil) and check(p, n, rel)
|
||||
if allow == false then break end
|
||||
if allow and ((not sneak) or matching(pos, node, p, n)) then
|
||||
minetest.node_dig(p, n, user, ...)
|
||||
objpos[minetest.hash_node_position(p)] = true
|
||||
end
|
||||
end
|
||||
for _, lua in pairs(minetest.luaentities) do
|
||||
if lua.name == "__builtin:item" then
|
||||
local p = lua.object and lua.object:get_pos()
|
||||
if p and objpos[minetest.hash_node_position(
|
||||
vector.round(p))] then
|
||||
lua.object:set_pos(pos)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local rakelock = {}
|
||||
|
||||
nodecore.register_on_dignode("rake handling", function(pos, node, user, ...)
|
||||
local nowraking = lastraking
|
||||
if not nowraking then return end
|
||||
lastraking = nil
|
||||
|
||||
if not (pos and node and user and user:is_player()) then return end
|
||||
local volume, check = nowraking(pos, node, user, ...)
|
||||
if not (volume and check) then return end
|
||||
|
||||
local pname = user:get_player_name()
|
||||
if rakelock[pname] then return end
|
||||
rakelock[pname] = true
|
||||
deferfall(dorake, volume, check, pos, node, user, ...)
|
||||
rakelock[pname] = nil
|
||||
end)
|
@ -1,20 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, minetest, nodecore
|
||||
= ItemStack, minetest, nodecore
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
nodecore.register_on_register_item(function(_, def)
|
||||
if def.tool_wears_to then
|
||||
def.after_use = def.after_use or function(what, who, _, dp)
|
||||
what:add_wear(dp.wear)
|
||||
if what:get_count() == 0 then
|
||||
if def.sound and def.sound.breaks then
|
||||
minetest.sound_play(def.sound.breaks,
|
||||
{object = who, gain = 0.5})
|
||||
end
|
||||
return ItemStack(def.tool_wears_to)
|
||||
end
|
||||
return what
|
||||
end
|
||||
end
|
||||
end)
|
41
mods/nc_api/item_touch_hurt.lua
Normal file
41
mods/nc_api/item_touch_hurt.lua
Normal file
@ -0,0 +1,41 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, minetest, nodecore
|
||||
= ItemStack, minetest, nodecore
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local function toolcandig(wield, node)
|
||||
if (not wield) or wield:is_empty() then return end
|
||||
local def = node and node.name and minetest.registered_items[node.name]
|
||||
if not (def and def.groups) then return end
|
||||
local toolspeed = nodecore.toolspeed(wield, def.groups)
|
||||
if not toolspeed then return end
|
||||
local handspeed = nodecore.toolspeed(ItemStack(""), def.groups)
|
||||
return handspeed and (toolspeed < handspeed)
|
||||
end
|
||||
|
||||
nodecore.register_on_register_item(function(_, def)
|
||||
local dmg = def.pointable ~= false and def.groups
|
||||
and def.groups.damage_touch
|
||||
if not (dmg and dmg > 0) then return end
|
||||
|
||||
def.on_punch = def.on_punch or function(pos, node, puncher, ...)
|
||||
if puncher and puncher:is_player()
|
||||
and (not toolcandig(puncher:get_wielded_item(), node)) then
|
||||
nodecore.addphealth(puncher, -dmg, {
|
||||
nc_type = "node_touch_hurt",
|
||||
node = node
|
||||
})
|
||||
end
|
||||
return minetest.node_punch(pos, node, puncher, ...)
|
||||
end
|
||||
|
||||
def.on_scaling = def.on_scaling or function(_, _, player, node)
|
||||
if player and player:is_player() then
|
||||
nodecore.addphealth(player, -dmg, {
|
||||
nc_type = "node_touch_hurt",
|
||||
node = node
|
||||
})
|
||||
end
|
||||
return true
|
||||
end
|
||||
end)
|
58
mods/nc_api/item_txp_overlay.lua
Normal file
58
mods/nc_api/item_txp_overlay.lua
Normal file
@ -0,0 +1,58 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local io, minetest, nodecore, pairs, table, tostring, type
|
||||
= io, minetest, nodecore, pairs, table, tostring, type
|
||||
local io_open, table_concat, table_sort
|
||||
= io.open, table.concat, table.sort
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local missing = {}
|
||||
|
||||
minetest.after(0, function()
|
||||
local t = {}
|
||||
for k in pairs(missing) do t[#t + 1] = k end
|
||||
if #t < 1 then
|
||||
return nodecore.log("action", "txp override images ok")
|
||||
end
|
||||
table_sort(t)
|
||||
nodecore.log("warning", "missing txp override images:\n\t"
|
||||
.. table_concat(t, "\n\t"))
|
||||
end)
|
||||
|
||||
local function overlay(name, img, imgtype, force)
|
||||
if type(img) == "table" then
|
||||
local t = {}
|
||||
for k, v in pairs(img) do
|
||||
if type(k) == "number" then
|
||||
t[k] = overlay(name, v, imgtype .. tostring(k), force)
|
||||
elseif k == "name" then
|
||||
t[k] = overlay(name, v, imgtype, force)
|
||||
else
|
||||
t[k] = v
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
if (not img) or (img == "") or (type(img) ~= "string")
|
||||
or (not (force or img:match("%^"))) or img:match("%^txp_") then return img end
|
||||
|
||||
local tpath = "txp_" .. name:gsub("^%W+", "")
|
||||
:gsub("%W+", "_") .. "_" .. imgtype .. ".png"
|
||||
|
||||
local fullpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
.. "/textures/" .. tpath
|
||||
local f = io_open(fullpath, "rb")
|
||||
if not f then
|
||||
missing[fullpath] = img
|
||||
return img
|
||||
end
|
||||
f:close()
|
||||
|
||||
return tostring(nodecore.tmod(img):add(tpath):makealpha(255, 254, 2))
|
||||
end
|
||||
|
||||
nodecore.register_on_register_item(function(name, def)
|
||||
def.inventory_image = overlay(name, def.inventory_image, "inv")
|
||||
def.wield_image = overlay(name, def.wield_image, "wield")
|
||||
def.special_tiles = overlay(name, def.special_tiles, "special", true)
|
||||
end)
|
@ -1,6 +1,6 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, minetest, nodecore, setmetatable
|
||||
= ItemStack, minetest, nodecore, setmetatable
|
||||
local ItemStack, minetest, nodecore
|
||||
= ItemStack, minetest, nodecore
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local function isvirtual(item)
|
||||
@ -17,13 +17,3 @@ local function guard(func)
|
||||
end
|
||||
minetest.spawn_item = guard(minetest.spawn_item)
|
||||
minetest.add_item = guard(minetest.add_item)
|
||||
|
||||
local bii = minetest.registered_entities["__builtin:item"]
|
||||
local newbii = {
|
||||
on_activate = function(self, ...)
|
||||
bii.on_activate(self, ...)
|
||||
if isvirtual(self.itemstring) then return self.object:remove() end
|
||||
end
|
||||
}
|
||||
setmetatable(newbii, bii)
|
||||
minetest.register_entity(":__builtin:item", newbii)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# textdomain: nc_api
|
||||
(C)2018-2019 by Aaron Suen <warr1024@@gmail.com>=(C)2018-2019 から Aaron Suen <warr1024@@gmail.com>
|
||||
(C)2018-2020 by Aaron Suen <warr1024@@gmail.com>=(C)2018-2020 から Aaron Suen <warr1024@@gmail.com>
|
||||
(and 1 more hint)=(さらに1つのヒント)
|
||||
(and @1 more hints)=(さらに@1つのヒント)
|
||||
|
@ -1,8 +1,9 @@
|
||||
# textdomain: nc_api
|
||||
(C)2018-2019 by Aaron Suen <warr1024@@gmail.com>=(C)2018-2019 por Aaron Suen <war1024@@gmail.com>
|
||||
(C)2018-2020 by Aaron Suen <warr1024@@gmail.com>=(C)2018-2020 por Aaron Suen <war1024@@gmail.com>
|
||||
(and 1 more hint)=( e mais 1 dica)
|
||||
(and @1 more hints)=(e mais @1 dicas)
|
||||
- Crafting is done by building recipes in-world.=- A Criação de Itens é feita construindo as receitas pelo mundo.
|
||||
- Drop items onto ground to create stack nodes. They do not decay.=- Solte itens no chão para criar um node de itens amontoados. Eles não desaparecem.
|
||||
- If a recipe exists, you will see a special particle effect.=- Se uma receita existe, você verá um efeito especial de partícula sair do node.
|
||||
- Items picked up try to fit into the current selected slot first.=- Os itens pegados são primeiramente armazenados no espaço atualmente selecionado.
|
||||
- Order and specific face of placement may matter for crafting.=- A ordem e a face em que os itens são colocados pode importar no processo de criação.
|
||||
@ -10,10 +11,64 @@
|
||||
- Sneak+drop to count out single items from stack.=- Use os comandos de agachar e soltar juntos para soltar um só item.
|
||||
- Some recipes require "pummeling" a node.=- Algumas receitas necessitam que você "esmurre" um node.
|
||||
- Stacks may be pummeled, exact item count may matter.=- Amontoados de itens podem ser esmurrados, pode ser que precise de uma quantidade exata do item.
|
||||
- Stuck in a pit? Pummel surfaces barehanded to find places to climb.=[REMOVED].
|
||||
- There is NO inventory screen.=- NÃO EXISTE tela de inventário.
|
||||
- To pummel, punch a node repeatedly, WITHOUT digging.=- Para esmurrar, bata num node repetidamente, SEM QUEBRÁ-LO.
|
||||
- Wielded item, target face, and surrounding nodes may matter.=- O item segurado, a face do objeto alvo e os nodes ao redor podem importar durante a criação de algo.
|
||||
- You do not have to punch very fast (about 1 per second).=- Você não precisa bater muito rápido(basta 1 batida por segundo).
|
||||
...and 1 more hint...=...e mais 1 dica...
|
||||
...and @1 more hints...=...e mais @1 dicas...
|
||||
...have you activated a lens yet?=...você já ativou uma lente?
|
||||
...have you assembled a staff from sticks yet?=...você já montou um bastão usando gravetos?
|
||||
...have you assembled a wooden frame yet?=...você já montou um estrutura de madeira?
|
||||
...have you assembled a wooden ladder yet?=...você já montou uma escada de madeira?
|
||||
...have you assembled a wooden shelf yet?=...você já montou uma estante de madeira?
|
||||
...have you assembled a wooden tool yet?=...você já montou uma ferramenta de madeira?
|
||||
...have you assembled an adze out of sticks yet?=...você já montou um enxó usando gravetos?
|
||||
...have you assembled an annealed lode tote handle yet?=...você já montou uma alça de bolsa recozida?
|
||||
...have you bashed a plank into sticks yet?=...você já quebrou uma tábua em gravetos batendo nela?
|
||||
...have you broken cobble into chips yet?=...você já quebrou pedregulho em pedaços?
|
||||
...have you carved a wooden plank completely yet?=...você já entalhou completamente uma tábua de madeira?
|
||||
...have you carved wooden tool heads from planks yet?=...você já transformou uma tábua em cabeças de ferramentas, entalhando a madeira?
|
||||
...have you chipped chromatic glass into prisms yet?=...você já quebrou um vidro cromático em prismas, lascando o vidro?
|
||||
...have you chopped a lode cube into prills yet?=...você já quebrou um veio mineral em lascas, usando um machado?
|
||||
...have you chopped chromatic glass into lenses yet?=...você já quebrou vidro cromático em lentes, usando um machado?
|
||||
...have you chopped up charcoal yet?=...você já quebrou carvão usando um machado?
|
||||
...have you cold-forged an annealed lode tool head yet?=...você já fez uma forja fria de uma cabeça de ferramenta de veio mineral?
|
||||
...have you cold-forged lode down completely yet?=...você já fez uma forja fria de um veio mineral?
|
||||
...have you cooled molten glass into crude glass yet?=...você já esfriou vidro derretido para que este virasse vidro cru?
|
||||
...have you cut down a tree yet?=...você já cortou uma árvore?
|
||||
...have you dug up a tree stump yet?=...você já desenterrou um toco de árvore?
|
||||
...have you dug up dirt yet?=...você já cavou terra?
|
||||
...have you dug up gravel yet?=...você já cavou cascalho?
|
||||
...have you dug up lode ore yet?=...você já desenterrou um veio mineral?
|
||||
...have you dug up sand yet?=...você já cavou areia?
|
||||
...have you dug up stone yet?=...você já cavou pedra?
|
||||
...have you found a lode stratum yet?=...você já encontrou um estrato de veio mineral?
|
||||
...have you found ash yet?=...você já encontrou cinzas?
|
||||
...have you found charcoal yet?=...você já encontrou carvão?
|
||||
...have you found deep stone strata yet?=...você já encontrou um estrato de pedra profunda?
|
||||
...have you found dry leaves yet?=...você já encontrou folhas secas?
|
||||
...have you found eggcorns yet?=...você já encontrou semente de carvalho?
|
||||
...have you found lode ore yet?=...você já encontrou um veio mineral?
|
||||
...have you found molten rock yet?=...você já encontrou pedra derretida (lava)?
|
||||
...have you found sponges yet?=...você já encontrou esponjas?
|
||||
...have you found sticks yet?=...você já encontrou gravetos?
|
||||
...have you made fire by rubbing sticks together yet?=...você já fez fogo esfregando gravetos?
|
||||
...have you melted down lode metal yet?=...você já derreteu um veio mineral?
|
||||
...have you melted sand into glass yet?=...você já transformou areia em vidro, derretendo a areia?
|
||||
...have you molded molten glass into clear glass yet?=...você já moldou vidro derretido em vidro transparente?
|
||||
...have you packed high-quality charcoal yet?=...você já juntou carvão de alta qualidade?
|
||||
...have you packed stone chips back into cobble yet?=...você já juntou pedaços de pedra para que virassem pedregulho?
|
||||
...have you planted an eggcorn yet?=...você já plantou uma semente de carvalho?
|
||||
...have you produced light from a lens yet?=...você já gerou luz a partir de uma lente?
|
||||
...have you put a stone tip onto a tool yet?=...você já colocou uma ponta de pedra em uma ferramenta?
|
||||
...have you quenched molten glass into chromatic glass yet?=...você já temperou vidro derretido para que virasse vidro cromático?
|
||||
...have you sintered glowing lode into a cube yet?=...você já moldou veio mineral incandescente em um cubo?
|
||||
...have you split a tree trunk into planks yet?=...você já fez tábuas quebrando troncos de madeira?
|
||||
...have you tempered a lode anvil yet?=...você já fez uma bigorna temperando veio mineral?
|
||||
...have you tempered a lode tool head yet?=...você já fez uma cabeça de ferramenta temperando veio mineral?
|
||||
...have you welded a lode pick and spade together yet?=...você já soldou uma picareta de veio mineral com uma pá de veio mineral?
|
||||
About=Sobre
|
||||
Active Lens=Lente Ativa
|
||||
Active Prism=Prisma Ativo
|
||||
@ -78,8 +133,7 @@ Loose Lode Cobble=Veio de Pedregulho Solto
|
||||
Loose Sand=Areia Solta
|
||||
Molten Glass=Vidro Derretido
|
||||
Molten Rock=Pedra Derretida
|
||||
Player's Guide: Inventory Management=Guia do Jogador: Gerenciamento de Inventário
|
||||
Player's Guide: Pummeling Recipes=Guia do Jogador: Receitas por Esmurrada
|
||||
Not all game content is covered by hints. Explore!=As dicas não cobrem todo o conteúdo do jogo. Explore!
|
||||
Prism=Prisma
|
||||
Progress: @1 complete, @2 current, @3 future=Progresso: @1 completo(s), @2 atual(is), @3 futuro(s)
|
||||
Pummel=Esmurrar
|
||||
|
@ -1,32 +1,93 @@
|
||||
# textdomain: nc_api
|
||||
(C)2018-2019 by Aaron Suen <warr1024@@gmail.com>=(C)2018-2019 por Aaron Suen <war1024@@gmail.com>
|
||||
(C)2018-2020 by Aaron Suen <warr1024@@gmail.com>=(C)2018-2020 por Aaron Suen <war1024@@gmail.com>
|
||||
(and 1 more hint)=(e mais 1 dica)
|
||||
(and @1 more hints)=(e mais @1 dica)
|
||||
- "Furnaces" are not a thing; discover smelting with open flames.=-"Fornalhas" não existem; descubra como cozinhar com chamas à céu aberto.
|
||||
- Can't dig trees or grass? Search for sticks in the canopy.=- Não consegue quebrar árvores ou cavar? Procure por gravetos na cobertura.
|
||||
- Crafting is done by building recipes in-world.=- A Criação de Itens é feita construindo as receitas pelo mundo.
|
||||
- Do not use F5 debug info; it will mislead you!=- Não use as informações de debug do F5; Apenas irão lhe confundir!
|
||||
- Drop items onto ground to create stack nodes. They do not decay.=- Solte itens no chão para criar um node de itens amontoados. Eles não desaparecem.
|
||||
- Drop items onto ground to create stack nodes. They do not decay.=- Derrube itens no chão para criar pilhas de nodes. Eles não somem.
|
||||
- Hold/repeat right-click on walls/ceilings barehanded to climb.=- Segure/repita o clique direito em paredes/tetos para escalar com mãos nuas.
|
||||
- If a recipe exists, you will see a special particle effect.=- Se uma receita existe, você verá um efeito especial de partícula sair do node.
|
||||
- Items picked up try to fit into the current selected slot first.=- Os itens pegados são primeiramente armazenados no espaço atualmente selecionado.
|
||||
- Larger recipes are usually more symmetrical.=- Receitas maiores geralmente são mais simétricas.
|
||||
- Order and specific face of placement may matter for crafting.=- A ordem e a face em que os itens são colocados pode importar no processo de criação.
|
||||
- Ores may be hidden, but revealed by subtle clues in terrain.=sutis pelo terreno.
|
||||
- Recipes are time-based, punching faster does not speed up.=- Receitas são cronometradas, bater mais forte não afetará a velocidade delas.
|
||||
- Sneak+drop to count out single items from stack.=- Use os comandos de agachar e soltar juntos para soltar um só item.
|
||||
- Some recipes require "pummeling" a node.=- Algumas receitas necessitam que você "esmurre" um node.
|
||||
- Some recipes use a 3x3 "grid", laid out flat on the ground.=- Algumas receitas usam uma "grade" 3x3, disposta diretamente sobre o chão.
|
||||
- Stacks may be pummeled, exact item count may matter.=- Amontoados de itens podem ser esmurrados, pode ser que precise de uma quantidade exata do item.
|
||||
- Stuck in a pit? Hold right-click on surfaces barehanded to climb.=mãos nuas para escalar.
|
||||
- Stuck in a pit? Pummel surfaces barehanded to find places to climb.=[REMOVED].
|
||||
- The game is challenging by design, sometimes frustrating. DON'T GIVE UP!=- O jogo é feito para ser desafiante, algumas fezes frustrante. NÃO DESISTA!
|
||||
- There is NO inventory screen.=- NÃO EXISTE tela de inventário.
|
||||
- To pummel, punch a node repeatedly, WITHOUT digging.=- Para esmurrar, bata num node repetidamente, SEM QUEBRÁ-LO.
|
||||
- Trouble lighting a fire? Try using longer sticks, more tinder.=inflamáveis.
|
||||
- Wielded item, target face, and surrounding nodes may matter.=- O item segurado, a face do objeto alvo e os nodes ao redor podem importar durante a criação de algo.
|
||||
- You do not have to punch very fast (about 1 per second).=- Você não precisa bater muito rápido(basta 1 batida por segundo).
|
||||
...and 1 more hint...=...e mais 1 dica...
|
||||
...and @1 more hints...=...e mais @1 dicas...
|
||||
...have you activated a lens yet?=...você já ativou uma lente?
|
||||
...have you assembled a staff from sticks yet?=...você já montou um bastão usando gravetos?
|
||||
...have you assembled a wooden frame yet?=...você já montou um estrutura de madeira?
|
||||
...have you assembled a wooden ladder yet?=...você já montou uma escada de madeira?
|
||||
...have you assembled a wooden shelf yet?=...você já montou uma estante de madeira?
|
||||
...have you assembled a wooden tool yet?=...você já montou uma ferramenta de madeira?
|
||||
...have you assembled an adze out of sticks yet?=...você já montou um enxó usando gravetos?
|
||||
...have you assembled an annealed lode tote handle yet?=...você já montou uma alça de bolsa recozida?
|
||||
...have you bashed a plank into sticks yet?=...você já quebrou uma tábua em gravetos batendo nela?
|
||||
...have you broken cobble into chips yet?=...você já quebrou pedregulho em pedaços?
|
||||
...have you carved a wooden plank completely yet?=...você já entalhou completamente uma tábua de madeira?
|
||||
...have you carved wooden tool heads from planks yet?=...você já transformou uma tábua em cabeças de ferramentas, entalhando a madeira?
|
||||
...have you chipped chromatic glass into prisms yet?=...você já quebrou um vidro cromático em prismas, lascando o vidro?
|
||||
...have you chopped a lode cube into prills yet?=...você já quebrou um veio mineral em lascas, usando um machado?
|
||||
...have you chopped chromatic glass into lenses yet?=...você já quebrou vidro cromático em lentes, usando um machado?
|
||||
...have you chopped up charcoal yet?=...você já quebrou carvão usando um machado?
|
||||
...have you cold-forged an annealed lode tool head yet?=...você já fez uma forja fria de uma cabeça de ferramenta de veio mineral?
|
||||
...have you cold-forged lode down completely yet?=...você já fez uma forja fria de um veio mineral?
|
||||
...have you cooled molten glass into crude glass yet?=...você já esfriou vidro derretido para que este virasse vidro cru?
|
||||
...have you cut down a tree yet?=...você já cortou uma árvore?
|
||||
...have you dug up a tree stump yet?=...você já desenterrou um toco de árvore?
|
||||
...have you dug up dirt yet?=...você já cavou terra?
|
||||
...have you dug up gravel yet?=...você já cavou cascalho?
|
||||
...have you dug up lode ore yet?=...você já desenterrou um veio mineral?
|
||||
...have you dug up sand yet?=...você já cavou areia?
|
||||
...have you dug up stone yet?=...você já cavou pedra?
|
||||
...have you found a lode stratum yet?=...você já encontrou um estrato de veio mineral?
|
||||
...have you found ash yet?=...você já encontrou cinzas?
|
||||
...have you found charcoal yet?=...você já encontrou carvão?
|
||||
...have you found deep stone strata yet?=...você já encontrou um estrato de pedra profunda?
|
||||
...have you found dry leaves yet?=...você já encontrou folhas secas?
|
||||
...have you found eggcorns yet?=...você já encontrou semente de carvalho?
|
||||
...have you found lode ore yet?=...você já encontrou um veio mineral?
|
||||
...have you found molten rock yet?=...você já encontrou pedra derretida (lava)?
|
||||
...have you found sponges yet?=...você já encontrou esponjas?
|
||||
...have you found sticks yet?=...você já encontrou gravetos?
|
||||
...have you made fire by rubbing sticks together yet?=...você já fez fogo esfregando gravetos?
|
||||
...have you melted down lode metal yet?=...você já derreteu um veio mineral?
|
||||
...have you melted sand into glass yet?=...você já transformou areia em vidro, derretendo a areia?
|
||||
...have you molded molten glass into clear glass yet?=...você já moldou vidro derretido em vidro transparente?
|
||||
...have you packed high-quality charcoal yet?=...você já juntou carvão de alta qualidade?
|
||||
...have you packed stone chips back into cobble yet?=...você já juntou pedaços de pedra para que virassem pedregulho?
|
||||
...have you planted an eggcorn yet?=...você já plantou uma semente de carvalho?
|
||||
...have you produced light from a lens yet?=...você já gerou luz a partir de uma lente?
|
||||
...have you put a stone tip onto a tool yet?=...você já colocou uma ponta de pedra em uma ferramenta?
|
||||
...have you quenched molten glass into chromatic glass yet?=...você já temperou vidro derretido para que virasse vidro cromático?
|
||||
...have you sintered glowing lode into a cube yet?=...você já moldou veio mineral incandescente em um cubo?
|
||||
...have you split a tree trunk into planks yet?=...você já fez tábuas quebrando troncos de madeira?
|
||||
...have you tempered a lode anvil yet?=...você já fez uma bigorna temperando veio mineral?
|
||||
...have you tempered a lode tool head yet?=...você já fez uma cabeça de ferramenta temperando veio mineral?
|
||||
...have you welded a lode pick and spade together yet?=...você já soldou uma picareta de veio mineral com uma pá de veio mineral?
|
||||
About=Sobre
|
||||
Active Lens=Lente Ativa
|
||||
Active Prism=Prisma Ativo
|
||||
Adobe Mix=Mistura de Adobe
|
||||
Adze=Enxó
|
||||
Aggregate=Agregar
|
||||
Aggregate=Agregado
|
||||
Air=Ar
|
||||
Amalgamation=Amalgamação
|
||||
Annealed Lode=Veio Mineral Recozido
|
||||
Annealed Lode Bar=Barra de Veio Mineral Recozida
|
||||
Annealed Lode Hatchet=Machado de Veio Mineral Recozida
|
||||
@ -41,12 +102,32 @@ Annealed Lode Prill=Lascas de Veio Mineral Recozida
|
||||
Annealed Lode Rod=Vara de Veio Mineral Recozida
|
||||
Annealed Lode Spade=Pá de Veio Mineral Recozida
|
||||
Annealed Lode Spade Head=Cabeça de Pá de Veio Mineral Recozida
|
||||
Artificial Water=Água Artificial
|
||||
Ash=Cinza
|
||||
Ash Lump=Nódulo de Cinzas
|
||||
Bindy=Liguento
|
||||
Bindy Adobe=Adobe Liguento
|
||||
Bindy Pliant Adobe=Adobe Flexível Liguenta
|
||||
Bindy Pliant Sandstone=Arenito Flexível Liguento
|
||||
Bindy Pliant Stone=Pedra Flexível Liguenta
|
||||
Bindy Pliant Tarstone=Pedra de Alcatrão Flexível Liguenta
|
||||
Bindy Sandstone=Arenito Liguento
|
||||
Bindy Stone=Pedra Liguenta
|
||||
Bindy Tarstone=Pedra de Alcatrão Liguenta
|
||||
Blank=Vazio(Em Branco)
|
||||
Bonded Stone Bricks=Tijolos de Pedra Ligados
|
||||
Boxy=Quadradão
|
||||
Boxy Adobe=Adobe Quadrado
|
||||
Boxy Pliant Adobe=Adobe Flexível Quadrado
|
||||
Boxy Pliant Sandstone=Arenito Flexível Quadrado
|
||||
Boxy Pliant Stone=Pedra Flexível Quadrada
|
||||
Boxy Pliant Tarstone=Pedra de Alcatrão Flexível Quadrada
|
||||
Boxy Sandstone=Arenito Quadrada
|
||||
Boxy Stone=Pedra Quadrada
|
||||
Boxy Tarstone=Pedra de Alcatrão Quadrada
|
||||
Burn=Queimadura
|
||||
Burning Embers=Brasa Quente
|
||||
Charcoal=Carvão Vegetal
|
||||
Charcoal Glyph=Glifo de Carvão Vegetal
|
||||
Charcoal Lump=Nódulo de Carvão Vegetal
|
||||
Chromatic Glass=Vidro Cromático
|
||||
Clear Glass=Vidro Transparente
|
||||
@ -107,11 +188,9 @@ Lux Flow=Fluxo de Lux
|
||||
MIT License (http://www.opensource.org/licenses/MIT)=Licença MIT (http://www.opensource.org/licenses/MIT)
|
||||
Molten Glass=Vidro Derretido
|
||||
Molten Rock=Pedra Derretida
|
||||
Not all game content is covered by hints. Explore!=As dicas não cobrem todo o conteúdo do jogo. Explore!
|
||||
Not all game content is covered by hints. Explore!=Nem todo o conteúdo do jogo é coberto pelas dicas. Explore!
|
||||
Peat=Turfa
|
||||
Player's Guide: Inventory Management=Guia do Jogador: Gerenciamento de Inventário
|
||||
Player's Guide: Pummeling Recipes=Guia do Jogador: Receitas por Esmurrada
|
||||
Player's Guide: Tips and Guidance=Guia do Jogador: Dicas e Orientações
|
||||
Prism=Prisma
|
||||
Progress: @1 complete, @2 current, @3 future=Progresso: @1 completo(s), @2 atual(is), @3 futuro(s)
|
||||
Pummel=Esmurrar
|
||||
@ -193,8 +272,6 @@ chop a lode crate back apart=quebre uma caixa de veio mineral
|
||||
chop a lode rod back into bars=martele uma haste de veio mineral de volta em barras
|
||||
chop chromatic glass into lenses=martele vidro cromático tornando-o lentes
|
||||
chop up charcoal=martele carvão mineral
|
||||
cold-forge annealed lode prills into a tool head=faça uma cabeça de ferramenta forjando friamente granulado de filão recozido
|
||||
cold-forge lode down completely=forge filão completamente, de forma fria
|
||||
cool molten glass into crude glass=esfrie vidro derretido em vidro bruto
|
||||
craft a torch from staff and coal lump=construa uma tocha a partir de um bastão e um nódulo de carvão
|
||||
cut down a tree=corte uma árvore
|
||||
@ -207,7 +284,6 @@ dig up sand=cave areia
|
||||
dig up stone=escave pedra
|
||||
dry out a sponge=drene uma esponja
|
||||
ferment peat into humus=fermente turga em húmus
|
||||
find a lode stratum=encontre um estrato de filão
|
||||
find a sponge=encontre esponja
|
||||
find a stick=encontre um graveto
|
||||
find an eggcorn=encontre uma pinha
|
||||
@ -227,7 +303,6 @@ insert metal rod into a cobble panel=insira uma haste de metal em um painel de p
|
||||
insert wooden pin into wooden door panel=insira um pino de madeira em um painel de porta de madeira
|
||||
light a torch=acenda uma tocha
|
||||
lux-infuse a lode tool=infusa uma ferramenta de filão com lux
|
||||
make an anvil by tempering a lode cube=faça uma forja temperando um cubo de filão
|
||||
make fire by rubbing sticks together=faça fogo esfregando gravetos
|
||||
make wet aggregate=faça agregado úmido
|
||||
melt down lode metal from lode cobble=derreta filão metálico a partir de pedregulho de filão
|
||||
|
@ -1,33 +1,92 @@
|
||||
# textdomain: nc_api
|
||||
(C)2018-2019 by Aaron Suen <warr1024@@gmail.com>=(C)2018-2019 Аарон Суэн <warr1024@@gmail.com>
|
||||
(C)2018-2020 by Aaron Suen <warr1024@@gmail.com>=(C)2018-2020 Аарон Суэн <warr1024@@gmail.com>
|
||||
(and 1 more hint)=(и еще 1 подсказка)
|
||||
(and @1 more hints)=(и еще @1 подсказок)
|
||||
- "Furnaces" are not a thing; discover smelting with open flames.=- "Печек" тут нет; откройте для себя плавку открытым огнём.
|
||||
- Can't dig trees or grass? Search for sticks in the canopy.=- Не можете копать деревья или траву? Ищите палки в сени.
|
||||
- Crafting is done by building recipes in-world.=- Крафтинг совершается постройкой рецептов в мире.
|
||||
- DONE: @1=- ЗАВЕРШЕНО: @1
|
||||
- Do not use F5 debug info; it will mislead you!=- Не используйте отладочную информацию F5; Она введет вас в заблуждение!
|
||||
- Drop items onto ground to create stack nodes. They do not decay.=[УДАЛЕНО].
|
||||
- Drop items onto ground to create stack nodes. They do not decay.=- Бросайте вещи на землю чтобы создать стак-ноды. Они не исчезают.
|
||||
- If a recipe exists, you will see a special particle effect.=- Если рецепт существует, вы увидите спец-эффект.
|
||||
- Items picked up try to fit into the current selected slot first.=- Подобранные предметы пытаются поместиться в выделенный слот.
|
||||
- Larger recipes are usually more symmetrical.=- Большие рецепты обычно более симметричны.
|
||||
- Order and specific face of placement may matter for crafting.=- Порядок и грань размещения может может иметь значение.
|
||||
- Ores may be hidden, but revealed by subtle clues in terrain.=- Может руды и спрятаны, но их раскрывают тонкие подсказки на местности.
|
||||
- Recipes are time-based, punching faster does not speed up.=- Рецепты зависят от времени, учащенные удары ничего не ускоряют.
|
||||
- Sneak+drop to count out single items from stack.=- Присесть+бросок чтобы отсчитывать отдельные предметы из стака.
|
||||
- Some recipes require "pummeling" a node.=- Некоторые рецепты требуют "избивать" ноду.
|
||||
- Some recipes use a 3x3 "grid", laid out flat on the ground.=- Некоторые рецепты используют "сетку" 3x3, разложенную плоско на земле.
|
||||
- Stacks may be pummeled, exact item count may matter.=- Стаки тоже могут быть избиты, количество предметов может иметь значение.
|
||||
- Stuck in a pit? Hold right-click on surfaces barehanded to climb.=- Застряли? Удерживайте ПКМ на поверхностях с голыми руками чтобы лазать.
|
||||
- Stuck in a pit? Pummel surfaces barehanded to find places to climb.=[УДАЛЕНО].
|
||||
- The game is challenging by design, sometimes frustrating. DON'T GIVE UP!=- Игра сложная по задумке, иногда разочаровывает. НЕ СДАВАЙТЕСЬ!
|
||||
- There is NO inventory screen.=- Экрана инвентаря НЕТ.
|
||||
- To pummel, punch a node repeatedly, WITHOUT digging.=- Чтобы избивать, повторно ударяйте ноду, НЕ КОПАЯ ЕЁ.
|
||||
- Trouble lighting a fire? Try using longer sticks, more tinder.=- Проблемы с разведением огня? Попробуйте использовать палки подлиннее.
|
||||
- Wielded item, target face, and surrounding nodes may matter.=- Предмет в руках, целевая грань и окружающие ноды могут иметь значение.
|
||||
- You do not have to punch very fast (about 1 per second).=- Ударять нужно не так часто (около 1 удара в секунду).
|
||||
...and 1 more hint...=[УДАЛЕНО].
|
||||
...and @1 more hints...=[УДАЛЕНО].
|
||||
...have you activated a lens yet?=[УДАЛЕНО]?
|
||||
...have you assembled a staff from sticks yet?=[УДАЛЕНО]?
|
||||
...have you assembled a wooden frame yet?=[УДАЛЕНО]?
|
||||
...have you assembled a wooden ladder yet?=[УДАЛЕНО]?
|
||||
...have you assembled a wooden shelf yet?=[УДАЛЕНО]?
|
||||
...have you assembled a wooden tool yet?=[УДАЛЕНО]?
|
||||
...have you assembled an adze out of sticks yet?=[УДАЛЕНО]?
|
||||
...have you assembled an annealed lode tote handle yet?=[УДАЛЕНО]?
|
||||
...have you bashed a plank into sticks yet?=[УДАЛЕНО]?
|
||||
...have you broken cobble into chips yet?=[УДАЛЕНО]?
|
||||
...have you carved a wooden plank completely yet?=[УДАЛЕНО]?
|
||||
...have you carved wooden tool heads from planks yet?=[УДАЛЕНО]?
|
||||
...have you chipped chromatic glass into prisms yet?=[УДАЛЕНО]?
|
||||
...have you chopped a lode cube into prills yet?=[УДАЛЕНО]?
|
||||
...have you chopped chromatic glass into lenses yet?=[УДАЛЕНО]?
|
||||
...have you chopped up charcoal yet?=[УДАЛЕНО]?
|
||||
...have you cold-forged an annealed lode tool head yet?=[УДАЛЕНО]?
|
||||
...have you cold-forged lode down completely yet?=[УДАЛЕНО]?
|
||||
...have you cooled molten glass into crude glass yet?=[УДАЛЕНО]?
|
||||
...have you cut down a tree yet?=[УДАЛЕНО]?
|
||||
...have you dug up a tree stump yet?=[УДАЛЕНО]?
|
||||
...have you dug up dirt yet?=[УДАЛЕНО]?
|
||||
...have you dug up gravel yet?=[УДАЛЕНО]?
|
||||
...have you dug up lode ore yet?=[УДАЛЕНО]?
|
||||
...have you dug up sand yet?=[УДАЛЕНО]?
|
||||
...have you dug up stone yet?=[УДАЛЕНО]?
|
||||
...have you found a lode stratum yet?=[УДАЛЕНО]?
|
||||
...have you found ash yet?=[УДАЛЕНО]?
|
||||
...have you found charcoal yet?=[УДАЛЕНО]?
|
||||
...have you found deep stone strata yet?=[УДАЛЕНО]?
|
||||
...have you found dry leaves yet?=[УДАЛЕНО]?
|
||||
...have you found eggcorns yet?=[УДАЛЕНО]?
|
||||
...have you found lode ore yet?=[УДАЛЕНО]?
|
||||
...have you found molten rock yet?=[УДАЛЕНО]?
|
||||
...have you found sponges yet?=[УДАЛЕНО]?
|
||||
...have you found sticks yet?=[УДАЛЕНО]?
|
||||
...have you made fire by rubbing sticks together yet?=[УДАЛЕНО]?
|
||||
...have you melted down lode metal yet?=[УДАЛЕНО]?
|
||||
...have you melted sand into glass yet?=[УДАЛЕНО]?
|
||||
...have you molded molten glass into clear glass yet?=[УДАЛЕНО]?
|
||||
...have you packed high-quality charcoal yet?=[УДАЛЕНО]?
|
||||
...have you packed stone chips back into cobble yet?=[УДАЛЕНО]?
|
||||
...have you planted an eggcorn yet?=[УДАЛЕНО]?
|
||||
...have you produced light from a lens yet?=[УДАЛЕНО]?
|
||||
...have you put a stone tip onto a tool yet?=[УДАЛЕНО]?
|
||||
...have you quenched molten glass into chromatic glass yet?=[УДАЛЕНО]?
|
||||
...have you sintered glowing lode into a cube yet?=[УДАЛЕНО]?
|
||||
...have you split a tree trunk into planks yet?=[УДАЛЕНО]?
|
||||
...have you tempered a lode anvil yet?=[УДАЛЕНО]?
|
||||
...have you tempered a lode tool head yet?=[УДАЛЕНО]?
|
||||
...have you welded a lode pick and spade together yet?=[УДАЛЕНО]?
|
||||
About=Об игре
|
||||
Active Lens=Активная Линза
|
||||
Active Prism=Активная Призма
|
||||
Adze=Тесло
|
||||
Aggregate=Цемент
|
||||
Air=Воздух
|
||||
Amalgamation=Амальгамация
|
||||
Annealed Lode=Обожжёный Металл
|
||||
Annealed Lode Bar=Обожжёный Металлический Брусок
|
||||
Annealed Lode Hatchet=Обожжёный Металлический Топорик
|
||||
@ -42,12 +101,12 @@ Annealed Lode Prill=Обожжёный Металлический Самород
|
||||
Annealed Lode Rod=Обожжёный Металлический Стержень
|
||||
Annealed Lode Spade=Обожжёный Металлический Заступ
|
||||
Annealed Lode Spade Head=Обожжёный Металлический Обух Заступа
|
||||
Artificial Water=Искуственная вода
|
||||
Ash=Пепел
|
||||
Ash Lump=Комок Пепла
|
||||
Burn=Ожог
|
||||
Burning Embers=Горящие Угли
|
||||
Charcoal=Уголь
|
||||
Charcoal Glyph=Угольный Символ
|
||||
Charcoal Lump=Комок Угля
|
||||
Chromatic Glass=Хроматическое Стекло
|
||||
Clear Glass=Прозрачное Стекло
|
||||
@ -74,6 +133,8 @@ Glowing Lode Rod=Раскалённый Металлический Стерже
|
||||
Glowing Lode Spade Head=Раскалённый Металлический Обух Заступа
|
||||
Grass=Трава
|
||||
Gravel=Гравий
|
||||
Growing Leaves=Растущие Листья
|
||||
Growing Tree Trunk=Растущий Ствол Дерева
|
||||
Hints=Подсказки
|
||||
Humus=Гумус
|
||||
Ignore=Не обращайте внимания
|
||||
@ -97,6 +158,7 @@ Lode Cobble=Булыжник с Металлом
|
||||
Lode Crate=Металлический Ящик
|
||||
Lode Ore=Металлическая Руда
|
||||
Log=Бревно
|
||||
Loose Amalgamation=Рыхлая Амальгамация
|
||||
Loose Cobble=Рыхлый Булыжник
|
||||
Loose Dirt=Рыхлая Грязь
|
||||
Loose Gravel=Насыпной Гравий
|
||||
@ -110,11 +172,9 @@ Lux Flow=Поток Люкса
|
||||
MIT License (http://www.opensource.org/licenses/MIT)=Лицензия MIT (http://www.opensource.org/licenses/MIT)
|
||||
Molten Glass=Расплавленное Стекло
|
||||
Molten Rock=Расплавленный Камень
|
||||
Not all game content is covered by hints. Explore!=[УДАЛЕНО]!
|
||||
Not all game content is covered by hints. Explore!=Не вся игра покрыта подсказками. Исследуйте!
|
||||
Peat=Торф
|
||||
Player's Guide: Inventory Management=Руководсво Игрока: Управление Инвентарём
|
||||
Player's Guide: Pummeling Recipes=Руководство Игрока: Рецепты Избиения
|
||||
Player's Guide: Tips and Guidance=Руководство Игрока: Советы и Направление
|
||||
Prism=Призма
|
||||
Progress: @1 complete, @2 current, @3 future=Прогресс: @1 готовы, @2 сейчас, @3 в будущем
|
||||
Pummel=Избиение
|
||||
@ -123,6 +183,7 @@ Sand=Песок
|
||||
See included LICENSE file for full details and credits=См. детали и кредиты в файле LICENSE
|
||||
Shining Lens=Сияющая Линза
|
||||
Sponge=Губка
|
||||
Sprout=Росток
|
||||
Staff=Жезл
|
||||
Stick=Палка
|
||||
Stone=Камень
|
||||
@ -177,6 +238,9 @@ Wooden Shelf=Деревянная Полка
|
||||
Wooden Spade=Деревянный Заступ
|
||||
Wooden Spade Head=Деревянный Обух Заступа
|
||||
activate a lens=активируйте линзу
|
||||
activate a prism=активируйте призму
|
||||
assemble a glass tank=соберите стеклянный танк
|
||||
assemble a rake from adzes and a stick=соберите грабли из тесел и палки
|
||||
assemble a staff from sticks=соберите жезл из палок
|
||||
assemble a wooden frame from staves=соберите деревянный каркас из жезлов
|
||||
assemble a wooden ladder from sticks=соберите деревянную лестницу из палок
|
||||
@ -188,6 +252,7 @@ bash a plank into sticks=разбейте доску на палки
|
||||
break cobble into chips=разбейте булыжник на кусочки
|
||||
carve a wooden plank completely=вырежте доску до конца
|
||||
carve wooden tool heads from planks=вырежте обухи из досок
|
||||
catapult an item with a hinged panel=катапультируйте предмет с помощью приклепленной панели
|
||||
chip chromatic glass into prisms=выстрогайте призмы из хроматического стекла
|
||||
chisel a hinge groove into a wooden plank=высеките выемку для петли в доске
|
||||
chisel a hinge groove into cobble=высеките выемку для петли в булыжнике
|
||||
@ -196,8 +261,8 @@ chop a lode crate back apart=разрубите металлический ящ
|
||||
chop a lode rod back into bars=разрубите металлический стержень обратно на бруски
|
||||
chop chromatic glass into lenses=разрубите хроматическое стекло на линзы
|
||||
chop up charcoal=нарежте уголь
|
||||
cold-forge annealed lode prills into a tool head=выкуйте обух инструмента из холодных обожжённых металлический самородков
|
||||
cold-forge lode down completely=выкуйте холодный металл до конца
|
||||
cold-forge annealed lode on a tempered anvil=выкуйте отожженный металл холодной ковкой на закаленной наковальне
|
||||
compress something with a hinged panel=сожмите что-нибудь прикрепленной панелью
|
||||
cool molten glass into crude glass=остудите расплавленное стекло в рыхлое стекло
|
||||
craft a torch from staff and coal lump=скрафтите факел из жезла и кусочка угля
|
||||
cut down a tree=срубите дерево
|
||||
@ -210,7 +275,6 @@ dig up sand=выкопайте песок
|
||||
dig up stone=выкопайте камень
|
||||
dry out a sponge=высушите губку
|
||||
ferment peat into humus=ферментируйте торф в гумус
|
||||
find a lode stratum=найдите слой металла
|
||||
find a sponge=найдите губку
|
||||
find a stick=найдите палку
|
||||
find an eggcorn=найдите яйцезерно
|
||||
@ -221,6 +285,7 @@ find dry (loose) leaves=найдите сухие (опавшие) листья
|
||||
find lode ore=найдите железную руду
|
||||
find lux=найдите люкс
|
||||
find molten rock=найдите расплавленный камень
|
||||
forge lode down completely on an anvil=выкуйте металл до конца
|
||||
grind leaves into peat=измельчите листья в торф
|
||||
hammer a lode bar back to a prill=выкуйте металлический брусок обратно в самородок
|
||||
hammer a lode prill into a bar=выкуйте металлический брусок из самородка
|
||||
@ -230,7 +295,6 @@ insert metal rod into a cobble panel=вставьте металлический
|
||||
insert wooden pin into wooden door panel=вставьте деревянную булаву в деревянную дверную панель
|
||||
light a torch=зажгите факел
|
||||
lux-infuse a lode tool=зарядите металлический инструмент люксом
|
||||
make an anvil by tempering a lode cube=сделайте наковальню закалив металлический куб
|
||||
make fire by rubbing sticks together=разведите огонь потерев палки друг о друга
|
||||
make wet aggregate=сделайте влажный цемент
|
||||
melt down lode metal from lode cobble=выплавьте металл из булыжника с металлом
|
||||
@ -254,6 +318,5 @@ solder lode rods into crates=спаяйте металлические стер
|
||||
split a tree trunk into planks=разрубите ствол дерева на доски
|
||||
squeeze out a sponge=выжмите губку
|
||||
temper a lode tool head=закалите обух металлического инструмента
|
||||
traverse a dark floor by feel=перейдите темный пол наощупь
|
||||
weld glowing lode pick and spade heads together=сварите раскаленные обухи кирки и заступа вместе
|
||||
write on a surface with a charcoal lump=напишите углем на поверхности
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2019-10-04 22:59+0000\n"
|
||||
"Last-Translator: Terifo <none@example.org>\n"
|
||||
"PO-Revision-Date: 2020-01-12 16:26+0000\n"
|
||||
"Last-Translator: Weblate Admin <warr1024@gmail.com>\n"
|
||||
"Language-Team: Japanese <http://nodecore.mine.nu/trans/projects/nodecore/"
|
||||
"core/ja/>\n"
|
||||
"Language: ja\n"
|
||||
@ -19,3 +19,6 @@ msgstr "(さらに1つのヒント)"
|
||||
|
||||
msgid "(C)2018-2019 by Aaron Suen <warr1024@@gmail.com>"
|
||||
msgstr "(C)2018-2019 から Aaron Suen <warr1024@@gmail.com>"
|
||||
|
||||
msgid "(C)2018-2020 by Aaron Suen <warr1024@@gmail.com>"
|
||||
msgstr "(C)2018-2020 から Aaron Suen <warr1024@@gmail.com>"
|
||||
|
@ -3,7 +3,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-09-12 14:44+0000\n"
|
||||
"PO-Revision-Date: 2019-11-23 14:35+0000\n"
|
||||
"PO-Revision-Date: 2020-04-21 13:55+0000\n"
|
||||
"Last-Translator: Weblate Admin <warr1024@gmail.com>\n"
|
||||
"Language-Team: Portuguese <http://nodecore.mine.nu/trans/projects/nodecore/"
|
||||
"core/pt/>\n"
|
||||
@ -636,7 +636,10 @@ msgid "pack leaves into peat"
|
||||
msgstr "[REMOVED]"
|
||||
|
||||
msgid "- Stuck in a pit? Pummel surfaces barehanded to find places to climb."
|
||||
msgstr "[REMOVED]"
|
||||
msgstr "[REMOVED]."
|
||||
|
||||
msgid "Adze"
|
||||
msgstr "Enxó"
|
||||
|
||||
msgid "(C)2018-2020 by Aaron Suen <warr1024@@gmail.com>"
|
||||
msgstr "(C)2018-2020 por Aaron Suen <war1024@@gmail.com>"
|
||||
|
@ -3,8 +3,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-09-12 14:44+0000\n"
|
||||
"PO-Revision-Date: 2019-11-23 14:35+0000\n"
|
||||
"Last-Translator: Weblate Admin <warr1024@gmail.com>\n"
|
||||
"PO-Revision-Date: 2020-09-02 12:25+0000\n"
|
||||
"Last-Translator: Terifo <none@example.org>\n"
|
||||
"Language-Team: Portuguese (Brazil) <http://nodecore.mine.nu/trans/projects/"
|
||||
"nodecore/core/pt_BR/>\n"
|
||||
"Language: pt_BR\n"
|
||||
@ -12,7 +12,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 3.8\n"
|
||||
"X-Generator: Weblate 4.0.4\n"
|
||||
|
||||
msgid "(C)2018-2019 by Aaron Suen <warr1024@@gmail.com>"
|
||||
msgstr "(C)2018-2019 por Aaron Suen <war1024@@gmail.com>"
|
||||
@ -225,7 +225,7 @@ msgid "Active Prism"
|
||||
msgstr "Prisma Ativo"
|
||||
|
||||
msgid "Aggregate"
|
||||
msgstr "Agregar"
|
||||
msgstr "Agregado"
|
||||
|
||||
msgid "Air"
|
||||
msgstr "Ar"
|
||||
@ -631,7 +631,7 @@ msgstr ""
|
||||
"- O jogo é feito para ser desafiante, algumas fezes frustrante. NÃO DESISTA!"
|
||||
|
||||
msgid "- Stuck in a pit? Pummel surfaces barehanded to find places to climb."
|
||||
msgstr "[REMOVED]"
|
||||
msgstr "[REMOVED]."
|
||||
|
||||
msgid "- Ores may be hidden, but revealed by subtle clues in terrain."
|
||||
msgstr ""
|
||||
@ -950,3 +950,167 @@ msgstr "[REMOVED]"
|
||||
|
||||
msgid "Adze"
|
||||
msgstr "Enxó"
|
||||
|
||||
msgid "(C)2018-2020 by Aaron Suen <warr1024@@gmail.com>"
|
||||
msgstr "(C)2018-2020 por Aaron Suen <war1024@@gmail.com>"
|
||||
|
||||
msgid "+"
|
||||
msgstr "+"
|
||||
|
||||
msgid "Artificial Water"
|
||||
msgstr "Água Artificial"
|
||||
|
||||
msgid "Amalgamation"
|
||||
msgstr "Amalgamação"
|
||||
|
||||
msgid "Adobe Mix"
|
||||
msgstr "Mistura de Adobe"
|
||||
|
||||
msgid "Adobe"
|
||||
msgstr "Adobe"
|
||||
|
||||
msgid "@1 |||||"
|
||||
msgstr "@1 |||||"
|
||||
|
||||
msgid "@1 ||||."
|
||||
msgstr "@1 ||||."
|
||||
|
||||
msgid "@1 |||.."
|
||||
msgstr "@1 |||.."
|
||||
|
||||
msgid "@1 ||..."
|
||||
msgstr "@1 ||..."
|
||||
|
||||
msgid "@1 |...."
|
||||
msgstr "@1 |...."
|
||||
|
||||
msgid "@1 ....."
|
||||
msgstr "@1 ....."
|
||||
|
||||
msgid "@1 (90@2)"
|
||||
msgstr "@1 (90@2)"
|
||||
|
||||
msgid "@1 (9)"
|
||||
msgstr "@1 (9)"
|
||||
|
||||
msgid "@1 (80@2)"
|
||||
msgstr "@1 (80@2)"
|
||||
|
||||
msgid "@1 (8)"
|
||||
msgstr "@1 (8)"
|
||||
|
||||
msgid "@1 (70@2)"
|
||||
msgstr "@1 (70@2)"
|
||||
|
||||
msgid "@1 (7)"
|
||||
msgstr "@1 (7)"
|
||||
|
||||
msgid "@1 (60@2)"
|
||||
msgstr "@1 (60@2)"
|
||||
|
||||
msgid "@1 (6)"
|
||||
msgstr "@1 (6)"
|
||||
|
||||
msgid "@1 (50@2)"
|
||||
msgstr "@1 (50@2)"
|
||||
|
||||
msgid "@1 (5)"
|
||||
msgstr "@1 (5)"
|
||||
|
||||
msgid "@1 (40@2)"
|
||||
msgstr "@1 (40@2)"
|
||||
|
||||
msgid "@1 (4)"
|
||||
msgstr "@1 (4)"
|
||||
|
||||
msgid "@1 (30@2)"
|
||||
msgstr "@1 (30@2)"
|
||||
|
||||
msgid "@1 (3)"
|
||||
msgstr "@1 (3)"
|
||||
|
||||
msgid "@1 (20@2)"
|
||||
msgstr "@1 (20@2)"
|
||||
|
||||
msgid "@1 (2)"
|
||||
msgstr "@1 (2)"
|
||||
|
||||
msgid "@1 (10@2)"
|
||||
msgstr "@1 (10@2)"
|
||||
|
||||
msgid "@1 (100@2)"
|
||||
msgstr "@1 (100@2)"
|
||||
|
||||
msgid "- Some recipes use a 3x3 "grid", laid out flat on the ground."
|
||||
msgstr ""
|
||||
"- Algumas receitas usam uma \"grade\" 3x3, disposta diretamente sobre o chão."
|
||||
|
||||
msgid "- Larger recipes are usually more symmetrical."
|
||||
msgstr "- Receitas maiores geralmente são mais simétricas."
|
||||
|
||||
msgid "- Hold/repeat right-click on walls/ceilings barehanded to climb."
|
||||
msgstr ""
|
||||
"- Segure/repita o clique direito em paredes/tetos para escalar com mãos nuas."
|
||||
|
||||
msgid "- Do not use F5 debug info; it will mislead you!"
|
||||
msgstr "- Não use as informações de debug do F5; Apenas irão lhe confundir!"
|
||||
|
||||
msgid "Bindy Pliant Tarstone"
|
||||
msgstr "Pedra de Alcatrão Flexível Liguenta"
|
||||
|
||||
msgid "Bindy Pliant Stone"
|
||||
msgstr "Pedra Flexível Liguenta"
|
||||
|
||||
msgid "Bindy Pliant Sandstone"
|
||||
msgstr "Arenito Flexível Liguento"
|
||||
|
||||
msgid "Bindy Pliant Adobe"
|
||||
msgstr "Adobe Flexível Liguenta"
|
||||
|
||||
msgid "Bindy Adobe"
|
||||
msgstr "Adobe Liguento"
|
||||
|
||||
msgid "Bindy"
|
||||
msgstr "Liguento"
|
||||
|
||||
msgid "Bindy Tarstone"
|
||||
msgstr "Pedra de Alcatrão Liguenta"
|
||||
|
||||
msgid "Bindy Stone"
|
||||
msgstr "Pedra Liguenta"
|
||||
|
||||
msgid "Bindy Sandstone"
|
||||
msgstr "Arenito Liguento"
|
||||
|
||||
msgid "Boxy Tarstone"
|
||||
msgstr "Pedra de Alcatrão Quadrada"
|
||||
|
||||
msgid "Boxy Stone"
|
||||
msgstr "Pedra Quadrada"
|
||||
|
||||
msgid "Boxy Pliant Tarstone"
|
||||
msgstr "Pedra de Alcatrão Flexível Quadrada"
|
||||
|
||||
msgid "Boxy Sandstone"
|
||||
msgstr "Arenito Quadrada"
|
||||
|
||||
msgid "Boxy Pliant Stone"
|
||||
msgstr "Pedra Flexível Quadrada"
|
||||
|
||||
msgid "Boxy Pliant Sandstone"
|
||||
msgstr "Arenito Flexível Quadrado"
|
||||
|
||||
msgid "Boxy Pliant Adobe"
|
||||
msgstr "Adobe Flexível Quadrado"
|
||||
|
||||
msgid "Boxy Adobe"
|
||||
msgstr "Adobe Quadrado"
|
||||
|
||||
msgid "Boxy"
|
||||
msgstr "Quadradão"
|
||||
|
||||
msgid "Bonded Stone Bricks"
|
||||
msgstr "Tijolos de Pedra Ligados"
|
||||
|
||||
msgid "Blank"
|
||||
msgstr "Vazio(Em Branco)"
|
||||
|
@ -1,7 +1,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2019-12-19 04:08+0000\n"
|
||||
"Last-Translator: Kimapr <none2@example.org>\n"
|
||||
"PO-Revision-Date: 2020-04-20 13:07+0000\n"
|
||||
"Last-Translator: Weblate Admin <warr1024@gmail.com>\n"
|
||||
"Language-Team: Russian <http://nodecore.mine.nu/trans/projects/nodecore/core/"
|
||||
"ru/>\n"
|
||||
"Language: ru\n"
|
||||
@ -175,40 +175,40 @@ msgid "About"
|
||||
msgstr "Об игре"
|
||||
|
||||
msgid "...have you broken cobble into chips yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you bashed a plank into sticks yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you assembled an annealed lode tote handle yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you assembled an adze out of sticks yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you assembled a wooden tool yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you assembled a wooden shelf yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you assembled a wooden ladder yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you assembled a wooden frame yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you assembled a staff from sticks yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you activated a lens yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...and @1 more hints..."
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]."
|
||||
|
||||
msgid "...and 1 more hint..."
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]."
|
||||
|
||||
msgid "- You do not have to punch very fast (about 1 per second)."
|
||||
msgstr "- Ударять нужно не так часто (около 1 удара в секунду)."
|
||||
@ -230,7 +230,7 @@ msgid "- The game is challenging by design, sometimes frustrating. DON'T GIVE UP
|
||||
msgstr "- Игра сложная по задумке, иногда разочаровывает. НЕ СДАВАЙТЕСЬ!"
|
||||
|
||||
msgid "- Stuck in a pit? Pummel surfaces barehanded to find places to climb."
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]."
|
||||
|
||||
msgid "- Stuck in a pit? Hold right-click on surfaces barehanded to climb."
|
||||
msgstr ""
|
||||
@ -266,7 +266,7 @@ msgid "- Drop items onto ground to create stack nodes. They do not decay."
|
||||
msgstr "- Бросайте вещи на землю чтобы создать стак-ноды. Они не исчезают."
|
||||
|
||||
msgid "- Drop items onto ground to create stack nodes. They do not decay."
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]."
|
||||
|
||||
msgid "- DONE: @1"
|
||||
msgstr "- ЗАВЕРШЕНО: @1"
|
||||
@ -293,40 +293,40 @@ msgid "(C)2018-2019 by Aaron Suen <warr1024@@gmail.com>"
|
||||
msgstr "(C)2018-2019 Аарон Суэн <warr1024@@gmail.com>"
|
||||
|
||||
msgid "...have you carved a wooden plank completely yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you carved wooden tool heads from planks yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you chipped chromatic glass into prisms yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you chopped a lode cube into prills yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you chopped chromatic glass into lenses yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you made fire by rubbing sticks together yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you chopped up charcoal yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you put a stone tip onto a tool yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you cold-forged an annealed lode tool head yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you cold-forged lode down completely yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "Loose Humus"
|
||||
msgstr "Рыхлый Гумус"
|
||||
|
||||
msgid "...have you cooled molten glass into crude glass yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "Loose Lode Cobble"
|
||||
msgstr "Рыхлый Булыжник с Металлом"
|
||||
@ -335,97 +335,97 @@ msgid "MIT License (http://www.opensource.org/licenses/MIT)"
|
||||
msgstr "Лицензия MIT (http://www.opensource.org/licenses/MIT)"
|
||||
|
||||
msgid "...have you cut down a tree yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "Not all game content is covered by hints. Explore!"
|
||||
msgstr "Не вся игра покрыта подсказками. Исследуйте!"
|
||||
|
||||
msgid "...have you dug up a tree stump yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you dug up dirt yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you dug up gravel yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you dug up lode ore yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you dug up sand yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you dug up stone yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found a lode stratum yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found ash yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found charcoal yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found deep stone strata yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found dry leaves yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found eggcorns yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found lode ore yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found molten rock yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found sponges yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you found sticks yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you melted down lode metal yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you melted sand into glass yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you molded molten glass into clear glass yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you packed high-quality charcoal yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you packed stone chips back into cobble yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you planted an eggcorn yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you produced light from a lens yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you quenched molten glass into chromatic glass yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you sintered glowing lode into a cube yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you split a tree trunk into planks yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you tempered a lode anvil yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you tempered a lode tool head yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "...have you welded a lode pick and spade together yet?"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]?"
|
||||
|
||||
msgid "Discord: https://discord.gg/SHq2tkb"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
@ -639,7 +639,7 @@ msgid "Molten Rock"
|
||||
msgstr "Расплавленный Камень"
|
||||
|
||||
msgid "Not all game content is covered by hints. Explore!"
|
||||
msgstr "[УДАЛЕНО]"
|
||||
msgstr "[УДАЛЕНО]!"
|
||||
|
||||
msgid "Peat"
|
||||
msgstr "Торф"
|
||||
@ -1015,3 +1015,119 @@ msgstr "сварите раскаленные обухи кирки и заст
|
||||
|
||||
msgid "write on a surface with a charcoal lump"
|
||||
msgstr "напишите углем на поверхности"
|
||||
|
||||
msgid "Artificial Water"
|
||||
msgstr "Искуственная вода"
|
||||
|
||||
msgid "@1 (90@2)"
|
||||
msgstr "@1 (90@2)"
|
||||
|
||||
msgid "@1 (9)"
|
||||
msgstr "@1 (9)"
|
||||
|
||||
msgid "@1 (80@2)"
|
||||
msgstr "@1 (80@2)"
|
||||
|
||||
msgid "@1 (8)"
|
||||
msgstr "@1 (8)"
|
||||
|
||||
msgid "@1 (70@2)"
|
||||
msgstr "@1 (70@2)"
|
||||
|
||||
msgid "@1 (7)"
|
||||
msgstr "@1 (7)"
|
||||
|
||||
msgid "@1 (60@2)"
|
||||
msgstr "@1 (60@2)"
|
||||
|
||||
msgid "@1 (6)"
|
||||
msgstr "@1 (6)"
|
||||
|
||||
msgid "@1 (50@2)"
|
||||
msgstr "@1 (50@2)"
|
||||
|
||||
msgid "@1 (5)"
|
||||
msgstr "@1 (5)"
|
||||
|
||||
msgid "@1 (40@2)"
|
||||
msgstr "@1 (40@2)"
|
||||
|
||||
msgid "@1 (4)"
|
||||
msgstr "@1 (4)"
|
||||
|
||||
msgid "@1 (30@2)"
|
||||
msgstr "@1 (30@2)"
|
||||
|
||||
msgid "@1 (3)"
|
||||
msgstr "@1 (3)"
|
||||
|
||||
msgid "@1 (20@2)"
|
||||
msgstr "@1 (20@2)"
|
||||
|
||||
msgid "@1 (2)"
|
||||
msgstr "@1 (2)"
|
||||
|
||||
msgid "@1 (10@2)"
|
||||
msgstr "@1 (10@2)"
|
||||
|
||||
msgid "@1 (100@2)"
|
||||
msgstr "@1 (100@2)"
|
||||
|
||||
msgid "+"
|
||||
msgstr "+"
|
||||
|
||||
msgid "(C)2018-2020 by Aaron Suen <warr1024@@gmail.com>"
|
||||
msgstr "(C)2018-2020 Аарон Суэн <warr1024@@gmail.com>"
|
||||
|
||||
msgid "forge lode down completely on an anvil"
|
||||
msgstr "выкуйте металл до конца"
|
||||
|
||||
msgid "compress something with a hinged panel"
|
||||
msgstr "сожмите что-нибудь прикрепленной панелью"
|
||||
|
||||
msgid "cold-forge annealed lode on a tempered anvil"
|
||||
msgstr "выкуйте отожженный металл холодной ковкой на закаленной наковальне"
|
||||
|
||||
msgid "catapult an item with a hinged panel"
|
||||
msgstr "катапультируйте предмет с помощью приклепленной панели"
|
||||
|
||||
msgid "assemble a rake from adzes and a stick"
|
||||
msgstr "соберите грабли из тесел и палки"
|
||||
|
||||
msgid "assemble a glass tank"
|
||||
msgstr "соберите стеклянный танк"
|
||||
|
||||
msgid "activate a prism"
|
||||
msgstr "активируйте призму"
|
||||
|
||||
msgid "Sprout"
|
||||
msgstr "Росток"
|
||||
|
||||
msgid "Loose Amalgamation"
|
||||
msgstr "Рыхлая Амальгамация"
|
||||
|
||||
msgid "Growing Tree Trunk"
|
||||
msgstr "Растущий Ствол Дерева"
|
||||
|
||||
msgid "Growing Leaves"
|
||||
msgstr "Растущие Листья"
|
||||
|
||||
msgid "Cheat Torch"
|
||||
msgstr "Читерский Факел"
|
||||
|
||||
msgid "Amalgamation"
|
||||
msgstr "Амальгамация"
|
||||
|
||||
msgid "- Some recipes use a 3x3 "grid", laid out flat on the ground."
|
||||
msgstr ""
|
||||
"- Некоторые рецепты используют \"сетку\" 3x3, разложенную плоско на земле."
|
||||
|
||||
msgid "- Larger recipes are usually more symmetrical."
|
||||
msgstr "- Большие рецепты обычно более симметричны."
|
||||
|
||||
msgid "- Hold/repeat right-click on walls/ceilings barehanded to climb."
|
||||
msgstr ""
|
||||
|
||||
msgid "- Do not use F5 debug info; it will mislead you!"
|
||||
msgstr ""
|
||||
"- Не используйте отладочную информацию F5; Она введет вас в заблуждение!"
|
||||
|
18
mods/nc_api/mapgen_limits.lua
Normal file
18
mods/nc_api/mapgen_limits.lua
Normal file
@ -0,0 +1,18 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local math, minetest, nodecore, string, tonumber
|
||||
= math, minetest, nodecore, string, tonumber
|
||||
local math_floor, string_format
|
||||
= math.floor, string.format
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local limit = tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000
|
||||
|
||||
local chunksize = tonumber(minetest.get_mapgen_setting("chunksize")) or 5
|
||||
chunksize = chunksize * 16
|
||||
local limitchunks = math_floor(limit / chunksize)
|
||||
|
||||
nodecore.map_limit_min = (-limitchunks + 0.5) * chunksize + 7.5
|
||||
nodecore.map_limit_max = (limitchunks - 0.5) * chunksize + 7.5
|
||||
|
||||
nodecore.log("action", string_format("mapgen limit: %d, chunk: %d, bounds: %0.1f to %0.1f",
|
||||
limit, chunksize, nodecore.map_limit_min, nodecore.map_limit_max))
|
@ -1,39 +1,70 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local VoxelArea, ipairs, math, minetest, nodecore, table
|
||||
= VoxelArea, ipairs, math, minetest, nodecore, table
|
||||
local math_floor, table_insert
|
||||
= math.floor, table.insert
|
||||
local PcgRandom, VoxelArea, ipairs, math, minetest, nodecore, table
|
||||
= PcgRandom, VoxelArea, ipairs, math, minetest, nodecore, table
|
||||
local math_floor, math_random, table_insert
|
||||
= math.floor, math.random, table.insert
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local mapgens = {}
|
||||
nodecore.registered_mapgen_shared = mapgens
|
||||
|
||||
local prios = {}
|
||||
local singlenode = minetest.get_mapgen_setting("mg_name") == "singlenode"
|
||||
|
||||
function nodecore.register_mapgen_shared(func, prio)
|
||||
prio = prio or 0
|
||||
local counters = {}
|
||||
function nodecore.register_mapgen_shared(def)
|
||||
local label = def.label
|
||||
if not label then
|
||||
label = minetest.get_current_modname()
|
||||
local i = (counters[label] or 0) + 1
|
||||
counters[label] = i
|
||||
label = label .. ":" .. i
|
||||
end
|
||||
|
||||
local prio = def.priority or 0
|
||||
def.priority = prio
|
||||
local min = 1
|
||||
local max = #mapgens + 1
|
||||
while max > min do
|
||||
local try = math_floor((min + max) / 2)
|
||||
local oldp = prios[try]
|
||||
if prio < oldp then
|
||||
local oldp = mapgens[try].priority
|
||||
if (prio < oldp) or (prio == oldp and label > mapgens[try].label) then
|
||||
min = try + 1
|
||||
else
|
||||
max = try
|
||||
end
|
||||
end
|
||||
table_insert(mapgens, min, func)
|
||||
table_insert(prios, min, prio)
|
||||
table_insert(mapgens, min, def)
|
||||
end
|
||||
|
||||
minetest.register_on_generated(function(minp, maxp)
|
||||
local mapperlin
|
||||
minetest.after(0, function() mapperlin = minetest.get_perlin(0, 1, 0, 1) end)
|
||||
|
||||
nodecore.register_on_generated("mapgen shared", function(minp, maxp)
|
||||
local vm, emin, emax = minetest.get_mapgen_object("voxelmanip")
|
||||
local data = vm:get_data()
|
||||
local area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
|
||||
|
||||
for _, v in ipairs(mapgens) do
|
||||
v(minp, maxp, area, data, vm, emin, emax)
|
||||
local rng = math_random
|
||||
if PcgRandom then
|
||||
local seed = mapperlin:get_3d({x = minp.x, y = minp.y, z = minp.z})
|
||||
seed = math_floor((seed - math_floor(seed)) * 2 ^ 32 - 2 ^ 31)
|
||||
local pcg = PcgRandom(seed)
|
||||
rng = function(a, b)
|
||||
if b then
|
||||
return pcg:next(a, b)
|
||||
elseif a then
|
||||
return pcg:next(1, a)
|
||||
end
|
||||
return (pcg:next() + 2 ^ 31) / 2 ^ 32
|
||||
end
|
||||
end
|
||||
|
||||
for _, def in ipairs(mapgens) do
|
||||
local en = def.enabled
|
||||
if en == nil then en = not singlenode end
|
||||
if en then
|
||||
def.func(minp, maxp, area, data, vm, emin, emax, rng)
|
||||
end
|
||||
end
|
||||
|
||||
vm:set_data(data)
|
||||
|
@ -1 +0,0 @@
|
||||
name = nc_api
|
@ -1,134 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, math, minetest, nodecore, pairs, setmetatable, string
|
||||
= ItemStack, math, minetest, nodecore, pairs, setmetatable, string
|
||||
local math_random, string_format
|
||||
= math.random, string.format
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
-- Active ItemStack Modifiers
|
||||
|
||||
-- Definition:
|
||||
--- itemnames: {"mod:itemname", "group:name"}
|
||||
--- interval: integer,
|
||||
--- chance: integer,
|
||||
--- func: function(stack, data) end
|
||||
-- Data:
|
||||
--- {pos, node}
|
||||
--- {player, inv, list, slot}
|
||||
|
||||
nodecore.register_aism,
|
||||
nodecore.registered_aisms
|
||||
= nodecore.mkreg()
|
||||
|
||||
local aismidx = {}
|
||||
local function defadd(key, def)
|
||||
aismidx[key] = aismidx[key] or {}
|
||||
aismidx[key][def] = true
|
||||
end
|
||||
minetest.after(0, function()
|
||||
for _, def in pairs(nodecore.registered_aisms) do
|
||||
for _, name in pairs(def.itemnames) do
|
||||
if name:sub(1, 6) == "group:" then
|
||||
for k, v in pairs(minetest.registered_items) do
|
||||
if v and v.groups and v.groups[name:sub(7)] then
|
||||
defadd(k, def)
|
||||
end
|
||||
end
|
||||
else
|
||||
defadd(name, def)
|
||||
end
|
||||
end
|
||||
end
|
||||
local keys = 0
|
||||
local defs = 0
|
||||
local peak = 0
|
||||
for _, v in pairs(aismidx) do
|
||||
keys = keys + 1
|
||||
local n = 0
|
||||
for _ in pairs(v) do n = n + 1 end
|
||||
defs = defs + n
|
||||
if n > peak then peak = n end
|
||||
end
|
||||
minetest.log(string_format("register_aism: %d keys, %d defs, %d peak", keys, defs, peak))
|
||||
end)
|
||||
|
||||
local function checkrun(def, stack, data)
|
||||
if def.chance and def.chance > 1 and math_random(1, def.chance) ~= 1 then return end
|
||||
if def.interval and def.interval > 1 and (minetest.get_gametime() % def.interval) ~= 0 then return end
|
||||
stack = def.action(stack, data)
|
||||
if stack and data.set then data.set(ItemStack(stack)) end
|
||||
end
|
||||
|
||||
local function checkstack(stack, data)
|
||||
if (not stack) or stack:is_empty() then return end
|
||||
local name = stack:get_name()
|
||||
local defs = aismidx[name]
|
||||
if not defs then return end
|
||||
for def in pairs(defs) do
|
||||
checkrun(def, stack, data)
|
||||
end
|
||||
end
|
||||
nodecore.aism_check_stack = checkstack
|
||||
|
||||
nodecore.register_limited_abm({
|
||||
label = "AISM Scheduler",
|
||||
nodenames = {"group:visinv"},
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
action = function(pos, node)
|
||||
return checkstack(nodecore.stack_get(pos), {
|
||||
pos = pos,
|
||||
node = node,
|
||||
set = function(s)
|
||||
return nodecore.stack_set(pos, s)
|
||||
end
|
||||
})
|
||||
end
|
||||
})
|
||||
|
||||
local function invtick()
|
||||
minetest.after(1, invtick)
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local pos = player:get_pos()
|
||||
pos.y = pos.y + player:get_properties().eye_height
|
||||
local inv = player:get_inventory()
|
||||
for lname, list in pairs(inv:get_lists()) do
|
||||
for slot, stack in pairs(list) do
|
||||
checkstack(stack, {
|
||||
pos = pos,
|
||||
player = player,
|
||||
inv = inv,
|
||||
list = lname,
|
||||
slot = slot,
|
||||
set = function(s)
|
||||
return inv:set_stack(lname, slot, s)
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
invtick()
|
||||
|
||||
local bii = minetest.registered_entities["__builtin:item"]
|
||||
local newbii = {
|
||||
on_step = function(self, dtime, ...)
|
||||
local t = (self.aismtimer or 0) + dtime
|
||||
while t >= 1 do
|
||||
t = t - 1
|
||||
checkstack(ItemStack(self.itemstring), {
|
||||
pos = self.object:get_pos(),
|
||||
obj = self.object,
|
||||
ent = self,
|
||||
set = function(s)
|
||||
if s:is_empty() then return self.object:remove() end
|
||||
self.itemstring = s:to_string()
|
||||
end
|
||||
})
|
||||
end
|
||||
self.aismtimer = t
|
||||
return bii.on_step(self, dtime, ...)
|
||||
end
|
||||
}
|
||||
setmetatable(newbii, bii)
|
||||
minetest.register_entity(":__builtin:item", newbii)
|
10
mods/nc_api/register_entlabels.lua
Normal file
10
mods/nc_api/register_entlabels.lua
Normal file
@ -0,0 +1,10 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest
|
||||
= minetest
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local oldfunc = minetest.register_entity
|
||||
function minetest.register_entity(name, def, ...)
|
||||
def.label = def.label or name
|
||||
return oldfunc(name, def, ...)
|
||||
end
|
@ -1,74 +0,0 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local math, minetest, nodecore, pairs, unpack
|
||||
= math, minetest, nodecore, pairs, unpack
|
||||
local math_random
|
||||
= math.random
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local genlabels = 0
|
||||
|
||||
function nodecore.register_limited_abm(def)
|
||||
def = nodecore.underride(def, {
|
||||
limited_queue = {},
|
||||
limited_seen = {},
|
||||
limited_qty = 0,
|
||||
limited_max = 1000,
|
||||
limited_interval = 1,
|
||||
limited_jitter = 0.05,
|
||||
limited_action = def.action or function() end,
|
||||
catch_up = false
|
||||
})
|
||||
|
||||
if not def.label then
|
||||
def.label = minetest.get_current_modname() .. ":" .. genlabels
|
||||
genlabels = genlabels + 1
|
||||
end
|
||||
def.limited_alert = def.limited_alert or def.limited_max
|
||||
|
||||
def.action = function(pos, ...)
|
||||
local hash = minetest.hash_node_position(pos)
|
||||
local seen = def.limited_seen
|
||||
if seen[hash] then return end
|
||||
seen[hash] = true
|
||||
|
||||
local q = def.limited_queue
|
||||
local max = def.limited_max
|
||||
local nqty = def.limited_qty + 1
|
||||
if #q < max then
|
||||
q[#q + 1] = {pos, ...}
|
||||
else
|
||||
local r = math_random(1, nqty)
|
||||
if r <= #q then q[r] = {pos, ...} end
|
||||
end
|
||||
def.limited_qty = nqty
|
||||
end
|
||||
|
||||
local function pumpq()
|
||||
minetest.after(def.limited_interval
|
||||
- def.limited_jitter
|
||||
+ def.limited_jitter * math_random() * 2,
|
||||
pumpq)
|
||||
|
||||
if def.limited_qty >= def.limited_alert then
|
||||
minetest.log("limited abm \"" .. def.label .. "\" filled ("
|
||||
.. def.limited_qty .. "/" .. def.limited_max .. ")")
|
||||
end
|
||||
|
||||
local act = def.limited_action
|
||||
for _, args in pairs(def.limited_queue) do
|
||||
local pos = args[1]
|
||||
local node = pos and args[2]
|
||||
local nn = node and minetest.get_node_or_nil(pos)
|
||||
if nn and nn.name == node.name then
|
||||
act(unpack(args))
|
||||
end
|
||||
end
|
||||
|
||||
def.limited_queue = {}
|
||||
def.limited_seen = {}
|
||||
def.limited_qty = 0
|
||||
end
|
||||
pumpq()
|
||||
|
||||
return minetest.register_abm(def)
|
||||
end
|
Binary file not shown.
Before Width: | Height: | Size: 429 B |
@ -1,6 +1,6 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore, pairs
|
||||
= minetest, nodecore, pairs
|
||||
local minetest, nodecore, pairs, vector
|
||||
= minetest, nodecore, pairs, vector
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local queue
|
||||
@ -15,5 +15,6 @@ function nodecore.fallcheck(pos)
|
||||
queue = nil
|
||||
end)
|
||||
end
|
||||
queue[minetest.pos_to_string(pos)] = pos
|
||||
pos = vector.round(pos)
|
||||
queue[minetest.hash_node_position(pos)] = pos
|
||||
end
|
||||
|
@ -5,16 +5,16 @@ local math_abs
|
||||
= math.abs
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
nodecore.register_globalstep("gametime", function(dtime)
|
||||
local mtt = minetest.get_gametime()
|
||||
local nct = nodecore.gametime
|
||||
if not nct then
|
||||
minetest.log("nodecore.gametime: init to " .. mtt)
|
||||
nodecore.log("action", "nodecore.gametime: init to " .. mtt)
|
||||
nct = mtt
|
||||
end
|
||||
nct = nct + dtime
|
||||
if math_abs(nct - mtt) >= 2 then
|
||||
minetest.log("nodecore.gametime: excess drift; nct="
|
||||
nodecore.log("warning", "nodecore.gametime: excess drift; nct="
|
||||
.. nct .. ", mtt=" .. mtt)
|
||||
nct = mtt
|
||||
end
|
||||
|
52
mods/nc_api/util_hookmeta.lua
Normal file
52
mods/nc_api/util_hookmeta.lua
Normal file
@ -0,0 +1,52 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore, pairs, setmetatable, type, unpack
|
||||
= minetest, nodecore, pairs, setmetatable, type, unpack
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local function mkdef(...)
|
||||
local def = {}
|
||||
local ext = {}
|
||||
for _, v in pairs({...}) do
|
||||
if type(v) == "function" then
|
||||
def.func = v
|
||||
elseif type(v) == "string" then
|
||||
def.label = v
|
||||
elseif type(v) == "table" then
|
||||
for tk, tv in pairs(v) do
|
||||
def[tk] = tv
|
||||
end
|
||||
else
|
||||
ext[#ext + 1] = v
|
||||
end
|
||||
end
|
||||
setmetatable(def, {__call = function(_, ...) return def.func(...) end})
|
||||
return def, unpack(ext)
|
||||
end
|
||||
|
||||
for k in pairs({
|
||||
register_globalstep = true,
|
||||
register_playerevent = true,
|
||||
register_on_placenode = true,
|
||||
register_on_dignode = true,
|
||||
register_on_punchnode = true,
|
||||
register_on_generated = true,
|
||||
register_on_newplayer = true,
|
||||
register_on_dieplayer = true,
|
||||
register_on_respawnplayer = true,
|
||||
register_on_prejoinplayer = true,
|
||||
register_on_joinplayer = true,
|
||||
register_on_leaveplayer = true,
|
||||
register_on_cheat = true,
|
||||
register_on_chat_message = true,
|
||||
register_on_player_receive_fields = true,
|
||||
register_on_craft = true,
|
||||
register_craft_predict = true,
|
||||
register_on_protection_violation = true,
|
||||
register_on_item_eat = true,
|
||||
register_on_punchplayer = true,
|
||||
register_on_player_hpchange = true,
|
||||
register_on_shutdown = true
|
||||
}) do
|
||||
local base = minetest[k]
|
||||
nodecore[k] = function(...) return base(mkdef(...)) end
|
||||
end
|
@ -3,10 +3,12 @@ local ItemStack, ipairs, math, minetest, nodecore, pairs, string,
|
||||
tonumber, tostring, type, unpack, vector
|
||||
= ItemStack, ipairs, math, minetest, nodecore, pairs, string,
|
||||
tonumber, tostring, type, unpack, vector
|
||||
local math_cos, math_floor, math_log, math_pi, math_random, math_sin,
|
||||
math_sqrt, string_gsub, string_lower
|
||||
= math.cos, math.floor, math.log, math.pi, math.random, math.sin,
|
||||
math.sqrt, string.gsub, string.lower
|
||||
local math_abs, math_cos, math_floor, math_log, math_pi, math_pow,
|
||||
math_random, math_sin, math_sqrt, string_format, string_gsub,
|
||||
string_lower
|
||||
= math.abs, math.cos, math.floor, math.log, math.pi, math.pow,
|
||||
math.random, math.sin, math.sqrt, string.format, string.gsub,
|
||||
string.lower
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
for k, v in pairs(minetest) do
|
||||
@ -159,11 +161,12 @@ function nodecore.tool_digs(what, groups)
|
||||
end
|
||||
|
||||
function nodecore.interval(after, func)
|
||||
local function go()
|
||||
minetest.after(after, go)
|
||||
return func()
|
||||
end
|
||||
minetest.after(after, go)
|
||||
local go
|
||||
local setnext = (type(after) == "function")
|
||||
and function() return minetest.after(after(), go) end
|
||||
or function() return minetest.after(after, go) end
|
||||
go = function() setnext() return func() end
|
||||
minetest.after(0, go)
|
||||
end
|
||||
|
||||
function nodecore.wear_wield(player, groups, qty)
|
||||
@ -179,7 +182,7 @@ function nodecore.wear_wield(player, groups, qty)
|
||||
wielded:add_wear(dp.wear * (qty or 1))
|
||||
if wielded:get_count() <= 0 and wdef.sound
|
||||
and wdef.sound.breaks then
|
||||
minetest.sound_play(wdef.sound.breaks,
|
||||
nodecore.sound_play(wdef.sound.breaks,
|
||||
{object = player, gain = 0.5})
|
||||
end
|
||||
end
|
||||
@ -218,60 +221,6 @@ function nodecore.node_group(name, pos, node)
|
||||
return def.groups and def.groups[name]
|
||||
end
|
||||
|
||||
function nodecore.item_eject(pos, stack, speed, qty, vel)
|
||||
stack = ItemStack(stack)
|
||||
speed = speed or 0
|
||||
vel = vel or {x = 0, y = 0, z = 0}
|
||||
if speed == 0 and vel.x == 0 and vel.y == 0 and vel.z == 0
|
||||
and nodecore.place_stack and minetest.get_node(pos).name == "air" then
|
||||
stack:set_count(stack:get_count() * (qty or 1))
|
||||
return nodecore.place_stack(pos, stack)
|
||||
end
|
||||
for _ = 1, (qty or 1) do
|
||||
local v = {
|
||||
x = vel.x + (math_random() - 0.5) * speed,
|
||||
y = vel.y + math_random() * speed,
|
||||
z = vel.z + (math_random() - 0.5) * speed,
|
||||
}
|
||||
local p = {
|
||||
x = v.x > 0 and pos.x + 0.4 or v.x < 0 and pos.x - 0.4 or pos.x,
|
||||
y = pos.y + 0.25,
|
||||
z = v.z > 0 and pos.z + 0.4 or v.z < 0 and pos.z - 0.4 or pos.z,
|
||||
}
|
||||
local obj = minetest.add_item(p, stack)
|
||||
if obj then obj:set_velocity(v) end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local stddirs = {}
|
||||
for _, v in pairs(nodecore.dirs()) do
|
||||
if v.y <= 0 then stddirs[#stddirs + 1] = v end
|
||||
end
|
||||
function nodecore.item_disperse(pos, name, qty, outdirs)
|
||||
if qty < 1 then return end
|
||||
local dirs = {}
|
||||
for _, d in pairs(outdirs or stddirs) do
|
||||
local p = vector.add(pos, d)
|
||||
if nodecore.buildable_to(p) then
|
||||
dirs[#dirs + 1] = {pos = p, qty = 0}
|
||||
end
|
||||
end
|
||||
if #dirs < 1 then
|
||||
return nodecore.item_eject(pos, name .. " " .. qty)
|
||||
end
|
||||
for _ = 1, qty do
|
||||
local p = dirs[math_random(1, #dirs)]
|
||||
p.qty = p.qty + 1
|
||||
end
|
||||
for _, v in pairs(dirs) do
|
||||
if v.qty > 0 then
|
||||
nodecore.item_eject(v.pos, name .. " " .. v.qty)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function nodecore.find_nodes_around(pos, spec, r, s)
|
||||
r = r or 1
|
||||
if type(r) == "number" then
|
||||
@ -302,10 +251,11 @@ function nodecore.node_spin_custom(...)
|
||||
local qty = #arr
|
||||
|
||||
return function(pos, node, clicker, itemstack)
|
||||
if nodecore.protection_test(pos, clicker) then return end
|
||||
node = node or minetest.get_node(pos)
|
||||
node.param2 = lut[node.param2] or lut[false]
|
||||
if clicker:is_player() then
|
||||
minetest.log(clicker:get_player_name() .. " spins "
|
||||
nodecore.log("action", clicker:get_player_name() .. " spins "
|
||||
.. node.name .. " at " .. minetest.pos_to_string(pos)
|
||||
.. " to param2 " .. node.param2 .. " ("
|
||||
.. qty .. " total)")
|
||||
@ -333,11 +283,6 @@ function nodecore.node_spin_filtered(func)
|
||||
return nodecore.node_spin_custom(unpack(rots))
|
||||
end
|
||||
|
||||
function nodecore.node_change(pos, node, newname)
|
||||
if node.name == newname then return end
|
||||
return minetest.set_node(pos, underride({name = newname}, node))
|
||||
end
|
||||
|
||||
local function scrubkey(s)
|
||||
return string_lower(string_gsub(tostring(s), "%W+", "_"))
|
||||
end
|
||||
@ -354,6 +299,11 @@ function nodecore.rate_adjustment(...)
|
||||
return rate
|
||||
end
|
||||
|
||||
local infodump_key = scrubkey(nodecore.product) .. "_infodump"
|
||||
function nodecore.infodump()
|
||||
return minetest.settings:get_bool(infodump_key)
|
||||
end
|
||||
|
||||
function nodecore.obstructed(minpos, maxpos)
|
||||
if not maxpos then
|
||||
maxpos = {x = minpos.x + 0.5, y = minpos.y + 0.5, z = minpos.z + 0.5}
|
||||
@ -363,16 +313,211 @@ function nodecore.obstructed(minpos, maxpos)
|
||||
local radius = 4 + vector.distance(minpos, maxpos) / 2
|
||||
for _, obj in pairs(minetest.get_objects_inside_radius(avgpos, radius)) do
|
||||
local op = obj:get_pos()
|
||||
local cb = obj:get_properties().collisionbox
|
||||
if maxpos.x > op.x + cb[1] and minpos.x < op.x + cb[4]
|
||||
local props = obj:get_properties()
|
||||
local cb = props.collisionbox
|
||||
if props.static_save
|
||||
and maxpos.x > op.x + cb[1] and minpos.x < op.x + cb[4]
|
||||
and maxpos.y > op.y + cb[2] and minpos.y < op.y + cb[5]
|
||||
and maxpos.z > op.z + cb[3] and minpos.z < op.z + cb[6]
|
||||
then
|
||||
local lua = obj.get_luaentity and obj:get_luaentity()
|
||||
if not ((lua and lua.is_stack) or (not nodecore.interact(obj))
|
||||
or (not nodecore.player_visible(obj))) then
|
||||
return obj
|
||||
end
|
||||
and obj.get_luaentity and obj:get_luaentity() then
|
||||
return obj
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local gravity = tonumber(minetest.settings:get("movement_gravity")) or 9.81
|
||||
local friction = tonumber(minetest.settings:get("nodecore_air_friction")) or 0.0004
|
||||
|
||||
local function air_accel_factor(v)
|
||||
local q = (friction * v * v) * 2 - 1
|
||||
return q > 0 and q or 0
|
||||
end
|
||||
function nodecore.grav_air_physics_player(v)
|
||||
if v.y > 0 then return 1 end
|
||||
return 1 - air_accel_factor(v.y)
|
||||
end
|
||||
local function air_accel_net(v)
|
||||
return v == 0 and 0 or v / -math_abs(v) * gravity * air_accel_factor(v)
|
||||
end
|
||||
function nodecore.grav_air_accel(v)
|
||||
return {
|
||||
x = air_accel_net(v.x),
|
||||
y = air_accel_net(v.y) - gravity,
|
||||
z = air_accel_net(v.z)
|
||||
}
|
||||
end
|
||||
function nodecore.grav_air_accel_ent(obj)
|
||||
local cur = obj:get_acceleration()
|
||||
local new = nodecore.grav_air_accel(obj:get_velocity())
|
||||
if vector.equals(cur, new) then return end
|
||||
return obj:set_acceleration(new)
|
||||
end
|
||||
|
||||
function nodecore.near_unloaded(pos, radius)
|
||||
return minetest.find_node_near(pos, radius or 1, {"ignore"}, true)
|
||||
end
|
||||
|
||||
function nodecore.get_objects_at_pos(pos)
|
||||
pos = vector.round(pos)
|
||||
local t = {}
|
||||
-- get_objects_inside_radius just loops over these and does a euclidian
|
||||
-- distance check anyway, which we can skip
|
||||
for _, obj in pairs(minetest.object_refs) do
|
||||
local p = obj:get_pos()
|
||||
if p and vector.equals(vector.round(p), pos) then
|
||||
t[#t + 1] = obj
|
||||
end
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
function nodecore.get_depth_light(y, qty)
|
||||
qty = qty or 4/5
|
||||
if y < 0 then qty = qty * math_pow(2, y / 64) end
|
||||
return qty
|
||||
end
|
||||
|
||||
nodecore.light_sun = 15
|
||||
nodecore.light_sky = math_floor(0.5 + nodecore.light_sun * nodecore.get_depth_light(0))
|
||||
|
||||
function nodecore.is_full_sun(pos)
|
||||
return pos.y >= 0 and minetest.get_node_light(pos, 0.5) == nodecore.light_sun
|
||||
end
|
||||
|
||||
function nodecore.get_node_light(pos)
|
||||
local artificial = minetest.get_node_light(pos, 0)
|
||||
if not artificial then return end
|
||||
local natural = math_floor(0.5 + minetest.get_node_light(pos, 0.5)
|
||||
* nodecore.get_depth_light(pos.y))
|
||||
return artificial > natural and artificial or natural
|
||||
end
|
||||
|
||||
local liquids = {}
|
||||
minetest.after(0, function()
|
||||
for k, v in pairs(minetest.registered_items) do
|
||||
if v.liquidtype and v.liquidtype ~= "none" then
|
||||
liquids[k] = v
|
||||
end
|
||||
end
|
||||
end)
|
||||
nodecore.registered_liquids = liquids
|
||||
local player_was_swimming = {}
|
||||
function nodecore.player_swimming(player)
|
||||
local pname = player:get_player_name()
|
||||
local pos = player:get_pos()
|
||||
local r = 0.6
|
||||
local swimming = true
|
||||
for dz = -r, r, r do
|
||||
for dx = -r, r, r do
|
||||
local p = {
|
||||
x = pos.x + dx,
|
||||
y = pos.y,
|
||||
z = pos.z + dz
|
||||
}
|
||||
local node = minetest.get_node(p)
|
||||
if (node.name == "air" or liquids[node.name]) then
|
||||
p.y = p.y - 0.35
|
||||
node = minetest.get_node(p)
|
||||
end
|
||||
if node.name == "air" then swimming = nil
|
||||
elseif not liquids[node.name] then
|
||||
player_was_swimming[pname] = nil
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
if swimming then
|
||||
player_was_swimming[pname] = true
|
||||
return true
|
||||
end
|
||||
return player_was_swimming[pname]
|
||||
end
|
||||
|
||||
local function mismatch(a, b)
|
||||
if type(a) == "table" then
|
||||
if type(b) ~= "table" then return true end
|
||||
for k, v in pairs(a) do
|
||||
if mismatch(v, b[k]) then return true end
|
||||
end
|
||||
return
|
||||
end
|
||||
if type(a) == "number" and type(b) == "number" then
|
||||
local ratio = a / b
|
||||
-- Floating point rounding...
|
||||
if ratio > 0.99999 and ratio < 1.00001 then return end
|
||||
end
|
||||
return a ~= b
|
||||
end
|
||||
nodecore.prop_mismatch = mismatch
|
||||
|
||||
function nodecore.item_matching_index(items, getnames, idxname, asarray, keymod)
|
||||
local index = {}
|
||||
local function itemadd(key, item)
|
||||
local t = index[key]
|
||||
if not t then
|
||||
t = {}
|
||||
index[key] = t
|
||||
end
|
||||
if asarray then
|
||||
t[#t + 1] = item
|
||||
else
|
||||
t[item] = true
|
||||
end
|
||||
end
|
||||
keymod = keymod or function(x) return x end
|
||||
local report_pending
|
||||
local function rebuild()
|
||||
for k in pairs(index) do index[k] = nil end
|
||||
for _, item in pairs(items) do
|
||||
for _, name in pairs(getnames(item)) do
|
||||
if name == true then
|
||||
for k in pairs(minetest.registered_items) do
|
||||
itemadd(keymod(k, item), item)
|
||||
end
|
||||
elseif type(name) == "string" and name:sub(1, 6) == "group:" then
|
||||
for k, v in pairs(minetest.registered_items) do
|
||||
if v and v.groups and v.groups[name:sub(7)] then
|
||||
itemadd(keymod(k, item), item)
|
||||
end
|
||||
end
|
||||
else
|
||||
itemadd(keymod(name, item), item)
|
||||
end
|
||||
end
|
||||
end
|
||||
if idxname and not report_pending then
|
||||
report_pending = true
|
||||
minetest.after(0, function()
|
||||
report_pending = nil
|
||||
local keys = 0
|
||||
local defs = 0
|
||||
local peak = 0
|
||||
for _, v in pairs(index) do
|
||||
keys = keys + 1
|
||||
local n = 0
|
||||
for _ in pairs(v) do n = n + 1 end
|
||||
defs = defs + n
|
||||
if n > peak then peak = n end
|
||||
end
|
||||
nodecore.log("action", string_format(
|
||||
"%s %s: %d keys, %d defs, %d peak",
|
||||
"item_matching_index",
|
||||
idxname, keys, defs, peak))
|
||||
end)
|
||||
end
|
||||
end
|
||||
minetest.after(0, rebuild)
|
||||
return index, rebuild
|
||||
end
|
||||
|
||||
function nodecore.protection_test(pos, player)
|
||||
if not player then return end
|
||||
if type(player) ~= "string" then
|
||||
if not player:is_player() then return end
|
||||
player = player:get_player_name()
|
||||
end
|
||||
if minetest.is_protected(pos, player) then
|
||||
minetest.record_protection_violation(pos, player)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
@ -17,3 +17,22 @@ nodecore.buildable_to = defprop("buildable_to")
|
||||
nodecore.walkable = defprop("walkable")
|
||||
nodecore.climbable = defprop("climbable")
|
||||
nodecore.sunlight_propagates = defprop("sunlight_propagates")
|
||||
|
||||
local airpass_drawtypes = {
|
||||
airlike = true,
|
||||
torchlike = true,
|
||||
signlike = true,
|
||||
firelike = true,
|
||||
fencelike = true,
|
||||
raillike = true,
|
||||
nodebox = true,
|
||||
mesh = true,
|
||||
plantlike = true
|
||||
}
|
||||
function nodecore.air_pass(thing)
|
||||
local name = type(thing) == "string" and thing or thing.name
|
||||
or minetest.get_node(thing).name
|
||||
local def = minetest.registered_items[name] or {}
|
||||
if def.air_pass ~= nil then return def.air_pass end
|
||||
return airpass_drawtypes[def.drawtype or false] or false
|
||||
end
|
||||
|
@ -1,6 +1,6 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local math, minetest, nodecore
|
||||
= math, minetest, nodecore
|
||||
local math, nodecore, type
|
||||
= math, nodecore, type
|
||||
local math_ceil
|
||||
= math.ceil
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
@ -10,25 +10,29 @@ local function getphealth(player)
|
||||
end
|
||||
nodecore.getphealth = getphealth
|
||||
|
||||
local function setphealth(player, hp)
|
||||
if hp > 20 then hp = 20 end
|
||||
local function setphealth(player, hp, reason, minwhole)
|
||||
local hpmax = player:get_properties().hp_max
|
||||
if hp > hpmax then hp = hpmax end
|
||||
if hp < 0 then hp = 0 end
|
||||
local whole = math_ceil(hp)
|
||||
if whole == 0 then whole = 1 end
|
||||
if minwhole and whole < minwhole then whole = minwhole end
|
||||
local dhp = hp - whole
|
||||
player:get_meta():set_float("dhp", dhp)
|
||||
local old = player:get_hp()
|
||||
player:set_hp(whole)
|
||||
if type(reason) ~= "table" then reason = {nc_type = reason} end
|
||||
reason = reason or {}
|
||||
reason.from = "mod"
|
||||
reason.type = "set_hp"
|
||||
player:set_hp(whole, reason)
|
||||
return old ~= whole
|
||||
end
|
||||
nodecore.setphealth = setphealth
|
||||
|
||||
local function addphealth(player, hp)
|
||||
return setphealth(player, getphealth(player) + hp)
|
||||
local function addphealth(player, hp, reason)
|
||||
return setphealth(player,
|
||||
getphealth(player) + hp,
|
||||
reason,
|
||||
hp >= 0 and player:get_hp())
|
||||
end
|
||||
nodecore.addphealth = addphealth
|
||||
|
||||
function nodecore.node_punch_hurt(pos, node, puncher, ...)
|
||||
if puncher and puncher:is_player() then addphealth(puncher, -1) end
|
||||
return minetest.node_punch(pos, node, puncher, ...)
|
||||
end
|
||||
|
@ -20,7 +20,8 @@ function nodecore.scan_flood(pos, range, func)
|
||||
local np = {
|
||||
x = p.x + v.x,
|
||||
y = p.y + v.y,
|
||||
z = p.z + v.z
|
||||
z = p.z + v.z,
|
||||
prev = p
|
||||
}
|
||||
local nk = minetest.hash_node_position(np)
|
||||
if not seen[nk] then
|
||||
|
69
mods/nc_api/util_settlescan.lua
Normal file
69
mods/nc_api/util_settlescan.lua
Normal file
@ -0,0 +1,69 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local math, nodecore, pairs, table, vector
|
||||
= math, nodecore, pairs, table, vector
|
||||
local math_random, table_sort
|
||||
= math.random, table.sort
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local settleorder = {}
|
||||
|
||||
local groups = {}
|
||||
local keys = {}
|
||||
for x = -5, 5 do
|
||||
for y = -5, 5 do
|
||||
for z = -5, 5 do
|
||||
local p = {
|
||||
x = x,
|
||||
y = y,
|
||||
z = z,
|
||||
}
|
||||
local d = vector.length(p)
|
||||
if d <= 5 then
|
||||
p.v = d + p.y / 100
|
||||
local g = groups[p.v]
|
||||
if not g then
|
||||
g = {}
|
||||
groups[p.v] = g
|
||||
keys[#keys + 1] = p.v
|
||||
end
|
||||
g[#g + 1] = p
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
table_sort(keys)
|
||||
for _, k in pairs(keys) do
|
||||
local stamp = 0
|
||||
local t = groups[k]
|
||||
settleorder[#settleorder + 1] = function()
|
||||
if stamp == nodecore.gametime then return t end
|
||||
local n = #t
|
||||
if n < 2 then return t end
|
||||
for i = 1, n do
|
||||
local j = math_random(1, n)
|
||||
local x = t[i]
|
||||
t[i] = t[j]
|
||||
t[j] = x
|
||||
end
|
||||
stamp = nodecore.gametime
|
||||
return t
|
||||
end
|
||||
end
|
||||
|
||||
function nodecore.settlescan()
|
||||
local i = 0
|
||||
local grp = {}
|
||||
local j = 0
|
||||
return function()
|
||||
if j >= #grp then
|
||||
if i >= #settleorder then
|
||||
return
|
||||
end
|
||||
i = i + 1
|
||||
grp = settleorder[i]()
|
||||
j = 0
|
||||
end
|
||||
j = j + 1
|
||||
return grp[j]
|
||||
end
|
||||
end
|
@ -8,48 +8,18 @@ local math_exp, math_random, math_sin, math_sqrt
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local oldplay = minetest.sound_play
|
||||
function minetest.sound_play(name, spec, ...)
|
||||
if spec and type(spec) == "table" and spec.pitch == nil then
|
||||
spec.pitch = math_exp((math_random() - 0.5) * (spec.pitchvary or 0.05))
|
||||
function nodecore.sound_play(name, spec, ephem, ...)
|
||||
if spec and type(spec) == "table" then
|
||||
spec.pitch = (spec.pitch or 1) * math_exp(
|
||||
(math_random() - 0.5) * (spec.pitchvary or 0.05))
|
||||
end
|
||||
return oldplay(name, spec, ...)
|
||||
end
|
||||
|
||||
function nodecore.windiness(y)
|
||||
if y < 0 then return 0 end
|
||||
if y > 512 then y = 512 end
|
||||
return math_sqrt(y) * (1 + 0.5 * math_sin(nodecore.gametime / 5))
|
||||
end
|
||||
|
||||
function nodecore.stack_sounds(pos, kind, stack)
|
||||
stack = stack or nodecore.stack_get(pos)
|
||||
stack = ItemStack(stack)
|
||||
if stack:is_empty() then return end
|
||||
local def = minetest.registered_items[stack:get_name()] or {}
|
||||
if (not def.sounds) or (not def.sounds[kind]) then return end
|
||||
local t = {}
|
||||
for k, v in pairs(def.sounds[kind]) do t[k] = v end
|
||||
t.pos = pos
|
||||
return minetest.sound_play(t.name, t)
|
||||
end
|
||||
function nodecore.stack_sounds_delay(...)
|
||||
local t = {...}
|
||||
minetest.after(0, function()
|
||||
nodecore.stack_sounds(unpack(t))
|
||||
end)
|
||||
end
|
||||
function nodecore.sounds(name, gfoot, gdug, gplace)
|
||||
return {
|
||||
footstep = {name = name, gain = gfoot or 0.2},
|
||||
dig = {name = name, gain = gdug or 0.5},
|
||||
dug = {name = name, gain = gdug or 1},
|
||||
place = {name = name, gain = gplace or 1}
|
||||
}
|
||||
if ephem == nil then ephem = not spec.not_ephemeral end
|
||||
return oldplay(name, spec, ephem, ...)
|
||||
end
|
||||
|
||||
function nodecore.sound_play_except(name, def, pname)
|
||||
if not pname then
|
||||
return minetest.sound_play(name, def)
|
||||
return nodecore.sound_play(name, def)
|
||||
end
|
||||
if type(pname) ~= "string" then
|
||||
pname = pname:get_player_name()
|
||||
@ -59,18 +29,72 @@ function nodecore.sound_play_except(name, def, pname)
|
||||
if pn ~= pname and ((not def.pos)
|
||||
or (vector.distance(p:get_pos(), def.pos) <= 32)) then
|
||||
def.to_player = pn
|
||||
minetest.sound_play(name, def)
|
||||
nodecore.sound_play(name, def)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function nodecore.windiness(y)
|
||||
if y < 0 then return 0 end
|
||||
if y > 512 then y = 512 end
|
||||
return math_sqrt(y) * (1 + 0.5 * math_sin(nodecore.gametime / 5))
|
||||
end
|
||||
|
||||
function nodecore.stack_sounds(pos, kind, stack, except)
|
||||
stack = stack or nodecore.stack_get(pos)
|
||||
stack = ItemStack(stack)
|
||||
if stack:is_empty() then return end
|
||||
local def = minetest.registered_items[stack:get_name()] or {}
|
||||
if (not def.sounds) or (not def.sounds[kind]) then return end
|
||||
local t = {}
|
||||
for k, v in pairs(def.sounds[kind]) do t[k] = v end
|
||||
t.pos = pos
|
||||
if except then return nodecore.sound_play_except(t.name, t, except) end
|
||||
return nodecore.sound_play(t.name, t)
|
||||
end
|
||||
function nodecore.stack_sounds_delay(...)
|
||||
local t = {...}
|
||||
minetest.after(0, function()
|
||||
nodecore.stack_sounds(unpack(t))
|
||||
end)
|
||||
end
|
||||
|
||||
local gains_base = {
|
||||
footstep = 0.2,
|
||||
dig = 0.5,
|
||||
dug = 1,
|
||||
place = 1,
|
||||
place_failed = 0.2,
|
||||
fall = 0.1
|
||||
}
|
||||
function nodecore.sounds(name, gains, pitch)
|
||||
local t = {}
|
||||
for k, v in pairs(gains_base) do
|
||||
t[k] = {
|
||||
name = name,
|
||||
gain = (gains and gains[k] or 1) * v,
|
||||
pitch = pitch
|
||||
}
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
function nodecore.node_sound(pos, kind, opts)
|
||||
nodecore.stack_sounds(pos, kind)
|
||||
local node = opts and opts.node or minetest.get_node(pos)
|
||||
local def = minetest.registered_items[node.name] or {}
|
||||
if def.groups and def.groups.visinv then
|
||||
nodecore.stack_sounds(pos, kind)
|
||||
end
|
||||
if (not def.sounds) or (not def.sounds[kind]) then return end
|
||||
local t = {}
|
||||
for k, v in pairs(def.sounds[kind]) do t[k] = v end
|
||||
t.pos = pos
|
||||
return nodecore.sound_play_except(t.name, t, opts and opts.except)
|
||||
end
|
||||
|
||||
function nodecore.set_loud(pos, node, opts)
|
||||
minetest.set_node(pos, node)
|
||||
opts = opts or {}
|
||||
opts.node = node
|
||||
return nodecore.node_sound(pos, "place", opts)
|
||||
end
|
||||
|
@ -1,14 +1,39 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, ipairs, minetest, nodecore
|
||||
= ItemStack, ipairs, minetest, nodecore
|
||||
local ItemStack, getmetatable, math, minetest, nodecore, pairs, string,
|
||||
vector
|
||||
= ItemStack, getmetatable, math, minetest, nodecore, pairs, string,
|
||||
vector
|
||||
local math_cos, math_floor, math_pi, math_random, math_sin,
|
||||
string_format
|
||||
= math.cos, math.floor, math.pi, math.random, math.sin,
|
||||
string.format
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local function shortdesc(stack, noqty)
|
||||
stack = ItemStack(stack)
|
||||
if noqty and stack:get_count() > 1 then stack:set_count(1) end
|
||||
local pre = stack:to_string()
|
||||
stack:get_meta():from_table({})
|
||||
local desc = stack:to_string()
|
||||
if pre == desc then return desc end
|
||||
return string_format("%s @%d", desc, #pre - #desc)
|
||||
end
|
||||
nodecore.stack_shortdesc = shortdesc
|
||||
|
||||
local function family(stack)
|
||||
stack = ItemStack(stack)
|
||||
if stack:is_empty() then return "" end
|
||||
local name = stack:get_name()
|
||||
local def = minetest.registered_items[name]
|
||||
return def and def.stackfamily or stack:to_string()
|
||||
if def and def.stackfamily then
|
||||
stack:set_name(def.stackfamily)
|
||||
end
|
||||
if stack:get_count() > 1 then
|
||||
stack:set_count(1)
|
||||
end
|
||||
return stack:to_string()
|
||||
end
|
||||
nodecore.stack_family = family
|
||||
function nodecore.stack_merge(dest, src)
|
||||
if dest:is_empty() then return dest:add_item(src) end
|
||||
if family(src) ~= family(dest) then
|
||||
@ -32,17 +57,19 @@ function nodecore.stack_get(pos)
|
||||
end
|
||||
|
||||
local function update(pos, ...)
|
||||
for _, v in ipairs(nodecore.visinv_update_ents(pos)) do
|
||||
v:get_luaentity():itemcheck()
|
||||
end
|
||||
nodecore.visinv_update_ents(pos)
|
||||
return ...
|
||||
end
|
||||
|
||||
function nodecore.stack_set(pos, stack)
|
||||
function nodecore.stack_set(pos, stack, player)
|
||||
if player then
|
||||
nodecore.log("action", string_format("%s sets stack %q at %s",
|
||||
player:get_player_name(), shortdesc(stack), minetest.pos_to_string(pos)))
|
||||
end
|
||||
return update(pos, nodecore.node_inv(pos):set_stack("solo", 1, ItemStack(stack)))
|
||||
end
|
||||
|
||||
function nodecore.stack_add(pos, stack)
|
||||
function nodecore.stack_add(pos, stack, player)
|
||||
local node = minetest.get_node(pos)
|
||||
local def = minetest.registered_items[node.name] or {}
|
||||
if def.stack_allow then
|
||||
@ -51,7 +78,9 @@ function nodecore.stack_add(pos, stack)
|
||||
if ret and ret ~= true then return ret end
|
||||
end
|
||||
stack = ItemStack(stack)
|
||||
local donate = stack:get_count()
|
||||
local item = nodecore.stack_get(pos)
|
||||
local exist = item:get_count()
|
||||
local left
|
||||
if item:is_empty() then
|
||||
left = nodecore.node_inv(pos):add_item("solo", stack)
|
||||
@ -59,7 +88,15 @@ function nodecore.stack_add(pos, stack)
|
||||
left = nodecore.stack_merge(item, stack)
|
||||
nodecore.stack_set(pos, item)
|
||||
end
|
||||
if left:get_count() ~= stack:get_count() then
|
||||
local remain = left:get_count()
|
||||
if donate ~= remain then
|
||||
if player then
|
||||
nodecore.log("action", string_format(
|
||||
"%s adds stack %q %d + %d = %d + %d at %s",
|
||||
player:get_player_name(), shortdesc(stack, true),
|
||||
exist, donate, exist + donate - remain, remain,
|
||||
minetest.pos_to_string(pos)))
|
||||
end
|
||||
nodecore.stack_sounds(pos, "place")
|
||||
end
|
||||
return update(pos, left)
|
||||
@ -70,10 +107,144 @@ function nodecore.stack_giveto(pos, player)
|
||||
local qty = stack:get_count()
|
||||
if qty < 1 then return true end
|
||||
|
||||
stack = player:get_inventory():add_item("main", stack)
|
||||
if stack:get_count() == qty then return stack:is_empty() end
|
||||
local left = player:get_inventory():add_item("main", stack)
|
||||
local remain = left:get_count()
|
||||
if remain == qty then return stack:is_empty() end
|
||||
|
||||
nodecore.log("action", string_format(
|
||||
"%s takes stack %q %d - %d = %d at %s",
|
||||
player:get_player_name(), shortdesc(stack, true),
|
||||
qty, qty - remain, remain, minetest.pos_to_string(pos)))
|
||||
|
||||
nodecore.stack_sounds(pos, "dug")
|
||||
nodecore.stack_set(pos, stack)
|
||||
nodecore.stack_set(pos, left)
|
||||
return stack:is_empty()
|
||||
end
|
||||
|
||||
function nodecore.item_eject(pos, stack, speed, qty, vel)
|
||||
stack = ItemStack(stack)
|
||||
speed = speed or 0
|
||||
vel = vel or {x = 0, y = 0, z = 0}
|
||||
if speed == 0 and vel.x == 0 and vel.y == 0 and vel.z == 0
|
||||
and nodecore.place_stack and minetest.get_node(pos).name == "air" then
|
||||
stack:set_count(stack:get_count() * (qty or 1))
|
||||
return nodecore.place_stack(pos, stack)
|
||||
end
|
||||
for _ = 1, (qty or 1) do
|
||||
local v = {x = vel.x, y = vel.y, z = vel.z}
|
||||
if speed > 0 then
|
||||
local inc = math_random() * math_pi / 3
|
||||
local y = math_sin(inc)
|
||||
local xz = math_cos(inc)
|
||||
local theta = math_random() * math_pi * 2
|
||||
local x = math_sin(theta) * xz
|
||||
local z = math_cos(theta) * xz
|
||||
v = {
|
||||
x = v.x + x * speed,
|
||||
y = v.y + y * speed,
|
||||
z = v.z + z * speed
|
||||
}
|
||||
end
|
||||
local p = {x = pos.x, y = pos.y + 0.25, z = pos.z}
|
||||
local obj = minetest.add_item(p, stack)
|
||||
if obj then obj:set_velocity(v) end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local stddirs = {}
|
||||
for _, v in pairs(nodecore.dirs()) do
|
||||
if v.y <= 0 then stddirs[#stddirs + 1] = v end
|
||||
end
|
||||
function nodecore.item_disperse(pos, name, qty, outdirs)
|
||||
if qty < 1 then return end
|
||||
local dirs = {}
|
||||
for _, d in pairs(outdirs or stddirs) do
|
||||
local p = vector.add(pos, d)
|
||||
if nodecore.buildable_to(p) then
|
||||
dirs[#dirs + 1] = {pos = p, qty = 0}
|
||||
end
|
||||
end
|
||||
if #dirs < 1 then
|
||||
return nodecore.item_eject(pos, name .. " " .. qty)
|
||||
end
|
||||
for _ = 1, qty do
|
||||
local p = dirs[math_random(1, #dirs)]
|
||||
p.qty = p.qty + 1
|
||||
end
|
||||
for _, v in pairs(dirs) do
|
||||
if v.qty > 0 then
|
||||
nodecore.item_eject(v.pos, name .. " " .. v.qty)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function item_lose(player, listname, slot, speed)
|
||||
local inv = player:get_inventory()
|
||||
local stack = inv:get_stack(listname, slot)
|
||||
if stack:is_empty() or nodecore.item_is_virtual(stack) then return end
|
||||
|
||||
local pos = player:get_pos()
|
||||
pos.y = pos.y + player:get_properties().eye_height
|
||||
|
||||
local def = stack:get_definition() or {}
|
||||
if def.on_drop
|
||||
and def.on_drop ~= minetest.item_drop
|
||||
and def.on_drop ~= minetest.nodedef_default.on_drop
|
||||
and def.on_drop ~= minetest.craftitemdef_default.on_drop
|
||||
and def.on_drop ~= minetest.tooldef_default.on_drop
|
||||
and def.on_drop ~= minetest.noneitemdef_default.on_drop then
|
||||
nodecore.log("action", string_format("%s loses item %q at %s by on_drop",
|
||||
player:get_player_name(), shortdesc(stack),
|
||||
minetest.pos_to_string(pos, 0)))
|
||||
stack = def.on_drop(stack, player, pos)
|
||||
return inv:set_stack(listname, slot, stack)
|
||||
end
|
||||
|
||||
nodecore.log("action", string_format("%s loses item %q at %s by eject(%d)",
|
||||
player:get_player_name(), shortdesc(stack),
|
||||
minetest.pos_to_string(pos, 0), math_floor(speed + 0.5)))
|
||||
nodecore.item_eject(pos, stack, speed)
|
||||
return inv:set_stack(listname, slot, "")
|
||||
end
|
||||
nodecore.item_lose = item_lose
|
||||
|
||||
function nodecore.inventory_dump(player)
|
||||
for listname, list in pairs(player:get_inventory():get_lists()) do
|
||||
if listname ~= "hand" then
|
||||
for slot in pairs(list) do
|
||||
item_lose(player, listname, slot, 0.001)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local keeppriv = "keepinv"
|
||||
minetest.register_privilege(keeppriv, {
|
||||
description = "Allow player to keep inventory on teleport",
|
||||
give_to_singleplayer = false,
|
||||
give_to_admin = false
|
||||
})
|
||||
|
||||
local telefunc = minetest.registered_chatcommands.teleport
|
||||
telefunc = telefunc and telefunc.func
|
||||
if telefunc then
|
||||
minetest.registered_chatcommands.teleport.func = function(...)
|
||||
local anyplayer = minetest.get_connected_players()[1]
|
||||
local meta = anyplayer and getmetatable(anyplayer)
|
||||
local oldsetpos = meta and meta.set_pos
|
||||
if not oldsetpos then return telefunc(...) end
|
||||
meta.set_pos = function(player, ...)
|
||||
if not minetest.check_player_privs(player, keeppriv) then
|
||||
nodecore.inventory_dump(player)
|
||||
end
|
||||
return oldsetpos(player, ...)
|
||||
end
|
||||
local function helper(...)
|
||||
meta.set_pos = oldsetpos
|
||||
return ...
|
||||
end
|
||||
return helper(telefunc(...))
|
||||
end
|
||||
end
|
||||
|
95
mods/nc_api/util_texturemod.lua
Normal file
95
mods/nc_api/util_texturemod.lua
Normal file
@ -0,0 +1,95 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local nodecore, pairs, setmetatable, string, tostring
|
||||
= nodecore, pairs, setmetatable, string, tostring
|
||||
local string_find, string_gsub
|
||||
= string.find, string.gsub
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local tmod = {}
|
||||
local tmeta = {}
|
||||
setmetatable(tmod, tmeta)
|
||||
nodecore.tmod = tmod
|
||||
|
||||
function tmod:new(img)
|
||||
local obj = {img = img}
|
||||
local ometa = {}
|
||||
for k, v in pairs(tmeta) do ometa[k] = v end
|
||||
ometa.__index = self
|
||||
setmetatable(obj, ometa)
|
||||
return obj
|
||||
end
|
||||
tmeta.__call = tmod.new
|
||||
|
||||
function tmeta:__tostring()
|
||||
return self.img
|
||||
end
|
||||
|
||||
function tmod:add(img)
|
||||
if not self.img then return tmod:new(img) end
|
||||
img = tostring(img)
|
||||
if string_find(img, "%^") then
|
||||
return tmod:new(self.img .. "^(" .. img .. ")")
|
||||
else
|
||||
return tmod:new(self.img .. "^" .. img)
|
||||
end
|
||||
end
|
||||
|
||||
local function esc(s)
|
||||
return string_gsub(string_gsub(tostring(s),
|
||||
"%^", "\\^"), ":", "\\:")
|
||||
end
|
||||
|
||||
local function addmod(self, name)
|
||||
if self.img then
|
||||
return self.img .. "^[" .. name
|
||||
end
|
||||
return "[" .. name
|
||||
end
|
||||
|
||||
local function simplemod(name, ...)
|
||||
local delims = {...}
|
||||
local lastdelim = delims[#delims]
|
||||
return function(self, ...)
|
||||
local s = addmod(self, name)
|
||||
local args = {...}
|
||||
for i = 1, #args do
|
||||
s = s .. (delims[i] or lastdelim) .. esc(args[i])
|
||||
end
|
||||
return tmod:new(s)
|
||||
end
|
||||
end
|
||||
|
||||
for k in pairs({
|
||||
crack = true,
|
||||
cracko = true,
|
||||
opacity = true,
|
||||
invert = true,
|
||||
brighten = true,
|
||||
noalpha = true,
|
||||
lowpart = true,
|
||||
verticalframe = true,
|
||||
mask = true,
|
||||
colorize = true,
|
||||
multiply = true
|
||||
}) do
|
||||
tmod[k] = simplemod(k, ":")
|
||||
end
|
||||
|
||||
tmod.resize = simplemod("resize", ":", "x")
|
||||
tmod.makealpha = simplemod("makealpha", ":", ",")
|
||||
tmod.transform = simplemod("transform", "")
|
||||
tmod.sheet = simplemod("sheet", ":", "x", ":", ",")
|
||||
|
||||
function tmod:inventorycube(...)
|
||||
local s = addmod(self, "inventorycube")
|
||||
for _, arg in pairs({...}) do
|
||||
s = s .. "{" .. string_gsub(tostring(arg), "%^", "&")
|
||||
end
|
||||
return tmod:new(s)
|
||||
end
|
||||
|
||||
tmod.combine = simplemod("combine", ":", "x")
|
||||
function tmod:layer(x, y, img)
|
||||
return tmod:new((self.img or "") .. ":" .. esc(x) .. ","
|
||||
.. esc(y) .. "=" .. esc(img))
|
||||
end
|
@ -11,6 +11,7 @@ local basetimes = {
|
||||
choppy = 2,
|
||||
crumbly = 0.5,
|
||||
snappy = 0.4,
|
||||
scratchy = 2
|
||||
}
|
||||
nodecore.tool_basetimes = basetimes
|
||||
|
||||
@ -36,5 +37,5 @@ function nodecore.toolcaps(opts)
|
||||
}
|
||||
end
|
||||
end
|
||||
return {groupcaps = gcaps, opts = opts}
|
||||
return {groupcaps = gcaps, opts = opts, punch_attack_uses = 0}
|
||||
end
|
||||
|
@ -30,19 +30,21 @@ function nodecore.translate(str, ...)
|
||||
return minetest.translate(modname, str, ...)
|
||||
end
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
if not strings_dirty then return end
|
||||
strings_dirty = nil
|
||||
if nodecore.infodump() then
|
||||
nodecore.register_globalstep("translate templates", function()
|
||||
if not strings_dirty then return end
|
||||
strings_dirty = nil
|
||||
|
||||
local keys = {}
|
||||
for k in pairs(strings) do keys[#keys + 1] = k end
|
||||
table_sort(keys)
|
||||
local keys = {}
|
||||
for k in pairs(strings) do keys[#keys + 1] = k end
|
||||
table_sort(keys)
|
||||
|
||||
local data = "# textdomain: " .. modname .. "\n"
|
||||
for _, k in ipairs(keys) do
|
||||
data = data .. k .. "=" .. "\n"
|
||||
end
|
||||
local data = "# textdomain: " .. modname .. "\n"
|
||||
for _, k in ipairs(keys) do
|
||||
data = data .. k .. "=" .. "\n"
|
||||
end
|
||||
|
||||
local p = minetest.get_worldpath() .. "/" .. modname .. ".template.tr"
|
||||
return minetest.safe_file_write(p, data)
|
||||
end)
|
||||
local p = minetest.get_worldpath() .. "/" .. modname .. ".template.tr"
|
||||
return minetest.safe_file_write(p, data)
|
||||
end)
|
||||
end
|
||||
|
85
mods/nc_api_active/abmmux.lua
Normal file
85
mods/nc_api_active/abmmux.lua
Normal file
@ -0,0 +1,85 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local minetest, nodecore, pairs, rawset, table
|
||||
= minetest, nodecore, pairs, rawset, table
|
||||
local table_concat
|
||||
= table.concat
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local muxdefs = {}
|
||||
local abmsdefined = {}
|
||||
|
||||
local grp = "group:"
|
||||
local function matches(name, def, nodenames)
|
||||
for _, n in pairs(nodenames) do
|
||||
if name == n then return true
|
||||
elseif n:sub(1, #grp) == grp then
|
||||
local g = def.groups and def.groups[n:sub(#grp + 1)]
|
||||
if g and g > 0 then return true end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
nodecore.register_on_register_item(function(name, def)
|
||||
if def.type == "node" then
|
||||
for _, mux in pairs(muxdefs) do
|
||||
if (not (def.groups and def.groups[mux.muxkey]))
|
||||
and matches(name, def, mux.nodenames) then
|
||||
rawset(def.groups, "abmmux_" .. mux.muxkey, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local muxidx = nodecore.item_matching_index(muxdefs,
|
||||
function(i) return i.nodenames end,
|
||||
"register_abm",
|
||||
true,
|
||||
function(n, i) return i.muxkey .. n end
|
||||
)
|
||||
|
||||
local oldreg = minetest.register_abm
|
||||
function minetest.register_abm(def)
|
||||
local rawkey = table_concat({
|
||||
def.interval,
|
||||
def.chance,
|
||||
def.catchup and 1 or 0,
|
||||
table_concat(def.neighbors or {}, ";")
|
||||
}, "|")
|
||||
def.rawkey = rawkey
|
||||
local muxkey = minetest.sha1(rawkey):sub(1, 8)
|
||||
def.muxkey = muxkey
|
||||
muxdefs[#muxdefs + 1] = def
|
||||
for k, v in pairs(minetest.registered_nodes) do
|
||||
if (not v.groups[muxkey]) and matches(k, v, def.nodenames) then
|
||||
rawset(v.groups, "abmmux_" .. muxkey, 1)
|
||||
minetest.override_item(k, {groups = v.groups})
|
||||
end
|
||||
end
|
||||
if abmsdefined[muxkey] then return end
|
||||
abmsdefined[muxkey] = true
|
||||
local warnunused
|
||||
warnunused = function(nn)
|
||||
warnunused = function() end
|
||||
return nodecore.log("warning", "no abm found for mux " .. rawkey
|
||||
.. " node " .. nn)
|
||||
end
|
||||
return oldreg({
|
||||
label = "mux abm for " .. rawkey,
|
||||
interval = def.interval,
|
||||
chance = def.chance,
|
||||
catchup = def.catchup,
|
||||
neighbors = def.neighbors,
|
||||
nodenames = {"group:abmmux_" .. muxkey},
|
||||
action = function(pos, node, ...)
|
||||
local oldname = node.name
|
||||
local found = muxidx[muxkey .. oldname]
|
||||
if not found then return warnunused(oldname) end
|
||||
found[1].action(pos, node, ...)
|
||||
if #found <= 1 then return end
|
||||
for i = 2, #found do
|
||||
if minetest.get_node(pos).name ~= oldname then return end
|
||||
found[i].action(pos, node, ...)
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
106
mods/nc_api_active/aism.lua
Normal file
106
mods/nc_api_active/aism.lua
Normal file
@ -0,0 +1,106 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, math, minetest, nodecore, pairs
|
||||
= ItemStack, math, minetest, nodecore, pairs
|
||||
local math_random
|
||||
= math.random
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
-- Active ItemStack Modifiers
|
||||
|
||||
-- Definition:
|
||||
--- itemnames: {"mod:itemname", "group:name"}
|
||||
--- interval: integer,
|
||||
--- chance: integer,
|
||||
--- action: function(stack, data) end
|
||||
-- Data:
|
||||
--- {pos, node}
|
||||
--- {player, inv, list, slot}
|
||||
|
||||
nodecore.register_aism,
|
||||
nodecore.registered_aisms
|
||||
= nodecore.mkreg()
|
||||
|
||||
local aismidx = nodecore.item_matching_index(
|
||||
nodecore.registered_aisms,
|
||||
function(i) return i.itemnames end,
|
||||
"register_aism"
|
||||
)
|
||||
|
||||
local function checkrun(def, stack, data)
|
||||
if nodecore.stasis and not def.ignore_stasis then return end
|
||||
if def.chance and def.chance > 1 and math_random(1, def.chance) ~= 1 then return end
|
||||
if def.interval and def.interval > 1 and (minetest.get_gametime() % def.interval) ~= 0 then return end
|
||||
stack = def.action(stack, data)
|
||||
if stack and data.set then data.set(ItemStack(stack)) end
|
||||
end
|
||||
|
||||
local function checkstack(stack, data)
|
||||
local defs = aismidx[stack:get_name()]
|
||||
if not defs then return end
|
||||
for def in pairs(defs) do
|
||||
checkrun(def, stack, data)
|
||||
end
|
||||
end
|
||||
nodecore.aism_check_stack = checkstack
|
||||
|
||||
nodecore.register_limited_abm({
|
||||
label = "aism schedule",
|
||||
nodenames = {"group:visinv"},
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
ignore_stasis = true,
|
||||
action = function(pos, node)
|
||||
return checkstack(nodecore.stack_get(pos), {
|
||||
pos = pos,
|
||||
node = node,
|
||||
set = function(s)
|
||||
return nodecore.stack_set(pos, s)
|
||||
end
|
||||
})
|
||||
end
|
||||
})
|
||||
|
||||
nodecore.interval(1, function()
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
local pos = player:get_pos()
|
||||
pos.y = pos.y + player:get_properties().eye_height
|
||||
local inv = player:get_inventory()
|
||||
for lname, list in pairs(inv:get_lists()) do
|
||||
for slot, stack in pairs(list) do
|
||||
checkstack(stack, {
|
||||
pos = pos,
|
||||
player = player,
|
||||
inv = inv,
|
||||
list = lname,
|
||||
slot = slot,
|
||||
set = function(s)
|
||||
return inv:set_stack(lname, slot, s)
|
||||
end
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
nodecore.register_item_entity_step(function(self, dtime)
|
||||
local t = (self.aismtimer or 0) + dtime
|
||||
while t >= 1 do
|
||||
t = t - 1
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return end
|
||||
local setstack
|
||||
checkstack(ItemStack(self.itemstring), {
|
||||
pos = pos,
|
||||
obj = self.object,
|
||||
ent = self,
|
||||
set = function(s) setstack = s end
|
||||
})
|
||||
if setstack then
|
||||
if setstack:is_empty() then
|
||||
return self.object:remove()
|
||||
end
|
||||
self.itemstring = setstack:to_string()
|
||||
end
|
||||
end
|
||||
self.aismtimer = t
|
||||
end)
|
@ -5,7 +5,7 @@ local math_random
|
||||
= math.random
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
function nodecore.register_ambiance(def)
|
||||
local function ambiance_core(def, getpos)
|
||||
local max = def.queue_max or 100
|
||||
local rate = 1 / (def.queue_rate or 20)
|
||||
|
||||
@ -15,7 +15,7 @@ function nodecore.register_ambiance(def)
|
||||
|
||||
local batch
|
||||
local time = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
nodecore.register_globalstep("ambiance_core " .. (def.label or "unlabeled"), function(dtime)
|
||||
time = time + dtime
|
||||
while time > rate do
|
||||
if not batch then
|
||||
@ -32,13 +32,14 @@ function nodecore.register_ambiance(def)
|
||||
|
||||
opts.name = opts.name or def.sound_name
|
||||
opts.gain = opts.gain or def.sound_gain
|
||||
minetest.sound_play(opts.name, opts)
|
||||
nodecore.sound_play(opts.name, opts)
|
||||
|
||||
time = time - rate
|
||||
end
|
||||
end)
|
||||
|
||||
def.action = function(pos)
|
||||
def.action = function(...)
|
||||
local pos = getpos(...)
|
||||
local hash = minetest.hash_node_position(pos)
|
||||
if seen[hash] then return end
|
||||
seen[hash] = true
|
||||
@ -60,6 +61,16 @@ function nodecore.register_ambiance(def)
|
||||
end
|
||||
total = total + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function abm_pos(pos) return pos end
|
||||
function nodecore.register_ambiance(def)
|
||||
ambiance_core(def, abm_pos)
|
||||
return nodecore.register_limited_abm(def)
|
||||
end
|
||||
|
||||
local function aism_pos(_, data) return data.pos end
|
||||
function nodecore.register_item_ambiance(def)
|
||||
ambiance_core(def, aism_pos)
|
||||
return nodecore.register_aism(def)
|
||||
end
|
144
mods/nc_api_active/dnts.lua
Normal file
144
mods/nc_api_active/dnts.lua
Normal file
@ -0,0 +1,144 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local error, math, minetest, nodecore, pairs, string
|
||||
= error, math, minetest, nodecore, pairs, string
|
||||
local math_random, string_format
|
||||
= math.random, string.format
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
-- Active Block Modifiers, meet Delayed Node Triggers.
|
||||
|
||||
-- Definition:
|
||||
--- mname: "modname:technicalname"
|
||||
--- nodenames: {"mod:itemname", "group:name"}
|
||||
--- time: float (optional),
|
||||
--- loop: boolean,
|
||||
--- action: function(pos, node) end
|
||||
|
||||
nodecore.registered_dnts = {}
|
||||
|
||||
local grouppref = "group:"
|
||||
local function buildidx(list)
|
||||
if not list then return end
|
||||
local n = {}
|
||||
local g
|
||||
for _, v in pairs(list) do
|
||||
if v:sub(1, #grouppref) == grouppref then
|
||||
g = g or {}
|
||||
g[v:sub(#grouppref + 1)] = true
|
||||
else
|
||||
n[v] = true
|
||||
end
|
||||
end
|
||||
if g then
|
||||
minetest.after(0, function()
|
||||
for k in pairs(minetest.registered_nodes) do
|
||||
for x in pairs(g) do
|
||||
if minetest.get_item_group(k, x) > 0 then
|
||||
n[k] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
function nodecore.register_dnt(def)
|
||||
if not def.name then return error("dnt name required") end
|
||||
if not def.action then return error("dnt action required") end
|
||||
if nodecore.registered_dnts[def.name] then
|
||||
return error(string_format("dnt %q already registered", def.name))
|
||||
end
|
||||
def.nodeidx = buildidx(def.nodenames)
|
||||
nodecore.registered_dnts[def.name] = def
|
||||
end
|
||||
|
||||
local dntkey = "dnt"
|
||||
|
||||
local function dntsave(pos, meta, data)
|
||||
local now = nodecore.gametime
|
||||
local prev = data[false]
|
||||
local el = prev and (now - prev) or 0
|
||||
|
||||
local min
|
||||
local run = {}
|
||||
local reg = nodecore.registered_dnts
|
||||
for k, v in pairs(data) do
|
||||
if k then
|
||||
v = v - el
|
||||
if v < 0 then
|
||||
local def = reg[k]
|
||||
if def then
|
||||
if def.ignore_stasis or not nodecore.stasis then
|
||||
run[def] = true
|
||||
v = def.loop and def.time or nil
|
||||
else
|
||||
v = def.time and (def.time < 1) and def.time or 1
|
||||
end
|
||||
data[k] = v
|
||||
if (not min) or (min < v) then min = v end
|
||||
end
|
||||
else
|
||||
data[k] = v
|
||||
if (not min) or (min < v) then min = v end
|
||||
end
|
||||
end
|
||||
end
|
||||
data[false] = now
|
||||
|
||||
meta:set_string(dntkey, minetest.serialize(data))
|
||||
if min then minetest.get_node_timer(pos):start(min) end
|
||||
|
||||
local node = minetest.get_node(pos)
|
||||
local nn = node.name
|
||||
for k in pairs(run) do
|
||||
local idx = k.nodeidx
|
||||
if (not idx) or idx[nn] then k.action(pos, node) end
|
||||
end
|
||||
end
|
||||
|
||||
local function dntload(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local s = meta:get_string(dntkey)
|
||||
s = s and s ~= "" and minetest.deserialize(s) or {}
|
||||
return s, function() return dntsave(pos, meta, s) end
|
||||
end
|
||||
|
||||
local squelched = {}
|
||||
local function maybecheck(pos, save)
|
||||
local hash = minetest.hash_node_position(pos)
|
||||
local s = squelched[hash]
|
||||
if s and s > nodecore.gametime then return end
|
||||
squelched[hash] = nodecore.gametime + 5 + math_random() * 10
|
||||
return save()
|
||||
end
|
||||
|
||||
function nodecore.dnt_set(pos, name, time)
|
||||
local data, save = dntload(pos)
|
||||
local prev = data[name]
|
||||
time = time or nodecore.registered_dnts[name].time or 1
|
||||
if prev and prev < time then return maybecheck(pos, save) end
|
||||
data[name] = time
|
||||
return save()
|
||||
end
|
||||
|
||||
function nodecore.dnt_reset(pos, name, time)
|
||||
local data, save = dntload(pos)
|
||||
local prev = data[name]
|
||||
time = time or nodecore.registered_dnts[name].time or 1
|
||||
if prev and prev == time then return maybecheck(pos, save) end
|
||||
data[name] = time
|
||||
return save()
|
||||
end
|
||||
|
||||
minetest.nodedef_default.on_timer = function(pos)
|
||||
local _, save = dntload(pos)
|
||||
return save()
|
||||
end
|
||||
|
||||
nodecore.register_on_register_item(function(def)
|
||||
if def.on_timer then
|
||||
return error("on_timer hook is disallowed in "
|
||||
.. nodecore.product .. "; use DNT instead")
|
||||
end
|
||||
end)
|
186
mods/nc_api_active/dynalight.lua
Normal file
186
mods/nc_api_active/dynalight.lua
Normal file
@ -0,0 +1,186 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local ItemStack, minetest, nodecore, pairs, setmetatable, vector
|
||||
= ItemStack, minetest, nodecore, pairs, setmetatable, vector
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
local modname = minetest.get_current_modname()
|
||||
|
||||
-- Register nodes that can be replaced by dynamic lights
|
||||
|
||||
local canreplace = {air = 0}
|
||||
|
||||
local true_airlike = {
|
||||
drawtype = "airlike",
|
||||
pointable = false,
|
||||
walkable = false,
|
||||
climbable = false,
|
||||
buildable_to = true,
|
||||
floodable = true,
|
||||
air_equivalent = true,
|
||||
paramtype = "light",
|
||||
light_source = 0,
|
||||
sunlight_propagates = true,
|
||||
}
|
||||
|
||||
minetest.after(0, function()
|
||||
for k, v in pairs(minetest.registered_nodes) do
|
||||
local ok = not canreplace[k]
|
||||
for dk, dv in pairs(true_airlike) do
|
||||
ok = ok and v[dk] == dv
|
||||
end
|
||||
if ok then canreplace[k] = 0 end
|
||||
end
|
||||
end)
|
||||
|
||||
-- API for checking if dynamic lights are valid
|
||||
|
||||
local ttl = 0.25
|
||||
|
||||
local active_lights = {}
|
||||
|
||||
local function setup_light(pos, check)
|
||||
active_lights[minetest.hash_node_position(pos)] = {
|
||||
exp = nodecore.gametime + ttl,
|
||||
check = check
|
||||
}
|
||||
minetest.get_node_timer(pos):start(ttl)
|
||||
end
|
||||
|
||||
local function check_light(pos)
|
||||
local data = active_lights[minetest.hash_node_position(pos)]
|
||||
if not data then return minetest.remove_node(pos) end
|
||||
if nodecore.gametime < data.exp then return end
|
||||
if data.check and data.check() then
|
||||
data.exp = nodecore.gametime + ttl
|
||||
minetest.get_node_timer(pos):start(ttl)
|
||||
return
|
||||
end
|
||||
minetest.remove_node(pos)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Register dynamic light nodes
|
||||
|
||||
local nodes = {}
|
||||
|
||||
local function dynamic_light_node(level) return modname .. ":light" .. level end
|
||||
nodecore.dynamic_light_node = dynamic_light_node
|
||||
|
||||
for level = 1, nodecore.light_sun - 1 do
|
||||
if nodes[level] then return nodes[level] end
|
||||
local name = dynamic_light_node(level)
|
||||
local def = {
|
||||
light_source = level,
|
||||
on_timer = check_light,
|
||||
air_equivalent = true,
|
||||
groups = {dynamic_light = level}
|
||||
}
|
||||
for k, v in pairs(true_airlike) do def[k] = def[k] or v end
|
||||
minetest.register_node(":" .. name, def)
|
||||
nodes[level] = name
|
||||
canreplace[name] = level
|
||||
end
|
||||
|
||||
minetest.register_alias("nc_torch:wield_light", dynamic_light_node(8))
|
||||
|
||||
-- API for adding dynamic lights to world
|
||||
|
||||
nodecore.register_limited_abm({
|
||||
label = "dynamic light cleanup",
|
||||
interval = 1,
|
||||
chance = 1,
|
||||
nodenames = {"group:dynamic_light"},
|
||||
action = check_light
|
||||
})
|
||||
|
||||
local function dynamic_light_add(pos, level, check, exact)
|
||||
if not pos then return end
|
||||
local name = minetest.get_node(pos).name
|
||||
local curlight = canreplace[name]
|
||||
if not curlight then
|
||||
if exact then return end
|
||||
return dynamic_light_add({x = pos.x, y = pos.y - 1, z = pos.z}, level, check, true)
|
||||
or dynamic_light_add({x = pos.x, y = pos.y + 1, z = pos.z}, level, check, true)
|
||||
or dynamic_light_add({x = pos.x + 1, y = pos.y, z = pos.z}, level, check, true)
|
||||
or dynamic_light_add({x = pos.x - 1, y = pos.y, z = pos.z}, level, check, true)
|
||||
or dynamic_light_add({x = pos.x, y = pos.y, z = pos.z + 1}, level, check, true)
|
||||
or dynamic_light_add({x = pos.x, y = pos.y, z = pos.z - 1}, level, check, true)
|
||||
end
|
||||
if level < 1 then return end
|
||||
if level > nodecore.light_sun - 1 then level = nodecore.light_sun - 1 end
|
||||
local setname = dynamic_light_node(level)
|
||||
pos = vector.round(pos)
|
||||
if curlight <= level then
|
||||
local ll = nodecore.get_node_light(pos)
|
||||
if ll and ll > level then return end
|
||||
end
|
||||
if curlight > level and not check_light(pos) then return end
|
||||
if name ~= setname then minetest.set_node(pos, {name = setname}) end
|
||||
setup_light(pos, check)
|
||||
return true
|
||||
end
|
||||
nodecore.dynamic_light_add = dynamic_light_add
|
||||
|
||||
-- Automatic player wield lights
|
||||
|
||||
local function lightsrc(stack)
|
||||
local def = minetest.registered_items[stack:get_name()] or {}
|
||||
return def.light_source or 0
|
||||
end
|
||||
|
||||
local function player_wield_light(player)
|
||||
local glow = 0
|
||||
for _, stack in pairs(player:get_inventory():get_list("main")) do
|
||||
local src = lightsrc(stack)
|
||||
if src > glow then glow = src end
|
||||
end
|
||||
if glow < 1 then return end
|
||||
local pos = player:get_pos()
|
||||
pos.y = pos.y + player:get_properties().eye_height
|
||||
pos = vector.round(pos)
|
||||
local pname = player:get_player_name()
|
||||
return dynamic_light_add(pos, glow, function()
|
||||
local pl = minetest.get_player_by_name(pname)
|
||||
if not pl then return end
|
||||
local pp = pl:get_pos()
|
||||
pp.y = pp.y + pl:get_properties().eye_height
|
||||
return vector.equals(pos, vector.round(pp))
|
||||
end)
|
||||
end
|
||||
|
||||
nodecore.register_playerstep({
|
||||
label = "player wield light",
|
||||
action = function(player)
|
||||
if nodecore.player_visible(player) then
|
||||
return player_wield_light(player)
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
-- Automatic entity light sources
|
||||
|
||||
local function entlight(self, ...)
|
||||
local stack = ItemStack(self.node and self.node.name or self.itemstring or "")
|
||||
local src = lightsrc(stack)
|
||||
if src > 0 then
|
||||
local pos = self.object:get_pos()
|
||||
if not pos then return ... end
|
||||
pos = vector.round(pos)
|
||||
nodecore.dynamic_light_add(pos, src, function()
|
||||
for _, v in pairs(nodecore.get_objects_at_pos(pos)) do
|
||||
if v == self.object then return true end
|
||||
end
|
||||
end)
|
||||
end
|
||||
return ...
|
||||
end
|
||||
for _, name in pairs({"item", "falling_node"}) do
|
||||
local def = minetest.registered_entities["__builtin:" .. name]
|
||||
local ndef = {
|
||||
on_step = function(self, ...)
|
||||
return entlight(self, def.on_step(self, ...))
|
||||
end
|
||||
}
|
||||
setmetatable(ndef, def)
|
||||
minetest.register_entity(":__builtin:" .. name, ndef)
|
||||
end
|
17
mods/nc_api_active/init.lua
Normal file
17
mods/nc_api_active/init.lua
Normal file
@ -0,0 +1,17 @@
|
||||
-- LUALOCALS < ---------------------------------------------------------
|
||||
local include, minetest, nodecore
|
||||
= include, minetest, nodecore
|
||||
-- LUALOCALS > ---------------------------------------------------------
|
||||
|
||||
nodecore.amcoremod()
|
||||
|
||||
nodecore.register_limited_abm = function(...) return minetest.register_abm(...) end
|
||||
|
||||
include("abmmux")
|
||||
include("stasis")
|
||||
include("dnts")
|
||||
include("aism")
|
||||
include("soaking")
|
||||
include("ambiance")
|
||||
include("playerstep")
|
||||
include("dynalight")
|
1
mods/nc_api_active/mod.conf
Normal file
1
mods/nc_api_active/mod.conf
Normal file
@ -0,0 +1 @@
|
||||
depends = nc_api, nc_api_ents
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user