]> git.lizzy.rs Git - dragonfireclient.git/blob - src/content_abm.cpp
Move the sapling growing and grass adding/removing ABMs to Lua
[dragonfireclient.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 "main.h" // for g_settings
29 #include "map.h"
30 #include "scripting_game.h"
31 #include "log.h"
32
33 #define PP(x) "("<<(x).X<<","<<(x).Y<<","<<(x).Z<<")"
34
35 class LiquidFlowABM : public ActiveBlockModifier {
36         private:
37                 std::set<std::string> contents;
38
39         public:
40                 LiquidFlowABM(ServerEnvironment *env, INodeDefManager *nodemgr) {
41                         std::set<content_t> liquids;
42                         nodemgr->getIds("group:liquid", liquids);
43                         for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
44                                 contents.insert(nodemgr->get(*k).liquid_alternative_flowing);
45                 }
46                 virtual std::set<std::string> getTriggerContents() {
47                         return contents;
48                 }
49                 virtual float getTriggerInterval()
50                 { return 10.0; }
51                 virtual u32 getTriggerChance()
52                 { return 10; }
53                 virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
54                         ServerMap *map = &env->getServerMap();
55                         if (map->transforming_liquid_size() > 500)
56                                 return;
57                         map->transforming_liquid_add(p);
58                 }
59 };
60
61 class LiquidDropABM : public ActiveBlockModifier {
62         private:
63                 std::set<std::string> contents;
64
65         public:
66                 LiquidDropABM(ServerEnvironment *env, INodeDefManager *nodemgr) {
67                         std::set<content_t> liquids;
68                         nodemgr->getIds("group:liquid", liquids);
69                         for(std::set<content_t>::const_iterator k = liquids.begin(); k != liquids.end(); k++)
70                                 contents.insert(nodemgr->get(*k).liquid_alternative_source);
71                 }
72                 virtual std::set<std::string> getTriggerContents()
73                 { return contents; }
74                 virtual std::set<std::string> getRequiredNeighbors() {
75                         std::set<std::string> neighbors;
76                         neighbors.insert("air");
77                         return neighbors;
78                 }
79                 virtual float getTriggerInterval()
80                 { return 20.0; }
81                 virtual u32 getTriggerChance()
82                 { return 10; }
83                 virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
84                         ServerMap *map = &env->getServerMap();
85                         if (map->transforming_liquid_size() > 500)
86                                 return;
87                         if (   map->getNodeNoEx(p - v3s16(0,  1, 0 )).getContent() != CONTENT_AIR  // below
88                             && map->getNodeNoEx(p - v3s16(1,  0, 0 )).getContent() != CONTENT_AIR  // right
89                             && map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent() != CONTENT_AIR  // left
90                             && map->getNodeNoEx(p - v3s16(0,  0, 1 )).getContent() != CONTENT_AIR  // back
91                             && map->getNodeNoEx(p - v3s16(0,  0, -1)).getContent() != CONTENT_AIR  // front
92                            )
93                                 return;
94                         map->transforming_liquid_add(p);
95                 }
96 };
97
98 class LiquidFreeze : public ActiveBlockModifier {
99         public:
100                 LiquidFreeze(ServerEnvironment *env, INodeDefManager *nodemgr) { }
101                 virtual std::set<std::string> getTriggerContents() {
102                         std::set<std::string> s;
103                         s.insert("group:freezes");
104                         return s;
105                 }
106                 virtual std::set<std::string> getRequiredNeighbors() {
107                         std::set<std::string> s;
108                         s.insert("air");
109                         s.insert("group:melts");
110                         return s;
111                 }
112                 virtual float getTriggerInterval()
113                 { return 10.0; }
114                 virtual u32 getTriggerChance()
115                 { return 20; }
116                 virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
117                         ServerMap *map = &env->getServerMap();
118                         INodeDefManager *ndef = env->getGameDef()->ndef();
119
120                         float heat = map->updateBlockHeat(env, p);
121                         //heater = rare
122                         content_t c = map->getNodeNoEx(p - v3s16(0,  -1, 0 )).getContent(); // top
123                         //more chance to freeze if air at top
124                         if (heat <= -1 && (heat <= -50 || (myrand_range(-50, heat) <= (c == CONTENT_AIR ? -10 : -40)))) {
125                                 content_t c_self = n.getContent();
126                                 // making freeze not annoying, do not freeze random blocks in center of ocean
127                                 // todo: any block not water (dont freeze _source near _flowing)
128                                 bool allow = heat < -40;
129                                 // todo: make for(...)
130                                 if (!allow) {
131                                  c = map->getNodeNoEx(p - v3s16(0,  1, 0 )).getContent(); // below
132                                  if (c == CONTENT_AIR || c == CONTENT_IGNORE)
133                                         return; // do not freeze when falling
134                                  if (c != c_self && c != CONTENT_IGNORE) allow = 1;
135                                  if (!allow) {
136                                   c = map->getNodeNoEx(p - v3s16(1,  0, 0 )).getContent(); // right
137                                   if (c != c_self && c != CONTENT_IGNORE) allow = 1;
138                                   if (!allow) {
139                                    c = map->getNodeNoEx(p - v3s16(-1, 0, 0 )).getContent(); // left
140                                    if (c != c_self && c != CONTENT_IGNORE) allow = 1;
141                                    if (!allow) {
142                                     c = map->getNodeNoEx(p - v3s16(0,  0, 1 )).getContent(); // back
143                                     if (c != c_self && c != CONTENT_IGNORE) allow = 1;
144                                     if (!allow) {
145                                      c = map->getNodeNoEx(p - v3s16(0,  0, -1)).getContent(); // front
146                                      if (c != c_self && c != CONTENT_IGNORE) allow = 1;
147                                     }
148                                    }
149                                   }
150                                  }
151                                 }
152                                 if (allow) {
153                                         n.freezeMelt(ndef);
154                                         map->addNodeWithEvent(p, n);
155                                 }
156                         }
157                 }
158 };
159
160 class LiquidMeltWeather : public ActiveBlockModifier {
161         public:
162                 LiquidMeltWeather(ServerEnvironment *env, INodeDefManager *nodemgr) { }
163                 virtual std::set<std::string> getTriggerContents() {
164                         std::set<std::string> s;
165                         s.insert("group:melts");
166                         return s;
167                 }
168                 virtual std::set<std::string> getRequiredNeighbors() {
169                         std::set<std::string> s;
170                         s.insert("air");
171                         s.insert("group:freezes");
172                         return s;
173                 }
174                 virtual float getTriggerInterval()
175                 { return 10.0; }
176                 virtual u32 getTriggerChance()
177                 { return 20; }
178                 virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
179                         ServerMap *map = &env->getServerMap();
180                         INodeDefManager *ndef = env->getGameDef()->ndef();
181
182                         float heat = map->updateBlockHeat(env, p);
183                         content_t c = map->getNodeNoEx(p - v3s16(0,  -1, 0 )).getContent(); // top
184                         if (heat >= 1 && (heat >= 40 || ((myrand_range(heat, 40)) >= (c == CONTENT_AIR ? 10 : 20)))) {
185                                 n.freezeMelt(ndef);
186                                 map->addNodeWithEvent(p, n);
187                                 env->getScriptIface()->node_falling_update(p);
188                         }
189                 }
190 };
191
192 class LiquidMeltHot : public ActiveBlockModifier {
193         public:
194                 LiquidMeltHot(ServerEnvironment *env, INodeDefManager *nodemgr) { }
195                 virtual std::set<std::string> getTriggerContents() {
196                         std::set<std::string> s;
197                         s.insert("group:melts");
198                         return s;
199                 }
200                 virtual std::set<std::string> getRequiredNeighbors() {
201                         std::set<std::string> s;
202                         s.insert("group:igniter");
203                         s.insert("group:hot");
204                         return s;
205                 }
206                 virtual float getTriggerInterval()
207                 { return 2.0; }
208                 virtual u32 getTriggerChance()
209                 { return 4; }
210                 virtual void trigger(ServerEnvironment *env, v3s16 p, MapNode n) {
211                         ServerMap *map = &env->getServerMap();
212                         INodeDefManager *ndef = env->getGameDef()->ndef();
213                         n.freezeMelt(ndef);
214                         map->addNodeWithEvent(p, n);
215                         env->getScriptIface()->node_falling_update(p);
216                 }
217 };
218
219 /* too buggy, later via liquid flow code
220 class LiquidMeltAround : public LiquidMeltHot {
221         public:
222                 LiquidMeltAround(ServerEnvironment *env, INodeDefManager *nodemgr) 
223                         : LiquidMeltHot(env, nodemgr) { }
224                 virtual std::set<std::string> getRequiredNeighbors() {
225                         std::set<std::string> s;
226                         s.insert("group:melt_around");
227                         return s;
228                 }
229                 virtual float getTriggerInterval()
230                 { return 40.0; }
231                 virtual u32 getTriggerChance()
232                 { return 60; }
233 };
234 */
235
236 void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef) {
237         if (g_settings->getBool("liquid_finite")) {
238                 env->addActiveBlockModifier(new LiquidFlowABM(env, nodedef));
239                 env->addActiveBlockModifier(new LiquidDropABM(env, nodedef));
240                 env->addActiveBlockModifier(new LiquidMeltHot(env, nodedef));
241                 //env->addActiveBlockModifier(new LiquidMeltAround(env, nodedef));
242                 if (env->m_use_weather) {
243                         env->addActiveBlockModifier(new LiquidFreeze(env, nodedef));
244                         env->addActiveBlockModifier(new LiquidMeltWeather(env, nodedef));
245                 }
246         }
247 }