Add ABM required neighbor check
authorPerttu Ahola <celeron55@gmail.com>
Sat, 3 Dec 2011 16:18:59 +0000 (18:18 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Sat, 3 Dec 2011 16:18:59 +0000 (18:18 +0200)
data/mods/default/init.lua
src/environment.cpp
src/environment.h
src/scriptapi.cpp

index 2e07b54121ceea5b147cbd8859d9a332a00c7627..7383996b13bada6ee2882939dd33d121818eac1d 100644 (file)
@@ -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))
 --     }
 -- }
 --
+-- 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))
 
index 67ea05cf60e83e9df021c594acd1559bfbca5f43..aa2b45f8f5c95b77d571d03af747a55920278a6f 100644 (file)
@@ -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
index 7759d43afb6598351c613bd5b1ccc9dd22552e2d..e14a9c48589a6109a3229efbf54ba70f3f58f59b 100644 (file)
@@ -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){};
index c9f132f4affccbce7af3102827d8595b00a9f94e..3fe69e709b361c911f9d618a4ebed3ec92925252 100644 (file)
@@ -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);