Merge branch 'master' into crossbow

This commit is contained in:
Lizzy Fleckenstein 2021-03-18 13:29:16 +01:00
commit 54413d0954
349 changed files with 4299 additions and 3074 deletions

9
API.md
View File

@ -39,7 +39,7 @@ A lot of things are possible by using one of the APIs in the mods. Note that not
* Dispenser support: `ITEMS/REDSTONE/mcl_dispensers`
## Mobs
* Mobs: `ENTITIES/mcl_mods`
* Mobs: `ENTITIES/mcl_mobs`
MineClone 2 uses its own mobs framework, called “Mobs Redo: MineClone 2 Edition” or “MRM” for short.
This is a fork of Mobs Redo [`mobs`] by TenPlus1.
@ -67,6 +67,9 @@ chances are good that it works out of the box.
* Get flowing direction of liquids: `CORE/flowlib`
* `on_walk_over` callback for nodes: `CORE/walkover`
* Get node names close to player (to reduce constant querying): `PLAYER/mcl_playerinfo`
* Explosion API
* Music discs API
* Flowers and flower pots
### Unstable APIs
The following APIs may be subject to change in future. You could already use these APIs but there will probably be breaking changes in the future, or the API is not as fleshed out as it should be. Use at your own risk!
@ -79,12 +82,10 @@ The following APIs may be subject to change in future. You could already use the
### Planned APIs
* Flowers
* Saplings and trees
* Custom banner patterns
* Custom dimensions
* Custom portals
* Music discs
* Dispenser and dropper support
* Proper sky and weather APIs
* Explosion API

View File

@ -21,7 +21,7 @@ The basic digging time groups determine by which tools a node can be dug.
* `swordy=1`: Diggable by sword (any material), and this node is *not* a cobweb
* `swordy_cobweb=1`: Diggable by sword (any material), and this node is a cobweb
* `shearsy=1`: Diggable by shears, and this node is *not* wool
* `shearsy=wool=1`: Diggable by shears, and this node is wool
* `shearsy_wool=1`: Diggable by shears, and this node is wool
* `handy=1`: Breakable by hand and this node gives it useful drop when dug by hand. All nodes which are breakable by pickaxe, axe, shovel, sword or shears are also automatically breakable by hand, but not neccess
* `creative_breakable=1`: Block is breakable by hand in creative mode. This group is implied if the node belongs to any other digging group

View File

