summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/mods/default/init.lua11
-rw-r--r--src/environment.cpp36
-rw-r--r--src/environment.h8
-rw-r--r--src/scriptapi.cpp32
4 files changed, 84 insertions, 3 deletions
diff --git a/data/mods/default/init.lua b/data/mods/default/init.lua
index 2e07b5412..7383996b1 100644
--- a/data/mods/default/init.lua
+++ b/data/mods/default/init.lua
@@ -73,6 +73,7 @@
-- minetest.register_node(name, node definition)
-- minetest.register_craftitem(name, craftitem definition)
-- minetest.register_craft(recipe)
+-- minetest.register_abm(abm definition)
-- minetest.register_globalstep(func(dtime))
-- minetest.register_on_placenode(func(pos, newnode, placer))
-- minetest.register_on_dignode(func(pos, oldnode, digger))
@@ -285,6 +286,16 @@
-- }
-- }
--
+-- ABM (ActiveBlockModifier) definition:
+-- {
+-- nodenames = {"lava_source"},
+-- neighbors = {"water_source", "water_flowing"}, -- (any of these)
+-- ^ If left out or empty, any neighbor will do
+-- ^ This might get removed in the future
+-- interval = 1.0, -- (operation interval)
+-- chance = 1, -- (chance of trigger is 1.0/this)
+-- action = func(pos, node, active_object_count, active_object_count_wider),
+-- }
-- print("minetest dump: "..dump(minetest))
diff --git a/src/environment.cpp b/src/environment.cpp
index 67ea05cf6..aa2b45f8f 100644
--- a/src/environment.cpp
+++ b/src/environment.cpp
@@ -565,6 +565,7 @@ struct ActiveABM
{
ActiveBlockModifier *abm;
int chance;
+ std::set<content_t> required_neighbors;
};
class ABMHandler
@@ -602,6 +603,18 @@ public:
aabm.chance = 1.0 / pow((float)1.0/chance, (float)intervals);
if(aabm.chance == 0)
aabm.chance = 1;
+ // Trigger neighbors
+ std::set<std::string> required_neighbors_s
+ = abm->getRequiredNeighbors();
+ for(std::set<std::string>::iterator
+ i = required_neighbors_s.begin();
+ i != required_neighbors_s.end(); i++){
+ content_t c = ndef->getId(*i);
+ if(c == CONTENT_IGNORE)
+ continue;
+ aabm.required_neighbors.insert(c);
+ }
+ // Trigger contents
std::set<std::string> contents_s = abm->getTriggerContents();
for(std::set<std::string>::iterator
i = contents_s.begin(); i != contents_s.end(); i++){
@@ -646,6 +659,29 @@ public:
if(myrand() % i->chance != 0)
continue;
+ // Check neighbors
+ if(!i->required_neighbors.empty())
+ {
+ v3s16 p1;
+ for(p1.X = p.X-1; p1.X <= p.X+1; p1.X++)
+ for(p1.Y = p.Y-1; p1.Y <= p.Y+1; p1.Y++)
+ for(p1.Z = p.Z-1; p1.Z <= p.Z+1; p1.Z++)
+ {
+ if(p1 == p)
+ continue;
+ MapNode n = map->getNodeNoEx(p1);
+ content_t c = n.getContent();
+ std::set<content_t>::const_iterator k;
+ k = i->required_neighbors.find(c);
+ if(k != i->required_neighbors.end()){
+ goto neighbor_found;
+ }
+ }
+ // No required neighbor found
+ continue;
+ }
+neighbor_found:
+
// Find out how many objects the block contains
u32 active_object_count = block->m_static_objects.m_active.size();
// Find out how many objects this and all the neighbors contain
diff --git a/src/environment.h b/src/environment.h
index 7759d43af..e14a9c485 100644
--- a/src/environment.h
+++ b/src/environment.h
@@ -108,9 +108,15 @@ public:
ActiveBlockModifier(){};
virtual ~ActiveBlockModifier(){};
+ // Set of contents to trigger on
virtual std::set<std::string> getTriggerContents()=0;
+ // Set of required neighbors (trigger doesn't happen if none are found)
+ // Empty = do not check neighbors
+ virtual std::set<std::string> getRequiredNeighbors()
+ { return std::set<std::string>(); }
+ // Trigger interval in seconds
virtual float getTriggerInterval() = 0;
- // chance of (1 / return value), 0 is disallowed
+ // Random chance of (1 / return value), 0 is disallowed
virtual u32 getTriggerChance() = 0;
// This is called usually at interval for 1/chance of the nodes
virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n){};
diff --git a/src/scriptapi.cpp b/src/scriptapi.cpp
index c9f132f4a..3fe69e709 100644
--- a/src/scriptapi.cpp
+++ b/src/scriptapi.cpp
@@ -709,15 +709,18 @@ private:
int m_id;
std::set<std::string> m_trigger_contents;
+ std::set<std::string> m_required_neighbors;
float m_trigger_interval;
u32 m_trigger_chance;
public:
LuaABM(lua_State *L, int id,
const std::set<std::string> &trigger_contents,
+ const std::set<std::string> &required_neighbors,
float trigger_interval, u32 trigger_chance):
m_lua(L),
m_id(id),
m_trigger_contents(trigger_contents),
+ m_required_neighbors(required_neighbors),
m_trigger_interval(trigger_interval),
m_trigger_chance(trigger_chance)
{
@@ -726,6 +729,10 @@ public:
{
return m_trigger_contents;
}
+ virtual std::set<std::string> getRequiredNeighbors()
+ {
+ return m_required_neighbors;
+ }
virtual float getTriggerInterval()
{
return m_trigger_interval;
@@ -2575,7 +2582,9 @@ void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
lua_pushlightuserdata(L, env);
lua_setfield(L, LUA_REGISTRYINDEX, "minetest_env");
- /* Add ActiveBlockModifiers to environment */
+ /*
+ Add ActiveBlockModifiers to environment
+ */
// Get minetest.registered_abms
lua_getglobal(L, "minetest");
@@ -2603,6 +2612,25 @@ void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
// removes value, keeps key for next iteration
lua_pop(L, 1);
}
+ } else if(lua_isstring(L, -1)){
+ trigger_contents.insert(lua_tostring(L, -1));
+ }
+ lua_pop(L, 1);
+
+ std::set<std::string> required_neighbors;
+ lua_getfield(L, current_abm, "neighbors");
+ if(lua_istable(L, -1)){
+ int table = lua_gettop(L);
+ lua_pushnil(L);
+ while(lua_next(L, table) != 0){
+ // key at index -2 and value at index -1
+ luaL_checktype(L, -1, LUA_TSTRING);
+ required_neighbors.insert(lua_tostring(L, -1));
+ // removes value, keeps key for next iteration
+ lua_pop(L, 1);
+ }
+ } else if(lua_isstring(L, -1)){
+ required_neighbors.insert(lua_tostring(L, -1));
}
lua_pop(L, 1);
@@ -2613,7 +2641,7 @@ void scriptapi_add_environment(lua_State *L, ServerEnvironment *env)
getintfield(L, current_abm, "chance", trigger_chance);
LuaABM *abm = new LuaABM(L, id, trigger_contents,
- trigger_interval, trigger_chance);
+ required_neighbors, trigger_interval, trigger_chance);
env->addActiveBlockModifier(abm);