aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/content_abm.cpp274
-rw-r--r--src/defaultsettings.cpp2
-rw-r--r--src/emerge.cpp8
-rw-r--r--src/environment.h1
-rw-r--r--src/game.cpp5
-rw-r--r--src/map.cpp82
-rw-r--r--src/map.h8
-rw-r--r--src/mapblock.cpp16
-rw-r--r--src/mapblock.h5
-rw-r--r--src/mapnode.cpp46
-rw-r--r--src/mapnode.h2
-rw-r--r--src/nodedef.cpp1
-rw-r--r--src/nodedef.h2
-rw-r--r--src/script/common/c_content.cpp1
-rw-r--r--src/script/cpp_api/s_node.cpp17
-rw-r--r--src/script/cpp_api/s_node.h2
-rw-r--r--src/script/lua_api/l_env.cpp82
-rw-r--r--src/script/lua_api/l_env.h19
-rw-r--r--src/serialization.h3
-rw-r--r--src/util/numeric.h7
20 files changed, 510 insertions, 73 deletions
diff --git a/src/content_abm.cpp b/src/content_abm.cpp
index 6adcbf708..110ac1eea 100644
--- a/src/content_abm.cpp
+++ b/src/content_abm.cpp
@@ -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));
+ }
}
}
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index a537732db..326e11b8f 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -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");
diff --git a/src/emerge.cpp b/src/emerge.cpp
index c0560ba3b..f97763718 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -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();
diff --git a/src/environment.h b/src/environment.h
index e175d70d9..8fc5611e4 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -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:
/*
diff --git a/src/game.cpp b/src/game.cpp
index 3f14f09d4..0c7d15d0c 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -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);
diff --git a/src/map.cpp b/src/map.cpp
index 11f5d6483..fa52a2f52 100644
--- a/src/map.cpp
+++ b/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
*/
diff --git a/src/map.h b/src/map.h
index bccadcec5..c1fd361a7 100644
--- a/src/map.h
+++ b/src/map.h
@@ -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;
diff --git a/src/mapblock.cpp b/src/mapblock.cpp
index dd95ab77f..56d4416a4 100644
--- a/src/mapblock.cpp
+++ b/src/mapblock.cpp
@@ -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())
diff --git a/src/mapblock.h b/src/mapblock.h
index 05bb944a6..016841115 100644
--- a/src/mapblock.h
+++ b/src/mapblock.h
@@ -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
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 33644cf5c..4707978cb 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -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))
diff --git a/src/mapnode.h b/src/mapnode.h
index 74b079c6d..fcff1707a 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -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
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index a4d036883..96dca730b 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -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;
diff --git a/src/nodedef.h b/src/nodedef.h
index 3a8210304..067861e62 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -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;
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index dcffabb8b..d97264009 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -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,
diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp
index 49a825cac..d0b0583c0 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -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));
+}
diff --git a/src/script/cpp_api/s_node.h b/src/script/cpp_api/s_node.h
index a8c9b3a79..517b4b04e 100644
--- a/src/script/cpp_api/s_node.h
+++ b/src/script/cpp_api/s_node.h
@@ -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[];
diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp
index 1cbf34ab9..52ea55717 100644
--- a/src/script/lua_api/l_env.cpp
+++ b/src/script/lua_api/l_env.cpp
@@ -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;
}
diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h
index 713cfa69f..eaef16180 100644
--- a/src/script/lua_api/l_env.h
+++ b/src/script/lua_api/l_env.h
@@ -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[];
diff --git a/src/serialization.h b/src/serialization.h
index defead31e..807b68e9d 100644
--- a/src/serialization.h
+++ b/src/serialization.h
@@ -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
diff --git a/src/util/numeric.h b/src/util/numeric.h
index 3e82997bd..076a08efc 100644
--- a/src/util/numeric.h
+++ b/src/util/numeric.h
@@ -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