install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minetest_game" DESTINATION "${SHAREDIR}/games/"
COMPONENT "SUBGAME_MINETEST_GAME" OPTIONAL PATTERN ".git*" EXCLUDE )
-install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/minimal" DESTINATION "${SHAREDIR}/games/"
+install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games/devtest" DESTINATION "${SHAREDIR}/games/"
COMPONENT "SUBGAME_MINIMAL" OPTIONAL PATTERN ".git*" EXCLUDE )
if(BUILD_CLIENT)
)
cpack_add_component(SUBGAME_MINIMAL
- DISPLAY_NAME "Minimal development test"
- DESCRIPTION "A minimal subgame helping to develop the engine."
+ DISPLAY_NAME "Development Test"
+ DESCRIPTION "A minimal test game helping to develop the engine."
DISABLED #DISABLED does not mean it is disabled, and is just not selected by default.
GROUP "Subgames"
)
git clone --depth 1 https://github.com/minetest/minetest.git
cd minetest
-Download minetest_game (otherwise only the "Minimal development test" game is available) using Git:
+Download minetest_game (otherwise only the "Development Test" game is available) using Git:
git clone --depth 1 https://github.com/minetest/minetest_game.git games/minetest_game
label_spflags = "label[0,"..y_start..";" .. fgettext("Mapgen-specific flags") .. "]"
end
- -- Warning if only minimal is installed
- local minimal_only = ""
+ -- Warning if only devtest is installed
+ local devtest_only = ""
local gamelist_height = 2.3
- if #pkgmgr.games == 1 and pkgmgr.games[1].id == "minimal" then
- minimal_only = "box[0,0;5.8,1.7;#ff8800]" ..
+ if #pkgmgr.games == 1 and pkgmgr.games[1].id == "devtest" then
+ devtest_only = "box[0,0;5.8,1.7;#ff8800]" ..
"textarea[0.3,0;6,1.8;;;"..
- fgettext("Warning: The minimal development test is meant for developers.") .. "\n" ..
+ fgettext("Warning: The Development Test is meant for developers.") .. "\n" ..
fgettext("Download a game, such as Minetest Game, from minetest.net") .. "]"
gamelist_height = 0.5
end
"textlist[0,3.85;5.8,"..gamelist_height..";games;" ..
pkgmgr.gamelist() .. ";" .. gameidx .. ";false]" ..
"container[0,4.5]" ..
- minimal_only ..
+ devtest_only ..
"container_end[]" ..
"container_end[]" ..
There are a bunch of different looking node types.
-Look for examples in `games/minimal` or `games/minetest_game`.
+Look for examples in `games/devtest` or `games/minetest_game`.
* `normal`
* A node-sized cube.
--- /dev/null
+License information for Development Test
+----------------------------------------
+
+The same license as for Minetest applies.
--- /dev/null
+# Development Test (devtest)
+
+This is a basic testing environment that contains a bunch of things to test the engine, but it could also be used as a minimal testbed for testing out mods.
+
+## Features
+
+* Basic nodes for mapgen
+* Basic, minimal map generator
+* Lots of example nodes for testing drawtypes, param2, light level, and many other node properties
+* Example entities
+* Other example items
+* Formspec test (via `/test_formspec` command)
+* Automated unit tests (disabled by default)
+* Tools for manipulating nodes and entities, like the "Param2 Tool"
+
+## Getting started
+
+Basically, just create a world and start. A few important things to note:
+
+* Items are gotten from the “Chest of Everything” (`chest_of_everything:chest`)
+* When you lost your initial items, type in `/stuff` command to get them back
+* By default, Creative Mode activates infinite node placement. This behavior can be changed with the `devtest_infplace` setting
+* Use the `/infplace` command to toggle infinite node placement in-game
+* Use the Param2 Tool to change the param2 of nodes; it's useful to experiment with the various drawtype test nodes
+* Check out the game settings and server commands for additional tests and features
+* Creative Mode does nothing (apart from default engine behavior)
+
+Confused by a certain node or item? Check out for inline code comments.
+
+### Example tests
+
+* You can use this to test what happens if a player is simultaneously in 2 nodes with `damage_per_second` but with a different value.
+* Or use the Falling Node Tool on various test nodes to see how they behave when falling.
+* You could also use this as a testbed for dependency-free mods, e.g. to test out how your formspecs behave without theming.
+
+## Random notes
+
+* Experimental/strange/unstructured tests can be found in the `experimental` mod
+* Textures of drawtype test nodes have a red dot at the top left corner. This is to see whether the textures are oriented properly
+
+## Design philosophy
+
+This should loosely follow the following principles:
+
+* Engine testing: The main focus of this is to aid testing of *engine* features, such as mapgen or node drawtypes
+* Mod testing: The secondary focus is to help modders as well, either as a minimal testbed for mods or even as a code example
+* Minimal interference: Under default settings, it shall not interfere with APIs except on explicit user wish. Non-trivial tests and features need to be enabled by a setting first
+* Convenience: Have various tools to make usage easier and more convenient
+* Reproducing engine bugs: When an engine bug was found, consider creating a test case
+* Clarity: Textures and names need to be designed to keep different things clearly visually apart at a glance
+* Low loading time: It must load blazing-fast so stuff can be tested quickly
+
--- /dev/null
+name = Development Test
+description = Testing environment to help with testing the engine features of Minetest. It can also be helpful in mod development.
--- /dev/null
+local WATER_ALPHA = 160
+local WATER_VISC = 1
+local LAVA_VISC = 7
+
+--
+-- Node definitions
+--
+
+-- Register nodes
+
+minetest.register_node("basenodes:stone", {
+ description = "Stone",
+ tiles = {"default_stone.png"},
+ groups = {cracky=3},
+})
+
+minetest.register_node("basenodes:desert_stone", {
+ description = "Desert Stone",
+ tiles = {"default_desert_stone.png"},
+ groups = {cracky=3},
+})
+
+minetest.register_node("basenodes:dirt_with_grass", {
+ description = "Dirt with Grass",
+ tiles ={"default_grass.png",
+ -- a little dot on the bottom to distinguish it from dirt
+ "default_dirt.png^basenodes_dirt_with_grass_bottom.png",
+ {name = "default_dirt.png^default_grass_side.png",
+ tileable_vertical = false}},
+ groups = {crumbly=3, soil=1},
+})
+
+minetest.register_node("basenodes:dirt_with_snow", {
+ description = "Dirt with Snow",
+ tiles ={"basenodes_dirt_with_snow.png",
+ -- a little dot on the bottom to distinguish it from dirt
+ "default_dirt.png^basenodes_dirt_with_snow_bottom.png",
+ {name = "default_dirt.png^default_snow_side.png",
+ tileable_vertical = false}},
+ groups = {crumbly=3, soil=1},
+})
+
+minetest.register_node("basenodes:dirt", {
+ description = "Dirt",
+ tiles ={"default_dirt.png"},
+ groups = {crumbly=3, soil=1},
+})
+
+minetest.register_node("basenodes:sand", {
+ description = "Sand",
+ tiles ={"default_sand.png"},
+ groups = {crumbly=3},
+})
+
+minetest.register_node("basenodes:desert_sand", {
+ description = "Desert Sand",
+ tiles ={"default_desert_sand.png"},
+ groups = {crumbly=3},
+})
+
+minetest.register_node("basenodes:gravel", {
+ description = "Gravel",
+ tiles ={"default_gravel.png"},
+ groups = {crumbly=2},
+})
+
+minetest.register_node("basenodes:junglegrass", {
+ description = "Jungle Grass",
+ drawtype = "plantlike",
+ tiles ={"default_junglegrass.png"},
+ inventory_image = "default_junglegrass.png",
+ wield_image = "default_junglegrass.png",
+ paramtype = "light",
+ walkable = false,
+ groups = {snappy=3},
+})
+
+minetest.register_node("basenodes:tree", {
+ description = "Normal Tree Trunk",
+ tiles = {"default_tree_top.png", "default_tree_top.png", "default_tree.png"},
+ is_ground_content = false,
+ groups = {choppy=2,oddly_breakable_by_hand=1},
+})
+
+minetest.register_node("basenodes:leaves", {
+ description = "Normal Leaves",
+ drawtype = "allfaces_optional",
+ tiles = {"default_leaves.png"},
+ paramtype = "light",
+ is_ground_content = false,
+ groups = {snappy=3},
+})
+
+minetest.register_node("basenodes:jungletree", {
+ description = "Jungle Tree Trunk",
+ tiles = {"default_jungletree_top.png", "default_jungletree_top.png", "default_jungletree.png"},
+ is_ground_content = false,
+ groups = {choppy=2,oddly_breakable_by_hand=1},
+})
+
+minetest.register_node("basenodes:jungleleaves", {
+ description = "Jungle Leaves",
+ drawtype = "allfaces_optional",
+ tiles = {"default_jungleleaves.png"},
+ paramtype = "light",
+ is_ground_content = false,
+ groups = {snappy=3},
+})
+
+minetest.register_node("basenodes:pine_tree", {
+ description = "Pine Tree Trunk",
+ tiles = {"default_pine_tree_top.png", "default_pine_tree_top.png", "default_pine_tree.png"},
+ is_ground_content = false,
+ groups = {choppy=2,oddly_breakable_by_hand=1},
+})
+
+minetest.register_node("basenodes:pine_needles", {
+ description = "Pine Needles",
+ drawtype = "allfaces_optional",
+ tiles = {"default_pine_needles.png"},
+ paramtype = "light",
+ is_ground_content = false,
+ groups = {snappy=3},
+})
+
+minetest.register_node("basenodes:water_source", {
+ description = "Water Source",
+ drawtype = "liquid",
+ tiles = {"default_water.png"},
+ special_tiles = {
+ {name = "default_water.png", backface_culling = false},
+ {name = "default_water.png", backface_culling = true},
+ },
+ alpha = WATER_ALPHA,
+ paramtype = "light",
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ drowning = 1,
+ liquidtype = "source",
+ liquid_alternative_flowing = "basenodes:water_flowing",
+ liquid_alternative_source = "basenodes:water_source",
+ liquid_viscosity = WATER_VISC,
+ post_effect_color = {a = 64, r = 100, g = 100, b = 200},
+ groups = {water = 3, liquid = 3},
+})
+
+minetest.register_node("basenodes:water_flowing", {
+ description = "Flowing Water",
+ drawtype = "flowingliquid",
+ tiles = {"default_water_flowing.png"},
+ special_tiles = {
+ {name = "default_water_flowing.png", backface_culling = false},
+ {name = "default_water_flowing.png", backface_culling = false},
+ },
+ alpha = WATER_ALPHA,
+ paramtype = "light",
+ paramtype2 = "flowingliquid",
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ drowning = 1,
+ liquidtype = "flowing",
+ liquid_alternative_flowing = "basenodes:water_flowing",
+ liquid_alternative_source = "basenodes:water_source",
+ liquid_viscosity = WATER_VISC,
+ post_effect_color = {a = 64, r = 100, g = 100, b = 200},
+ groups = {water = 3, liquid = 3},
+})
+
+minetest.register_node("basenodes:river_water_source", {
+ description = "River Water Source",
+ drawtype = "liquid",
+ tiles = { "default_river_water.png" },
+ special_tiles = {
+ {name = "default_river_water.png", backface_culling = false},
+ {name = "default_river_water.png", backface_culling = true},
+ },
+ alpha = WATER_ALPHA,
+ paramtype = "light",
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ drowning = 1,
+ liquidtype = "source",
+ liquid_alternative_flowing = "basenodes:river_water_flowing",
+ liquid_alternative_source = "basenodes:river_water_source",
+ liquid_viscosity = 1,
+ liquid_renewable = false,
+ liquid_range = 2,
+ post_effect_color = {a = 103, r = 30, g = 76, b = 90},
+ groups = {water = 3, liquid = 3, },
+})
+
+minetest.register_node("basenodes:river_water_flowing", {
+ description = "Flowing River Water",
+ drawtype = "flowingliquid",
+ tiles = {"default_river_water_flowing.png"},
+ special_tiles = {
+ {name = "default_river_water_flowing.png", backface_culling = false},
+ {name = "default_river_water_flowing.png", backface_culling = false},
+ },
+ alpha = WATER_ALPHA,
+ paramtype = "light",
+ paramtype2 = "flowingliquid",
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ drowning = 1,
+ liquidtype = "flowing",
+ liquid_alternative_flowing = "basenodes:river_water_flowing",
+ liquid_alternative_source = "basenodes:river_water_source",
+ liquid_viscosity = 1,
+ liquid_renewable = false,
+ liquid_range = 2,
+ post_effect_color = {a = 103, r = 30, g = 76, b = 90},
+ groups = {water = 3, liquid = 3, },
+})
+
+minetest.register_node("basenodes:lava_flowing", {
+ description = "Flowing Lava",
+ drawtype = "flowingliquid",
+ tiles = {"default_lava_flowing.png"},
+ special_tiles = {
+ {name="default_lava_flowing.png", backface_culling = false},
+ {name="default_lava_flowing.png", backface_culling = false},
+ },
+ paramtype = "light",
+ light_source = minetest.LIGHT_MAX,
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ drowning = 1,
+ damage_per_second = 4,
+ liquidtype = "flowing",
+ liquid_alternative_flowing = "basenodes:lava_flowing",
+ liquid_alternative_source = "basenodes:lava_source",
+ liquid_viscosity = LAVA_VISC,
+ post_effect_color = {a=192, r=255, g=64, b=0},
+ groups = {lava=3, liquid=1},
+})
+
+minetest.register_node("basenodes:lava_source", {
+ description = "Lava Source",
+ drawtype = "liquid",
+ tiles = { "default_lava.png" },
+ special_tiles = {
+ {name = "default_lava.png", backface_culling = false},
+ {name = "default_lava.png", backface_culling = true},
+ },
+ paramtype = "light",
+ light_source = minetest.LIGHT_MAX,
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ drowning = 1,
+ damage_per_second = 4,
+ liquidtype = "source",
+ liquid_alternative_flowing = "basenodes:lava_flowing",
+ liquid_alternative_source = "basenodes:lava_source",
+ liquid_viscosity = LAVA_VISC,
+ post_effect_color = {a=192, r=255, g=64, b=0},
+ groups = {lava=3, liquid=1},
+})
+
+minetest.register_node("basenodes:cobble", {
+ description = "Cobblestone",
+ tiles ={"default_cobble.png"},
+ is_ground_content = false,
+ groups = {cracky=3},
+})
+
+minetest.register_node("basenodes:mossycobble", {
+ description = "Mossy Cobblestone",
+ tiles ={"default_mossycobble.png"},
+ is_ground_content = false,
+ groups = {cracky=3},
+})
+
+minetest.register_node("basenodes:apple", {
+ description = "Apple",
+ drawtype = "plantlike",
+ tiles ={"default_apple.png"},
+ inventory_image = "default_apple.png",
+ paramtype = "light",
+ is_ground_content = false,
+ sunlight_propagates = true,
+ walkable = false,
+ groups = {dig_immediate=3},
+
+ -- Make eatable because why not?
+ on_use = minetest.item_eat(2),
+})
+
+minetest.register_node("basenodes:ice", {
+ description = "Ice",
+ tiles ={"default_ice.png"},
+ groups = {cracky=3},
+})
+
+-- The snow nodes intentionally have different tints to make them more
+-- distinguishable
+minetest.register_node("basenodes:snow", {
+ description = "Snow Sheet",
+ tiles = {"basenodes_snow_sheet.png"},
+ groups = {crumbly=3},
+ walkable = false,
+ paramtype = "light",
+ drawtype = "nodebox",
+ node_box = {
+ type = "fixed",
+ fixed = {-0.5, -0.5, -0.5, 0.5, -0.25, 0.5},
+ },
+})
+
+minetest.register_node("basenodes:snowblock", {
+ description = "Snow Block",
+ tiles ={"default_snow.png"},
+ groups = {crumbly=3},
+})
+
+
--- /dev/null
+name = basenodes
+description = Contains basic nodes for mapgen
--- /dev/null
+--
+-- Tool definitions
+--
+
+--[[ TOOLS SUMMARY:
+
+Tool types:
+
+* Hand: basic tool/weapon (just for convenience, not optimized for testing)
+* Pickaxe: dig cracky
+* Axe: dig choppy
+* Shovel: dig crumbly
+* Shears: dig snappy
+* Sword: deal damage
+* Dagger: deal damage, but faster
+
+Tool materials:
+
+* Dirt: dig nodes of rating 3, one use only
+* Wood: dig nodes of rating 3
+* Stone: dig nodes of rating 3 or 2
+* Steel: dig nodes of rating 3, 2 or 1
+* Mese: dig "everything" instantly
+]]
+
+-- The hand
+minetest.register_item(":", {
+ type = "none",
+ wield_image = "wieldhand.png",
+ wield_scale = {x=1,y=1,z=2.5},
+ tool_capabilities = {
+ full_punch_interval = 1.0,
+ max_drop_level = 0,
+ groupcaps = {
+ crumbly = {times={[3]=1.50}, uses=0, maxlevel=0},
+ snappy = {times={[3]=1.50}, uses=0, maxlevel=0},
+ oddly_breakable_by_hand = {times={[1]=7.00,[2]=4.00,[3]=2.00}, uses=0, maxlevel=0},
+ },
+ damage_groups = {fleshy=1},
+ }
+})
+
+-- Mese Pickaxe: special tool that digs "everything" instantly
+minetest.register_tool("basetools:pick_mese", {
+ description = "Mese Pickaxe",
+ inventory_image = "basetools_mesepick.png",
+ tool_capabilities = {
+ full_punch_interval = 1.0,
+ max_drop_level=3,
+ groupcaps={
+ cracky={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
+ crumbly={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
+ snappy={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
+ choppy={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
+ dig_immediate={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
+ },
+ },
+})
+
+
+--
+-- Pickaxes: Dig cracky
+--
+
+-- This should break after only 1 use
+minetest.register_tool("basetools:pick_dirt", {
+ description = "Dirt Pickaxe",
+ inventory_image = "basetools_dirtpick.png",
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ cracky={times={[3]=2.00}, uses=1, maxlevel=0}
+ },
+ },
+})
+
+minetest.register_tool("basetools:pick_wood", {
+ description = "Wooden Pickaxe",
+ inventory_image = "basetools_woodpick.png",
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ cracky={times={[3]=2.00}, uses=30, maxlevel=0}
+ },
+ },
+})
+minetest.register_tool("basetools:pick_stone", {
+ description = "Stone Pickaxe",
+ inventory_image = "basetools_stonepick.png",
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ cracky={times={[2]=1.20, [3]=0.80}, uses=60, maxlevel=0}
+ },
+ },
+})
+minetest.register_tool("basetools:pick_steel", {
+ description = "Steel Pickaxe",
+ inventory_image = "basetools_steelpick.png",
+ tool_capabilities = {
+ max_drop_level=1,
+ groupcaps={
+ cracky={times={[1]=4.00, [2]=1.60, [3]=1.00}, uses=90, maxlevel=0}
+ },
+ },
+})
+minetest.register_tool("basetools:pick_steel_l1", {
+ description = "Steel Pickaxe Level 1",
+ inventory_image = "basetools_steelpick_l1.png",
+ tool_capabilities = {
+ max_drop_level=1,
+ groupcaps={
+ cracky={times={[1]=4.00, [2]=1.60, [3]=1.00}, uses=90, maxlevel=1}
+ },
+ },
+})
+minetest.register_tool("basetools:pick_steel_l2", {
+ description = "Steel Pickaxe Level 2",
+ inventory_image = "basetools_steelpick_l2.png",
+ tool_capabilities = {
+ max_drop_level=1,
+ groupcaps={
+ cracky={times={[1]=4.00, [2]=1.60, [3]=1.00}, uses=90, maxlevel=2}
+ },
+ },
+})
+
+--
+-- Shovels (dig crumbly)
+--
+
+minetest.register_tool("basetools:shovel_wood", {
+ description = "Wooden Shovel",
+ inventory_image = "basetools_woodshovel.png",
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ crumbly={times={[3]=0.50}, uses=30, maxlevel=0}
+ },
+ },
+})
+minetest.register_tool("basetools:shovel_stone", {
+ description = "Stone Shovel",
+ inventory_image = "basetools_stoneshovel.png",
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ crumbly={times={[2]=0.50, [3]=0.30}, uses=60, maxlevel=0}
+ },
+ },
+})
+minetest.register_tool("basetools:shovel_steel", {
+ description = "Steel Shovel",
+ inventory_image = "basetools_steelshovel.png",
+ tool_capabilities = {
+ max_drop_level=1,
+ groupcaps={
+ crumbly={times={[1]=1.00, [2]=0.70, [3]=0.60}, uses=90, maxlevel=0}
+ },
+ },
+})
+
+--
+-- Axes (dig choppy)
+--
+
+minetest.register_tool("basetools:axe_wood", {
+ description = "Wooden Axe",
+ inventory_image = "basetools_woodaxe.png",
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ choppy={times={[3]=0.80}, uses=30, maxlevel=0},
+ },
+ },
+})
+minetest.register_tool("basetools:axe_stone", {
+ description = "Stone Axe",
+ inventory_image = "basetools_stoneaxe.png",
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ choppy={times={[2]=1.00, [3]=0.60}, uses=60, maxlevel=0},
+ },
+ },
+})
+minetest.register_tool("basetools:axe_steel", {
+ description = "Steel Axe",
+ inventory_image = "basetools_steelaxe.png",
+ tool_capabilities = {
+ max_drop_level=1,
+ groupcaps={
+ choppy={times={[1]=2.00, [2]=0.80, [3]=0.40}, uses=90, maxlevel=0},
+ },
+ },
+})
+
+--
+-- Shears (dig snappy)
+--
+
+minetest.register_tool("basetools:shears_wood", {
+ description = "Wooden Shears",
+ inventory_image = "basetools_woodshears.png",
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ snappy={times={[3]=1.00}, uses=30, maxlevel=0},
+ },
+ },
+})
+minetest.register_tool("basetools:shears_stone", {
+ description = "Stone Shears",
+ inventory_image = "basetools_stoneshears.png",
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ snappy={times={[2]=1.00, [3]=0.50}, uses=60, maxlevel=0},
+ },
+ },
+})
+minetest.register_tool("basetools:shears_steel", {
+ description = "Steel Shears",
+ inventory_image = "basetools_steelshears.png",
+ tool_capabilities = {
+ max_drop_level=1,
+ groupcaps={
+ snappy={times={[1]=1.00, [2]=0.50, [3]=0.25}, uses=90, maxlevel=0},
+ },
+ },
+})
+
+--
+-- Swords (deal damage)
+--
+
+minetest.register_tool("basetools:sword_wood", {
+ description = "Wooden Sword",
+ inventory_image = "basetools_woodsword.png",
+ tool_capabilities = {
+ full_punch_interval = 1.0,
+ damage_groups = {fleshy=2},
+ }
+})
+minetest.register_tool("basetools:sword_stone", {
+ description = "Stone Sword",
+ inventory_image = "basetools_stonesword.png",
+ tool_capabilities = {
+ full_punch_interval = 1.0,
+ max_drop_level=0,
+ damage_groups = {fleshy=4},
+ }
+})
+minetest.register_tool("basetools:sword_steel", {
+ description = "Steel Sword",
+ inventory_image = "basetools_steelsword.png",
+ tool_capabilities = {
+ full_punch_interval = 1.0,
+ max_drop_level=1,
+ damage_groups = {fleshy=6},
+ }
+})
+
+-- Fire/Ice sword: Deal damage to non-fleshy damage groups
+minetest.register_tool("basetools:sword_fire", {
+ description = "Fire Sword",
+ inventory_image = "basetools_firesword.png",
+ tool_capabilities = {
+ full_punch_interval = 1.0,
+ max_drop_level=0,
+ damage_groups = {icy=6},
+ }
+})
+minetest.register_tool("basetools:sword_ice", {
+ description = "Ice Sword",
+ inventory_image = "basetools_icesword.png",
+ tool_capabilities = {
+ full_punch_interval = 1.0,
+ max_drop_level=0,
+ damage_groups = {firy=6},
+ }
+})
+
+--
+-- Dagger: Low damage, fast punch interval
+--
+minetest.register_tool("basetools:dagger_steel", {
+ description = "Steel Dagger",
+ inventory_image = "basetools_steeldagger.png",
+ tool_capabilities = {
+ full_punch_interval = 0.5,
+ max_drop_level=0,
+ damage_groups = {fleshy=2},
+ }
+})
--- /dev/null
+name = basetools
+description = Contains basic digging tools
--- /dev/null
+-- Bucket: Punch liquid source or flowing liquid to collect it
+
+minetest.register_tool("bucket:bucket", {
+ description = "Bucket",
+ inventory_image = "bucket.png",
+ stack_max = 1,
+ liquids_pointable = true,
+ groups = { disable_repair = 1 },
+ on_use = function(itemstack, user, pointed_thing)
+ -- Must be pointing to node
+ if pointed_thing.type ~= "node" then
+ return
+ end
+ -- Check if pointing to a liquid
+ local n = minetest.get_node(pointed_thing.under)
+ local def = minetest.registered_nodes[n.name]
+ if def ~= nil and (def.liquidtype == "source" or def.liquidtype == "flowing") then
+ minetest.add_node(pointed_thing.under, {name="air"})
+ local inv = user:get_inventory()
+ if inv then
+ inv:add_item("main", ItemStack(n.name))
+ end
+ end
+ end,
+})
+
--- /dev/null
+name = bucket
+description = Minimal bucket to pick up liquids
--- /dev/null
+minetest.register_node("chest:chest", {
+ description = "Chest",
+ tiles ={"chest_chest.png^[sheet:2x2:0,0", "chest_chest.png^[sheet:2x2:0,0",
+ "chest_chest.png^[sheet:2x2:1,0", "chest_chest.png^[sheet:2x2:1,0",
+ "chest_chest.png^[sheet:2x2:1,0", "chest_chest.png^[sheet:2x2:0,1"},
+ paramtype2 = "facedir",
+ groups = {dig_immediate=2,choppy=3},
+ is_ground_content = false,
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ meta:set_string("formspec",
+ "size[8,9]"..
+ "list[current_name;main;0,0;8,4;]"..
+ "list[current_player;main;0,5;8,4;]" ..
+ "listring[]")
+ meta:set_string("infotext", "Chest")
+ local inv = meta:get_inventory()
+ inv:set_size("main", 8*4)
+ end,
+ can_dig = function(pos,player)
+ local meta = minetest.get_meta(pos);
+ local inv = meta:get_inventory()
+ return inv:is_empty("main")
+ end,
+})
+
+
--- /dev/null
+name = chest
+description = A simple chest to store items
--- /dev/null
+local F = minetest.formspec_escape
+
+-- Create a detached inventory
+local inv_everything = minetest.create_detached_inventory("everything", {
+ allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
+ return 0
+ end,
+ allow_put = function(inv, listname, index, stack, player)
+ return 0
+ end,
+ allow_take = function(inv, listname, index, stack, player)
+ return -1
+ end,
+})
+local inv_trash = minetest.create_detached_inventory("trash", {
+ allow_take = function(inv, listname, index, stack, player)
+ return 0
+ end,
+ allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
+ return 0
+ end,
+ on_put = function(inv, listname, index, stack, player)
+ inv:set_list("main", {})
+ end,
+})
+inv_trash:set_size("main", 1)
+
+local max_page = 1
+
+local function get_chest_formspec(page)
+ local start = 0 + (page-1)*32
+ return "size[8,9]"..
+ "list[detached:everything;main;0,0;8,4;"..start.."]"..
+ "list[current_player;main;0,5;8,4;]" ..
+ "label[6,4;Trash:]" ..
+ "list[detached:trash;main;7,4;1,1]" ..
+ "button[0,4;1,1;chest_of_everything_prev;"..F("<").."]"..
+ "button[1,4;1,1;chest_of_everything_next;"..F(">").."]"..
+ "label[2,4;"..F("Page: "..page).."]"..
+ "listring[detached:everything;main]"..
+ "listring[current_player;main]"..
+ "listring[detached:trash;main]"
+end
+
+minetest.register_node("chest_of_everything:chest", {
+ description = "Chest of Everything",
+ tiles ={"chest_of_everything_chest.png^[sheet:2x2:0,0", "chest_of_everything_chest.png^[sheet:2x2:0,0",
+ "chest_of_everything_chest.png^[sheet:2x2:1,0", "chest_of_everything_chest.png^[sheet:2x2:1,0",
+ "chest_of_everything_chest.png^[sheet:2x2:1,0", "chest_of_everything_chest.png^[sheet:2x2:0,1"},
+ paramtype2 = "facedir",
+ groups = {dig_immediate=2,choppy=3},
+ is_ground_content = false,
+ on_construct = function(pos)
+ local meta = minetest.get_meta(pos)
+ meta:set_string("infotext", "Chest of Everything")
+ meta:set_int("page", 1)
+ meta:set_string("formspec", get_chest_formspec(1))
+ end,
+ on_receive_fields = function(pos, formname, fields, sender)
+ if formname == "" then
+ local meta = minetest.get_meta(pos)
+ local page = meta:get_int("page")
+ if fields.chest_of_everything_prev then
+ page = page - 1
+ elseif fields.chest_of_everything_next then
+ page = page + 1
+ end
+ if page < 1 then
+ page = 1
+ end
+ if page > max_page then
+ page = max_page
+ end
+ meta:set_int("page", page)
+ meta:set_string("formspec", get_chest_formspec(page))
+ end
+ end,
+})
+
+minetest.register_on_mods_loaded(function()
+ local items = {}
+ for itemstring,_ in pairs(minetest.registered_items) do
+ if itemstring ~= "" and itemstring ~= "unknown" and itemstring ~= "ignore" then
+ table.insert(items, itemstring)
+ end
+ end
+ --[[ Sort items in this order:
+ * Chest of Everything
+ * Test tools
+ * Other tools
+ * Craftitems
+ * Other items
+ * Dummy items ]]
+ local function compare(item1, item2)
+ local def1 = minetest.registered_items[item1]
+ local def2 = minetest.registered_items[item2]
+ local tool1 = def1.type == "tool"
+ local tool2 = def2.type == "tool"
+ local testtool1 = minetest.get_item_group(item1, "testtool") == 1
+ local testtool2 = minetest.get_item_group(item2, "testtool") == 1
+ local dummy1 = minetest.get_item_group(item1, "dummy") == 1
+ local dummy2 = minetest.get_item_group(item2, "dummy") == 1
+ local craftitem1 = def1.type == "craft"
+ local craftitem2 = def2.type == "craft"
+ if item1 == "chest_of_everything:chest" then
+ return true
+ elseif item2 == "chest_of_everything:chest" then
+ return false
+ elseif dummy1 and not dummy2 then
+ return false
+ elseif not dummy1 and dummy2 then
+ return true
+ elseif testtool1 and not testtool2 then
+ return true
+ elseif not testtool1 and testtool2 then
+ return false
+ elseif tool1 and not tool2 then
+ return true
+ elseif not tool1 and tool2 then
+ return false
+ elseif craftitem1 and not craftitem2 then
+ return true
+ elseif not craftitem1 and craftitem2 then
+ return false
+ else
+ return item1 < item2
+ end
+ end
+ table.sort(items, compare)
+ inv_everything:set_size("main", #items)
+ max_page = math.ceil(#items / 32)
+ for i=1, #items do
+ inv_everything:add_item("main", items[i])
+ end
+end)
--- /dev/null
+name = chest_of_everything
+description = Adds the chest of everything from which you can take all items
--- /dev/null
+local groups = {
+ "cracky", "dig_immediate"
+}
+
+-- Register dig nodes with 1 digging group, a rating between 1-3 and a level between 0-2
+for g=1, #groups do
+ local gr = groups[g]
+ for r=1, 3 do
+ for l=0, 2 do
+ if not (gr=="dig_immediate" and (l>0 or r==1)) then
+ local d
+ if l > 0 then
+ d = string.format("Dig Test Node: %s=%d, level=%d", gr, r, l)
+ else
+ d = string.format("Dig Test Node: %s=%d", gr, r)
+ end
+ local tile = "dignodes_"..gr..".png^dignodes_rating"..r..".png"
+ if l==1 then
+ tile = tile .. "^[colorize:#FFFF00:127"
+ elseif l==2 then
+ tile = tile .. "^[colorize:#FF0000:127"
+ end
+ minetest.register_node("dignodes:"..gr.."_"..r.."_"..l, {
+ description = d,
+ tiles = { tile },
+ groups = { [gr] = r, level = l },
+ })
+ end
+ end
+ end
+end
+
+-- Node without any digging groups
+minetest.register_node("dignodes:none", {
+ description = "Dig Test Node: groupless",
+ tiles = {"dignodes_none.png"},
+})
--- /dev/null
+name = dignodes
+description = Nodes with different digging groups
--- /dev/null
+minetest.register_chatcommand("test_inv", {
+ params = "",
+ description = "Test: Modify player's inventory formspec",
+ func = function(name, param)
+ local player = minetest.get_player_by_name(name)
+ if not player then
+ return false, "No player."
+ end
+ player:set_inventory_formspec(
+ "size[13,7.5]"..
+ "image[6,0.6;1,2;player.png]"..
+ "list[current_player;main;5,3.5;8,4;]"..
+ "list[current_player;craft;8,0;3,3;]"..
+ "list[current_player;craftpreview;12,1;1,1;]"..
+ "list[detached:test_inventory;main;0,0;4,6;0]"..
+ "button[0.5,7;2,1;button1;Button 1]"..
+ "button_exit[2.5,7;2,1;button2;Exit Button]")
+ return true, "Done."
+ end,
+})
+
+minetest.register_chatcommand("test_bulk_set_node", {
+ params = "",
+ description = "Test: Bulk-set 9×9×9 stone nodes",
+ func = function(name, param)
+ local player = minetest.get_player_by_name(name)
+ if not player then
+ return false, "No player."
+ end
+ local pos_list = {}
+ local ppos = player:get_pos()
+ local i = 1
+ for x=2,10 do
+ for y=2,10 do
+ for z=2,10 do
+ pos_list[i] = {x=ppos.x + x,y = ppos.y + y,z = ppos.z + z}
+ i = i + 1
+ end
+ end
+ end
+ minetest.bulk_set_node(pos_list, {name = "mapgen_stone"})
+ return true, "Done."
+ end,
+})
+
+minetest.register_chatcommand("bench_bulk_set_node", {
+ params = "",
+ description = "Benchmark: Bulk-set 99×99×99 stone nodes",
+ func = function(name, param)
+ local player = minetest.get_player_by_name(name)
+ if not player then
+ return false, "No player."
+ end
+ local pos_list = {}
+ local ppos = player:get_pos()
+ local i = 1
+ for x=2,100 do
+ for y=2,100 do
+ for z=2,100 do
+ pos_list[i] = {x=ppos.x + x,y = ppos.y + y,z = ppos.z + z}
+ i = i + 1
+ end
+ end
+ end
+
+ minetest.chat_send_player(name, "Benchmarking minetest.bulk_set_node. Warming up ...");
+
+ -- warm up with stone to prevent having different callbacks
+ -- due to different node topology
+ minetest.bulk_set_node(pos_list, {name = "mapgen_stone"})
+
+ minetest.chat_send_player(name, "Warming up finished, now benchmarking ...");
+
+ local start_time = minetest.get_us_time()
+ for i=1,#pos_list do
+ minetest.set_node(pos_list[i], {name = "mapgen_stone"})
+ end
+ local middle_time = minetest.get_us_time()
+ minetest.bulk_set_node(pos_list, {name = "mapgen_stone"})
+ local end_time = minetest.get_us_time()
+ local msg = string.format("Benchmark results: minetest.set_node loop: %.2f ms; minetest.bulk_set_node: %.2f ms",
+ ((middle_time - start_time)) / 1000,
+ ((end_time - middle_time)) / 1000
+ )
+ return true, msg
+ end,
+})
+
+local function advance_pos(pos, start_pos, advance_z)
+ if advance_z then
+ pos.z = pos.z + 2
+ pos.x = start_pos.x
+ else
+ pos.x = pos.x + 2
+ end
+ if pos.x > 30900 or pos.x - start_pos.x > 46 then
+ pos.x = start_pos.x
+ pos.z = pos.z + 2
+ end
+ if pos.z > 30900 then
+ -- We ran out of space! Aborting
+ aborted = true
+ return false
+ end
+ return pos
+end
+
+local function place_nodes(param)
+ local nodes = param.nodes
+ local name = param.name
+ local pos = param.pos
+ local start_pos = param.start_pos
+ table.sort(nodes)
+ minetest.chat_send_player(name, "Placing nodes …")
+ local nodes_placed = 0
+ for n=1, #nodes do
+ local itemstring = nodes[n]
+ local def = minetest.registered_nodes[itemstring]
+ local p2_max = 0
+ if param.param ~= "no_param2" then
+ -- Also test the param2 values of the nodes
+ -- ... but we only use permissible param2 values
+ if def.paramtype2 == "wallmounted" then
+ p2_max = 5
+ elseif def.paramtype2 == "facedir" then
+ p2_max = 23
+ elseif def.paramtype2 == "glasslikeliquidlevel" then
+ p2_max = 63
+ elseif def.paramtype2 == "meshoptions" and def.drawtype == "plantlike" then
+ p2_max = 63
+ elseif def.paramtype2 == "leveled" then
+ p2_max = 127
+ elseif def.paramtype2 == "degrotate" and def.drawtype == "plantlike" then
+ p2_max = 179
+ elseif def.paramtype2 == "colorfacedir" or
+ def.paramtype2 == "colorwallmounted" or
+ def.paramtype2 == "color" then
+ p2_max = 255
+ end
+ end
+ for p2 = 0, p2_max do
+ -- Skip undefined param2 values
+ if not ((def.paramtype2 == "meshoptions" and p2 % 8 > 4) or
+ (def.paramtype2 == "colorwallmounted" and p2 % 8 > 5) or
+ (def.paramtype2 == "colorfacedir" and p2 % 32 > 23)) then
+
+ minetest.set_node(pos, { name = itemstring, param2 = p2 })
+ nodes_placed = nodes_placed + 1
+ pos = advance_pos(pos, start_pos)
+ if not pos then
+ aborted = true
+ break
+ end
+ end
+ end
+ if aborted then
+ break
+ end
+ end
+ if aborted then
+ minetest.chat_send_player(name, "Not all nodes could be placed, please move further away from the world boundary. Nodes placed: "..nodes_placed)
+ end
+ minetest.chat_send_player(name, "Nodes placed: "..nodes_placed..".")
+end
+
+local function after_emerge(blockpos, action, calls_remaining, param)
+ if calls_remaining == 0 then
+ place_nodes(param)
+ end
+end
+
+minetest.register_chatcommand("test_place_nodes", {
+ params = "[ no_param2 ]",
+ description = "Test: Place all non-experimental nodes and optionally their permissible param2 variants",
+ func = function(name, param)
+ local player = minetest.get_player_by_name(name)
+ if not player then
+ return false, "No player."
+ end
+ local pos = vector.floor(player:get_pos())
+ pos.x = math.ceil(pos.x + 3)
+ pos.z = math.ceil(pos.z + 3)
+ pos.y = math.ceil(pos.y + 1)
+ local start_pos = table.copy(pos)
+ if pos.x > 30800 then
+ return false, "Too close to world boundary (+X). Please move to X < 30800."
+ end
+ if pos.z > 30800 then
+ return false, "Too close to world boundary (+Z). Please move to Z < 30800."
+ end
+
+ local aborted = false
+ local nodes = {}
+ local emerge_estimate = 0
+ for itemstring, def in pairs(minetest.registered_nodes) do
+ if itemstring ~= "ignore" and string.sub(itemstring, 1, 13) ~= "experimental:" then
+ table.insert(nodes, itemstring)
+ if def.paramtype2 == 0 then
+ emerge_estimate = emerge_estimate + 1
+ else
+ emerge_estimate = emerge_estimate + 255
+ end
+ end
+ end
+ -- Emerge area to make sure that all nodes are being placed.
+ -- Note we will emerge much more than we need to (overestimation),
+ -- the estimation code could be improved performance-wise …
+ local length = 16 + math.ceil(emerge_estimate / 24) * 2
+ minetest.emerge_area(start_pos,
+ { x = start_pos.x + 46, y = start_pos.y, z = start_pos.z + length },
+ after_emerge, { nodes = nodes, name = name, pos = pos, start_pos = start_pos, param = param })
+ return true, "Emerging area …"
+ end,
+})
+
--- /dev/null
+-- Create a detached inventory
+local inv = minetest.create_detached_inventory("test_inventory", {
+ allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
+ experimental.print_to_everything("allow move asked")
+ return count -- Allow all
+ end,
+ allow_put = function(inv, listname, index, stack, player)
+ experimental.print_to_everything("allow put asked")
+ return 1 -- Allow only 1
+ end,
+ allow_take = function(inv, listname, index, stack, player)
+ experimental.print_to_everything("allow take asked")
+ return 4 -- Allow 4 at max
+ end,
+ on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
+ experimental.print_to_everything(player:get_player_name().." moved items")
+ end,
+ on_put = function(inv, listname, index, stack, player)
+ experimental.print_to_everything(player:get_player_name().." put items")
+ end,
+ on_take = function(inv, listname, index, stack, player)
+ experimental.print_to_everything(player:get_player_name().." took items")
+ end,
+})
+inv:set_size("main", 4*6)
+inv:add_item("main", "experimental:callback_node")
+inv:add_item("main", "experimental:particle_spawner")
+
+
--- /dev/null
+--
+-- Experimental things
+--
+
+experimental = {}
+
+dofile(minetest.get_modpath("experimental").."/detached.lua")
+dofile(minetest.get_modpath("experimental").."/items.lua")
+dofile(minetest.get_modpath("experimental").."/commands.lua")
+
+function experimental.print_to_everything(msg)
+ minetest.log("action", msg)
+ minetest.chat_send_all(msg)
+end
+
+minetest.log("info", "[experimental] modname="..dump(minetest.get_current_modname()))
+minetest.log("info", "[experimental] modpath="..dump(minetest.get_modpath("experimental")))
+minetest.log("info", "[experimental] worldpath="..dump(minetest.get_worldpath()))
+
+
+minetest.register_on_mods_loaded(function()
+ minetest.log("action", "[experimental] on_mods_loaded()")
+end)
--- /dev/null
+minetest.register_node("experimental:callback_node", {
+ description = "Callback Test Node (construct/destruct/timer)",
+ tiles = {"experimental_callback_node.png"},
+ groups = {dig_immediate=3},
+ -- This was known to cause a bug in minetest.item_place_node() when used
+ -- via minetest.place_node(), causing a placer with no position
+ paramtype2 = "facedir",
+ drop = "",
+
+ on_construct = function(pos)
+ experimental.print_to_everything("experimental:callback_node:on_construct("..minetest.pos_to_string(pos)..")")
+ local meta = minetest.get_meta(pos)
+ meta:set_string("mine", "test")
+ local timer = minetest.get_node_timer(pos)
+ timer:start(4, 3)
+ end,
+
+ after_place_node = function(pos, placer)
+ experimental.print_to_everything("experimental:callback_node:after_place_node("..minetest.pos_to_string(pos)..")")
+ local meta = minetest.get_meta(pos)
+ if meta:get_string("mine") == "test" then
+ experimental.print_to_everything("correct metadata found")
+ else
+ experimental.print_to_everything("incorrect metadata found")
+ end
+ end,
+
+ on_destruct = function(pos)
+ experimental.print_to_everything("experimental:callback_node:on_destruct("..minetest.pos_to_string(pos)..")")
+ end,
+
+ after_destruct = function(pos)
+ experimental.print_to_everything("experimental:callback_node:after_destruct("..minetest.pos_to_string(pos)..")")
+ end,
+
+ after_dig_node = function(pos, oldnode, oldmetadata, digger)
+ experimental.print_to_everything("experimental:callback_node:after_dig_node("..minetest.pos_to_string(pos)..")")
+ end,
+
+ on_timer = function(pos, elapsed)
+ experimental.print_to_everything("on_timer(): elapsed="..dump(elapsed))
+ return true
+ end,
+})
+
+minetest.register_tool("experimental:privatizer", {
+ description = "Node Meta Privatizer",
+ inventory_image = "experimental_tester_tool_1.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type == "node" then
+ local node = minetest.get_node(pointed_thing.under)
+ if node.name == "chest:chest" then
+ local p = pointed_thing.under
+ minetest.log("action", "Privatizer used at "..minetest.pos_to_string(p))
+ minetest.get_meta(p):mark_as_private({"infotext", "formspec"})
+ if user and user:is_player() then
+ minetest.chat_send_player(user:get_player_name(), "Chest metadata (infotext, formspec) set private!")
+ end
+ return
+ end
+ end
+ if user and user:is_player() then
+ minetest.chat_send_player(user:get_player_name(), "Privatizer can only be used on chest!")
+ end
+ end,
+})
+
+minetest.register_tool("experimental:particle_spawner", {
+ description = "Particle Spawner",
+ inventory_image = "experimental_tester_tool_1.png^[invert:g",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_use = function(itemstack, user, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing, true)
+ if pos == nil then
+ if user then
+ pos = user:get_pos()
+ end
+ end
+ pos = vector.add(pos, {x=0, y=0.5, z=0})
+ local tex, anim
+ if math.random(0, 1) == 0 then
+ tex = "experimental_particle_sheet.png"
+ anim = {type="sheet_2d", frames_w=3, frames_h=2, frame_length=0.5}
+ else
+ tex = "experimental_particle_vertical.png"
+ anim = {type="vertical_frames", aspect_w=16, aspect_h=16, length=3.3}
+ end
+
+ minetest.add_particle({
+ pos = pos,
+ velocity = {x=0, y=0, z=0},
+ acceleration = {x=0, y=0.04, z=0},
+ expirationtime = 6,
+ collisiondetection = true,
+ texture = tex,
+ animation = anim,
+ size = 4,
+ glow = math.random(0, 5),
+ })
+ end,
+})
+
--- /dev/null
+name = experimental
+description = Chaotic mod containing unstructured tests for testing out engine features. The features in this mod should be moved to other mods.
--- /dev/null
+local give_if_not_gotten_already = function(inv, list, item)
+ if not inv:contains_item(list, item) then
+ inv:add_item(list, item)
+ end
+end
+
+local give_initial_stuff = function(player)
+ local inv = player:get_inventory()
+ give_if_not_gotten_already(inv, "main", "basetools:pick_mese")
+ give_if_not_gotten_already(inv, "main", "basetools:axe_steel")
+ give_if_not_gotten_already(inv, "main", "basetools:shovel_steel")
+ give_if_not_gotten_already(inv, "main", "bucket:bucket")
+ give_if_not_gotten_already(inv, "main", "testnodes:light14")
+ give_if_not_gotten_already(inv, "main", "chest_of_everything:chest")
+ minetest.log("action", "[give_initial_stuff] Giving initial stuff to "..player:get_player_name())
+end
+
+minetest.register_on_newplayer(function(player)
+ if minetest.settings:get_bool("give_initial_stuff", true) then
+ give_initial_stuff(player)
+ end
+end)
+
+minetest.register_chatcommand("stuff", {
+ params = "",
+ privs = { give = true },
+ description = "Give yourself initial items",
+ func = function(name, param)
+ local player = minetest.get_player_by_name(name)
+ if not player or not player:is_player() then
+ return false, "No player."
+ end
+ give_initial_stuff(player)
+ return true
+ end,
+})
+
--- /dev/null
+name = give_initial_stuff
+description = Gives items to players on join
+depends = basetools, bucket, chest_of_everything, testnodes
--- /dev/null
+minetest.register_on_joinplayer(function(player)
+ local cb = function(player)
+ if not player or not player:is_player() then
+ return
+ end
+ minetest.chat_send_player(player:get_player_name(), "This is the \"Development Test\" [devtest], meant only for testing and development. Use Minetest Game for the real thing.")
+ end
+ minetest.after(2.0, cb, player)
+end)
--- /dev/null
+name = initial_message
+description = Show message to joining players explaining what this testing game is about
--- /dev/null
+--
+-- Aliases for map generator outputs
+--
+
+-- ESSENTIAL node aliases
+-- Basic nodes
+minetest.register_alias("mapgen_stone", "basenodes:stone")
+minetest.register_alias("mapgen_water_source", "basenodes:water_source")
+minetest.register_alias("mapgen_river_water_source", "basenodes:river_water_source")
+
+-- Additional essential aliases for v6
+minetest.register_alias("mapgen_lava_source", "basenodes:lava_source")
+minetest.register_alias("mapgen_dirt", "basenodes:dirt")
+minetest.register_alias("mapgen_dirt_with_grass", "basenodes:dirt_with_grass")
+minetest.register_alias("mapgen_sand", "basenodes:sand")
+minetest.register_alias("mapgen_tree", "basenodes:tree")
+minetest.register_alias("mapgen_leaves", "basenodes:leaves")
+minetest.register_alias("mapgen_apple", "basenodes:apple")
+
+-- Essential alias for dungeons
+minetest.register_alias("mapgen_cobble", "basenodes:cobble")
+
+-- Optional aliases for v6 (they all have fallback values in the engine)
+if minetest.settings:get_bool("devtest_v6_mapgen_aliases", false) then
+ minetest.register_alias("mapgen_gravel", "basenodes:gravel")
+ minetest.register_alias("mapgen_desert_stone", "basenodes:desert_stone")
+ minetest.register_alias("mapgen_desert_sand", "basenodes:desert_sand")
+ minetest.register_alias("mapgen_dirt_with_snow", "basenodes:dirt_with_snow")
+ minetest.register_alias("mapgen_snowblock", "basenodes:snowblock")
+ minetest.register_alias("mapgen_snow", "basenodes:snow")
+ minetest.register_alias("mapgen_ice", "basenodes:ice")
+ minetest.register_alias("mapgen_junglegrass", "basenodes:junglegrass")
+ minetest.register_alias("mapgen_jungletree", "basenodes:jungletree")
+ minetest.register_alias("mapgen_jungleleaves", "basenodes:jungleleaves")
+ minetest.register_alias("mapgen_pine_tree", "basenodes:pine_tree")
+ minetest.register_alias("mapgen_pine_needles", "basenodes:pine_needles")
+end
+-- Optional alias for mossycobble (should fall back to cobble)
+if minetest.settings:get_bool("devtest_dungeon_mossycobble", false) then
+ minetest.register_alias("mapgen_mossycobble", "basenodes:mossycobble")
+end
+-- Optional aliases for dungeon stairs (should fall back to full nodes)
+if minetest.settings:get_bool("devtest_dungeon_stairs", false) then
+ minetest.register_alias("mapgen_stair_cobble", "stairs:stair_cobble")
+ if minetest.settings:get_bool("devtest_v6_mapgen_aliases", false) then
+ minetest.register_alias("mapgen_stair_desert_stone", "stairs:stair_desert_stone")
+ end
+end
+
+--
+-- Register biomes for biome API
+--
+
+minetest.clear_registered_biomes()
+minetest.clear_registered_decorations()
+
+if minetest.settings:get_bool("devtest_register_biomes", true) then
+ minetest.register_biome({
+ name = "mapgen:grassland",
+ node_top = "basenodes:dirt_with_grass",
+ depth_top = 1,
+ node_filler = "basenodes:dirt",
+ depth_filler = 1,
+ y_min = 5,
+ y_max = 31000,
+ heat_point = 50,
+ humidity_point = 50,
+ })
+
+ minetest.register_biome({
+ name = "mapgen:grassland_ocean",
+ node_top = "basenodes:sand",
+ depth_top = 1,
+ node_filler = "basenodes:sand",
+ depth_filler = 2,
+ y_min = -31000,
+ y_max = 4,
+ heat_point = 50,
+ humidity_point = 50,
+ })
+end
--- /dev/null
+name = mapgen
+description = Minimal map generator
+depends = basenodes
--- /dev/null
+--
+-- Mod channels experimental handlers
+--
+local mod_channel = minetest.mod_channel_join("experimental_preview")
+
+minetest.register_on_modchannel_message(function(channel, sender, message)
+ minetest.log("action", "[modchannels] Server received message `" .. message
+ .. "` on channel `" .. channel .. "` from sender `" .. sender .. "`")
+
+ if mod_channel:is_writeable() then
+ mod_channel:send_all("experimental answers to preview")
+ mod_channel:leave()
+ end
+end)
--- /dev/null
+name = modchannels
+description = Add experimental mod channel handlers
--- /dev/null
+local simple_nodes = {
+ footstep = { "Footstep Sound Node", "soundstuff_node_footstep.png" },
+ dig = { "Dig Sound Node", "soundstuff_node_dig.png" },
+ dug = { "Dug Sound Node", "soundstuff_node_dug.png" },
+ place = { "Place Sound Node", "soundstuff_node_place.png" },
+ place_failed = { "Place Failed Sound Node", "soundstuff_node_place_failed.png" },
+}
+
+for k,v in pairs(simple_nodes) do
+ minetest.register_node("soundstuff:"..k, {
+ description = v[1],
+ tiles = {"soundstuff_node_sound.png","soundstuff_node_sound.png",v[2]},
+ groups = {dig_immediate=2},
+ sounds = {
+ [k] = { name = "soundstuff_mono", gain = 1.0 },
+ }
+ })
+end
+
+minetest.register_node("soundstuff:place_failed_attached", {
+ description = "Attached Place Failed Sound Node",
+ tiles = {"soundstuff_node_sound.png", "soundstuff_node_sound.png", "soundstuff_node_place_failed.png"},
+ groups = {dig_immediate=2, attached_node=1},
+ drawtype = "nodebox",
+ paramtype = "light",
+ node_box = { type = "fixed", fixed = {
+ { -7/16, -7/16, -7/16, 7/16, 7/16, 7/16 },
+ { -0.5, -0.5, -0.5, 0.5, -7/16, 0.5 },
+ }},
+ sounds = {
+ place_failed = { name = "soundstuff_mono", gain = 1.0 },
+ },
+})
+
+minetest.register_node("soundstuff:fall", {
+ description = "Fall Sound Node",
+ tiles = {"soundstuff_node_sound.png", "soundstuff_node_sound.png", "soundstuff_node_fall.png"},
+ groups = {dig_immediate=2, falling_node=1},
+ sounds = {
+ fall = { name = "soundstuff_mono", gain = 1.0 },
+ }
+})
+
+minetest.register_node("soundstuff:fall_attached", {
+ description = "Attached Fall Sound Node",
+ tiles = {"soundstuff_node_sound.png", "soundstuff_node_sound.png", "soundstuff_node_fall.png"},
+ groups = {dig_immediate=2, attached_node=1},
+ drawtype = "nodebox",
+ paramtype = "light",
+ node_box = { type = "fixed", fixed = {
+ { -7/16, -7/16, -7/16, 7/16, 7/16, 7/16 },
+ { -0.5, -0.5, -0.5, 0.5, -7/16, 0.5 },
+ }},
+ sounds = {
+ fall = { name = "soundstuff_mono", gain = 1.0 },
+ }
+})
+
+minetest.register_node("soundstuff:footstep_liquid", {
+ description = "Liquid Footstep Sound Node",
+ drawtype = "liquid",
+ tiles = {
+ "soundstuff_node_sound.png^[colorize:#0000FF:127",
+ },
+ special_tiles = {
+ {name = "soundstuff_node_sound.png^[colorize:#0000FF:127", backface_culling = false},
+ {name = "soundstuff_node_sound.png^[colorize:#0000FF:127", backface_culling = true},
+ },
+ liquids_pointable = true,
+ liquidtype = "source",
+ liquid_alternative_flowing = "soundstuff:footstep_liquid",
+ liquid_alternative_source = "soundstuff:footstep_liquid",
+ liquid_renewable = false,
+ liquid_range = 0,
+ liquid_viscosity = 0,
+ alpha = 190,
+ paramtype = "light",
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ post_effect_color = {a = 64, r = 0, g = 0, b = 200},
+ sounds = {
+ footstep = { name = "soundstuff_mono", gain = 1.0 },
+ }
+})
+
+minetest.register_node("soundstuff:footstep_climbable", {
+ description = "Climbable Footstep Sound Node",
+ drawtype = "allfaces",
+ tiles = {
+ "soundstuff_node_climbable.png",
+ },
+ alpha = 120,
+ paramtype = "light",
+ sunlight_propagates = true,
+ walkable = false,
+ climbable = true,
+ is_ground_content = false,
+ groups = { dig_immediate = 2 },
+ sounds = {
+ footstep = { name = "soundstuff_mono", gain = 1.0 },
+ }
+})
+
+
+
+minetest.register_craftitem("soundstuff:eat", {
+ description = "Eat Sound Item",
+ inventory_image = "soundstuff_eat.png",
+ on_use = minetest.item_eat(0),
+ sound = {
+ eat = { name = "soundstuff_mono", gain = 1.0 },
+ }
+})
+
+minetest.register_tool("soundstuff:breaks", {
+ description = "Break Sound Tool",
+ inventory_image = "soundstuff_node_dug.png",
+ sound = {
+ breaks = { name = "soundstuff_mono", gain = 1.0 },
+ },
+ tool_capabilities = {
+ max_drop_level=0,
+ groupcaps={
+ cracky={times={[2]=2.00, [3]=1.20}, uses=1, maxlevel=0},
+ choppy={times={[2]=2.00, [3]=1.20}, uses=1, maxlevel=0},
+ snappy={times={[2]=2.00, [3]=1.20}, uses=1, maxlevel=0},
+ crumbly={times={[2]=2.00, [3]=1.20}, uses=1, maxlevel=0},
+ },
+ },
+})
+
+-- Plays sound repeatedly
+minetest.register_node("soundstuff:positional", {
+ description = "Positional Sound Node",
+ on_construct = function(pos)
+ local timer = minetest.get_node_timer(pos)
+ timer:start(0)
+ end,
+ on_timer = function(pos, elapsed)
+ local node = minetest.get_node(pos)
+ local dist = node.param2
+ if dist == 0 then
+ dist = nil
+ end
+ minetest.sound_play("soundstuff_mono", { pos = pos, max_hear_distance = dist })
+ local timer = minetest.get_node_timer(pos)
+ timer:start(0.7)
+ end,
+ on_rightclick = function(pos, node, clicker)
+ node.param2 = (node.param2 + 1) % 64
+ minetest.set_node(pos, node)
+ if clicker and clicker:is_player() then
+ local dist = node.param2
+ local diststr
+ if dist == 0 then
+ diststr = "<default>"
+ else
+ diststr = tostring(dist)
+ end
+ minetest.chat_send_player(clicker:get_player_name(), "max_hear_distance = " .. diststr)
+ end
+ end,
+
+ groups = { dig_immediate = 2 },
+ tiles = { "soundstuff_node_sound.png" },
+})
+
--- /dev/null
+name = soundstuff
+description = Example items and nodes for testing sound effects
--- /dev/null
+stairs = {}
+
+-- Node will be called stairs:stair_<subname>
+function stairs.register_stair(subname, recipeitem, groups, images, description)
+ minetest.register_node(":stairs:stair_" .. subname, {
+ description = description,
+ drawtype = "nodebox",
+ tiles = images,
+ paramtype = "light",
+ paramtype2 = "facedir",
+ is_ground_content = true,
+ groups = groups,
+ node_box = {
+ type = "fixed",
+ fixed = {
+ {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
+ {-0.5, 0, 0, 0.5, 0.5, 0.5},
+ },
+ },
+ })
+end
+
+-- Node will be called stairs:slab_<subname>
+function stairs.register_slab(subname, recipeitem, groups, images, description)
+ minetest.register_node(":stairs:slab_" .. subname, {
+ description = description,
+ drawtype = "nodebox",
+ tiles = images,
+ paramtype = "light",
+ is_ground_content = true,
+ groups = groups,
+ node_box = {
+ type = "fixed",
+ fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
+ },
+ selection_box = {
+ type = "fixed",
+ fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
+ },
+ })
+end
+
+-- Nodes will be called stairs:{stair,slab}_<subname>
+function stairs.register_stair_and_slab(subname, recipeitem, groups, images, desc_stair, desc_slab)
+ stairs.register_stair(subname, recipeitem, groups, images, desc_stair)
+ stairs.register_slab(subname, recipeitem, groups, images, desc_slab)
+end
+
+stairs.register_stair_and_slab("stone", "basenodes:stone",
+ {cracky=3},
+ {"default_stone.png"},
+ "Stone Stair",
+ "Stone Slab")
+
+stairs.register_stair_and_slab("desert_stone", "basenodes:desert_stone",
+ {cracky=3},
+ {"default_desert_stone.png"},
+ "Desert Stone Stair",
+ "Desert Stone Slab")
+
+stairs.register_stair_and_slab("cobble", "basenodes:cobble",
+ {cracky=3},
+ {"default_cobble.png"},
+ "Cobblestone Stair",
+ "Cobblestone Slab")
--- /dev/null
+name = stairs
+description = Adds stairs and slabs
+depends = basenodes
--- /dev/null
+-- Armorball: Test entity for testing armor groups
+-- Rightclick to change armor group
+
+local phasearmor = {
+ [0]={icy=100},
+ [1]={firy=100},
+ [2]={fleshy=100},
+ [3]={immortal=1},
+ [4]={punch_operable=1},
+}
+
+minetest.register_entity("testentities:armorball", {
+ initial_properties = {
+ hp_max = 20,
+ physical = false,
+ collisionbox = {-0.4,-0.4,-0.4, 0.4,0.4,0.4},
+ visual = "sprite",
+ visual_size = {x=1, y=1},
+ textures = {"testentities_armorball.png"},
+ spritediv = {x=1, y=5},
+ initial_sprite_basepos = {x=0, y=0},
+ },
+
+ _phase = 2,
+
+ on_activate = function(self, staticdata)
+ minetest.log("action", "[testentities] armorball.on_activate")
+ self.object:set_armor_groups(phasearmor[self._phase])
+ self.object:set_sprite({x=0, y=self._phase})
+ end,
+
+ on_rightclick = function(self, clicker)
+ -- Change armor group and sprite
+ self._phase = self._phase + 1
+ if self._phase >= 5 then
+ self._phase = 0
+ end
+ self.object:set_sprite({x=0, y=self._phase})
+ self.object:set_armor_groups(phasearmor[self._phase])
+ end,
+})
--- /dev/null
+-- Entities that test their callbacks
+
+local message = function(msg)
+ minetest.log("action", msg)
+ minetest.chat_send_all(msg)
+end
+
+local get_object_name = function(obj)
+ local name = "<nil>"
+ if obj then
+ if obj:is_player() then
+ name = obj:get_player_name()
+ else
+ name = "<entity>"
+ end
+ end
+ return name
+end
+
+local spos = function(self)
+ return minetest.pos_to_string(vector.round(self.object:get_pos()))
+end
+
+-- Callback test entity (all callbacks except on_step)
+minetest.register_entity("testentities:callback", {
+ initial_properties = {
+ visual = "upright_sprite",
+ textures = { "testentities_callback.png" },
+ },
+
+ on_activate = function(self, staticdata, dtime_s)
+ message("Callback entity: on_activate! pos="..spos(self).."; dtime_s="..dtime_s)
+ end,
+ on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
+ local name = get_object_name(puncher)
+ message(
+ "Callback entity: on_punch! "..
+ "pos="..spos(self).."; puncher="..name.."; "..
+ "time_from_last_punch="..time_from_last_punch.."; "..
+ "tool_capabilities="..tostring(dump(tool_capabilities)).."; "..
+ "dir="..tostring(dump(dir)).."; damage="..damage)
+ end,
+ on_rightclick = function(self, clicker)
+ local name = get_object_name(clicker)
+ message("Callback entity: on_rightclick! pos="..spos(self).."; clicker="..name)
+ end,
+ on_death = function(self, killer)
+ local name = get_object_name(killer)
+ message("Callback entity: on_death! pos="..spos(self).."; killer="..name)
+ end,
+ on_attach_child = function(self, child)
+ local name = get_object_name(child)
+ message("Callback entity: on_attach_child! pos="..spos(self).."; child="..name)
+ end,
+ on_detach_child = function(self, child)
+ local name = get_object_name(child)
+ message("Callback entity: on_detach_child! pos="..spos(self).."; child="..name)
+ end,
+ on_detach = function(self, parent)
+ local name = get_object_name(parent)
+ message("Callback entity: on_detach! pos="..spos(self).."; parent="..name)
+ end,
+ get_staticdata = function(self)
+ message("Callback entity: get_staticdata! pos="..spos(self))
+ end,
+})
+
+-- Only test on_step callback
+minetest.register_entity("testentities:callback_step", {
+ visual = "upright_sprite",
+ textures = { "testentities_callback_step.png" },
+ on_step = function(self, dtime)
+ message("on_step callback entity: on_step! pos="..spos(self).."; dtime="..dtime)
+ end,
+})
--- /dev/null
+dofile(minetest.get_modpath("testentities").."/visuals.lua")
+dofile(minetest.get_modpath("testentities").."/armor.lua")
+dofile(minetest.get_modpath("testentities").."/callbacks.lua")
--- /dev/null
+name = testentities
+description = Example entities for testing
--- /dev/null
+-- Minimal test entities to test visuals
+
+minetest.register_entity("testentities:sprite", {
+ initial_properties = {
+ visual = "sprite",
+ textures = { "testentities_sprite.png" },
+ },
+})
+
+minetest.register_entity("testentities:upright_sprite", {
+ initial_properties = {
+ visual = "upright_sprite",
+ textures = {
+ "testentities_upright_sprite1.png",
+ "testentities_upright_sprite2.png",
+ },
+ },
+})
+
+minetest.register_entity("testentities:cube", {
+ initial_properties = {
+ visual = "cube",
+ textures = {
+ "testentities_cube1.png",
+ "testentities_cube2.png",
+ "testentities_cube3.png",
+ "testentities_cube4.png",
+ "testentities_cube5.png",
+ "testentities_cube6.png",
+ },
+ },
+})
+
+minetest.register_entity("testentities:item", {
+ initial_properties = {
+ visual = "item",
+ wield_item = "testnodes:normal",
+ },
+})
+
+minetest.register_entity("testentities:wielditem", {
+ initial_properties = {
+ visual = "wielditem",
+ wield_item = "testnodes:normal",
+ },
+})
+
+minetest.register_entity("testentities:mesh", {
+ initial_properties = {
+ visual = "mesh",
+ mesh = "testnodes_pyramid.obj",
+ textures = {
+ "testnodes_mesh_stripes2.png"
+ },
+ },
+})
+
+-- Advanced visual tests
+
+-- A test entity for testing animated and yaw-modulated sprites
+minetest.register_entity("testentities:yawsprite", {
+ initial_properties = {
+ selectionbox = {-0.3, -0.5, -0.3, 0.3, 0.3, 0.3},
+ visual = "sprite",
+ visual_size = {x=0.6666, y=1},
+ textures = {"testentities_dungeon_master.png^[makealpha:128,0,0^[makealpha:128,128,0"},
+ spritediv = {x=6, y=5},
+ initial_sprite_basepos = {x=0, y=0},
+ on_activate = function(self, staticdata)
+ self.object:set_sprite({x=0, y=0}, 1, 0, true)
+ end,
+ },
+})
+
--- /dev/null
+local S = minetest.get_translator("testfood")
+
+minetest.register_craftitem("testfood:good1", {
+ description = S("Good Food (+1)"),
+ inventory_image = "testfood_good.png",
+ on_use = minetest.item_eat(1),
+})
+minetest.register_craftitem("testfood:good5", {
+ description = S("Good Food (+5)"),
+ inventory_image = "testfood_good2.png",
+ on_use = minetest.item_eat(5),
+})
+
+minetest.register_craftitem("testfood:bad1", {
+ description = S("Bad Food (-1)"),
+ inventory_image = "testfood_bad.png",
+ on_use = minetest.item_eat(-1),
+})
+minetest.register_craftitem("testfood:bad5", {
+ description = S("Bad Food (-5)"),
+ inventory_image = "testfood_bad2.png",
+ on_use = minetest.item_eat(-5),
+})
+
--- /dev/null
+name = testfood
+description = For testing food items
--- /dev/null
+local callback_test = 0
+
+local out = function(player, formname, fields, number)
+ local snum = ""
+ if number then
+ snum = " "..number
+ end
+ local msg = "Formspec callback"..snum..": player="..player:get_player_name()..", formname=\""..tostring(formname).."\", fields="..dump(fields)
+ minetest.chat_send_player(player:get_player_name(), msg)
+ minetest.log("action", msg)
+end
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ if callback_test == 1 then
+ out(player, formname, fields)
+ elseif callback_test == 2 then
+ out(player, formname, fields, 1)
+ end
+end)
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ if callback_test == 2 then
+ out(player, formname, fields, 2)
+ return true -- Disable the first callback
+ end
+end)
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ if callback_test == 2 then
+ out(player, formname, fields, 3)
+ end
+end)
+
+minetest.register_chatcommand("test_formspec_callbacks", {
+ params = "[ 0 | 1 | 2 ]",
+ description = "Test: Change formspec callbacks testing mode",
+ func = function(name, param)
+ local mode = tonumber(param)
+ if not mode then
+ callback_test = (callback_test + 1 % 3)
+ else
+ callback_test = mode
+ end
+ if callback_test == 1 then
+ minetest.chat_send_player(name, "Formspec callback test mode 1 enabled: Logging only")
+ elseif callback_test == 2 then
+ minetest.chat_send_player(name, "Formspec callback test mode 2 enabled: Three callbacks, disable pre-registered callbacks")
+ else
+ callback_test = 0
+ minetest.chat_send_player(name, "Formspec callback test disabled!")
+ end
+ end
+})
--- /dev/null
+-- This code adds dummy items that are supposed to be used in formspecs
+-- for testing item_image formspec elements.
+
+minetest.register_node("testformspec:node", {
+ description = "Formspec Test Node",
+ tiles = { "testformspec_node.png" },
+ groups = { dig_immediate = 3, dummy = 1 },
+})
+
+minetest.register_craftitem("testformspec:item", {
+ description = "Formspec Test Item",
+ inventory_image = "testformspec_item.png",
+ groups = { dummy = 1 },
+})
--- /dev/null
+local color = minetest.colorize
+
+local clip_fs = [[
+ style_type[label,button,image_button,item_image_button,
+ tabheader,scrollbar,table,animated_image
+ ,field,textarea,checkbox,dropdown;noclip=%c]
+
+ label[0,0;A clipping test]
+ button[0,1;3,0.8;clip_button;A clipping test]
+ image_button[0,2;3,0.8;testformspec_button_image.png;clip_image_button;A clipping test]
+ item_image_button[0,3;3,0.8;testformspec:item;clip_item_image_button;A clipping test]
+ tabheader[0,4.7;3,0.63;clip_tabheader;Clip,Test,Text,Tabs;1;false;false]
+ field[0,5;3,0.8;clip_field;Title;]
+ textarea[0,6;3,1;clip_textarea;Title;]
+ checkbox[0,7.5;clip_checkbox;This is a test;true]
+ dropdown[0,8;3,0.8;clip_dropdown;Select An Item,One,Two,Three,Four,Five;1]
+ scrollbar[0,9;3,0.8;horizontal;clip_scrollbar;3]
+ tablecolumns[text;text]
+ table[0,10;3,1;clip_table;one,two,three,four;1]
+ animated_image[-0.5,11;4.5,1;clip_animated_image;testformspec_animation.png;4;100]
+]]
+
+local tabheaders_fs = [[
+ tabheader[0,0;10,0.63;tabs_opaque;Opaque,Without,Border;1;false;false]
+ tabheader[0,1;10,0.63;tabs_opaque_border;Opaque,With,Border;1;false;true]
+ tabheader[0,2;10,0.63;tabs_transparent;Transparent,Without,Border;1;true;false]
+ tabheader[0,3;10,0.63;tabs_transparent_border;Transparent,With,Border;1;true;true]
+ tabheader[0,4;tabs_default;Default,Tabs;1]
+ tabheader[0,6;10,0.5;tabs_size1;Height=0.5;1;false;false]
+ tabheader[2,6;10,0.75;tabs_size1;Height=0.75;1;false;false]
+ tabheader[4,6;10,1;tabs_size2;Height=1;1;false;false]
+ tabheader[6,6;10,1.25;tabs_size2;Height=1.25;1;false;false]
+ tabheader[8,6;10,1.5;tabs_size2;Height=1.5;1;false;false]
+]]
+
+local hypertext_basic = [[
+<bigger>Normal test</bigger>
+This is a normal text.
+
+<bigger><mono>style</mono> test</bigger>
+<style color=#FFFF00>Yellow text.</style> <style color=#FF0000>Red text.</style>
+<style size=24>Size 24.</style> <style size=16>Size 16</style>. <style size=12>Size 12.</style>
+<style font=normal>Normal font.</style> <style font=mono>Mono font.</style>
+
+<bigger>Tag test</bigger>
+<normal>normal</normal>
+<mono>mono</mono>
+<b>bold</b>
+<i>italic</i>
+<u>underlined</u>
+<big>big</big>
+<bigger>bigger</bigger>
+<left>left</left>
+<center>center</center>
+<right>right</right>
+<justify>justify. Here comes a blind text: Lorem testum dolor sit amet consecutor celeron fiftifahivus e shadoninia e smalus jokus anrus relsocutoti rubenwardus. Erasputinus hara holisti dominus wusi. Grumarinsti erltusmuate ol fortitusti fla flo, blani burki e sfani fahif. Ultae ratii, e megus gigae don anonimus. Grinus dimondus krockus e nore. Endus finalus nowus comus endus o blindus tekstus.</justify>
+
+<bigger>Custom tag test</bigger>
+<tag name=t_green color=green>
+<tag name=t_hover hovercolor=yellow>
+<tag name=t_size size=24>
+<tag name=t_mono font=mono>
+<tag name=t_multi color=green font=mono size=24>
+<t_green>color=green</t_green>
+Action: <action name=color><t_green>color=green</t_green></action>
+Action: <action name=hovercolor><t_hover>hovercolor=yellow</t_hover></action>
+<t_size>size=24</t_size>
+<t_mono>font=mono</t_mono>
+<t_multi>color=green font=mono size=24</t_multi>
+
+<bigger><mono>action</mono> test</bigger>
+<action name=action_test>action</action>
+
+<bigger><mono>img</mono> test</bigger>
+Normal:
+<img name=testformspec_item.png>
+<mono>width=48 height=48</mono>:
+<img name=testformspec_item.png width=48 height=48>
+<mono>float=left</mono>:
+<img name=testformspec_item.png float=left>
+<mono>float=right</mono>:
+<img name=testformspec_item.png float=right>
+
+<bigger><mono>item</mono> test</bigger>
+Normal:
+<item name=testformspec:node>
+<mono>width=48 height=48</mono>
+<item name=testformspec:node width=48 height=48>
+<mono>angle=30,0,0</mono>:
+<item name=testformspec:node angle=30,0,0>
+<mono>angle=0,30,0</mono>:
+<item name=testformspec:node angle=0,30,0>
+<mono>angle=0,0,30</mono>:
+<item name=testformspec:node angle=0,0,30>
+<mono>rotate=yes</mono>:
+<item name=testformspec:node rotate=yes>
+<mono>rotate=100,0,0</mono>:
+<item name=testformspec:node rotate=100,0,0>
+<mono>rotate=0,100,0</mono>:
+<item name=testformspec:node rotate=0,100,0>
+<mono>rotate=0,0,100</mono>:
+<item name=testformspec:node rotate=0,0,100>
+<mono>rotate=50,75,100</mono>:
+<item name=testformspec:node rotate=50,75,100>
+<mono>angle=-30,-45,90 rotate=100,150,-50</mono>:
+<item name=testformspec:node angle=-30,-45,90 rotate=100,150,-50>]]
+
+local hypertext_global = [[
+<global background=gray margin=20 valign=bottom halign=right color=pink hovercolor=purple size=12 font=mono>
+This is a test of the global tag. The parameters are:
+background=gray margin=20 valign=bottom halign=right color=pink hovercolor=purple size=12 font=mono
+<action name=global>action</action>]]
+
+local hypertext_fs = "hypertext[0,0;11,9;hypertext;"..minetest.formspec_escape(hypertext_basic).."]"..
+ "hypertext[0,9.5;11,2.5;hypertext;"..minetest.formspec_escape(hypertext_global).."]"
+
+local style_fs = [[
+ style[one_btn1;bgcolor=red;textcolor=yellow;bgcolor_hovered=orange;
+ bgcolor_pressed=purple]
+ button[0,0;2.5,0.8;one_btn1;Button]
+
+ style[one_btn2;border=false;textcolor=cyan] ]]..
+ "button[0,1.05;2.5,0.8;one_btn2;Text " .. color("#FF0", "Yellow") .. [[]
+
+ style[one_btn3;bgimg=testformspec_button_image.png;bgimg_hovered=testformspec_hovered.png;
+ bgimg_pressed=testformspec_pressed.png]
+ button[0,2.1;1,1;one_btn3;Border]
+
+ style[one_btn4;bgimg=testformspec_button_image.png;bgimg_hovered=testformspec_hovered.png;
+ bgimg_pressed=testformspec_pressed.png;border=false]
+ button[1.25,2.1;1,1;one_btn4;NoBor]
+
+ style[one_btn5;bgimg=testformspec_button_image.png;bgimg_hovered=testformspec_hovered.png;
+ bgimg_pressed=testformspec_pressed.png;border=false;alpha=false]
+ button[0,3.35;1,1;one_btn5;Alph]
+
+ style[one_btn6;border=true]
+ image_button[0,4.6;1,1;testformspec_button_image.png;one_btn6;Border]
+
+ style[one_btn7;border=false]
+ image_button[1.25,4.6;1,1;testformspec_button_image.png;one_btn7;NoBor]
+
+ style[one_btn8;border=false]
+ image_button[0,5.85;1,1;testformspec_button_image.png;one_btn8;Border;false;true;testformspec_pressed.png]
+
+ style[one_btn9;border=true]
+ image_button[1.25,5.85;1,1;testformspec_button_image.png;one_btn9;NoBor;false;false;testformspec_pressed.png]
+
+ style[one_btn10;alpha=false]
+ image_button[0,7.1;1,1;testformspec_button_image.png;one_btn10;NoAlpha]
+
+ style[one_btn11;alpha=true]
+ image_button[1.25,7.1;1,1;testformspec_button_image.png;one_btn11;Alpha]
+
+ style[one_btn12;border=true]
+ item_image_button[0,8.35;1,1;testformspec:item;one_btn12;Border]
+
+ style[one_btn13;border=false]
+ item_image_button[1.25,8.35;1,1;testformspec:item;one_btn13;NoBor]
+
+ style[one_btn14;border=false;bgimg=testformspec_bg.png;fgimg=testformspec_button_image.png]
+ style[one_btn14:hovered;bgimg=testformspec_bg_hovered.png;fgimg=testformspec_hovered.png;textcolor=yellow]
+ style[one_btn14:pressed;bgimg=testformspec_bg_pressed.png;fgimg=testformspec_pressed.png;textcolor=blue]
+ style[one_btn14:hovered+pressed;textcolor=purple]
+ image_button[0,9.6;1,1;testformspec_button_image.png;one_btn14;Bg]
+
+ style[one_btn15;border=false;bgimg=testformspec_bg.png;bgimg_hovered=testformspec_bg_hovered.png;bgimg_pressed=testformspec_bg_pressed.png]
+ item_image_button[1.25,9.6;1,1;testformspec:item;one_btn15;Bg]
+
+ style[one_btn16;border=false;bgimg=testformspec_bg_9slice.png;bgimg_hovered=testformspec_bg_9slice_hovered.png;bgimg_pressed=testformspec_bg_9slice_pressed.png;bgimg_middle=4,6]
+ button[2.5,9.6;2,1;one_btn16;9-Slice Bg]
+
+
+
+ container[2.75,0]
+
+ style[one_tb1;textcolor=Yellow]
+ tabheader[0,3;2.5,0.63;one_tb1;Yellow,Text,Tabs;1;false;false]
+
+ style[one_f1;textcolor=yellow]
+ field[0,4.25;2.5,0.8;one_f1;Field One;Yellow Text]
+
+ style[one_f2;border=false;textcolor=cyan]
+ field[0,5.75;2.5,0.8;one_f2;Field Two;Borderless Cyan Text]
+
+ style[one_f3;textcolor=yellow]
+ textarea[0,7.025;2.5,0.8;one_f3;Label;]] ..
+ minetest.formspec_escape("Yellow Text\nLine two") .. [[ ]
+
+ style[one_f4;border=false;textcolor=cyan]
+ textarea[0,8.324999999999999;2.5,0.8;one_f4;Label;]] ..
+ minetest.formspec_escape("Borderless Cyan Text\nLine two") .. [[ ]
+
+ container_end[]
+]]
+
+local scroll_fs =
+ "button[8.5,1;4,1;outside;Outside of container]"..
+ "box[1,1;8,6;#00aa]"..
+ "scroll_container[1,1;8,6;scrbar;vertical]"..
+ "button[0,1;1,1;lorem;Lorem]"..
+ "button[0,10;1,1;ipsum;Ipsum]"..
+ "pwdfield[2,2;1,1;lorem2;Lorem]"..
+ "list[current_player;main;4,4;1,5;]"..
+ "box[2,5;3,2;#ffff00]"..
+ "image[1,10;3,2;testformspec_item.png]"..
+ "image[3,1;testformspec_item.png]"..
+ "item_image[2,6;3,2;testformspec:node]"..
+ "label[2,15;bla Bli\nfoo bar]"..
+ "item_image_button[2,3;1,1;testformspec:node;itemimagebutton;ItemImageButton]"..
+ "tooltip[0,11;3,2;Buz;#f00;#000]"..
+ "box[0,11;3,2;#00ff00]"..
+ "hypertext[3,13;3,3;;" .. hypertext_basic .. "]" ..
+ "container[0,18]"..
+ "box[1,2;3,2;#0a0a]"..
+ "scroll_container[1,2;3,2;scrbar2;horizontal;0.06]"..
+ "button[0,0;6,1;butnest;Nest]"..
+ "label[10,0.5;nest]"..
+ "scroll_container_end[]"..
+ "scrollbar[1,0;3.5,0.3;horizontal;scrbar2;0]"..
+ "container_end[]"..
+ "dropdown[0,6;2;hmdrpdwn;apple,bulb;1]"..
+ "image_button[0,4;2,2;testformspec_button_image.png;imagebutton;bbbbtt;false;true;testformspec_pressed.png]"..
+ "box[1,22.5;4,1;#a00a]"..
+ "scroll_container_end[]"..
+ "scrollbaroptions[max=170]".. -- lowest seen pos is: 0.1*170+6=23 (factor*max+height)
+ "scrollbar[7.5,0;0.3,4;vertical;scrbar;0]"..
+ "scrollbar[8,0;0.3,4;vertical;scrbarhmmm;0]"..
+ "dropdown[0,6;2;hmdrpdwnnn;Outside,of,container;1]"
+
+--style_type[label;textcolor=green]
+--label[0,0;Green]
+--style_type[label;textcolor=blue]
+--label[0,1;Blue]
+--style_type[label;textcolor=;border=true]
+--label[1.2,0;Border]
+--style_type[label;border=true;bgcolor=red]
+--label[1.2,1;Background]
+--style_type[label;border=;bgcolor=]
+--label[0.75,2;Reset]
+
+
+local pages = {
+ -- Real Coordinates
+ [[
+ formspec_version[3]
+ size[12,13]
+ image_button[0,0;1,1;logo.png;rc_image_button_1x1;1x1]
+ image_button[1,0;2,2;logo.png;rc_image_button_2x2;2x2]
+ button[0,2;1,1;rc_button_1x1;1x1]
+ button[1,2;2,2;rc_button_2x2;2x2]
+ item_image[0,4;1,1;air]
+ item_image[1,4;2,2;air]
+ item_image_button[0,6;1,1;testformspec:node;rc_item_image_button_1x1;1x1]
+ item_image_button[1,6;2,2;testformspec:node;rc_item_image_button_2x2;2x2]
+ field[3,.5;3,.5;rc_field;Field;text]
+ pwdfield[6,.5;3,1;rc_pwdfield;Password Field]
+ field[3,1;3,1;;Read-Only Field;text]
+ textarea[3,2;3,.5;rc_textarea_small;Textarea;text]
+ textarea[6,2;3,2;rc_textarea_big;Textarea;text\nmore text]
+ textarea[3,3;3,1;;Read-Only Textarea;text\nmore text]
+ textlist[3,4;3,2;rc_textlist;Textlist,Perfect Coordinates;1;false]
+ tableoptions[highlight=#ABCDEF75;background=#00000055;border=false]
+ table[6,4;3,2;rc_table;Table,Cool Stuff,Foo,Bar;2]
+ dropdown[3,6;3,1;rc_dropdown_small;This,is,a,dropdown;1]
+ dropdown[6,6;3,2;rc_dropdown_big;I,am,a,bigger,dropdown;5]
+ image[0,8;3,2;ignore.png]
+ box[3,7;3,1;#00A3FF]
+ checkbox[3,8;rc_checkbox_1;Check me!;false]
+ checkbox[3,9;rc_checkbox_2;Uncheck me now!;true]
+ scrollbar[0,11.5;11.5,.5;horizontal;rc_scrollbar_horizontal;500]
+ scrollbar[11.5,0;.5,11.5;vertical;rc_scrollbar_vertical;0]
+ list[current_player;main;6,8;3,2;1]
+ button[9,0;2.5,1;rc_empty_button_1;]
+ button[9,1;2.5,1;rc_empty_button_2;]
+ button[9,2;2.5,1;rc_empty_button_3;] ]]..
+ "label[9,0.5;This is a label.\nLine\nLine\nLine\nEnd]"..
+ [[button[9,3;1,1;rc_empty_button_4;]
+ vertlabel[9,4;VERT]
+ label[10,3;HORIZ]
+ tabheader[8,0;6,0.65;rc_tabheader;Tab 1,Tab 2,Tab 3,Secrets;1;false;false]
+ ]],
+ -- Style
+
+ "formspec_version[3]size[12,13]" ..
+ ("label[0.375,0.375;Styled - %s %s]"):format(
+ color("#F00", "red text"),
+ color("#77FF00CC", "green text")) ..
+ "label[6.375,0.375;Unstyled]" ..
+ "box[0,0.75;12,0.1;#999]" ..
+ "box[6,0.85;0.1,11.15;#999]" ..
+ "container[0.375,1.225]" ..
+ style_fs ..
+ "container_end[]container[6.375,1.225]" ..
+ style_fs:gsub("one_", "two_"):gsub("style%[[^%]]+%]", ""):gsub("style_type%[[^%]]+%]", "") ..
+ "container_end[]",
+
+ -- Noclip
+ "formspec_version[3]size[12,13]" ..
+ "label[0.1,0.5;Clip]" ..
+ "container[-2.5,1]" .. clip_fs:gsub("%%c", "false") .. "container_end[]" ..
+ "label[11,0.5;Noclip]" ..
+ "container[11.5,1]" .. clip_fs:gsub("%%c", "true") .. "container_end[]",
+
+ -- Hypertext
+ "size[12,13]real_coordinates[true]" ..
+ "container[0.5,0.5]" .. hypertext_fs .. "container_end[]",
+
+ -- Tabheaders
+ "size[12,13]real_coordinates[true]" ..
+ "container[0.5,1.5]" .. tabheaders_fs .. "container_end[]",
+
+ -- Animation
+ [[
+ formspec_version[3]
+ size[12,13]
+ animated_image[0.5,0.5;1,1;;testformspec_animation.png;4;100]
+ animated_image[0.5,1.75;1,1;;testformspec_animation.jpg;4;100]
+ animated_image[1.75,0.5;1,1;;testformspec_animation.png;100;100]
+ animated_image[3,0.5;1,1;ani_img_1;testformspec_animation.png;4;1000]
+ button[4.25,0.5;1,1;ani_btn_1;Current
+Number]
+ animated_image[3,1.75;1,1;ani_img_2;testformspec_animation.png;4;1000;2]
+ button[4.25,1.75;1,1;ani_btn_2;Current
+Number]
+ animated_image[3,3;1,1;;testformspec_animation.png;4;0]
+ animated_image[3,4.25;1,1;;testformspec_animation.png;4;0;3]
+ animated_image[5.5,0.5;5,2;;testformspec_animation.png;4;100]
+ animated_image[5.5,2.75;5,2;;testformspec_animation.jpg;4;100]
+ ]],
+
+ -- Scroll containers
+ "formspec_version[3]size[12,13]" ..
+ scroll_fs,
+}
+
+local function show_test_formspec(pname, page_id)
+ page_id = page_id or 2
+
+ local fs = pages[page_id] .. "tabheader[0,0;8,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Anim,ScrollC;" .. page_id .. ";false;false]"
+
+ minetest.show_formspec(pname, "testformspec:formspec", fs)
+end
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ if formname ~= "testformspec:formspec" then
+ return false
+ end
+
+
+ if fields.maintabs then
+ show_test_formspec(player:get_player_name(), tonumber(fields.maintabs))
+ return true
+ end
+
+ if fields.ani_img_1 and fields.ani_btn_1 then
+ minetest.chat_send_player(player:get_player_name(), "ani_img_1 = " .. tostring(fields.ani_img_1))
+ return true
+ elseif fields.ani_img_2 and fields.ani_btn_2 then
+ minetest.chat_send_player(player:get_player_name(), "ani_img_2 = " .. tostring(fields.ani_img_2))
+ return true
+ end
+
+ if fields.hypertext then
+ minetest.chat_send_player(player:get_player_name(), "Hypertext action received: " .. tostring(fields.hypertext))
+ return true
+ end
+end)
+
+minetest.register_chatcommand("test_formspec", {
+ params = "",
+ description = "Open the test formspec",
+ func = function(name)
+ if not minetest.get_player_by_name(name) then
+ return false, "You need to be online!"
+ end
+
+ show_test_formspec(name)
+ return true
+ end,
+})
--- /dev/null
+dofile(minetest.get_modpath("testformspec").."/dummy_items.lua")
+dofile(minetest.get_modpath("testformspec").."/formspec.lua")
+dofile(minetest.get_modpath("testformspec").."/callbacks.lua")
--- /dev/null
+name = testformspec
+description = Contains an example formspec to test all the features of formspecs
--- /dev/null
+# Test Nodes
+
+This mod contains a bunch of basic nodes to test development stuff.
+Most nodes are kept as minimal as possible in order to show off one particular feature of the engine, to make testing stuff easier.
+
+This mod includes tests for:
+
+* drawtypes
+* paramtype2's
+* node properties such as damage, drowning, falling, etc.
+* other random stuff
--- /dev/null
+--[[ Drawtype Test: This file tests out and provides examples for
+all drawtypes in Minetest. It is attempted to keep the node
+definitions as simple and minimal as possible to keep
+side-effects to a minimum.
+
+How to read the node definitions:
+There are two parts which are separated by 2 newlines:
+The first part contains the things that are more or less essential
+for defining the drawtype (except description, which is
+at the top for readability).
+The second part (after the 2 newlines) contains stuff that are
+unrelated to the drawtype, stuff that is mostly there to make
+testing this node easier and more convenient.
+]]
+
+local S = minetest.get_translator("testnodes")
+
+-- If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
+-- This is due to <https://github.com/minetest/minetest/issues/9209>.
+-- This is only added to make the items more visible to avoid confusion, but you will no longer see
+-- the default inventory images for these items. When you want to test the default inventory image of drawtypes,
+-- this should be turned off.
+-- TODO: Remove support for fallback inventory image as soon #9209 is fixed.
+local SHOW_FALLBACK_IMAGE = minetest.settings:get_bool("testnodes_show_fallback_image", false)
+
+local fallback_image = function(img)
+ if SHOW_FALLBACK_IMAGE then
+ return img
+ else
+ return nil
+ end
+end
+
+-- A regular cube
+minetest.register_node("testnodes:normal", {
+ description = S("Normal Drawtype Test Node"),
+ drawtype = "normal",
+ tiles = { "testnodes_normal.png" },
+
+ groups = { dig_immediate = 3 },
+})
+
+-- Standard glasslike node
+minetest.register_node("testnodes:glasslike", {
+ description = S("Glasslike Drawtype Test Node"),
+ drawtype = "glasslike",
+ paramtype = "light",
+ tiles = { "testnodes_glasslike.png" },
+
+ groups = { dig_immediate = 3 },
+})
+
+-- Glasslike framed with the two textures (normal and "detail")
+minetest.register_node("testnodes:glasslike_framed", {
+ description = S("Glasslike Framed Drawtype Test Node"),
+ drawtype = "glasslike_framed",
+ paramtype = "light",
+ tiles = {
+ "testnodes_glasslike_framed.png",
+ "testnodes_glasslike_detail.png",
+ },
+
+
+ sunlight_propagates = true,
+ groups = { dig_immediate = 3 },
+})
+
+-- Like the one above, but without the "detail" texture (texture 2).
+-- This node was added to see how the engine behaves when the "detail" texture
+-- is missing.
+minetest.register_node("testnodes:glasslike_framed_no_detail", {
+ description = S("Glasslike Framed without Detail Drawtype Test Node"),
+ drawtype = "glasslike_framed",
+ paramtype = "light",
+ tiles = { "testnodes_glasslike_framed2.png" },
+
+
+ sunlight_propagates = true,
+ groups = { dig_immediate = 3 },
+})
+
+
+minetest.register_node("testnodes:glasslike_framed_optional", {
+ description = S("Glasslike Framed Optional Drawtype Test Node"),
+ drawtype = "glasslike_framed_optional",
+ paramtype = "light",
+ tiles = {
+ "testnodes_glasslike_framed_optional.png",
+ "testnodes_glasslike_detail.png",
+ },
+
+
+ sunlight_propagates = true,
+ groups = { dig_immediate = 3 },
+})
+
+
+
+minetest.register_node("testnodes:allfaces", {
+ description = S("Allfaces Drawtype Test Node"),
+ drawtype = "allfaces",
+ paramtype = "light",
+ tiles = { "testnodes_allfaces.png" },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:allfaces_optional", {
+ description = S("Allfaces Optional Drawtype Test Node"),
+ drawtype = "allfaces_optional",
+ paramtype = "light",
+ tiles = { "testnodes_allfaces_optional.png" },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:allfaces_optional_waving", {
+ description = S("Waving Allfaces Optional Drawtype Test Node"),
+ drawtype = "allfaces_optional",
+ paramtype = "light",
+ tiles = { "testnodes_allfaces_optional.png^[brighten" },
+ waving = 2,
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:firelike", {
+ description = S("Firelike Drawtype Test Node"),
+ drawtype = "firelike",
+ paramtype = "light",
+ tiles = { "testnodes_firelike.png" },
+
+
+ walkable = false,
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:fencelike", {
+ description = S("Fencelike Drawtype Test Node"),
+ drawtype = "fencelike",
+ paramtype = "light",
+ tiles = { "testnodes_fencelike.png" },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:torchlike", {
+ description = S("Wallmounted Torchlike Drawtype Test Node"),
+ drawtype = "torchlike",
+ paramtype = "light",
+ paramtype2 = "wallmounted",
+ tiles = {
+ "testnodes_torchlike_floor.png",
+ "testnodes_torchlike_ceiling.png",
+ "testnodes_torchlike_wall.png",
+ },
+
+
+ walkable = false,
+ sunlight_propagates = true,
+ groups = { dig_immediate = 3 },
+ inventory_image = fallback_image("testnodes_torchlike_floor.png"),
+})
+
+minetest.register_node("testnodes:signlike", {
+ description = S("Wallmounted Signlike Drawtype Test Node"),
+ drawtype = "signlike",
+ paramtype = "light",
+ paramtype2 = "wallmounted",
+ tiles = { "testnodes_signlike.png" },
+
+
+ walkable = false,
+ groups = { dig_immediate = 3 },
+ sunlight_propagates = true,
+ inventory_image = fallback_image("testnodes_signlike.png"),
+})
+
+minetest.register_node("testnodes:plantlike", {
+ description = S("Plantlike Drawtype Test Node"),
+ drawtype = "plantlike",
+ paramtype = "light",
+ tiles = { "testnodes_plantlike.png" },
+
+
+ walkable = false,
+ sunlight_propagates = true,
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:plantlike_waving", {
+ description = S("Waving Plantlike Drawtype Test Node"),
+ drawtype = "plantlike",
+ paramtype = "light",
+ tiles = { "testnodes_plantlike_waving.png" },
+ waving = 1,
+
+
+ walkable = false,
+ sunlight_propagates = true,
+ groups = { dig_immediate = 3 },
+})
+
+
+
+-- param2 will rotate
+minetest.register_node("testnodes:plantlike_degrotate", {
+ description = S("Degrotate Plantlike Drawtype Test Node"),
+ drawtype = "plantlike",
+ paramtype = "light",
+ paramtype2 = "degrotate",
+ tiles = { "testnodes_plantlike_degrotate.png" },
+
+
+ walkable = false,
+ sunlight_propagates = true,
+ groups = { dig_immediate = 3 },
+})
+
+-- param2 will change height
+minetest.register_node("testnodes:plantlike_leveled", {
+ description = S("Leveled Plantlike Drawtype Test Node"),
+ drawtype = "plantlike",
+ paramtype = "light",
+ paramtype2 = "leveled",
+ tiles = {
+ { name = "testnodes_plantlike_leveled.png", tileable_vertical = true },
+ },
+
+
+ -- We set a default param2 here only for convenience, to make the "plant" visible after placement
+ place_param2 = 8,
+ walkable = false,
+ sunlight_propagates = true,
+ groups = { dig_immediate = 3 },
+})
+
+-- param2 changes shape
+minetest.register_node("testnodes:plantlike_meshoptions", {
+ description = S("Meshoptions Plantlike Drawtype Test Node"),
+ drawtype = "plantlike",
+ paramtype = "light",
+ paramtype2 = "meshoptions",
+ tiles = { "testnodes_plantlike_meshoptions.png" },
+
+
+ walkable = false,
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:plantlike_rooted", {
+ description = S("Rooted Plantlike Drawtype Test Node"),
+ drawtype = "plantlike_rooted",
+ paramtype = "light",
+ tiles = { "testnodes_plantlike_rooted_base.png" },
+ special_tiles = { "testnodes_plantlike_rooted.png" },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:plantlike_rooted_waving", {
+ description = S("Waving Rooted Plantlike Drawtype Test Node"),
+ drawtype = "plantlike_rooted",
+ paramtype = "light",
+ tiles = {
+ "testnodes_plantlike_rooted_base.png",
+ "testnodes_plantlike_rooted_base.png",
+ "testnodes_plantlike_rooted_base_side_waving.png",
+ },
+ special_tiles = { "testnodes_plantlike_rooted_waving.png" },
+ waving = 1,
+
+ groups = { dig_immediate = 3 },
+})
+
+-- param2 changes height
+minetest.register_node("testnodes:plantlike_rooted_leveled", {
+ description = S("Leveled Rooted Plantlike Drawtype Test Node"),
+ drawtype = "plantlike_rooted",
+ paramtype = "light",
+ paramtype2 = "leveled",
+ tiles = {
+ "testnodes_plantlike_rooted_base.png",
+ "testnodes_plantlike_rooted_base.png",
+ "testnodes_plantlike_rooted_base_side_leveled.png",
+ },
+ special_tiles = {
+ { name = "testnodes_plantlike_rooted_leveled.png", tileable_vertical = true },
+ },
+
+
+ -- We set a default param2 here only for convenience, to make the "plant" visible after placement
+ place_param2 = 8,
+ groups = { dig_immediate = 3 },
+})
+
+-- param2 changes shape
+minetest.register_node("testnodes:plantlike_rooted_meshoptions", {
+ description = S("Meshoptions Rooted Plantlike Drawtype Test Node"),
+ drawtype = "plantlike_rooted",
+ paramtype = "light",
+ paramtype2 = "meshoptions",
+ tiles = {
+ "testnodes_plantlike_rooted_base.png",
+ "testnodes_plantlike_rooted_base.png",
+ "testnodes_plantlike_rooted_base_side_meshoptions.png",
+ },
+ special_tiles = {
+ "testnodes_plantlike_rooted_meshoptions.png",
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
+-- param2 changes rotation
+minetest.register_node("testnodes:plantlike_rooted_degrotate", {
+ description = S("Degrotate Rooted Plantlike Drawtype Test Node"),
+ drawtype = "plantlike_rooted",
+ paramtype = "light",
+ paramtype2 = "degrotate",
+ tiles = {
+ "testnodes_plantlike_rooted_base.png",
+ "testnodes_plantlike_rooted_base.png",
+ "testnodes_plantlike_rooted_base_side_degrotate.png",
+ },
+ special_tiles = {
+ "testnodes_plantlike_rooted_degrotate.png",
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
+-- Demonstrative liquid nodes, source and flowing form. This is only the
+-- drawtype, no physical liquid properties are used
+minetest.register_node("testnodes:liquid", {
+ description = S("Source Liquid Drawtype Test Node"),
+ drawtype = "liquid",
+ paramtype = "light",
+ tiles = {
+ "testnodes_liquidsource.png",
+ },
+ special_tiles = {
+ {name="testnodes_liquidsource.png", backface_culling=false},
+ {name="testnodes_liquidsource.png", backface_culling=true},
+ },
+ use_texture_alpha = true,
+
+
+ walkable = false,
+ liquid_alternative_flowing = "testnodes:liquid_flowing",
+ liquid_alternative_source = "testnodes:liquid",
+ groups = { dig_immediate = 3 },
+})
+minetest.register_node("testnodes:liquid_flowing", {
+ description = S("Flowing Liquid Drawtype Test Node"),
+ drawtype = "flowingliquid",
+ paramtype = "light",
+ paramtype2 = "flowingliquid",
+ tiles = {
+ "testnodes_liquidflowing.png",
+ },
+ special_tiles = {
+ {name="testnodes_liquidflowing.png", backface_culling=false},
+ {name="testnodes_liquidflowing.png", backface_culling=false},
+ },
+ use_texture_alpha = true,
+
+
+ walkable = false,
+ liquid_alternative_flowing = "testnodes:liquid_flowing",
+ liquid_alternative_source = "testnodes:liquid",
+ groups = { dig_immediate = 3 },
+})
+minetest.register_node("testnodes:liquid_waving", {
+ description = S("Waving Source Liquid Drawtype Test Node"),
+ drawtype = "liquid",
+ paramtype = "light",
+ tiles = {
+ "testnodes_liquidsource.png^[brighten",
+ },
+ special_tiles = {
+ {name="testnodes_liquidsource.png^[brighten", backface_culling=false},
+ {name="testnodes_liquidsource.png^[brighten", backface_culling=true},
+ },
+ use_texture_alpha = true,
+ waving = 3,
+
+
+ walkable = false,
+ liquid_alternative_flowing = "testnodes:liquid_flowing",
+ liquid_alternative_source = "testnodes:liquid",
+ groups = { dig_immediate = 3 },
+})
+minetest.register_node("testnodes:liquid_flowing_waving", {
+ description = S("Waving Flowing Liquid Drawtype Test Node"),
+ drawtype = "flowingliquid",
+ paramtype = "light",
+ paramtype2 = "flowingliquid",
+ tiles = {
+ "testnodes_liquidflowing.png^[brighten",
+ },
+ special_tiles = {
+ {name="testnodes_liquidflowing.png^[brighten", backface_culling=false},
+ {name="testnodes_liquidflowing.png^[brighten", backface_culling=false},
+ },
+ use_texture_alpha = true,
+ waving = 3,
+
+
+ walkable = false,
+ liquid_alternative_flowing = "testnodes:liquid_flowing",
+ liquid_alternative_source = "testnodes:liquid",
+ groups = { dig_immediate = 3 },
+})
+
+
+
+-- Invisible node
+minetest.register_node("testnodes:airlike", {
+ description = S("Airlike Drawtype Test Node"),
+ drawtype = "airlike",
+ paramtype = "light",
+
+
+ walkable = false,
+ groups = { dig_immediate = 3 },
+ sunlight_propagates = true,
+ inventory_image = fallback_image("testnodes_airlike.png"),
+})
+
+-- param2 changes liquid height
+minetest.register_node("testnodes:glassliquid", {
+ description = S("Glasslike Liquid Level Drawtype Test Node"),
+ drawtype = "glasslike_framed",
+ paramtype = "light",
+ paramtype2 = "glasslikeliquidlevel",
+ tiles = {
+ "testnodes_glasslikeliquid.png",
+ },
+ special_tiles = {
+ "testnodes_liquid.png",
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
+-- Adding many raillike examples, primarily to demonstrate the behavior of
+-- "raillike groups". Nodes of the same type (rail, groupless, line, street)
+-- should connect to nodes of the same "rail type" (=same shape, different
+-- color) only.
+local rails = {
+ { "rail", {"testnodes_rail_straight.png", "testnodes_rail_curved.png", "testnodes_rail_t_junction.png", "testnodes_rail_crossing.png"} },
+ { "line", {"testnodes_line_straight.png", "testnodes_line_curved.png", "testnodes_line_t_junction.png", "testnodes_line_crossing.png"}, },
+ { "street", {"testnodes_street_straight.png", "testnodes_street_curved.png", "testnodes_street_t_junction.png", "testnodes_street_crossing.png"}, },
+ -- the "groupless" nodes are nodes in which the "connect_to_raillike" group is not set
+ { "groupless", {"testnodes_rail2_straight.png", "testnodes_rail2_curved.png", "testnodes_rail2_t_junction.png", "testnodes_rail2_crossing.png"} },
+}
+local colors = { "", "cyan", "red" }
+
+for r=1, #rails do
+ local id = rails[r][1]
+ local tiles = rails[r][2]
+ local raillike_group
+ if id ~= "groupless" then
+ raillike_group = minetest.raillike_group(id)
+ end
+ for c=1, #colors do
+ local color
+ if colors[c] ~= "" then
+ color = colors[c]
+ end
+ minetest.register_node("testnodes:raillike_"..id..c, {
+ description = S("Raillike Drawtype Test Node: @1 @2", id, c),
+ drawtype = "raillike",
+ paramtype = "light",
+ tiles = tiles,
+ groups = { connect_to_raillike = raillike_group, dig_immediate = 3 },
+
+
+ color = color,
+ selection_box = {
+ type = "fixed",
+ fixed = {{-0.5, -0.5, -0.5, 0.5, -0.4, 0.5}},
+ },
+ sunlight_propagates = true,
+ walkable = false,
+ })
+ end
+end
+
+
+
+-- Add visual_scale variants of previous nodes for half and double size
+local scale = function(subname, desc_double, desc_half)
+ local original = "testnodes:"..subname
+ local def = table.copy(minetest.registered_items[original])
+ def.visual_scale = 2.0
+ def.description = desc_double
+ minetest.register_node("testnodes:"..subname.."_double", def)
+ def = table.copy(minetest.registered_items[original])
+ def.visual_scale = 0.5
+ def.description = desc_half
+ minetest.register_node("testnodes:"..subname.."_half", def)
+end
+
+scale("plantlike",
+ S("Double-sized Plantlike Drawtype Test Node"),
+ S("Half-sized Plantlike Drawtype Test Node"))
+scale("torchlike",
+ S("Double-sized Wallmounted Torchlike Drawtype Test Node"),
+ S("Half-sized Wallmounted Torchlike Drawtype Test Node"))
+scale("signlike",
+ S("Double-sized Wallmounted Signlike Drawtype Test Node"),
+ S("Half-sized Wallmounted Signlike Drawtype Test Node"))
+scale("firelike",
+ S("Double-sized Firelike Drawtype Test Node"),
+ S("Half-sized Firelike Drawtype Test Node"))
--- /dev/null
+local path = minetest.get_modpath(minetest.get_current_modname())
+
+dofile(path.."/drawtypes.lua")
+dofile(path.."/meshes.lua")
+dofile(path.."/nodeboxes.lua")
+dofile(path.."/param2.lua")
+dofile(path.."/properties.lua")
+dofile(path.."/liquids.lua")
+dofile(path.."/light.lua")
+dofile(path.."/textures.lua")
--- /dev/null
+-- Test Nodes: Light test
+
+local S = minetest.get_translator("testnodes")
+
+-- All possible light levels
+for i=1, minetest.LIGHT_MAX do
+ minetest.register_node("testnodes:light"..i, {
+ description = S("Light Source (@1)", i),
+ paramtype = "light",
+ light_source = i,
+
+
+ tiles ={"testnodes_light_"..i..".png"},
+ drawtype = "glasslike",
+ walkable = false,
+ sunlight_propagates = true,
+ is_ground_content = false,
+ groups = {dig_immediate=3},
+ })
+end
+
+-- Lets light through, but not sunlight, leading to a
+-- reduction in light level when light passes through
+minetest.register_node("testnodes:sunlight_filter", {
+ description = S("Sunlight Filter"),
+ paramtype = "light",
+
+
+ drawtype = "glasslike",
+ tiles = {
+ "testnodes_sunlight_filter.png",
+ },
+ groups = { dig_immediate = 3 },
+})
+
+-- Lets light and sunlight through without obstruction
+minetest.register_node("testnodes:sunlight_propagator", {
+ description = S("Sunlight Propagator"),
+ paramtype = "light",
+ sunlight_propagates = true,
+
+
+ drawtype = "glasslike",
+ tiles = {
+ "testnodes_sunlight_filter.png^[brighten",
+ },
+ groups = { dig_immediate = 3 },
+})
--- /dev/null
+-- Add liquids for ranges and viscosity levels 0-8
+
+for d=0, 8 do
+ minetest.register_node("testnodes:rliquid_"..d, {
+ description = "Test Liquid Source, Range "..d,
+ drawtype = "liquid",
+ tiles = {"testnodes_liquidsource_r"..d..".png"},
+ special_tiles = {
+ {name = "testnodes_liquidsource_r"..d..".png", backface_culling = false},
+ {name = "testnodes_liquidsource_r"..d..".png", backface_culling = true},
+ },
+ alpha = 192,
+ paramtype = "light",
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ liquidtype = "source",
+ liquid_alternative_flowing = "testnodes:rliquid_flowing_"..d,
+ liquid_alternative_source = "testnodes:rliquid_"..d,
+ liquid_range = d,
+ })
+
+ minetest.register_node("testnodes:rliquid_flowing_"..d, {
+ description = "Flowing Test Liquid, Range "..d,
+ drawtype = "flowingliquid",
+ tiles = {"testnodes_liquidflowing_r"..d..".png"},
+ special_tiles = {
+ {name = "testnodes_liquidflowing_r"..d..".png", backface_culling = false},
+ {name = "testnodes_liquidflowing_r"..d..".png", backface_culling = false},
+ },
+ alpha = 192,
+ paramtype = "light",
+ paramtype2 = "flowingliquid",
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ liquidtype = "flowing",
+ liquid_alternative_flowing = "testnodes:rliquid_flowing_"..d,
+ liquid_alternative_source = "testnodes:rliquid_"..d,
+ liquid_range = d,
+ })
+
+ local mod = "^[colorize:#000000:127"
+ minetest.register_node("testnodes:vliquid_"..d, {
+ description = "Test Liquid Source, Viscosity "..d,
+ drawtype = "liquid",
+ tiles = {"testnodes_liquidsource_r"..d..".png"..mod},
+ special_tiles = {
+ {name = "testnodes_liquidsource_r"..d..".png"..mod, backface_culling = false},
+ {name = "testnodes_liquidsource_r"..d..".png"..mod, backface_culling = true},
+ },
+ alpha = 192,
+ paramtype = "light",
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ liquidtype = "source",
+ liquid_alternative_flowing = "testnodes:vliquid_flowing_"..d,
+ liquid_alternative_source = "testnodes:vliquid_"..d,
+ liquid_viscosity = d,
+ })
+
+ minetest.register_node("testnodes:vliquid_flowing_"..d, {
+ description = "Flowing Test Liquid, Viscosity "..d,
+ drawtype = "flowingliquid",
+ tiles = {"testnodes_liquidflowing_r"..d..".png"..mod},
+ special_tiles = {
+ {name = "testnodes_liquidflowing_r"..d..".png"..mod, backface_culling = false},
+ {name = "testnodes_liquidflowing_r"..d..".png"..mod, backface_culling = false},
+ },
+ alpha = 192,
+ paramtype = "light",
+ paramtype2 = "flowingliquid",
+ walkable = false,
+ pointable = false,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ liquidtype = "flowing",
+ liquid_alternative_flowing = "testnodes:vliquid_flowing_"..d,
+ liquid_alternative_source = "testnodes:vliquid_"..d,
+ liquid_viscosity = d,
+ })
+
+end
--- /dev/null
+-- Meshes
+
+local S = minetest.get_translator("testnodes")
+
+local ocorner_cbox = {
+ type = "fixed",
+ fixed = {
+ {-0.5, -0.5, -0.5, 0.5, -0.25, 0.5},
+ {-0.5, -0.25, -0.25, 0.25, 0, 0.5},
+ {-0.5, 0, 0, 0, 0.25, 0.5},
+ {-0.5, 0.25, 0.25, -0.25, 0.5, 0.5}
+ }
+}
+
+local tall_pyr_cbox = {
+ type = "fixed",
+ fixed = {
+ { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 },
+ { -0.375, -0.25, -0.375, 0.375, 0, 0.375},
+ { -0.25, 0, -0.25, 0.25, 0.25, 0.25},
+ { -0.125, 0.25, -0.125, 0.125, 0.5, 0.125}
+ }
+}
+
+-- Normal mesh
+minetest.register_node("testnodes:mesh", {
+ description = S("Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_pyramid.obj",
+ tiles = {"testnodes_mesh_stripes2.png"},
+ paramtype = "light",
+ collision_box = tall_pyr_cbox,
+
+ groups = {dig_immediate=3},
+})
+
+-- Facedir mesh: outer corner slope
+minetest.register_node("testnodes:mesh_facedir", {
+ description = S("Facedir Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_ocorner.obj",
+ tiles = {"testnodes_mesh_stripes.png"},
+ paramtype = "light",
+ paramtype2 = "facedir",
+ collision_box = ocorner_cbox,
+
+ groups = {dig_immediate=3},
+})
+
+minetest.register_node("testnodes:mesh_colorfacedir", {
+ description = S("Color Facedir Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_ocorner.obj",
+ tiles = {"testnodes_mesh_stripes3.png"},
+ paramtype = "light",
+ paramtype2 = "colorfacedir",
+ palette = "testnodes_palette_facedir.png",
+ collision_box = ocorner_cbox,
+
+ groups = {dig_immediate=3},
+})
+
+-- Wallmounted mesh: pyramid
+minetest.register_node("testnodes:mesh_wallmounted", {
+ description = S("Wallmounted Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_pyramid.obj",
+ tiles = {"testnodes_mesh_stripes2.png"},
+ paramtype = "light",
+ paramtype2 = "wallmounted",
+ collision_box = tall_pyr_cbox,
+
+ groups = {dig_immediate=3},
+})
+
+minetest.register_node("testnodes:mesh_colorwallmounted", {
+ description = S("Color Wallmounted Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_pyramid.obj",
+ tiles = {"testnodes_mesh_stripes3.png"},
+ paramtype = "light",
+ paramtype2 = "colorwallmounted",
+ palette = "testnodes_palette_wallmounted.png",
+ collision_box = tall_pyr_cbox,
+
+ groups = {dig_immediate=3},
+})
+
+
+minetest.register_node("testnodes:mesh_double", {
+ description = S("Double-sized Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_pyramid.obj",
+ tiles = {"testnodes_mesh_stripes2.png"},
+ paramtype = "light",
+ collision_box = tall_pyr_cbox,
+ visual_scale = 2,
+
+ groups = {dig_immediate=3},
+})
+minetest.register_node("testnodes:mesh_half", {
+ description = S("Half-sized Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_pyramid.obj",
+ tiles = {"testnodes_mesh_stripes2.png"},
+ paramtype = "light",
+ collision_box = tall_pyr_cbox,
+ visual_scale = 0.5,
+
+ groups = {dig_immediate=3},
+})
+
+minetest.register_node("testnodes:mesh_waving1", {
+ description = S("Plantlike-waving Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_pyramid.obj",
+ tiles = {"testnodes_mesh_stripes4.png^[multiply:#B0FFB0"},
+ paramtype = "light",
+ collision_box = tall_pyr_cbox,
+ waving = 1,
+
+ groups = {dig_immediate=3},
+})
+minetest.register_node("testnodes:mesh_waving2", {
+ description = S("Leaflike-waving Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_pyramid.obj",
+ tiles = {"testnodes_mesh_stripes4.png^[multiply:#FFFFB0"},
+ paramtype = "light",
+ collision_box = tall_pyr_cbox,
+ waving = 2,
+
+ groups = {dig_immediate=3},
+})
+minetest.register_node("testnodes:mesh_waving3", {
+ description = S("Liquidlike-waving Mesh Test Node"),
+ drawtype = "mesh",
+ mesh = "testnodes_pyramid.obj",
+ tiles = {"testnodes_mesh_stripes4.png^[multiply:#B0B0FF"},
+ paramtype = "light",
+ collision_box = tall_pyr_cbox,
+ waving = 3,
+
+ groups = {dig_immediate=3},
+})
--- /dev/null
+name = testnodes
+description = Contains a bunch of basic example nodes for demonstrative purposes, development and testing
--- /dev/null
+# Blender v2.73 (sub 0) OBJ File: 'slope_test_ocorner_onetexture.blend'
+# www.blender.org
+o Cube_Cube.002
+v 0.500000 0.500000 0.500000
+v -0.500000 -0.500000 0.500000
+v 0.500000 -0.500000 0.500000
+v -0.500000 -0.500000 -0.500000
+v 0.500000 -0.500000 -0.500000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vn 0.000000 -1.000000 -0.000000
+vn 1.000000 0.000000 0.000000
+vn 0.000000 -0.000000 1.000000
+vn -0.707100 0.707100 0.000000
+vn 0.000000 0.707100 -0.707100
+s off
+f 3/1/1 2/2/1 4/3/1 5/4/1
+f 1/2/2 3/3/2 5/4/2
+f 1/1/3 2/3/3 3/4/3
+f 1/1/4 4/3/4 2/4/4
+f 1/2/5 5/3/5 4/4/5
--- /dev/null
+# Blender v2.73 (sub 0) OBJ File: 'slope_test_pyramid_onetexture.blend'
+# www.blender.org
+o Cube
+v 0.500000 -0.500000 -0.500000
+v 0.500000 -0.500000 0.500000
+v -0.500000 -0.500000 0.500000
+v -0.500000 -0.500000 -0.500000
+v -0.000000 0.500000 -0.000000
+vt 1.000000 1.000000
+vt 0.000000 1.000000
+vt 0.000000 0.000000
+vt 1.000000 0.000000
+vt 0.500000 1.000000
+vn 0.000000 -1.000000 0.000000
+vn -0.894400 0.447200 -0.000000
+vn 0.000000 0.447200 -0.894400
+vn 0.894400 0.447200 0.000000
+vn -0.000000 0.447200 0.894400
+s off
+f 1/1/1 2/2/1 3/3/1 4/4/1
+f 3/4/2 5/5/2 4/3/2
+f 5/5/3 1/3/3 4/4/3
+f 1/4/4 5/5/4 2/3/4
+f 2/4/5 5/5/5 3/3/5
--- /dev/null
+local S = minetest.get_translator("testnodes")
+
+-- Nodebox examples and tests.
+
+-- An simple example nodebox with one centered box
+minetest.register_node("testnodes:nodebox_fixed", {
+ description = S("Fixed Nodebox Test Node"),
+ tiles = {"testnodes_nodebox.png"},
+ drawtype = "nodebox",
+ paramtype = "light",
+ node_box = {
+ type = "fixed",
+ fixed = {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25},
+ },
+
+ groups = {dig_immediate=3},
+})
+
+-- 50% higher than a regular node
+minetest.register_node("testnodes:nodebox_overhigh", {
+ description = S("Overhigh Nodebox Test Node"),
+ tiles = {"testnodes_nodebox.png"},
+ drawtype = "nodebox",
+ paramtype = "light",
+ node_box = {
+ type = "fixed",
+ fixed = {-0.5, -0.5, -0.5, 0.5, 1, 0.5},
+ },
+
+ groups = {dig_immediate=3},
+})
+
+-- 100% higher than a regular node
+minetest.register_node("testnodes:nodebox_overhigh2", {
+ description = S("Double-height Nodebox Test Node"),
+ tiles = {"testnodes_nodebox.png"},
+ drawtype = "nodebox",
+ paramtype = "light",
+ node_box = {
+ type = "fixed",
+ fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5},
+ },
+
+ groups = {dig_immediate=3},
+})
+
+-- Height of nodebox changes with its param2 value
+minetest.register_node("testnodes:nodebox_leveled", {
+ description = S("Leveled Nodebox Test Node"),
+ tiles = {"testnodes_nodebox.png"},
+ drawtype = "nodebox",
+ paramtype = "light",
+ paramtype2 = "leveled",
+ node_box = {
+ type = "leveled",
+ fixed = {-0.5, 0.0, -0.5, 0.5, -0.499, 0.5},
+ },
+
+ groups = {dig_immediate=3},
+})
+
+-- Wall-like nodebox that connects to neighbors
+minetest.register_node("testnodes:nodebox_connected", {
+ description = S("Connected Nodebox Test Node"),
+ tiles = {"testnodes_nodebox.png"},
+ groups = {connected_nodebox=1, dig_immediate=3},
+ drawtype = "nodebox",
+ paramtype = "light",
+ connects_to = {"group:connected_nodebox"},
+ connect_sides = {"front", "back", "left", "right"},
+ node_box = {
+ type = "connected",
+ fixed = {-0.125, -0.500, -0.125, 0.125, 0.500, 0.125},
+ connect_front = {-0.125, -0.500, -0.500, 0.125, 0.400, -0.125},
+ connect_back = {-0.125, -0.500, 0.125, 0.125, 0.400, 0.500},
+ connect_left = {-0.500, -0.500, -0.125, -0.125, 0.400, 0.125},
+ connect_right = {0.125, -0.500, -0.125, 0.500, 0.400, 0.125},
+ },
+})
+
--- /dev/null
+-- This file is for misc. param2 tests that aren't covered in drawtypes.lua already.
+
+local S = minetest.get_translator("testnodes")
+
+minetest.register_node("testnodes:facedir", {
+ description = S("Facedir Test Node"),
+ paramtype2 = "facedir",
+ tiles = {
+ "testnodes_1.png",
+ "testnodes_2.png",
+ "testnodes_3.png",
+ "testnodes_4.png",
+ "testnodes_5.png",
+ "testnodes_6.png",
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:facedir_nodebox", {
+ description = S("Facedir Nodebox Test Node"),
+ tiles = {
+ "testnodes_1.png",
+ "testnodes_2.png",
+ "testnodes_3.png",
+ "testnodes_4.png",
+ "testnodes_5.png",
+ "testnodes_6.png",
+ },
+ drawtype = "nodebox",
+ paramtype = "light",
+ paramtype2 = "facedir",
+ node_box = {
+ type = "fixed",
+ fixed = {-0.5, -0.5, -0.5, 0.2, 0.2, 0.2},
+ },
+
+ groups = {dig_immediate=3},
+})
+
+minetest.register_node("testnodes:wallmounted", {
+ description = S("Wallmounted Test Node"),
+ paramtype2 = "wallmounted",
+ tiles = {
+ "testnodes_1w.png",
+ "testnodes_2w.png",
+ "testnodes_3w.png",
+ "testnodes_4w.png",
+ "testnodes_5w.png",
+ "testnodes_6w.png",
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:wallmounted_nodebox", {
+ description = S("Wallmounted Nodebox Test Node"),
+ paramtype2 = "wallmounted",
+ paramtype = "light",
+ tiles = {
+ "testnodes_1w.png",
+ "testnodes_2w.png",
+ "testnodes_3w.png",
+ "testnodes_4w.png",
+ "testnodes_5w.png",
+ "testnodes_6w.png",
+ },
+ drawtype = "nodebox",
+ node_box = {
+ type = "wallmounted",
+ wall_top = { -0.5, 0, -0.5, 0.5, 0.5, 0.5 },
+ wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 },
+ wall_side = { -0.5, -0.5, -0.5, 0, 0.5, 0.5 },
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:color", {
+ description = S("Color Test Node"),
+ paramtype2 = "color",
+ palette = "testnodes_palette_full.png",
+ tiles = {
+ "testnodes_node.png",
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:colorfacedir", {
+ description = S("Color Facedir Test Node"),
+ paramtype2 = "colorfacedir",
+ palette = "testnodes_palette_facedir.png",
+ tiles = {
+ "testnodes_1g.png",
+ "testnodes_2g.png",
+ "testnodes_3g.png",
+ "testnodes_4g.png",
+ "testnodes_5g.png",
+ "testnodes_6g.png",
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:colorfacedir_nodebox", {
+ description = S("Color Facedir Nodebox Test Node"),
+ tiles = {
+ "testnodes_1g.png",
+ "testnodes_2g.png",
+ "testnodes_3g.png",
+ "testnodes_4g.png",
+ "testnodes_5g.png",
+ "testnodes_6g.png",
+ },
+ drawtype = "nodebox",
+ paramtype = "light",
+ paramtype2 = "colorfacedir",
+ palette = "testnodes_palette_facedir.png",
+ node_box = {
+ type = "fixed",
+ fixed = {-0.5, -0.5, -0.5, 0.2, 0.2, 0.2},
+ },
+
+ groups = {dig_immediate=3},
+})
+
+minetest.register_node("testnodes:colorwallmounted", {
+ description = S("Color Wallmounted Test Node"),
+ paramtype2 = "colorwallmounted",
+ paramtype = "light",
+ palette = "testnodes_palette_wallmounted.png",
+ tiles = {
+ "testnodes_1wg.png",
+ "testnodes_2wg.png",
+ "testnodes_3wg.png",
+ "testnodes_4wg.png",
+ "testnodes_5wg.png",
+ "testnodes_6wg.png",
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
+minetest.register_node("testnodes:colorwallmounted_nodebox", {
+ description = S("Color Wallmounted Nodebox Test Node"),
+ paramtype2 = "colorwallmounted",
+ paramtype = "light",
+ palette = "testnodes_palette_wallmounted.png",
+ tiles = {
+ "testnodes_1wg.png",
+ "testnodes_2wg.png",
+ "testnodes_3wg.png",
+ "testnodes_4wg.png",
+ "testnodes_5wg.png",
+ "testnodes_6wg.png",
+ },
+ drawtype = "nodebox",
+ node_box = {
+ type = "wallmounted",
+ wall_top = { -0.5, 0, -0.5, 0.5, 0.5, 0.5 },
+ wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 },
+ wall_side = { -0.5, -0.5, -0.5, 0, 0.5, 0.5 },
+ },
+
+ groups = { dig_immediate = 3 },
+})
+
--- /dev/null
+-- Test Nodes: Node property tests
+
+local S = minetest.get_translator("testnodes")
+
+-- Is supposed to fall when it doesn't rest on solid ground
+minetest.register_node("testnodes:falling", {
+ description = S("Falling Node"),
+ tiles = {
+ "testnodes_node.png",
+ "testnodes_node.png",
+ "testnodes_node_falling.png",
+ },
+ groups = { falling_node = 1, dig_immediate = 3 },
+})
+
+-- Same as falling node, but will stop falling on top of liquids
+minetest.register_node("testnodes:falling_float", {
+ description = S("Falling+Floating Node"),
+ groups = { falling_node = 1, float = 1, dig_immediate = 3 },
+
+
+ tiles = {
+ "testnodes_node.png",
+ "testnodes_node.png",
+ "testnodes_node_falling.png",
+ },
+ color = "cyan",
+})
+
+-- This node attaches to the floor and drops as item
+-- when the floor is gone.
+minetest.register_node("testnodes:attached", {
+ description = S("Floor-Attached Node"),
+ tiles = {
+ "testnodes_attached_top.png",
+ "testnodes_attached_bottom.png",
+ "testnodes_attached_side.png",
+ },
+ groups = { attached_node = 1, dig_immediate = 3 },
+})
+
+-- This node attaches to the side of a node and drops as item
+-- when the node it attaches to is gone.
+minetest.register_node("testnodes:attached_wallmounted", {
+ description = S("Wallmounted Attached Node"),
+ paramtype2 = "wallmounted",
+ tiles = {
+ "testnodes_attachedw_top.png",
+ "testnodes_attachedw_bottom.png",
+ "testnodes_attachedw_side.png",
+ },
+ groups = { attached_node = 1, dig_immediate = 3 },
+})
+
+-- Jump disabled
+minetest.register_node("testnodes:nojump", {
+ description = S("Non-jumping Node"),
+ groups = {disable_jump=1, dig_immediate=3},
+
+
+ tiles = {"testnodes_nojump_top.png", "testnodes_nojump_side.png"},
+})
+
+-- Climbable up and down with jump and sneak keys
+minetest.register_node("testnodes:climbable", {
+ description = S("Climbable Node"),
+ climbable = true,
+ walkable = false,
+
+
+ paramtype = "light",
+ sunlight_propagates = true,
+ is_ground_content = false,
+ tiles ={"testnodes_climbable_side.png"},
+ drawtype = "glasslike",
+ groups = {dig_immediate=3},
+})
+
+-- Climbable only downwards with sneak key
+minetest.register_node("testnodes:climbable_nojump", {
+ description = S("Downwards-climbable Node"),
+ climbable = true,
+ walkable = false,
+
+ groups = {disable_jump=1, dig_immediate=3},
+ drawtype = "glasslike",
+ tiles ={"testnodes_climbable_nojump_side.png"},
+ paramtype = "light",
+ sunlight_propagates = true,
+})
+
+-- A liquid in which you can't rise
+minetest.register_node("testnodes:liquid_nojump", {
+ description = S("Non-jumping Liquid Source Node"),
+ liquidtype = "source",
+ liquid_range = 1,
+ liquid_viscosity = 0,
+ liquid_alternative_flowing = "testnodes:liquidflowing_nojump",
+ liquid_alternative_source = "testnodes:liquid_nojump",
+ liquid_renewable = false,
+ groups = {disable_jump=1, dig_immediate=3},
+ walkable = false,
+
+ drawtype = "liquid",
+ tiles = {"testnodes_liquidsource.png^[colorize:#FF0000:127"},
+ special_tiles = {
+ {name = "testnodes_liquidsource.png^[colorize:#FF0000:127", backface_culling = false},
+ {name = "testnodes_liquidsource.png^[colorize:#FF0000:127", backface_culling = true},
+ },
+ use_texture_alpha = true,
+ paramtype = "light",
+ pointable = false,
+ liquids_pointable = true,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ post_effect_color = {a = 70, r = 255, g = 0, b = 200},
+})
+
+-- A liquid in which you can't rise (flowing variant)
+minetest.register_node("testnodes:liquidflowing_nojump", {
+ description = S("Non-jumping Flowing Liquid Node"),
+ liquidtype = "flowing",
+ liquid_range = 1,
+ liquid_viscosity = 0,
+ liquid_alternative_flowing = "testnodes:liquidflowing_nojump",
+ liquid_alternative_source = "testnodes:liquid_nojump",
+ liquid_renewable = false,
+ groups = {disable_jump=1, dig_immediate=3},
+ walkable = false,
+
+
+ drawtype = "flowingliquid",
+ tiles = {"testnodes_liquidflowing.png^[colorize:#FF0000:127"},
+ special_tiles = {
+ {name = "testnodes_liquidflowing.png^[colorize:#FF0000:127", backface_culling = false},
+ {name = "testnodes_liquidflowing.png^[colorize:#FF0000:127", backface_culling = false},
+ },
+ use_texture_alpha = true,
+ paramtype = "light",
+ paramtype2 = "flowingliquid",
+ pointable = false,
+ liquids_pointable = true,
+ diggable = false,
+ buildable_to = true,
+ is_ground_content = false,
+ post_effect_color = {a = 70, r = 255, g = 0, b = 200},
+})
+
+-- Nodes that modify fall damage (various damage modifiers)
+for i=-100, 100, 25 do
+ if i ~= 0 then
+ local subname, descnum
+ if i < 0 then
+ subname = "m"..math.abs(i)
+ descnum = tostring(i)
+ else
+ subname = tostring(i)
+ descnum = S("+@1", i)
+ end
+ local tex, color, desc
+ if i > 0 then
+ local val = math.floor((i/100)*255)
+ tex = "testnodes_fall_damage_plus.png"
+ color = { b=0, g=255-val, r=255, a=255 }
+ desc = S("Fall Damage Node (+@1%)", i)
+ else
+ tex = "testnodes_fall_damage_minus.png"
+ if i == -100 then
+ color = { r=0, b=0, g=255, a=255 }
+ else
+ local val = math.floor((math.abs(i)/100)*255)
+ color = { r=0, b=255, g=255-val, a=255 }
+ end
+ desc = S("Fall Damage Node (-@1%)", math.abs(i))
+ end
+ minetest.register_node("testnodes:damage"..subname, {
+ description = desc,
+ groups = {fall_damage_add_percent=i, dig_immediate=3},
+
+
+ tiles = { tex },
+ is_ground_content = false,
+ color = color,
+ })
+ end
+end
+
+-- Bouncy nodes (various bounce levels)
+for i=20, 180, 20 do
+ local val = math.floor(((i-20)/200)*255)
+ minetest.register_node("testnodes:bouncy"..i, {
+ description = S("Bouncy Node (@1%)", i),
+ groups = {bouncy=i, dig_immediate=3},
+
+
+ tiles ={"testnodes_bouncy.png"},
+ is_ground_content = false,
+ color = { r=255, g=255-val, b=val, a=255 },
+ })
+end
+
+-- Slippery nodes (various slippery levels)
+for i=1, 5 do
+ minetest.register_node("testnodes:slippery"..i, {
+ description = S("Slippery Node (@1)", i),
+ tiles ={"testnodes_slippery.png"},
+ is_ground_content = false,
+ groups = {slippery=i, dig_immediate=3},
+ color = { r=0, g=255, b=math.floor((i/5)*255), a=255 },
+ })
+end
+
+-- By placing something on the node, the node itself will be replaced
+minetest.register_node("testnodes:buildable_to", {
+ description = S("Replacable Node"),
+ buildable_to = true,
+ tiles = {"testnodes_buildable_to.png"},
+ is_ground_content = false,
+ groups = {dig_immediate=3},
+})
+
+-- Nodes that deal damage to players that are inside them.
+-- Negative damage nodes should heal.
+for d=-3,3 do
+ if d ~= 0 then
+ local sub, tile
+ if d > 0 then
+ sub = tostring(d)
+ tile = "testnodes_damage.png"
+ else
+ sub = "m" .. tostring(math.abs(d))
+ tile = "testnodes_damage_neg.png"
+ end
+ if math.abs(d) == 2 then
+ tile = tile .. "^[colorize:#000000:70"
+ elseif math.abs(d) == 3 then
+ tile = tile .. "^[colorize:#000000:140"
+ end
+ minetest.register_node("testnodes:damage_"..sub, {
+ description = S("Damage Node (@1 damage per second)", d),
+ damage_per_second = d,
+
+
+ walkable = false,
+ is_ground_content = false,
+ drawtype = "allfaces",
+ paramtype = "light",
+ sunlight_propagates = true,
+ tiles = { tile },
+ groups = {dig_immediate=3},
+ })
+ end
+end
+
+-- Causes drowning damage
+minetest.register_node("testnodes:drowning_1", {
+ description = S("Drowning Node (@1 damage)", 1),
+ drowning = 1,
+
+
+ walkable = false,
+ is_ground_content = false,
+ drawtype = "allfaces",
+ paramtype = "light",
+ sunlight_propagates = true,
+ tiles = { "testnodes_drowning.png" },
+ groups = {dig_immediate=3},
+})
+
--- /dev/null
+# If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
+# This is due to <https://github.com/minetest/minetest/issues/9209>.
+# This is only added to make the items more visible to avoid confusion, but you will no longer see the default inventory images for these items. When you want to test the default inventory image of drawtypes, this should be turned off.
+testnodes_show_fallback_image (Use fallback inventory images) bool false
--- /dev/null
+-- Node texture tests
+
+local S = minetest.get_translator("testnodes")
+
+minetest.register_node("testnodes:6sides", {
+ description = S("Six Textures Test Node"),
+ tiles = {
+ "testnodes_normal1.png",
+ "testnodes_normal2.png",
+ "testnodes_normal3.png",
+ "testnodes_normal4.png",
+ "testnodes_normal5.png",
+ "testnodes_normal6.png",
+ },
+
+ groups = { dig_immediate = 2 },
+})
+
+minetest.register_node("testnodes:anim", {
+ description = S("Animated Test Node"),
+ tiles = {
+ { name = "testnodes_anim.png",
+ animation = {
+ type = "vertical_frames",
+ aspect_w = 16,
+ aspect_h = 16,
+ length = 4.0,
+ }, },
+ },
+
+ groups = { dig_immediate = 2 },
+})
+
+-- Node texture transparency test
+
+local alphas = { 64, 128, 191 }
+
+for a=1,#alphas do
+ local alpha = alphas[a]
+
+ -- Transparency taken from texture
+ minetest.register_node("testnodes:alpha_texture_"..alpha, {
+ description = S("Texture Alpha Test Node (@1)", alpha),
+ drawtype = "glasslike",
+ paramtype = "light",
+ tiles = {
+ "testnodes_alpha"..alpha..".png",
+ },
+ use_texture_alpha = true,
+
+ groups = { dig_immediate = 3 },
+ })
+
+ -- Transparency set via "alpha" parameter
+ minetest.register_node("testnodes:alpha_"..alpha, {
+ description = S("Alpha Test Node (@1)", alpha),
+ -- It seems that only the liquid drawtype supports the alpha parameter
+ drawtype = "liquid",
+ paramtype = "light",
+ tiles = {
+ "testnodes_alpha.png",
+ },
+ alpha = alpha,
+
+ groups = { dig_immediate = 3 },
+ })
+end
--- /dev/null
+# Pathfinder Tester
+
+Usage:
+
+Use the Pathfinder Tester tool (`testpathfinder:testpathfinder`).
+Here's how it works:
+
+* Place on node: Set destination position
+* Punch: Find path
+* Sneak+punch: Select pathfinding algorithm
+
+Information will be shown in chat. If a path was found, all waypoints
+will be shown for a few seconds.
+
+See `init.lua` for config variables.
--- /dev/null
+local S = minetest.get_translator("testpathfinder")
+
+-- Config parameters
+
+-- Maximum direct distance between start and end
+local MAX_DIRECT_DISTANCE = 64
+-- Maximum search distance
+local MAX_SEARCH_DISTANCE = 32
+-- Maximum permitted jump height
+local MAX_JUMP = 1
+-- Maximum permitted drop height
+local MAX_DROP = 5
+-- If true, mod won't refuse to run pathfinder even at long distances
+local IGNORE_MAX_DISTANCE_SAFEGUARD = false
+
+-- End of config parameters
+
+local timer = 0
+local algorithms = {
+ "A*_noprefetch",
+ "A*",
+ "Dijkstra",
+}
+
+local function find_path_for_player(player, itemstack)
+ local meta = itemstack:get_meta()
+ if not meta then
+ return
+ end
+ local x = meta:get_int("pos_x")
+ local y = meta:get_int("pos_y")
+ local z = meta:get_int("pos_z")
+ local algo = meta:get_int("algorithm")
+ if x and y and z then
+ local pos2 = {x=x, y=y, z=z}
+ algo = algorithms[algo+1]
+ local pos1 = vector.round(player:get_pos())
+ -- Don't bother calling pathfinder for high distance to avoid freezing
+ if (not IGNORE_MAX_DISTANCE_SAFEGUARD) and (vector.distance(pos1, pos2) > MAX_DIRECT_DISTANCE) then
+ minetest.chat_send_player(player:get_player_name(), S("Destination too far away! Set a destination (via placing) within a distance of @1 and try again!", MAX_DIRECT_DISTANCE))
+ return
+ end
+ local str = S("Path from @1 to @2:",
+ minetest.pos_to_string(pos1),
+ minetest.pos_to_string(pos2))
+
+ minetest.chat_send_player(player:get_player_name(), str)
+ local time_start = minetest.get_us_time()
+ local path = minetest.find_path(pos1, pos2, MAX_SEARCH_DISTANCE, MAX_JUMP, MAX_DROP, algo)
+ local time_end = minetest.get_us_time()
+ local time_diff = time_end - time_start
+ str = ""
+ if not path then
+ minetest.chat_send_player(player:get_player_name(), S("No path!"))
+ minetest.chat_send_player(player:get_player_name(), S("Time: @1 ms", time_diff/1000))
+ return
+ end
+ for s=1, #path do
+ str = str .. minetest.pos_to_string(path[s]) .. "\n"
+ local t
+ if s == #path then
+ t = "testpathfinder_waypoint_end.png"
+ elseif s == 1 then
+ t = "testpathfinder_waypoint_start.png"
+ else
+ local c = math.floor(((#path-s)/#path)*255)
+ t = string.format("testpathfinder_waypoint.png^[multiply:#%02x%02x00", 0xFF-c, c)
+ end
+ minetest.add_particle({
+ pos = path[s],
+ expirationtime = 5 + 0.2 * s,
+ playername = player:get_player_name(),
+ glow = minetest.LIGHT_MAX,
+ texture = t,
+ size = 3,
+ })
+ end
+ minetest.chat_send_player(player:get_player_name(), str)
+ minetest.chat_send_player(player:get_player_name(), S("Path length: @1", #path))
+ minetest.chat_send_player(player:get_player_name(), S("Time: @1 ms", time_diff/1000))
+ end
+end
+
+local function set_destination(itemstack, user, pointed_thing)
+ if not (user and user:is_player()) then
+ return
+ end
+ local name = user:get_player_name()
+ local obj
+ local meta = itemstack:get_meta()
+ if pointed_thing.type == "node" then
+ local pos = pointed_thing.above
+ meta:set_int("pos_x", pos.x)
+ meta:set_int("pos_y", pos.y)
+ meta:set_int("pos_z", pos.z)
+ minetest.chat_send_player(user:get_player_name(), S("Destination set to @1", minetest.pos_to_string(pos)))
+ return itemstack
+ end
+end
+
+local function find_path_or_set_algorithm(itemstack, user, pointed_thing)
+ if not (user and user:is_player()) then
+ return
+ end
+ local ctrl = user:get_player_control()
+ -- No sneak: Find path
+ if not ctrl.sneak then
+ find_path_for_player(user, itemstack)
+ else
+ -- Sneak: Set algorithm
+ local meta = itemstack:get_meta()
+ local algo = meta:get_int("algorithm")
+ algo = (algo + 1) % #algorithms
+ meta:set_int("algorithm", algo)
+ minetest.chat_send_player(user:get_player_name(), S("Algorithm: @1", algorithms[algo+1]))
+ return itemstack
+ end
+end
+
+-- Punch: Find path
+-- Sneak+punch: Select pathfinding algorithm
+-- Place: Select destination node
+minetest.register_tool("testpathfinder:testpathfinder", {
+ description = S("Pathfinder Tester"),
+ inventory_image = "testpathfinder_testpathfinder.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_use = find_path_or_set_algorithm,
+ on_secondary_use = set_destination,
+ on_place = set_destination,
+})
+
+
--- /dev/null
+name = testpathfinder
+description = Tool to test Minetest's pathfinder function
--- /dev/null
+# Test Tools readme
+
+Test Tools is a mod for developers that adds a bunch of tools to directly manipulate nodes and entities. This is great for quickly testing out stuff.
+
+Here's the list of tools:
+
+## Remover
+Removes nodes and non-player entities that you punch.
+
+## Node Setter
+Replace a node with another one.
+
+First, punch a node you want to remember.
+Then rightclick any other node to replace it with the node you remembered.
+
+If you rightclick while pointing nothing, you can manually enter the node and param2.
+
+## Param2 Tool
+Change the value param2 of nodes.
+
+* Punch: Add 1 to param2
+* Sneak+Punch: Add 8 to param2
+* Place: Subtract 1 from param2
+* Sneak+Place: Subtract 8 from param2
+
+Note: Use the debug screen (F5) to see the param2 of the pointed node.
+
+## Falling Node Tool
+Turns nodes into falling nodes.
+
+Usage:
+
+* Punch node: Make it fall
+* Place: Try to teleport up to 2 units upwards, then make it fall
+
+## Entity Rotator
+Changes the entity rotation (with `set_rotation`).
+
+Usage:
+
+* Punch entity: Rotate yaw
+* Punch entity while holding down “Sneak” key: Rotate pitch
+* Punch entity while holding down “Special” key (aka “Aux”): Rotate roll
+
+Each usage rotates the entity by 22.5°.
+
+## Entity Spawner
+Spawns entities.
+
+Usage:
+
+* Punch to select entity or spawn one directly
+* Place to place selected entity
+
+## Object Property Editor
+Edits properties of objects.
+
+Usage:
+
+* Punch object to open a formspec that allows you to view and edit properties
+* Punch air to edit properties of your own player object
+
+To edit a property, select it in the list, enter a new value (in Lua syntax)
+and hit “Submit”.
+
+## Object Attacher
+Allows you to attach an object to another one.
+
+Basic usage:
+* First select the parent object, then the child object that should be attached
+* Selecting an object is done by punching it
+* Sneak+punch to detach selected object
+* If you punch air, you select yourself
+
+Configuration:
+* Place: Increase attachment Y position
+* Sneak+place: decrease attachment Y position
+* Aux+place: Increase attachment X rotation
+* Aux+Sneak+Rightclick: Decrease attachment X rotation
+
+Hint: To detach all objects nearby you (including on yourself), use the
+`/detach` server command.
+
+## Object Mover
+Move an object by a given distance.
+
+Usage:
+* Punch object into the direction you want to move it
+* Sneak+punch: Move object towards you
+* Place: Increase move distance
+* Sneak+place: Decrease move distance
+
+## Entity Visual Scaler
+Change visual size of entities
+
+Usage:
+
+* Punch entity to increase visual size
+* Sneak+punch entity to decrease visual size
--- /dev/null
+local S = minetest.get_translator("testtools")
+local F = minetest.formspec_escape
+
+-- TODO: Add a Node Metadata tool
+
+-- Param 2 Tool: Set param2 value of tools
+-- Punch: +1
+-- Punch+Shift: +8
+-- Place: -1
+-- Place+Shift: -8
+minetest.register_tool("testtools:param2tool", {
+ description = S("Param2 Tool"),
+ inventory_image = "testtools_param2tool.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_use = function(itemstack, user, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing)
+ if pointed_thing.type ~= "node" or (not pos) then
+ return
+ end
+ local add = 1
+ if user then
+ local ctrl = user:get_player_control()
+ if ctrl.sneak then
+ add = 8
+ end
+ end
+ local node = minetest.get_node(pos)
+ node.param2 = node.param2 + add
+ minetest.swap_node(pos, node)
+ end,
+ on_place = function(itemstack, user, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing)
+ if pointed_thing.type ~= "node" or (not pos) then
+ return
+ end
+ local add = -1
+ if user then
+ local ctrl = user:get_player_control()
+ if ctrl.sneak then
+ add = -8
+ end
+ end
+ local node = minetest.get_node(pos)
+ node.param2 = node.param2 + add
+ minetest.swap_node(pos, node)
+ end,
+})
+
+minetest.register_tool("testtools:node_setter", {
+ description = S("Node Setter"),
+ inventory_image = "testtools_node_setter.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_use = function(itemstack, user, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing)
+ if pointed_thing.type == "nothing" then
+ local meta = itemstack:get_meta()
+ meta:set_string("node", "air")
+ meta:set_int("node_param2", 0)
+ if user and user:is_player() then
+ minetest.chat_send_player(user:get_player_name(), S("Now placing: @1 (param2=@2)", "air", 0))
+ end
+ return itemstack
+ elseif pointed_thing.type ~= "node" or (not pos) then
+ return
+ end
+ local node = minetest.get_node(pos)
+ local meta = itemstack:get_meta()
+ meta:set_string("node", node.name)
+ meta:set_int("node_param2", node.param2)
+ if user and user:is_player() then
+ minetest.chat_send_player(user:get_player_name(), S("Now placing: @1 (param2=@2)", node.name, node.param2))
+ end
+ return itemstack
+ end,
+ on_secondary_use = function(itemstack, user, pointed_thing)
+ local meta = itemstack:get_meta()
+ local nodename = meta:get_string("node") or ""
+ local param2 = meta:get_int("node_param2") or 0
+
+ minetest.show_formspec(user:get_player_name(), "testtools:node_setter",
+ "size[4,4]"..
+ "field[0.5,1;3,1;nodename;"..F(S("Node name (itemstring):"))..";"..F(nodename).."]"..
+ "field[0.5,2;3,1;param2;"..F(S("param2:"))..";"..F(tostring(param2)).."]"..
+ "button_exit[0.5,3;3,1;submit;"..F(S("Submit")).."]"
+ )
+ end,
+ on_place = function(itemstack, user, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing)
+ local meta = itemstack:get_meta()
+ local nodename = meta:get_string("node")
+ if nodename == "" and user and user:is_player() then
+ minetest.chat_send_player(user:get_player_name(), S("Punch a node first!"))
+ return
+ end
+ local param2 = meta:get_int("node_param2")
+ if not param2 then
+ param2 = 0
+ end
+ local node = { name = nodename, param2 = param2 }
+ if not minetest.registered_nodes[nodename] then
+ minetest.chat_send_player(user:get_player_name(), S("Cannot set unknown node: @1", nodename))
+ return
+ end
+ minetest.set_node(pos, node)
+ end,
+})
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ if formname == "testtools:node_setter" then
+ local playername = player:get_player_name()
+ local witem = player:get_wielded_item()
+ if witem:get_name() == "testtools:node_setter" then
+ if fields.nodename and fields.param2 then
+ local param2 = tonumber(fields.param2)
+ if not param2 then
+ return
+ end
+ local meta = witem:get_meta()
+ meta:set_string("node", fields.nodename)
+ meta:set_int("node_param2", param2)
+ player:set_wielded_item(witem)
+ end
+ end
+ end
+end)
+
+minetest.register_tool("testtools:remover", {
+ description = S("Remover"),
+ inventory_image = "testtools_remover.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_use = function(itemstack, user, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing)
+ if pointed_thing.type == "node" and pos ~= nil then
+ minetest.remove_node(pos)
+ elseif pointed_thing.type == "object" then
+ local obj = pointed_thing.ref
+ if not obj:is_player() then
+ obj:remove()
+ end
+ end
+ end,
+})
+
+minetest.register_tool("testtools:falling_node_tool", {
+ description = S("Falling Node Tool"),
+ inventory_image = "testtools_falling_node_tool.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_place = function(itemstack, user, pointed_thing)
+ -- Teleport node 1-2 units upwards (if possible) and make it fall
+ local pos = minetest.get_pointed_thing_position(pointed_thing)
+ if pointed_thing.type ~= "node" or (not pos) then
+ return
+ end
+ local ok = false
+ local highest
+ for i=1,2 do
+ local above = {x=pos.x,y=pos.y+i,z=pos.z}
+ local n2 = minetest.get_node(above)
+ local def2 = minetest.registered_nodes[n2.name]
+ if def2 and (not def2.walkable) then
+ highest = above
+ else
+ break
+ end
+ end
+ if highest then
+ local node = minetest.get_node(pos)
+ local metatable = minetest.get_meta(pos):to_table()
+ minetest.remove_node(pos)
+ minetest.set_node(highest, node)
+ local meta_highest = minetest.get_meta(highest)
+ meta_highest:from_table(metatable)
+ ok = minetest.spawn_falling_node(highest)
+ else
+ ok = minetest.spawn_falling_node(pos)
+ end
+ if not ok and user and user:is_player() then
+ minetest.chat_send_player(user:get_player_name(), S("Falling node could not be spawned!"))
+ end
+ end,
+ on_use = function(itemstack, user, pointed_thing)
+ local pos = minetest.get_pointed_thing_position(pointed_thing)
+ if pointed_thing.type ~= "node" or (not pos) then
+ return
+ end
+ local ok = minetest.spawn_falling_node(pos)
+ if not ok and user and user:is_player() then
+ minetest.chat_send_player(user:get_player_name(), S("Falling node could not be spawned!"))
+ end
+ end,
+})
+
+minetest.register_tool("testtools:rotator", {
+ description = S("Entity Rotator"),
+ inventory_image = "testtools_entity_rotator.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type ~= "object" then
+ return
+ end
+ local obj = pointed_thing.ref
+ if obj:is_player() then
+ -- No player rotation
+ return
+ else
+ local axis = "y"
+ if user and user:is_player() then
+ local ctrl = user:get_player_control()
+ if ctrl.sneak then
+ axis = "x"
+ elseif ctrl.aux1 then
+ axis = "z"
+ end
+ end
+ local rot = obj:get_rotation()
+ rot[axis] = rot[axis] + math.pi/8
+ if rot[axis] > math.pi*2 then
+ rot[axis] = rot[axis] - math.pi*2
+ end
+ obj:set_rotation(rot)
+ end
+ end,
+})
+
+local mover_config = function(itemstack, user, pointed_thing)
+ if not (user and user:is_player()) then
+ return
+ end
+ local name = user:get_player_name()
+ local ctrl = user:get_player_control()
+ local meta = itemstack:get_meta()
+ local dist = 1.0
+ if meta:contains("distance") then
+ dist = meta:get_int("distance")
+ end
+ if ctrl.sneak then
+ dist = dist - 1
+ else
+ dist = dist + 1
+ end
+ meta:set_int("distance", dist)
+ minetest.chat_send_player(user:get_player_name(), S("distance=@1/10", dist*2))
+ return itemstack
+end
+
+minetest.register_tool("testtools:object_mover", {
+ description = S("Object Mover"),
+ inventory_image = "testtools_object_mover.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_place = mover_config,
+ on_secondary_use = mover_config,
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type ~= "object" then
+ return
+ end
+ local obj = pointed_thing.ref
+ if not (user and user:is_player()) then
+ return
+ end
+ local yaw = user:get_look_horizontal()
+ local dir = minetest.yaw_to_dir(yaw)
+ local pos = obj:get_pos()
+ local pitch = user:get_look_vertical()
+ if pitch > 0.25 * math.pi then
+ dir.y = -1
+ dir.x = 0
+ dir.z = 0
+ elseif pitch < -0.25 * math.pi then
+ dir.y = 1
+ dir.x = 0
+ dir.z = 0
+ end
+ local ctrl = user:get_player_control()
+ if ctrl.sneak then
+ dir = vector.multiply(dir, -1)
+ end
+ local meta = itemstack:get_meta()
+ if meta:contains("distance") then
+ local dist = meta:get_int("distance")
+ dir = vector.multiply(dir, dist*0.2)
+ end
+ pos = vector.add(pos, dir)
+ obj:set_pos(pos)
+ end,
+})
+
+
+
+minetest.register_tool("testtools:entity_scaler", {
+ description = S("Entity Visual Scaler"),
+ inventory_image = "testtools_entity_scaler.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type ~= "object" then
+ return
+ end
+ local obj = pointed_thing.ref
+ if obj:is_player() then
+ -- No player scaling
+ return
+ else
+ local diff = 0.1
+ if user and user:is_player() then
+ local ctrl = user:get_player_control()
+ if ctrl.sneak then
+ diff = -0.1
+ end
+ end
+ local prop = obj:get_properties()
+ if not prop.visual_size then
+ prop.visual_size = { x=1, y=1, z=1 }
+ else
+ prop.visual_size = { x=prop.visual_size.x+diff, y=prop.visual_size.y+diff, z=prop.visual_size.z+diff }
+ if prop.visual_size.x <= 0.1 then
+ prop.visual_size.x = 0.1
+ end
+ if prop.visual_size.y <= 0.1 then
+ prop.visual_size.y = 0.1
+ end
+ if prop.visual_size.z <= 0.1 then
+ prop.visual_size.z = 0.1
+ end
+ end
+ obj:set_properties(prop)
+ end
+ end,
+})
+
+local selections = {}
+local entity_list
+local function get_entity_list()
+ if entity_list then
+ return entity_list
+ end
+ local ents = minetest.registered_entities
+ local list = {}
+ for k,_ in pairs(ents) do
+ table.insert(list, k)
+ end
+ table.sort(list)
+ entity_list = list
+ return entity_list
+end
+minetest.register_tool("testtools:entity_spawner", {
+ description = S("Entity Spawner"),
+ inventory_image = "testtools_entity_spawner.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_place = function(itemstack, user, pointed_thing)
+ local name = user:get_player_name()
+ if selections[name] and pointed_thing.type == "node" then
+ local pos = pointed_thing.above
+ minetest.add_entity(pos, get_entity_list()[selections[name]])
+ end
+ end,
+ on_use = function(itemstack, user, pointed_thing)
+ if pointed_thing.type == "object" then
+ return
+ end
+ if user and user:is_player() then
+ local list = table.concat(get_entity_list(), ",")
+ local name = user:get_player_name()
+ local sel = selections[name] or ""
+ minetest.show_formspec(name, "testtools:entity_list",
+ "size[9,9]"..
+ "textlist[0,0;9,8;entity_list;"..list..";"..sel..";false]"..
+ "button[0,8;4,1;spawn;Spawn entity]"
+ )
+ end
+ end,
+})
+
+local function prop_to_string(property)
+ if type(property) == "string" then
+ return "\"" .. property .. "\""
+ elseif type(property) == "table" then
+ return tostring(dump(property)):gsub("\n", "")
+ else
+ return tostring(property)
+ end
+end
+
+local property_formspec_data = {}
+local property_formspec_index = {}
+local selected_objects = {}
+local function get_object_properties_form(obj, playername)
+ if not playername then return "" end
+ local props = obj:get_properties()
+ local str = ""
+ property_formspec_data[playername] = {}
+ local proplist = {}
+ for k,_ in pairs(props) do
+ table.insert(proplist, k)
+ end
+ table.sort(proplist)
+ for p=1, #proplist do
+ local k = proplist[p]
+ local v = props[k]
+ local newline = ""
+ newline = k .. " = "
+ newline = newline .. prop_to_string(v)
+ str = str .. F(newline)
+ if p < #proplist then
+ str = str .. ","
+ end
+ table.insert(property_formspec_data[playername], k)
+ end
+ return str
+end
+
+local editor_formspec_selindex = {}
+
+local editor_formspec = function(playername, obj, value, sel)
+ if not value then
+ value = ""
+ end
+ if not sel then
+ sel = ""
+ end
+ local list = get_object_properties_form(obj, playername)
+ local title
+ if obj:is_player() then
+ title = S("Object properties of player “@1”", obj:get_player_name())
+ else
+ local ent = obj:get_luaentity()
+ title = S("Object properties of @1", ent.name)
+ end
+ minetest.show_formspec(playername, "testtools:object_editor",
+ "size[9,9]"..
+ "label[0,0;"..F(title).."]"..
+ "textlist[0,0.5;9,7.5;object_props;"..list..";"..sel..";false]"..
+ "field[0.2,8.75;8,1;value;"..F(S("Value"))..";"..F(value).."]"..
+ "button[8,8.5;1,1;submit;"..F(S("Submit")).."]"
+ )
+end
+
+minetest.register_tool("testtools:object_editor", {
+ description = S("Object Property Editor"),
+ inventory_image = "testtools_object_editor.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_use = function(itemstack, user, pointed_thing)
+ if user and user:is_player() then
+ local name = user:get_player_name()
+
+ if pointed_thing.type == "object" then
+ selected_objects[name] = pointed_thing.ref
+ elseif pointed_thing.type == "nothing" then
+ -- Use on yourself if pointing nothing
+ selected_objects[name] = user
+ else
+ -- Unsupported pointed thing
+ return
+ end
+
+ local sel = editor_formspec_selindex[name]
+ local val
+ if selected_objects[name] and selected_objects[name]:get_properties() then
+ local props = selected_objects[name]:get_properties()
+ local keys = property_formspec_data[name]
+ if property_formspec_index[name] and props then
+ local key = keys[property_formspec_index[name]]
+ val = prop_to_string(props[key])
+ end
+ end
+
+ editor_formspec(name, selected_objects[name], val, sel)
+ end
+ end,
+})
+
+local ent_parent = {}
+local ent_child = {}
+local DEFAULT_ATTACH_OFFSET_Y = 11
+
+local attacher_config = function(itemstack, user, pointed_thing)
+ if not (user and user:is_player()) then
+ return
+ end
+ if pointed_thing.type == "object" then
+ return
+ end
+ local name = user:get_player_name()
+ local ctrl = user:get_player_control()
+ local meta = itemstack:get_meta()
+ if ctrl.aux1 then
+ local rot_x = meta:get_float("rot_x")
+ if ctrl.sneak then
+ rot_x = rot_x - math.pi/8
+ else
+ rot_x = rot_x + math.pi/8
+ end
+ if rot_x > 6.2 then
+ rot_x = 0
+ elseif rot_x < 0 then
+ rot_x = math.pi * (15/8)
+ end
+ minetest.chat_send_player(name, S("rotation=@1", minetest.pos_to_string({x=rot_x,y=0,z=0})))
+ meta:set_float("rot_x", rot_x)
+ else
+ local pos_y
+ if meta:contains("pos_y") then
+ pos_y = meta:get_int("pos_y")
+ else
+ pos_y = DEFAULT_ATTACH_OFFSET_Y
+ end
+ if ctrl.sneak then
+ pos_y = pos_y - 1
+ else
+ pos_y = pos_y + 1
+ end
+ minetest.chat_send_player(name, S("position=@1", minetest.pos_to_string({x=0,y=pos_y,z=0})))
+ meta:set_int("pos_y", pos_y)
+ end
+ return itemstack
+end
+
+minetest.register_tool("testtools:object_attacher", {
+ description = S("Object Attacher"),
+ inventory_image = "testtools_object_attacher.png",
+ groups = { testtool = 1, disable_repair = 1 },
+ on_place = attacher_config,
+ on_secondary_use = attacher_config,
+ on_use = function(itemstack, user, pointed_thing)
+ if user and user:is_player() then
+ local name = user:get_player_name()
+ local selected_object
+ if pointed_thing.type == "object" then
+ selected_object = pointed_thing.ref
+ elseif pointed_thing.type == "nothing" then
+ selected_object = user
+ else
+ return
+ end
+ local ctrl = user:get_player_control()
+ if ctrl.sneak then
+ if selected_object:get_attach() then
+ selected_object:set_detach()
+ minetest.chat_send_player(name, S("Object detached!"))
+ else
+ minetest.chat_send_player(name, S("Object is not attached!"))
+ end
+ return
+ end
+ local parent = ent_parent[name]
+ local child = ent_child[name]
+ local ename = S("<unknown>")
+ if not parent then
+ parent = selected_object
+ ent_parent[name] = parent
+ elseif not child then
+ child = selected_object
+ ent_child[name] = child
+ end
+ local entity = selected_object:get_luaentity()
+ if entity then
+ ename = entity.name
+ elseif selected_object:is_player() then
+ ename = selected_object:get_player_name()
+ end
+ if selected_object == parent then
+ minetest.chat_send_player(name, S("Parent object selected: @1", ename))
+ elseif selected_object == child then
+ minetest.chat_send_player(name, S("Child object selected: @1", ename))
+ end
+ if parent and child then
+ if parent == child then
+ minetest.chat_send_player(name, S("Can't attach an object to itself!"))
+ ent_parent[name] = nil
+ ent_child[name] = nil
+ return
+ end
+ local meta = itemstack:get_meta()
+ local y
+ if meta:contains("pos_y") then
+ y = meta:get_int("pos_y")
+ else
+ y = DEFAULT_ATTACH_OFFSET_Y
+ end
+ local rx = meta:get_float("rot_x") or 0
+ local offset = {x=0,y=y,z=0}
+ local angle = {x=rx,y=0,z=0}
+ child:set_attach(parent, "", offset, angle)
+ local check_parent = child:get_attach()
+ if check_parent then
+ minetest.chat_send_player(name, S("Object attached! position=@1, rotation=@2",
+ minetest.pos_to_string(offset), minetest.pos_to_string(angle)))
+ else
+ minetest.chat_send_player(name, S("Attachment failed!"))
+ end
+ ent_parent[name] = nil
+ ent_child[name] = nil
+ end
+ end
+ end,
+})
+
+-- Use loadstring to parse param as a Lua value
+local function use_loadstring(param, player)
+ -- For security reasons, require 'server' priv, just in case
+ -- someone is actually crazy enough to run this on a public server.
+ local privs = minetest.get_player_privs(player:get_player_name())
+ if not privs.server then
+ return false, "You need 'server' privilege to change object properties!"
+ end
+ if not param then
+ return false, "Failed: parameter is nil"
+ end
+ --[[ DANGER ZONE ]]
+ -- Interpret string as Lua value
+ local func, errormsg = loadstring("return (" .. param .. ")")
+ if not func then
+ return false, "Failed: " .. errormsg
+ end
+
+ -- Apply sandbox here using setfenv
+ setfenv(func, {})
+
+ -- Run it
+ local good, errOrResult = pcall(func)
+ if not good then
+ -- A Lua error was thrown
+ return false, "Failed: " .. errOrResult
+ end
+
+ -- errOrResult will be the value
+ return true, errOrResult
+end
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ if not (player and player:is_player()) then
+ return
+ end
+ if formname == "testtools:entity_list" then
+ local name = player:get_player_name()
+ if fields.entity_list then
+ local expl = minetest.explode_textlist_event(fields.entity_list)
+ if expl.type == "DCL" then
+ local pos = vector.add(player:get_pos(), {x=0,y=1,z=0})
+ selections[name] = expl.index
+ minetest.add_entity(pos, get_entity_list()[expl.index])
+ return
+ elseif expl.type == "CHG" then
+ selections[name] = expl.index
+ return
+ end
+ elseif fields.spawn and selections[name] then
+ local pos = vector.add(player:get_pos(), {x=0,y=1,z=0})
+ minetest.add_entity(pos, get_entity_list()[selections[name]])
+ return
+ end
+ elseif formname == "testtools:object_editor" then
+ local name = player:get_player_name()
+ if fields.object_props then
+ local expl = minetest.explode_textlist_event(fields.object_props)
+ if expl.type == "DCL" or expl.type == "CHG" then
+ property_formspec_index[name] = expl.index
+
+ local props = selected_objects[name]:get_properties()
+ local keys = property_formspec_data[name]
+ if (not property_formspec_index[name]) or (not props) then
+ return
+ end
+ local key = keys[property_formspec_index[name]]
+ editor_formspec_selindex[name] = expl.index
+ editor_formspec(name, selected_objects[name], prop_to_string(props[key]), expl.index)
+ return
+ end
+ end
+ if fields.submit then
+ local props = selected_objects[name]:get_properties()
+ local keys = property_formspec_data[name]
+ if (not property_formspec_index[name]) or (not props) then
+ return
+ end
+ local key = keys[property_formspec_index[name]]
+ if not key then
+ return
+ end
+ local success, str = use_loadstring(fields.value, player)
+ if success then
+ props[key] = str
+ else
+ minetest.chat_send_player(name, str)
+ return
+ end
+ selected_objects[name]:set_properties(props)
+ local sel = editor_formspec_selindex[name]
+ editor_formspec(name, selected_objects[name], prop_to_string(props[key]), sel)
+ return
+ end
+ end
+end)
--- /dev/null
+name = testtools
+description = Some tools to directly manipulate nodes and entities. Great for development and testing
--- /dev/null
+minetest.register_node("tiled:tiled", {
+ description = "Tiled Node (world-aligned)",
+ tiles = {{
+ name = "tiled_tiled.png",
+ align_style = "world",
+ scale = 8,
+ }},
+ groups = {cracky=3},
+})
+
+minetest.register_node("tiled:tiled_n", {
+ description = "Tiled Node (node-aligned)",
+ tiles = {{
+ name = "tiled_tiled.png",
+ align_style = "node",
+ scale = 8,
+ }},
+ groups = {cracky=3},
+})
+
+stairs.register_stair_and_slab("tiled_n", "tiled:tiled",
+ {cracky=3},
+ {{name="tiled_tiled.png", align_style="node", scale=8}},
+ "Tiled Stair (node-aligned)",
+ "Tiled Slab (node-aligned)")
+
+stairs.register_stair_and_slab("tiled", "tiled:tiled",
+ {cracky=3},
+ {{name="tiled_tiled.png", align_style="world", scale=8}},
+ "Tiled Stair (world-aligned)",
+ "Tiled Slab (world-aligned)")
+
+
--- /dev/null
+name = tiled
+description = Add nodes with a special texture that spans multiple nodes (aka "world-aligned")
+depends = stairs
--- /dev/null
+-- Test minetest.clear_craft function
+local function test_clear_craft()
+ minetest.log("info", "[unittests] Testing minetest.clear_craft")
+ -- Clearing by output
+ minetest.register_craft({
+ output = "foo",
+ recipe = {{"bar"}}
+ })
+ minetest.register_craft({
+ output = "foo 4",
+ recipe = {{"foo", "bar"}}
+ })
+ assert(#minetest.get_all_craft_recipes("foo") == 2)
+ minetest.clear_craft({output="foo"})
+ assert(minetest.get_all_craft_recipes("foo") == nil)
+ -- Clearing by input
+ minetest.register_craft({
+ output = "foo 4",
+ recipe = {{"foo", "bar"}}
+ })
+ assert(#minetest.get_all_craft_recipes("foo") == 1)
+ minetest.clear_craft({recipe={{"foo", "bar"}}})
+ assert(minetest.get_all_craft_recipes("foo") == nil)
+end
+
+-- Test minetest.get_craft_result function
+local function test_get_craft_result()
+ minetest.log("info", "[unittests] Testing minetest.get_craft_result")
+
+ -- normal
+ local input = {
+ method = "normal",
+ width = 2,
+ items = {"", "unittests:coal_lump", "", "unittests:stick"}
+ }
+ minetest.log("info", "[unittests] torch crafting input: "..dump(input))
+ local output, decremented_input = minetest.get_craft_result(input)
+ minetest.log("info", "[unittests] torch crafting output: "..dump(output))
+ minetest.log("info", "[unittests] torch crafting decremented input: "..dump(decremented_input))
+ assert(output.item)
+ minetest.log("info", "[unittests] torch crafting output.item:to_table(): "..dump(output.item:to_table()))
+ assert(output.item:get_name() == "unittests:torch")
+ assert(output.item:get_count() == 4)
+
+ -- fuel
+ input = {
+ method = "fuel",
+ width = 1,
+ items = {"unittests:coal_lump"}
+ }
+ minetest.log("info", "[unittests] coal fuel input: "..dump(input))
+ output, decremented_input = minetest.get_craft_result(input)
+ minetest.log("info", "[unittests] coal fuel output: "..dump(output))
+ minetest.log("info", "[unittests] coal fuel decremented input: "..dump(decremented_input))
+ assert(output.time)
+ assert(output.time > 0)
+
+ -- cooking
+ input = {
+ method = "cooking",
+ width = 1,
+ items = {"unittests:iron_lump"}
+ }
+ minetest.log("info", "[unittests] iron lump cooking input: "..dump(output))
+ output, decremented_input = minetest.get_craft_result(input)
+ minetest.log("info", "[unittests] iron lump cooking output: "..dump(output))
+ minetest.log("info", "[unittests] iron lump cooking decremented input: "..dump(decremented_input))
+ assert(output.time)
+ assert(output.time > 0)
+ assert(output.item)
+ minetest.log("info", "[unittests] iron lump cooking output.item:to_table(): "..dump(output.item:to_table()))
+ assert(output.item:get_name() == "unittests:steel_ingot")
+ assert(output.item:get_count() == 1)
+
+ -- tool repair (repairable)
+ input = {
+ method = "normal",
+ width = 2,
+ -- Using a wear of 60000
+ items = {"unittests:repairable_tool 1 60000", "unittests:repairable_tool 1 60000"}
+ }
+ minetest.log("info", "[unittests] repairable tool crafting input: "..dump(input))
+ output, decremented_input = minetest.get_craft_result(input)
+ minetest.log("info", "[unittests] repairable tool crafting output: "..dump(output))
+ minetest.log("info", "[unittests] repairable tool crafting decremented input: "..dump(decremented_input))
+ assert(output.item)
+ minetest.log("info", "[unittests] repairable tool crafting output.item:to_table(): "..dump(output.item:to_table()))
+ assert(output.item:get_name() == "unittests:repairable_tool")
+ -- Test the wear value.
+ -- See src/craftdef.cpp in Minetest source code for the formula. The formula to calculate
+ -- the value 51187 is:
+ -- 65536 - ((65536-60000)+(65536-60000)) + floor(additonal_wear * 65536 + 0.5) = 51187
+ -- where additional_wear = 0.05
+ assert(output.item:get_wear() == 51187)
+ assert(output.item:get_count() == 1)
+
+ -- failing tool repair (unrepairable)
+ input = {
+ method = "normal",
+ width = 2,
+ items = {"unittests:unrepairable_tool 1 60000", "unittests:unrepairable_tool 1 60000"}
+ }
+ minetest.log("info", "[unittests] unrepairable tool crafting input: "..dump(input))
+ output, decremented_input = minetest.get_craft_result(input)
+ minetest.log("info", "[unittests] unrepairable tool crafting output: "..dump(output))
+ minetest.log("info", "[unittests] unrepairable tool crafting decremented input: "..dump(decremented_input))
+ assert(output.item)
+ minetest.log("info", "[unittests] unrepairable tool crafting output.item:to_table(): "..dump(output.item:to_table()))
+ -- unrepairable tool must not yield any output
+ assert(output.item:get_name() == "")
+
+end
+
+function unittests.test_crafting()
+ test_clear_craft()
+ test_get_craft_result()
+ minetest.log("action", "[unittests] Crafting tests passed!")
+ return true
+end
+
--- /dev/null
+-- Registering some dummy items and recipes for the crafting tests
+
+minetest.register_craftitem("unittests:torch", {
+ description = "Crafting Test Item: Torch",
+ inventory_image = "unittests_torch.png",
+
+ groups = { dummy = 1 },
+})
+minetest.register_craftitem("unittests:coal_lump", {
+ description = "Crafting Test Item: Coal Lump",
+ inventory_image = "unittests_coal_lump.png",
+
+ groups = { dummy = 1 },
+})
+minetest.register_craftitem("unittests:stick", {
+ description = "Crafting Test Item: Stick",
+ inventory_image = "unittests_stick.png",
+
+ groups = { dummy = 1 },
+})
+minetest.register_craftitem("unittests:iron_lump", {
+ description = "Crafting Test Item: Iron Lump",
+ inventory_image = "unittests_iron_lump.png",
+
+ groups = { dummy = 1 },
+})
+minetest.register_craftitem("unittests:steel_ingot", {
+ description = "Crafting Test Item: Steel Ingot",
+ inventory_image = "unittests_steel_ingot.png",
+
+ groups = { dummy = 1 },
+})
+
+-- Recipes for tests: Normal crafting, cooking and fuel
+
+minetest.register_craft({
+ output = 'unittests:torch 4',
+ recipe = {
+ {'unittests:coal_lump'},
+ {'unittests:stick'},
+ }
+})
+
+minetest.register_craft({
+ type = "cooking",
+ output = "unittests:steel_ingot",
+ recipe = "unittests:iron_lump",
+})
+
+minetest.register_craft({
+ type = "fuel",
+ recipe = "unittests:coal_lump",
+ burntime = 40,
+})
+
+-- Test tool repair
+minetest.register_craft({
+ type = "toolrepair",
+ additional_wear = -0.05,
+})
+
+-- Test the disable_repair=1 group
+minetest.register_tool("unittests:unrepairable_tool", {
+ description = "Crafting Test Item: Unrepairable Tool",
+ inventory_image = "unittests_unrepairable_tool.png",
+ tool_capabilities = {
+ groupcaps = {
+ cracky = {
+ times = {3, 2, 1},
+ }
+ }
+ },
+ groups = { disable_repair = 1, dummy = 1 }
+})
+
+minetest.register_tool("unittests:repairable_tool", {
+ description = "Crafting Test Item: Repairable Tool",
+ inventory_image = "unittests_repairable_tool.png",
+ tool_capabilities = {
+ groupcaps = {
+ cracky = {
+ times = {3, 2, 1},
+ }
+ }
+ },
+
+ groups = { dummy = 1 },
+})
--- /dev/null
+unittests = {}
+
+local modpath = minetest.get_modpath("unittests")
+dofile(modpath .. "/random.lua")
+dofile(modpath .. "/player.lua")
+dofile(modpath .. "/crafting_prepare.lua")
+dofile(modpath .. "/crafting.lua")
+
+if minetest.settings:get_bool("devtest_unittests_autostart", false) then
+ unittests.test_random()
+ unittests.test_crafting()
+ minetest.register_on_joinplayer(function(player)
+ unittests.test_player(player)
+ end)
+end
+
--- /dev/null
+name = unittests
+description = Adds automated unit tests for the engine
--- /dev/null
+--
+-- HP Change Reasons
+--
+local expect = nil
+local function run_hpchangereason_tests(player)
+ expect = { type = "set_hp", from = "mod" }
+ player:set_hp(3)
+ assert(expect == nil)
+
+ expect = { a = 234, type = "set_hp", from = "mod" }
+ player:set_hp(7, { a= 234 })
+ assert(expect == nil)
+
+ expect = { df = 3458973454, type = "fall", from = "mod" }
+ player:set_hp(10, { type = "fall", df = 3458973454 })
+ assert(expect == nil)
+
+ player:set_hp(20)
+end
+
+local function run_player_meta_tests(player)
+ local meta = player:get_meta()
+ meta:set_string("foo", "bar")
+ assert(meta:contains("foo"))
+ assert(meta:get_string("foo") == "bar")
+ assert(meta:get("foo") == "bar")
+
+ local meta2 = player:get_meta()
+ assert(meta2:get_string("foo") == "bar")
+ assert(meta2:get("foo") == "bar")
+ assert(meta:equals(meta2))
+
+ meta:set_string("bob", "dillan")
+ assert(meta:get_string("foo") == "bar")
+ assert(meta:get_string("bob") == "dillan")
+ assert(meta:get("bob") == "dillan")
+ assert(meta2:get_string("foo") == "bar")
+ assert(meta2:get_string("bob") == "dillan")
+ assert(meta2:get("bob") == "dillan")
+ assert(meta:equals(meta2))
+
+ meta:set_string("foo", "")
+ assert(not meta:contains("foo"))
+ assert(meta:get("foo") == nil)
+ assert(meta:get_string("foo") == "")
+ assert(meta:equals(meta2))
+end
+
+function unittests.test_player(player)
+ minetest.register_on_player_hpchange(function(player, hp, reason)
+ if not expect then
+ return
+ end
+
+ for key, value in pairs(reason) do
+ assert(expect[key] == value)
+ end
+
+ for key, value in pairs(expect) do
+ assert(reason[key] == value)
+ end
+
+ expect = nil
+ end)
+
+ run_hpchangereason_tests(player)
+ run_player_meta_tests(player)
+ local msg = "Player tests passed for player '"..player:get_player_name().."'!"
+ minetest.chat_send_all(msg)
+ minetest.log("action", "[unittests] "..msg)
+ return true
+end
+
--- /dev/null
+function unittests.test_random()
+ -- Try out PseudoRandom
+ minetest.log("action", "[unittests] Testing PseudoRandom ...")
+ local pseudo = PseudoRandom(13)
+ assert(pseudo:next() == 22290)
+ assert(pseudo:next() == 13854)
+ minetest.log("action", "[unittests] PseudoRandom test passed!")
+ return true
+end
+
--- /dev/null
+minetest.register_chatcommand("hotbar", {
+ params = "<size>",
+ description = "Set hotbar size",
+ func = function(name, param)
+ local player = minetest.get_player_by_name(name)
+ if not player then
+ return false, "No player."
+ end
+ local size = tonumber(param)
+ if not size then
+ return false, "Missing or incorrect size parameter!"
+ end
+ local ok = player:hud_set_hotbar_itemcount(size)
+ if ok then
+ return true
+ else
+ return false, "Invalid item count!"
+ end
+ end,
+})
+
+minetest.register_chatcommand("hp", {
+ params = "<hp>",
+ description = "Set your health",
+ func = function(name, param)
+ local player = minetest.get_player_by_name(name)
+ if not player then
+ return false, "No player."
+ end
+ local hp = tonumber(param)
+ if not hp then
+ return false, "Missing or incorrect hp parameter!"
+ end
+ player:set_hp(hp)
+ return true
+ end,
+})
+
+minetest.register_chatcommand("zoom", {
+ params = "[<zoom_fov>]",
+ description = "Set or display your zoom_fov",
+ func = function(name, param)
+ local player = minetest.get_player_by_name(name)
+ if not player then
+ return false, "No player."
+ end
+ if param == "" then
+ local fov = player:get_properties().zoom_fov
+ return true, "zoom_fov = "..tostring(fov)
+ end
+ local fov = tonumber(param)
+ if not fov then
+ return false, "Missing or incorrect zoom_fov parameter!"
+ end
+ player:set_properties({zoom_fov = fov})
+ fov = player:get_properties().zoom_fov
+ return true, "zoom_fov = "..tostring(fov)
+ end,
+})
+
+
+
+local s_infplace = minetest.settings:get("devtest_infplace")
+if s_infplace == "true" then
+ infplace = true
+elseif s_infplace == "false" then
+ infplace = false
+else
+ infplace = minetest.settings:get_bool("creative_mode", false)
+end
+
+minetest.register_chatcommand("infplace", {
+ params = "",
+ description = "Toggle infinite node placement",
+ func = function(name, param)
+ infplace = not infplace
+ if infplace then
+ minetest.chat_send_all("Infinite node placement enabled!")
+ minetest.log("action", "Infinite node placement enabled")
+ else
+ minetest.chat_send_all("Infinite node placement disabled!")
+ minetest.log("action", "Infinite node placement disabled")
+ end
+ return true
+ end,
+})
+
+minetest.register_chatcommand("detach", {
+ params = "[<radius>]",
+ description = "Detach all objects nearby",
+ func = function(name, param)
+ local radius = tonumber(param)
+ if type(radius) ~= "number" then
+ radius = 8
+ end
+ if radius < 1 then
+ radius = 1
+ end
+ local player = minetest.get_player_by_name(name)
+ if not player then
+ return false, "No player."
+ end
+ local objs = minetest.get_objects_inside_radius(player:get_pos(), radius)
+ local num = 0
+ for o=1, #objs do
+ if objs[o]:get_attach() then
+ objs[o]:set_detach()
+ num = num + 1
+ end
+ end
+ return true, string.format("%d object(s) detached.", num)
+ end,
+})
+
+
+-- Unlimited node placement
+minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack)
+ if placer and placer:is_player() then
+ return infplace
+ end
+end)
+
+-- Don't pick up if the item is already in the inventory
+local old_handle_node_drops = minetest.handle_node_drops
+function minetest.handle_node_drops(pos, drops, digger)
+ if not digger or not digger:is_player() or not infplace then
+ return old_handle_node_drops(pos, drops, digger)
+ end
+ local inv = digger:get_inventory()
+ if inv then
+ for _, item in ipairs(drops) do
+ if not inv:contains_item("main", item, true) then
+ inv:add_item("main", item)
+ end
+ end
+ end
+end
--- /dev/null
+name = util_commands
+description = Random server commands to make testing easier and more convenient
--- /dev/null
+# If enabled, nodes won't be used up when placed.
+# Note: This behavior can also be toggled in-game with the /infplace command.
+#
+# - true: enabled
+# - false: disabled
+# - auto: only enabled when Creative Mode is enabled (default)
+devtest_infplace (Infinite node placement) enum auto true,false,auto
+
+# If enabled, new players receive some initial items when joining for the first time.
+give_initial_stuff (Give initial stuff) bool true
+
+# If enabled, automated tests of the Lua API such as player health, crafting and PseudoRandom will be performed on startup.
+devtest_unittests_autostart (Perform unit tests) bool false
+
+# If enabled, the game will use all mapgen aliases for the v6 mapgen.
+# If disabled, it will only use a minimal set of mapgen aliases.
+# If enabled, there should be biome-specific tree, leaves and ground nodes. If disabled, stuff should use fallback nodes (like stone instead of desert stone).
+#
+# Many mapgen aliases have fallback values when no value is provided. Having this setting disabled can be useful to test whether those fallback values are functional.
+devtest_v6_mapgen_aliases (Use all v6 mapgen aliases) bool false
+
+# If enabled, the game will use dungeon stairs by enabling the corresponding mapgen aliases.
+#
+# Disabling this setting can be useful to test whether dungeons still work when stairs are not defined.
+devtest_dungeon_stairs (Generate dungeon stairs) bool false
+
+# If enabled, the mapgen alias 'mapgen_mossycobble' will be used. This should enable random mossy cobblestone in dungeons.
+# If disabled, it won't be used. The engine should fall back to cobble instead.
+devtest_dungeon_mossycobble (Generate mossy cobblestone) bool false
+
+# If enabled, some very basic biomes will be registered.
+devtest_register_biomes (Register biomes) bool true
+
+# If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
+# This is due to <https://github.com/minetest/minetest/issues/9209>.
+# This is only added to make the items more visible to avoid confusion, but you will no longer see the default inventory images for these items. When you want to test the default inventory image of drawtypes, this should be turned off.
+testnodes_show_fallback_image (Use fallback inventory images) bool false
+++ /dev/null
-License information for Developer Test
---------------------------------------
-
-The same license as for Minetest applies.
+++ /dev/null
-# Minimal development test
-
-This is a basic testing environment that contains a bunch of things to test the engine, but it could also be used as a minimal testbed for testing out mods.
-
-## Features
-
-* Basic nodes for mapgen
-* Basic, minimal map generator
-* Lots of example nodes for testing drawtypes, param2, light level, and many other node properties
-* Example entities
-* Other example items
-* Formspec test (via `/test_formspec` command)
-* Automated unit tests (disabled by default)
-* Tools for manipulating nodes and entities, like the "Param2 Tool"
-
-## Getting started
-
-Basically, just create a world and start. A few important things to note:
-
-* Items are gotten from the “Chest of Everything” (`chest_of_everything:chest`)
-* When you lost your initial items, type in `/stuff` command to get them back
-* By default, Creative Mode activates infinite node placement. This behavior can be changed with the `devtest_infplace` setting
-* Use the `/infplace` command to toggle infinite node placement in-game
-* Use the Param2 Tool to change the param2 of nodes; it's useful to experiment with the various drawtype test nodes
-* Check out the game settings and server commands for additional tests and features
-* Creative Mode does nothing (apart from default engine behavior)
-
-Confused by a certain node or item? Check out for inline code comments.
-
-### Example tests
-
-* You can use this to test what happens if a player is simultaneously in 2 nodes with `damage_per_second` but with a different value.
-* Or use the Falling Node Tool on various test nodes to see how they behave when falling.
-* You could also use this as a testbed for dependency-free mods, e.g. to test out how your formspecs behave without theming.
-
-## Random notes
-
-* Experimental/strange/unstructured tests can be found in the `experimental` mod
-* Textures of drawtype test nodes have a red dot at the top left corner. This is to see whether the textures are oriented properly
-
-## Design philosophy
-
-This should loosely follow the following principles:
-
-* Engine testing: The main focus of this is to aid testing of *engine* features, such as mapgen or node drawtypes
-* Mod testing: The secondary focus is to help modders as well, either as a minimal testbed for mods or even as a code example
-* Minimal interference: Under default settings, it shall not interfere with APIs except on explicit user wish. Non-trivial tests and features need to be enabled by a setting first
-* Convenience: Have various tools to make usage easier and more convenient
-* Reproducing engine bugs: When an engine bug was found, consider creating a test case
-* Clarity: Textures and names need to be designed to keep different things clearly visually apart at a glance
-* Low loading time: It must load blazing-fast so stuff can be tested quickly
-
+++ /dev/null
-name = Minimal development test
-description = Testing environment to help with testing the engine features of Minetest. It can also be helpful in mod development.
+++ /dev/null
-local WATER_ALPHA = 160
-local WATER_VISC = 1
-local LAVA_VISC = 7
-
---
--- Node definitions
---
-
--- Register nodes
-
-minetest.register_node("basenodes:stone", {
- description = "Stone",
- tiles = {"default_stone.png"},
- groups = {cracky=3},
-})
-
-minetest.register_node("basenodes:desert_stone", {
- description = "Desert Stone",
- tiles = {"default_desert_stone.png"},
- groups = {cracky=3},
-})
-
-minetest.register_node("basenodes:dirt_with_grass", {
- description = "Dirt with Grass",
- tiles ={"default_grass.png",
- -- a little dot on the bottom to distinguish it from dirt
- "default_dirt.png^basenodes_dirt_with_grass_bottom.png",
- {name = "default_dirt.png^default_grass_side.png",
- tileable_vertical = false}},
- groups = {crumbly=3, soil=1},
-})
-
-minetest.register_node("basenodes:dirt_with_snow", {
- description = "Dirt with Snow",
- tiles ={"basenodes_dirt_with_snow.png",
- -- a little dot on the bottom to distinguish it from dirt
- "default_dirt.png^basenodes_dirt_with_snow_bottom.png",
- {name = "default_dirt.png^default_snow_side.png",
- tileable_vertical = false}},
- groups = {crumbly=3, soil=1},
-})
-
-minetest.register_node("basenodes:dirt", {
- description = "Dirt",
- tiles ={"default_dirt.png"},
- groups = {crumbly=3, soil=1},
-})
-
-minetest.register_node("basenodes:sand", {
- description = "Sand",
- tiles ={"default_sand.png"},
- groups = {crumbly=3},
-})
-
-minetest.register_node("basenodes:desert_sand", {
- description = "Desert Sand",
- tiles ={"default_desert_sand.png"},
- groups = {crumbly=3},
-})
-
-minetest.register_node("basenodes:gravel", {
- description = "Gravel",
- tiles ={"default_gravel.png"},
- groups = {crumbly=2},
-})
-
-minetest.register_node("basenodes:junglegrass", {
- description = "Jungle Grass",
- drawtype = "plantlike",
- tiles ={"default_junglegrass.png"},
- inventory_image = "default_junglegrass.png",
- wield_image = "default_junglegrass.png",
- paramtype = "light",
- walkable = false,
- groups = {snappy=3},
-})
-
-minetest.register_node("basenodes:tree", {
- description = "Normal Tree Trunk",
- tiles = {"default_tree_top.png", "default_tree_top.png", "default_tree.png"},
- is_ground_content = false,
- groups = {choppy=2,oddly_breakable_by_hand=1},
-})
-
-minetest.register_node("basenodes:leaves", {
- description = "Normal Leaves",
- drawtype = "allfaces_optional",
- tiles = {"default_leaves.png"},
- paramtype = "light",
- is_ground_content = false,
- groups = {snappy=3},
-})
-
-minetest.register_node("basenodes:jungletree", {
- description = "Jungle Tree Trunk",
- tiles = {"default_jungletree_top.png", "default_jungletree_top.png", "default_jungletree.png"},
- is_ground_content = false,
- groups = {choppy=2,oddly_breakable_by_hand=1},
-})
-
-minetest.register_node("basenodes:jungleleaves", {
- description = "Jungle Leaves",
- drawtype = "allfaces_optional",
- tiles = {"default_jungleleaves.png"},
- paramtype = "light",
- is_ground_content = false,
- groups = {snappy=3},
-})
-
-minetest.register_node("basenodes:pine_tree", {
- description = "Pine Tree Trunk",
- tiles = {"default_pine_tree_top.png", "default_pine_tree_top.png", "default_pine_tree.png"},
- is_ground_content = false,
- groups = {choppy=2,oddly_breakable_by_hand=1},
-})
-
-minetest.register_node("basenodes:pine_needles", {
- description = "Pine Needles",
- drawtype = "allfaces_optional",
- tiles = {"default_pine_needles.png"},
- paramtype = "light",
- is_ground_content = false,
- groups = {snappy=3},
-})
-
-minetest.register_node("basenodes:water_source", {
- description = "Water Source",
- drawtype = "liquid",
- tiles = {"default_water.png"},
- special_tiles = {
- {name = "default_water.png", backface_culling = false},
- {name = "default_water.png", backface_culling = true},
- },
- alpha = WATER_ALPHA,
- paramtype = "light",
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- drowning = 1,
- liquidtype = "source",
- liquid_alternative_flowing = "basenodes:water_flowing",
- liquid_alternative_source = "basenodes:water_source",
- liquid_viscosity = WATER_VISC,
- post_effect_color = {a = 64, r = 100, g = 100, b = 200},
- groups = {water = 3, liquid = 3},
-})
-
-minetest.register_node("basenodes:water_flowing", {
- description = "Flowing Water",
- drawtype = "flowingliquid",
- tiles = {"default_water_flowing.png"},
- special_tiles = {
- {name = "default_water_flowing.png", backface_culling = false},
- {name = "default_water_flowing.png", backface_culling = false},
- },
- alpha = WATER_ALPHA,
- paramtype = "light",
- paramtype2 = "flowingliquid",
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- drowning = 1,
- liquidtype = "flowing",
- liquid_alternative_flowing = "basenodes:water_flowing",
- liquid_alternative_source = "basenodes:water_source",
- liquid_viscosity = WATER_VISC,
- post_effect_color = {a = 64, r = 100, g = 100, b = 200},
- groups = {water = 3, liquid = 3},
-})
-
-minetest.register_node("basenodes:river_water_source", {
- description = "River Water Source",
- drawtype = "liquid",
- tiles = { "default_river_water.png" },
- special_tiles = {
- {name = "default_river_water.png", backface_culling = false},
- {name = "default_river_water.png", backface_culling = true},
- },
- alpha = WATER_ALPHA,
- paramtype = "light",
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- drowning = 1,
- liquidtype = "source",
- liquid_alternative_flowing = "basenodes:river_water_flowing",
- liquid_alternative_source = "basenodes:river_water_source",
- liquid_viscosity = 1,
- liquid_renewable = false,
- liquid_range = 2,
- post_effect_color = {a = 103, r = 30, g = 76, b = 90},
- groups = {water = 3, liquid = 3, },
-})
-
-minetest.register_node("basenodes:river_water_flowing", {
- description = "Flowing River Water",
- drawtype = "flowingliquid",
- tiles = {"default_river_water_flowing.png"},
- special_tiles = {
- {name = "default_river_water_flowing.png", backface_culling = false},
- {name = "default_river_water_flowing.png", backface_culling = false},
- },
- alpha = WATER_ALPHA,
- paramtype = "light",
- paramtype2 = "flowingliquid",
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- drowning = 1,
- liquidtype = "flowing",
- liquid_alternative_flowing = "basenodes:river_water_flowing",
- liquid_alternative_source = "basenodes:river_water_source",
- liquid_viscosity = 1,
- liquid_renewable = false,
- liquid_range = 2,
- post_effect_color = {a = 103, r = 30, g = 76, b = 90},
- groups = {water = 3, liquid = 3, },
-})
-
-minetest.register_node("basenodes:lava_flowing", {
- description = "Flowing Lava",
- drawtype = "flowingliquid",
- tiles = {"default_lava_flowing.png"},
- special_tiles = {
- {name="default_lava_flowing.png", backface_culling = false},
- {name="default_lava_flowing.png", backface_culling = false},
- },
- paramtype = "light",
- light_source = minetest.LIGHT_MAX,
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- drowning = 1,
- damage_per_second = 4,
- liquidtype = "flowing",
- liquid_alternative_flowing = "basenodes:lava_flowing",
- liquid_alternative_source = "basenodes:lava_source",
- liquid_viscosity = LAVA_VISC,
- post_effect_color = {a=192, r=255, g=64, b=0},
- groups = {lava=3, liquid=1},
-})
-
-minetest.register_node("basenodes:lava_source", {
- description = "Lava Source",
- drawtype = "liquid",
- tiles = { "default_lava.png" },
- special_tiles = {
- {name = "default_lava.png", backface_culling = false},
- {name = "default_lava.png", backface_culling = true},
- },
- paramtype = "light",
- light_source = minetest.LIGHT_MAX,
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- drowning = 1,
- damage_per_second = 4,
- liquidtype = "source",
- liquid_alternative_flowing = "basenodes:lava_flowing",
- liquid_alternative_source = "basenodes:lava_source",
- liquid_viscosity = LAVA_VISC,
- post_effect_color = {a=192, r=255, g=64, b=0},
- groups = {lava=3, liquid=1},
-})
-
-minetest.register_node("basenodes:cobble", {
- description = "Cobblestone",
- tiles ={"default_cobble.png"},
- is_ground_content = false,
- groups = {cracky=3},
-})
-
-minetest.register_node("basenodes:mossycobble", {
- description = "Mossy Cobblestone",
- tiles ={"default_mossycobble.png"},
- is_ground_content = false,
- groups = {cracky=3},
-})
-
-minetest.register_node("basenodes:apple", {
- description = "Apple",
- drawtype = "plantlike",
- tiles ={"default_apple.png"},
- inventory_image = "default_apple.png",
- paramtype = "light",
- is_ground_content = false,
- sunlight_propagates = true,
- walkable = false,
- groups = {dig_immediate=3},
-
- -- Make eatable because why not?
- on_use = minetest.item_eat(2),
-})
-
-minetest.register_node("basenodes:ice", {
- description = "Ice",
- tiles ={"default_ice.png"},
- groups = {cracky=3},
-})
-
--- The snow nodes intentionally have different tints to make them more
--- distinguishable
-minetest.register_node("basenodes:snow", {
- description = "Snow Sheet",
- tiles = {"basenodes_snow_sheet.png"},
- groups = {crumbly=3},
- walkable = false,
- paramtype = "light",
- drawtype = "nodebox",
- node_box = {
- type = "fixed",
- fixed = {-0.5, -0.5, -0.5, 0.5, -0.25, 0.5},
- },
-})
-
-minetest.register_node("basenodes:snowblock", {
- description = "Snow Block",
- tiles ={"default_snow.png"},
- groups = {crumbly=3},
-})
-
-
+++ /dev/null
-name = basenodes
-description = Contains basic nodes for mapgen
+++ /dev/null
---
--- Tool definitions
---
-
---[[ TOOLS SUMMARY:
-
-Tool types:
-
-* Hand: basic tool/weapon (just for convenience, not optimized for testing)
-* Pickaxe: dig cracky
-* Axe: dig choppy
-* Shovel: dig crumbly
-* Shears: dig snappy
-* Sword: deal damage
-* Dagger: deal damage, but faster
-
-Tool materials:
-
-* Dirt: dig nodes of rating 3, one use only
-* Wood: dig nodes of rating 3
-* Stone: dig nodes of rating 3 or 2
-* Steel: dig nodes of rating 3, 2 or 1
-* Mese: dig "everything" instantly
-]]
-
--- The hand
-minetest.register_item(":", {
- type = "none",
- wield_image = "wieldhand.png",
- wield_scale = {x=1,y=1,z=2.5},
- tool_capabilities = {
- full_punch_interval = 1.0,
- max_drop_level = 0,
- groupcaps = {
- crumbly = {times={[3]=1.50}, uses=0, maxlevel=0},
- snappy = {times={[3]=1.50}, uses=0, maxlevel=0},
- oddly_breakable_by_hand = {times={[1]=7.00,[2]=4.00,[3]=2.00}, uses=0, maxlevel=0},
- },
- damage_groups = {fleshy=1},
- }
-})
-
--- Mese Pickaxe: special tool that digs "everything" instantly
-minetest.register_tool("basetools:pick_mese", {
- description = "Mese Pickaxe",
- inventory_image = "basetools_mesepick.png",
- tool_capabilities = {
- full_punch_interval = 1.0,
- max_drop_level=3,
- groupcaps={
- cracky={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
- crumbly={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
- snappy={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
- choppy={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
- dig_immediate={times={[1]=0.0, [2]=0.0, [3]=0.0}, maxlevel=255},
- },
- },
-})
-
-
---
--- Pickaxes: Dig cracky
---
-
--- This should break after only 1 use
-minetest.register_tool("basetools:pick_dirt", {
- description = "Dirt Pickaxe",
- inventory_image = "basetools_dirtpick.png",
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- cracky={times={[3]=2.00}, uses=1, maxlevel=0}
- },
- },
-})
-
-minetest.register_tool("basetools:pick_wood", {
- description = "Wooden Pickaxe",
- inventory_image = "basetools_woodpick.png",
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- cracky={times={[3]=2.00}, uses=30, maxlevel=0}
- },
- },
-})
-minetest.register_tool("basetools:pick_stone", {
- description = "Stone Pickaxe",
- inventory_image = "basetools_stonepick.png",
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- cracky={times={[2]=1.20, [3]=0.80}, uses=60, maxlevel=0}
- },
- },
-})
-minetest.register_tool("basetools:pick_steel", {
- description = "Steel Pickaxe",
- inventory_image = "basetools_steelpick.png",
- tool_capabilities = {
- max_drop_level=1,
- groupcaps={
- cracky={times={[1]=4.00, [2]=1.60, [3]=1.00}, uses=90, maxlevel=0}
- },
- },
-})
-minetest.register_tool("basetools:pick_steel_l1", {
- description = "Steel Pickaxe Level 1",
- inventory_image = "basetools_steelpick_l1.png",
- tool_capabilities = {
- max_drop_level=1,
- groupcaps={
- cracky={times={[1]=4.00, [2]=1.60, [3]=1.00}, uses=90, maxlevel=1}
- },
- },
-})
-minetest.register_tool("basetools:pick_steel_l2", {
- description = "Steel Pickaxe Level 2",
- inventory_image = "basetools_steelpick_l2.png",
- tool_capabilities = {
- max_drop_level=1,
- groupcaps={
- cracky={times={[1]=4.00, [2]=1.60, [3]=1.00}, uses=90, maxlevel=2}
- },
- },
-})
-
---
--- Shovels (dig crumbly)
---
-
-minetest.register_tool("basetools:shovel_wood", {
- description = "Wooden Shovel",
- inventory_image = "basetools_woodshovel.png",
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- crumbly={times={[3]=0.50}, uses=30, maxlevel=0}
- },
- },
-})
-minetest.register_tool("basetools:shovel_stone", {
- description = "Stone Shovel",
- inventory_image = "basetools_stoneshovel.png",
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- crumbly={times={[2]=0.50, [3]=0.30}, uses=60, maxlevel=0}
- },
- },
-})
-minetest.register_tool("basetools:shovel_steel", {
- description = "Steel Shovel",
- inventory_image = "basetools_steelshovel.png",
- tool_capabilities = {
- max_drop_level=1,
- groupcaps={
- crumbly={times={[1]=1.00, [2]=0.70, [3]=0.60}, uses=90, maxlevel=0}
- },
- },
-})
-
---
--- Axes (dig choppy)
---
-
-minetest.register_tool("basetools:axe_wood", {
- description = "Wooden Axe",
- inventory_image = "basetools_woodaxe.png",
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- choppy={times={[3]=0.80}, uses=30, maxlevel=0},
- },
- },
-})
-minetest.register_tool("basetools:axe_stone", {
- description = "Stone Axe",
- inventory_image = "basetools_stoneaxe.png",
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- choppy={times={[2]=1.00, [3]=0.60}, uses=60, maxlevel=0},
- },
- },
-})
-minetest.register_tool("basetools:axe_steel", {
- description = "Steel Axe",
- inventory_image = "basetools_steelaxe.png",
- tool_capabilities = {
- max_drop_level=1,
- groupcaps={
- choppy={times={[1]=2.00, [2]=0.80, [3]=0.40}, uses=90, maxlevel=0},
- },
- },
-})
-
---
--- Shears (dig snappy)
---
-
-minetest.register_tool("basetools:shears_wood", {
- description = "Wooden Shears",
- inventory_image = "basetools_woodshears.png",
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- snappy={times={[3]=1.00}, uses=30, maxlevel=0},
- },
- },
-})
-minetest.register_tool("basetools:shears_stone", {
- description = "Stone Shears",
- inventory_image = "basetools_stoneshears.png",
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- snappy={times={[2]=1.00, [3]=0.50}, uses=60, maxlevel=0},
- },
- },
-})
-minetest.register_tool("basetools:shears_steel", {
- description = "Steel Shears",
- inventory_image = "basetools_steelshears.png",
- tool_capabilities = {
- max_drop_level=1,
- groupcaps={
- snappy={times={[1]=1.00, [2]=0.50, [3]=0.25}, uses=90, maxlevel=0},
- },
- },
-})
-
---
--- Swords (deal damage)
---
-
-minetest.register_tool("basetools:sword_wood", {
- description = "Wooden Sword",
- inventory_image = "basetools_woodsword.png",
- tool_capabilities = {
- full_punch_interval = 1.0,
- damage_groups = {fleshy=2},
- }
-})
-minetest.register_tool("basetools:sword_stone", {
- description = "Stone Sword",
- inventory_image = "basetools_stonesword.png",
- tool_capabilities = {
- full_punch_interval = 1.0,
- max_drop_level=0,
- damage_groups = {fleshy=4},
- }
-})
-minetest.register_tool("basetools:sword_steel", {
- description = "Steel Sword",
- inventory_image = "basetools_steelsword.png",
- tool_capabilities = {
- full_punch_interval = 1.0,
- max_drop_level=1,
- damage_groups = {fleshy=6},
- }
-})
-
--- Fire/Ice sword: Deal damage to non-fleshy damage groups
-minetest.register_tool("basetools:sword_fire", {
- description = "Fire Sword",
- inventory_image = "basetools_firesword.png",
- tool_capabilities = {
- full_punch_interval = 1.0,
- max_drop_level=0,
- damage_groups = {icy=6},
- }
-})
-minetest.register_tool("basetools:sword_ice", {
- description = "Ice Sword",
- inventory_image = "basetools_icesword.png",
- tool_capabilities = {
- full_punch_interval = 1.0,
- max_drop_level=0,
- damage_groups = {firy=6},
- }
-})
-
---
--- Dagger: Low damage, fast punch interval
---
-minetest.register_tool("basetools:dagger_steel", {
- description = "Steel Dagger",
- inventory_image = "basetools_steeldagger.png",
- tool_capabilities = {
- full_punch_interval = 0.5,
- max_drop_level=0,
- damage_groups = {fleshy=2},
- }
-})
+++ /dev/null
-name = basetools
-description = Contains basic digging tools
+++ /dev/null
--- Bucket: Punch liquid source or flowing liquid to collect it
-
-minetest.register_tool("bucket:bucket", {
- description = "Bucket",
- inventory_image = "bucket.png",
- stack_max = 1,
- liquids_pointable = true,
- groups = { disable_repair = 1 },
- on_use = function(itemstack, user, pointed_thing)
- -- Must be pointing to node
- if pointed_thing.type ~= "node" then
- return
- end
- -- Check if pointing to a liquid
- local n = minetest.get_node(pointed_thing.under)
- local def = minetest.registered_nodes[n.name]
- if def ~= nil and (def.liquidtype == "source" or def.liquidtype == "flowing") then
- minetest.add_node(pointed_thing.under, {name="air"})
- local inv = user:get_inventory()
- if inv then
- inv:add_item("main", ItemStack(n.name))
- end
- end
- end,
-})
-
+++ /dev/null
-name = bucket
-description = Minimal bucket to pick up liquids
+++ /dev/null
-minetest.register_node("chest:chest", {
- description = "Chest",
- tiles ={"chest_chest.png^[sheet:2x2:0,0", "chest_chest.png^[sheet:2x2:0,0",
- "chest_chest.png^[sheet:2x2:1,0", "chest_chest.png^[sheet:2x2:1,0",
- "chest_chest.png^[sheet:2x2:1,0", "chest_chest.png^[sheet:2x2:0,1"},
- paramtype2 = "facedir",
- groups = {dig_immediate=2,choppy=3},
- is_ground_content = false,
- on_construct = function(pos)
- local meta = minetest.get_meta(pos)
- meta:set_string("formspec",
- "size[8,9]"..
- "list[current_name;main;0,0;8,4;]"..
- "list[current_player;main;0,5;8,4;]" ..
- "listring[]")
- meta:set_string("infotext", "Chest")
- local inv = meta:get_inventory()
- inv:set_size("main", 8*4)
- end,
- can_dig = function(pos,player)
- local meta = minetest.get_meta(pos);
- local inv = meta:get_inventory()
- return inv:is_empty("main")
- end,
-})
-
-
+++ /dev/null
-name = chest
-description = A simple chest to store items
+++ /dev/null
-local F = minetest.formspec_escape
-
--- Create a detached inventory
-local inv_everything = minetest.create_detached_inventory("everything", {
- allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
- return 0
- end,
- allow_put = function(inv, listname, index, stack, player)
- return 0
- end,
- allow_take = function(inv, listname, index, stack, player)
- return -1
- end,
-})
-local inv_trash = minetest.create_detached_inventory("trash", {
- allow_take = function(inv, listname, index, stack, player)
- return 0
- end,
- allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
- return 0
- end,
- on_put = function(inv, listname, index, stack, player)
- inv:set_list("main", {})
- end,
-})
-inv_trash:set_size("main", 1)
-
-local max_page = 1
-
-local function get_chest_formspec(page)
- local start = 0 + (page-1)*32
- return "size[8,9]"..
- "list[detached:everything;main;0,0;8,4;"..start.."]"..
- "list[current_player;main;0,5;8,4;]" ..
- "label[6,4;Trash:]" ..
- "list[detached:trash;main;7,4;1,1]" ..
- "button[0,4;1,1;chest_of_everything_prev;"..F("<").."]"..
- "button[1,4;1,1;chest_of_everything_next;"..F(">").."]"..
- "label[2,4;"..F("Page: "..page).."]"..
- "listring[detached:everything;main]"..
- "listring[current_player;main]"..
- "listring[detached:trash;main]"
-end
-
-minetest.register_node("chest_of_everything:chest", {
- description = "Chest of Everything",
- tiles ={"chest_of_everything_chest.png^[sheet:2x2:0,0", "chest_of_everything_chest.png^[sheet:2x2:0,0",
- "chest_of_everything_chest.png^[sheet:2x2:1,0", "chest_of_everything_chest.png^[sheet:2x2:1,0",
- "chest_of_everything_chest.png^[sheet:2x2:1,0", "chest_of_everything_chest.png^[sheet:2x2:0,1"},
- paramtype2 = "facedir",
- groups = {dig_immediate=2,choppy=3},
- is_ground_content = false,
- on_construct = function(pos)
- local meta = minetest.get_meta(pos)
- meta:set_string("infotext", "Chest of Everything")
- meta:set_int("page", 1)
- meta:set_string("formspec", get_chest_formspec(1))
- end,
- on_receive_fields = function(pos, formname, fields, sender)
- if formname == "" then
- local meta = minetest.get_meta(pos)
- local page = meta:get_int("page")
- if fields.chest_of_everything_prev then
- page = page - 1
- elseif fields.chest_of_everything_next then
- page = page + 1
- end
- if page < 1 then
- page = 1
- end
- if page > max_page then
- page = max_page
- end
- meta:set_int("page", page)
- meta:set_string("formspec", get_chest_formspec(page))
- end
- end,
-})
-
-minetest.register_on_mods_loaded(function()
- local items = {}
- for itemstring,_ in pairs(minetest.registered_items) do
- if itemstring ~= "" and itemstring ~= "unknown" and itemstring ~= "ignore" then
- table.insert(items, itemstring)
- end
- end
- --[[ Sort items in this order:
- * Chest of Everything
- * Test tools
- * Other tools
- * Craftitems
- * Other items
- * Dummy items ]]
- local function compare(item1, item2)
- local def1 = minetest.registered_items[item1]
- local def2 = minetest.registered_items[item2]
- local tool1 = def1.type == "tool"
- local tool2 = def2.type == "tool"
- local testtool1 = minetest.get_item_group(item1, "testtool") == 1
- local testtool2 = minetest.get_item_group(item2, "testtool") == 1
- local dummy1 = minetest.get_item_group(item1, "dummy") == 1
- local dummy2 = minetest.get_item_group(item2, "dummy") == 1
- local craftitem1 = def1.type == "craft"
- local craftitem2 = def2.type == "craft"
- if item1 == "chest_of_everything:chest" then
- return true
- elseif item2 == "chest_of_everything:chest" then
- return false
- elseif dummy1 and not dummy2 then
- return false
- elseif not dummy1 and dummy2 then
- return true
- elseif testtool1 and not testtool2 then
- return true
- elseif not testtool1 and testtool2 then
- return false
- elseif tool1 and not tool2 then
- return true
- elseif not tool1 and tool2 then
- return false
- elseif craftitem1 and not craftitem2 then
- return true
- elseif not craftitem1 and craftitem2 then
- return false
- else
- return item1 < item2
- end
- end
- table.sort(items, compare)
- inv_everything:set_size("main", #items)
- max_page = math.ceil(#items / 32)
- for i=1, #items do
- inv_everything:add_item("main", items[i])
- end
-end)
+++ /dev/null
-name = chest_of_everything
-description = Adds the chest of everything from which you can take all items
+++ /dev/null
-local groups = {
- "cracky", "dig_immediate"
-}
-
--- Register dig nodes with 1 digging group, a rating between 1-3 and a level between 0-2
-for g=1, #groups do
- local gr = groups[g]
- for r=1, 3 do
- for l=0, 2 do
- if not (gr=="dig_immediate" and (l>0 or r==1)) then
- local d
- if l > 0 then
- d = string.format("Dig Test Node: %s=%d, level=%d", gr, r, l)
- else
- d = string.format("Dig Test Node: %s=%d", gr, r)
- end
- local tile = "dignodes_"..gr..".png^dignodes_rating"..r..".png"
- if l==1 then
- tile = tile .. "^[colorize:#FFFF00:127"
- elseif l==2 then
- tile = tile .. "^[colorize:#FF0000:127"
- end
- minetest.register_node("dignodes:"..gr.."_"..r.."_"..l, {
- description = d,
- tiles = { tile },
- groups = { [gr] = r, level = l },
- })
- end
- end
- end
-end
-
--- Node without any digging groups
-minetest.register_node("dignodes:none", {
- description = "Dig Test Node: groupless",
- tiles = {"dignodes_none.png"},
-})
+++ /dev/null
-name = dignodes
-description = Nodes with different digging groups
+++ /dev/null
-minetest.register_chatcommand("test_inv", {
- params = "",
- description = "Test: Modify player's inventory formspec",
- func = function(name, param)
- local player = minetest.get_player_by_name(name)
- if not player then
- return false, "No player."
- end
- player:set_inventory_formspec(
- "size[13,7.5]"..
- "image[6,0.6;1,2;player.png]"..
- "list[current_player;main;5,3.5;8,4;]"..
- "list[current_player;craft;8,0;3,3;]"..
- "list[current_player;craftpreview;12,1;1,1;]"..
- "list[detached:test_inventory;main;0,0;4,6;0]"..
- "button[0.5,7;2,1;button1;Button 1]"..
- "button_exit[2.5,7;2,1;button2;Exit Button]")
- return true, "Done."
- end,
-})
-
-minetest.register_chatcommand("test_bulk_set_node", {
- params = "",
- description = "Test: Bulk-set 9×9×9 stone nodes",
- func = function(name, param)
- local player = minetest.get_player_by_name(name)
- if not player then
- return false, "No player."
- end
- local pos_list = {}
- local ppos = player:get_pos()
- local i = 1
- for x=2,10 do
- for y=2,10 do
- for z=2,10 do
- pos_list[i] = {x=ppos.x + x,y = ppos.y + y,z = ppos.z + z}
- i = i + 1
- end
- end
- end
- minetest.bulk_set_node(pos_list, {name = "mapgen_stone"})
- return true, "Done."
- end,
-})
-
-minetest.register_chatcommand("bench_bulk_set_node", {
- params = "",
- description = "Benchmark: Bulk-set 99×99×99 stone nodes",
- func = function(name, param)
- local player = minetest.get_player_by_name(name)
- if not player then
- return false, "No player."
- end
- local pos_list = {}
- local ppos = player:get_pos()
- local i = 1
- for x=2,100 do
- for y=2,100 do
- for z=2,100 do
- pos_list[i] = {x=ppos.x + x,y = ppos.y + y,z = ppos.z + z}
- i = i + 1
- end
- end
- end
-
- minetest.chat_send_player(name, "Benchmarking minetest.bulk_set_node. Warming up ...");
-
- -- warm up with stone to prevent having different callbacks
- -- due to different node topology
- minetest.bulk_set_node(pos_list, {name = "mapgen_stone"})
-
- minetest.chat_send_player(name, "Warming up finished, now benchmarking ...");
-
- local start_time = minetest.get_us_time()
- for i=1,#pos_list do
- minetest.set_node(pos_list[i], {name = "mapgen_stone"})
- end
- local middle_time = minetest.get_us_time()
- minetest.bulk_set_node(pos_list, {name = "mapgen_stone"})
- local end_time = minetest.get_us_time()
- local msg = string.format("Benchmark results: minetest.set_node loop: %.2f ms; minetest.bulk_set_node: %.2f ms",
- ((middle_time - start_time)) / 1000,
- ((end_time - middle_time)) / 1000
- )
- return true, msg
- end,
-})
-
-local function advance_pos(pos, start_pos, advance_z)
- if advance_z then
- pos.z = pos.z + 2
- pos.x = start_pos.x
- else
- pos.x = pos.x + 2
- end
- if pos.x > 30900 or pos.x - start_pos.x > 46 then
- pos.x = start_pos.x
- pos.z = pos.z + 2
- end
- if pos.z > 30900 then
- -- We ran out of space! Aborting
- aborted = true
- return false
- end
- return pos
-end
-
-local function place_nodes(param)
- local nodes = param.nodes
- local name = param.name
- local pos = param.pos
- local start_pos = param.start_pos
- table.sort(nodes)
- minetest.chat_send_player(name, "Placing nodes …")
- local nodes_placed = 0
- for n=1, #nodes do
- local itemstring = nodes[n]
- local def = minetest.registered_nodes[itemstring]
- local p2_max = 0
- if param.param ~= "no_param2" then
- -- Also test the param2 values of the nodes
- -- ... but we only use permissible param2 values
- if def.paramtype2 == "wallmounted" then
- p2_max = 5
- elseif def.paramtype2 == "facedir" then
- p2_max = 23
- elseif def.paramtype2 == "glasslikeliquidlevel" then
- p2_max = 63
- elseif def.paramtype2 == "meshoptions" and def.drawtype == "plantlike" then
- p2_max = 63
- elseif def.paramtype2 == "leveled" then
- p2_max = 127
- elseif def.paramtype2 == "degrotate" and def.drawtype == "plantlike" then
- p2_max = 179
- elseif def.paramtype2 == "colorfacedir" or
- def.paramtype2 == "colorwallmounted" or
- def.paramtype2 == "color" then
- p2_max = 255
- end
- end
- for p2 = 0, p2_max do
- -- Skip undefined param2 values
- if not ((def.paramtype2 == "meshoptions" and p2 % 8 > 4) or
- (def.paramtype2 == "colorwallmounted" and p2 % 8 > 5) or
- (def.paramtype2 == "colorfacedir" and p2 % 32 > 23)) then
-
- minetest.set_node(pos, { name = itemstring, param2 = p2 })
- nodes_placed = nodes_placed + 1
- pos = advance_pos(pos, start_pos)
- if not pos then
- aborted = true
- break
- end
- end
- end
- if aborted then
- break
- end
- end
- if aborted then
- minetest.chat_send_player(name, "Not all nodes could be placed, please move further away from the world boundary. Nodes placed: "..nodes_placed)
- end
- minetest.chat_send_player(name, "Nodes placed: "..nodes_placed..".")
-end
-
-local function after_emerge(blockpos, action, calls_remaining, param)
- if calls_remaining == 0 then
- place_nodes(param)
- end
-end
-
-minetest.register_chatcommand("test_place_nodes", {
- params = "[ no_param2 ]",
- description = "Test: Place all non-experimental nodes and optionally their permissible param2 variants",
- func = function(name, param)
- local player = minetest.get_player_by_name(name)
- if not player then
- return false, "No player."
- end
- local pos = vector.floor(player:get_pos())
- pos.x = math.ceil(pos.x + 3)
- pos.z = math.ceil(pos.z + 3)
- pos.y = math.ceil(pos.y + 1)
- local start_pos = table.copy(pos)
- if pos.x > 30800 then
- return false, "Too close to world boundary (+X). Please move to X < 30800."
- end
- if pos.z > 30800 then
- return false, "Too close to world boundary (+Z). Please move to Z < 30800."
- end
-
- local aborted = false
- local nodes = {}
- local emerge_estimate = 0
- for itemstring, def in pairs(minetest.registered_nodes) do
- if itemstring ~= "ignore" and string.sub(itemstring, 1, 13) ~= "experimental:" then
- table.insert(nodes, itemstring)
- if def.paramtype2 == 0 then
- emerge_estimate = emerge_estimate + 1
- else
- emerge_estimate = emerge_estimate + 255
- end
- end
- end
- -- Emerge area to make sure that all nodes are being placed.
- -- Note we will emerge much more than we need to (overestimation),
- -- the estimation code could be improved performance-wise …
- local length = 16 + math.ceil(emerge_estimate / 24) * 2
- minetest.emerge_area(start_pos,
- { x = start_pos.x + 46, y = start_pos.y, z = start_pos.z + length },
- after_emerge, { nodes = nodes, name = name, pos = pos, start_pos = start_pos, param = param })
- return true, "Emerging area …"
- end,
-})
-
+++ /dev/null
--- Create a detached inventory
-local inv = minetest.create_detached_inventory("test_inventory", {
- allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
- experimental.print_to_everything("allow move asked")
- return count -- Allow all
- end,
- allow_put = function(inv, listname, index, stack, player)
- experimental.print_to_everything("allow put asked")
- return 1 -- Allow only 1
- end,
- allow_take = function(inv, listname, index, stack, player)
- experimental.print_to_everything("allow take asked")
- return 4 -- Allow 4 at max
- end,
- on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
- experimental.print_to_everything(player:get_player_name().." moved items")
- end,
- on_put = function(inv, listname, index, stack, player)
- experimental.print_to_everything(player:get_player_name().." put items")
- end,
- on_take = function(inv, listname, index, stack, player)
- experimental.print_to_everything(player:get_player_name().." took items")
- end,
-})
-inv:set_size("main", 4*6)
-inv:add_item("main", "experimental:callback_node")
-inv:add_item("main", "experimental:particle_spawner")
-
-
+++ /dev/null
---
--- Experimental things
---
-
-experimental = {}
-
-dofile(minetest.get_modpath("experimental").."/detached.lua")
-dofile(minetest.get_modpath("experimental").."/items.lua")
-dofile(minetest.get_modpath("experimental").."/commands.lua")
-
-function experimental.print_to_everything(msg)
- minetest.log("action", msg)
- minetest.chat_send_all(msg)
-end
-
-minetest.log("info", "[experimental] modname="..dump(minetest.get_current_modname()))
-minetest.log("info", "[experimental] modpath="..dump(minetest.get_modpath("experimental")))
-minetest.log("info", "[experimental] worldpath="..dump(minetest.get_worldpath()))
-
-
-minetest.register_on_mods_loaded(function()
- minetest.log("action", "[experimental] on_mods_loaded()")
-end)
+++ /dev/null
-minetest.register_node("experimental:callback_node", {
- description = "Callback Test Node (construct/destruct/timer)",
- tiles = {"experimental_callback_node.png"},
- groups = {dig_immediate=3},
- -- This was known to cause a bug in minetest.item_place_node() when used
- -- via minetest.place_node(), causing a placer with no position
- paramtype2 = "facedir",
- drop = "",
-
- on_construct = function(pos)
- experimental.print_to_everything("experimental:callback_node:on_construct("..minetest.pos_to_string(pos)..")")
- local meta = minetest.get_meta(pos)
- meta:set_string("mine", "test")
- local timer = minetest.get_node_timer(pos)
- timer:start(4, 3)
- end,
-
- after_place_node = function(pos, placer)
- experimental.print_to_everything("experimental:callback_node:after_place_node("..minetest.pos_to_string(pos)..")")
- local meta = minetest.get_meta(pos)
- if meta:get_string("mine") == "test" then
- experimental.print_to_everything("correct metadata found")
- else
- experimental.print_to_everything("incorrect metadata found")
- end
- end,
-
- on_destruct = function(pos)
- experimental.print_to_everything("experimental:callback_node:on_destruct("..minetest.pos_to_string(pos)..")")
- end,
-
- after_destruct = function(pos)
- experimental.print_to_everything("experimental:callback_node:after_destruct("..minetest.pos_to_string(pos)..")")
- end,
-
- after_dig_node = function(pos, oldnode, oldmetadata, digger)
- experimental.print_to_everything("experimental:callback_node:after_dig_node("..minetest.pos_to_string(pos)..")")
- end,
-
- on_timer = function(pos, elapsed)
- experimental.print_to_everything("on_timer(): elapsed="..dump(elapsed))
- return true
- end,
-})
-
-minetest.register_tool("experimental:privatizer", {
- description = "Node Meta Privatizer",
- inventory_image = "experimental_tester_tool_1.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_use = function(itemstack, user, pointed_thing)
- if pointed_thing.type == "node" then
- local node = minetest.get_node(pointed_thing.under)
- if node.name == "chest:chest" then
- local p = pointed_thing.under
- minetest.log("action", "Privatizer used at "..minetest.pos_to_string(p))
- minetest.get_meta(p):mark_as_private({"infotext", "formspec"})
- if user and user:is_player() then
- minetest.chat_send_player(user:get_player_name(), "Chest metadata (infotext, formspec) set private!")
- end
- return
- end
- end
- if user and user:is_player() then
- minetest.chat_send_player(user:get_player_name(), "Privatizer can only be used on chest!")
- end
- end,
-})
-
-minetest.register_tool("experimental:particle_spawner", {
- description = "Particle Spawner",
- inventory_image = "experimental_tester_tool_1.png^[invert:g",
- groups = { testtool = 1, disable_repair = 1 },
- on_use = function(itemstack, user, pointed_thing)
- local pos = minetest.get_pointed_thing_position(pointed_thing, true)
- if pos == nil then
- if user then
- pos = user:get_pos()
- end
- end
- pos = vector.add(pos, {x=0, y=0.5, z=0})
- local tex, anim
- if math.random(0, 1) == 0 then
- tex = "experimental_particle_sheet.png"
- anim = {type="sheet_2d", frames_w=3, frames_h=2, frame_length=0.5}
- else
- tex = "experimental_particle_vertical.png"
- anim = {type="vertical_frames", aspect_w=16, aspect_h=16, length=3.3}
- end
-
- minetest.add_particle({
- pos = pos,
- velocity = {x=0, y=0, z=0},
- acceleration = {x=0, y=0.04, z=0},
- expirationtime = 6,
- collisiondetection = true,
- texture = tex,
- animation = anim,
- size = 4,
- glow = math.random(0, 5),
- })
- end,
-})
-
+++ /dev/null
-name = experimental
-description = Chaotic mod containing unstructured tests for testing out engine features. The features in this mod should be moved to other mods.
+++ /dev/null
-local give_if_not_gotten_already = function(inv, list, item)
- if not inv:contains_item(list, item) then
- inv:add_item(list, item)
- end
-end
-
-local give_initial_stuff = function(player)
- local inv = player:get_inventory()
- give_if_not_gotten_already(inv, "main", "basetools:pick_mese")
- give_if_not_gotten_already(inv, "main", "basetools:axe_steel")
- give_if_not_gotten_already(inv, "main", "basetools:shovel_steel")
- give_if_not_gotten_already(inv, "main", "bucket:bucket")
- give_if_not_gotten_already(inv, "main", "testnodes:light14")
- give_if_not_gotten_already(inv, "main", "chest_of_everything:chest")
- minetest.log("action", "[give_initial_stuff] Giving initial stuff to "..player:get_player_name())
-end
-
-minetest.register_on_newplayer(function(player)
- if minetest.settings:get_bool("give_initial_stuff", true) then
- give_initial_stuff(player)
- end
-end)
-
-minetest.register_chatcommand("stuff", {
- params = "",
- privs = { give = true },
- description = "Give yourself initial items",
- func = function(name, param)
- local player = minetest.get_player_by_name(name)
- if not player or not player:is_player() then
- return false, "No player."
- end
- give_initial_stuff(player)
- return true
- end,
-})
-
+++ /dev/null
-name = give_initial_stuff
-description = Gives items to players on join
-depends = basetools, bucket, chest_of_everything, testnodes
+++ /dev/null
-minetest.register_on_joinplayer(function(player)
- local cb = function(player)
- if not player or not player:is_player() then
- return
- end
- minetest.chat_send_player(player:get_player_name(), "This is the \"Minimal development Test\" [minimal], meant only for testing and development. Use Minetest Game for the real thing.")
- end
- minetest.after(2.0, cb, player)
-end)
+++ /dev/null
-name = initial_message
-description = Show message to joining players explaining what this testing game is about
+++ /dev/null
---
--- Aliases for map generator outputs
---
-
--- ESSENTIAL node aliases
--- Basic nodes
-minetest.register_alias("mapgen_stone", "basenodes:stone")
-minetest.register_alias("mapgen_water_source", "basenodes:water_source")
-minetest.register_alias("mapgen_river_water_source", "basenodes:river_water_source")
-
--- Additional essential aliases for v6
-minetest.register_alias("mapgen_lava_source", "basenodes:lava_source")
-minetest.register_alias("mapgen_dirt", "basenodes:dirt")
-minetest.register_alias("mapgen_dirt_with_grass", "basenodes:dirt_with_grass")
-minetest.register_alias("mapgen_sand", "basenodes:sand")
-minetest.register_alias("mapgen_tree", "basenodes:tree")
-minetest.register_alias("mapgen_leaves", "basenodes:leaves")
-minetest.register_alias("mapgen_apple", "basenodes:apple")
-
--- Essential alias for dungeons
-minetest.register_alias("mapgen_cobble", "basenodes:cobble")
-
--- Optional aliases for v6 (they all have fallback values in the engine)
-if minetest.settings:get_bool("devtest_v6_mapgen_aliases", false) then
- minetest.register_alias("mapgen_gravel", "basenodes:gravel")
- minetest.register_alias("mapgen_desert_stone", "basenodes:desert_stone")
- minetest.register_alias("mapgen_desert_sand", "basenodes:desert_sand")
- minetest.register_alias("mapgen_dirt_with_snow", "basenodes:dirt_with_snow")
- minetest.register_alias("mapgen_snowblock", "basenodes:snowblock")
- minetest.register_alias("mapgen_snow", "basenodes:snow")
- minetest.register_alias("mapgen_ice", "basenodes:ice")
- minetest.register_alias("mapgen_junglegrass", "basenodes:junglegrass")
- minetest.register_alias("mapgen_jungletree", "basenodes:jungletree")
- minetest.register_alias("mapgen_jungleleaves", "basenodes:jungleleaves")
- minetest.register_alias("mapgen_pine_tree", "basenodes:pine_tree")
- minetest.register_alias("mapgen_pine_needles", "basenodes:pine_needles")
-end
--- Optional alias for mossycobble (should fall back to cobble)
-if minetest.settings:get_bool("devtest_dungeon_mossycobble", false) then
- minetest.register_alias("mapgen_mossycobble", "basenodes:mossycobble")
-end
--- Optional aliases for dungeon stairs (should fall back to full nodes)
-if minetest.settings:get_bool("devtest_dungeon_stairs", false) then
- minetest.register_alias("mapgen_stair_cobble", "stairs:stair_cobble")
- if minetest.settings:get_bool("devtest_v6_mapgen_aliases", false) then
- minetest.register_alias("mapgen_stair_desert_stone", "stairs:stair_desert_stone")
- end
-end
-
---
--- Register biomes for biome API
---
-
-minetest.clear_registered_biomes()
-minetest.clear_registered_decorations()
-
-if minetest.settings:get_bool("devtest_register_biomes", true) then
- minetest.register_biome({
- name = "mapgen:grassland",
- node_top = "basenodes:dirt_with_grass",
- depth_top = 1,
- node_filler = "basenodes:dirt",
- depth_filler = 1,
- y_min = 5,
- y_max = 31000,
- heat_point = 50,
- humidity_point = 50,
- })
-
- minetest.register_biome({
- name = "mapgen:grassland_ocean",
- node_top = "basenodes:sand",
- depth_top = 1,
- node_filler = "basenodes:sand",
- depth_filler = 2,
- y_min = -31000,
- y_max = 4,
- heat_point = 50,
- humidity_point = 50,
- })
-end
+++ /dev/null
-name = mapgen
-description = Minimal map generator
-depends = basenodes
+++ /dev/null
---
--- Mod channels experimental handlers
---
-local mod_channel = minetest.mod_channel_join("experimental_preview")
-
-minetest.register_on_modchannel_message(function(channel, sender, message)
- minetest.log("action", "[modchannels] Server received message `" .. message
- .. "` on channel `" .. channel .. "` from sender `" .. sender .. "`")
-
- if mod_channel:is_writeable() then
- mod_channel:send_all("experimental answers to preview")
- mod_channel:leave()
- end
-end)
+++ /dev/null
-name = modchannels
-description = Add experimental mod channel handlers
+++ /dev/null
-local simple_nodes = {
- footstep = { "Footstep Sound Node", "soundstuff_node_footstep.png" },
- dig = { "Dig Sound Node", "soundstuff_node_dig.png" },
- dug = { "Dug Sound Node", "soundstuff_node_dug.png" },
- place = { "Place Sound Node", "soundstuff_node_place.png" },
- place_failed = { "Place Failed Sound Node", "soundstuff_node_place_failed.png" },
-}
-
-for k,v in pairs(simple_nodes) do
- minetest.register_node("soundstuff:"..k, {
- description = v[1],
- tiles = {"soundstuff_node_sound.png","soundstuff_node_sound.png",v[2]},
- groups = {dig_immediate=2},
- sounds = {
- [k] = { name = "soundstuff_mono", gain = 1.0 },
- }
- })
-end
-
-minetest.register_node("soundstuff:place_failed_attached", {
- description = "Attached Place Failed Sound Node",
- tiles = {"soundstuff_node_sound.png", "soundstuff_node_sound.png", "soundstuff_node_place_failed.png"},
- groups = {dig_immediate=2, attached_node=1},
- drawtype = "nodebox",
- paramtype = "light",
- node_box = { type = "fixed", fixed = {
- { -7/16, -7/16, -7/16, 7/16, 7/16, 7/16 },
- { -0.5, -0.5, -0.5, 0.5, -7/16, 0.5 },
- }},
- sounds = {
- place_failed = { name = "soundstuff_mono", gain = 1.0 },
- },
-})
-
-minetest.register_node("soundstuff:fall", {
- description = "Fall Sound Node",
- tiles = {"soundstuff_node_sound.png", "soundstuff_node_sound.png", "soundstuff_node_fall.png"},
- groups = {dig_immediate=2, falling_node=1},
- sounds = {
- fall = { name = "soundstuff_mono", gain = 1.0 },
- }
-})
-
-minetest.register_node("soundstuff:fall_attached", {
- description = "Attached Fall Sound Node",
- tiles = {"soundstuff_node_sound.png", "soundstuff_node_sound.png", "soundstuff_node_fall.png"},
- groups = {dig_immediate=2, attached_node=1},
- drawtype = "nodebox",
- paramtype = "light",
- node_box = { type = "fixed", fixed = {
- { -7/16, -7/16, -7/16, 7/16, 7/16, 7/16 },
- { -0.5, -0.5, -0.5, 0.5, -7/16, 0.5 },
- }},
- sounds = {
- fall = { name = "soundstuff_mono", gain = 1.0 },
- }
-})
-
-minetest.register_node("soundstuff:footstep_liquid", {
- description = "Liquid Footstep Sound Node",
- drawtype = "liquid",
- tiles = {
- "soundstuff_node_sound.png^[colorize:#0000FF:127",
- },
- special_tiles = {
- {name = "soundstuff_node_sound.png^[colorize:#0000FF:127", backface_culling = false},
- {name = "soundstuff_node_sound.png^[colorize:#0000FF:127", backface_culling = true},
- },
- liquids_pointable = true,
- liquidtype = "source",
- liquid_alternative_flowing = "soundstuff:footstep_liquid",
- liquid_alternative_source = "soundstuff:footstep_liquid",
- liquid_renewable = false,
- liquid_range = 0,
- liquid_viscosity = 0,
- alpha = 190,
- paramtype = "light",
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- post_effect_color = {a = 64, r = 0, g = 0, b = 200},
- sounds = {
- footstep = { name = "soundstuff_mono", gain = 1.0 },
- }
-})
-
-minetest.register_node("soundstuff:footstep_climbable", {
- description = "Climbable Footstep Sound Node",
- drawtype = "allfaces",
- tiles = {
- "soundstuff_node_climbable.png",
- },
- alpha = 120,
- paramtype = "light",
- sunlight_propagates = true,
- walkable = false,
- climbable = true,
- is_ground_content = false,
- groups = { dig_immediate = 2 },
- sounds = {
- footstep = { name = "soundstuff_mono", gain = 1.0 },
- }
-})
-
-
-
-minetest.register_craftitem("soundstuff:eat", {
- description = "Eat Sound Item",
- inventory_image = "soundstuff_eat.png",
- on_use = minetest.item_eat(0),
- sound = {
- eat = { name = "soundstuff_mono", gain = 1.0 },
- }
-})
-
-minetest.register_tool("soundstuff:breaks", {
- description = "Break Sound Tool",
- inventory_image = "soundstuff_node_dug.png",
- sound = {
- breaks = { name = "soundstuff_mono", gain = 1.0 },
- },
- tool_capabilities = {
- max_drop_level=0,
- groupcaps={
- cracky={times={[2]=2.00, [3]=1.20}, uses=1, maxlevel=0},
- choppy={times={[2]=2.00, [3]=1.20}, uses=1, maxlevel=0},
- snappy={times={[2]=2.00, [3]=1.20}, uses=1, maxlevel=0},
- crumbly={times={[2]=2.00, [3]=1.20}, uses=1, maxlevel=0},
- },
- },
-})
-
--- Plays sound repeatedly
-minetest.register_node("soundstuff:positional", {
- description = "Positional Sound Node",
- on_construct = function(pos)
- local timer = minetest.get_node_timer(pos)
- timer:start(0)
- end,
- on_timer = function(pos, elapsed)
- local node = minetest.get_node(pos)
- local dist = node.param2
- if dist == 0 then
- dist = nil
- end
- minetest.sound_play("soundstuff_mono", { pos = pos, max_hear_distance = dist })
- local timer = minetest.get_node_timer(pos)
- timer:start(0.7)
- end,
- on_rightclick = function(pos, node, clicker)
- node.param2 = (node.param2 + 1) % 64
- minetest.set_node(pos, node)
- if clicker and clicker:is_player() then
- local dist = node.param2
- local diststr
- if dist == 0 then
- diststr = "<default>"
- else
- diststr = tostring(dist)
- end
- minetest.chat_send_player(clicker:get_player_name(), "max_hear_distance = " .. diststr)
- end
- end,
-
- groups = { dig_immediate = 2 },
- tiles = { "soundstuff_node_sound.png" },
-})
-
+++ /dev/null
-name = soundstuff
-description = Example items and nodes for testing sound effects
+++ /dev/null
-stairs = {}
-
--- Node will be called stairs:stair_<subname>
-function stairs.register_stair(subname, recipeitem, groups, images, description)
- minetest.register_node(":stairs:stair_" .. subname, {
- description = description,
- drawtype = "nodebox",
- tiles = images,
- paramtype = "light",
- paramtype2 = "facedir",
- is_ground_content = true,
- groups = groups,
- node_box = {
- type = "fixed",
- fixed = {
- {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
- {-0.5, 0, 0, 0.5, 0.5, 0.5},
- },
- },
- })
-end
-
--- Node will be called stairs:slab_<subname>
-function stairs.register_slab(subname, recipeitem, groups, images, description)
- minetest.register_node(":stairs:slab_" .. subname, {
- description = description,
- drawtype = "nodebox",
- tiles = images,
- paramtype = "light",
- is_ground_content = true,
- groups = groups,
- node_box = {
- type = "fixed",
- fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
- },
- selection_box = {
- type = "fixed",
- fixed = {-0.5, -0.5, -0.5, 0.5, 0, 0.5},
- },
- })
-end
-
--- Nodes will be called stairs:{stair,slab}_<subname>
-function stairs.register_stair_and_slab(subname, recipeitem, groups, images, desc_stair, desc_slab)
- stairs.register_stair(subname, recipeitem, groups, images, desc_stair)
- stairs.register_slab(subname, recipeitem, groups, images, desc_slab)
-end
-
-stairs.register_stair_and_slab("stone", "basenodes:stone",
- {cracky=3},
- {"default_stone.png"},
- "Stone Stair",
- "Stone Slab")
-
-stairs.register_stair_and_slab("desert_stone", "basenodes:desert_stone",
- {cracky=3},
- {"default_desert_stone.png"},
- "Desert Stone Stair",
- "Desert Stone Slab")
-
-stairs.register_stair_and_slab("cobble", "basenodes:cobble",
- {cracky=3},
- {"default_cobble.png"},
- "Cobblestone Stair",
- "Cobblestone Slab")
+++ /dev/null
-name = stairs
-description = Adds stairs and slabs
-depends = basenodes
+++ /dev/null
--- Armorball: Test entity for testing armor groups
--- Rightclick to change armor group
-
-local phasearmor = {
- [0]={icy=100},
- [1]={firy=100},
- [2]={fleshy=100},
- [3]={immortal=1},
- [4]={punch_operable=1},
-}
-
-minetest.register_entity("testentities:armorball", {
- initial_properties = {
- hp_max = 20,
- physical = false,
- collisionbox = {-0.4,-0.4,-0.4, 0.4,0.4,0.4},
- visual = "sprite",
- visual_size = {x=1, y=1},
- textures = {"testentities_armorball.png"},
- spritediv = {x=1, y=5},
- initial_sprite_basepos = {x=0, y=0},
- },
-
- _phase = 2,
-
- on_activate = function(self, staticdata)
- minetest.log("action", "[testentities] armorball.on_activate")
- self.object:set_armor_groups(phasearmor[self._phase])
- self.object:set_sprite({x=0, y=self._phase})
- end,
-
- on_rightclick = function(self, clicker)
- -- Change armor group and sprite
- self._phase = self._phase + 1
- if self._phase >= 5 then
- self._phase = 0
- end
- self.object:set_sprite({x=0, y=self._phase})
- self.object:set_armor_groups(phasearmor[self._phase])
- end,
-})
+++ /dev/null
--- Entities that test their callbacks
-
-local message = function(msg)
- minetest.log("action", msg)
- minetest.chat_send_all(msg)
-end
-
-local get_object_name = function(obj)
- local name = "<nil>"
- if obj then
- if obj:is_player() then
- name = obj:get_player_name()
- else
- name = "<entity>"
- end
- end
- return name
-end
-
-local spos = function(self)
- return minetest.pos_to_string(vector.round(self.object:get_pos()))
-end
-
--- Callback test entity (all callbacks except on_step)
-minetest.register_entity("testentities:callback", {
- initial_properties = {
- visual = "upright_sprite",
- textures = { "testentities_callback.png" },
- },
-
- on_activate = function(self, staticdata, dtime_s)
- message("Callback entity: on_activate! pos="..spos(self).."; dtime_s="..dtime_s)
- end,
- on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
- local name = get_object_name(puncher)
- message(
- "Callback entity: on_punch! "..
- "pos="..spos(self).."; puncher="..name.."; "..
- "time_from_last_punch="..time_from_last_punch.."; "..
- "tool_capabilities="..tostring(dump(tool_capabilities)).."; "..
- "dir="..tostring(dump(dir)).."; damage="..damage)
- end,
- on_rightclick = function(self, clicker)
- local name = get_object_name(clicker)
- message("Callback entity: on_rightclick! pos="..spos(self).."; clicker="..name)
- end,
- on_death = function(self, killer)
- local name = get_object_name(killer)
- message("Callback entity: on_death! pos="..spos(self).."; killer="..name)
- end,
- on_attach_child = function(self, child)
- local name = get_object_name(child)
- message("Callback entity: on_attach_child! pos="..spos(self).."; child="..name)
- end,
- on_detach_child = function(self, child)
- local name = get_object_name(child)
- message("Callback entity: on_detach_child! pos="..spos(self).."; child="..name)
- end,
- on_detach = function(self, parent)
- local name = get_object_name(parent)
- message("Callback entity: on_detach! pos="..spos(self).."; parent="..name)
- end,
- get_staticdata = function(self)
- message("Callback entity: get_staticdata! pos="..spos(self))
- end,
-})
-
--- Only test on_step callback
-minetest.register_entity("testentities:callback_step", {
- visual = "upright_sprite",
- textures = { "testentities_callback_step.png" },
- on_step = function(self, dtime)
- message("on_step callback entity: on_step! pos="..spos(self).."; dtime="..dtime)
- end,
-})
+++ /dev/null
-dofile(minetest.get_modpath("testentities").."/visuals.lua")
-dofile(minetest.get_modpath("testentities").."/armor.lua")
-dofile(minetest.get_modpath("testentities").."/callbacks.lua")
+++ /dev/null
-name = testentities
-description = Example entities for testing
+++ /dev/null
--- Minimal test entities to test visuals
-
-minetest.register_entity("testentities:sprite", {
- initial_properties = {
- visual = "sprite",
- textures = { "testentities_sprite.png" },
- },
-})
-
-minetest.register_entity("testentities:upright_sprite", {
- initial_properties = {
- visual = "upright_sprite",
- textures = {
- "testentities_upright_sprite1.png",
- "testentities_upright_sprite2.png",
- },
- },
-})
-
-minetest.register_entity("testentities:cube", {
- initial_properties = {
- visual = "cube",
- textures = {
- "testentities_cube1.png",
- "testentities_cube2.png",
- "testentities_cube3.png",
- "testentities_cube4.png",
- "testentities_cube5.png",
- "testentities_cube6.png",
- },
- },
-})
-
-minetest.register_entity("testentities:item", {
- initial_properties = {
- visual = "item",
- wield_item = "testnodes:normal",
- },
-})
-
-minetest.register_entity("testentities:wielditem", {
- initial_properties = {
- visual = "wielditem",
- wield_item = "testnodes:normal",
- },
-})
-
-minetest.register_entity("testentities:mesh", {
- initial_properties = {
- visual = "mesh",
- mesh = "testnodes_pyramid.obj",
- textures = {
- "testnodes_mesh_stripes2.png"
- },
- },
-})
-
--- Advanced visual tests
-
--- A test entity for testing animated and yaw-modulated sprites
-minetest.register_entity("testentities:yawsprite", {
- initial_properties = {
- selectionbox = {-0.3, -0.5, -0.3, 0.3, 0.3, 0.3},
- visual = "sprite",
- visual_size = {x=0.6666, y=1},
- textures = {"testentities_dungeon_master.png^[makealpha:128,0,0^[makealpha:128,128,0"},
- spritediv = {x=6, y=5},
- initial_sprite_basepos = {x=0, y=0},
- on_activate = function(self, staticdata)
- self.object:set_sprite({x=0, y=0}, 1, 0, true)
- end,
- },
-})
-
+++ /dev/null
-local S = minetest.get_translator("testfood")
-
-minetest.register_craftitem("testfood:good1", {
- description = S("Good Food (+1)"),
- inventory_image = "testfood_good.png",
- on_use = minetest.item_eat(1),
-})
-minetest.register_craftitem("testfood:good5", {
- description = S("Good Food (+5)"),
- inventory_image = "testfood_good2.png",
- on_use = minetest.item_eat(5),
-})
-
-minetest.register_craftitem("testfood:bad1", {
- description = S("Bad Food (-1)"),
- inventory_image = "testfood_bad.png",
- on_use = minetest.item_eat(-1),
-})
-minetest.register_craftitem("testfood:bad5", {
- description = S("Bad Food (-5)"),
- inventory_image = "testfood_bad2.png",
- on_use = minetest.item_eat(-5),
-})
-
+++ /dev/null
-name = testfood
-description = For testing food items
+++ /dev/null
-local callback_test = 0
-
-local out = function(player, formname, fields, number)
- local snum = ""
- if number then
- snum = " "..number
- end
- local msg = "Formspec callback"..snum..": player="..player:get_player_name()..", formname=\""..tostring(formname).."\", fields="..dump(fields)
- minetest.chat_send_player(player:get_player_name(), msg)
- minetest.log("action", msg)
-end
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- if callback_test == 1 then
- out(player, formname, fields)
- elseif callback_test == 2 then
- out(player, formname, fields, 1)
- end
-end)
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- if callback_test == 2 then
- out(player, formname, fields, 2)
- return true -- Disable the first callback
- end
-end)
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- if callback_test == 2 then
- out(player, formname, fields, 3)
- end
-end)
-
-minetest.register_chatcommand("test_formspec_callbacks", {
- params = "[ 0 | 1 | 2 ]",
- description = "Test: Change formspec callbacks testing mode",
- func = function(name, param)
- local mode = tonumber(param)
- if not mode then
- callback_test = (callback_test + 1 % 3)
- else
- callback_test = mode
- end
- if callback_test == 1 then
- minetest.chat_send_player(name, "Formspec callback test mode 1 enabled: Logging only")
- elseif callback_test == 2 then
- minetest.chat_send_player(name, "Formspec callback test mode 2 enabled: Three callbacks, disable pre-registered callbacks")
- else
- callback_test = 0
- minetest.chat_send_player(name, "Formspec callback test disabled!")
- end
- end
-})
+++ /dev/null
--- This code adds dummy items that are supposed to be used in formspecs
--- for testing item_image formspec elements.
-
-minetest.register_node("testformspec:node", {
- description = "Formspec Test Node",
- tiles = { "testformspec_node.png" },
- groups = { dig_immediate = 3, dummy = 1 },
-})
-
-minetest.register_craftitem("testformspec:item", {
- description = "Formspec Test Item",
- inventory_image = "testformspec_item.png",
- groups = { dummy = 1 },
-})
+++ /dev/null
-local color = minetest.colorize
-
-local clip_fs = [[
- style_type[label,button,image_button,item_image_button,
- tabheader,scrollbar,table,animated_image
- ,field,textarea,checkbox,dropdown;noclip=%c]
-
- label[0,0;A clipping test]
- button[0,1;3,0.8;clip_button;A clipping test]
- image_button[0,2;3,0.8;testformspec_button_image.png;clip_image_button;A clipping test]
- item_image_button[0,3;3,0.8;testformspec:item;clip_item_image_button;A clipping test]
- tabheader[0,4.7;3,0.63;clip_tabheader;Clip,Test,Text,Tabs;1;false;false]
- field[0,5;3,0.8;clip_field;Title;]
- textarea[0,6;3,1;clip_textarea;Title;]
- checkbox[0,7.5;clip_checkbox;This is a test;true]
- dropdown[0,8;3,0.8;clip_dropdown;Select An Item,One,Two,Three,Four,Five;1]
- scrollbar[0,9;3,0.8;horizontal;clip_scrollbar;3]
- tablecolumns[text;text]
- table[0,10;3,1;clip_table;one,two,three,four;1]
- animated_image[-0.5,11;4.5,1;clip_animated_image;testformspec_animation.png;4;100]
-]]
-
-local tabheaders_fs = [[
- tabheader[0,0;10,0.63;tabs_opaque;Opaque,Without,Border;1;false;false]
- tabheader[0,1;10,0.63;tabs_opaque_border;Opaque,With,Border;1;false;true]
- tabheader[0,2;10,0.63;tabs_transparent;Transparent,Without,Border;1;true;false]
- tabheader[0,3;10,0.63;tabs_transparent_border;Transparent,With,Border;1;true;true]
- tabheader[0,4;tabs_default;Default,Tabs;1]
- tabheader[0,6;10,0.5;tabs_size1;Height=0.5;1;false;false]
- tabheader[2,6;10,0.75;tabs_size1;Height=0.75;1;false;false]
- tabheader[4,6;10,1;tabs_size2;Height=1;1;false;false]
- tabheader[6,6;10,1.25;tabs_size2;Height=1.25;1;false;false]
- tabheader[8,6;10,1.5;tabs_size2;Height=1.5;1;false;false]
-]]
-
-local hypertext_basic = [[
-<bigger>Normal test</bigger>
-This is a normal text.
-
-<bigger><mono>style</mono> test</bigger>
-<style color=#FFFF00>Yellow text.</style> <style color=#FF0000>Red text.</style>
-<style size=24>Size 24.</style> <style size=16>Size 16</style>. <style size=12>Size 12.</style>
-<style font=normal>Normal font.</style> <style font=mono>Mono font.</style>
-
-<bigger>Tag test</bigger>
-<normal>normal</normal>
-<mono>mono</mono>
-<b>bold</b>
-<i>italic</i>
-<u>underlined</u>
-<big>big</big>
-<bigger>bigger</bigger>
-<left>left</left>
-<center>center</center>
-<right>right</right>
-<justify>justify. Here comes a blind text: Lorem testum dolor sit amet consecutor celeron fiftifahivus e shadoninia e smalus jokus anrus relsocutoti rubenwardus. Erasputinus hara holisti dominus wusi. Grumarinsti erltusmuate ol fortitusti fla flo, blani burki e sfani fahif. Ultae ratii, e megus gigae don anonimus. Grinus dimondus krockus e nore. Endus finalus nowus comus endus o blindus tekstus.</justify>
-
-<bigger>Custom tag test</bigger>
-<tag name=t_green color=green>
-<tag name=t_hover hovercolor=yellow>
-<tag name=t_size size=24>
-<tag name=t_mono font=mono>
-<tag name=t_multi color=green font=mono size=24>
-<t_green>color=green</t_green>
-Action: <action name=color><t_green>color=green</t_green></action>
-Action: <action name=hovercolor><t_hover>hovercolor=yellow</t_hover></action>
-<t_size>size=24</t_size>
-<t_mono>font=mono</t_mono>
-<t_multi>color=green font=mono size=24</t_multi>
-
-<bigger><mono>action</mono> test</bigger>
-<action name=action_test>action</action>
-
-<bigger><mono>img</mono> test</bigger>
-Normal:
-<img name=testformspec_item.png>
-<mono>width=48 height=48</mono>:
-<img name=testformspec_item.png width=48 height=48>
-<mono>float=left</mono>:
-<img name=testformspec_item.png float=left>
-<mono>float=right</mono>:
-<img name=testformspec_item.png float=right>
-
-<bigger><mono>item</mono> test</bigger>
-Normal:
-<item name=testformspec:node>
-<mono>width=48 height=48</mono>
-<item name=testformspec:node width=48 height=48>
-<mono>angle=30,0,0</mono>:
-<item name=testformspec:node angle=30,0,0>
-<mono>angle=0,30,0</mono>:
-<item name=testformspec:node angle=0,30,0>
-<mono>angle=0,0,30</mono>:
-<item name=testformspec:node angle=0,0,30>
-<mono>rotate=yes</mono>:
-<item name=testformspec:node rotate=yes>
-<mono>rotate=100,0,0</mono>:
-<item name=testformspec:node rotate=100,0,0>
-<mono>rotate=0,100,0</mono>:
-<item name=testformspec:node rotate=0,100,0>
-<mono>rotate=0,0,100</mono>:
-<item name=testformspec:node rotate=0,0,100>
-<mono>rotate=50,75,100</mono>:
-<item name=testformspec:node rotate=50,75,100>
-<mono>angle=-30,-45,90 rotate=100,150,-50</mono>:
-<item name=testformspec:node angle=-30,-45,90 rotate=100,150,-50>]]
-
-local hypertext_global = [[
-<global background=gray margin=20 valign=bottom halign=right color=pink hovercolor=purple size=12 font=mono>
-This is a test of the global tag. The parameters are:
-background=gray margin=20 valign=bottom halign=right color=pink hovercolor=purple size=12 font=mono
-<action name=global>action</action>]]
-
-local hypertext_fs = "hypertext[0,0;11,9;hypertext;"..minetest.formspec_escape(hypertext_basic).."]"..
- "hypertext[0,9.5;11,2.5;hypertext;"..minetest.formspec_escape(hypertext_global).."]"
-
-local style_fs = [[
- style[one_btn1;bgcolor=red;textcolor=yellow;bgcolor_hovered=orange;
- bgcolor_pressed=purple]
- button[0,0;2.5,0.8;one_btn1;Button]
-
- style[one_btn2;border=false;textcolor=cyan] ]]..
- "button[0,1.05;2.5,0.8;one_btn2;Text " .. color("#FF0", "Yellow") .. [[]
-
- style[one_btn3;bgimg=testformspec_button_image.png;bgimg_hovered=testformspec_hovered.png;
- bgimg_pressed=testformspec_pressed.png]
- button[0,2.1;1,1;one_btn3;Border]
-
- style[one_btn4;bgimg=testformspec_button_image.png;bgimg_hovered=testformspec_hovered.png;
- bgimg_pressed=testformspec_pressed.png;border=false]
- button[1.25,2.1;1,1;one_btn4;NoBor]
-
- style[one_btn5;bgimg=testformspec_button_image.png;bgimg_hovered=testformspec_hovered.png;
- bgimg_pressed=testformspec_pressed.png;border=false;alpha=false]
- button[0,3.35;1,1;one_btn5;Alph]
-
- style[one_btn6;border=true]
- image_button[0,4.6;1,1;testformspec_button_image.png;one_btn6;Border]
-
- style[one_btn7;border=false]
- image_button[1.25,4.6;1,1;testformspec_button_image.png;one_btn7;NoBor]
-
- style[one_btn8;border=false]
- image_button[0,5.85;1,1;testformspec_button_image.png;one_btn8;Border;false;true;testformspec_pressed.png]
-
- style[one_btn9;border=true]
- image_button[1.25,5.85;1,1;testformspec_button_image.png;one_btn9;NoBor;false;false;testformspec_pressed.png]
-
- style[one_btn10;alpha=false]
- image_button[0,7.1;1,1;testformspec_button_image.png;one_btn10;NoAlpha]
-
- style[one_btn11;alpha=true]
- image_button[1.25,7.1;1,1;testformspec_button_image.png;one_btn11;Alpha]
-
- style[one_btn12;border=true]
- item_image_button[0,8.35;1,1;testformspec:item;one_btn12;Border]
-
- style[one_btn13;border=false]
- item_image_button[1.25,8.35;1,1;testformspec:item;one_btn13;NoBor]
-
- style[one_btn14;border=false;bgimg=testformspec_bg.png;fgimg=testformspec_button_image.png]
- style[one_btn14:hovered;bgimg=testformspec_bg_hovered.png;fgimg=testformspec_hovered.png;textcolor=yellow]
- style[one_btn14:pressed;bgimg=testformspec_bg_pressed.png;fgimg=testformspec_pressed.png;textcolor=blue]
- style[one_btn14:hovered+pressed;textcolor=purple]
- image_button[0,9.6;1,1;testformspec_button_image.png;one_btn14;Bg]
-
- style[one_btn15;border=false;bgimg=testformspec_bg.png;bgimg_hovered=testformspec_bg_hovered.png;bgimg_pressed=testformspec_bg_pressed.png]
- item_image_button[1.25,9.6;1,1;testformspec:item;one_btn15;Bg]
-
- style[one_btn16;border=false;bgimg=testformspec_bg_9slice.png;bgimg_hovered=testformspec_bg_9slice_hovered.png;bgimg_pressed=testformspec_bg_9slice_pressed.png;bgimg_middle=4,6]
- button[2.5,9.6;2,1;one_btn16;9-Slice Bg]
-
-
-
- container[2.75,0]
-
- style[one_tb1;textcolor=Yellow]
- tabheader[0,3;2.5,0.63;one_tb1;Yellow,Text,Tabs;1;false;false]
-
- style[one_f1;textcolor=yellow]
- field[0,4.25;2.5,0.8;one_f1;Field One;Yellow Text]
-
- style[one_f2;border=false;textcolor=cyan]
- field[0,5.75;2.5,0.8;one_f2;Field Two;Borderless Cyan Text]
-
- style[one_f3;textcolor=yellow]
- textarea[0,7.025;2.5,0.8;one_f3;Label;]] ..
- minetest.formspec_escape("Yellow Text\nLine two") .. [[ ]
-
- style[one_f4;border=false;textcolor=cyan]
- textarea[0,8.324999999999999;2.5,0.8;one_f4;Label;]] ..
- minetest.formspec_escape("Borderless Cyan Text\nLine two") .. [[ ]
-
- container_end[]
-]]
-
-local scroll_fs =
- "button[8.5,1;4,1;outside;Outside of container]"..
- "box[1,1;8,6;#00aa]"..
- "scroll_container[1,1;8,6;scrbar;vertical]"..
- "button[0,1;1,1;lorem;Lorem]"..
- "button[0,10;1,1;ipsum;Ipsum]"..
- "pwdfield[2,2;1,1;lorem2;Lorem]"..
- "list[current_player;main;4,4;1,5;]"..
- "box[2,5;3,2;#ffff00]"..
- "image[1,10;3,2;testformspec_item.png]"..
- "image[3,1;testformspec_item.png]"..
- "item_image[2,6;3,2;testformspec:node]"..
- "label[2,15;bla Bli\nfoo bar]"..
- "item_image_button[2,3;1,1;testformspec:node;itemimagebutton;ItemImageButton]"..
- "tooltip[0,11;3,2;Buz;#f00;#000]"..
- "box[0,11;3,2;#00ff00]"..
- "hypertext[3,13;3,3;;" .. hypertext_basic .. "]" ..
- "container[0,18]"..
- "box[1,2;3,2;#0a0a]"..
- "scroll_container[1,2;3,2;scrbar2;horizontal;0.06]"..
- "button[0,0;6,1;butnest;Nest]"..
- "label[10,0.5;nest]"..
- "scroll_container_end[]"..
- "scrollbar[1,0;3.5,0.3;horizontal;scrbar2;0]"..
- "container_end[]"..
- "dropdown[0,6;2;hmdrpdwn;apple,bulb;1]"..
- "image_button[0,4;2,2;testformspec_button_image.png;imagebutton;bbbbtt;false;true;testformspec_pressed.png]"..
- "box[1,22.5;4,1;#a00a]"..
- "scroll_container_end[]"..
- "scrollbaroptions[max=170]".. -- lowest seen pos is: 0.1*170+6=23 (factor*max+height)
- "scrollbar[7.5,0;0.3,4;vertical;scrbar;0]"..
- "scrollbar[8,0;0.3,4;vertical;scrbarhmmm;0]"..
- "dropdown[0,6;2;hmdrpdwnnn;Outside,of,container;1]"
-
---style_type[label;textcolor=green]
---label[0,0;Green]
---style_type[label;textcolor=blue]
---label[0,1;Blue]
---style_type[label;textcolor=;border=true]
---label[1.2,0;Border]
---style_type[label;border=true;bgcolor=red]
---label[1.2,1;Background]
---style_type[label;border=;bgcolor=]
---label[0.75,2;Reset]
-
-
-local pages = {
- -- Real Coordinates
- [[
- formspec_version[3]
- size[12,13]
- image_button[0,0;1,1;logo.png;rc_image_button_1x1;1x1]
- image_button[1,0;2,2;logo.png;rc_image_button_2x2;2x2]
- button[0,2;1,1;rc_button_1x1;1x1]
- button[1,2;2,2;rc_button_2x2;2x2]
- item_image[0,4;1,1;air]
- item_image[1,4;2,2;air]
- item_image_button[0,6;1,1;testformspec:node;rc_item_image_button_1x1;1x1]
- item_image_button[1,6;2,2;testformspec:node;rc_item_image_button_2x2;2x2]
- field[3,.5;3,.5;rc_field;Field;text]
- pwdfield[6,.5;3,1;rc_pwdfield;Password Field]
- field[3,1;3,1;;Read-Only Field;text]
- textarea[3,2;3,.5;rc_textarea_small;Textarea;text]
- textarea[6,2;3,2;rc_textarea_big;Textarea;text\nmore text]
- textarea[3,3;3,1;;Read-Only Textarea;text\nmore text]
- textlist[3,4;3,2;rc_textlist;Textlist,Perfect Coordinates;1;false]
- tableoptions[highlight=#ABCDEF75;background=#00000055;border=false]
- table[6,4;3,2;rc_table;Table,Cool Stuff,Foo,Bar;2]
- dropdown[3,6;3,1;rc_dropdown_small;This,is,a,dropdown;1]
- dropdown[6,6;3,2;rc_dropdown_big;I,am,a,bigger,dropdown;5]
- image[0,8;3,2;ignore.png]
- box[3,7;3,1;#00A3FF]
- checkbox[3,8;rc_checkbox_1;Check me!;false]
- checkbox[3,9;rc_checkbox_2;Uncheck me now!;true]
- scrollbar[0,11.5;11.5,.5;horizontal;rc_scrollbar_horizontal;500]
- scrollbar[11.5,0;.5,11.5;vertical;rc_scrollbar_vertical;0]
- list[current_player;main;6,8;3,2;1]
- button[9,0;2.5,1;rc_empty_button_1;]
- button[9,1;2.5,1;rc_empty_button_2;]
- button[9,2;2.5,1;rc_empty_button_3;] ]]..
- "label[9,0.5;This is a label.\nLine\nLine\nLine\nEnd]"..
- [[button[9,3;1,1;rc_empty_button_4;]
- vertlabel[9,4;VERT]
- label[10,3;HORIZ]
- tabheader[8,0;6,0.65;rc_tabheader;Tab 1,Tab 2,Tab 3,Secrets;1;false;false]
- ]],
- -- Style
-
- "formspec_version[3]size[12,13]" ..
- ("label[0.375,0.375;Styled - %s %s]"):format(
- color("#F00", "red text"),
- color("#77FF00CC", "green text")) ..
- "label[6.375,0.375;Unstyled]" ..
- "box[0,0.75;12,0.1;#999]" ..
- "box[6,0.85;0.1,11.15;#999]" ..
- "container[0.375,1.225]" ..
- style_fs ..
- "container_end[]container[6.375,1.225]" ..
- style_fs:gsub("one_", "two_"):gsub("style%[[^%]]+%]", ""):gsub("style_type%[[^%]]+%]", "") ..
- "container_end[]",
-
- -- Noclip
- "formspec_version[3]size[12,13]" ..
- "label[0.1,0.5;Clip]" ..
- "container[-2.5,1]" .. clip_fs:gsub("%%c", "false") .. "container_end[]" ..
- "label[11,0.5;Noclip]" ..
- "container[11.5,1]" .. clip_fs:gsub("%%c", "true") .. "container_end[]",
-
- -- Hypertext
- "size[12,13]real_coordinates[true]" ..
- "container[0.5,0.5]" .. hypertext_fs .. "container_end[]",
-
- -- Tabheaders
- "size[12,13]real_coordinates[true]" ..
- "container[0.5,1.5]" .. tabheaders_fs .. "container_end[]",
-
- -- Animation
- [[
- formspec_version[3]
- size[12,13]
- animated_image[0.5,0.5;1,1;;testformspec_animation.png;4;100]
- animated_image[0.5,1.75;1,1;;testformspec_animation.jpg;4;100]
- animated_image[1.75,0.5;1,1;;testformspec_animation.png;100;100]
- animated_image[3,0.5;1,1;ani_img_1;testformspec_animation.png;4;1000]
- button[4.25,0.5;1,1;ani_btn_1;Current
-Number]
- animated_image[3,1.75;1,1;ani_img_2;testformspec_animation.png;4;1000;2]
- button[4.25,1.75;1,1;ani_btn_2;Current
-Number]
- animated_image[3,3;1,1;;testformspec_animation.png;4;0]
- animated_image[3,4.25;1,1;;testformspec_animation.png;4;0;3]
- animated_image[5.5,0.5;5,2;;testformspec_animation.png;4;100]
- animated_image[5.5,2.75;5,2;;testformspec_animation.jpg;4;100]
- ]],
-
- -- Scroll containers
- "formspec_version[3]size[12,13]" ..
- scroll_fs,
-}
-
-local function show_test_formspec(pname, page_id)
- page_id = page_id or 2
-
- local fs = pages[page_id] .. "tabheader[0,0;8,0.65;maintabs;Real Coord,Styles,Noclip,Hypertext,Tabs,Anim,ScrollC;" .. page_id .. ";false;false]"
-
- minetest.show_formspec(pname, "testformspec:formspec", fs)
-end
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- if formname ~= "testformspec:formspec" then
- return false
- end
-
-
- if fields.maintabs then
- show_test_formspec(player:get_player_name(), tonumber(fields.maintabs))
- return true
- end
-
- if fields.ani_img_1 and fields.ani_btn_1 then
- minetest.chat_send_player(player:get_player_name(), "ani_img_1 = " .. tostring(fields.ani_img_1))
- return true
- elseif fields.ani_img_2 and fields.ani_btn_2 then
- minetest.chat_send_player(player:get_player_name(), "ani_img_2 = " .. tostring(fields.ani_img_2))
- return true
- end
-
- if fields.hypertext then
- minetest.chat_send_player(player:get_player_name(), "Hypertext action received: " .. tostring(fields.hypertext))
- return true
- end
-end)
-
-minetest.register_chatcommand("test_formspec", {
- params = "",
- description = "Open the test formspec",
- func = function(name)
- if not minetest.get_player_by_name(name) then
- return false, "You need to be online!"
- end
-
- show_test_formspec(name)
- return true
- end,
-})
+++ /dev/null
-dofile(minetest.get_modpath("testformspec").."/dummy_items.lua")
-dofile(minetest.get_modpath("testformspec").."/formspec.lua")
-dofile(minetest.get_modpath("testformspec").."/callbacks.lua")
+++ /dev/null
-name = testformspec
-description = Contains an example formspec to test all the features of formspecs
+++ /dev/null
-# Test Nodes
-
-This mod contains a bunch of basic nodes to test development stuff.
-Most nodes are kept as minimal as possible in order to show off one particular feature of the engine, to make testing stuff easier.
-
-This mod includes tests for:
-
-* drawtypes
-* paramtype2's
-* node properties such as damage, drowning, falling, etc.
-* other random stuff
+++ /dev/null
---[[ Drawtype Test: This file tests out and provides examples for
-all drawtypes in Minetest. It is attempted to keep the node
-definitions as simple and minimal as possible to keep
-side-effects to a minimum.
-
-How to read the node definitions:
-There are two parts which are separated by 2 newlines:
-The first part contains the things that are more or less essential
-for defining the drawtype (except description, which is
-at the top for readability).
-The second part (after the 2 newlines) contains stuff that are
-unrelated to the drawtype, stuff that is mostly there to make
-testing this node easier and more convenient.
-]]
-
-local S = minetest.get_translator("testnodes")
-
--- If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
--- This is due to <https://github.com/minetest/minetest/issues/9209>.
--- This is only added to make the items more visible to avoid confusion, but you will no longer see
--- the default inventory images for these items. When you want to test the default inventory image of drawtypes,
--- this should be turned off.
--- TODO: Remove support for fallback inventory image as soon #9209 is fixed.
-local SHOW_FALLBACK_IMAGE = minetest.settings:get_bool("testnodes_show_fallback_image", false)
-
-local fallback_image = function(img)
- if SHOW_FALLBACK_IMAGE then
- return img
- else
- return nil
- end
-end
-
--- A regular cube
-minetest.register_node("testnodes:normal", {
- description = S("Normal Drawtype Test Node"),
- drawtype = "normal",
- tiles = { "testnodes_normal.png" },
-
- groups = { dig_immediate = 3 },
-})
-
--- Standard glasslike node
-minetest.register_node("testnodes:glasslike", {
- description = S("Glasslike Drawtype Test Node"),
- drawtype = "glasslike",
- paramtype = "light",
- tiles = { "testnodes_glasslike.png" },
-
- groups = { dig_immediate = 3 },
-})
-
--- Glasslike framed with the two textures (normal and "detail")
-minetest.register_node("testnodes:glasslike_framed", {
- description = S("Glasslike Framed Drawtype Test Node"),
- drawtype = "glasslike_framed",
- paramtype = "light",
- tiles = {
- "testnodes_glasslike_framed.png",
- "testnodes_glasslike_detail.png",
- },
-
-
- sunlight_propagates = true,
- groups = { dig_immediate = 3 },
-})
-
--- Like the one above, but without the "detail" texture (texture 2).
--- This node was added to see how the engine behaves when the "detail" texture
--- is missing.
-minetest.register_node("testnodes:glasslike_framed_no_detail", {
- description = S("Glasslike Framed without Detail Drawtype Test Node"),
- drawtype = "glasslike_framed",
- paramtype = "light",
- tiles = { "testnodes_glasslike_framed2.png" },
-
-
- sunlight_propagates = true,
- groups = { dig_immediate = 3 },
-})
-
-
-minetest.register_node("testnodes:glasslike_framed_optional", {
- description = S("Glasslike Framed Optional Drawtype Test Node"),
- drawtype = "glasslike_framed_optional",
- paramtype = "light",
- tiles = {
- "testnodes_glasslike_framed_optional.png",
- "testnodes_glasslike_detail.png",
- },
-
-
- sunlight_propagates = true,
- groups = { dig_immediate = 3 },
-})
-
-
-
-minetest.register_node("testnodes:allfaces", {
- description = S("Allfaces Drawtype Test Node"),
- drawtype = "allfaces",
- paramtype = "light",
- tiles = { "testnodes_allfaces.png" },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:allfaces_optional", {
- description = S("Allfaces Optional Drawtype Test Node"),
- drawtype = "allfaces_optional",
- paramtype = "light",
- tiles = { "testnodes_allfaces_optional.png" },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:allfaces_optional_waving", {
- description = S("Waving Allfaces Optional Drawtype Test Node"),
- drawtype = "allfaces_optional",
- paramtype = "light",
- tiles = { "testnodes_allfaces_optional.png^[brighten" },
- waving = 2,
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:firelike", {
- description = S("Firelike Drawtype Test Node"),
- drawtype = "firelike",
- paramtype = "light",
- tiles = { "testnodes_firelike.png" },
-
-
- walkable = false,
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:fencelike", {
- description = S("Fencelike Drawtype Test Node"),
- drawtype = "fencelike",
- paramtype = "light",
- tiles = { "testnodes_fencelike.png" },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:torchlike", {
- description = S("Wallmounted Torchlike Drawtype Test Node"),
- drawtype = "torchlike",
- paramtype = "light",
- paramtype2 = "wallmounted",
- tiles = {
- "testnodes_torchlike_floor.png",
- "testnodes_torchlike_ceiling.png",
- "testnodes_torchlike_wall.png",
- },
-
-
- walkable = false,
- sunlight_propagates = true,
- groups = { dig_immediate = 3 },
- inventory_image = fallback_image("testnodes_torchlike_floor.png"),
-})
-
-minetest.register_node("testnodes:signlike", {
- description = S("Wallmounted Signlike Drawtype Test Node"),
- drawtype = "signlike",
- paramtype = "light",
- paramtype2 = "wallmounted",
- tiles = { "testnodes_signlike.png" },
-
-
- walkable = false,
- groups = { dig_immediate = 3 },
- sunlight_propagates = true,
- inventory_image = fallback_image("testnodes_signlike.png"),
-})
-
-minetest.register_node("testnodes:plantlike", {
- description = S("Plantlike Drawtype Test Node"),
- drawtype = "plantlike",
- paramtype = "light",
- tiles = { "testnodes_plantlike.png" },
-
-
- walkable = false,
- sunlight_propagates = true,
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:plantlike_waving", {
- description = S("Waving Plantlike Drawtype Test Node"),
- drawtype = "plantlike",
- paramtype = "light",
- tiles = { "testnodes_plantlike_waving.png" },
- waving = 1,
-
-
- walkable = false,
- sunlight_propagates = true,
- groups = { dig_immediate = 3 },
-})
-
-
-
--- param2 will rotate
-minetest.register_node("testnodes:plantlike_degrotate", {
- description = S("Degrotate Plantlike Drawtype Test Node"),
- drawtype = "plantlike",
- paramtype = "light",
- paramtype2 = "degrotate",
- tiles = { "testnodes_plantlike_degrotate.png" },
-
-
- walkable = false,
- sunlight_propagates = true,
- groups = { dig_immediate = 3 },
-})
-
--- param2 will change height
-minetest.register_node("testnodes:plantlike_leveled", {
- description = S("Leveled Plantlike Drawtype Test Node"),
- drawtype = "plantlike",
- paramtype = "light",
- paramtype2 = "leveled",
- tiles = {
- { name = "testnodes_plantlike_leveled.png", tileable_vertical = true },
- },
-
-
- -- We set a default param2 here only for convenience, to make the "plant" visible after placement
- place_param2 = 8,
- walkable = false,
- sunlight_propagates = true,
- groups = { dig_immediate = 3 },
-})
-
--- param2 changes shape
-minetest.register_node("testnodes:plantlike_meshoptions", {
- description = S("Meshoptions Plantlike Drawtype Test Node"),
- drawtype = "plantlike",
- paramtype = "light",
- paramtype2 = "meshoptions",
- tiles = { "testnodes_plantlike_meshoptions.png" },
-
-
- walkable = false,
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:plantlike_rooted", {
- description = S("Rooted Plantlike Drawtype Test Node"),
- drawtype = "plantlike_rooted",
- paramtype = "light",
- tiles = { "testnodes_plantlike_rooted_base.png" },
- special_tiles = { "testnodes_plantlike_rooted.png" },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:plantlike_rooted_waving", {
- description = S("Waving Rooted Plantlike Drawtype Test Node"),
- drawtype = "plantlike_rooted",
- paramtype = "light",
- tiles = {
- "testnodes_plantlike_rooted_base.png",
- "testnodes_plantlike_rooted_base.png",
- "testnodes_plantlike_rooted_base_side_waving.png",
- },
- special_tiles = { "testnodes_plantlike_rooted_waving.png" },
- waving = 1,
-
- groups = { dig_immediate = 3 },
-})
-
--- param2 changes height
-minetest.register_node("testnodes:plantlike_rooted_leveled", {
- description = S("Leveled Rooted Plantlike Drawtype Test Node"),
- drawtype = "plantlike_rooted",
- paramtype = "light",
- paramtype2 = "leveled",
- tiles = {
- "testnodes_plantlike_rooted_base.png",
- "testnodes_plantlike_rooted_base.png",
- "testnodes_plantlike_rooted_base_side_leveled.png",
- },
- special_tiles = {
- { name = "testnodes_plantlike_rooted_leveled.png", tileable_vertical = true },
- },
-
-
- -- We set a default param2 here only for convenience, to make the "plant" visible after placement
- place_param2 = 8,
- groups = { dig_immediate = 3 },
-})
-
--- param2 changes shape
-minetest.register_node("testnodes:plantlike_rooted_meshoptions", {
- description = S("Meshoptions Rooted Plantlike Drawtype Test Node"),
- drawtype = "plantlike_rooted",
- paramtype = "light",
- paramtype2 = "meshoptions",
- tiles = {
- "testnodes_plantlike_rooted_base.png",
- "testnodes_plantlike_rooted_base.png",
- "testnodes_plantlike_rooted_base_side_meshoptions.png",
- },
- special_tiles = {
- "testnodes_plantlike_rooted_meshoptions.png",
- },
-
- groups = { dig_immediate = 3 },
-})
-
--- param2 changes rotation
-minetest.register_node("testnodes:plantlike_rooted_degrotate", {
- description = S("Degrotate Rooted Plantlike Drawtype Test Node"),
- drawtype = "plantlike_rooted",
- paramtype = "light",
- paramtype2 = "degrotate",
- tiles = {
- "testnodes_plantlike_rooted_base.png",
- "testnodes_plantlike_rooted_base.png",
- "testnodes_plantlike_rooted_base_side_degrotate.png",
- },
- special_tiles = {
- "testnodes_plantlike_rooted_degrotate.png",
- },
-
- groups = { dig_immediate = 3 },
-})
-
--- Demonstrative liquid nodes, source and flowing form. This is only the
--- drawtype, no physical liquid properties are used
-minetest.register_node("testnodes:liquid", {
- description = S("Source Liquid Drawtype Test Node"),
- drawtype = "liquid",
- paramtype = "light",
- tiles = {
- "testnodes_liquidsource.png",
- },
- special_tiles = {
- {name="testnodes_liquidsource.png", backface_culling=false},
- {name="testnodes_liquidsource.png", backface_culling=true},
- },
- use_texture_alpha = true,
-
-
- walkable = false,
- liquid_alternative_flowing = "testnodes:liquid_flowing",
- liquid_alternative_source = "testnodes:liquid",
- groups = { dig_immediate = 3 },
-})
-minetest.register_node("testnodes:liquid_flowing", {
- description = S("Flowing Liquid Drawtype Test Node"),
- drawtype = "flowingliquid",
- paramtype = "light",
- paramtype2 = "flowingliquid",
- tiles = {
- "testnodes_liquidflowing.png",
- },
- special_tiles = {
- {name="testnodes_liquidflowing.png", backface_culling=false},
- {name="testnodes_liquidflowing.png", backface_culling=false},
- },
- use_texture_alpha = true,
-
-
- walkable = false,
- liquid_alternative_flowing = "testnodes:liquid_flowing",
- liquid_alternative_source = "testnodes:liquid",
- groups = { dig_immediate = 3 },
-})
-minetest.register_node("testnodes:liquid_waving", {
- description = S("Waving Source Liquid Drawtype Test Node"),
- drawtype = "liquid",
- paramtype = "light",
- tiles = {
- "testnodes_liquidsource.png^[brighten",
- },
- special_tiles = {
- {name="testnodes_liquidsource.png^[brighten", backface_culling=false},
- {name="testnodes_liquidsource.png^[brighten", backface_culling=true},
- },
- use_texture_alpha = true,
- waving = 3,
-
-
- walkable = false,
- liquid_alternative_flowing = "testnodes:liquid_flowing",
- liquid_alternative_source = "testnodes:liquid",
- groups = { dig_immediate = 3 },
-})
-minetest.register_node("testnodes:liquid_flowing_waving", {
- description = S("Waving Flowing Liquid Drawtype Test Node"),
- drawtype = "flowingliquid",
- paramtype = "light",
- paramtype2 = "flowingliquid",
- tiles = {
- "testnodes_liquidflowing.png^[brighten",
- },
- special_tiles = {
- {name="testnodes_liquidflowing.png^[brighten", backface_culling=false},
- {name="testnodes_liquidflowing.png^[brighten", backface_culling=false},
- },
- use_texture_alpha = true,
- waving = 3,
-
-
- walkable = false,
- liquid_alternative_flowing = "testnodes:liquid_flowing",
- liquid_alternative_source = "testnodes:liquid",
- groups = { dig_immediate = 3 },
-})
-
-
-
--- Invisible node
-minetest.register_node("testnodes:airlike", {
- description = S("Airlike Drawtype Test Node"),
- drawtype = "airlike",
- paramtype = "light",
-
-
- walkable = false,
- groups = { dig_immediate = 3 },
- sunlight_propagates = true,
- inventory_image = fallback_image("testnodes_airlike.png"),
-})
-
--- param2 changes liquid height
-minetest.register_node("testnodes:glassliquid", {
- description = S("Glasslike Liquid Level Drawtype Test Node"),
- drawtype = "glasslike_framed",
- paramtype = "light",
- paramtype2 = "glasslikeliquidlevel",
- tiles = {
- "testnodes_glasslikeliquid.png",
- },
- special_tiles = {
- "testnodes_liquid.png",
- },
-
- groups = { dig_immediate = 3 },
-})
-
--- Adding many raillike examples, primarily to demonstrate the behavior of
--- "raillike groups". Nodes of the same type (rail, groupless, line, street)
--- should connect to nodes of the same "rail type" (=same shape, different
--- color) only.
-local rails = {
- { "rail", {"testnodes_rail_straight.png", "testnodes_rail_curved.png", "testnodes_rail_t_junction.png", "testnodes_rail_crossing.png"} },
- { "line", {"testnodes_line_straight.png", "testnodes_line_curved.png", "testnodes_line_t_junction.png", "testnodes_line_crossing.png"}, },
- { "street", {"testnodes_street_straight.png", "testnodes_street_curved.png", "testnodes_street_t_junction.png", "testnodes_street_crossing.png"}, },
- -- the "groupless" nodes are nodes in which the "connect_to_raillike" group is not set
- { "groupless", {"testnodes_rail2_straight.png", "testnodes_rail2_curved.png", "testnodes_rail2_t_junction.png", "testnodes_rail2_crossing.png"} },
-}
-local colors = { "", "cyan", "red" }
-
-for r=1, #rails do
- local id = rails[r][1]
- local tiles = rails[r][2]
- local raillike_group
- if id ~= "groupless" then
- raillike_group = minetest.raillike_group(id)
- end
- for c=1, #colors do
- local color
- if colors[c] ~= "" then
- color = colors[c]
- end
- minetest.register_node("testnodes:raillike_"..id..c, {
- description = S("Raillike Drawtype Test Node: @1 @2", id, c),
- drawtype = "raillike",
- paramtype = "light",
- tiles = tiles,
- groups = { connect_to_raillike = raillike_group, dig_immediate = 3 },
-
-
- color = color,
- selection_box = {
- type = "fixed",
- fixed = {{-0.5, -0.5, -0.5, 0.5, -0.4, 0.5}},
- },
- sunlight_propagates = true,
- walkable = false,
- })
- end
-end
-
-
-
--- Add visual_scale variants of previous nodes for half and double size
-local scale = function(subname, desc_double, desc_half)
- local original = "testnodes:"..subname
- local def = table.copy(minetest.registered_items[original])
- def.visual_scale = 2.0
- def.description = desc_double
- minetest.register_node("testnodes:"..subname.."_double", def)
- def = table.copy(minetest.registered_items[original])
- def.visual_scale = 0.5
- def.description = desc_half
- minetest.register_node("testnodes:"..subname.."_half", def)
-end
-
-scale("plantlike",
- S("Double-sized Plantlike Drawtype Test Node"),
- S("Half-sized Plantlike Drawtype Test Node"))
-scale("torchlike",
- S("Double-sized Wallmounted Torchlike Drawtype Test Node"),
- S("Half-sized Wallmounted Torchlike Drawtype Test Node"))
-scale("signlike",
- S("Double-sized Wallmounted Signlike Drawtype Test Node"),
- S("Half-sized Wallmounted Signlike Drawtype Test Node"))
-scale("firelike",
- S("Double-sized Firelike Drawtype Test Node"),
- S("Half-sized Firelike Drawtype Test Node"))
+++ /dev/null
-local path = minetest.get_modpath(minetest.get_current_modname())
-
-dofile(path.."/drawtypes.lua")
-dofile(path.."/meshes.lua")
-dofile(path.."/nodeboxes.lua")
-dofile(path.."/param2.lua")
-dofile(path.."/properties.lua")
-dofile(path.."/liquids.lua")
-dofile(path.."/light.lua")
-dofile(path.."/textures.lua")
+++ /dev/null
--- Test Nodes: Light test
-
-local S = minetest.get_translator("testnodes")
-
--- All possible light levels
-for i=1, minetest.LIGHT_MAX do
- minetest.register_node("testnodes:light"..i, {
- description = S("Light Source (@1)", i),
- paramtype = "light",
- light_source = i,
-
-
- tiles ={"testnodes_light_"..i..".png"},
- drawtype = "glasslike",
- walkable = false,
- sunlight_propagates = true,
- is_ground_content = false,
- groups = {dig_immediate=3},
- })
-end
-
--- Lets light through, but not sunlight, leading to a
--- reduction in light level when light passes through
-minetest.register_node("testnodes:sunlight_filter", {
- description = S("Sunlight Filter"),
- paramtype = "light",
-
-
- drawtype = "glasslike",
- tiles = {
- "testnodes_sunlight_filter.png",
- },
- groups = { dig_immediate = 3 },
-})
-
--- Lets light and sunlight through without obstruction
-minetest.register_node("testnodes:sunlight_propagator", {
- description = S("Sunlight Propagator"),
- paramtype = "light",
- sunlight_propagates = true,
-
-
- drawtype = "glasslike",
- tiles = {
- "testnodes_sunlight_filter.png^[brighten",
- },
- groups = { dig_immediate = 3 },
-})
+++ /dev/null
--- Add liquids for ranges and viscosity levels 0-8
-
-for d=0, 8 do
- minetest.register_node("testnodes:rliquid_"..d, {
- description = "Test Liquid Source, Range "..d,
- drawtype = "liquid",
- tiles = {"testnodes_liquidsource_r"..d..".png"},
- special_tiles = {
- {name = "testnodes_liquidsource_r"..d..".png", backface_culling = false},
- {name = "testnodes_liquidsource_r"..d..".png", backface_culling = true},
- },
- alpha = 192,
- paramtype = "light",
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- liquidtype = "source",
- liquid_alternative_flowing = "testnodes:rliquid_flowing_"..d,
- liquid_alternative_source = "testnodes:rliquid_"..d,
- liquid_range = d,
- })
-
- minetest.register_node("testnodes:rliquid_flowing_"..d, {
- description = "Flowing Test Liquid, Range "..d,
- drawtype = "flowingliquid",
- tiles = {"testnodes_liquidflowing_r"..d..".png"},
- special_tiles = {
- {name = "testnodes_liquidflowing_r"..d..".png", backface_culling = false},
- {name = "testnodes_liquidflowing_r"..d..".png", backface_culling = false},
- },
- alpha = 192,
- paramtype = "light",
- paramtype2 = "flowingliquid",
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- liquidtype = "flowing",
- liquid_alternative_flowing = "testnodes:rliquid_flowing_"..d,
- liquid_alternative_source = "testnodes:rliquid_"..d,
- liquid_range = d,
- })
-
- local mod = "^[colorize:#000000:127"
- minetest.register_node("testnodes:vliquid_"..d, {
- description = "Test Liquid Source, Viscosity "..d,
- drawtype = "liquid",
- tiles = {"testnodes_liquidsource_r"..d..".png"..mod},
- special_tiles = {
- {name = "testnodes_liquidsource_r"..d..".png"..mod, backface_culling = false},
- {name = "testnodes_liquidsource_r"..d..".png"..mod, backface_culling = true},
- },
- alpha = 192,
- paramtype = "light",
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- liquidtype = "source",
- liquid_alternative_flowing = "testnodes:vliquid_flowing_"..d,
- liquid_alternative_source = "testnodes:vliquid_"..d,
- liquid_viscosity = d,
- })
-
- minetest.register_node("testnodes:vliquid_flowing_"..d, {
- description = "Flowing Test Liquid, Viscosity "..d,
- drawtype = "flowingliquid",
- tiles = {"testnodes_liquidflowing_r"..d..".png"..mod},
- special_tiles = {
- {name = "testnodes_liquidflowing_r"..d..".png"..mod, backface_culling = false},
- {name = "testnodes_liquidflowing_r"..d..".png"..mod, backface_culling = false},
- },
- alpha = 192,
- paramtype = "light",
- paramtype2 = "flowingliquid",
- walkable = false,
- pointable = false,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- liquidtype = "flowing",
- liquid_alternative_flowing = "testnodes:vliquid_flowing_"..d,
- liquid_alternative_source = "testnodes:vliquid_"..d,
- liquid_viscosity = d,
- })
-
-end
+++ /dev/null
--- Meshes
-
-local S = minetest.get_translator("testnodes")
-
-local ocorner_cbox = {
- type = "fixed",
- fixed = {
- {-0.5, -0.5, -0.5, 0.5, -0.25, 0.5},
- {-0.5, -0.25, -0.25, 0.25, 0, 0.5},
- {-0.5, 0, 0, 0, 0.25, 0.5},
- {-0.5, 0.25, 0.25, -0.25, 0.5, 0.5}
- }
-}
-
-local tall_pyr_cbox = {
- type = "fixed",
- fixed = {
- { -0.5, -0.5, -0.5, 0.5, -0.25, 0.5 },
- { -0.375, -0.25, -0.375, 0.375, 0, 0.375},
- { -0.25, 0, -0.25, 0.25, 0.25, 0.25},
- { -0.125, 0.25, -0.125, 0.125, 0.5, 0.125}
- }
-}
-
--- Normal mesh
-minetest.register_node("testnodes:mesh", {
- description = S("Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_pyramid.obj",
- tiles = {"testnodes_mesh_stripes2.png"},
- paramtype = "light",
- collision_box = tall_pyr_cbox,
-
- groups = {dig_immediate=3},
-})
-
--- Facedir mesh: outer corner slope
-minetest.register_node("testnodes:mesh_facedir", {
- description = S("Facedir Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_ocorner.obj",
- tiles = {"testnodes_mesh_stripes.png"},
- paramtype = "light",
- paramtype2 = "facedir",
- collision_box = ocorner_cbox,
-
- groups = {dig_immediate=3},
-})
-
-minetest.register_node("testnodes:mesh_colorfacedir", {
- description = S("Color Facedir Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_ocorner.obj",
- tiles = {"testnodes_mesh_stripes3.png"},
- paramtype = "light",
- paramtype2 = "colorfacedir",
- palette = "testnodes_palette_facedir.png",
- collision_box = ocorner_cbox,
-
- groups = {dig_immediate=3},
-})
-
--- Wallmounted mesh: pyramid
-minetest.register_node("testnodes:mesh_wallmounted", {
- description = S("Wallmounted Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_pyramid.obj",
- tiles = {"testnodes_mesh_stripes2.png"},
- paramtype = "light",
- paramtype2 = "wallmounted",
- collision_box = tall_pyr_cbox,
-
- groups = {dig_immediate=3},
-})
-
-minetest.register_node("testnodes:mesh_colorwallmounted", {
- description = S("Color Wallmounted Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_pyramid.obj",
- tiles = {"testnodes_mesh_stripes3.png"},
- paramtype = "light",
- paramtype2 = "colorwallmounted",
- palette = "testnodes_palette_wallmounted.png",
- collision_box = tall_pyr_cbox,
-
- groups = {dig_immediate=3},
-})
-
-
-minetest.register_node("testnodes:mesh_double", {
- description = S("Double-sized Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_pyramid.obj",
- tiles = {"testnodes_mesh_stripes2.png"},
- paramtype = "light",
- collision_box = tall_pyr_cbox,
- visual_scale = 2,
-
- groups = {dig_immediate=3},
-})
-minetest.register_node("testnodes:mesh_half", {
- description = S("Half-sized Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_pyramid.obj",
- tiles = {"testnodes_mesh_stripes2.png"},
- paramtype = "light",
- collision_box = tall_pyr_cbox,
- visual_scale = 0.5,
-
- groups = {dig_immediate=3},
-})
-
-minetest.register_node("testnodes:mesh_waving1", {
- description = S("Plantlike-waving Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_pyramid.obj",
- tiles = {"testnodes_mesh_stripes4.png^[multiply:#B0FFB0"},
- paramtype = "light",
- collision_box = tall_pyr_cbox,
- waving = 1,
-
- groups = {dig_immediate=3},
-})
-minetest.register_node("testnodes:mesh_waving2", {
- description = S("Leaflike-waving Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_pyramid.obj",
- tiles = {"testnodes_mesh_stripes4.png^[multiply:#FFFFB0"},
- paramtype = "light",
- collision_box = tall_pyr_cbox,
- waving = 2,
-
- groups = {dig_immediate=3},
-})
-minetest.register_node("testnodes:mesh_waving3", {
- description = S("Liquidlike-waving Mesh Test Node"),
- drawtype = "mesh",
- mesh = "testnodes_pyramid.obj",
- tiles = {"testnodes_mesh_stripes4.png^[multiply:#B0B0FF"},
- paramtype = "light",
- collision_box = tall_pyr_cbox,
- waving = 3,
-
- groups = {dig_immediate=3},
-})
+++ /dev/null
-name = testnodes
-description = Contains a bunch of basic example nodes for demonstrative purposes, development and testing
+++ /dev/null
-# Blender v2.73 (sub 0) OBJ File: 'slope_test_ocorner_onetexture.blend'
-# www.blender.org
-o Cube_Cube.002
-v 0.500000 0.500000 0.500000
-v -0.500000 -0.500000 0.500000
-v 0.500000 -0.500000 0.500000
-v -0.500000 -0.500000 -0.500000
-v 0.500000 -0.500000 -0.500000
-vt 1.000000 1.000000
-vt 0.000000 1.000000
-vt 0.000000 0.000000
-vt 1.000000 0.000000
-vn 0.000000 -1.000000 -0.000000
-vn 1.000000 0.000000 0.000000
-vn 0.000000 -0.000000 1.000000
-vn -0.707100 0.707100 0.000000
-vn 0.000000 0.707100 -0.707100
-s off
-f 3/1/1 2/2/1 4/3/1 5/4/1
-f 1/2/2 3/3/2 5/4/2
-f 1/1/3 2/3/3 3/4/3
-f 1/1/4 4/3/4 2/4/4
-f 1/2/5 5/3/5 4/4/5
+++ /dev/null
-# Blender v2.73 (sub 0) OBJ File: 'slope_test_pyramid_onetexture.blend'
-# www.blender.org
-o Cube
-v 0.500000 -0.500000 -0.500000
-v 0.500000 -0.500000 0.500000
-v -0.500000 -0.500000 0.500000
-v -0.500000 -0.500000 -0.500000
-v -0.000000 0.500000 -0.000000
-vt 1.000000 1.000000
-vt 0.000000 1.000000
-vt 0.000000 0.000000
-vt 1.000000 0.000000
-vt 0.500000 1.000000
-vn 0.000000 -1.000000 0.000000
-vn -0.894400 0.447200 -0.000000
-vn 0.000000 0.447200 -0.894400
-vn 0.894400 0.447200 0.000000
-vn -0.000000 0.447200 0.894400
-s off
-f 1/1/1 2/2/1 3/3/1 4/4/1
-f 3/4/2 5/5/2 4/3/2
-f 5/5/3 1/3/3 4/4/3
-f 1/4/4 5/5/4 2/3/4
-f 2/4/5 5/5/5 3/3/5
+++ /dev/null
-local S = minetest.get_translator("testnodes")
-
--- Nodebox examples and tests.
-
--- An simple example nodebox with one centered box
-minetest.register_node("testnodes:nodebox_fixed", {
- description = S("Fixed Nodebox Test Node"),
- tiles = {"testnodes_nodebox.png"},
- drawtype = "nodebox",
- paramtype = "light",
- node_box = {
- type = "fixed",
- fixed = {-0.25, -0.25, -0.25, 0.25, 0.25, 0.25},
- },
-
- groups = {dig_immediate=3},
-})
-
--- 50% higher than a regular node
-minetest.register_node("testnodes:nodebox_overhigh", {
- description = S("Overhigh Nodebox Test Node"),
- tiles = {"testnodes_nodebox.png"},
- drawtype = "nodebox",
- paramtype = "light",
- node_box = {
- type = "fixed",
- fixed = {-0.5, -0.5, -0.5, 0.5, 1, 0.5},
- },
-
- groups = {dig_immediate=3},
-})
-
--- 100% higher than a regular node
-minetest.register_node("testnodes:nodebox_overhigh2", {
- description = S("Double-height Nodebox Test Node"),
- tiles = {"testnodes_nodebox.png"},
- drawtype = "nodebox",
- paramtype = "light",
- node_box = {
- type = "fixed",
- fixed = {-0.5, -0.5, -0.5, 0.5, 1.5, 0.5},
- },
-
- groups = {dig_immediate=3},
-})
-
--- Height of nodebox changes with its param2 value
-minetest.register_node("testnodes:nodebox_leveled", {
- description = S("Leveled Nodebox Test Node"),
- tiles = {"testnodes_nodebox.png"},
- drawtype = "nodebox",
- paramtype = "light",
- paramtype2 = "leveled",
- node_box = {
- type = "leveled",
- fixed = {-0.5, 0.0, -0.5, 0.5, -0.499, 0.5},
- },
-
- groups = {dig_immediate=3},
-})
-
--- Wall-like nodebox that connects to neighbors
-minetest.register_node("testnodes:nodebox_connected", {
- description = S("Connected Nodebox Test Node"),
- tiles = {"testnodes_nodebox.png"},
- groups = {connected_nodebox=1, dig_immediate=3},
- drawtype = "nodebox",
- paramtype = "light",
- connects_to = {"group:connected_nodebox"},
- connect_sides = {"front", "back", "left", "right"},
- node_box = {
- type = "connected",
- fixed = {-0.125, -0.500, -0.125, 0.125, 0.500, 0.125},
- connect_front = {-0.125, -0.500, -0.500, 0.125, 0.400, -0.125},
- connect_back = {-0.125, -0.500, 0.125, 0.125, 0.400, 0.500},
- connect_left = {-0.500, -0.500, -0.125, -0.125, 0.400, 0.125},
- connect_right = {0.125, -0.500, -0.125, 0.500, 0.400, 0.125},
- },
-})
-
+++ /dev/null
--- This file is for misc. param2 tests that aren't covered in drawtypes.lua already.
-
-local S = minetest.get_translator("testnodes")
-
-minetest.register_node("testnodes:facedir", {
- description = S("Facedir Test Node"),
- paramtype2 = "facedir",
- tiles = {
- "testnodes_1.png",
- "testnodes_2.png",
- "testnodes_3.png",
- "testnodes_4.png",
- "testnodes_5.png",
- "testnodes_6.png",
- },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:facedir_nodebox", {
- description = S("Facedir Nodebox Test Node"),
- tiles = {
- "testnodes_1.png",
- "testnodes_2.png",
- "testnodes_3.png",
- "testnodes_4.png",
- "testnodes_5.png",
- "testnodes_6.png",
- },
- drawtype = "nodebox",
- paramtype = "light",
- paramtype2 = "facedir",
- node_box = {
- type = "fixed",
- fixed = {-0.5, -0.5, -0.5, 0.2, 0.2, 0.2},
- },
-
- groups = {dig_immediate=3},
-})
-
-minetest.register_node("testnodes:wallmounted", {
- description = S("Wallmounted Test Node"),
- paramtype2 = "wallmounted",
- tiles = {
- "testnodes_1w.png",
- "testnodes_2w.png",
- "testnodes_3w.png",
- "testnodes_4w.png",
- "testnodes_5w.png",
- "testnodes_6w.png",
- },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:wallmounted_nodebox", {
- description = S("Wallmounted Nodebox Test Node"),
- paramtype2 = "wallmounted",
- paramtype = "light",
- tiles = {
- "testnodes_1w.png",
- "testnodes_2w.png",
- "testnodes_3w.png",
- "testnodes_4w.png",
- "testnodes_5w.png",
- "testnodes_6w.png",
- },
- drawtype = "nodebox",
- node_box = {
- type = "wallmounted",
- wall_top = { -0.5, 0, -0.5, 0.5, 0.5, 0.5 },
- wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 },
- wall_side = { -0.5, -0.5, -0.5, 0, 0.5, 0.5 },
- },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:color", {
- description = S("Color Test Node"),
- paramtype2 = "color",
- palette = "testnodes_palette_full.png",
- tiles = {
- "testnodes_node.png",
- },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:colorfacedir", {
- description = S("Color Facedir Test Node"),
- paramtype2 = "colorfacedir",
- palette = "testnodes_palette_facedir.png",
- tiles = {
- "testnodes_1g.png",
- "testnodes_2g.png",
- "testnodes_3g.png",
- "testnodes_4g.png",
- "testnodes_5g.png",
- "testnodes_6g.png",
- },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:colorfacedir_nodebox", {
- description = S("Color Facedir Nodebox Test Node"),
- tiles = {
- "testnodes_1g.png",
- "testnodes_2g.png",
- "testnodes_3g.png",
- "testnodes_4g.png",
- "testnodes_5g.png",
- "testnodes_6g.png",
- },
- drawtype = "nodebox",
- paramtype = "light",
- paramtype2 = "colorfacedir",
- palette = "testnodes_palette_facedir.png",
- node_box = {
- type = "fixed",
- fixed = {-0.5, -0.5, -0.5, 0.2, 0.2, 0.2},
- },
-
- groups = {dig_immediate=3},
-})
-
-minetest.register_node("testnodes:colorwallmounted", {
- description = S("Color Wallmounted Test Node"),
- paramtype2 = "colorwallmounted",
- paramtype = "light",
- palette = "testnodes_palette_wallmounted.png",
- tiles = {
- "testnodes_1wg.png",
- "testnodes_2wg.png",
- "testnodes_3wg.png",
- "testnodes_4wg.png",
- "testnodes_5wg.png",
- "testnodes_6wg.png",
- },
-
- groups = { dig_immediate = 3 },
-})
-
-minetest.register_node("testnodes:colorwallmounted_nodebox", {
- description = S("Color Wallmounted Nodebox Test Node"),
- paramtype2 = "colorwallmounted",
- paramtype = "light",
- palette = "testnodes_palette_wallmounted.png",
- tiles = {
- "testnodes_1wg.png",
- "testnodes_2wg.png",
- "testnodes_3wg.png",
- "testnodes_4wg.png",
- "testnodes_5wg.png",
- "testnodes_6wg.png",
- },
- drawtype = "nodebox",
- node_box = {
- type = "wallmounted",
- wall_top = { -0.5, 0, -0.5, 0.5, 0.5, 0.5 },
- wall_bottom = { -0.5, -0.5, -0.5, 0.5, 0, 0.5 },
- wall_side = { -0.5, -0.5, -0.5, 0, 0.5, 0.5 },
- },
-
- groups = { dig_immediate = 3 },
-})
-
+++ /dev/null
--- Test Nodes: Node property tests
-
-local S = minetest.get_translator("testnodes")
-
--- Is supposed to fall when it doesn't rest on solid ground
-minetest.register_node("testnodes:falling", {
- description = S("Falling Node"),
- tiles = {
- "testnodes_node.png",
- "testnodes_node.png",
- "testnodes_node_falling.png",
- },
- groups = { falling_node = 1, dig_immediate = 3 },
-})
-
--- Same as falling node, but will stop falling on top of liquids
-minetest.register_node("testnodes:falling_float", {
- description = S("Falling+Floating Node"),
- groups = { falling_node = 1, float = 1, dig_immediate = 3 },
-
-
- tiles = {
- "testnodes_node.png",
- "testnodes_node.png",
- "testnodes_node_falling.png",
- },
- color = "cyan",
-})
-
--- This node attaches to the floor and drops as item
--- when the floor is gone.
-minetest.register_node("testnodes:attached", {
- description = S("Floor-Attached Node"),
- tiles = {
- "testnodes_attached_top.png",
- "testnodes_attached_bottom.png",
- "testnodes_attached_side.png",
- },
- groups = { attached_node = 1, dig_immediate = 3 },
-})
-
--- This node attaches to the side of a node and drops as item
--- when the node it attaches to is gone.
-minetest.register_node("testnodes:attached_wallmounted", {
- description = S("Wallmounted Attached Node"),
- paramtype2 = "wallmounted",
- tiles = {
- "testnodes_attachedw_top.png",
- "testnodes_attachedw_bottom.png",
- "testnodes_attachedw_side.png",
- },
- groups = { attached_node = 1, dig_immediate = 3 },
-})
-
--- Jump disabled
-minetest.register_node("testnodes:nojump", {
- description = S("Non-jumping Node"),
- groups = {disable_jump=1, dig_immediate=3},
-
-
- tiles = {"testnodes_nojump_top.png", "testnodes_nojump_side.png"},
-})
-
--- Climbable up and down with jump and sneak keys
-minetest.register_node("testnodes:climbable", {
- description = S("Climbable Node"),
- climbable = true,
- walkable = false,
-
-
- paramtype = "light",
- sunlight_propagates = true,
- is_ground_content = false,
- tiles ={"testnodes_climbable_side.png"},
- drawtype = "glasslike",
- groups = {dig_immediate=3},
-})
-
--- Climbable only downwards with sneak key
-minetest.register_node("testnodes:climbable_nojump", {
- description = S("Downwards-climbable Node"),
- climbable = true,
- walkable = false,
-
- groups = {disable_jump=1, dig_immediate=3},
- drawtype = "glasslike",
- tiles ={"testnodes_climbable_nojump_side.png"},
- paramtype = "light",
- sunlight_propagates = true,
-})
-
--- A liquid in which you can't rise
-minetest.register_node("testnodes:liquid_nojump", {
- description = S("Non-jumping Liquid Source Node"),
- liquidtype = "source",
- liquid_range = 1,
- liquid_viscosity = 0,
- liquid_alternative_flowing = "testnodes:liquidflowing_nojump",
- liquid_alternative_source = "testnodes:liquid_nojump",
- liquid_renewable = false,
- groups = {disable_jump=1, dig_immediate=3},
- walkable = false,
-
- drawtype = "liquid",
- tiles = {"testnodes_liquidsource.png^[colorize:#FF0000:127"},
- special_tiles = {
- {name = "testnodes_liquidsource.png^[colorize:#FF0000:127", backface_culling = false},
- {name = "testnodes_liquidsource.png^[colorize:#FF0000:127", backface_culling = true},
- },
- use_texture_alpha = true,
- paramtype = "light",
- pointable = false,
- liquids_pointable = true,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- post_effect_color = {a = 70, r = 255, g = 0, b = 200},
-})
-
--- A liquid in which you can't rise (flowing variant)
-minetest.register_node("testnodes:liquidflowing_nojump", {
- description = S("Non-jumping Flowing Liquid Node"),
- liquidtype = "flowing",
- liquid_range = 1,
- liquid_viscosity = 0,
- liquid_alternative_flowing = "testnodes:liquidflowing_nojump",
- liquid_alternative_source = "testnodes:liquid_nojump",
- liquid_renewable = false,
- groups = {disable_jump=1, dig_immediate=3},
- walkable = false,
-
-
- drawtype = "flowingliquid",
- tiles = {"testnodes_liquidflowing.png^[colorize:#FF0000:127"},
- special_tiles = {
- {name = "testnodes_liquidflowing.png^[colorize:#FF0000:127", backface_culling = false},
- {name = "testnodes_liquidflowing.png^[colorize:#FF0000:127", backface_culling = false},
- },
- use_texture_alpha = true,
- paramtype = "light",
- paramtype2 = "flowingliquid",
- pointable = false,
- liquids_pointable = true,
- diggable = false,
- buildable_to = true,
- is_ground_content = false,
- post_effect_color = {a = 70, r = 255, g = 0, b = 200},
-})
-
--- Nodes that modify fall damage (various damage modifiers)
-for i=-100, 100, 25 do
- if i ~= 0 then
- local subname, descnum
- if i < 0 then
- subname = "m"..math.abs(i)
- descnum = tostring(i)
- else
- subname = tostring(i)
- descnum = S("+@1", i)
- end
- local tex, color, desc
- if i > 0 then
- local val = math.floor((i/100)*255)
- tex = "testnodes_fall_damage_plus.png"
- color = { b=0, g=255-val, r=255, a=255 }
- desc = S("Fall Damage Node (+@1%)", i)
- else
- tex = "testnodes_fall_damage_minus.png"
- if i == -100 then
- color = { r=0, b=0, g=255, a=255 }
- else
- local val = math.floor((math.abs(i)/100)*255)
- color = { r=0, b=255, g=255-val, a=255 }
- end
- desc = S("Fall Damage Node (-@1%)", math.abs(i))
- end
- minetest.register_node("testnodes:damage"..subname, {
- description = desc,
- groups = {fall_damage_add_percent=i, dig_immediate=3},
-
-
- tiles = { tex },
- is_ground_content = false,
- color = color,
- })
- end
-end
-
--- Bouncy nodes (various bounce levels)
-for i=20, 180, 20 do
- local val = math.floor(((i-20)/200)*255)
- minetest.register_node("testnodes:bouncy"..i, {
- description = S("Bouncy Node (@1%)", i),
- groups = {bouncy=i, dig_immediate=3},
-
-
- tiles ={"testnodes_bouncy.png"},
- is_ground_content = false,
- color = { r=255, g=255-val, b=val, a=255 },
- })
-end
-
--- Slippery nodes (various slippery levels)
-for i=1, 5 do
- minetest.register_node("testnodes:slippery"..i, {
- description = S("Slippery Node (@1)", i),
- tiles ={"testnodes_slippery.png"},
- is_ground_content = false,
- groups = {slippery=i, dig_immediate=3},
- color = { r=0, g=255, b=math.floor((i/5)*255), a=255 },
- })
-end
-
--- By placing something on the node, the node itself will be replaced
-minetest.register_node("testnodes:buildable_to", {
- description = S("Replacable Node"),
- buildable_to = true,
- tiles = {"testnodes_buildable_to.png"},
- is_ground_content = false,
- groups = {dig_immediate=3},
-})
-
--- Nodes that deal damage to players that are inside them.
--- Negative damage nodes should heal.
-for d=-3,3 do
- if d ~= 0 then
- local sub, tile
- if d > 0 then
- sub = tostring(d)
- tile = "testnodes_damage.png"
- else
- sub = "m" .. tostring(math.abs(d))
- tile = "testnodes_damage_neg.png"
- end
- if math.abs(d) == 2 then
- tile = tile .. "^[colorize:#000000:70"
- elseif math.abs(d) == 3 then
- tile = tile .. "^[colorize:#000000:140"
- end
- minetest.register_node("testnodes:damage_"..sub, {
- description = S("Damage Node (@1 damage per second)", d),
- damage_per_second = d,
-
-
- walkable = false,
- is_ground_content = false,
- drawtype = "allfaces",
- paramtype = "light",
- sunlight_propagates = true,
- tiles = { tile },
- groups = {dig_immediate=3},
- })
- end
-end
-
--- Causes drowning damage
-minetest.register_node("testnodes:drowning_1", {
- description = S("Drowning Node (@1 damage)", 1),
- drowning = 1,
-
-
- walkable = false,
- is_ground_content = false,
- drawtype = "allfaces",
- paramtype = "light",
- sunlight_propagates = true,
- tiles = { "testnodes_drowning.png" },
- groups = {dig_immediate=3},
-})
-
+++ /dev/null
-# If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
-# This is due to <https://github.com/minetest/minetest/issues/9209>.
-# This is only added to make the items more visible to avoid confusion, but you will no longer see the default inventory images for these items. When you want to test the default inventory image of drawtypes, this should be turned off.
-testnodes_show_fallback_image (Use fallback inventory images) bool false
+++ /dev/null
--- Node texture tests
-
-local S = minetest.get_translator("testnodes")
-
-minetest.register_node("testnodes:6sides", {
- description = S("Six Textures Test Node"),
- tiles = {
- "testnodes_normal1.png",
- "testnodes_normal2.png",
- "testnodes_normal3.png",
- "testnodes_normal4.png",
- "testnodes_normal5.png",
- "testnodes_normal6.png",
- },
-
- groups = { dig_immediate = 2 },
-})
-
-minetest.register_node("testnodes:anim", {
- description = S("Animated Test Node"),
- tiles = {
- { name = "testnodes_anim.png",
- animation = {
- type = "vertical_frames",
- aspect_w = 16,
- aspect_h = 16,
- length = 4.0,
- }, },
- },
-
- groups = { dig_immediate = 2 },
-})
-
--- Node texture transparency test
-
-local alphas = { 64, 128, 191 }
-
-for a=1,#alphas do
- local alpha = alphas[a]
-
- -- Transparency taken from texture
- minetest.register_node("testnodes:alpha_texture_"..alpha, {
- description = S("Texture Alpha Test Node (@1)", alpha),
- drawtype = "glasslike",
- paramtype = "light",
- tiles = {
- "testnodes_alpha"..alpha..".png",
- },
- use_texture_alpha = true,
-
- groups = { dig_immediate = 3 },
- })
-
- -- Transparency set via "alpha" parameter
- minetest.register_node("testnodes:alpha_"..alpha, {
- description = S("Alpha Test Node (@1)", alpha),
- -- It seems that only the liquid drawtype supports the alpha parameter
- drawtype = "liquid",
- paramtype = "light",
- tiles = {
- "testnodes_alpha.png",
- },
- alpha = alpha,
-
- groups = { dig_immediate = 3 },
- })
-end
+++ /dev/null
-# Pathfinder Tester
-
-Usage:
-
-Use the Pathfinder Tester tool (`testpathfinder:testpathfinder`).
-Here's how it works:
-
-* Place on node: Set destination position
-* Punch: Find path
-* Sneak+punch: Select pathfinding algorithm
-
-Information will be shown in chat. If a path was found, all waypoints
-will be shown for a few seconds.
-
-See `init.lua` for config variables.
+++ /dev/null
-local S = minetest.get_translator("testpathfinder")
-
--- Config parameters
-
--- Maximum direct distance between start and end
-local MAX_DIRECT_DISTANCE = 64
--- Maximum search distance
-local MAX_SEARCH_DISTANCE = 32
--- Maximum permitted jump height
-local MAX_JUMP = 1
--- Maximum permitted drop height
-local MAX_DROP = 5
--- If true, mod won't refuse to run pathfinder even at long distances
-local IGNORE_MAX_DISTANCE_SAFEGUARD = false
-
--- End of config parameters
-
-local timer = 0
-local algorithms = {
- "A*_noprefetch",
- "A*",
- "Dijkstra",
-}
-
-local function find_path_for_player(player, itemstack)
- local meta = itemstack:get_meta()
- if not meta then
- return
- end
- local x = meta:get_int("pos_x")
- local y = meta:get_int("pos_y")
- local z = meta:get_int("pos_z")
- local algo = meta:get_int("algorithm")
- if x and y and z then
- local pos2 = {x=x, y=y, z=z}
- algo = algorithms[algo+1]
- local pos1 = vector.round(player:get_pos())
- -- Don't bother calling pathfinder for high distance to avoid freezing
- if (not IGNORE_MAX_DISTANCE_SAFEGUARD) and (vector.distance(pos1, pos2) > MAX_DIRECT_DISTANCE) then
- minetest.chat_send_player(player:get_player_name(), S("Destination too far away! Set a destination (via placing) within a distance of @1 and try again!", MAX_DIRECT_DISTANCE))
- return
- end
- local str = S("Path from @1 to @2:",
- minetest.pos_to_string(pos1),
- minetest.pos_to_string(pos2))
-
- minetest.chat_send_player(player:get_player_name(), str)
- local time_start = minetest.get_us_time()
- local path = minetest.find_path(pos1, pos2, MAX_SEARCH_DISTANCE, MAX_JUMP, MAX_DROP, algo)
- local time_end = minetest.get_us_time()
- local time_diff = time_end - time_start
- str = ""
- if not path then
- minetest.chat_send_player(player:get_player_name(), S("No path!"))
- minetest.chat_send_player(player:get_player_name(), S("Time: @1 ms", time_diff/1000))
- return
- end
- for s=1, #path do
- str = str .. minetest.pos_to_string(path[s]) .. "\n"
- local t
- if s == #path then
- t = "testpathfinder_waypoint_end.png"
- elseif s == 1 then
- t = "testpathfinder_waypoint_start.png"
- else
- local c = math.floor(((#path-s)/#path)*255)
- t = string.format("testpathfinder_waypoint.png^[multiply:#%02x%02x00", 0xFF-c, c)
- end
- minetest.add_particle({
- pos = path[s],
- expirationtime = 5 + 0.2 * s,
- playername = player:get_player_name(),
- glow = minetest.LIGHT_MAX,
- texture = t,
- size = 3,
- })
- end
- minetest.chat_send_player(player:get_player_name(), str)
- minetest.chat_send_player(player:get_player_name(), S("Path length: @1", #path))
- minetest.chat_send_player(player:get_player_name(), S("Time: @1 ms", time_diff/1000))
- end
-end
-
-local function set_destination(itemstack, user, pointed_thing)
- if not (user and user:is_player()) then
- return
- end
- local name = user:get_player_name()
- local obj
- local meta = itemstack:get_meta()
- if pointed_thing.type == "node" then
- local pos = pointed_thing.above
- meta:set_int("pos_x", pos.x)
- meta:set_int("pos_y", pos.y)
- meta:set_int("pos_z", pos.z)
- minetest.chat_send_player(user:get_player_name(), S("Destination set to @1", minetest.pos_to_string(pos)))
- return itemstack
- end
-end
-
-local function find_path_or_set_algorithm(itemstack, user, pointed_thing)
- if not (user and user:is_player()) then
- return
- end
- local ctrl = user:get_player_control()
- -- No sneak: Find path
- if not ctrl.sneak then
- find_path_for_player(user, itemstack)
- else
- -- Sneak: Set algorithm
- local meta = itemstack:get_meta()
- local algo = meta:get_int("algorithm")
- algo = (algo + 1) % #algorithms
- meta:set_int("algorithm", algo)
- minetest.chat_send_player(user:get_player_name(), S("Algorithm: @1", algorithms[algo+1]))
- return itemstack
- end
-end
-
--- Punch: Find path
--- Sneak+punch: Select pathfinding algorithm
--- Place: Select destination node
-minetest.register_tool("testpathfinder:testpathfinder", {
- description = S("Pathfinder Tester"),
- inventory_image = "testpathfinder_testpathfinder.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_use = find_path_or_set_algorithm,
- on_secondary_use = set_destination,
- on_place = set_destination,
-})
-
-
+++ /dev/null
-name = testpathfinder
-description = Tool to test Minetest's pathfinder function
+++ /dev/null
-# Test Tools readme
-
-Test Tools is a mod for developers that adds a bunch of tools to directly manipulate nodes and entities. This is great for quickly testing out stuff.
-
-Here's the list of tools:
-
-## Remover
-Removes nodes and non-player entities that you punch.
-
-## Node Setter
-Replace a node with another one.
-
-First, punch a node you want to remember.
-Then rightclick any other node to replace it with the node you remembered.
-
-If you rightclick while pointing nothing, you can manually enter the node and param2.
-
-## Param2 Tool
-Change the value param2 of nodes.
-
-* Punch: Add 1 to param2
-* Sneak+Punch: Add 8 to param2
-* Place: Subtract 1 from param2
-* Sneak+Place: Subtract 8 from param2
-
-Note: Use the debug screen (F5) to see the param2 of the pointed node.
-
-## Falling Node Tool
-Turns nodes into falling nodes.
-
-Usage:
-
-* Punch node: Make it fall
-* Place: Try to teleport up to 2 units upwards, then make it fall
-
-## Entity Rotator
-Changes the entity rotation (with `set_rotation`).
-
-Usage:
-
-* Punch entity: Rotate yaw
-* Punch entity while holding down “Sneak” key: Rotate pitch
-* Punch entity while holding down “Special” key (aka “Aux”): Rotate roll
-
-Each usage rotates the entity by 22.5°.
-
-## Entity Spawner
-Spawns entities.
-
-Usage:
-
-* Punch to select entity or spawn one directly
-* Place to place selected entity
-
-## Object Property Editor
-Edits properties of objects.
-
-Usage:
-
-* Punch object to open a formspec that allows you to view and edit properties
-* Punch air to edit properties of your own player object
-
-To edit a property, select it in the list, enter a new value (in Lua syntax)
-and hit “Submit”.
-
-## Object Attacher
-Allows you to attach an object to another one.
-
-Basic usage:
-* First select the parent object, then the child object that should be attached
-* Selecting an object is done by punching it
-* Sneak+punch to detach selected object
-* If you punch air, you select yourself
-
-Configuration:
-* Place: Increase attachment Y position
-* Sneak+place: decrease attachment Y position
-* Aux+place: Increase attachment X rotation
-* Aux+Sneak+Rightclick: Decrease attachment X rotation
-
-Hint: To detach all objects nearby you (including on yourself), use the
-`/detach` server command.
-
-## Object Mover
-Move an object by a given distance.
-
-Usage:
-* Punch object into the direction you want to move it
-* Sneak+punch: Move object towards you
-* Place: Increase move distance
-* Sneak+place: Decrease move distance
-
-## Entity Visual Scaler
-Change visual size of entities
-
-Usage:
-
-* Punch entity to increase visual size
-* Sneak+punch entity to decrease visual size
+++ /dev/null
-local S = minetest.get_translator("testtools")
-local F = minetest.formspec_escape
-
--- TODO: Add a Node Metadata tool
-
--- Param 2 Tool: Set param2 value of tools
--- Punch: +1
--- Punch+Shift: +8
--- Place: -1
--- Place+Shift: -8
-minetest.register_tool("testtools:param2tool", {
- description = S("Param2 Tool"),
- inventory_image = "testtools_param2tool.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_use = function(itemstack, user, pointed_thing)
- local pos = minetest.get_pointed_thing_position(pointed_thing)
- if pointed_thing.type ~= "node" or (not pos) then
- return
- end
- local add = 1
- if user then
- local ctrl = user:get_player_control()
- if ctrl.sneak then
- add = 8
- end
- end
- local node = minetest.get_node(pos)
- node.param2 = node.param2 + add
- minetest.swap_node(pos, node)
- end,
- on_place = function(itemstack, user, pointed_thing)
- local pos = minetest.get_pointed_thing_position(pointed_thing)
- if pointed_thing.type ~= "node" or (not pos) then
- return
- end
- local add = -1
- if user then
- local ctrl = user:get_player_control()
- if ctrl.sneak then
- add = -8
- end
- end
- local node = minetest.get_node(pos)
- node.param2 = node.param2 + add
- minetest.swap_node(pos, node)
- end,
-})
-
-minetest.register_tool("testtools:node_setter", {
- description = S("Node Setter"),
- inventory_image = "testtools_node_setter.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_use = function(itemstack, user, pointed_thing)
- local pos = minetest.get_pointed_thing_position(pointed_thing)
- if pointed_thing.type == "nothing" then
- local meta = itemstack:get_meta()
- meta:set_string("node", "air")
- meta:set_int("node_param2", 0)
- if user and user:is_player() then
- minetest.chat_send_player(user:get_player_name(), S("Now placing: @1 (param2=@2)", "air", 0))
- end
- return itemstack
- elseif pointed_thing.type ~= "node" or (not pos) then
- return
- end
- local node = minetest.get_node(pos)
- local meta = itemstack:get_meta()
- meta:set_string("node", node.name)
- meta:set_int("node_param2", node.param2)
- if user and user:is_player() then
- minetest.chat_send_player(user:get_player_name(), S("Now placing: @1 (param2=@2)", node.name, node.param2))
- end
- return itemstack
- end,
- on_secondary_use = function(itemstack, user, pointed_thing)
- local meta = itemstack:get_meta()
- local nodename = meta:get_string("node") or ""
- local param2 = meta:get_int("node_param2") or 0
-
- minetest.show_formspec(user:get_player_name(), "testtools:node_setter",
- "size[4,4]"..
- "field[0.5,1;3,1;nodename;"..F(S("Node name (itemstring):"))..";"..F(nodename).."]"..
- "field[0.5,2;3,1;param2;"..F(S("param2:"))..";"..F(tostring(param2)).."]"..
- "button_exit[0.5,3;3,1;submit;"..F(S("Submit")).."]"
- )
- end,
- on_place = function(itemstack, user, pointed_thing)
- local pos = minetest.get_pointed_thing_position(pointed_thing)
- local meta = itemstack:get_meta()
- local nodename = meta:get_string("node")
- if nodename == "" and user and user:is_player() then
- minetest.chat_send_player(user:get_player_name(), S("Punch a node first!"))
- return
- end
- local param2 = meta:get_int("node_param2")
- if not param2 then
- param2 = 0
- end
- local node = { name = nodename, param2 = param2 }
- if not minetest.registered_nodes[nodename] then
- minetest.chat_send_player(user:get_player_name(), S("Cannot set unknown node: @1", nodename))
- return
- end
- minetest.set_node(pos, node)
- end,
-})
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- if formname == "testtools:node_setter" then
- local playername = player:get_player_name()
- local witem = player:get_wielded_item()
- if witem:get_name() == "testtools:node_setter" then
- if fields.nodename and fields.param2 then
- local param2 = tonumber(fields.param2)
- if not param2 then
- return
- end
- local meta = witem:get_meta()
- meta:set_string("node", fields.nodename)
- meta:set_int("node_param2", param2)
- player:set_wielded_item(witem)
- end
- end
- end
-end)
-
-minetest.register_tool("testtools:remover", {
- description = S("Remover"),
- inventory_image = "testtools_remover.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_use = function(itemstack, user, pointed_thing)
- local pos = minetest.get_pointed_thing_position(pointed_thing)
- if pointed_thing.type == "node" and pos ~= nil then
- minetest.remove_node(pos)
- elseif pointed_thing.type == "object" then
- local obj = pointed_thing.ref
- if not obj:is_player() then
- obj:remove()
- end
- end
- end,
-})
-
-minetest.register_tool("testtools:falling_node_tool", {
- description = S("Falling Node Tool"),
- inventory_image = "testtools_falling_node_tool.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_place = function(itemstack, user, pointed_thing)
- -- Teleport node 1-2 units upwards (if possible) and make it fall
- local pos = minetest.get_pointed_thing_position(pointed_thing)
- if pointed_thing.type ~= "node" or (not pos) then
- return
- end
- local ok = false
- local highest
- for i=1,2 do
- local above = {x=pos.x,y=pos.y+i,z=pos.z}
- local n2 = minetest.get_node(above)
- local def2 = minetest.registered_nodes[n2.name]
- if def2 and (not def2.walkable) then
- highest = above
- else
- break
- end
- end
- if highest then
- local node = minetest.get_node(pos)
- local metatable = minetest.get_meta(pos):to_table()
- minetest.remove_node(pos)
- minetest.set_node(highest, node)
- local meta_highest = minetest.get_meta(highest)
- meta_highest:from_table(metatable)
- ok = minetest.spawn_falling_node(highest)
- else
- ok = minetest.spawn_falling_node(pos)
- end
- if not ok and user and user:is_player() then
- minetest.chat_send_player(user:get_player_name(), S("Falling node could not be spawned!"))
- end
- end,
- on_use = function(itemstack, user, pointed_thing)
- local pos = minetest.get_pointed_thing_position(pointed_thing)
- if pointed_thing.type ~= "node" or (not pos) then
- return
- end
- local ok = minetest.spawn_falling_node(pos)
- if not ok and user and user:is_player() then
- minetest.chat_send_player(user:get_player_name(), S("Falling node could not be spawned!"))
- end
- end,
-})
-
-minetest.register_tool("testtools:rotator", {
- description = S("Entity Rotator"),
- inventory_image = "testtools_entity_rotator.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_use = function(itemstack, user, pointed_thing)
- if pointed_thing.type ~= "object" then
- return
- end
- local obj = pointed_thing.ref
- if obj:is_player() then
- -- No player rotation
- return
- else
- local axis = "y"
- if user and user:is_player() then
- local ctrl = user:get_player_control()
- if ctrl.sneak then
- axis = "x"
- elseif ctrl.aux1 then
- axis = "z"
- end
- end
- local rot = obj:get_rotation()
- rot[axis] = rot[axis] + math.pi/8
- if rot[axis] > math.pi*2 then
- rot[axis] = rot[axis] - math.pi*2
- end
- obj:set_rotation(rot)
- end
- end,
-})
-
-local mover_config = function(itemstack, user, pointed_thing)
- if not (user and user:is_player()) then
- return
- end
- local name = user:get_player_name()
- local ctrl = user:get_player_control()
- local meta = itemstack:get_meta()
- local dist = 1.0
- if meta:contains("distance") then
- dist = meta:get_int("distance")
- end
- if ctrl.sneak then
- dist = dist - 1
- else
- dist = dist + 1
- end
- meta:set_int("distance", dist)
- minetest.chat_send_player(user:get_player_name(), S("distance=@1/10", dist*2))
- return itemstack
-end
-
-minetest.register_tool("testtools:object_mover", {
- description = S("Object Mover"),
- inventory_image = "testtools_object_mover.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_place = mover_config,
- on_secondary_use = mover_config,
- on_use = function(itemstack, user, pointed_thing)
- if pointed_thing.type ~= "object" then
- return
- end
- local obj = pointed_thing.ref
- if not (user and user:is_player()) then
- return
- end
- local yaw = user:get_look_horizontal()
- local dir = minetest.yaw_to_dir(yaw)
- local pos = obj:get_pos()
- local pitch = user:get_look_vertical()
- if pitch > 0.25 * math.pi then
- dir.y = -1
- dir.x = 0
- dir.z = 0
- elseif pitch < -0.25 * math.pi then
- dir.y = 1
- dir.x = 0
- dir.z = 0
- end
- local ctrl = user:get_player_control()
- if ctrl.sneak then
- dir = vector.multiply(dir, -1)
- end
- local meta = itemstack:get_meta()
- if meta:contains("distance") then
- local dist = meta:get_int("distance")
- dir = vector.multiply(dir, dist*0.2)
- end
- pos = vector.add(pos, dir)
- obj:set_pos(pos)
- end,
-})
-
-
-
-minetest.register_tool("testtools:entity_scaler", {
- description = S("Entity Visual Scaler"),
- inventory_image = "testtools_entity_scaler.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_use = function(itemstack, user, pointed_thing)
- if pointed_thing.type ~= "object" then
- return
- end
- local obj = pointed_thing.ref
- if obj:is_player() then
- -- No player scaling
- return
- else
- local diff = 0.1
- if user and user:is_player() then
- local ctrl = user:get_player_control()
- if ctrl.sneak then
- diff = -0.1
- end
- end
- local prop = obj:get_properties()
- if not prop.visual_size then
- prop.visual_size = { x=1, y=1, z=1 }
- else
- prop.visual_size = { x=prop.visual_size.x+diff, y=prop.visual_size.y+diff, z=prop.visual_size.z+diff }
- if prop.visual_size.x <= 0.1 then
- prop.visual_size.x = 0.1
- end
- if prop.visual_size.y <= 0.1 then
- prop.visual_size.y = 0.1
- end
- if prop.visual_size.z <= 0.1 then
- prop.visual_size.z = 0.1
- end
- end
- obj:set_properties(prop)
- end
- end,
-})
-
-local selections = {}
-local entity_list
-local function get_entity_list()
- if entity_list then
- return entity_list
- end
- local ents = minetest.registered_entities
- local list = {}
- for k,_ in pairs(ents) do
- table.insert(list, k)
- end
- table.sort(list)
- entity_list = list
- return entity_list
-end
-minetest.register_tool("testtools:entity_spawner", {
- description = S("Entity Spawner"),
- inventory_image = "testtools_entity_spawner.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_place = function(itemstack, user, pointed_thing)
- local name = user:get_player_name()
- if selections[name] and pointed_thing.type == "node" then
- local pos = pointed_thing.above
- minetest.add_entity(pos, get_entity_list()[selections[name]])
- end
- end,
- on_use = function(itemstack, user, pointed_thing)
- if pointed_thing.type == "object" then
- return
- end
- if user and user:is_player() then
- local list = table.concat(get_entity_list(), ",")
- local name = user:get_player_name()
- local sel = selections[name] or ""
- minetest.show_formspec(name, "testtools:entity_list",
- "size[9,9]"..
- "textlist[0,0;9,8;entity_list;"..list..";"..sel..";false]"..
- "button[0,8;4,1;spawn;Spawn entity]"
- )
- end
- end,
-})
-
-local function prop_to_string(property)
- if type(property) == "string" then
- return "\"" .. property .. "\""
- elseif type(property) == "table" then
- return tostring(dump(property)):gsub("\n", "")
- else
- return tostring(property)
- end
-end
-
-local property_formspec_data = {}
-local property_formspec_index = {}
-local selected_objects = {}
-local function get_object_properties_form(obj, playername)
- if not playername then return "" end
- local props = obj:get_properties()
- local str = ""
- property_formspec_data[playername] = {}
- local proplist = {}
- for k,_ in pairs(props) do
- table.insert(proplist, k)
- end
- table.sort(proplist)
- for p=1, #proplist do
- local k = proplist[p]
- local v = props[k]
- local newline = ""
- newline = k .. " = "
- newline = newline .. prop_to_string(v)
- str = str .. F(newline)
- if p < #proplist then
- str = str .. ","
- end
- table.insert(property_formspec_data[playername], k)
- end
- return str
-end
-
-local editor_formspec_selindex = {}
-
-local editor_formspec = function(playername, obj, value, sel)
- if not value then
- value = ""
- end
- if not sel then
- sel = ""
- end
- local list = get_object_properties_form(obj, playername)
- local title
- if obj:is_player() then
- title = S("Object properties of player “@1”", obj:get_player_name())
- else
- local ent = obj:get_luaentity()
- title = S("Object properties of @1", ent.name)
- end
- minetest.show_formspec(playername, "testtools:object_editor",
- "size[9,9]"..
- "label[0,0;"..F(title).."]"..
- "textlist[0,0.5;9,7.5;object_props;"..list..";"..sel..";false]"..
- "field[0.2,8.75;8,1;value;"..F(S("Value"))..";"..F(value).."]"..
- "button[8,8.5;1,1;submit;"..F(S("Submit")).."]"
- )
-end
-
-minetest.register_tool("testtools:object_editor", {
- description = S("Object Property Editor"),
- inventory_image = "testtools_object_editor.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_use = function(itemstack, user, pointed_thing)
- if user and user:is_player() then
- local name = user:get_player_name()
-
- if pointed_thing.type == "object" then
- selected_objects[name] = pointed_thing.ref
- elseif pointed_thing.type == "nothing" then
- -- Use on yourself if pointing nothing
- selected_objects[name] = user
- else
- -- Unsupported pointed thing
- return
- end
-
- local sel = editor_formspec_selindex[name]
- local val
- if selected_objects[name] and selected_objects[name]:get_properties() then
- local props = selected_objects[name]:get_properties()
- local keys = property_formspec_data[name]
- if property_formspec_index[name] and props then
- local key = keys[property_formspec_index[name]]
- val = prop_to_string(props[key])
- end
- end
-
- editor_formspec(name, selected_objects[name], val, sel)
- end
- end,
-})
-
-local ent_parent = {}
-local ent_child = {}
-local DEFAULT_ATTACH_OFFSET_Y = 11
-
-local attacher_config = function(itemstack, user, pointed_thing)
- if not (user and user:is_player()) then
- return
- end
- if pointed_thing.type == "object" then
- return
- end
- local name = user:get_player_name()
- local ctrl = user:get_player_control()
- local meta = itemstack:get_meta()
- if ctrl.aux1 then
- local rot_x = meta:get_float("rot_x")
- if ctrl.sneak then
- rot_x = rot_x - math.pi/8
- else
- rot_x = rot_x + math.pi/8
- end
- if rot_x > 6.2 then
- rot_x = 0
- elseif rot_x < 0 then
- rot_x = math.pi * (15/8)
- end
- minetest.chat_send_player(name, S("rotation=@1", minetest.pos_to_string({x=rot_x,y=0,z=0})))
- meta:set_float("rot_x", rot_x)
- else
- local pos_y
- if meta:contains("pos_y") then
- pos_y = meta:get_int("pos_y")
- else
- pos_y = DEFAULT_ATTACH_OFFSET_Y
- end
- if ctrl.sneak then
- pos_y = pos_y - 1
- else
- pos_y = pos_y + 1
- end
- minetest.chat_send_player(name, S("position=@1", minetest.pos_to_string({x=0,y=pos_y,z=0})))
- meta:set_int("pos_y", pos_y)
- end
- return itemstack
-end
-
-minetest.register_tool("testtools:object_attacher", {
- description = S("Object Attacher"),
- inventory_image = "testtools_object_attacher.png",
- groups = { testtool = 1, disable_repair = 1 },
- on_place = attacher_config,
- on_secondary_use = attacher_config,
- on_use = function(itemstack, user, pointed_thing)
- if user and user:is_player() then
- local name = user:get_player_name()
- local selected_object
- if pointed_thing.type == "object" then
- selected_object = pointed_thing.ref
- elseif pointed_thing.type == "nothing" then
- selected_object = user
- else
- return
- end
- local ctrl = user:get_player_control()
- if ctrl.sneak then
- if selected_object:get_attach() then
- selected_object:set_detach()
- minetest.chat_send_player(name, S("Object detached!"))
- else
- minetest.chat_send_player(name, S("Object is not attached!"))
- end
- return
- end
- local parent = ent_parent[name]
- local child = ent_child[name]
- local ename = S("<unknown>")
- if not parent then
- parent = selected_object
- ent_parent[name] = parent
- elseif not child then
- child = selected_object
- ent_child[name] = child
- end
- local entity = selected_object:get_luaentity()
- if entity then
- ename = entity.name
- elseif selected_object:is_player() then
- ename = selected_object:get_player_name()
- end
- if selected_object == parent then
- minetest.chat_send_player(name, S("Parent object selected: @1", ename))
- elseif selected_object == child then
- minetest.chat_send_player(name, S("Child object selected: @1", ename))
- end
- if parent and child then
- if parent == child then
- minetest.chat_send_player(name, S("Can't attach an object to itself!"))
- ent_parent[name] = nil
- ent_child[name] = nil
- return
- end
- local meta = itemstack:get_meta()
- local y
- if meta:contains("pos_y") then
- y = meta:get_int("pos_y")
- else
- y = DEFAULT_ATTACH_OFFSET_Y
- end
- local rx = meta:get_float("rot_x") or 0
- local offset = {x=0,y=y,z=0}
- local angle = {x=rx,y=0,z=0}
- child:set_attach(parent, "", offset, angle)
- local check_parent = child:get_attach()
- if check_parent then
- minetest.chat_send_player(name, S("Object attached! position=@1, rotation=@2",
- minetest.pos_to_string(offset), minetest.pos_to_string(angle)))
- else
- minetest.chat_send_player(name, S("Attachment failed!"))
- end
- ent_parent[name] = nil
- ent_child[name] = nil
- end
- end
- end,
-})
-
--- Use loadstring to parse param as a Lua value
-local function use_loadstring(param, player)
- -- For security reasons, require 'server' priv, just in case
- -- someone is actually crazy enough to run this on a public server.
- local privs = minetest.get_player_privs(player:get_player_name())
- if not privs.server then
- return false, "You need 'server' privilege to change object properties!"
- end
- if not param then
- return false, "Failed: parameter is nil"
- end
- --[[ DANGER ZONE ]]
- -- Interpret string as Lua value
- local func, errormsg = loadstring("return (" .. param .. ")")
- if not func then
- return false, "Failed: " .. errormsg
- end
-
- -- Apply sandbox here using setfenv
- setfenv(func, {})
-
- -- Run it
- local good, errOrResult = pcall(func)
- if not good then
- -- A Lua error was thrown
- return false, "Failed: " .. errOrResult
- end
-
- -- errOrResult will be the value
- return true, errOrResult
-end
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
- if not (player and player:is_player()) then
- return
- end
- if formname == "testtools:entity_list" then
- local name = player:get_player_name()
- if fields.entity_list then
- local expl = minetest.explode_textlist_event(fields.entity_list)
- if expl.type == "DCL" then
- local pos = vector.add(player:get_pos(), {x=0,y=1,z=0})
- selections[name] = expl.index
- minetest.add_entity(pos, get_entity_list()[expl.index])
- return
- elseif expl.type == "CHG" then
- selections[name] = expl.index
- return
- end
- elseif fields.spawn and selections[name] then
- local pos = vector.add(player:get_pos(), {x=0,y=1,z=0})
- minetest.add_entity(pos, get_entity_list()[selections[name]])
- return
- end
- elseif formname == "testtools:object_editor" then
- local name = player:get_player_name()
- if fields.object_props then
- local expl = minetest.explode_textlist_event(fields.object_props)
- if expl.type == "DCL" or expl.type == "CHG" then
- property_formspec_index[name] = expl.index
-
- local props = selected_objects[name]:get_properties()
- local keys = property_formspec_data[name]
- if (not property_formspec_index[name]) or (not props) then
- return
- end
- local key = keys[property_formspec_index[name]]
- editor_formspec_selindex[name] = expl.index
- editor_formspec(name, selected_objects[name], prop_to_string(props[key]), expl.index)
- return
- end
- end
- if fields.submit then
- local props = selected_objects[name]:get_properties()
- local keys = property_formspec_data[name]
- if (not property_formspec_index[name]) or (not props) then
- return
- end
- local key = keys[property_formspec_index[name]]
- if not key then
- return
- end
- local success, str = use_loadstring(fields.value, player)
- if success then
- props[key] = str
- else
- minetest.chat_send_player(name, str)
- return
- end
- selected_objects[name]:set_properties(props)
- local sel = editor_formspec_selindex[name]
- editor_formspec(name, selected_objects[name], prop_to_string(props[key]), sel)
- return
- end
- end
-end)
+++ /dev/null
-name = testtools
-description = Some tools to directly manipulate nodes and entities. Great for development and testing
+++ /dev/null
-minetest.register_node("tiled:tiled", {
- description = "Tiled Node (world-aligned)",
- tiles = {{
- name = "tiled_tiled.png",
- align_style = "world",
- scale = 8,
- }},
- groups = {cracky=3},
-})
-
-minetest.register_node("tiled:tiled_n", {
- description = "Tiled Node (node-aligned)",
- tiles = {{
- name = "tiled_tiled.png",
- align_style = "node",
- scale = 8,
- }},
- groups = {cracky=3},
-})
-
-stairs.register_stair_and_slab("tiled_n", "tiled:tiled",
- {cracky=3},
- {{name="tiled_tiled.png", align_style="node", scale=8}},
- "Tiled Stair (node-aligned)",
- "Tiled Slab (node-aligned)")
-
-stairs.register_stair_and_slab("tiled", "tiled:tiled",
- {cracky=3},
- {{name="tiled_tiled.png", align_style="world", scale=8}},
- "Tiled Stair (world-aligned)",
- "Tiled Slab (world-aligned)")
-
-
+++ /dev/null
-name = tiled
-description = Add nodes with a special texture that spans multiple nodes (aka "world-aligned")
-depends = stairs
+++ /dev/null
--- Test minetest.clear_craft function
-local function test_clear_craft()
- minetest.log("info", "[unittests] Testing minetest.clear_craft")
- -- Clearing by output
- minetest.register_craft({
- output = "foo",
- recipe = {{"bar"}}
- })
- minetest.register_craft({
- output = "foo 4",
- recipe = {{"foo", "bar"}}
- })
- assert(#minetest.get_all_craft_recipes("foo") == 2)
- minetest.clear_craft({output="foo"})
- assert(minetest.get_all_craft_recipes("foo") == nil)
- -- Clearing by input
- minetest.register_craft({
- output = "foo 4",
- recipe = {{"foo", "bar"}}
- })
- assert(#minetest.get_all_craft_recipes("foo") == 1)
- minetest.clear_craft({recipe={{"foo", "bar"}}})
- assert(minetest.get_all_craft_recipes("foo") == nil)
-end
-
--- Test minetest.get_craft_result function
-local function test_get_craft_result()
- minetest.log("info", "[unittests] Testing minetest.get_craft_result")
-
- -- normal
- local input = {
- method = "normal",
- width = 2,
- items = {"", "unittests:coal_lump", "", "unittests:stick"}
- }
- minetest.log("info", "[unittests] torch crafting input: "..dump(input))
- local output, decremented_input = minetest.get_craft_result(input)
- minetest.log("info", "[unittests] torch crafting output: "..dump(output))
- minetest.log("info", "[unittests] torch crafting decremented input: "..dump(decremented_input))
- assert(output.item)
- minetest.log("info", "[unittests] torch crafting output.item:to_table(): "..dump(output.item:to_table()))
- assert(output.item:get_name() == "unittests:torch")
- assert(output.item:get_count() == 4)
-
- -- fuel
- input = {
- method = "fuel",
- width = 1,
- items = {"unittests:coal_lump"}
- }
- minetest.log("info", "[unittests] coal fuel input: "..dump(input))
- output, decremented_input = minetest.get_craft_result(input)
- minetest.log("info", "[unittests] coal fuel output: "..dump(output))
- minetest.log("info", "[unittests] coal fuel decremented input: "..dump(decremented_input))
- assert(output.time)
- assert(output.time > 0)
-
- -- cooking
- input = {
- method = "cooking",
- width = 1,
- items = {"unittests:iron_lump"}
- }
- minetest.log("info", "[unittests] iron lump cooking input: "..dump(output))
- output, decremented_input = minetest.get_craft_result(input)
- minetest.log("info", "[unittests] iron lump cooking output: "..dump(output))
- minetest.log("info", "[unittests] iron lump cooking decremented input: "..dump(decremented_input))
- assert(output.time)
- assert(output.time > 0)
- assert(output.item)
- minetest.log("info", "[unittests] iron lump cooking output.item:to_table(): "..dump(output.item:to_table()))
- assert(output.item:get_name() == "unittests:steel_ingot")
- assert(output.item:get_count() == 1)
-
- -- tool repair (repairable)
- input = {
- method = "normal",
- width = 2,
- -- Using a wear of 60000
- items = {"unittests:repairable_tool 1 60000", "unittests:repairable_tool 1 60000"}
- }
- minetest.log("info", "[unittests] repairable tool crafting input: "..dump(input))
- output, decremented_input = minetest.get_craft_result(input)
- minetest.log("info", "[unittests] repairable tool crafting output: "..dump(output))
- minetest.log("info", "[unittests] repairable tool crafting decremented input: "..dump(decremented_input))
- assert(output.item)
- minetest.log("info", "[unittests] repairable tool crafting output.item:to_table(): "..dump(output.item:to_table()))
- assert(output.item:get_name() == "unittests:repairable_tool")
- -- Test the wear value.
- -- See src/craftdef.cpp in Minetest source code for the formula. The formula to calculate
- -- the value 51187 is:
- -- 65536 - ((65536-60000)+(65536-60000)) + floor(additonal_wear * 65536 + 0.5) = 51187
- -- where additional_wear = 0.05
- assert(output.item:get_wear() == 51187)
- assert(output.item:get_count() == 1)
-
- -- failing tool repair (unrepairable)
- input = {
- method = "normal",
- width = 2,
- items = {"unittests:unrepairable_tool 1 60000", "unittests:unrepairable_tool 1 60000"}
- }
- minetest.log("info", "[unittests] unrepairable tool crafting input: "..dump(input))
- output, decremented_input = minetest.get_craft_result(input)
- minetest.log("info", "[unittests] unrepairable tool crafting output: "..dump(output))
- minetest.log("info", "[unittests] unrepairable tool crafting decremented input: "..dump(decremented_input))
- assert(output.item)
- minetest.log("info", "[unittests] unrepairable tool crafting output.item:to_table(): "..dump(output.item:to_table()))
- -- unrepairable tool must not yield any output
- assert(output.item:get_name() == "")
-
-end
-
-function unittests.test_crafting()
- test_clear_craft()
- test_get_craft_result()
- minetest.log("action", "[unittests] Crafting tests passed!")
- return true
-end
-
+++ /dev/null
--- Registering some dummy items and recipes for the crafting tests
-
-minetest.register_craftitem("unittests:torch", {
- description = "Crafting Test Item: Torch",
- inventory_image = "unittests_torch.png",
-
- groups = { dummy = 1 },
-})
-minetest.register_craftitem("unittests:coal_lump", {
- description = "Crafting Test Item: Coal Lump",
- inventory_image = "unittests_coal_lump.png",
-
- groups = { dummy = 1 },
-})
-minetest.register_craftitem("unittests:stick", {
- description = "Crafting Test Item: Stick",
- inventory_image = "unittests_stick.png",
-
- groups = { dummy = 1 },
-})
-minetest.register_craftitem("unittests:iron_lump", {
- description = "Crafting Test Item: Iron Lump",
- inventory_image = "unittests_iron_lump.png",
-
- groups = { dummy = 1 },
-})
-minetest.register_craftitem("unittests:steel_ingot", {
- description = "Crafting Test Item: Steel Ingot",
- inventory_image = "unittests_steel_ingot.png",
-
- groups = { dummy = 1 },
-})
-
--- Recipes for tests: Normal crafting, cooking and fuel
-
-minetest.register_craft({
- output = 'unittests:torch 4',
- recipe = {
- {'unittests:coal_lump'},
- {'unittests:stick'},
- }
-})
-
-minetest.register_craft({
- type = "cooking",
- output = "unittests:steel_ingot",
- recipe = "unittests:iron_lump",
-})
-
-minetest.register_craft({
- type = "fuel",
- recipe = "unittests:coal_lump",
- burntime = 40,
-})
-
--- Test tool repair
-minetest.register_craft({
- type = "toolrepair",
- additional_wear = -0.05,
-})
-
--- Test the disable_repair=1 group
-minetest.register_tool("unittests:unrepairable_tool", {
- description = "Crafting Test Item: Unrepairable Tool",
- inventory_image = "unittests_unrepairable_tool.png",
- tool_capabilities = {
- groupcaps = {
- cracky = {
- times = {3, 2, 1},
- }
- }
- },
- groups = { disable_repair = 1, dummy = 1 }
-})
-
-minetest.register_tool("unittests:repairable_tool", {
- description = "Crafting Test Item: Repairable Tool",
- inventory_image = "unittests_repairable_tool.png",
- tool_capabilities = {
- groupcaps = {
- cracky = {
- times = {3, 2, 1},
- }
- }
- },
-
- groups = { dummy = 1 },
-})
+++ /dev/null
-unittests = {}
-
-local modpath = minetest.get_modpath("unittests")
-dofile(modpath .. "/random.lua")
-dofile(modpath .. "/player.lua")
-dofile(modpath .. "/crafting_prepare.lua")
-dofile(modpath .. "/crafting.lua")
-
-if minetest.settings:get_bool("devtest_unittests_autostart", false) then
- unittests.test_random()
- unittests.test_crafting()
- minetest.register_on_joinplayer(function(player)
- unittests.test_player(player)
- end)
-end
-
+++ /dev/null
-name = unittests
-description = Adds automated unit tests for the engine
+++ /dev/null
---
--- HP Change Reasons
---
-local expect = nil
-local function run_hpchangereason_tests(player)
- expect = { type = "set_hp", from = "mod" }
- player:set_hp(3)
- assert(expect == nil)
-
- expect = { a = 234, type = "set_hp", from = "mod" }
- player:set_hp(7, { a= 234 })
- assert(expect == nil)
-
- expect = { df = 3458973454, type = "fall", from = "mod" }
- player:set_hp(10, { type = "fall", df = 3458973454 })
- assert(expect == nil)
-
- player:set_hp(20)
-end
-
-local function run_player_meta_tests(player)
- local meta = player:get_meta()
- meta:set_string("foo", "bar")
- assert(meta:contains("foo"))
- assert(meta:get_string("foo") == "bar")
- assert(meta:get("foo") == "bar")
-
- local meta2 = player:get_meta()
- assert(meta2:get_string("foo") == "bar")
- assert(meta2:get("foo") == "bar")
- assert(meta:equals(meta2))
-
- meta:set_string("bob", "dillan")
- assert(meta:get_string("foo") == "bar")
- assert(meta:get_string("bob") == "dillan")
- assert(meta:get("bob") == "dillan")
- assert(meta2:get_string("foo") == "bar")
- assert(meta2:get_string("bob") == "dillan")
- assert(meta2:get("bob") == "dillan")
- assert(meta:equals(meta2))
-
- meta:set_string("foo", "")
- assert(not meta:contains("foo"))
- assert(meta:get("foo") == nil)
- assert(meta:get_string("foo") == "")
- assert(meta:equals(meta2))
-end
-
-function unittests.test_player(player)
- minetest.register_on_player_hpchange(function(player, hp, reason)
- if not expect then
- return
- end
-
- for key, value in pairs(reason) do
- assert(expect[key] == value)
- end
-
- for key, value in pairs(expect) do
- assert(reason[key] == value)
- end
-
- expect = nil
- end)
-
- run_hpchangereason_tests(player)
- run_player_meta_tests(player)
- local msg = "Player tests passed for player '"..player:get_player_name().."'!"
- minetest.chat_send_all(msg)
- minetest.log("action", "[unittests] "..msg)
- return true
-end
-
+++ /dev/null
-function unittests.test_random()
- -- Try out PseudoRandom
- minetest.log("action", "[unittests] Testing PseudoRandom ...")
- local pseudo = PseudoRandom(13)
- assert(pseudo:next() == 22290)
- assert(pseudo:next() == 13854)
- minetest.log("action", "[unittests] PseudoRandom test passed!")
- return true
-end
-
+++ /dev/null
-minetest.register_chatcommand("hotbar", {
- params = "<size>",
- description = "Set hotbar size",
- func = function(name, param)
- local player = minetest.get_player_by_name(name)
- if not player then
- return false, "No player."
- end
- local size = tonumber(param)
- if not size then
- return false, "Missing or incorrect size parameter!"
- end
- local ok = player:hud_set_hotbar_itemcount(size)
- if ok then
- return true
- else
- return false, "Invalid item count!"
- end
- end,
-})
-
-minetest.register_chatcommand("hp", {
- params = "<hp>",
- description = "Set your health",
- func = function(name, param)
- local player = minetest.get_player_by_name(name)
- if not player then
- return false, "No player."
- end
- local hp = tonumber(param)
- if not hp then
- return false, "Missing or incorrect hp parameter!"
- end
- player:set_hp(hp)
- return true
- end,
-})
-
-minetest.register_chatcommand("zoom", {
- params = "[<zoom_fov>]",
- description = "Set or display your zoom_fov",
- func = function(name, param)
- local player = minetest.get_player_by_name(name)
- if not player then
- return false, "No player."
- end
- if param == "" then
- local fov = player:get_properties().zoom_fov
- return true, "zoom_fov = "..tostring(fov)
- end
- local fov = tonumber(param)
- if not fov then
- return false, "Missing or incorrect zoom_fov parameter!"
- end
- player:set_properties({zoom_fov = fov})
- fov = player:get_properties().zoom_fov
- return true, "zoom_fov = "..tostring(fov)
- end,
-})
-
-
-
-local s_infplace = minetest.settings:get("devtest_infplace")
-if s_infplace == "true" then
- infplace = true
-elseif s_infplace == "false" then
- infplace = false
-else
- infplace = minetest.settings:get_bool("creative_mode", false)
-end
-
-minetest.register_chatcommand("infplace", {
- params = "",
- description = "Toggle infinite node placement",
- func = function(name, param)
- infplace = not infplace
- if infplace then
- minetest.chat_send_all("Infinite node placement enabled!")
- minetest.log("action", "Infinite node placement enabled")
- else
- minetest.chat_send_all("Infinite node placement disabled!")
- minetest.log("action", "Infinite node placement disabled")
- end
- return true
- end,
-})
-
-minetest.register_chatcommand("detach", {
- params = "[<radius>]",
- description = "Detach all objects nearby",
- func = function(name, param)
- local radius = tonumber(param)
- if type(radius) ~= "number" then
- radius = 8
- end
- if radius < 1 then
- radius = 1
- end
- local player = minetest.get_player_by_name(name)
- if not player then
- return false, "No player."
- end
- local objs = minetest.get_objects_inside_radius(player:get_pos(), radius)
- local num = 0
- for o=1, #objs do
- if objs[o]:get_attach() then
- objs[o]:set_detach()
- num = num + 1
- end
- end
- return true, string.format("%d object(s) detached.", num)
- end,
-})
-
-
--- Unlimited node placement
-minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack)
- if placer and placer:is_player() then
- return infplace
- end
-end)
-
--- Don't pick up if the item is already in the inventory
-local old_handle_node_drops = minetest.handle_node_drops
-function minetest.handle_node_drops(pos, drops, digger)
- if not digger or not digger:is_player() or not infplace then
- return old_handle_node_drops(pos, drops, digger)
- end
- local inv = digger:get_inventory()
- if inv then
- for _, item in ipairs(drops) do
- if not inv:contains_item("main", item, true) then
- inv:add_item("main", item)
- end
- end
- end
-end
+++ /dev/null
-name = util_commands
-description = Random server commands to make testing easier and more convenient
+++ /dev/null
-# If enabled, nodes won't be used up when placed.
-# Note: This behavior can also be toggled in-game with the /infplace command.
-#
-# - true: enabled
-# - false: disabled
-# - auto: only enabled when Creative Mode is enabled (default)
-devtest_infplace (Infinite node placement) enum auto true,false,auto
-
-# If enabled, new players receive some initial items when joining for the first time.
-give_initial_stuff (Give initial stuff) bool true
-
-# If enabled, automated tests of the Lua API such as player health, crafting and PseudoRandom will be performed on startup.
-devtest_unittests_autostart (Perform unit tests) bool false
-
-# If enabled, the game will use all mapgen aliases for the v6 mapgen.
-# If disabled, it will only use a minimal set of mapgen aliases.
-# If enabled, there should be biome-specific tree, leaves and ground nodes. If disabled, stuff should use fallback nodes (like stone instead of desert stone).
-#
-# Many mapgen aliases have fallback values when no value is provided. Having this setting disabled can be useful to test whether those fallback values are functional.
-devtest_v6_mapgen_aliases (Use all v6 mapgen aliases) bool false
-
-# If enabled, the game will use dungeon stairs by enabling the corresponding mapgen aliases.
-#
-# Disabling this setting can be useful to test whether dungeons still work when stairs are not defined.
-devtest_dungeon_stairs (Generate dungeon stairs) bool false
-
-# If enabled, the mapgen alias 'mapgen_mossycobble' will be used. This should enable random mossy cobblestone in dungeons.
-# If disabled, it won't be used. The engine should fall back to cobble instead.
-devtest_dungeon_mossycobble (Generate mossy cobblestone) bool false
-
-# If enabled, some very basic biomes will be registered.
-devtest_register_biomes (Register biomes) bool true
-
-# If set to true, will show an inventory image for nodes that have no inventory image as of Minetest 5.1.0.
-# This is due to <https://github.com/minetest/minetest/issues/9209>.
-# This is only added to make the items more visible to avoid confusion, but you will no longer see the default inventory images for these items. When you want to test the default inventory image of drawtypes, this should be turned off.
-testnodes_show_fallback_image (Use fallback inventory images) bool false
PARENT_SCOPE)
set (TEST_WORLDDIR ${CMAKE_CURRENT_SOURCE_DIR}/test_world)
-set (TEST_SUBGAME_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../games/minimal)
+set (TEST_SUBGAME_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../games/devtest)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/test_config.h.in"
{
std::string path = std::string(TEST_WORLDDIR) + DIR_DELIM + "world.mt";
Settings world_config;
- world_config.set("gameid", "minimal");
+ world_config.set("gameid", "devtest");
UASSERTEQ(bool, world_config.updateConfigFile(path.c_str()), true);
ServerModManager sm(TEST_WORLDDIR);
}
const auto &mods = sm.getMods();
UASSERTEQ(bool, mods.empty(), false);
- // Ensure we found default mod inside the test folder
+ // Ensure we found basenodes mod (part of devtest)
bool default_found = false;
for (const auto &m : mods) {
- if (m.name == "default")
+ if (m.name == "basenodes")
default_found = true;
// Verify if paths are not empty
{
ServerModManager sm(std::string(TEST_WORLDDIR));
UASSERTEQ(const ModSpec *, sm.getModSpec("wrongmod"), NULL);
- UASSERT(sm.getModSpec("default") != NULL);
+ UASSERT(sm.getModSpec("basenodes") != NULL);
}
void TestServerModManager::testGetModNamesWrongDir()
std::vector<std::string> result;
sm.getModNames(result);
UASSERTEQ(bool, result.empty(), false);
- UASSERT(std::find(result.begin(), result.end(), "default") != result.end());
+ UASSERT(std::find(result.begin(), result.end(), "basenodes") != result.end());
}
void TestServerModManager::testGetModMediaPathsWrongDir()
#!/bin/bash
dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-gameid=minimal
+gameid=devtest
minetest=$dir/../bin/minetest
testspath=$dir/../tests
worldpath=$testspath/testworld_$gameid