forked from VoxeLibre/VoxeLibre
Merge branch 'master' into crossbow
This commit is contained in:
commit
54413d0954
9
API.md
9
API.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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!
|
||||
|
|
BIN
menu/header.png
BIN
menu/header.png
Binary file not shown.
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 76 KiB |
|
@ -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
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
MineClone 2 core mod which automatically adds groups to all items. Very important for digging times.
|
|
@ -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.
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
name = biomeinfo
|
||||
author = Wuzzy
|
||||
description = Simple API to get data about biomes.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
name=controls
|
||||
name = controls
|
||||
author = Arcelmi
|
||||
description = Controls framework by Arcelmi
|
||||
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
name = flowlib
|
||||
author = Qwertymine3
|
||||
description = Simple flow functions for use in Minetest mods by Qwertymine3
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Adds additional ways for nodes to be attached.
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_attached
|
||||
author = Wuzzy
|
||||
description = Adds additional ways for nodes to be attached.
|
|
@ -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",
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_colors
|
||||
author = Fleckenstein
|
||||
description = The HTML sequences for the minecraft colors
|
|
@ -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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
name = mcl_explosions
|
||||
author = ryvnf
|
||||
description = A common API to create explosions.
|
||||
depends = mcl_particles
|
||||
optional_depends = mcl_fire
|
||||
|
|
|
@ -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.
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
API for filling a chest with random treasures.
|
|
@ -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
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
name = mcl_loot
|
||||
author = Wuzzy
|
||||
description = API for filling a chest with random treasures.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Contains particle images of MineClone 2. No code.
|
|
@ -1 +1,3 @@
|
|||
name = mcl_particles
|
||||
author = Wuzzy
|
||||
description = Contains particle images of MineClone 2. No code.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
This mod contains the core sounds of MineClone 2 as well as helper function for mods to access them.
|
|
@ -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.
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
mcl_init
|
|
@ -1 +0,0 @@
|
|||
Helper functions for MineClone 2.
|
|
@ -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
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
name = mcl_util
|
||||
author = Wuzzy
|
||||
description = Helper functions for MineClone 2.
|
||||
depends = mcl_init
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
mcl_init
|
|
@ -1 +0,0 @@
|
|||
Utility functions for worlds and the “dimensions”.
|
|
@ -0,0 +1,5 @@
|
|||
name = mcl_worlds
|
||||
author = Wuzzy
|
||||
description = Utility functions for worlds and the “dimensions”.
|
||||
depends = mcl_init
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
@ -1 +0,0 @@
|
|||
mcl_core
|
|
@ -0,0 +1,4 @@
|
|||
name = drippingwater
|
||||
author = kddekadenz
|
||||
description = Drops are generated rarely under solid nodes
|
||||
depends = mcl_core
|
|
@ -20,4 +20,4 @@ Authors include:
|
|||
* Various Minetest / Minetest Game developers and contributors (2012-2016)
|
||||
* maikerumine (2017)
|
||||
* Wuzzy (2017)
|
||||
|
||||
* Fleckenstein (2020-2021)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
mcl_player
|
||||
mcl_core?
|
||||
doc_identifier?
|
|
@ -1 +0,0 @@
|
|||
Adds drivable boats.
|
|
@ -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
|
||||
|
|
|
@ -1 +1,7 @@
|
|||
name = mcl_boats
|
||||
author = PilzAdam
|
||||
description = Adds drivable boats.
|
||||
depends = mcl_player
|
||||
optional_depends = mcl_core, doc_identifier
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Falling node entities, Minecraft-style
|
|
@ -1 +1,3 @@
|
|||
name = mcl_falling_nodes
|
||||
author = Wuzzy
|
||||
description = Falling node entities, Minecraft-style
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
flowlib
|
||||
mcl_enchanting
|
|
@ -1 +0,0 @@
|
|||
Dropped items will be attracted to the player like a magnet.
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
|
@ -1 +0,0 @@
|
|||
Minecarts are vehicles to move players quickly on rails.
|
|
@ -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",
|
||||
|
|
|
@ -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=Нажмите [Красться] для высадки
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Adds a mob API for mods to add animals or monsters, etc.
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -1 +1,5 @@
|
|||
name = mcl_paintings
|
||||
author = Wuzzy
|
||||
description = The paintings mod for MCL2
|
||||
depends = mcl_wip
|
||||
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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?
|
|
@ -1 +0,0 @@
|
|||
Adds Minecraft-like monsters and animals.
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 |
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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")
|
|
@ -1,2 +0,0 @@
|
|||
mcl_init
|
||||
mcl_core
|
|
@ -0,0 +1,4 @@
|
|||
name = mobs_mc_gameconfig
|
||||
author = Wuzzy
|
||||
description = mobs_mc game configuration for MCL2
|
||||
depends = mcl_init, mcl_core
|
|
@ -1,2 +0,0 @@
|
|||
mcl_fire
|
||||
mcl_death_messages?
|
|
@ -1 +0,0 @@
|
|||
A mod that adds thunder and lightning effects.
|
|
@ -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)
|
||||
|
|
|
@ -1 +1,6 @@
|
|||
name = lightning
|
||||
author = sofar
|
||||
description = A mod that adds thunder and lightning effects.
|
||||
depends = mcl_fire
|
||||
optional_depends = mcl_death_messages
|
||||
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
name = mcl_moon
|
||||
author = Wuzzy
|
||||
description = Adds moon phases to the game
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
mcl_worlds
|
||||
mcl_death_messages
|
|
@ -1 +0,0 @@
|
|||
Deal damage to entities stuck in the deep void
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
mcl_init
|
||||
mcl_worlds
|
||||
lightning?
|
|
@ -1 +0,0 @@
|
|||
Weather and sky handling: Rain, snow, thunderstorm, End and Nether ambience
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue