push minetest server
17
README.md
Normal file
@ -0,0 +1,17 @@
|
||||
# MINETEST SERVER
|
||||
|
||||
## PRE REQUIS
|
||||
|
||||
- docker
|
||||
|
||||
### DEPLOYER LOCALEMENT
|
||||
|
||||
```bash
|
||||
|
||||
```
|
||||
|
||||
### DEPLOYER SUR INTERNET
|
||||
|
||||
```bash
|
||||
|
||||
```
|
||||
3497
conf/minetest.conf
Normal file
4
data/games/garage/LICENSE.txt
Normal file
@ -0,0 +1,4 @@
|
||||
License information for Development Test
|
||||
----------------------------------------
|
||||
|
||||
The same license as for Luanti applies.
|
||||
50
data/games/garage/README.md
Normal file
@ -0,0 +1,50 @@
|
||||
# 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
|
||||
|
||||
Confused by a certain node or item? Check out for inline code comments. The usages of most tools are explained in their tooltips.
|
||||
|
||||
### 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
|
||||
|
||||
* 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
|
||||
|
||||
4
data/games/garage/game.conf
Normal file
@ -0,0 +1,4 @@
|
||||
title = Development Test
|
||||
description = Testing environment to help with testing the engine features of Luanti. It can also be helpful in mod development.
|
||||
first_mod = first_mod
|
||||
last_mod = last_mod
|
||||
BIN
data/games/garage/menu/background.png
Normal file
|
After Width: | Height: | Size: 139 B |
BIN
data/games/garage/menu/header.png
Normal file
|
After Width: | Height: | Size: 209 B |
BIN
data/games/garage/menu/icon.png
Normal file
|
After Width: | Height: | Size: 217 B |
361
data/games/garage/mods/basenodes/init.lua
Normal file
@ -0,0 +1,361 @@
|
||||
local WATER_ALPHA = "^[opacity:" .. 160
|
||||
local WATER_VISC = 1
|
||||
local LAVA_VISC = 7
|
||||
|
||||
--
|
||||
-- Node definitions
|
||||
--
|
||||
|
||||
-- Register nodes
|
||||
|
||||
core.register_node("basenodes:stone", {
|
||||
description = "Stone",
|
||||
tiles = {"default_stone.png"},
|
||||
groups = {cracky=3},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:desert_stone", {
|
||||
description = "Desert Stone",
|
||||
tiles = {"default_desert_stone.png"},
|
||||
groups = {cracky=3},
|
||||
})
|
||||
|
||||
core.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},
|
||||
})
|
||||
|
||||
core.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},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:dirt", {
|
||||
description = "Dirt",
|
||||
tiles ={"default_dirt.png"},
|
||||
groups = {crumbly=3, soil=1},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:sand", {
|
||||
description = "Sand",
|
||||
tiles ={"default_sand.png"},
|
||||
groups = {crumbly=3},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:desert_sand", {
|
||||
description = "Desert Sand",
|
||||
tiles ={"default_desert_sand.png"},
|
||||
groups = {crumbly=3},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:gravel", {
|
||||
description = "Gravel",
|
||||
tiles ={"default_gravel.png"},
|
||||
groups = {crumbly=2},
|
||||
})
|
||||
|
||||
core.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},
|
||||
})
|
||||
|
||||
core.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},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:leaves", {
|
||||
description = "Normal Leaves",
|
||||
drawtype = "allfaces_optional",
|
||||
tiles = {"default_leaves.png"},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
groups = {snappy=3},
|
||||
})
|
||||
|
||||
core.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},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:jungleleaves", {
|
||||
description = "Jungle Leaves",
|
||||
drawtype = "allfaces_optional",
|
||||
tiles = {"default_jungleleaves.png"},
|
||||
paramtype = "light",
|
||||
is_ground_content = false,
|
||||
groups = {snappy=3},
|
||||
})
|
||||
|
||||
core.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},
|
||||
})
|
||||
|
||||
core.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},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:water_source", {
|
||||
description = "Water Source".."\n"..
|
||||
"Swimmable, spreading, renewable liquid".."\n"..
|
||||
"Drowning damage: 1",
|
||||
drawtype = "liquid",
|
||||
waving = 3,
|
||||
tiles = {"default_water.png"..WATER_ALPHA},
|
||||
special_tiles = {
|
||||
{name = "default_water.png"..WATER_ALPHA, backface_culling = false},
|
||||
{name = "default_water.png"..WATER_ALPHA, backface_culling = true},
|
||||
},
|
||||
use_texture_alpha = "blend",
|
||||
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},
|
||||
post_effect_color_shaded = true,
|
||||
groups = {water = 3, liquid = 3},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:water_flowing", {
|
||||
description = "Flowing Water".."\n"..
|
||||
"Swimmable, spreading, renewable liquid".."\n"..
|
||||
"Drowning damage: 1",
|
||||
drawtype = "flowingliquid",
|
||||
waving = 3,
|
||||
tiles = {"default_water_flowing.png"},
|
||||
special_tiles = {
|
||||
{name = "default_water_flowing.png"..WATER_ALPHA,
|
||||
backface_culling = false},
|
||||
{name = "default_water_flowing.png"..WATER_ALPHA,
|
||||
backface_culling = false},
|
||||
},
|
||||
use_texture_alpha = "blend",
|
||||
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},
|
||||
post_effect_color_shaded = true,
|
||||
groups = {water = 3, liquid = 3},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:river_water_source", {
|
||||
description = "River Water Source".."\n"..
|
||||
"Swimmable, spreading, non-renewable liquid".."\n"..
|
||||
"Drowning damage: 1",
|
||||
drawtype = "liquid",
|
||||
waving = 3,
|
||||
tiles = { "default_river_water.png"..WATER_ALPHA },
|
||||
special_tiles = {
|
||||
{name = "default_river_water.png"..WATER_ALPHA, backface_culling = false},
|
||||
{name = "default_river_water.png"..WATER_ALPHA, backface_culling = true},
|
||||
},
|
||||
use_texture_alpha = "blend",
|
||||
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},
|
||||
post_effect_color_shaded = true,
|
||||
groups = {water = 3, liquid = 3, },
|
||||
})
|
||||
|
||||
core.register_node("basenodes:river_water_flowing", {
|
||||
description = "Flowing River Water".."\n"..
|
||||
"Swimmable, spreading, non-renewable liquid".."\n"..
|
||||
"Drowning damage: 1",
|
||||
drawtype = "flowingliquid",
|
||||
waving = 3,
|
||||
tiles = {"default_river_water_flowing.png"..WATER_ALPHA},
|
||||
special_tiles = {
|
||||
{name = "default_river_water_flowing.png"..WATER_ALPHA,
|
||||
backface_culling = false},
|
||||
{name = "default_river_water_flowing.png"..WATER_ALPHA,
|
||||
backface_culling = false},
|
||||
},
|
||||
use_texture_alpha = "blend",
|
||||
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},
|
||||
post_effect_color_shaded = true,
|
||||
groups = {water = 3, liquid = 3, },
|
||||
})
|
||||
|
||||
core.register_node("basenodes:lava_flowing", {
|
||||
description = "Flowing Lava".."\n"..
|
||||
"Swimmable, spreading, renewable liquid".."\n"..
|
||||
"4 damage per second".."\n"..
|
||||
"Drowning damage: 1",
|
||||
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 = core.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},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:lava_source", {
|
||||
description = "Lava Source".."\n"..
|
||||
"Swimmable, spreading, renewable liquid".."\n"..
|
||||
"4 damage per second".."\n"..
|
||||
"Drowning damage: 1",
|
||||
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 = core.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},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:cobble", {
|
||||
description = "Cobblestone",
|
||||
tiles ={"default_cobble.png"},
|
||||
is_ground_content = false,
|
||||
groups = {cracky=3},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:mossycobble", {
|
||||
description = "Mossy Cobblestone",
|
||||
tiles ={"default_mossycobble.png"},
|
||||
is_ground_content = false,
|
||||
groups = {cracky=3},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:apple", {
|
||||
description = "Apple".."\n"..
|
||||
"Punch: Eat (+2)",
|
||||
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 = core.item_eat(2),
|
||||
})
|
||||
|
||||
core.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
|
||||
core.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},
|
||||
},
|
||||
})
|
||||
|
||||
core.register_node("basenodes:snowblock", {
|
||||
description = "Snow Block",
|
||||
tiles ={"default_snow.png"},
|
||||
groups = {crumbly=3},
|
||||
})
|
||||
|
||||
|
||||
2
data/games/garage/mods/basenodes/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name = basenodes
|
||||
description = Contains basic nodes for mapgen
|
||||
|
After Width: | Height: | Size: 187 B |
|
After Width: | Height: | Size: 166 B |
|
After Width: | Height: | Size: 177 B |
|
After Width: | Height: | Size: 166 B |
BIN
data/games/garage/mods/basenodes/textures/default_apple.png
Normal file
|
After Width: | Height: | Size: 102 B |
BIN
data/games/garage/mods/basenodes/textures/default_cobble.png
Normal file
|
After Width: | Height: | Size: 340 B |
|
After Width: | Height: | Size: 293 B |
|
After Width: | Height: | Size: 584 B |
BIN
data/games/garage/mods/basenodes/textures/default_dirt.png
Normal file
|
After Width: | Height: | Size: 782 B |
BIN
data/games/garage/mods/basenodes/textures/default_grass.png
Normal file
|
After Width: | Height: | Size: 697 B |
BIN
data/games/garage/mods/basenodes/textures/default_gravel.png
Normal file
|
After Width: | Height: | Size: 171 B |
BIN
data/games/garage/mods/basenodes/textures/default_ice.png
Normal file
|
After Width: | Height: | Size: 369 B |
|
After Width: | Height: | Size: 201 B |
|
After Width: | Height: | Size: 399 B |
BIN
data/games/garage/mods/basenodes/textures/default_jungletree.png
Normal file
|
After Width: | Height: | Size: 730 B |
|
After Width: | Height: | Size: 714 B |
BIN
data/games/garage/mods/basenodes/textures/default_lava.png
Normal file
|
After Width: | Height: | Size: 172 B |
|
After Width: | Height: | Size: 91 B |
BIN
data/games/garage/mods/basenodes/textures/default_leaves.png
Normal file
|
After Width: | Height: | Size: 883 B |
|
After Width: | Height: | Size: 574 B |
|
After Width: | Height: | Size: 648 B |
BIN
data/games/garage/mods/basenodes/textures/default_pine_tree.png
Normal file
|
After Width: | Height: | Size: 604 B |
|
After Width: | Height: | Size: 174 B |
|
After Width: | Height: | Size: 496 B |
|
After Width: | Height: | Size: 99 B |
BIN
data/games/garage/mods/basenodes/textures/default_sand.png
Normal file
|
After Width: | Height: | Size: 554 B |
BIN
data/games/garage/mods/basenodes/textures/default_snow.png
Normal file
|
After Width: | Height: | Size: 166 B |
BIN
data/games/garage/mods/basenodes/textures/default_snow_side.png
Normal file
|
After Width: | Height: | Size: 152 B |
BIN
data/games/garage/mods/basenodes/textures/default_stone.png
Normal file
|
After Width: | Height: | Size: 313 B |
BIN
data/games/garage/mods/basenodes/textures/default_tree.png
Normal file
|
After Width: | Height: | Size: 659 B |
BIN
data/games/garage/mods/basenodes/textures/default_tree_top.png
Normal file
|
After Width: | Height: | Size: 175 B |
BIN
data/games/garage/mods/basenodes/textures/default_water.png
Normal file
|
After Width: | Height: | Size: 302 B |
|
After Width: | Height: | Size: 115 B |
|
After Width: | Height: | Size: 760 B |
|
After Width: | Height: | Size: 796 B |
7
data/games/garage/mods/basenodes/textures/info.txt
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
The dirt_with_grass folder is for testing loading textures from subfolders.
|
||||
If it works correctly, the default_grass_side.png file in the folder is used but
|
||||
default_grass.png is not overwritten by the file in the folder.
|
||||
|
||||
default_dirt.png should be overwritten by the default_dirt.png in the unittests
|
||||
mod which depends on basenodes.
|
||||
582
data/games/garage/mods/basetools/init.lua
Normal file
@ -0,0 +1,582 @@
|
||||
--
|
||||
-- Tool definitions
|
||||
--
|
||||
|
||||
--[[ TOOLS SUMMARY:
|
||||
|
||||
Tool types:
|
||||
|
||||
* Hand: basic tool/weapon (special capabilities in creative mode)
|
||||
* Pickaxe: dig cracky
|
||||
* Axe: dig choppy
|
||||
* Shovel: dig crumbly
|
||||
* Shears: dig snappy
|
||||
* Sword: deal damage
|
||||
* Dagger: deal damage, but faster
|
||||
|
||||
Tool materials:
|
||||
|
||||
* 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
|
||||
* n-Uses: can be used n times before breaking
|
||||
]]
|
||||
|
||||
-- The hand
|
||||
if core.settings:get_bool("creative_mode") then
|
||||
local digtime = 42
|
||||
local caps = {times = {digtime, digtime, digtime}, uses = 0, maxlevel = 256}
|
||||
|
||||
core.register_item(":", {
|
||||
type = "none",
|
||||
wield_image = "wieldhand.png",
|
||||
wield_scale = {x = 1, y = 1, z = 2.5},
|
||||
range = 10,
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 0.5,
|
||||
max_drop_level = 3,
|
||||
groupcaps = {
|
||||
crumbly = caps,
|
||||
cracky = caps,
|
||||
snappy = caps,
|
||||
choppy = caps,
|
||||
oddly_breakable_by_hand = caps,
|
||||
-- dig_immediate group doesn't use value 1. Value 3 is instant dig
|
||||
dig_immediate =
|
||||
{times = {[2] = digtime, [3] = 0}, uses = 0, maxlevel = 256},
|
||||
},
|
||||
damage_groups = {fleshy = 10},
|
||||
}
|
||||
})
|
||||
else
|
||||
core.register_item(":", {
|
||||
type = "none",
|
||||
wield_image = "wieldhand.png",
|
||||
wield_scale = {x = 1, y = 1, z = 2.5},
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 0.9,
|
||||
max_drop_level = 0,
|
||||
groupcaps = {
|
||||
crumbly = {times = {[2] = 3.00, [3] = 0.70}, uses = 0, maxlevel = 1},
|
||||
snappy = {times = {[3] = 0.40}, uses = 0, maxlevel = 1},
|
||||
oddly_breakable_by_hand =
|
||||
{times = {[1] = 3.50, [2] = 2.00, [3] = 0.70}, uses = 0}
|
||||
},
|
||||
damage_groups = {fleshy = 1},
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
-- Mese Pickaxe: special tool that digs "everything" instantly
|
||||
core.register_tool("basetools:pick_mese", {
|
||||
description = "Mese Pickaxe".."\n"..
|
||||
"Digs diggable nodes instantly.",
|
||||
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},
|
||||
},
|
||||
damage_groups = {fleshy=100},
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
-- A variant of the mese pickaxe that is not affected by the 0.15s digging delay
|
||||
core.register_tool("basetools:pick_mese_no_delay", {
|
||||
description = "Mese Pickaxe (no delay)".."\n"..
|
||||
"Digs diggable nodes instantly.".."\n"..
|
||||
"There is no delay between digging each node,\n"..
|
||||
'but the "repeat_dig_time" setting is still respected.',
|
||||
inventory_image = "basetools_mesepick_no_delay.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
max_drop_level=3,
|
||||
groupcaps={
|
||||
cracky={times={[1]=0.001, [2]=0.001, [3]=0.001}, maxlevel=255},
|
||||
crumbly={times={[1]=0.001, [2]=0.001, [3]=0.001}, maxlevel=255},
|
||||
snappy={times={[1]=0.001, [2]=0.001, [3]=0.001}, maxlevel=255},
|
||||
choppy={times={[1]=0.001, [2]=0.001, [3]=0.001}, maxlevel=255},
|
||||
dig_immediate={times={[1]=0.001, [2]=0.001, [3]=0.001}, maxlevel=255},
|
||||
},
|
||||
damage_groups = {fleshy=100},
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
--
|
||||
-- Pickaxes: Dig cracky
|
||||
--
|
||||
|
||||
core.register_tool("basetools:pick_wood", {
|
||||
description = "Wooden Pickaxe".."\n"..
|
||||
"Digs cracky=3",
|
||||
inventory_image = "basetools_woodpick.png",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
cracky={times={[3]=2.00}, uses=30, maxlevel=0}
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:pick_stone", {
|
||||
description = "Stone Pickaxe".."\n"..
|
||||
"Digs cracky=2..3",
|
||||
inventory_image = "basetools_stonepick.png",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
cracky={times={[2]=1.20, [3]=0.80}, uses=60, maxlevel=0}
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:pick_steel", {
|
||||
description = "Steel Pickaxe".."\n"..
|
||||
"Digs cracky=1..3",
|
||||
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}
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:pick_steel_l1", {
|
||||
description = "Steel Pickaxe Level 1".."\n"..
|
||||
"Digs cracky=1..3".."\n"..
|
||||
"maxlevel=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}
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:pick_steel_l2", {
|
||||
description = "Steel Pickaxe Level 2".."\n"..
|
||||
"Digs cracky=1..3".."\n"..
|
||||
"maxlevel=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)
|
||||
--
|
||||
|
||||
core.register_tool("basetools:shovel_wood", {
|
||||
description = "Wooden Shovel".."\n"..
|
||||
"Digs crumbly=3",
|
||||
inventory_image = "basetools_woodshovel.png",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
crumbly={times={[3]=0.50}, uses=30, maxlevel=0}
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:shovel_stone", {
|
||||
description = "Stone Shovel".."\n"..
|
||||
"Digs crumbly=2..3",
|
||||
inventory_image = "basetools_stoneshovel.png",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
crumbly={times={[2]=0.50, [3]=0.30}, uses=60, maxlevel=0}
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:shovel_steel", {
|
||||
description = "Steel Shovel".."\n"..
|
||||
"Digs crumbly=1..3",
|
||||
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)
|
||||
--
|
||||
|
||||
core.register_tool("basetools:axe_wood", {
|
||||
description = "Wooden Axe".."\n"..
|
||||
"Digs choppy=3",
|
||||
inventory_image = "basetools_woodaxe.png",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
choppy={times={[3]=0.80}, uses=30, maxlevel=0},
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:axe_stone", {
|
||||
description = "Stone Axe".."\n"..
|
||||
"Digs choppy=2..3",
|
||||
inventory_image = "basetools_stoneaxe.png",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
choppy={times={[2]=1.00, [3]=0.60}, uses=60, maxlevel=0},
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:axe_steel", {
|
||||
description = "Steel Axe".."\n"..
|
||||
"Digs choppy=1..3",
|
||||
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)
|
||||
--
|
||||
|
||||
core.register_tool("basetools:shears_wood", {
|
||||
description = "Wooden Shears".."\n"..
|
||||
"Digs snappy=3",
|
||||
inventory_image = "basetools_woodshears.png",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
snappy={times={[3]=1.00}, uses=30, maxlevel=0},
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:shears_stone", {
|
||||
description = "Stone Shears".."\n"..
|
||||
"Digs snappy=2..3",
|
||||
inventory_image = "basetools_stoneshears.png",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
snappy={times={[2]=1.00, [3]=0.50}, uses=60, maxlevel=0},
|
||||
},
|
||||
},
|
||||
})
|
||||
core.register_tool("basetools:shears_steel", {
|
||||
description = "Steel Shears".."\n"..
|
||||
"Digs snappy=1..3",
|
||||
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)
|
||||
--
|
||||
|
||||
core.register_tool("basetools:sword_wood", {
|
||||
description = "Wooden Sword".."\n"..
|
||||
"Damage: fleshy=2",
|
||||
inventory_image = "basetools_woodsword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy=2},
|
||||
}
|
||||
})
|
||||
core.register_tool("basetools:sword_stone", {
|
||||
description = "Stone Sword".."\n"..
|
||||
"Damage: fleshy=5",
|
||||
inventory_image = "basetools_stonesword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
max_drop_level=0,
|
||||
damage_groups = {fleshy=5},
|
||||
}
|
||||
})
|
||||
core.register_tool("basetools:sword_steel", {
|
||||
description = "Steel Sword".."\n"..
|
||||
"Damage: fleshy=10",
|
||||
inventory_image = "basetools_steelsword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
max_drop_level=1,
|
||||
damage_groups = {fleshy=10},
|
||||
}
|
||||
})
|
||||
core.register_tool("basetools:sword_titanium", {
|
||||
description = "Titanium Sword".."\n"..
|
||||
"Damage: fleshy=100",
|
||||
inventory_image = "basetools_titaniumsword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
max_drop_level=1,
|
||||
damage_groups = {fleshy=100},
|
||||
}
|
||||
})
|
||||
core.register_tool("basetools:sword_blood", {
|
||||
description = "Blood Sword".."\n"..
|
||||
"Damage: fleshy=1000",
|
||||
inventory_image = "basetools_bloodsword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
max_drop_level=1,
|
||||
damage_groups = {fleshy=1000},
|
||||
}
|
||||
})
|
||||
|
||||
-- Max. damage sword
|
||||
core.register_tool("basetools:sword_mese", {
|
||||
description = "Mese Sword".."\n"..
|
||||
"Damage: fleshy=32767, fiery=32767, icy=32767".."\n"..
|
||||
"Full Punch Interval: 0.0s",
|
||||
inventory_image = "basetools_mesesword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 0.0,
|
||||
max_drop_level=1,
|
||||
damage_groups = {fleshy=32767, fiery=32767, icy=32767},
|
||||
}
|
||||
})
|
||||
|
||||
-- Fire/Ice sword: Deal damage to non-fleshy damage groups
|
||||
core.register_tool("basetools:sword_fire", {
|
||||
description = "Fire Sword".."\n"..
|
||||
"Damage: icy=10",
|
||||
inventory_image = "basetools_firesword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
max_drop_level=0,
|
||||
damage_groups = {icy=10},
|
||||
}
|
||||
})
|
||||
core.register_tool("basetools:sword_ice", {
|
||||
description = "Ice Sword".."\n"..
|
||||
"Damage: fiery=10",
|
||||
inventory_image = "basetools_icesword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
max_drop_level=0,
|
||||
damage_groups = {fiery=10},
|
||||
}
|
||||
})
|
||||
core.register_tool("basetools:sword_elemental", {
|
||||
description = "Elemental Sword".."\n"..
|
||||
"Damage: fiery=10, icy=10",
|
||||
inventory_image = "basetools_elementalsword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
max_drop_level=0,
|
||||
damage_groups = {fiery=10, icy=10},
|
||||
}
|
||||
})
|
||||
|
||||
-- Healing weapons: heal HP
|
||||
core.register_tool("basetools:dagger_heal", {
|
||||
description = "Healing Dagger".."\n"..
|
||||
"Heal: fleshy=1".."\n"..
|
||||
"Full Punch Interval: 0.5s",
|
||||
inventory_image = "basetools_healdagger.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 0.5,
|
||||
damage_groups = {fleshy=-1},
|
||||
}
|
||||
})
|
||||
core.register_tool("basetools:sword_heal", {
|
||||
description = "Healing Sword".."\n"..
|
||||
"Heal: fleshy=10",
|
||||
inventory_image = "basetools_healsword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy=-10},
|
||||
}
|
||||
})
|
||||
core.register_tool("basetools:sword_heal_super", {
|
||||
description = "Super Healing Sword".."\n"..
|
||||
"Heal: fleshy=32768, fiery=32768, icy=32768",
|
||||
inventory_image = "basetools_superhealsword.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy=-32768, fiery=-32768, icy=-32768},
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
--
|
||||
-- Dagger: Low damage, fast punch interval
|
||||
--
|
||||
core.register_tool("basetools:dagger_wood", {
|
||||
description = "Wooden Dagger".."\n"..
|
||||
"Damage: fleshy=1".."\n"..
|
||||
"Full Punch Interval: 0.5s",
|
||||
inventory_image = "basetools_wooddagger.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 0.5,
|
||||
max_drop_level=0,
|
||||
damage_groups = {fleshy=1},
|
||||
}
|
||||
})
|
||||
core.register_tool("basetools:dagger_steel", {
|
||||
description = "Steel Dagger".."\n"..
|
||||
"Damage: fleshy=2".."\n"..
|
||||
"Full Punch Interval: 0.5s",
|
||||
inventory_image = "basetools_steeldagger.png",
|
||||
tool_capabilities = {
|
||||
full_punch_interval = 0.5,
|
||||
max_drop_level=0,
|
||||
damage_groups = {fleshy=2},
|
||||
}
|
||||
})
|
||||
|
||||
-- Test tool uses, punch_attack_uses, and wear bar coloring
|
||||
local tool_params = {
|
||||
{uses = 1},
|
||||
{uses = 2},
|
||||
{uses = 3},
|
||||
{
|
||||
uses = 5,
|
||||
wear_color = "#5865f2",
|
||||
wear_description = "Solid color: #5865f2",
|
||||
},
|
||||
{
|
||||
uses = 10,
|
||||
wear_color = "slateblue",
|
||||
wear_description = "Solid color: slateblue",
|
||||
},
|
||||
{
|
||||
uses = 50,
|
||||
wear_color = {
|
||||
color_stops = {
|
||||
[0] = "red",
|
||||
[0.5] = "yellow",
|
||||
[1.0] = "blue"
|
||||
},
|
||||
blend = "linear"
|
||||
},
|
||||
wear_description = "Ranges from blue to yellow to red",
|
||||
},
|
||||
{
|
||||
uses = 100,
|
||||
wear_color = {
|
||||
color_stops = {
|
||||
[0] = "#ffff00",
|
||||
[0.2] = "#ff00ff",
|
||||
[0.3] = "#ffff00",
|
||||
[0.45] = "#c0ffee",
|
||||
[0.6] = {r=255, g=255, b=0, a=100}, -- continues until the end
|
||||
},
|
||||
blend = "constant"
|
||||
},
|
||||
wear_description = "Misc. colors, constant interpolation",
|
||||
},
|
||||
{uses = 1e3},
|
||||
{uses = 1e4},
|
||||
{uses = 65535},
|
||||
}
|
||||
|
||||
for i, params in ipairs(tool_params) do
|
||||
local uses = params.uses
|
||||
local ustring = uses.."-Use"..(uses == 1 and "" or "s")
|
||||
local color = string.format("#FF00%02X", math.floor(((i-1)/#tool_params) * 255))
|
||||
core.register_tool("basetools:pick_uses_"..string.format("%05d", uses), {
|
||||
description = ustring.." Pickaxe".."\n"..
|
||||
"Digs cracky=3"..
|
||||
(params.wear_description and "\n".."Wear bar: " .. params.wear_description or ""),
|
||||
inventory_image = "basetools_usespick.png^[colorize:"..color..":127",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
cracky={times={[3]=0.1, [2]=0.2, [1]=0.3}, uses=uses, maxlevel=0}
|
||||
},
|
||||
},
|
||||
wear_color = params.wear_color
|
||||
})
|
||||
|
||||
core.register_tool("basetools:sword_uses_"..string.format("%05d", uses), {
|
||||
description = ustring.." Sword".."\n"..
|
||||
"Damage: fleshy=1",
|
||||
inventory_image = "basetools_usessword.png^[colorize:"..color..":127",
|
||||
tool_capabilities = {
|
||||
damage_groups = {fleshy=1},
|
||||
punch_attack_uses = uses,
|
||||
},
|
||||
})
|
||||
end
|
||||
|
||||
core.register_chatcommand("wear_color", {
|
||||
params = "[idx]",
|
||||
description = "Set wear bar color override",
|
||||
func = function(player_name, param)
|
||||
local player = core.get_player_by_name(player_name)
|
||||
if not player then return end
|
||||
|
||||
local wear_color = nil
|
||||
local wear_desc = "Reset override"
|
||||
|
||||
if param ~= "" then
|
||||
local params = tool_params[tonumber(param)]
|
||||
if not params then
|
||||
return false, "idx out of bounds"
|
||||
end
|
||||
wear_color = params.wear_color
|
||||
wear_desc = "Set override: "..(params.wear_description or "Default behavior")
|
||||
end
|
||||
local tool = player:get_wielded_item()
|
||||
if tool:get_count() == 0 then
|
||||
return false, "Tool not found"
|
||||
end
|
||||
tool:get_meta():set_wear_bar_params(wear_color)
|
||||
player:set_wielded_item(tool)
|
||||
return true, wear_desc
|
||||
end
|
||||
})
|
||||
|
||||
-- Punch handler to set random color & wear
|
||||
local wear_on_use = function(itemstack, user, pointed_thing)
|
||||
local meta = itemstack:get_meta()
|
||||
local color = math.random(0, 0xFFFFFF)
|
||||
local colorstr = string.format("#%06x", color)
|
||||
meta:set_wear_bar_params(colorstr)
|
||||
core.log("action", "[basetool] Wear bar color of "..itemstack:get_name().." changed to "..colorstr)
|
||||
itemstack:set_wear(math.random(0, 65535))
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Place handler to clear item metadata color
|
||||
local wear_on_place = function(itemstack, user, pointed_thing)
|
||||
local meta = itemstack:get_meta()
|
||||
meta:set_wear_bar_params(nil)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
core.register_tool("basetools:random_wear_bar", {
|
||||
description = "Wear Bar Color Test\n" ..
|
||||
"Punch: Set random color & wear\n" ..
|
||||
"Place: Clear color",
|
||||
-- Base texture: A grayscale square (can be colorized)
|
||||
inventory_image = "basetools_usespick.png^[colorize:#FFFFFF:127",
|
||||
tool_capabilities = {
|
||||
max_drop_level=0,
|
||||
groupcaps={
|
||||
cracky={times={[3]=0.1, [2]=0.2, [1]=0.3}, uses=1000, maxlevel=0}
|
||||
},
|
||||
},
|
||||
|
||||
on_use = wear_on_use,
|
||||
on_place = wear_on_place,
|
||||
on_secondary_use = wear_on_place,
|
||||
})
|
||||
2
data/games/garage/mods/basetools/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name = basetools
|
||||
description = Contains basic digging tools
|
||||
|
After Width: | Height: | Size: 165 B |
|
After Width: | Height: | Size: 177 B |
|
After Width: | Height: | Size: 166 B |
|
After Width: | Height: | Size: 162 B |
|
After Width: | Height: | Size: 170 B |
BIN
data/games/garage/mods/basetools/textures/basetools_icesword.png
Normal file
|
After Width: | Height: | Size: 170 B |
BIN
data/games/garage/mods/basetools/textures/basetools_mesepick.png
Normal file
|
After Width: | Height: | Size: 156 B |
|
After Width: | Height: | Size: 169 B |
|
After Width: | Height: | Size: 163 B |
BIN
data/games/garage/mods/basetools/textures/basetools_steelaxe.png
Normal file
|
After Width: | Height: | Size: 131 B |
|
After Width: | Height: | Size: 154 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 190 B |
|
After Width: | Height: | Size: 177 B |
|
After Width: | Height: | Size: 208 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 163 B |
BIN
data/games/garage/mods/basetools/textures/basetools_stoneaxe.png
Normal file
|
After Width: | Height: | Size: 130 B |
|
After Width: | Height: | Size: 155 B |
|
After Width: | Height: | Size: 224 B |
|
After Width: | Height: | Size: 134 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 192 B |
|
After Width: | Height: | Size: 160 B |
BIN
data/games/garage/mods/basetools/textures/basetools_usespick.png
Normal file
|
After Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 133 B |
BIN
data/games/garage/mods/basetools/textures/basetools_woodaxe.png
Normal file
|
After Width: | Height: | Size: 121 B |
|
After Width: | Height: | Size: 139 B |
BIN
data/games/garage/mods/basetools/textures/basetools_woodpick.png
Normal file
|
After Width: | Height: | Size: 149 B |
|
After Width: | Height: | Size: 212 B |
|
After Width: | Height: | Size: 133 B |
|
After Width: | Height: | Size: 139 B |
189
data/games/garage/mods/benchmarks/init.lua
Normal file
@ -0,0 +1,189 @@
|
||||
-- Safeguard against too much optimization. This way the results cannot be optimized
|
||||
-- away, but they can be garbage collected (due to __mode = "k").
|
||||
_G._bench_content_ids_data = setmetatable({}, {__mode = "k"})
|
||||
|
||||
local function bench_name2content()
|
||||
local t = {}
|
||||
_G._bench_content_ids_data[t] = true
|
||||
|
||||
local get_content_id = core.get_content_id
|
||||
|
||||
local start = core.get_us_time()
|
||||
|
||||
for i = 1, 200 do
|
||||
for name in pairs(core.registered_nodes) do
|
||||
t[#t + 1] = get_content_id(name)
|
||||
end
|
||||
end
|
||||
|
||||
local finish = core.get_us_time()
|
||||
|
||||
return (finish - start) / 1000
|
||||
end
|
||||
|
||||
local function bench_content2name()
|
||||
local t = {}
|
||||
_G._bench_content_ids_data[t] = true
|
||||
|
||||
-- Try to estimate the highest content ID that's used
|
||||
-- (not accurate but good enough for this test)
|
||||
local n = 0
|
||||
for _ in pairs(core.registered_nodes) do
|
||||
n = n + 1
|
||||
end
|
||||
|
||||
local get_name_from_content_id = core.get_name_from_content_id
|
||||
|
||||
local start = core.get_us_time()
|
||||
|
||||
for i = 1, 200 do
|
||||
for j = 0, n do
|
||||
t[#t + 1] = get_name_from_content_id(j)
|
||||
end
|
||||
end
|
||||
|
||||
local finish = core.get_us_time()
|
||||
|
||||
return (finish - start) / 1000
|
||||
end
|
||||
|
||||
core.register_chatcommand("bench_name2content", {
|
||||
params = "",
|
||||
description = "Benchmark: Conversion from node names to content IDs",
|
||||
func = function(name, param)
|
||||
core.chat_send_player(name, "Benchmarking core.get_content_id. Warming up ...")
|
||||
bench_name2content()
|
||||
core.chat_send_player(name, "Warming up finished, now benchmarking ...")
|
||||
local time = bench_name2content()
|
||||
return true, ("Time: %.2f ms"):format(time)
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("bench_content2name", {
|
||||
params = "",
|
||||
description = "Benchmark: Conversion from content IDs to node names",
|
||||
func = function(name, param)
|
||||
core.chat_send_player(name, "Benchmarking core.get_name_from_content_id. Warming up ...")
|
||||
bench_content2name()
|
||||
core.chat_send_player(name, "Warming up finished, now benchmarking ...")
|
||||
local time = bench_content2name()
|
||||
return true, ("Time: %.2f ms"):format(time)
|
||||
end,
|
||||
})
|
||||
|
||||
local function get_positions_cube(ppos)
|
||||
local pos_list = {}
|
||||
|
||||
local i = 1
|
||||
for x=2,100 do
|
||||
for y=2,100 do
|
||||
for z=2,100 do
|
||||
pos_list[i] = ppos:offset(x, y, z)
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return pos_list
|
||||
end
|
||||
|
||||
core.register_chatcommand("bench_bulk_set_node", {
|
||||
params = "",
|
||||
description = "Benchmark: Bulk-set 99×99×99 stone nodes",
|
||||
func = function(name, param)
|
||||
local player = core.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "No player."
|
||||
end
|
||||
local pos_list = get_positions_cube(player:get_pos())
|
||||
|
||||
core.chat_send_player(name, "Benchmarking core.bulk_set_node. Warming up ...")
|
||||
|
||||
-- warm up with stone to prevent having different callbacks
|
||||
-- due to different node topology
|
||||
core.bulk_set_node(pos_list, {name = "mapgen_stone"})
|
||||
|
||||
core.chat_send_player(name, "Warming up finished, now benchmarking ...")
|
||||
|
||||
local start_time = core.get_us_time()
|
||||
for i=1,#pos_list do
|
||||
core.set_node(pos_list[i], {name = "mapgen_stone"})
|
||||
end
|
||||
local middle_time = core.get_us_time()
|
||||
core.bulk_set_node(pos_list, {name = "mapgen_stone"})
|
||||
local end_time = core.get_us_time()
|
||||
local msg = string.format("Benchmark results: core.set_node loop: %.2f ms; core.bulk_set_node: %.2f ms",
|
||||
((middle_time - start_time)) / 1000,
|
||||
((end_time - middle_time)) / 1000
|
||||
)
|
||||
return true, msg
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("bench_bulk_get_node", {
|
||||
params = "",
|
||||
description = "Benchmark: Bulk-get 99×99×99 nodes",
|
||||
func = function(name, param)
|
||||
local player = core.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "No player."
|
||||
end
|
||||
local pos_list = get_positions_cube(player:get_pos())
|
||||
local function bench()
|
||||
local start_time = core.get_us_time()
|
||||
for i=1,#pos_list do
|
||||
local n = core.get_node(pos_list[i])
|
||||
-- Make sure the name lookup is never optimized away.
|
||||
-- Table allocation might still be omitted. But only accessing
|
||||
-- the name of a node is a common pattern anyways.
|
||||
if n.name == "benchmarks:nonexistent_node" then
|
||||
error("should never happen")
|
||||
end
|
||||
end
|
||||
return core.get_us_time() - start_time
|
||||
end
|
||||
|
||||
core.chat_send_player(name, "Benchmarking core.get_node. Warming up ...")
|
||||
bench()
|
||||
|
||||
core.chat_send_player(name, "Warming up finished, now benchmarking ...")
|
||||
local result_us = bench()
|
||||
|
||||
local msg = string.format("Benchmark results: core.get_node loop 1: %.2f ms",
|
||||
result_us / 1000)
|
||||
return true, msg
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_chatcommand("bench_bulk_swap_node", {
|
||||
params = "",
|
||||
description = "Benchmark: Bulk-swap 99×99×99 stone nodes",
|
||||
func = function(name, param)
|
||||
local player = core.get_player_by_name(name)
|
||||
if not player then
|
||||
return false, "No player."
|
||||
end
|
||||
local pos_list = get_positions_cube(player:get_pos())
|
||||
|
||||
core.chat_send_player(name, "Benchmarking core.bulk_swap_node. Warming up ...")
|
||||
|
||||
-- warm up because first execution otherwise becomes
|
||||
-- significantly slower
|
||||
core.bulk_swap_node(pos_list, {name = "mapgen_stone"})
|
||||
|
||||
core.chat_send_player(name, "Warming up finished, now benchmarking ...")
|
||||
|
||||
local start_time = core.get_us_time()
|
||||
for i=1,#pos_list do
|
||||
core.swap_node(pos_list[i], {name = "mapgen_stone"})
|
||||
end
|
||||
local middle_time = core.get_us_time()
|
||||
core.bulk_swap_node(pos_list, {name = "mapgen_stone"})
|
||||
local end_time = core.get_us_time()
|
||||
local msg = string.format("Benchmark results: core.swap_node loop: %.2f ms; core.bulk_swap_node: %.2f ms",
|
||||
((middle_time - start_time)) / 1000,
|
||||
((end_time - middle_time)) / 1000
|
||||
)
|
||||
return true, msg
|
||||
end,
|
||||
})
|
||||
2
data/games/garage/mods/benchmarks/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name = benchmarks
|
||||
description = Adds some benchmark chat commands
|
||||
11
data/games/garage/mods/broken/init.lua
Normal file
@ -0,0 +1,11 @@
|
||||
-- Register stuff with empty definitions to test if Luanti fallback options
|
||||
-- for these things work properly.
|
||||
|
||||
-- The itemstrings are deliberately kept descriptive to keep them easy to
|
||||
-- recognize.
|
||||
|
||||
core.register_node("broken:node_with_empty_definition", {})
|
||||
core.register_tool("broken:tool_with_empty_definition", {})
|
||||
core.register_craftitem("broken:craftitem_with_empty_definition", {})
|
||||
|
||||
core.register_entity("broken:entity_with_empty_definition", {})
|
||||
2
data/games/garage/mods/broken/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name = broken
|
||||
description = Register items and an entity with empty definitions to test fallback
|
||||
27
data/games/garage/mods/bucket/init.lua
Normal file
@ -0,0 +1,27 @@
|
||||
-- Bucket: Punch liquid source or flowing liquid to collect it
|
||||
|
||||
core.register_tool("bucket:bucket", {
|
||||
description = "Bucket".."\n"..
|
||||
"Picks up liquid nodes",
|
||||
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 = core.get_node(pointed_thing.under)
|
||||
local def = core.registered_nodes[n.name]
|
||||
if def ~= nil and (def.liquidtype == "source" or def.liquidtype == "flowing") then
|
||||
core.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,
|
||||
})
|
||||
|
||||
2
data/games/garage/mods/bucket/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name = bucket
|
||||
description = Minimal bucket to pick up liquids
|
||||
BIN
data/games/garage/mods/bucket/textures/bucket.png
Normal file
|
After Width: | Height: | Size: 163 B |
BIN
data/games/garage/mods/bucket/textures/bucket_lava.png
Normal file
|
After Width: | Height: | Size: 168 B |
BIN
data/games/garage/mods/bucket/textures/bucket_water.png
Normal file
|
After Width: | Height: | Size: 168 B |
101
data/games/garage/mods/callbacks/entities.lua
Normal file
@ -0,0 +1,101 @@
|
||||
-- Entities that test their callbacks
|
||||
|
||||
local message = function(msg)
|
||||
core.log("action", "[callbacks] "..msg)
|
||||
core.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 core.pos_to_string(vector.round(self.object:get_pos()))
|
||||
end
|
||||
|
||||
-- Callback test entity (all callbacks except on_step)
|
||||
core.register_entity("callbacks:callback", {
|
||||
initial_properties = {
|
||||
visual = "upright_sprite",
|
||||
textures = { "callbacks_callback_entity.png" },
|
||||
},
|
||||
|
||||
on_activate = function(self, staticdata, dtime_s)
|
||||
message("Callback entity: on_activate! pos="..spos(self).."; dtime_s="..dtime_s)
|
||||
end,
|
||||
on_deactivate = function(self, removal)
|
||||
message("Callback entity: on_deactivate! pos="..spos(self) .. "; removal=" .. tostring(removal))
|
||||
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
|
||||
core.register_entity("callbacks:callback_step", {
|
||||
visual = "upright_sprite",
|
||||
textures = { "callbacks_callback_entity_step.png" },
|
||||
on_step = function(self, dtime)
|
||||
message("on_step callback entity: on_step! pos="..spos(self).."; dtime="..dtime)
|
||||
end,
|
||||
})
|
||||
|
||||
-- Callback punch with nil puncher
|
||||
core.register_entity("callbacks:callback_puncher", {
|
||||
initial_properties = {
|
||||
visual = "upright_sprite",
|
||||
textures = { "callbacks_callback_entity.png" },
|
||||
infotext = "Callback entity for nil puncher test.",
|
||||
},
|
||||
|
||||
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
|
||||
if puncher then
|
||||
puncher:punch(nil, time_from_last_punch, tool_capabilities, dir)
|
||||
self.object:punch(nil, time_from_last_punch, tool_capabilities, dir)
|
||||
else
|
||||
message(
|
||||
"Callback entity: on_punch with nil puncher "..
|
||||
"pos="..spos(self).."; "..
|
||||
"time_from_last_punch="..time_from_last_punch.."; "..
|
||||
"tool_capabilities="..dump(tool_capabilities).."; "..
|
||||
"dir="..dump(dir).."; damage="..damage)
|
||||
end
|
||||
end,
|
||||
})
|
||||
4
data/games/garage/mods/callbacks/init.lua
Normal file
@ -0,0 +1,4 @@
|
||||
dofile(core.get_modpath("callbacks").."/items.lua")
|
||||
dofile(core.get_modpath("callbacks").."/nodes.lua")
|
||||
dofile(core.get_modpath("callbacks").."/entities.lua")
|
||||
dofile(core.get_modpath("callbacks").."/players.lua")
|
||||
120
data/games/garage/mods/callbacks/items.lua
Normal file
@ -0,0 +1,120 @@
|
||||
--
|
||||
-- Item callbacks
|
||||
--
|
||||
|
||||
local function print_to_everything(msg)
|
||||
core.log("action", "[callbacks] " .. msg)
|
||||
core.chat_send_all(msg)
|
||||
end
|
||||
|
||||
core.register_craftitem("callbacks:callback_item_1", {
|
||||
description = "Callback Test Item 1".."\n"..
|
||||
"Tests callbacks: on_secondary_use, on_drop, on_pickup, on_use, after_use".."\n"..
|
||||
"Punch/Drop + Sneak: Switch to Callback Test Item 2".."\n"..
|
||||
"Aux1 + pickup item: Print additional on_pickup arguments",
|
||||
inventory_image = "callbacks_callback_item_1.png",
|
||||
wield_image = "callbacks_callback_item_1.png",
|
||||
groups = { callback_test = 1 },
|
||||
|
||||
on_secondary_use = function(itemstack, user, pointed_thing)
|
||||
print_to_everything("[callbacks:callback_item_1 on_secondary_use] " .. itemstack:get_name())
|
||||
local ctrl = user and user:get_player_control() or {}
|
||||
if ctrl.sneak then
|
||||
itemstack = ItemStack(itemstack)
|
||||
itemstack:set_name("callbacks:callback_item_2")
|
||||
return itemstack
|
||||
end
|
||||
end,
|
||||
|
||||
on_drop = function(itemstack, dropper, pos)
|
||||
print_to_everything("[callbacks:callback_item_1 on_drop] " .. itemstack:get_name())
|
||||
local ctrl = dropper and dropper:get_player_control() or {}
|
||||
if ctrl.sneak then
|
||||
itemstack = ItemStack(itemstack)
|
||||
itemstack:set_name("callbacks:callback_item_2")
|
||||
end
|
||||
|
||||
return core.item_drop(itemstack, dropper, pos)
|
||||
end,
|
||||
|
||||
on_pickup = function(itemstack, picker, pointed_thing, ...)
|
||||
print_to_everything("[callbacks:callback_item_1 on_pickup]")
|
||||
assert(pointed_thing.ref:get_luaentity().name == "__builtin:item")
|
||||
local ctrl = picker and picker:get_player_control() or {}
|
||||
if ctrl.aux1 then
|
||||
-- Debug message
|
||||
print_to_everything("on_pickup dump:")
|
||||
print_to_everything(dump({...}))
|
||||
end
|
||||
if ctrl.sneak then
|
||||
-- Pick up one item of the other kind at once
|
||||
local taken = itemstack:take_item()
|
||||
taken:set_name("callbacks:callback_item_2")
|
||||
local leftover = core.item_pickup(taken, picker, pointed_thing, ...)
|
||||
leftover:set_name("callbacks:callback_item_1")
|
||||
itemstack:add_item(leftover)
|
||||
return itemstack
|
||||
elseif ctrl.up then
|
||||
-- Don't pick up
|
||||
return
|
||||
elseif ctrl.left then
|
||||
-- Eat it
|
||||
return core.do_item_eat(2, nil, itemstack, picker, pointed_thing)
|
||||
else
|
||||
-- Normal: pick up everything
|
||||
return core.item_pickup(itemstack, picker, pointed_thing, ...)
|
||||
end
|
||||
end,
|
||||
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
print_to_everything("[callbacks:callback_item_1 on_use] " .. itemstack:get_name())
|
||||
local ctrl = user and user:get_player_control() or {}
|
||||
if ctrl.sneak then
|
||||
itemstack = ItemStack(itemstack)
|
||||
itemstack:set_name("callbacks:callback_item_2")
|
||||
return itemstack
|
||||
end
|
||||
end,
|
||||
|
||||
after_use = function(itemstack, user, node, digparams) -- never called
|
||||
print_to_everything("[callbacks:callback_item_1 after_use]")
|
||||
local ctrl = user and user:get_player_control() or {}
|
||||
if ctrl.up then
|
||||
itemstack = ItemStack(itemstack)
|
||||
itemstack:set_name("callbacks:callback_item_2")
|
||||
return itemstack
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_craftitem("callbacks:callback_item_2", {
|
||||
description = "Callback Test Item 2".."\n"..
|
||||
"Punch to switch to Callback Test Item 1",
|
||||
inventory_image = "callbacks_callback_item_2.png",
|
||||
wield_image = "callbacks_callback_item_2.png",
|
||||
groups = { callback_test = 1 },
|
||||
|
||||
on_use = function(itemstack, user, pointed_thing)
|
||||
print_to_everything("[callbacks:callback_item_2 on_use]")
|
||||
itemstack = ItemStack(itemstack)
|
||||
itemstack:set_name("callbacks:callback_item_1")
|
||||
return itemstack
|
||||
end,
|
||||
})
|
||||
|
||||
core.register_on_item_pickup(function(itemstack, picker, pointed_thing, time_from_last_punch, ...)
|
||||
assert(not pointed_thing or pointed_thing.ref:get_luaentity().name == "__builtin:item")
|
||||
|
||||
local item_name = itemstack:get_name()
|
||||
if item_name ~= "callbacks:callback_item_1" and item_name ~= "callbacks:callback_item_2" then
|
||||
return
|
||||
end
|
||||
print_to_everything("["..item_name.." register_on_item_pickup]")
|
||||
|
||||
local ctrl = picker and picker:get_player_control() or {}
|
||||
if item_name == "callbacks:callback_item_2" and not ctrl.sneak then
|
||||
-- Same here. Pick up the other item type.
|
||||
itemstack:set_name("callbacks:callback_item_1")
|
||||
return picker:get_inventory():add_item("main", itemstack)
|
||||
end
|
||||
end)
|
||||
2
data/games/garage/mods/callbacks/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name = callbacks
|
||||
description = Adds various callback-related stuff
|
||||
51
data/games/garage/mods/callbacks/nodes.lua
Normal file
@ -0,0 +1,51 @@
|
||||
local function print_to_everything(msg)
|
||||
core.log("action", "[callbacks] " .. msg)
|
||||
core.chat_send_all(msg)
|
||||
end
|
||||
|
||||
core.register_node("callbacks:callback_node", {
|
||||
description = "Callback Test Node (construct/destruct/timer)".."\n"..
|
||||
"Tests callbacks: on_construct, after_place_node, on_destruct, after_destruct, after_dig_node, on_timer",
|
||||
tiles = {"callbacks_callback_node.png"},
|
||||
groups = {callback_test=1, dig_immediate=3},
|
||||
-- This was known to cause a bug in core.item_place_node() when used
|
||||
-- via core.place_node(), causing a placer with no position
|
||||
paramtype2 = "facedir",
|
||||
drop = "",
|
||||
|
||||
on_construct = function(pos)
|
||||
print_to_everything("callbacks:callback_node:on_construct("..core.pos_to_string(pos)..")")
|
||||
local meta = core.get_meta(pos)
|
||||
meta:set_string("mine", "test")
|
||||
local timer = core.get_node_timer(pos)
|
||||
timer:start(4, 3)
|
||||
end,
|
||||
|
||||
after_place_node = function(pos, placer)
|
||||
print_to_everything("callbacks:callback_node:after_place_node("..core.pos_to_string(pos)..")")
|
||||
local meta = core.get_meta(pos)
|
||||
if meta:get_string("mine") == "test" then
|
||||
print_to_everything("correct metadata found")
|
||||
else
|
||||
print_to_everything("incorrect metadata found")
|
||||
end
|
||||
end,
|
||||
|
||||
on_destruct = function(pos)
|
||||
print_to_everything("callbacks:callback_node:on_destruct("..core.pos_to_string(pos)..")")
|
||||
end,
|
||||
|
||||
after_destruct = function(pos)
|
||||
print_to_everything("callbacks:callback_node:after_destruct("..core.pos_to_string(pos)..")")
|
||||
end,
|
||||
|
||||
after_dig_node = function(pos, oldnode, oldmetadata, digger)
|
||||
print_to_everything("callbacks:callback_node:after_dig_node("..core.pos_to_string(pos)..")")
|
||||
end,
|
||||
|
||||
on_timer = function(pos, elapsed)
|
||||
print_to_everything("callbacks:callback_node:on_timer(): elapsed="..dump(elapsed))
|
||||
return true
|
||||
end,
|
||||
})
|
||||
|
||||
11
data/games/garage/mods/callbacks/players.lua
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
local message = function(msg)
|
||||
core.log("action", "[callbacks] "..msg)
|
||||
core.chat_send_all(msg)
|
||||
end
|
||||
|
||||
core.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
|
||||
if not hitter then
|
||||
message("Player "..player:get_player_name().." punched without hitter.")
|
||||
end
|
||||
end)
|
||||
|
After Width: | Height: | Size: 142 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 129 B |
|
After Width: | Height: | Size: 130 B |
|
After Width: | Height: | Size: 139 B |