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 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 required_neighbors_s + = abm->getRequiredNeighbors(); + for(std::set::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 contents_s = abm->getTriggerContents(); for(std::set::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::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 getTriggerContents()=0; + // Set of required neighbors (trigger doesn't happen if none are found) + // Empty = do not check neighbors + virtual std::set getRequiredNeighbors() + { return std::set(); } + // 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 m_trigger_contents; + std::set m_required_neighbors; float m_trigger_interval; u32 m_trigger_chance; public: LuaABM(lua_State *L, int id, const std::set &trigger_contents, + const std::set &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 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 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);