mirror of
https://github.com/minetest/minetest.git
synced 2024-08-18 20:44:16 +02:00
Weather support
This commit is contained in:
parent
e65d8ad655
commit
3aedfac968
@ -14,11 +14,11 @@ minetest.register_entity("__builtin:falling_node", {
|
||||
visual_size = {x=0.667, y=0.667},
|
||||
},
|
||||
|
||||
nodename = "",
|
||||
node = {},
|
||||
|
||||
set_node = function(self, nodename)
|
||||
self.nodename = nodename
|
||||
local stack = ItemStack(nodename)
|
||||
set_node = function(self, node)
|
||||
self.node = node
|
||||
local stack = ItemStack(node.name)
|
||||
local itemtable = stack:to_table()
|
||||
local itemname = nil
|
||||
if itemtable then
|
||||
@ -32,20 +32,19 @@ minetest.register_entity("__builtin:falling_node", {
|
||||
end
|
||||
prop = {
|
||||
is_visible = true,
|
||||
textures = {nodename},
|
||||
textures = {node.name},
|
||||
}
|
||||
self.object:set_properties(prop)
|
||||
end,
|
||||
|
||||
get_staticdata = function(self)
|
||||
return self.nodename
|
||||
return self.node.name
|
||||
end,
|
||||
|
||||
on_activate = function(self, staticdata)
|
||||
self.nodename = staticdata
|
||||
self.object:set_armor_groups({immortal=1})
|
||||
--self.object:setacceleration({x=0, y=-10, z=0})
|
||||
self:set_node(self.nodename)
|
||||
self:set_node({name=staticdata})
|
||||
end,
|
||||
|
||||
on_step = function(self, dtime)
|
||||
@ -57,8 +56,10 @@ minetest.register_entity("__builtin:falling_node", {
|
||||
local bcn = minetest.get_node(bcp)
|
||||
-- Note: walkable is in the node definition, not in item groups
|
||||
if minetest.registered_nodes[bcn.name] and
|
||||
minetest.registered_nodes[bcn.name].walkable then
|
||||
if minetest.registered_nodes[bcn.name].buildable_to then
|
||||
minetest.registered_nodes[bcn.name].walkable or
|
||||
(minetest.get_node_group(self.node.name, "float") ~= 0 and minetest.registered_nodes[bcn.name].liquidtype ~= "none")
|
||||
then
|
||||
if minetest.registered_nodes[bcn.name].buildable_to and (minetest.get_node_group(self.node.name, "float") == 0 or minetest.registered_nodes[bcn.name].liquidtype == "none") then
|
||||
minetest.remove_node(bcp)
|
||||
return
|
||||
end
|
||||
@ -83,7 +84,7 @@ minetest.register_entity("__builtin:falling_node", {
|
||||
end
|
||||
end
|
||||
-- Create node and remove entity
|
||||
minetest.add_node(np, {name=self.nodename})
|
||||
minetest.add_node(np, self.node)
|
||||
self.object:remove()
|
||||
nodeupdate(np)
|
||||
else
|
||||
@ -92,9 +93,9 @@ minetest.register_entity("__builtin:falling_node", {
|
||||
end
|
||||
})
|
||||
|
||||
function spawn_falling_node(p, nodename)
|
||||
function spawn_falling_node(p, node)
|
||||
obj = minetest.add_entity(p, "__builtin:falling_node")
|
||||
obj:get_luaentity():set_node(nodename)
|
||||
obj:get_luaentity():set_node(node)
|
||||
end
|
||||
|
||||
function drop_attached_node(p)
|
||||
@ -150,13 +151,14 @@ function nodeupdate_single(p, delay)
|
||||
n_bottom = minetest.get_node(p_bottom)
|
||||
-- Note: walkable is in the node definition, not in item groups
|
||||
if minetest.registered_nodes[n_bottom.name] and
|
||||
(minetest.get_node_group(n.name, "float") == 0 or minetest.registered_nodes[n_bottom.name].liquidtype == "none") and
|
||||
(not minetest.registered_nodes[n_bottom.name].walkable or
|
||||
minetest.registered_nodes[n_bottom.name].buildable_to) then
|
||||
if delay then
|
||||
minetest.after(0.1, nodeupdate_single, {x=p.x, y=p.y, z=p.z}, false)
|
||||
else
|
||||
minetest.remove_node(p)
|
||||
spawn_falling_node(p, n.name)
|
||||
spawn_falling_node(p, n)
|
||||
nodeupdate(p)
|
||||
end
|
||||
end
|
||||
@ -170,7 +172,7 @@ function nodeupdate_single(p, delay)
|
||||
end
|
||||
end
|
||||
|
||||
function nodeupdate(p)
|
||||
function nodeupdate(p, delay)
|
||||
-- Round p to prevent falling entities to get stuck
|
||||
p.x = math.floor(p.x+0.5)
|
||||
p.y = math.floor(p.y+0.5)
|
||||
@ -179,7 +181,7 @@ function nodeupdate(p)
|
||||
for x = -1,1 do
|
||||
for y = -1,1 do
|
||||
for z = -1,1 do
|
||||
nodeupdate_single({x=p.x+x, y=p.y+y, z=p.z+z}, not (x==0 and y==0 and z==0))
|
||||
nodeupdate_single({x=p.x+x, y=p.y+y, z=p.z+z}, delay or not (x==0 and y==0 and z==0))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -322,6 +322,8 @@ param2 is reserved for the engine when any of these are used:
|
||||
facedir modulo 4 = axisdir
|
||||
0 = y+ 1 = z+ 2 = z- 3 = x+ 4 = x- 5 = y-
|
||||
facedir's two less significant bits are rotation around the axis
|
||||
paramtype2 == "leveled"
|
||||
^ The drawn node level is read from param2, like flowingliquid
|
||||
|
||||
Nodes can also contain extra data. See "Node Metadata".
|
||||
|
||||
@ -353,7 +355,7 @@ Node selection boxes are defined using "node boxes"
|
||||
|
||||
The "nodebox" node drawtype allows defining visual of nodes consisting of
|
||||
arbitrary number of boxes. It allows defining stuff like stairs. Only the
|
||||
"fixed" box type is supported for these.
|
||||
"fixed" and "leveled" box type is supported for these.
|
||||
^ Please note that this is still experimental, and may be incompatibly
|
||||
changed in the future.
|
||||
|
||||
@ -381,6 +383,8 @@ A box is defined as:
|
||||
A box of a regular node would look like:
|
||||
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
|
||||
type = "leveled" is same as "fixed", but y2 will be automaticaly setted to level from param2
|
||||
|
||||
Ore types
|
||||
---------------
|
||||
These tell in what manner the ore is generated.
|
||||
@ -1258,6 +1262,18 @@ minetest.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)
|
||||
^ algorithm: A*_noprefetch(default), A*, Dijkstra
|
||||
minetest.spawn_tree (pos, {treedef})
|
||||
^ spawns L-System tree at given pos with definition in treedef table
|
||||
minetest.transforming_liquid_add(pos)
|
||||
^ add node to liquid update queue
|
||||
minetest.get_node_max_level(pos)
|
||||
^ get max available level for leveled node
|
||||
minetest.get_node_level(pos)
|
||||
^ get level of leveled node (water, snow)
|
||||
minetest.add_node_level(pos, level)
|
||||
^ increase level of leveled node by level, default level = 1, if totallevel > maxlevel returns rest (total-max). can be negative for decreasing
|
||||
minetest.get_heat(pos)
|
||||
^ heat at pos
|
||||
minetest.get_humidity(pos)
|
||||
^ humidity at pos
|
||||
|
||||
Inventory:
|
||||
minetest.get_inventory(location) -> InvRef
|
||||
@ -1965,6 +1981,8 @@ Node definition (register_node)
|
||||
liquid_alternative_source = "", -- Source version of flowing liquid
|
||||
liquid_viscosity = 0, -- Higher viscosity = slower flow (max. 7)
|
||||
liquid_renewable = true, -- Can new liquid source be created by placing
|
||||
freezemelt = "", -- water for snow/ice, ice/snow for water
|
||||
leveled = 0, -- Block contain level in param2. value - default level, used for snow. Dont forget use "leveled" type nodebox
|
||||
liquid_range = 8, -- number of flowing nodes arround source (max. 8)
|
||||
drowning = true, -- Player will drown in these
|
||||
two or more sources nearly?
|
||||
|
@ -107,6 +107,8 @@
|
||||
#liquid_fast_flood = 1
|
||||
# Underground water and lava springs, its infnity sources if liquid_finite enabled
|
||||
#underground_springs = 1
|
||||
# Enable weather (cold-hot, water freeze-melt). use only with liquid_finite=1
|
||||
#weather = false
|
||||
# Enable nice leaves; disable for speed
|
||||
#new_style_leaves = true
|
||||
# Enable smooth lighting with simple ambient occlusion;
|
||||
@ -268,7 +270,9 @@
|
||||
# Interval of sending time of day to clients
|
||||
#time_send_interval = 5
|
||||
# Length of day/night cycle. 72=20min, 360=4min, 1=24hour, 0=day/night/whatever stays unchanged
|
||||
#time_speed = 96
|
||||
#time_speed = 72
|
||||
# Length of year in days for seasons change. With default time_speed 365 days = 5 real days for year. 30 days = 10 real hours
|
||||
#year_days = 30
|
||||
#server_unload_unused_data_timeout = 29
|
||||
# Interval of saving important changes in the world
|
||||
#server_map_save_interval = 5.3
|
||||
|
@ -28,6 +28,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "treegen.h" // For treegen::make_tree
|
||||
#include "main.h" // for g_settings
|
||||
#include "map.h"
|
||||
#include "cpp_api/scriptapi.h"
|
||||
#include "log.h"
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
|
||||
@ -166,86 +168,220 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class LiquidFlowABM : public ActiveBlockModifier
|
||||
{
|
||||
private:
|
||||
std::set<std::string> contents;
|
||||
class LiquidFlowABM : public ActiveBlockModifier {
|
||||
private:
|
||||
std::set<std::string> contents;
|
||||
|
||||
public:
|
||||
LiquidFlowABM(ServerEnvironment *env, INodeDefManager *nodemgr)
|
||||
{
|
||||
std::set<content_t> liquids;
|
||||
nodemgr->getIds("group:liquid", liquids);
|
||||
for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
|
||||
contents.insert(nodemgr->get(*k).liquid_alternative_flowing);
|
||||
|
||||
}
|
||||
virtual std::set<std::string> getTriggerContents()
|
||||
{
|
||||
return contents;
|
||||
}
|
||||
virtual float getTriggerInterval()
|
||||
{ return 10.0; }
|
||||
virtual u32 getTriggerChance()
|
||||
{ return 10; }
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
|
||||
{
|
||||
ServerMap *map = &env->getServerMap();
|
||||
if (map->transforming_liquid_size() > 500)
|
||||
return;
|
||||
map->transforming_liquid_add(p);
|
||||
//if ((*map).m_transforming_liquid.size() < 500) (*map).m_transforming_liquid.push_back(p);
|
||||
}
|
||||
public:
|
||||
LiquidFlowABM(ServerEnvironment *env, INodeDefManager *nodemgr) {
|
||||
std::set<content_t> liquids;
|
||||
nodemgr->getIds("group:liquid", liquids);
|
||||
for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
|
||||
contents.insert(nodemgr->get(*k).liquid_alternative_flowing);
|
||||
}
|
||||
virtual std::set<std::string> getTriggerContents() {
|
||||
return contents;
|
||||
}
|
||||
virtual float getTriggerInterval()
|
||||
{ return 10.0; }
|
||||
virtual u32 getTriggerChance()
|
||||
{ return 10; }
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
|
||||
ServerMap *map = &env->getServerMap();
|
||||
if (map->transforming_liquid_size() > 500)
|
||||
return;
|
||||
map->transforming_liquid_add(p);
|
||||
}
|
||||
};
|
||||
|
||||
class LiquidDropABM : public ActiveBlockModifier
|
||||
{
|
||||
private:
|
||||
std::set<std::string> contents;
|
||||
class LiquidDropABM : public ActiveBlockModifier {
|
||||
private:
|
||||
std::set<std::string> contents;
|
||||
|
||||
public:
|
||||
LiquidDropABM(ServerEnvironment *env, INodeDefManager *nodemgr)
|
||||
{
|
||||
std::set<content_t> liquids;
|
||||
nodemgr->getIds("group:liquid", liquids);
|
||||
for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
|
||||
contents.insert(nodemgr->get(*k).liquid_alternative_source);
|
||||
}
|
||||
virtual std::set<std::string> getTriggerContents()
|
||||
{ return contents; }
|
||||
virtual std::set<std::string> getRequiredNeighbors()
|
||||
{
|
||||
std::set<std::string> neighbors;
|
||||
neighbors.insert("mapgen_air");
|
||||
return neighbors;
|
||||
}
|
||||
virtual float getTriggerInterval()
|
||||
{ return 20.0; }
|
||||
virtual u32 getTriggerChance()
|
||||
{ return 10; }
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
|
||||
{
|
||||
ServerMap *map = &env->getServerMap();
|
||||
if (map->transforming_liquid_size() > 500)
|
||||
return;
|
||||
if ( map->getNodeNoEx(p - v3s16(0, 1, 0 )).getContent() != CONTENT_AIR // below
|
||||
&& map->getNodeNoEx(p - v3s16(1, 0, 0 )).getContent() != CONTENT_AIR // right
|
||||
&& map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent() != CONTENT_AIR // left
|
||||
&& map->getNodeNoEx(p - v3s16(0, 0, 1 )).getContent() != CONTENT_AIR // back
|
||||
&& map->getNodeNoEx(p - v3s16(0, 0, -1)).getContent() != CONTENT_AIR // front
|
||||
)
|
||||
return;
|
||||
map->transforming_liquid_add(p);
|
||||
}
|
||||
public:
|
||||
LiquidDropABM(ServerEnvironment *env, INodeDefManager *nodemgr) {
|
||||
std::set<content_t> liquids;
|
||||
nodemgr->getIds("group:liquid", liquids);
|
||||
for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
|
||||
contents.insert(nodemgr->get(*k).liquid_alternative_source);
|
||||
}
|
||||
virtual std::set<std::string> getTriggerContents()
|
||||
{ return contents; }
|
||||
virtual std::set<std::string> getRequiredNeighbors() {
|
||||
std::set<std::string> neighbors;
|
||||
neighbors.insert("mapgen_air");
|
||||
return neighbors;
|
||||
}
|
||||
virtual float getTriggerInterval()
|
||||
{ return 20.0; }
|
||||
virtual u32 getTriggerChance()
|
||||
{ return 10; }
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
|
||||
ServerMap *map = &env->getServerMap();
|
||||
if (map->transforming_liquid_size() > 500)
|
||||
return;
|
||||
if ( map->getNodeNoEx(p - v3s16(0, 1, 0 )).getContent() != CONTENT_AIR // below
|
||||
&& map->getNodeNoEx(p - v3s16(1, 0, 0 )).getContent() != CONTENT_AIR // right
|
||||
&& map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent() != CONTENT_AIR // left
|
||||
&& map->getNodeNoEx(p - v3s16(0, 0, 1 )).getContent() != CONTENT_AIR // back
|
||||
&& map->getNodeNoEx(p - v3s16(0, 0, -1)).getContent() != CONTENT_AIR // front
|
||||
)
|
||||
return;
|
||||
map->transforming_liquid_add(p);
|
||||
}
|
||||
};
|
||||
|
||||
void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef)
|
||||
{
|
||||
class LiquidFreeze : public ActiveBlockModifier {
|
||||
public:
|
||||
LiquidFreeze(ServerEnvironment *env, INodeDefManager *nodemgr) { }
|
||||
virtual std::set<std::string> getTriggerContents() {
|
||||
std::set<std::string> s;
|
||||
s.insert("group:freezes");
|
||||
return s;
|
||||
}
|
||||
virtual std::set<std::string> getRequiredNeighbors() {
|
||||
std::set<std::string> s;
|
||||
s.insert("mapgen_air");
|
||||
s.insert("group:melts");
|
||||
return s;
|
||||
}
|
||||
virtual float getTriggerInterval()
|
||||
{ return 10.0; }
|
||||
virtual u32 getTriggerChance()
|
||||
{ return 20; }
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
|
||||
ServerMap *map = &env->getServerMap();
|
||||
INodeDefManager *ndef = env->getGameDef()->ndef();
|
||||
|
||||
float heat = map->getHeat(env, p);
|
||||
//heater = rare
|
||||
if (heat <= -1 && (heat <= -50 || ((myrand_range(-50, heat)) <= -30))) {
|
||||
content_t c_self = n.getContent();
|
||||
// making freeze not annoying, do not freeze random blocks in center of ocean
|
||||
// todo: any block not water (dont freeze _source near _flowing)
|
||||
content_t c;
|
||||
bool allow = heat < -40;
|
||||
// todo: make for(...)
|
||||
if (!allow) {
|
||||
c = map->getNodeNoEx(p - v3s16(0, 1, 0 )).getContent(); // below
|
||||
if (c == CONTENT_AIR || c == CONTENT_IGNORE)
|
||||
return; // do not freeze when falling
|
||||
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
|
||||
if (!allow) {
|
||||
c = map->getNodeNoEx(p - v3s16(1, 0, 0 )).getContent(); // right
|
||||
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
|
||||
if (!allow) {
|
||||
c = map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent(); // left
|
||||
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
|
||||
if (!allow) {
|
||||
c = map->getNodeNoEx(p - v3s16(0, 0, 1 )).getContent(); // back
|
||||
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
|
||||
if (!allow) {
|
||||
c = map->getNodeNoEx(p - v3s16(0, 0, -1)).getContent(); // front
|
||||
if (c != c_self && c != CONTENT_IGNORE) allow = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (allow) {
|
||||
n.setContent(ndef->getId(ndef->get(n).freezemelt));
|
||||
map->addNodeWithEvent(p, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class LiquidMeltWeather : public ActiveBlockModifier {
|
||||
public:
|
||||
LiquidMeltWeather(ServerEnvironment *env, INodeDefManager *nodemgr) { }
|
||||
virtual std::set<std::string> getTriggerContents() {
|
||||
std::set<std::string> s;
|
||||
s.insert("group:melts");
|
||||
return s;
|
||||
}
|
||||
virtual std::set<std::string> getRequiredNeighbors() {
|
||||
std::set<std::string> s;
|
||||
s.insert("mapgen_air");
|
||||
s.insert("group:freezes");
|
||||
return s;
|
||||
}
|
||||
virtual float getTriggerInterval()
|
||||
{ return 10.0; }
|
||||
virtual u32 getTriggerChance()
|
||||
{ return 20; }
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
|
||||
ServerMap *map = &env->getServerMap();
|
||||
INodeDefManager *ndef = env->getGameDef()->ndef();
|
||||
|
||||
float heat = map->getHeat(env, p);
|
||||
if (heat >= 1 && (heat >= 40 || ((myrand_range(heat, 40)) >= 20))) {
|
||||
n.setContent(ndef->getId(ndef->get(n).freezemelt));
|
||||
if (!n.getLevel(ndef))
|
||||
n.addLevel(ndef);
|
||||
map->addNodeWithEvent(p, n);
|
||||
env->getScriptIface()->node_falling_update(p);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class LiquidMeltHot : public ActiveBlockModifier {
|
||||
public:
|
||||
LiquidMeltHot(ServerEnvironment *env, INodeDefManager *nodemgr) { }
|
||||
virtual std::set<std::string> getTriggerContents() {
|
||||
std::set<std::string> s;
|
||||
s.insert("group:melts");
|
||||
return s;
|
||||
}
|
||||
virtual std::set<std::string> getRequiredNeighbors() {
|
||||
std::set<std::string> s;
|
||||
s.insert("group:igniter");
|
||||
s.insert("group:hot");
|
||||
return s;
|
||||
}
|
||||
virtual float getTriggerInterval()
|
||||
{ return 2.0; }
|
||||
virtual u32 getTriggerChance()
|
||||
{ return 4; }
|
||||
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
|
||||
ServerMap *map = &env->getServerMap();
|
||||
INodeDefManager *ndef = env->getGameDef()->ndef();
|
||||
n.setContent(ndef->getId(ndef->get(n).freezemelt));
|
||||
if (!n.getLevel(ndef))
|
||||
n.addLevel(ndef);
|
||||
map->addNodeWithEvent(p, n);
|
||||
env->getScriptIface()->node_falling_update(p);
|
||||
}
|
||||
};
|
||||
|
||||
class LiquidMeltAround : public LiquidMeltHot {
|
||||
public:
|
||||
LiquidMeltAround(ServerEnvironment *env, INodeDefManager *nodemgr)
|
||||
: LiquidMeltHot(env, nodemgr) { }
|
||||
virtual std::set<std::string> getRequiredNeighbors() {
|
||||
std::set<std::string> s;
|
||||
s.insert("group:melt_around");
|
||||
return s;
|
||||
}
|
||||
virtual float getTriggerInterval()
|
||||
{ return 40.0; }
|
||||
virtual u32 getTriggerChance()
|
||||
{ return 60; }
|
||||
};
|
||||
|
||||
|
||||
void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef) {
|
||||
env->addActiveBlockModifier(new GrowGrassABM());
|
||||
env->addActiveBlockModifier(new RemoveGrassABM());
|
||||
env->addActiveBlockModifier(new MakeTreesFromSaplingsABM(env, nodedef));
|
||||
if (g_settings->getBool("liquid_finite")) {
|
||||
env->addActiveBlockModifier(new LiquidFlowABM(env, nodedef));
|
||||
env->addActiveBlockModifier(new LiquidDropABM(env, nodedef));
|
||||
env->addActiveBlockModifier(new LiquidMeltHot(env, nodedef));
|
||||
env->addActiveBlockModifier(new LiquidMeltAround(env, nodedef));
|
||||
if (g_settings->getBool("weather")) {
|
||||
env->addActiveBlockModifier(new LiquidFreeze(env, nodedef));
|
||||
env->addActiveBlockModifier(new LiquidMeltWeather(env, nodedef));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ void set_default_settings(Settings *settings)
|
||||
settings->setDefault("max_clearobjects_extra_loaded_blocks", "4096");
|
||||
settings->setDefault("time_send_interval", "5");
|
||||
settings->setDefault("time_speed", "72");
|
||||
settings->setDefault("year_days", "30");
|
||||
settings->setDefault("server_unload_unused_data_timeout", "29");
|
||||
settings->setDefault("server_map_save_interval", "5.3");
|
||||
settings->setDefault("full_block_send_enable_min_time_from_building", "2.0");
|
||||
@ -214,6 +215,7 @@ void set_default_settings(Settings *settings)
|
||||
settings->setDefault("liquid_relax", "2");
|
||||
settings->setDefault("liquid_fast_flood", "1");
|
||||
settings->setDefault("underground_springs", "1");
|
||||
settings->setDefault("weather", "false");
|
||||
|
||||
//mapgen stuff
|
||||
settings->setDefault("mg_name", "v6");
|
||||
|
@ -488,6 +488,14 @@ void *EmergeThread::Thread() {
|
||||
if (block)
|
||||
modified_blocks[p] = block;
|
||||
|
||||
// Update weather data in mapblock
|
||||
for(std::map<v3s16, MapBlock *>::iterator
|
||||
i = modified_blocks.begin();
|
||||
i != modified_blocks.end(); ++i) {
|
||||
map->getHeat(m_server->m_env, MAP_BLOCKSIZE*i->first ,i->second);
|
||||
map->getHumidity(m_server->m_env, MAP_BLOCKSIZE*i->first, i->second);
|
||||
}
|
||||
|
||||
// Set the modified blocks unsent for all the clients
|
||||
for (std::map<u16, RemoteClient*>::iterator
|
||||
i = m_server->m_clients.begin();
|
||||
|
@ -303,6 +303,7 @@ public:
|
||||
//check if there's a line of sight between two positions
|
||||
bool line_of_sight(v3f pos1, v3f pos2, float stepsize=1.0);
|
||||
|
||||
u32 getGameTime() { return m_game_time; }
|
||||
private:
|
||||
|
||||
/*
|
||||
|
@ -2455,6 +2455,7 @@ void the_game(
|
||||
camera.step(dtime);
|
||||
|
||||
v3f player_position = player->getPosition();
|
||||
v3s16 pos_i = floatToInt(player_position, BS);
|
||||
v3f camera_position = camera.getPosition();
|
||||
v3f camera_direction = camera.getDirection();
|
||||
f32 camera_fov = camera.getFovMax();
|
||||
@ -3034,7 +3035,9 @@ void the_game(
|
||||
<<", "<<(player_position.Y/BS)
|
||||
<<", "<<(player_position.Z/BS)
|
||||
<<") (yaw="<<(wrapDegrees_0_360(camera_yaw))
|
||||
<<") (seed = "<<((unsigned long long)client.getMapSeed())
|
||||
<<") (t="<<client.getEnv().getClientMap().getHeat(pos_i)
|
||||
<<"C, h="<<client.getEnv().getClientMap().getHumidity(pos_i)
|
||||
<<"%) (seed = "<<((unsigned long long)client.getMapSeed())
|
||||
<<")";
|
||||
guitext2->setText(narrow_to_wide(os.str()).c_str());
|
||||
guitext2->setVisible(true);
|
||||
|
82
src/map.cpp
82
src/map.cpp
@ -36,6 +36,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "emerge.h"
|
||||
#include "mapgen_v6.h"
|
||||
#include "mapgen_indev.h"
|
||||
#include "biome.h"
|
||||
|
||||
#define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
|
||||
|
||||
@ -1087,6 +1088,7 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
|
||||
/*
|
||||
Add neighboring liquid nodes and the node itself if it is
|
||||
liquid (=water node was added) to transform queue.
|
||||
note: todo: for liquid_finite enough to add only self node
|
||||
*/
|
||||
v3s16 dirs[7] = {
|
||||
v3s16(0,0,0), // self
|
||||
@ -1278,6 +1280,7 @@ void Map::removeNodeAndUpdate(v3s16 p,
|
||||
/*
|
||||
Add neighboring liquid nodes and this node to transform queue.
|
||||
(it's vital for the node itself to get updated last.)
|
||||
note: todo: for liquid_finite enough to add only self node
|
||||
*/
|
||||
v3s16 dirs[7] = {
|
||||
v3s16(0,0,1), // back
|
||||
@ -2364,6 +2367,26 @@ void Map::removeNodeTimer(v3s16 p)
|
||||
block->m_node_timers.remove(p_rel);
|
||||
}
|
||||
|
||||
s16 Map::getHeat(v3s16 p)
|
||||
{
|
||||
MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
|
||||
if(block != NULL) {
|
||||
return block->heat;
|
||||
}
|
||||
//errorstream << "No heat for " << p.X<<"," << p.Z << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s16 Map::getHumidity(v3s16 p)
|
||||
{
|
||||
MapBlock *block = getBlockNoCreateNoEx(getNodeBlockPos(p));
|
||||
if(block != NULL) {
|
||||
return block->humidity;
|
||||
}
|
||||
//errorstream << "No humidity for " << p.X<<"," << p.Z << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
ServerMap
|
||||
*/
|
||||
@ -3863,7 +3886,7 @@ void ServerMap::loadBlock(std::string sectordir, std::string blockfile, MapSecto
|
||||
<<" (SerializationError). "
|
||||
<<"what()="<<e.what()
|
||||
<<std::endl;
|
||||
//" Ignoring. A new one will be generated.
|
||||
// Ignoring. A new one will be generated.
|
||||
assert(0);
|
||||
|
||||
// TODO: Backup file; name is in fullpath.
|
||||
@ -4039,6 +4062,63 @@ void ServerMap::PrintInfo(std::ostream &out)
|
||||
out<<"ServerMap: ";
|
||||
}
|
||||
|
||||
s16 ServerMap::getHeat(ServerEnvironment *env, v3s16 p, MapBlock *block)
|
||||
{
|
||||
if(block == NULL)
|
||||
block = getBlockNoCreateNoEx(getNodeBlockPos(p));
|
||||
if(block != NULL) {
|
||||
if (env->getGameTime() - block->heat_time < 10)
|
||||
return block->heat;
|
||||
}
|
||||
|
||||
//variant 1: full random
|
||||
//f32 heat = NoisePerlin3D(m_emerge->biomedef->np_heat, p.X, env->getGameTime()/100, p.Z, m_emerge->params->seed);
|
||||
|
||||
//variant 2: season change based on default heat map
|
||||
f32 heat = NoisePerlin2D(m_emerge->biomedef->np_heat, p.X, p.Z, m_emerge->params->seed);
|
||||
heat += -30; // -30 - todo REMOVE after fixed NoiseParams nparams_biome_def_heat = {50, 50, -> 20, 50,
|
||||
f32 base = (f32)env->getGameTime() * env->getTimeOfDaySpeed();
|
||||
base /= ( 86400 * g_settings->getS16("year_days") );
|
||||
base += (f32)p.X / 3000;
|
||||
heat += 30 * sin(base * M_PI); // season
|
||||
|
||||
heat += p.Y / -333; // upper=colder, lower=hotter
|
||||
|
||||
// daily change, hotter at sun +4, colder at night -4
|
||||
heat += 8 * (sin(cycle_shift(env->getTimeOfDayF(), -0.25) * M_PI) - 0.5);
|
||||
|
||||
if(block != NULL) {
|
||||
block->heat = heat;
|
||||
block->heat_time = env->getGameTime();
|
||||
}
|
||||
return heat;
|
||||
}
|
||||
|
||||
s16 ServerMap::getHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block)
|
||||
{
|
||||
if(block == NULL)
|
||||
block = getBlockNoCreateNoEx(getNodeBlockPos(p));
|
||||
if(block != NULL) {
|
||||
if (env->getGameTime() - block->humidity_time < 10)
|
||||
return block->humidity;
|
||||
}
|
||||
|
||||
f32 humidity = NoisePerlin3D( m_emerge->biomedef->np_humidity,
|
||||
p.X, env->getGameTime()/10, p.Z,
|
||||
m_emerge->params->seed);
|
||||
humidity += -12 * ( sin(cycle_shift(env->getTimeOfDayF(), -0.1) * M_PI) - 0.5);
|
||||
//todo like heat//humidity += 20 * ( sin(((f32)p.Z / 300) * M_PI) - 0.5);
|
||||
|
||||
if (humidity > 100) humidity = 100;
|
||||
if (humidity < 0) humidity = 0;
|
||||
|
||||
if(block != NULL) {
|
||||
block->humidity = humidity;
|
||||
block->humidity_time = env->getGameTime();
|
||||
}
|
||||
return humidity;
|
||||
}
|
||||
|
||||
/*
|
||||
MapVoxelManipulator
|
||||
*/
|
||||
|
@ -37,6 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "modifiedstate.h"
|
||||
#include "util/container.h"
|
||||
#include "nodetimer.h"
|
||||
#include "environment.h"
|
||||
|
||||
extern "C" {
|
||||
#include "sqlite3.h"
|
||||
@ -336,6 +337,9 @@ public:
|
||||
void transforming_liquid_add(v3s16 p);
|
||||
s32 transforming_liquid_size();
|
||||
|
||||
virtual s16 getHeat(v3s16 p);
|
||||
virtual s16 getHumidity(v3s16 p);
|
||||
|
||||
protected:
|
||||
friend class LuaVoxelManip;
|
||||
|
||||
@ -483,6 +487,10 @@ public:
|
||||
|
||||
// Parameters fed to the Mapgen
|
||||
MapgenParams *m_mgparams;
|
||||
|
||||
virtual s16 getHeat(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL);
|
||||
virtual s16 getHumidity(ServerEnvironment *env, v3s16 p, MapBlock *block = NULL);
|
||||
|
||||
private:
|
||||
// Seed used for all kinds of randomness in generation
|
||||
u64 m_seed;
|
||||
|
@ -58,7 +58,11 @@ MapBlock::MapBlock(Map *parent, v3s16 pos, IGameDef *gamedef, bool dummy):
|
||||
m_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
|
||||
m_disk_timestamp(BLOCK_TIMESTAMP_UNDEFINED),
|
||||
m_usage_timer(0),
|
||||
m_refcount(0)
|
||||
m_refcount(0),
|
||||
heat_time(0),
|
||||
heat(0),
|
||||
humidity_time(0),
|
||||
humidity(0)
|
||||
{
|
||||
data = NULL;
|
||||
if(dummy == false)
|
||||
@ -632,6 +636,11 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
|
||||
// Node timers
|
||||
m_node_timers.serialize(os, version);
|
||||
}
|
||||
} else {
|
||||
if(version >= 26){
|
||||
writeF1000(os, heat);
|
||||
writeF1000(os, humidity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -734,6 +743,11 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
|
||||
<<": Node timers (ver>=25)"<<std::endl);
|
||||
m_node_timers.deSerialize(is, version);
|
||||
}
|
||||
} else {
|
||||
if(version >= 26){
|
||||
heat = readF1000(is);
|
||||
humidity = readF1000(is);
|
||||
}
|
||||
}
|
||||
|
||||
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
|
||||
|
@ -518,6 +518,11 @@ public:
|
||||
NodeTimerList m_node_timers;
|
||||
StaticObjectList m_static_objects;
|
||||
|
||||
s16 heat;
|
||||
u32 heat_time;
|
||||
s16 humidity;
|
||||
u32 humidity_time;
|
||||
|
||||
private:
|
||||
/*
|
||||
Private member variables
|
||||
|
@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "content_mapnode.h" // For mapnode_translate_*_internal
|
||||
#include "serialization.h" // For ser_ver_supported
|
||||
#include "util/serialize.h"
|
||||
#include "log.h"
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
@ -359,9 +360,23 @@ std::vector<aabb3f> MapNode::getSelectionBoxes(INodeDefManager *nodemgr) const
|
||||
return transformNodeBox(*this, f.selection_box, nodemgr);
|
||||
}
|
||||
|
||||
u8 MapNode::getMaxLevel(INodeDefManager *nodemgr) const
|
||||
{
|
||||
const ContentFeatures &f = nodemgr->get(*this);
|
||||
// todo: after update in all games leave only if (f.param_type_2 ==
|
||||
if( f.liquid_type == LIQUID_SOURCE
|
||||
|| f.liquid_type == LIQUID_FLOWING
|
||||
|| f.param_type_2 == CPT2_FLOWINGLIQUID)
|
||||
return LIQUID_LEVEL_MAX;
|
||||
if(f.leveled || f.param_type_2 == CPT2_LEVELED)
|
||||
return LEVELED_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 MapNode::getLevel(INodeDefManager *nodemgr) const
|
||||
{
|
||||
const ContentFeatures &f = nodemgr->get(*this);
|
||||
// todo: after update in all games leave only if (f.param_type_2 ==
|
||||
if(f.liquid_type == LIQUID_SOURCE)
|
||||
return LIQUID_LEVEL_SOURCE;
|
||||
if (f.param_type_2 == CPT2_FLOWINGLIQUID)
|
||||
@ -377,6 +392,37 @@ u8 MapNode::getLevel(INodeDefManager *nodemgr) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
u8 MapNode::addLevel(INodeDefManager *nodemgr, s8 add)
|
||||
{
|
||||
s8 level = getLevel(nodemgr);
|
||||
u8 rest = 0;
|
||||
if (add == 0) level = 1;
|
||||
level += add;
|
||||
if (level < 1) {
|
||||
setContent(CONTENT_AIR);
|
||||
return 0;
|
||||
}
|
||||
const ContentFeatures &f = nodemgr->get(*this);
|
||||
if ( f.param_type_2 == CPT2_FLOWINGLIQUID
|
||||
|| f.liquid_type == LIQUID_FLOWING
|
||||
|| f.liquid_type == LIQUID_SOURCE) {
|
||||
if (level >= LIQUID_LEVEL_MAX) {
|
||||
rest = level - LIQUID_LEVEL_MAX;
|
||||
setContent(nodemgr->getId(f.liquid_alternative_source));
|
||||
} else {
|
||||
setContent(nodemgr->getId(f.liquid_alternative_flowing));
|
||||
setParam2(level & LIQUID_LEVEL_MASK);
|
||||
}
|
||||
} else if (f.leveled || f.param_type_2 == CPT2_LEVELED) {
|
||||
if (level > LEVELED_MAX) {
|
||||
rest = level - LEVELED_MAX;
|
||||
level = LEVELED_MAX;
|
||||
}
|
||||
setParam2(level & LEVELED_MASK);
|
||||
}
|
||||
return rest;
|
||||
}
|
||||
|
||||
u32 MapNode::serializedLength(u8 version)
|
||||
{
|
||||
if(!ser_ver_supported(version))
|
||||
|
@ -227,7 +227,9 @@ struct MapNode
|
||||
std::vector<aabb3f> getSelectionBoxes(INodeDefManager *nodemgr) const;
|
||||
|
||||
/* Liquid helpers */
|
||||
u8 getMaxLevel(INodeDefManager *nodemgr) const;
|
||||
u8 getLevel(INodeDefManager *nodemgr) const;
|
||||
u8 addLevel(INodeDefManager *nodemgr, s8 add = 1);
|
||||
|
||||
/*
|
||||
Serialization functions
|
||||
|
@ -213,6 +213,7 @@ void ContentFeatures::reset()
|
||||
liquid_alternative_source = "";
|
||||
liquid_viscosity = 0;
|
||||
liquid_renewable = true;
|
||||
freezemelt = "";
|
||||
liquid_range = LIQUID_LEVEL_MAX+1;
|
||||
drowning = true;
|
||||
light_source = 0;
|
||||
|
@ -224,6 +224,8 @@ struct ContentFeatures
|
||||
u8 liquid_viscosity;
|
||||
// Is liquid renewable (new liquid source will be created between 2 existing)
|
||||
bool liquid_renewable;
|
||||
// Ice for water, water for ice
|
||||
std::string freezemelt;
|
||||
// Number of flowing liquids surrounding source
|
||||
u8 liquid_range;
|
||||
bool drowning;
|
||||
|
@ -397,6 +397,7 @@ ContentFeatures read_content_features(lua_State *L, int index)
|
||||
f.leveled = getintfield_default(L, index, "leveled", f.leveled);
|
||||
|
||||
getboolfield(L, index, "liquid_renewable", f.liquid_renewable);
|
||||
getstringfield(L, index, "freezemelt", f.freezemelt);
|
||||
getboolfield(L, index, "drowning", f.drowning);
|
||||
// Amount of light the node emits
|
||||
f.light_source = getintfield_default(L, index,
|
||||
|
@ -233,3 +233,20 @@ void ScriptApiNode::node_on_receive_fields(v3s16 p,
|
||||
scriptError("error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
void ScriptApiNode::node_falling_update(v3s16 p)
|
||||
{
|
||||
SCRIPTAPI_PRECHECKHEADER
|
||||
lua_getglobal(L, "nodeupdate");
|
||||
push_v3s16(L, p);
|
||||
if(lua_pcall(L, 1, 0, 0))
|
||||
scriptError("error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
void ScriptApiNode::node_falling_update_single(v3s16 p)
|
||||
{
|
||||
SCRIPTAPI_PRECHECKHEADER
|
||||
lua_getglobal(L, "nodeupdate_single");
|
||||
push_v3s16(L, p);
|
||||
if(lua_pcall(L, 1, 0, 0))
|
||||
scriptError("error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
@ -49,6 +49,8 @@ public:
|
||||
const std::string &formname,
|
||||
const std::map<std::string, std::string> &fields,
|
||||
ServerActiveObject *sender);
|
||||
void node_falling_update(v3s16 p);
|
||||
void node_falling_update_single(v3s16 p);
|
||||
public:
|
||||
static struct EnumString es_DrawType[];
|
||||
static struct EnumString es_ContentParamType[];
|
||||
|
@ -263,6 +263,48 @@ int ModApiEnvMod::l_punch_node(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// minetest.get_node_max_level(pos)
|
||||
// pos = {x=num, y=num, z=num}
|
||||
int ModApiEnvMod::l_get_node_max_level(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
v3s16 pos = read_v3s16(L, 1);
|
||||
MapNode n = env->getMap().getNodeNoEx(pos);
|
||||
lua_pushnumber(L, n.getMaxLevel(env->getGameDef()->ndef()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// minetest.get_node_level(pos)
|
||||
// pos = {x=num, y=num, z=num}
|
||||
int ModApiEnvMod::l_get_node_level(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
v3s16 pos = read_v3s16(L, 1);
|
||||
MapNode n = env->getMap().getNodeNoEx(pos);
|
||||
lua_pushnumber(L, n.getLevel(env->getGameDef()->ndef()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// minetest.add_node_level(pos, level)
|
||||
// pos = {x=num, y=num, z=num}
|
||||
// level: 0..8
|
||||
int ModApiEnvMod::l_add_node_level(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
v3s16 pos = read_v3s16(L, 1);
|
||||
u8 level = 1;
|
||||
if(lua_isnumber(L, 2))
|
||||
level = lua_tonumber(L, 2);
|
||||
MapNode n = env->getMap().getNodeNoEx(pos);
|
||||
lua_pushnumber(L, n.addLevel(env->getGameDef()->ndef(), level));
|
||||
env->setNode(pos, n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// minetest.get_meta(pos)
|
||||
int ModApiEnvMod::l_get_meta(lua_State *L)
|
||||
{
|
||||
@ -820,6 +862,40 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// minetest.transforming_liquid_add(pos)
|
||||
int ModApiEnvMod::l_transforming_liquid_add(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
v3s16 p0 = read_v3s16(L, 1);
|
||||
env->getMap().transforming_liquid_add(p0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// minetest.get_heat(pos)
|
||||
// pos = {x=num, y=num, z=num}
|
||||
int ModApiEnvMod::l_get_heat(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
v3s16 pos = read_v3s16(L, 1);
|
||||
lua_pushnumber(L, env->getServerMap().getHeat(env, pos));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// minetest.get_humidity(pos)
|
||||
// pos = {x=num, y=num, z=num}
|
||||
int ModApiEnvMod::l_get_humidity(lua_State *L)
|
||||
{
|
||||
GET_ENV_PTR;
|
||||
|
||||
v3s16 pos = read_v3s16(L, 1);
|
||||
lua_pushnumber(L, env->getServerMap().getHumidity(env, pos));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
bool ModApiEnvMod::Initialize(lua_State *L,int top)
|
||||
{
|
||||
|
||||
@ -835,6 +911,9 @@ bool ModApiEnvMod::Initialize(lua_State *L,int top)
|
||||
retval &= API_FCT(place_node);
|
||||
retval &= API_FCT(dig_node);
|
||||
retval &= API_FCT(punch_node);
|
||||
retval &= API_FCT(get_node_max_level);
|
||||
retval &= API_FCT(get_node_level);
|
||||
retval &= API_FCT(add_node_level);
|
||||
retval &= API_FCT(add_entity);
|
||||
retval &= API_FCT(get_meta);
|
||||
retval &= API_FCT(get_node_timer);
|
||||
@ -853,6 +932,9 @@ bool ModApiEnvMod::Initialize(lua_State *L,int top)
|
||||
retval &= API_FCT(spawn_tree);
|
||||
retval &= API_FCT(find_path);
|
||||
retval &= API_FCT(line_of_sight);
|
||||
retval &= API_FCT(transforming_liquid_add);
|
||||
retval &= API_FCT(get_heat);
|
||||
retval &= API_FCT(get_humidity);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
@ -67,6 +67,19 @@ private:
|
||||
// pos = {x=num, y=num, z=num}
|
||||
static int l_punch_node(lua_State *L);
|
||||
|
||||
|
||||
// minetest.get_node_max_level(pos)
|
||||
// pos = {x=num, y=num, z=num}
|
||||
static int l_get_node_max_level(lua_State *L);
|
||||
|
||||
// minetest.get_node_level(pos)
|
||||
// pos = {x=num, y=num, z=num}
|
||||
static int l_get_node_level(lua_State *L);
|
||||
|
||||
// minetest.add_node_level(pos)
|
||||
// pos = {x=num, y=num, z=num}
|
||||
static int l_add_node_level(lua_State *L);
|
||||
|
||||
// minetest.get_meta(pos)
|
||||
static int l_get_meta(lua_State *L);
|
||||
|
||||
@ -135,6 +148,12 @@ private:
|
||||
// minetest.find_path(pos1, pos2, searchdistance,
|
||||
// max_jump, max_drop, algorithm) -> table containing path
|
||||
static int l_find_path(lua_State *L);
|
||||
|
||||
// minetest.transforming_liquid_add(pos)
|
||||
static int l_transforming_liquid_add(lua_State *L);
|
||||
|
||||
static int l_get_heat(lua_State *L);
|
||||
static int l_get_humidity(lua_State *L);
|
||||
|
||||
static struct EnumString es_MapgenObject[];
|
||||
|
||||
|
@ -61,11 +61,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
23: new node metadata format
|
||||
24: 16-bit node ids and node timers (never released as stable)
|
||||
25: Improved node timer format
|
||||
26: MapBlocks contain heat and humidity
|
||||
*/
|
||||
// This represents an uninitialized or invalid format
|
||||
#define SER_FMT_VER_INVALID 255
|
||||
// Highest supported serialization version
|
||||
#define SER_FMT_VER_HIGHEST 25
|
||||
#define SER_FMT_VER_HIGHEST 26
|
||||
// Lowest supported serialization version
|
||||
#define SER_FMT_VER_LOWEST 0
|
||||
|
||||
|
@ -349,5 +349,12 @@ inline void paging(u32 length, u32 page, u32 pagecount, u32 &minindex, u32 &maxi
|
||||
}
|
||||
}
|
||||
|
||||
inline float cycle_shift(float value, float by = 0, float max = 1)
|
||||
{
|
||||
if (value + by < 0) return max + by + value;
|
||||
if (value + by > max) return value + by - max;
|
||||
return value + by;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user