@ -2,7 +2,7 @@
An unofficial Minecraft-like game for Minetest. Forked from MineClone by davedevils.
Developed by many people. Not developed or endorsed by Mojang AB.
Version: 0.70.0
Version: 0.71.0
### Gameplay
You start in a randomly-generated world made entirely of cubes. You can explore
@ -185,6 +185,11 @@ Please report all bugs and missing Minecraft features here:
<https://git.minetest.land/MineClone2/MineClone2/issues>
## Chating with the community
Join our discord server at:
<https://discord.gg/84GKcxczG3>
## Other readme files
* `LICENSE.txt`: The GPLv3 license text
@ -206,6 +211,7 @@ There are so many people to list (sorry). Check out the respective mod directori
* [bzoss](https://github.com/bzoss): Status effects, potions, brewing stand
* kay27 <kay27@bk.ru>: Experience system, bugfixes, optimizations (Current maintainer)
* [EliasFleckenstein03](https://github.com/EliasFleckenstein03): End crystals, enchanting, burning mobs / players, animated chests, bugfixes (Current maintainer)
* epCode: Better player animations, new logo
* 2mac: Fix bug with powered rail
* Lots of other people: TO BE WRITTEN (see mod directories for details)

View File

@ -1 +1 @@
A survival sandbox game. Survive, gather, hunt, mine, build, explore, and do much more. Faithful clone of Minecraft 1.11. This is a work in progress! Expect bugs!
A survival sandbox game. Survive, gather, hunt, mine, build, explore, and do much more. Faithful clone of Minecraft 1.12. This is a work in progress! Expect bugs!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -32,4 +32,13 @@ mgvalleys_spflags = noaltitude_chill,noaltitude_dry,nohumid_rivers,vary_river_de
# MCL2-specific stuff
keepInventory = false
# Performance settings
dedicated_server_step = 0.001
abm_interval = 0.25
max_objects_per_block = 4096
max_packets_per_iteration = 10096
# Clientmodding to support official client
enable_client_modding = true
csm_restriction_flags = 0
enable_mod_channels = true

View File

@ -1 +0,0 @@
MineClone 2 core mod which automatically adds groups to all items. Very important for digging times.

View File

@ -1 +1,3 @@
name = _mcl_autogroup
author = Wuzzy
description = MineClone 2 core mod which automatically adds groups to all items. Very important for digging times.

View File

@ -1,2 +1,3 @@
name = biomeinfo
author = Wuzzy
description = Simple API to get data about biomes.

View File

@ -1,3 +1,6 @@
local get_connected_players = minetest.get_connected_players
local clock = os.clock
controls = {}
controls.players = {}
@ -42,7 +45,7 @@ minetest.register_on_leaveplayer(function(player)
end)
minetest.register_globalstep(function(dtime)
for _, player in pairs(minetest.get_connected_players()) do
for _, player in pairs(get_connected_players()) do
local player_name = player:get_player_name()
local player_controls = player:get_player_control()
if controls.players[player_name] then
@ -53,15 +56,15 @@ minetest.register_globalstep(function(dtime)
for _, func in pairs(controls.registered_on_press) do
func(player, cname)
end
controls.players[player_name][cname] = {true, os.clock()}
controls.players[player_name][cname] = {true, clock()}
elseif cbool==true and controls.players[player_name][cname][1]==true then
for _, func in pairs(controls.registered_on_hold) do
func(player, cname, os.clock()-controls.players[player_name][cname][2])
func(player, cname, clock()-controls.players[player_name][cname][2])
end
--Release a key
elseif cbool==false and controls.players[player_name][cname][1]==true then
for _, func in pairs(controls.registered_on_release) do
func(player, cname, os.clock()-controls.players[player_name][cname][2])
func(player, cname, clock()-controls.players[player_name][cname][2])
end
controls.players[player_name][cname] = {false}
end

View File

@ -1 +1,4 @@
name=controls
name = controls
author = Arcelmi
description = Controls framework by Arcelmi

View File

@ -1 +1,4 @@
name = flowlib
author = Qwertymine3
description = Simple flow functions for use in Minetest mods by Qwertymine3

View File

@ -1 +0,0 @@
Adds additional ways for nodes to be attached.

View File

@ -0,0 +1,3 @@
name = mcl_attached
author = Wuzzy
description = Adds additional ways for nodes to be attached.

View File

@ -0,0 +1,36 @@
mcl_colors = {
BLACK = "#000000",
DARK_BLUE = "#0000AA",
DARK_GREEN = "#00AA00",
DARK_AQUA = "#00AAAA",
DARK_RED = "#AA0000",
DARK_PURPLE = "#AA00AA",
GOLD = "#FFAA00",
GRAY = "#AAAAAA",
DARK_GRAY = "#555555",
BLUE = "#5555FF",
GREEN = "#55FF55",
AQUA = "#55FFFF",
RED = "#FF5555",
LIGHT_PURPLE = "#FF55FF",
YELLOW = "#FFFF55",
WHITE = "#FFFFFF",
background = {
BLACK = "#000000",
DARK_BLUE = "#00002A",
DARK_GREEN = "#002A00",
DARK_AQUA = "#002A2A",
DARK_RED = "#2A0000",
DARK_PURPLE = "#2A002A",
GOLD = "#2A2A00",
GRAY = "#2A2A2A",
DARK_GRAY = "#151515",
BLUE = "#15153F",
GREEN = "#153F15",
AQUA = "#153F3F",
RED = "#3F1515",
LIGHT_PURPLE = "#3F153F",
YELLOW = "#3F3F15",
WHITE = "#373501",
}
}

View File

@ -0,0 +1,3 @@
name = mcl_colors
author = Fleckenstein
description = The HTML sequences for the minecraft colors

View File

@ -18,6 +18,16 @@ local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire")
local S = minetest.get_translator("mcl_explosions")
local hash_node_position = minetest.hash_node_position
local get_objects_inside_radius = minetest.get_objects_inside_radius
local get_position_from_hash = minetest.get_position_from_hash
local get_node_drops = minetest.get_node_drops
local get_name_from_content_id = minetest.get_name_from_content_id
local get_voxel_manip = minetest.get_voxel_manip
local bulk_set_node = minetest.bulk_set_node
local check_for_falling = minetest.check_for_falling
local add_item = minetest.add_item
-- Saved sphere explosion shapes for various radiuses
local sphere_shapes = {}
@ -64,7 +74,7 @@ local function compute_sphere_rays(radius)
local d = x * x + y * y + z * z
if d <= radius * radius then
local pos = { x = x, y = y, z = z }
sphere[minetest.hash_node_position(pos)] = pos
sphere[hash_node_position(pos)] = pos
break
end
end
@ -79,7 +89,7 @@ local function compute_sphere_rays(radius)
local d = x * x + y * y + z * z
if d <= radius * radius then
local pos = { x = x, y = y, z = z }
sphere[minetest.hash_node_position(pos)] = pos
sphere[hash_node_position(pos)] = pos
break
end
end
@ -94,7 +104,7 @@ local function compute_sphere_rays(radius)
local d = x * x + y * y + z * z
if d <= radius * radius then
local pos = { x = x, y = y, z = z }
sphere[minetest.hash_node_position(pos)] = pos
sphere[hash_node_position(pos)] = pos
break
end
end
@ -149,12 +159,14 @@ end
-- max_blast_resistance - The explosion will treat all non-indestructible nodes
-- as having a blast resistance of no more than this
-- value
-- grief_protected - If true, the explosion will also destroy nodes which have
-- been protected
--
-- Note that this function has been optimized, it contains code which has been
-- inlined to avoid function calls and unnecessary table creation. This was
-- measured to give a significant performance increase.
local function trace_explode(pos, strength, raydirs, radius, info, puncher)
local vm = minetest.get_voxel_manip()
local vm = get_voxel_manip()
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
vector.add(pos, radius))
@ -178,6 +190,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
local drop_chance = info.drop_chance
local fire = info.fire
local max_blast_resistance = info.max_blast_resistance
local grief_protected = info.grief_protected
-- Trace rays for environment destruction
if info.griefing then
@ -194,6 +207,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
local npos_x = math.floor(rpos_x + 0.5)
local npos_y = math.floor(rpos_y + 0.5)
local npos_z = math.floor(rpos_z + 0.5)
local npos = { x = npos_x, y = npos_y, z = npos_z }
local idx = (npos_z - emin_z) * zstride + (npos_y - emin_y) * ystride +
npos_x - emin_x + 1
@ -203,7 +217,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
br = max_blast_resistance
end
local hash = minetest.hash_node_position({x=npos_x, y=npos_y, z=npos_z})
local hash = hash_node_position(npos)
rpos_x = rpos_x + STEP_LENGTH * rdir_x
rpos_y = rpos_y + STEP_LENGTH * rdir_y
@ -215,16 +229,18 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
break
end
if cid ~= minetest.CONTENT_AIR and not minetest.is_protected({x = npos_x, y = npos_y, z = npos_z}, "") then
if cid ~= minetest.CONTENT_AIR then
if not minetest.is_protected(npos, "") or grief_protected then
destroy[hash] = idx
end
end
end
end
end
-- Entities in radius of explosion
local punch_radius = 2 * strength
local objs = minetest.get_objects_inside_radius(pos, punch_radius)
local objs = get_objects_inside_radius(pos, punch_radius)
-- Trace rays for entity damage
for _, obj in pairs(objs) do
@ -329,13 +345,13 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
minetest.after(0.3, function(obj, damage, impact, punch_dir) -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE
if not obj then return end
obj:punch(obj, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
end, obj, damage, impact, vector.new(punch_dir))
else
obj:punch(source, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
if obj:is_player() then
obj:add_player_velocity(vector.multiply(punch_dir, impact * 20))
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
elseif ent.tnt_knockback then
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
end
@ -353,46 +369,46 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
local remove = true
if do_drop or on_blast ~= nil then
local npos = minetest.get_position_from_hash(hash)
local npos = get_position_from_hash(hash)
if on_blast ~= nil then
on_blast(npos, 1.0, do_drop)
remove = false
else
local name = minetest.get_name_from_content_id(data[idx])
local drop = minetest.get_node_drops(name, "")
local name = get_name_from_content_id(data[idx])
local drop = get_node_drops(name, "")
for _, item in ipairs(drop) do
if type(item) ~= "string" then
item = item:get_name() .. item:get_count()
end
minetest.add_item(npos, item)
add_item(npos, item)
end
end
end
if remove then
if mod_fire and fire and math.random(1, 3) == 1 then
table.insert(fires, minetest.get_position_from_hash(hash))
table.insert(fires, get_position_from_hash(hash))
else
table.insert(airs, minetest.get_position_from_hash(hash))
table.insert(airs, get_position_from_hash(hash))
end
end
end
-- We use bulk_set_node instead of LVM because we want to have on_destruct and
-- on_construct being called
if #airs > 0 then
minetest.bulk_set_node(airs, {name="air"})
bulk_set_node(airs, {name="air"})
end
if #fires > 0 then
minetest.bulk_set_node(fires, {name="mcl_fire:fire"})
bulk_set_node(fires, {name="mcl_fire:fire"})
end
-- Update falling nodes
for a=1, #airs do
local p = airs[a]
minetest.check_for_falling({x=p.x, y=p.y+1, z=p.z})
check_for_falling({x=p.x, y=p.y+1, z=p.z})
end
for f=1, #fires do
local p = fires[f]
minetest.check_for_falling({x=p.x, y=p.y+1, z=p.z})
check_for_falling({x=p.x, y=p.y+1, z=p.z})
end
-- Log explosion
@ -418,6 +434,8 @@ end
-- particles - If true, the explosion will create particles (default: true)
-- fire - If true, 1/3 nodes become fire (default: false)
-- griefing - If true, the explosion will destroy nodes (default: true)
-- grief_protected - If true, the explosion will also destroy nodes which have
-- been protected (default: false)
function mcl_explosions.explode(pos, strength, info, puncher)
if info == nil then
info = {}
@ -437,6 +455,7 @@ function mcl_explosions.explode(pos, strength, info, puncher)
if info.sound == nil then info.sound = true end
if info.fire == nil then info.fire = false end
if info.griefing == nil then info.griefing = true end
if info.grief_protected == nil then info.grief_protected = false end
if info.max_blast_resistance == nil then
info.max_blast_resistance = INDESTRUCT_BLASTRES
end

View File

@ -1,4 +1,5 @@
name = mcl_explosions
author = ryvnf
description = A common API to create explosions.
depends = mcl_particles
optional_depends = mcl_fire

View File

@ -1 +0,0 @@
Initialization mod of MineClone 2. Defines some common shared variables and sets up initial default settings which have to be set at the beginning.

View File

@ -46,6 +46,42 @@ local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / chunk_size_in_
mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes
mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes
local function coordinate_to_block(x)
return math.floor(x / mcl_vars.MAP_BLOCKSIZE)
end
local function coordinate_to_chunk(x)
return math.floor((coordinate_to_block(x) + central_chunk_offset) / mcl_vars.chunksize)
end
function mcl_vars.pos_to_block(pos)
return {
x = coordinate_to_block(pos.x),
y = coordinate_to_block(pos.y),
z = coordinate_to_block(pos.z)
}
end
function mcl_vars.pos_to_chunk(pos)
return {
x = coordinate_to_chunk(pos.x),
y = coordinate_to_chunk(pos.y),
z = coordinate_to_chunk(pos.z)
}
end
local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / chunk_size_in_nodes)
local k_positive_z = k_positive * 2
local k_positive_y = k_positive_z * k_positive_z
function mcl_vars.get_chunk_number(pos) -- unsigned int
local c = mcl_vars.pos_to_chunk(pos)
return
(c.y + k_positive) * k_positive_y +
(c.z + k_positive) * k_positive_z +
c.x + k_positive
end
if not superflat and not singlenode then
-- Normal mode
--[[ Realm stacking (h is for height)
@ -91,7 +127,7 @@ else
mcl_vars.mg_bedrock_is_rough = false
end
mcl_vars.mg_overworld_max = 31000
mcl_vars.mg_overworld_max = mcl_vars.mapgen_edge_max
-- The Nether (around Y = -29000)
mcl_vars.mg_nether_min = -29067 -- Carefully chosen to be at a mapchunk border

View File

@ -1 +1,3 @@
name = mcl_init
author = Wuzzy
description = Initialization mod of MineClone 2. Defines some common shared variables and sets up initial default settings which have to be set at the beginning.

View File

@ -1 +0,0 @@
API for filling a chest with random treasures.

View File

@ -111,14 +111,14 @@ end
Returns a table of length `max_slot` and all natural numbers between 1 and `max_slot`
in a random order.
]]
local function get_random_slots(max_slot)
local function get_random_slots(max_slot, pr)
local slots = {}
for s=1, max_slot do
slots[s] = s
end
local slots_out = {}
while #slots > 0 do
local r = math.random(1, #slots)
local r = pr and pr:next(1, #slots) or math.random(1, #slots)
table.insert(slots_out, slots[r])
table.remove(slots, r)
end
@ -135,9 +135,9 @@ Items will be added from start of the table to end.
If the inventory already has occupied slots, or is
too small, placement of some items might fail.
]]
function mcl_loot.fill_inventory(inv, listname, items)
function mcl_loot.fill_inventory(inv, listname, items, pr)
local size = inv:get_size(listname)
local slots = get_random_slots(size)
local slots = get_random_slots(size, pr)
local leftovers = {}
-- 1st pass: Add items into random slots
for i=1, math.min(#items, size) do

View File

@ -1 +1,3 @@
name = mcl_loot
author = Wuzzy
description = API for filling a chest with random treasures.

View File

@ -1 +0,0 @@
Contains particle images of MineClone 2. No code.

View File

@ -1 +1,3 @@
name = mcl_particles
author = Wuzzy
description = Contains particle images of MineClone 2. No code.

View File

@ -1 +0,0 @@
This mod contains the core sounds of MineClone 2 as well as helper function for mods to access them.

View File

@ -1 +1,3 @@
name = mcl_sounds
author = Wuzzy
description = This mod contains the core sounds of MineClone 2 as well as helper function for mods to access them.

View File

@ -1 +0,0 @@
mcl_init

View File

@ -1 +0,0 @@
Helper functions for MineClone 2.

View File

@ -406,52 +406,15 @@ function mcl_util.get_object_center(obj)
return pos
end
local get_node_emerge_queue = {}
local function ecb_get_far_node(blockpos, action, calls_remaining, param)
if calls_remaining <= 0 and param then
minetest.log("verbose","[mcl_util] ecb done for param = "..param.." node.name="..minetest.get_node(minetest.string_to_pos(param)).name)
get_node_emerge_queue[param] = nil
function mcl_util.get_color(colorstr)
local mc_color = mcl_colors[colorstr:upper()]
if mc_color then
colorstr = mc_color
elseif #colorstr ~= 7 or colorstr:sub(1, 1) ~= "#"then
return
end
local hex = tonumber(colorstr:sub(2, 7), 16)
if hex then
return colorstr, hex
end
end
function mcl_util.get_far_node(pos, force)
local node = minetest.get_node(pos)
if node.name ~= "ignore" then
return node
end
minetest.get_voxel_manip():read_from_map(pos, pos)
node = minetest.get_node(pos)
if node.name ~= "ignore" or not force then
return node
end
local blockpos = vector.multiply(vector.floor(vector.divide(pos, mcl_vars.MAP_BLOCKSIZE)), mcl_vars.MAP_BLOCKSIZE)
local key = minetest.pos_to_string(blockpos)
for i=1,2 do -- give engine 2 chances to emerge the data
if not get_node_emerge_queue[key] then
get_node_emerge_queue[key] = 1
minetest.log("verbose","[mcl_util] emerge during get_far_node("..minetest.pos_to_string(pos).."), key="..key..", blockpos="..minetest.pos_to_string(blockpos))
minetest.emerge_area(blockpos, vector.add(blockpos, mcl_vars.MAP_BLOCKSIZE-1), ecb_get_far_node, key)
end
while not get_node_emerge_queue[key] do end
minetest.log("verbose","[mcl_util] emerge finished for node "..minetest.pos_to_string(pos)..", key="..key..", blockpos="..minetest.pos_to_string(blockpos)..", node.name="..mcl_util.get_far_node(pos).name)
node = minetest.get_node(pos)
if node.name ~= "ignore" then
return node
end
minetest.get_voxel_manip():read_from_map(pos, pos)
node = minetest.get_node(pos)
if node.name ~= "ignore" or not force then
return node
end
end
node.name = "air" -- engine continuously returns "ignore" - probably it is a bug
minetest.swap_node(pos, node) -- engine continuously returns "ignore" - probably it is a bug
return node -- engine continuously returns "ignore" - probably it is a bug
end

View File

@ -1 +1,4 @@
name = mcl_util
author = Wuzzy
description = Helper functions for MineClone 2.
depends = mcl_init

View File

@ -1 +0,0 @@
mcl_init

View File

@ -1 +0,0 @@
Utility functions for worlds and the “dimensions”.

View File

@ -0,0 +1,5 @@
name = mcl_worlds
author = Wuzzy
description = Utility functions for worlds and the “dimensions”.
depends = mcl_init

View File

@ -1,4 +1,10 @@
-- register extra flavours of a base nodedef
local get_connected_players = minetest.get_connected_players
local get_node = minetest.get_node
local vector_add = vector.add
local ceil = math.ceil
walkover = {}
walkover.registered_globals = {}
@ -6,25 +12,38 @@ function walkover.register_global(func)
table.insert(walkover.registered_globals, func)
end
local on_walk = {}
local registered_globals = {}
minetest.register_on_mods_loaded(function()
for name,def in pairs(minetest.registered_nodes) do
if def.on_walk_over then
on_walk[name] = def.on_walk_over
end
end
for _,func in ipairs(walkover.registered_globals) do --cache registered globals
table.insert(registered_globals, func)
end
end)
local timer = 0
minetest.register_globalstep(function(dtime)
timer = timer + dtime;
if timer >= 0.3 then
for _,player in pairs(minetest.get_connected_players()) do
for _,player in pairs(get_connected_players()) do
local pp = player:get_pos()
pp.y = math.ceil(pp.y)
local loc = vector.add(pp, {x=0,y=-1,z=0})
pp.y = ceil(pp.y)
local loc = vector_add(pp, {x=0,y=-1,z=0})
if loc ~= nil then
local nodeiamon = minetest.get_node(loc)
local nodeiamon = get_node(loc)
if nodeiamon ~= nil then
local def = minetest.registered_nodes[nodeiamon.name]
if def ~= nil and def.on_walk_over ~= nil then
def.on_walk_over(loc, nodeiamon, player)
if on_walk[nodeiamon.name] then
on_walk[nodeiamon.name](loc, nodeiamon, player)
end
for _, func in ipairs(walkover.registered_globals) do
func(loc, nodeiamon, player)
for i = 1, #registered_globals do
registered_globals[i](loc, nodeiamon, player)
end
end
end

View File

@ -0,0 +1,4 @@
name = walkover
author = lordfingle
description = Some mode developers have shown an interest in having an `on_walk_over` event. This is useful for pressure-plates and the like.

View File

@ -1 +0,0 @@
mcl_core

View File

@ -0,0 +1,4 @@
name = drippingwater
author = kddekadenz
description = Drops are generated rarely under solid nodes
depends = mcl_core

View File

@ -20,4 +20,4 @@ Authors include:
* Various Minetest / Minetest Game developers and contributors (2012-2016)
* maikerumine (2017)
* Wuzzy (2017)
* Fleckenstein (2020-2021)

View File

@ -1,3 +0,0 @@
mcl_player
mcl_core?
doc_identifier?

View File

@ -1 +0,0 @@
Adds drivable boats.

View File

@ -1,13 +1,24 @@
local S = minetest.get_translator("mcl_boats")
--
-- Helper functions
--
local function is_water(pos)
local boat_visual_size = {x = 3, y = 3, z = 3}
local paddling_speed = 22
local boat_y_offset = 0.35
local boat_y_offset_ground = boat_y_offset + 0.6
local boat_side_offset = 1.001
local boat_max_hp = 4
local function is_group(pos, group)
local nn = minetest.get_node(pos).name
return minetest.get_item_group(nn, "water") ~= 0
return minetest.get_item_group(nn, group) ~= 0
end
local function is_water(pos)
return is_group(pos, "water")
end
local function is_ice(pos)
return is_group(pos, "ice")
end
local function get_sign(i)
if i == 0 then
@ -17,26 +28,83 @@ local function get_sign(i)
end
end
local function get_velocity(v, yaw, y)
local x = -math.sin(yaw) * v
local z = math.cos(yaw) * v
return {x = x, y = y, z = z}
end
local function get_v(v)
return math.sqrt(v.x ^ 2 + v.z ^ 2)
end
local boat_visual_size = {x = 3, y = 3}
-- Note: This mod assumes the default player visual_size is {x=1, y=1}
local driver_visual_size = { x = 1/boat_visual_size.x, y = 1/boat_visual_size.y }
local paddling_speed = 22
local boat_y_offset = 0.35
local boat_y_offset_ground = boat_y_offset + 0.6
local boat_side_offset = 1.001
local boat_max_hp = 4
local function check_object(obj)
return obj and (obj:is_player() or obj:get_luaentity()) and obj
end
local function get_visual_size(obj)
return obj:is_player() and {x = 1, y = 1, z = 1} or obj:get_luaentity()._old_visual_size or obj:get_properties().visual_size
end
local function set_attach(boat)
boat._driver:set_attach(boat.object, "",
{x = 0, y = 0.42, z = -1}, {x = 0, y = 0, z = 0})
end
local function set_double_attach(boat)
boat._driver:set_attach(boat.object, "",
{x = 0, y = 0.42, z = 0.8}, {x = 0, y = 0, z = 0})
boat._passenger:set_attach(boat.object, "",
{x = 0, y = 0.42, z = -2.2}, {x = 0, y = 0, z = 0})
end
local function attach_object(self, obj)
if self._driver then
if self._driver:is_player() then
self._passenger = obj
else
self._passenger = self._driver
self._driver = obj
end
set_double_attach(self)
else
self._driver = obj
set_attach(self)
end
local visual_size = get_visual_size(obj)
local yaw = self.object:get_yaw()
obj:set_properties({visual_size = vector.divide(visual_size, boat_visual_size)})
if obj:is_player() then
local name = obj:get_player_name()
mcl_player.player_attached[name] = true
minetest.after(0.2, function(name)
local player = minetest.get_player_by_name(name)
if player then
mcl_player.player_set_animation(player, "sit" , 30)
end
end, name)
obj:set_look_horizontal(yaw)
mcl_tmp_message.message(obj, S("Sneak to dismount"))
else
obj:get_luaentity()._old_visual_size = visual_size
end
end
local function detach_object(obj, change_pos)
obj:set_detach()
obj:set_properties({visual_size = get_visual_size(obj)})
if obj:is_player() then
mcl_player.player_attached[obj:get_player_name()] = false
mcl_player.player_set_animation(obj, "stand" , 30)
else
obj:get_luaentity()._old_visual_size = nil
end
if change_pos then
obj:set_pos(vector.add(obj:get_pos(), vector.new(0, 0.2, 0)))
end
end
--
-- Boat entity
@ -52,6 +120,7 @@ local boat = {
textures = {"mcl_boats_texture_oak_boat.png"},
visual_size = boat_visual_size,
hp_max = boat_max_hp,
damage_texture_modifier = "^[colorize:white:0",
_driver = nil, -- Attached driver (player) or nil if none
_passenger = nil,
@ -60,87 +129,31 @@ local boat = {
_removed = false, -- If true, boat entity is considered removed (e.g. after punch) and should be ignored
_itemstring = "mcl_boats:boat", -- Itemstring of the boat item (implies boat type)
_animation = 0, -- 0: not animated; 1: paddling forwards; -1: paddling forwards
_regen_timer = 0,
_damage_anim = 0,
}
local function detach_player(player, change_pos)
player:set_detach()
player:set_properties({visual_size = {x=1, y=1}})
mcl_player.player_attached[player:get_player_name()] = false
mcl_player.player_set_animation(player, "stand" , 30)
if change_pos then
player:set_pos(vector.add(player:get_pos(), vector.new(0, 0.2, 0)))
end
end
local function check_object(obj)
return obj and (obj:is_player() or obj:get_luaentity()) and obj
end
local function set_attach(boat)
boat._driver:set_attach(boat.object, "",
{x = 0, y = 0.42, z = -1}, {x = 0, y = 0, z = 0})
end
local function set_double_attach(boat)
boat._driver:set_attach(boat.object, "",
{x = 0, y = 0.42, z = 0.8}, {x = 0, y = 0, z = 0})
boat._passenger:set_attach(boat.object, "",
{x = 0, y = 0.42, z = -2.2}, {x = 0, y = 0, z = 0})
end
minetest.register_on_respawnplayer(detach_player)
minetest.register_on_respawnplayer(detach_object)
function boat.on_rightclick(self, clicker)
if self._passenger or not clicker or clicker:get_attach() then
return
end
local name = clicker:get_player_name()
--[[if attach and attach:get_luaentity() then
local luaentity = attach:get_luaentity()
if luaentity._driver then
luaentity._driver = nil
end
clicker:set_detach()
clicker:set_properties({visual_size = {x=1, y=1}})
end--]]
if self._driver then
if self._driver:is_player() then
self._passenger = clicker
else
-- for later use: transport mobs in boats
self._passenger = self._driver
self._driver = clicker
end
set_double_attach(self)
else
self._driver = clicker
set_attach(self)
end
clicker:set_properties({ visual_size = driver_visual_size })
mcl_player.player_attached[name] = true
minetest.after(0.2, function(name)
local player = minetest.get_player_by_name(name)
if player then
mcl_player.player_set_animation(player, "sit" , 30)
end
end, name)
clicker:set_look_horizontal(self.object:get_yaw())
mcl_tmp_message.message(clicker, S("Sneak to dismount"))
attach_object(self, clicker)
end
function boat.on_activate(self, staticdata, dtime_s)
--self.object:set_armor_groups({immortal = 1})
self.object:set_armor_groups({fleshy = 100})
local data = minetest.deserialize(staticdata)
if type(data) == "table" then
self._v = data.v
self._last_v = self._v
self._itemstring = data.itemstring
self.object:set_properties({textures = data.textures, damage_texture_modifier = ""})
self.object:set_properties({textures = data.textures})
end
end
function boat.get_staticdata(self)
return minetest.serialize({
v = self._v,
@ -149,8 +162,9 @@ function boat.get_staticdata(self)
})
end
function boat.on_death(self, killer)
mcl_burning.extinguish(self.object)
if killer and killer:is_player() and minetest.is_creative_enabled(killer:get_player_name()) then
local inv = killer:get_inventory()
if not inv:contains_item("main", self._itemstring) then
@ -160,43 +174,62 @@ function boat.on_death(self, killer)
minetest.add_item(self.object:get_pos(), self._itemstring)
end
if self._driver then
detach_player(self._driver)
detach_object(self._driver)
end
if self._passenger then
detach_player(self._passenger)
detach_object(self._passenger)
end
self._driver = nil
self._passenger = nil
end
function boat.on_punch(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
if damage > 0 then
self._regen_timer = 0
end
end
function boat.on_step(self, dtime, moveresult)
mcl_burning.tick(self.object, dtime)
self._v = get_v(self.object:get_velocity()) * get_sign(self._v)
local on_water = true
local in_water = false
local v_factor = 1
local v_slowdown = 0.02
local p = self.object:get_pos()
if (not is_water({x=p.x, y=p.y-boat_y_offset, z=p.z})) then
local on_water = true
local on_ice = false
local in_water = is_water({x=p.x, y=p.y-boat_y_offset+1, z=p.z})
local waterp = {x=p.x, y=p.y-boat_y_offset - 0.1, z=p.z}
if not is_water(waterp) then
on_water = false
v_factor = 0.5
if not in_water and is_ice(waterp) then
on_ice = true
else
v_slowdown = 0.04
elseif (is_water({x=p.x, y=p.y-boat_y_offset+1, z=p.z})) then
v_factor = 0.5
end
elseif in_water then
on_water = false
in_water = true
v_factor = 0.75
v_slowdown = 0.05
end
--local yaw = self.object:get_yaw()
--local hp = math.min(self.object:get_hp() + 2 * dtime, boat_max_hp)
--self.object:set_rotation(vector.new((boat_max_hp - hp) / boat_max_hp, 0, 0))
self.object:set_hp(self.object:get_hp() + 2 * dtime)
--self.object:set_yaw(yaw)
local hp = self.object:get_hp()
local regen_timer = self._regen_timer + dtime
if hp >= boat_max_hp then
regen_timer = 0
elseif regen_timer >= 0.5 then
hp = hp + 1
self.object:set_hp(hp)
regen_timer = 0
end
self._regen_timer = regen_timer
if moveresult and moveresult.collides then
for _, collision in ipairs(moveresult.collisions) do
for _, collision in pairs(moveresult.collisions) do
local pos = collision.node_pos
if collision.type == "node" and minetest.get_node_group(minetest.get_node(pos).name, "dig_by_boat") > 0 then
if collision.type == "node" and minetest.get_item_group(minetest.get_node(pos).name, "dig_by_boat") > 0 then
minetest.dig_node(pos)
end
end
@ -226,7 +259,7 @@ function boat.on_step(self, dtime, moveresult)
end
local ctrl = self._driver:get_player_control()
if ctrl and ctrl.sneak then
detach_player(self._driver, true)
detach_object(self._driver, true)
self._driver = nil
return
end
@ -275,11 +308,19 @@ function boat.on_step(self, dtime, moveresult)
self.object:set_animation({x=0, y=40}, 0, 0, true)
self._animation = 0
end
for _, obj in pairs(minetest.get_objects_inside_radius(self.object:get_pos(), 1.3)) do
local entity = obj:get_luaentity()
if entity and entity._cmi_is_mob then
attach_object(self, obj)
break
end
end
end
local s = get_sign(self._v)
if not on_water and not in_water and math.abs(self._v) > 1.0 then
v_slowdown = math.min(math.abs(self._v) - 1.0, v_slowdown * 5)
elseif in_water and math.abs(self._v) > 1.5 then
if not on_ice and not on_water and not in_water and math.abs(self._v) > 2.0 then
v_slowdown = math.min(math.abs(self._v) - 2.0, v_slowdown * 5)
elseif not on_ice and in_water and math.abs(self._v) > 1.5 then
v_slowdown = math.min(math.abs(self._v) - 1.5, v_slowdown * 5)
end
self._v = self._v - v_slowdown * s
@ -290,7 +331,7 @@ function boat.on_step(self, dtime, moveresult)
p.y = p.y - boat_y_offset
local new_velo
local new_acce = {x = 0, y = 0, z = 0}
if not is_water(p) then
if not is_water(p) and not on_ice then
-- Not on water or inside water: Free fall
local nodedef = minetest.registered_nodes[minetest.get_node(p).name]
new_acce = {x = 0, y = -9.8, z = 0}
@ -320,12 +361,17 @@ function boat.on_step(self, dtime, moveresult)
end
-- Terminal velocity: 8 m/s per axis of travel
local terminal_velocity = on_ice and 57.1 or 8.0
for _,axis in pairs({"z","y","x"}) do
if math.abs(new_velo[axis]) > 8 then
new_velo[axis] = 8 * get_sign(new_velo[axis])
if math.abs(new_velo[axis]) > terminal_velocity then
new_velo[axis] = terminal_velocity * get_sign(new_velo[axis])
end
end
local yaw = self.object:get_yaw()
local anim = (boat_max_hp - hp - regen_timer * 2) / boat_max_hp * math.pi / 4
self.object:set_rotation(vector.new(anim, yaw, anim))
self.object:set_velocity(new_velo)
self.object:set_acceleration(new_acce)
end

View File

@ -1 +1,7 @@
name = mcl_boats
author = PilzAdam
description = Adds drivable boats.
depends = mcl_player
optional_depends = mcl_core, doc_identifier

View File

@ -34,7 +34,7 @@ function mcl_burning.is_burning(obj)
end
function mcl_burning.is_affected_by_rain(obj)
return mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos())
return mcl_weather and mcl_weather.get_weather() == "rain" and mcl_weather.is_outdoor(obj:get_pos())
end
function mcl_burning.get_collisionbox(obj, smaller)
@ -107,11 +107,7 @@ function mcl_burning.damage(obj)
end
if do_damage then
local damage = mcl_burning.get(obj, "float", "damage")
if damage == 0 then
damage = 1
end
local new_hp = hp - damage
local new_hp = hp - 1
if health then
luaentity.health = new_hp
else
@ -120,7 +116,7 @@ function mcl_burning.damage(obj)
end
end
function mcl_burning.set_on_fire(obj, burn_time, damage, interval, reason)
function mcl_burning.set_on_fire(obj, burn_time, reason)
local luaentity = obj:get_luaentity()
if luaentity and luaentity.fire_resistant then
return
@ -173,8 +169,6 @@ function mcl_burning.set_on_fire(obj, burn_time, damage, interval, reason)
end
end
mcl_burning.set(obj, "float", "burn_time", burn_time)
mcl_burning.set(obj, "float", "damage", damage)
mcl_burning.set(obj, "float", "interval", interval)
mcl_burning.set(obj, "string", "reason", reason)
mcl_burning.set(obj, "int", "hud_id", hud_id)
mcl_burning.set(obj, "int", "sound_id", sound_id)
@ -208,8 +202,6 @@ function mcl_burning.extinguish(obj)
obj:hud_remove(hud_id)
end
mcl_burning.set(obj, "float", "damage")
mcl_burning.set(obj, "float", "interval")
mcl_burning.set(obj, "string", "reason")
mcl_burning.set(obj, "float", "burn_time")
mcl_burning.set(obj, "float", "damage_timer")
@ -240,12 +232,7 @@ function mcl_burning.tick(obj, dtime)
local damage_timer = mcl_burning.get(obj, "float", "damage_timer") + dtime
local interval = mcl_burning.get(obj, "float", "interval")
if interval == 0 then
interval = 1
end
if damage_timer >= interval then
if damage_timer >= 1 then
damage_timer = 0
mcl_burning.damage(obj)
end
@ -280,7 +267,7 @@ function mcl_burning.fire_entity_step(self, dtime)
if not parent or not mcl_burning.is_burning(parent) then
do_remove = true
else
for _, other in ipairs(minetest.get_objects_inside_radius(obj:get_pos(), 0)) do
for _, other in pairs(minetest.get_objects_inside_radius(obj:get_pos(), 0)) do
local luaentity = obj:get_luaentity()
if luaentity and luaentity.name == "mcl_burning:fire" and not luaentity.doing_step and not luaentity.removed then
do_remove = true

View File

@ -5,7 +5,7 @@ mcl_burning = {
animation_frames = tonumber(minetest.settings:get("fire_animation_frames")) or 8
}
dofile(modpath .. "/engine.lua")
dofile(modpath .. "/api.lua")
minetest.register_entity("mcl_burning:fire", {
initial_properties = {
@ -22,7 +22,7 @@ minetest.register_entity("mcl_burning:fire", {
})
minetest.register_globalstep(function(dtime)
for _, player in ipairs(minetest.get_connected_players()) do
for _, player in pairs(minetest.get_connected_players()) do
mcl_burning.tick(player, dtime)
end
end)

View File

@ -1 +0,0 @@
Falling node entities, Minecraft-style

View File

@ -1 +1,3 @@
name = mcl_falling_nodes
author = Wuzzy
description = Falling node entities, Minecraft-style

View File

@ -1,2 +0,0 @@
flowlib
mcl_enchanting

View File

@ -1 +0,0 @@
Dropped items will be attracted to the player like a magnet.

View File

@ -54,14 +54,14 @@ local disable_physics = function(object, luaentity, ignore_check, reset_movement
end
minetest.register_globalstep(function(dtime)
for _,player in ipairs(minetest.get_connected_players()) do
for _,player in pairs(minetest.get_connected_players()) do
if player:get_hp() > 0 or not minetest.settings:get_bool("enable_damage") then
local pos = player:get_pos()
local inv = player:get_inventory()
local checkpos = {x=pos.x,y=pos.y + item_drop_settings.player_collect_height,z=pos.z}
--magnet and collection
for _,object in ipairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
for _,object in pairs(minetest.get_objects_inside_radius(checkpos, item_drop_settings.xp_radius_magnet)) do
if not object:is_player() and vector.distance(checkpos, object:get_pos()) < item_drop_settings.radius_magnet and object:get_luaentity() and object:get_luaentity().name == "__builtin:item" and object:get_luaentity()._magnet_timer and (object:get_luaentity()._insta_collect or (object:get_luaentity().age > item_drop_settings.age)) then
object:get_luaentity()._magnet_timer = object:get_luaentity()._magnet_timer + dtime
local collected = false
@ -785,7 +785,7 @@ minetest.register_entity(":__builtin:item", {
if self.physical_state then
local own_stack = ItemStack(self.object:get_luaentity().itemstring)
-- Merge with close entities of the same item
for _, object in ipairs(minetest.get_objects_inside_radius(p, 0.8)) do
for _, object in pairs(minetest.get_objects_inside_radius(p, 0.8)) do
local obj = object:get_luaentity()
if obj and obj.name == "__builtin:item"
and obj.physical_state == false then

View File

@ -1 +1,4 @@
name = mcl_item_entity
author = PilzAdam
description = Dropped items will be attracted to the player like a magnet.
depends = flowlib, mcl_enchanting

View File

@ -1,12 +0,0 @@
mcl_explosions
mcl_core
mcl_sounds
mcl_player
mcl_achievements
mcl_chests
mcl_furnaces
mesecons_commandblock
mcl_hoppers
mcl_tnt
mesecons
doc_identifier?

View File

@ -1 +0,0 @@
Minecarts are vehicles to move players quickly on rails.

View File

@ -175,6 +175,19 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
cart.on_activate_by_rail = on_activate_by_rail
function cart:on_step(dtime)
local ctrl, player = nil, nil
if self._driver then
player = minetest.get_player_by_name(self._driver)
if player then
ctrl = player:get_player_control()
-- player detach
if ctrl.sneak then
detach_driver(self)
return
end
end
end
local vel = self.object:get_velocity()
local update = {}
if self._last_float_check == nil then
@ -190,19 +203,15 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
node = minetest.get_node(rou_pos)
local g = minetest.get_item_group(node.name, "connect_to_raillike")
if g ~= self._railtype and self._railtype ~= nil then
local player
-- Detach driver
if self._driver then
if player then
if self._old_pos then
self.object:set_pos(self._old_pos)
end
mcl_player.player_attached[self._driver] = nil
player = minetest.get_player_by_name(self._driver)
if player then
player:set_detach()
player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
end
end
-- Explode if already ignited
if self._boomtimer then
@ -337,14 +346,6 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
end
end
local ctrl, player = nil, nil
if self._driver then
player = minetest.get_player_by_name(self._driver)
if player then
ctrl = player:get_player_control()
end
end
-- Stop cart if velocity vector flips
if self._old_vel and self._old_vel.y == 0 and
(self._old_vel.x * vel.x < 0 or self._old_vel.z * vel.z < 0) then
@ -643,6 +644,7 @@ register_minecart(
if player then
mcl_player.player_set_animation(player, "sit" , 30)
player:set_eye_offset({x=0, y=-5.5, z=0},{x=0, y=-4, z=0})
mcl_tmp_message.message(clicker, S("Sneak to dismount"))
end
end, name)
end
@ -661,6 +663,8 @@ register_minecart(
{"mcl_minecarts:minecart", "mcl_chests:chest"},
nil, nil, false)
mcl_wip.register_wip_item("mcl_minecarts:chest_minecart")
-- Minecart with Furnace
register_minecart(
"mcl_minecarts:furnace_minecart",
@ -715,6 +719,8 @@ register_minecart(
end, nil, false
)
mcl_wip.register_wip_item("mcl_minecarts:furnace_minecart")
-- Minecart with Command Block
register_minecart(
"mcl_minecarts:command_block_minecart",
@ -736,6 +742,8 @@ register_minecart(
nil, nil, false
)
mcl_wip.register_wip_item("mcl_minecarts:command_block_minecart")
-- Minecart with Hopper
register_minecart(
"mcl_minecarts:hopper_minecart",
@ -754,6 +762,8 @@ register_minecart(
nil, nil, false
)
mcl_wip.register_wip_item("mcl_minecarts:hopper_minecart")
-- Minecart with TNT
register_minecart(
"mcl_minecarts:tnt_minecart",

View File

@ -33,3 +33,4 @@ Activates minecarts when powered=Активирует особые вагоне
Emits redstone power when a minecart is detected=Испускает энергию редстоуна при обнаружении вагонетки
Vehicle for fast travel on rails=Быстрый железнодорожный транспорт
Can be ignited by tools or powered activator rail=Можно воспламенить с помощью инструмента или подключенного рельсового активатора
Sneak to dismount=Нажмите [Красться] для высадки

View File

@ -33,3 +33,4 @@ Activates minecarts when powered=
Emits redstone power when a minecart is detected=
Vehicle for fast travel on rails=
Can be ignited by tools or powered activator rail=
Sneak to dismount=

View File

@ -1 +1,6 @@
name = mcl_minecarts
author = Krock
description = Minecarts are vehicles to move players quickly on rails.
depends = mcl_explosions, mcl_core, mcl_sounds, mcl_player, mcl_achievements, mcl_chests, mcl_furnaces, mesecons_commandblock, mcl_hoppers, mcl_tnt, mesecons, mcl_wip
optional_depends = doc_identifier

View File

@ -226,7 +226,7 @@ local collision = function(self)
local z = 0
local width = -self.collisionbox[1] + self.collisionbox[4] + 0.5
for _,object in ipairs(minetest.get_objects_inside_radius(pos, width)) do
for _,object in pairs(minetest.get_objects_inside_radius(pos, width)) do
if object:is_player()
or (object:get_luaentity()._cmi_is_mob == true and object ~= self.object) then
@ -396,7 +396,7 @@ local is_node_dangerous = function(self, nodename)
return true
end
end
if minetest.registered_nodes[nn].damage_per_second and minetest.registered_nodes[nn].damage_per_second > 0 then
if minetest.registered_nodes[nn] and minetest.registered_nodes[nn].damage_per_second and minetest.registered_nodes[nn].damage_per_second > 0 then
return true
end
return false
@ -751,10 +751,10 @@ local check_for_death = function(self, cause, cmi_cause)
-- play damage sound if health was reduced and make mob flash red.
if damaged then
add_texture_mod(self, "^[colorize:#FF000040")
add_texture_mod(self, "^[colorize:red:130")
minetest.after(.2, function(self)
if self and self.object then
remove_texture_mod(self, "^[colorize:#FF000040")
remove_texture_mod(self, "^[colorize:red:130")
end
end, self)
mob_sound(self, "damage")
@ -1047,8 +1047,13 @@ local do_env_damage = function(self)
end
end
-- Use get_node_light for Minetest version 5.3 where get_natural_light
-- does not exist yet.
local get_light = minetest.get_natural_light or minetest.get_node_light
local sunlight = get_light(pos, self.time_of_day)
-- bright light harms mob
if self.light_damage ~= 0 and (minetest.get_node_light(pos) or 0) > 12 then
if self.light_damage ~= 0 and (sunlight or 0) > 12 then
if deal_light_damage(self, pos, self.light_damage) then
return true
end
@ -1057,9 +1062,9 @@ local do_env_damage = function(self)
if mod_worlds then
_, dim = mcl_worlds.y_to_layer(pos.y)
end
if (self.sunlight_damage ~= 0 or self.ignited_by_sunlight) and (minetest.get_node_light(pos) or 0) >= minetest.LIGHT_MAX and dim == "overworld" then
if (self.sunlight_damage ~= 0 or self.ignited_by_sunlight) and (sunlight or 0) >= minetest.LIGHT_MAX and dim == "overworld" then
if self.ignited_by_sunlight then
mcl_burning.set_on_fire(self.object, 10, self.sunlight_damage or 1)
mcl_burning.set_on_fire(self.object, 10)
else
deal_light_damage(self, pos, self.sunlight_damage)
return true
@ -2975,8 +2980,7 @@ local mob_punch = function(self, hitter, tflp, tool_capabilities, dir)
if weapon then
local fire_aspect_level = mcl_enchanting.get_enchantment(weapon, "fire_aspect")
if fire_aspect_level > 0 then
local damage = fire_aspect_level * 4 - 1
mcl_burning.set_on_fire(self.object, 4, 1, 4 / damage)
mcl_burning.set_on_fire(self.object, fire_aspect_level * 4)
end
end
@ -3712,6 +3716,7 @@ end
minetest.register_entity(name, {
use_texture_alpha = def.use_texture_alpha,
stepheight = def.stepheight or 0.6,
name = name,
type = def.type,
@ -4576,9 +4581,9 @@ local timer = 0
minetest.register_globalstep(function(dtime)
timer = timer + dtime
if timer < 1 then return end
for _, player in ipairs(minetest.get_connected_players()) do
for _, player in pairs(minetest.get_connected_players()) do
local pos = player:get_pos()
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 47)) do
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 47)) do
local lua = obj:get_luaentity()
if lua and lua._cmi_is_mob then
lua.lifetimer = math.max(20, lua.lifetimer)

View File

@ -1 +0,0 @@
Adds a mob API for mods to add animals or monsters, etc.

View File

@ -1,3 +1,5 @@
name = mcl_mobs
author = PilzAdam
description = Adds a mob API for mods to add animals or monsters, etc.
depends = mcl_particles
optional_depends = mcl_weather, mcl_explosions, mcl_hunger, mcl_worlds, invisibility, lucky_block, cmi, doc_identifier, mcl_armor, mcl_portals, mcl_experience

View File

@ -154,7 +154,7 @@ function mobs.attach(entity, player)
minetest.after(0.2, function(name)
local player = minetest.get_player_by_name(name)
if player then
mcl_player.player_set_animation(player, "sit" , 30)
mcl_player.player_set_animation(player, "sit_mount" , 30)
end
end, player:get_player_name())

View File

@ -191,6 +191,14 @@ minetest.register_craftitem("mcl_paintings:painting", {
if pointed_thing.type ~= "node" then
return itemstack
end
local node = minetest.get_node(pointed_thing.under)
if placer and not placer:get_player_control().sneak then
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
end
end
local dir = vector.subtract(pointed_thing.above, pointed_thing.under)
dir = vector.normalize(dir)
if dir.y ~= 0 then
@ -293,6 +301,8 @@ minetest.register_craftitem("mcl_paintings:painting", {
end,
})
mcl_wip.register_wip_item("mcl_paintings:painting")
minetest.register_craft({
output = "mcl_paintings:painting",
recipe = {

View File

@ -1 +1,5 @@
name = mcl_paintings
author = Wuzzy
description = The paintings mod for MCL2
depends = mcl_wip

View File

@ -122,7 +122,7 @@ local arrows = {
}
local throwing_shoot_arrow = function(itemstack, player)
for _,arrow in ipairs(arrows) do
for _,arrow in pairs(arrows) do
if player:get_inventory():get_stack("main", player:get_wield_index()+1):get_name() == arrow[1] then
if not minetest.is_creative_enabled(player:get_player_name()) then
player:get_inventory():remove_item("main", arrow[1])

View File

@ -91,7 +91,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
if rawget(_G, "armor") and armor.last_damage_types then
armor.last_damage_types[player:get_player_name()] = "fireball"
end
mcl_burning.set_on_fire(player, 5, 1, 5 / 4, "blaze")
mcl_burning.set_on_fire(player, 5, "blaze")
player:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = 5},
@ -99,7 +99,7 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
end,
hit_mob = function(self, mob)
mcl_burning.set_on_fire(mob, 5, 1, 5 / 4)
mcl_burning.set_on_fire(mob, 5)
mob:punch(self.object, 1.0, {
full_punch_interval = 1.0,
damage_groups = {fleshy = 5},

View File

@ -1,12 +0,0 @@
mcl_init
mcl_particles
default?
mcl_mobs
mcl_tnt?
mcl_bows?
mcl_throwing?
mcl_fishing?
bones?
mesecons_materials?
mobs_mc_gameconfig?
doc_items?

View File

@ -1 +0,0 @@
Adds Minecraft-like monsters and animals.

View File

@ -25,6 +25,7 @@ mobs:register_mob("mobs_mc:enderdragon", {
view_range = 35,
walk_velocity = 6,
run_velocity = 6,
can_despawn = false,
sounds = {
-- TODO: more sounds
shoot_attack = "mobs_mc_ender_dragon_shoot",
@ -104,3 +105,5 @@ mobs:register_arrow("mobs_mc:dragon_fireball", {
})
mobs:register_egg("mobs_mc:enderdragon", S("Ender Dragon"), "mobs_mc_spawn_icon_dragon.png", 0, true)
mcl_wip.register_wip_item("mobs_mc:enderdragon")

View File

@ -242,6 +242,8 @@ mobs:register_mob("mobs_mc:enderman", {
})
end
-- RAIN DAMAGE / EVASIVE WARP BEHAVIOUR HERE.
local dim = mcl_worlds.pos_to_dimension(enderpos)
if dim == "overworld" then
if mcl_weather.state == "rain" or mcl_weather.state == "lightning" then
local damage = true
local enderpos = self.object:get_pos()
@ -272,6 +274,7 @@ mobs:register_mob("mobs_mc:enderman", {
self:teleport(nil)
end
end
else return end
-- AGRESSIVELY WARP/CHASE PLAYER BEHAVIOUR HERE.
if self.state == "attack" then
--if (minetest.get_timeofday() * 24000) > 5001 and (minetest.get_timeofday() * 24000) < 19000 then

View File

@ -450,7 +450,7 @@ mobs:spawn_specific("mobs_mc:donkey", mobs_mc.spawn.grassland_savanna, {"air"},
-- spawn eggs
mobs:register_egg("mobs_mc:horse", S("Horse"), "mobs_mc_spawn_icon_horse.png", 0)
mobs:register_egg("mobs_mc:skeleton_horse", S("Skeleton Horse"), "mobs_mc_spawn_icon_horse_skeleton.png", 0)
mobs:register_egg("mobs_mc:zombie_horse", S("Zombie Horse"), "mobs_mc_spawn_icon_horse_zombie.png", 0)
--mobs:register_egg("mobs_mc:skeleton_horse", S("Skeleton Horse"), "mobs_mc_spawn_icon_horse_skeleton.png", 0)
--mobs:register_egg("mobs_mc:zombie_horse", S("Zombie Horse"), "mobs_mc_spawn_icon_horse_zombie.png", 0)
mobs:register_egg("mobs_mc:donkey", S("Donkey"), "mobs_mc_spawn_icon_donkey.png", 0)
mobs:register_egg("mobs_mc:mule", S("Mule"), "mobs_mc_spawn_icon_mule.png", 0)

View File

@ -1 +1,6 @@
name = mobs_mc
author = maikerumine
description = Adds Minecraft-like monsters and animals.
depends = mcl_init, mcl_particles, mcl_mobs, mcl_wip
optional_depends = default, mcl_tnt, mcl_bows, mcl_throwing, mcl_fishing, bones, mesecons_materials, mobs_mc_gameconfig, doc_items

View File

@ -110,6 +110,7 @@ local slime_big = {
spawn_small_alternative = "mobs_mc:slime_small",
on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5),
fire_resistant = true,
use_texture_alpha = true,
}
mobs:register_mob("mobs_mc:slime_big", slime_big)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 992 B

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -412,6 +412,7 @@ local init_trades = function(self, inv)
offered_stack = mcl_enchanting.get_uniform_randomly_enchanted_book({"soul_speed"})
else
mcl_enchanting.enchant_randomly(offered_stack, math.random(5, 19), false, false, true)
mcl_enchanting.unload_enchantments(offered_stack)
end
end
@ -457,7 +458,9 @@ local set_trade = function(trader, player, inv, concrete_tradenum)
player_tradenum[name] = concrete_tradenum
local trade = trades[concrete_tradenum]
inv:set_stack("wanted", 1, ItemStack(trade.wanted[1]))
inv:set_stack("offered", 1, ItemStack(trade.offered))
local offered = ItemStack(trade.offered)
mcl_enchanting.load_enchantments(offered)
inv:set_stack("offered", 1, offered)
if trade.wanted[2] then
local wanted2 = ItemStack(trade.wanted[2])
inv:set_stack("wanted", 2, wanted2)

View File

@ -104,3 +104,5 @@ mobs:register_arrow("mobs_mc:potion_arrow", {
-- spawn eggs
mobs:register_egg("mobs_mc:witch", S("Witch"), "mobs_mc_spawn_icon_witch.png", 0, true)
mcl_wip.register_wip_item("mobs_mc:witch")

View File

@ -43,6 +43,7 @@ mobs:register_mob("mobs_mc:wither", {
dogshoot_switch = 1,
dogshoot_count_max =1,
attack_animals = true,
can_despawn = false,
drops = {
{name = mobs_mc.items.nether_star,
chance = 1,
@ -105,3 +106,5 @@ mobs:register_arrow("mobs_mc:wither_skull", {
--Spawn egg
mobs:register_egg("mobs_mc:wither", S("Wither"), "mobs_mc_spawn_icon_wither.png", 0, true)
mcl_wip.register_wip_item("mobs_mc:wither")

View File

@ -1,2 +0,0 @@
mcl_init
mcl_core

View File

@ -0,0 +1,4 @@
name = mobs_mc_gameconfig
author = Wuzzy
description = mobs_mc game configuration for MCL2
depends = mcl_init, mcl_core

View File

@ -1,2 +0,0 @@
mcl_fire
mcl_death_messages?

View File

@ -1 +0,0 @@
A mod that adds thunder and lightning effects.

View File

@ -11,6 +11,18 @@ of the license, or (at your option) any later version.
local S = minetest.get_translator("lightning")
local has_mcl_death_msg = minetest.get_modpath("mcl_death_messages")
local get_connected_players = minetest.get_connected_players
local line_of_sight = minetest.line_of_sight
local get_node = minetest.get_node
local set_node = minetest.set_node
local sound_play = minetest.sound_play
local add_particlespawner = minetest.add_particlespawner
local after = minetest.after
local add_entity = minetest.add_entity
local get_objects_inside_radius = minetest.get_objects_inside_radius
local get_item_group = minetest.get_item_group
lightning = {}
lightning.interval_low = 17
@ -45,7 +57,7 @@ minetest.register_globalstep(revertsky)
-- select a random strike point, midpoint
local function choose_pos(pos)
if not pos then
local playerlist = minetest.get_connected_players()
local playerlist = get_connected_players()
local playercount = table.getn(playerlist)
-- nobody on
@ -67,14 +79,14 @@ local function choose_pos(pos)
pos.z = math.floor(pos.z - (lightning.range_h / 2) + rng:next(1, lightning.range_h))
end
local b, pos2 = minetest.line_of_sight(pos, {x = pos.x, y = pos.y - lightning.range_v, z = pos.z}, 1)
local b, pos2 = line_of_sight(pos, {x = pos.x, y = pos.y - lightning.range_v, z = pos.z}, 1)
-- nothing but air found
if b then
return nil, nil
end
local n = minetest.get_node({x = pos2.x, y = pos2.y - 1/2, z = pos2.z})
local n = get_node({x = pos2.x, y = pos2.y - 1/2, z = pos2.z})
if n.name == "air" or n.name == "ignore" then
return nil, nil
end
@ -87,7 +99,7 @@ end
-- * returns: bool - success if a strike happened
lightning.strike = function(pos)
if lightning.auto then
minetest.after(rng:next(lightning.interval_low, lightning.interval_high), lightning.strike)
after(rng:next(lightning.interval_low, lightning.interval_high), lightning.strike)
end
local pos2
@ -97,7 +109,7 @@ lightning.strike = function(pos)
return false
end
minetest.add_particlespawner({
add_particlespawner({
amount = 1,
time = 0.2,
-- make it hit the top of a block exactly with the bottom
@ -120,16 +132,16 @@ lightning.strike = function(pos)
glow = minetest.LIGHT_MAX,
})
minetest.sound_play({ name = "lightning_thunder", gain = 10 }, { pos = pos, max_hear_distance = 500 }, true)
sound_play({ name = "lightning_thunder", gain = 10 }, { pos = pos, max_hear_distance = 500 }, true)
-- damage nearby objects, transform mobs
local objs = minetest.get_objects_inside_radius(pos2, 3.5)
local objs = get_objects_inside_radius(pos2, 3.5)
for o=1, #objs do
local obj = objs[o]
local lua = obj:get_luaentity()
if obj:is_player() then
-- Player damage
if minetest.get_modpath("mcl_death_messages") then
if has_mcl_death_msg then
mcl_death_messages.player_damage(obj, S("@1 was struck by lightning.", obj:get_player_name()))
end
obj:set_hp(obj:get_hp()-5, { type = "punch", from = "mod" })
@ -139,7 +151,7 @@ lightning.strike = function(pos)
if lua.name == "mobs_mc:pig" then
local rot = obj:get_yaw()
obj:remove()
obj = minetest.add_entity(pos2, "mobs_mc:pigman")
obj = add_entity(pos2, "mobs_mc:pigman")
obj:set_yaw(rot)
-- mooshroom: toggle color red/brown (no damage)
elseif lua.name == "mobs_mc:mooshroom" then
@ -163,7 +175,7 @@ lightning.strike = function(pos)
elseif lua.name == "mobs_mc:creeper" then
local rot = obj:get_yaw()
obj:remove()
obj = minetest.add_entity(pos2, "mobs_mc:creeper_charged")
obj = add_entity(pos2, "mobs_mc:creeper_charged")
obj:set_yaw(rot)
-- Other mobs: Just damage
else
@ -172,7 +184,7 @@ lightning.strike = function(pos)
end
end
local playerlist = minetest.get_connected_players()
local playerlist = get_connected_players()
for i = 1, #playerlist do
local player = playerlist[i]
local sky = {}
@ -197,25 +209,25 @@ lightning.strike = function(pos)
if rng:next(1,100) <= 3 then
skeleton_lightning = true
end
if minetest.get_item_group(minetest.get_node({x = pos2.x, y = pos2.y - 1, z = pos2.z}).name, "liquid") < 1 then
if minetest.get_node(pos2).name == "air" then
if get_item_group(get_node({x = pos2.x, y = pos2.y - 1, z = pos2.z}).name, "liquid") < 1 then
if get_node(pos2).name == "air" then
-- Low chance for a lightning to spawn skeleton horse + skeletons
if skeleton_lightning then
minetest.add_entity(pos2, "mobs_mc:skeleton_horse")
add_entity(pos2, "mobs_mc:skeleton_horse")
local angle, posadd
angle = math.random(0, math.pi*2)
for i=1,3 do
posadd = {x=math.cos(angle),y=0,z=math.sin(angle)}
posadd = vector.normalize(posadd)
local mob = minetest.add_entity(vector.add(pos2, posadd), "mobs_mc:skeleton")
local mob = add_entity(vector.add(pos2, posadd), "mobs_mc:skeleton")
mob:set_yaw(angle-math.pi/2)
angle = angle + (math.pi*2) / 3
end
-- Cause a fire
else
minetest.set_node(pos2, {name = "mcl_fire:fire"})
set_node(pos2, {name = "mcl_fire:fire"})
end
end
end
@ -223,9 +235,9 @@ lightning.strike = function(pos)
end
-- if other mods disable auto lightning during initialization, don't trigger the first lightning.
minetest.after(5, function(dtime)
after(5, function(dtime)
if lightning.auto then
minetest.after(rng:next(lightning.interval_low,
after(rng:next(lightning.interval_low,
lightning.interval_high), lightning.strike)
end
end)

View File

@ -1 +1,6 @@
name = lightning
author = sofar
description = A mod that adds thunder and lightning effects.
depends = mcl_fire
optional_depends = mcl_death_messages

View File

@ -1,2 +1,3 @@
name = mcl_moon
author = Wuzzy
description = Adds moon phases to the game

View File

@ -1,2 +0,0 @@
mcl_worlds
mcl_death_messages

View File

@ -1 +0,0 @@
Deal damage to entities stuck in the deep void

View File

@ -1,6 +1,14 @@
local S = minetest.get_translator("mcl_void_damage")
local enable_damage = minetest.settings:get_bool("enable_damage")
local pos_to_dim = mcl_worlds.pos_to_dimension
local dim_change = mcl_worlds.dimension_change
local is_in_void = mcl_worlds.is_in_void
local get_spawn_pos = mcl_spawn.get_player_spawn_pos
local death_msg = mcl_death_messages.player_damage
local send_chat = minetest.chat_send_player
local get_connected = minetest.get_connected_players
local voidtimer = 0
local VOID_DAMAGE_FREQ = 0.5
local VOID_DAMAGE = 4
@ -33,7 +41,7 @@ minetest.register_on_mods_loaded(function()
self._void_timer = 0
local pos = obj:get_pos()
local void, void_deadly = mcl_worlds.is_in_void(pos)
local void, void_deadly = is_in_void(pos)
if void_deadly then
local ent = obj:get_luaentity()
obj:remove()
@ -51,11 +59,11 @@ minetest.register_globalstep(function(dtime)
if voidtimer > VOID_DAMAGE_FREQ then
voidtimer = 0
local enable_damage = minetest.settings:get_bool("enable_damage")
local players = minetest.get_connected_players()
local players = get_connected()
for p=1, #players do
local player = players[p]
local pos = player:get_pos()
local void, void_deadly = mcl_worlds.is_in_void(pos)
local void, void_deadly = is_in_void(pos)
if void_deadly then
local immortal_val = player:get_armor_groups().immortal
local is_immortal = false
@ -65,14 +73,14 @@ minetest.register_globalstep(function(dtime)
if is_immortal or not enable_damage then
-- If damage is disabled, we can't kill players.
-- So we just teleport the player back to spawn.
local spawn = mcl_spawn.get_player_spawn_pos(player)
local spawn = get_spawn_pos(player)
player:set_pos(spawn)
mcl_worlds.dimension_change(player, mcl_worlds.pos_to_dimension(spawn))
minetest.chat_send_player(player:get_player_name(), S("The void is off-limits to you!"))
dim_change(player, pos_to_dim(spawn))
send_chat(player:get_player_name(), S("The void is off-limits to you!"))
elseif enable_damage and not is_immortal then
-- Damage enabled, not immortal: Deal void damage (4 HP / 0.5 seconds)
if player:get_hp() > 0 then
mcl_death_messages.player_damage(player, S("@1 fell into the endless void.", player:get_player_name()))
death_msg(player, S("@1 fell into the endless void.", player:get_player_name()))
player:set_hp(player:get_hp() - VOID_DAMAGE)
end
end

View File

@ -1 +1,4 @@
name = mcl_void_damage
author = Wuzzy
description = Deal damage to entities stuck in the deep void
depends = mcl_worlds, mcl_death_messages

View File

@ -1,3 +0,0 @@
mcl_init
mcl_worlds
lightning?

View File

@ -1 +0,0 @@
Weather and sky handling: Rain, snow, thunderstorm, End and Nether ambience

View File

@ -1 +1,5 @@
name = mcl_weather
author = xeranas
description = Weather and sky handling: Rain, snow, thunderstorm, End and Nether ambience
depends = mcl_init, mcl_worlds
optional_depends = lightning

View File

@ -27,7 +27,7 @@ minetest.register_globalstep(function(dtime)
if timer < 0.7 then return end
timer = 0
for _, player in ipairs(minetest.get_connected_players()) do
for _, player in pairs(minetest.get_connected_players()) do
if not mcl_worlds.has_dust(player:get_pos()) then
return false
end

View File

@ -1,6 +1,8 @@
local PARTICLES_COUNT_RAIN = 30
local PARTICLES_COUNT_THUNDER = 45
local get_connected_players = minetest.get_connected_players
mcl_weather.rain = {
-- max rain particles created at time
particles_count = PARTICLES_COUNT_RAIN,
@ -36,7 +38,7 @@ mcl_weather.rain.set_sky_box = function()
{r=85, g=86, b=98},
{r=0, g=0, b=0}})
mcl_weather.skycolor.active = true
for _, player in ipairs(minetest.get_connected_players()) do
for _, player in pairs(get_connected_players()) do
player:set_clouds({color="#5D5D5FE8"})
end
end
@ -154,7 +156,7 @@ mcl_weather.rain.clear = function()
mcl_weather.rain.init_done = false
mcl_weather.rain.set_particles_mode("rain")
mcl_weather.skycolor.remove_layer("weather-pack-rain-sky")
for _, player in ipairs(minetest.get_connected_players()) do
for _, player in pairs(get_connected_players()) do
mcl_weather.rain.remove_sound(player)
mcl_weather.rain.remove_player(player)
end
@ -176,7 +178,7 @@ mcl_weather.rain.make_weather = function()
mcl_weather.rain.init_done = true
end
for _, player in ipairs(minetest.get_connected_players()) do
for _, player in pairs(get_connected_players()) do
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then
mcl_weather.rain.remove_sound(player)
return false

View File

@ -43,7 +43,7 @@ mcl_weather.skycolor = {
-- Remove layer from colors table
remove_layer = function(layer_name)
for k, name in ipairs(mcl_weather.skycolor.layer_names) do
for k, name in pairs(mcl_weather.skycolor.layer_names) do
if name == layer_name then
table.remove(mcl_weather.skycolor.layer_names, k)
mcl_weather.skycolor.force_update = true

View File

@ -1,3 +1,5 @@
local get_connected_players = minetest.get_connected_players
mcl_weather.snow = {}
mcl_weather.snow.particles_count = 15
@ -37,7 +39,7 @@ mcl_weather.snow.set_sky_box = function()
{r=85, g=86, b=86},
{r=0, g=0, b=0}})
mcl_weather.skycolor.active = true
for _, player in ipairs(minetest.get_connected_players()) do
for _, player in pairs(get_connected_players()) do
player:set_clouds({color="#ADADADE8"})
end
mcl_weather.skycolor.active = true
@ -71,7 +73,7 @@ minetest.register_globalstep(function(dtime)
mcl_weather.snow.init_done = true
end
for _, player in ipairs(minetest.get_connected_players()) do
for _, player in pairs(get_connected_players()) do
if (mcl_weather.is_underwater(player) or not mcl_worlds.has_weather(player:get_pos())) then
return false
end

View File

@ -1,3 +1,5 @@
local get_connected_players = minetest.get_connected_players
-- turn off lightning mod 'auto mode'
lightning.auto = false
@ -25,7 +27,7 @@ minetest.register_globalstep(function(dtime)
{r=40, g=40, b=40},
{r=0, g=0, b=0}})
mcl_weather.skycolor.active = true
for _, player in ipairs(minetest.get_connected_players()) do
for _, player in pairs(get_connected_players()) do
player:set_clouds({color="#3D3D3FE8"})
end
mcl_weather.thunder.init_done = true

View File

@ -1 +0,0 @@
Provides an extensible in-game help with texts about gameplay basics (such a crafting), items and advanced usage.

Some files were not shown because too many files have changed in this diff Show More