e50edddd7def9aaa8b86f48e8fc6272ff7840bf9
[oweals/minetest.git] / src / content_abm.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "content_abm.h"
21
22 #include "environment.h"
23 #include "gamedef.h"
24 #include "nodedef.h"
25 #include "content_sao.h"
26 #include "settings.h"
27 #include "mapblock.h" // For getNodeBlockPos
28 #include "treegen.h" // For treegen::make_tree
29 #include "main.h" // for g_settings
30 #include "map.h"
31
32 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
33
34 class GrowGrassABM : public ActiveBlockModifier
35 {
36 private:
37 public:
38         virtual std::set<std::string> getTriggerContents()
39         {
40                 std::set<std::string> s;
41                 s.insert("mapgen_dirt");
42                 return s;
43         }
44         virtual float getTriggerInterval()
45         { return 2.0; }
46         virtual u32 getTriggerChance()
47         { return 200; }
48         virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
49         {
50                 INodeDefManager *ndef = env->getGameDef()->ndef();
51                 ServerMap *map = &env->getServerMap();
52                 
53                 MapNode n_top = map->getNodeNoEx(p+v3s16(0,1,0));
54                 if(ndef->get(n_top).light_propagates &&
55                                 !ndef->get(n_top).isLiquid() &&
56                                 n_top.getLightBlend(env->getDayNightRatio(), ndef) >= 13)
57                 {
58                         n.setContent(ndef->getId("mapgen_dirt_with_grass"));
59                         map->addNodeWithEvent(p, n);
60                 }
61         }
62 };
63
64 class RemoveGrassABM : public ActiveBlockModifier
65 {
66 private:
67 public:
68         virtual std::set<std::string> getTriggerContents()
69         {
70                 std::set<std::string> s;
71                 s.insert("mapgen_dirt_with_grass");
72                 return s;
73         }
74         virtual float getTriggerInterval()
75         { return 2.0; }
76         virtual u32 getTriggerChance()
77         { return 20; }
78         virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
79         {
80                 INodeDefManager *ndef = env->getGameDef()->ndef();
81                 ServerMap *map = &env->getServerMap();
82                 
83                 MapNode n_top = map->getNodeNoEx(p+v3s16(0,1,0));
84                 if((!ndef->get(n_top).light_propagates &&
85                                 n_top.getContent() != CONTENT_IGNORE) ||
86                                 ndef->get(n_top).isLiquid())
87                 {
88                         n.setContent(ndef->getId("mapgen_dirt"));
89                         map->addNodeWithEvent(p, n);
90                 }
91         }
92 };
93
94 class MakeTreesFromSaplingsABM : public ActiveBlockModifier
95 {
96 private:
97 public:
98         virtual std::set<std::string> getTriggerContents()
99         {
100                 std::set<std::string> s;
101                 s.insert("sapling");
102                 s.insert("junglesapling");
103                 return s;
104         }
105         virtual float getTriggerInterval()
106         { return 10.0; }
107         virtual u32 getTriggerChance()
108         { return 50; }
109         virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n,
110                         u32 active_object_count, u32 active_object_count_wider)
111         {
112                 INodeDefManager *ndef = env->getGameDef()->ndef();
113                 ServerMap *map = &env->getServerMap();
114                 
115                 bool is_jungle_tree = n.getContent() == ndef->getId("junglesapling");
116                 
117                 actionstream <<"A " << (is_jungle_tree ? "jungle " : "")
118                                 << "sapling grows into a tree at "
119                                 << PP(p) << std::endl;
120
121                 std::map<v3s16, MapBlock*> modified_blocks;
122                 v3s16 tree_p = p;
123                 ManualMapVoxelManipulator vmanip(map);
124                 v3s16 tree_blockp = getNodeBlockPos(tree_p);
125                 vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,1,1));
126                 
127                 if (is_jungle_tree) {
128                         treegen::make_jungletree(vmanip, tree_p, ndef, myrand());
129                 } else {
130                         bool is_apple_tree = myrand() % 4 == 0;
131                         treegen::make_tree(vmanip, tree_p, is_apple_tree, ndef, myrand());
132                 }
133                 
134                 vmanip.blitBackAll(&modified_blocks);
135
136                 // update lighting
137                 std::map<v3s16, MapBlock*> lighting_modified_blocks;
138                 lighting_modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
139                 map->updateLighting(lighting_modified_blocks, modified_blocks);
140
141                 // Send a MEET_OTHER event
142                 MapEditEvent event;
143                 event.type = MEET_OTHER;
144 //              event.modified_blocks.insert(modified_blocks.begin(), modified_blocks.end());
145                 for(std::map<v3s16, MapBlock*>::iterator
146                         i = modified_blocks.begin();
147                         i != modified_blocks.end(); ++i)
148                 {
149                         event.modified_blocks.insert(i->first);
150                 }
151                 map->dispatchEvent(&event);
152         }
153 };
154
155 class LiquidFlowABM : public ActiveBlockModifier
156 {
157 private:
158         std::set<std::string> contents;
159
160 public:
161         LiquidFlowABM(ServerEnvironment *env, INodeDefManager *nodemgr) 
162         {
163                 std::set<content_t> liquids;
164                 nodemgr->getIds("group:liquid", liquids);
165                 for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
166                         contents.insert(nodemgr->get(*k).liquid_alternative_flowing);
167                 
168         }
169         virtual std::set<std::string> getTriggerContents()
170         {
171                 return contents;
172         }
173         virtual float getTriggerInterval()
174         { return 10.0; }
175         virtual u32 getTriggerChance()
176         { return 10; }
177         virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n)
178         {
179                 ServerMap *map = &env->getServerMap();
180                 if (map->transforming_liquid_size() < 500)
181                         map->transforming_liquid_add(p);
182                 //if ((*map).m_transforming_liquid.size() < 500) (*map).m_transforming_liquid.push_back(p);
183         }
184 };
185
186 void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef)
187 {
188         env->addActiveBlockModifier(new GrowGrassABM());
189         env->addActiveBlockModifier(new RemoveGrassABM());
190         env->addActiveBlockModifier(new MakeTreesFromSaplingsABM());
191         if (g_settings->getBool("liquid_finite"))
192                 env->addActiveBlockModifier(new LiquidFlowABM(env, nodedef));
193 }