-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmapping.lua
350 lines (298 loc) · 12.4 KB
/
mapping.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
-- debug-print
--local dprint = print
local dprint = function() return end
local mapping = {}
-- visual for cost_item free for payment
mapping.c_free_item = "default:cloud"
-----------------------------------------------
-- door compatibility. Seems the old doors was facedir and now the wallmounted values should be used (custom_function)
-----------------------------------------------
function mapping.param2_wallmounted_to_facedir(mapped, node)
if mapped.param2 == 0 then -- +y?
mapped.param2 = 0
elseif mapped.param2 == 1 then -- -y?
mapped.param2 = 1
elseif mapped.param2 == 2 then --unsure
mapped.param2 = 3
elseif mapped.param2 == 3 then --unsure
mapped.param2 = 1
elseif mapped.param2 == 4 then --unsure
mapped.param2 = 2
elseif mapped.param2 == 5 then --unsure
mapped.param2 = 0
end
end
-----------------------------------------------
-- Torches compatibility (custom_function)
-----------------------------------------------
function mapping.torches_compat(mapped, node)
-- from default:3dtorch-lbm
if mapped.param2 == 0 then
mapped.name = "default:torch_ceiling"
elseif mapped.param2 == 1 then
mapped.name = "default:torch"
else
mapped.name = "default:torch_wall"
end
end
function mapping.remove_formspec(mapped, node)
-- Chest does use on_rightclick / show_formspec now
if mapped.meta and mapped.meta.fields then
mapped.meta.fields.formspec = nil
end
end
-----------------------------------------------
-- Unknown nodes mapping
-----------------------------------------------
local unknown_nodes_data = {
-- Fallback / Compatibility nodes replacement for ingame unknown nodes
["xpanes:pane_glass_10"] = { name = "xpanes:pane_10" },
["xpanes:pane_glass_5"] = { name = "xpanes:pane_5" },
["beds:bed_top_blue"] = { name = "beds:bed_top" },
["beds:bed_bottom_blue"] = { name = "beds:bed_bottom" },
["homedecor:table_lamp_max"] = { name = "homedecor:table_lamp_white_max" },
["homedecor:refrigerator"] = { name = "homedecor:refrigerator_steel" },
["ethereal:green_dirt"] = { name = "default:dirt_with_grass" },
["doors:door_wood_b_c"] = {name = "doors:door_wood_a", meta = {fields = {state = 1}}, custom_function = mapping.param2_wallmounted_to_facedir }, --closed
["doors:door_wood_b_o"] = {name = "doors:door_wood_b", meta = {fields = {state = 3}}, custom_function = mapping.param2_wallmounted_to_facedir }, --open
["doors:door_wood_b_1"] = {name = "doors:door_wood_a", meta = {fields = {state = 0}}}, --Left door closed
["doors:door_wood_b_2"] = {name = "doors:door_wood_b", meta = {fields = {state = 2}}}, --right door closed
["doors:door_wood_a_c"] = {name = "doors:hidden" },
["doors:door_wood_a_o"] = {name = "doors:hidden" },
["doors:door_wood_t_1"] = {name = "doors:hidden" },
["doors:door_wood_t_2"] = {name = "doors:hidden" },
["doors:door_glass_b_c"] = {name = "doors:door_glass_a", meta = {fields = {state = 1}}, custom_function = mapping.param2_wallmounted_to_facedir }, --closed
["doors:door_glass_b_o"] = {name = "doors:door_glass_b", meta = {fields = {state = 3}}, custom_function = mapping.param2_wallmounted_to_facedir }, --open
["doors:door_glass_b_1"] = {name = "doors:door_glass_a", meta = {fields = {state = 0}}}, --Left door closed
["doors:door_glass_b_2"] = {name = "doors:door_glass_b", meta = {fields = {state = 2}}}, --right door closed
["doors:door_glass_a_c"] = {name = "doors:hidden" },
["doors:door_glass_a_o"] = {name = "doors:hidden" },
["doors:door_glass_t_1"] = {name = "doors:hidden" },
["doors:door_glass_t_2"] = {name = "doors:hidden" },
["doors:door_steel_b_c"] = {name = "doors:door_steel_a", meta = {fields = {state = 1}}, custom_function = mapping.param2_wallmounted_to_facedir }, --closed
["doors:door_steel_b_o"] = {name = "doors:door_steel_b", meta = {fields = {state = 3}}, custom_function = mapping.param2_wallmounted_to_facedir }, --open
["doors:door_steel_b_1"] = {name = "doors:door_steel_a", meta = {fields = {state = 0}}}, --Left door closed
["doors:door_steel_b_2"] = {name = "doors:door_steel_b", meta = {fields = {state = 2}}}, --right door closed
["doors:door_steel_a_c"] = {name = "doors:hidden" },
["doors:door_steel_a_o"] = {name = "doors:hidden" },
["doors:door_steel_t_1"] = {name = "doors:hidden" },
["doors:door_steel_t_2"] = {name = "doors:hidden" },
["fallback"] = {name = "air" },
}
-----------------------------------------------
-- Default Replacements and adjustments
-----------------------------------------------
local default_replacements = {
-- "name" and "cost_item" are optional.
-- if name is missed it will not be changed
-- if cost_item is missed it will be determinated as usual (name or drop)
-- a crazy sample is: instead of cobble place goldblock, use wood as payment
-- c["default:cobble"] = { name = "default:goldblock", cost_item = "default:wood" }
["beds:bed_top"] = { cost_item = mapping.c_free_item }, -- the bottom of the bed is payed, so buld the top for free
-- it is hard to get a source in survival, so we use buckets. Note, the bucket is lost after usage by NPC
["default:lava_source"] = { cost_item = "bucket:bucket_lava" },
["default:river_water_source"] = { cost_item = "bucket:bucket_river_water" },
["default:water_source"] = { cost_item = "bucket:bucket_water" },
-- does not sense to set flowing water because it flow away without the source (and will be generated trough source)
["default:water_flowing"] = { name = "air" },
["default:lava_flowing"] = { name = "air" },
["default:river_water_flowing"] = { name = "air" },
-- pay different dirt types by the sane dirt
["default:dirt_with_dry_grass"] = { cost_item = "default:dirt" },
["default:dirt_with_grass"] = { cost_item = "default:dirt" },
["default:dirt_with_snow"] = { cost_item = "default:dirt" },
-- Changed with MTG-0.4.16
["xpanes:pane_5"] = { name = "xpanes:pane_flat", param2 = 0 }, --unsure
["xpanes:pane_10"] = { name = "xpanes:pane_flat", param2 = 1 }, --unsure
["default:torch"] = { custom_function = mapping.torches_compat },
["torches:wall"] = { name = "default:torch_wall" },
-- Chest does use on_rightclick / show_formspec now
["default:chest"] = {custom_function = mapping.remove_formspec },
["default:chest_locked"] = {custom_function = mapping.remove_formspec },
}
-----------------------------------------------
-- Handle doors mirroring (_a vs _b)
-----------------------------------------------
local function __mirror_doors(mr)
if not mr.node_def.door then
return
end
local node_name = mr.name
if node_name:sub(-1) == 'a' then
node_name = node_name:sub(1,-2)..'b'
else
node_name = node_name:sub(1,-2)..'a'
end
if minetest.registered_nodes[node_name] then
mr.node_def = minetest.registered_nodes[node_name]
mr.name = node_name
if mr.meta and mr.meta.fields and mr.meta.fields.state then
mr.meta.fields.state = (mr.meta.fields.state + 2) % 4
end
end
end
-----------------------------------------------
-- merge entry
-----------------------------------------------
function mapping.merge_map_entry(entry1, entry2)
if entry2 then
local ret_entry = table.copy(entry2)
for k,v in pairs(entry1) do
ret_entry[k] = v
end
return ret_entry
else
return table.copy(entry1)
end
end
-----------------------------------------------
-- is_equal_meta - compare meta information of 2 nodes
-- name - Node name to check and map
-- return - item name used as payment
-----------------------------------------------
function mapping.is_equal_meta(a,b)
local typa = type(a)
local typb = type(b)
if typa ~= typb then
return false
end
if typa == "table" then
if #a ~= #b then
return false
else
for i,v in ipairs(a) do
if not mapping.is_equal_meta(a[i],b[i]) then
return false
end
end
return true
end
else
if a == b then
return true
end
end
end
-----------------------------------------------
-- Fallback nodes replacement of unknown nodes
-----------------------------------------------
function mapping.map_unknown(name)
local map = unknown_nodes_data[name]
if not map or map.name == name or not minetest.registered_nodes[map.name] then
dprint("mapping failed:", name, dump(map))
print("unknown nodes in building", name)
return unknown_nodes_data["fallback"]
end
dprint("mapped", name, "to", map.name)
return mapping.merge_map_entry(map)
end
-----------------------------------------------
-- Take filters and actions on nodes before building
-----------------------------------------------
function mapping.map(name, plan)
-- get mapped registred node name for further mappings
local mr = {name = name}
local node_chk = minetest.registered_nodes[name]
--do fallback mapping if not registred node
if not node_chk then
mr = mapping.merge_map_entry(mapping.map_unknown(name), mr)
end
-- get default replacement
local map = default_replacements[name]
if map then
mr = mapping.merge_map_entry(map, mr)
end
if plan then
local plan_map = plan.data.replacements[name]
if plan_map then
mr = mapping.merge_map_entry(plan_map, mr)
end
end
--disabled by mapping
if mr.name == "" then
return
end
local node_def = minetest.registered_nodes[mr.name]
mr.node_def = node_def
if plan and plan.data.mirrored then
__mirror_doors(mr)
end
dprint("map", name, "to", mr.name, mr.param2)
return mr
end
function mapping.get_cost_item(node_name, plan)
-- get from mapping
local mapped = mapping.map(node_name, plan)
if mapped.cost_item then
return mapped.cost_item
end
-- Check if the node can be used byself
node_name = mapped.name or node_name
local node_def = minetest.registered_items[node_name]
if not node_def then
-- unknown node
return
end
if node_def.description and node_def.description ~= "" then
if node_def.groups.not_in_creative_inventory == 1 then
local recipe = minetest.get_craft_recipe(node_name)
if recipe and recipe.items then
-- node is crafteable, can be provided as cost item
return node_name
end
else
-- valid node, exists in creative inventory
return node_name
end
end
-- node cannot be used as cost item. Check for drops
local dropstack = minetest.get_node_drops(node_name)
if dropstack and dropstack[1] and dropstack[1] ~= "" then
return dropstack[1] -- use the first one
else
--something not supported, but known.
-- will be build for free. they are something like doors:hidden or second part of coffee lrfurn:coffeetable_back
return mapping.c_free_item
end
end
------------------------------------------
-- Cache some node content ID
------------------------------------------
mapping._protected_content_ids = {} -- this nodes detects other buildings
mapping._over_surface_content_ids = {} -- this nodes detects surface
mapping._volatile_contend_ids = {} -- this nodes will not be removed before placing new one
mapping._airlike_contend_ids = {} -- this nodes will not be removed if air should be placed
minetest.after(0, function()
for name, def in pairs(minetest.registered_nodes) do
-- protected nodes
if def.is_ground_content == false and not
(def.groups.leaves or def.groups.leafdecay or def.groups.tree) then
mapping._protected_content_ids[minetest.get_content_id(name)] = name
end
-- usual first node over surface
if def.walkable == false or def.drawtype == "airlike" or
def.groups.flora or def.groups.flower or
def.groups.leaves or def.groups.leafdecay
or def.groups.tree then
mapping._over_surface_content_ids[minetest.get_content_id(name)] = name
end
-- this nodes needs not to be removed before placing new one
if def.groups.liquid then
mapping._volatile_contend_ids[minetest.get_content_id(name)] = name
end
-- this nodes will not be removed if air should be placed
if def.liquidtype == "flowing" then
mapping._airlike_contend_ids[minetest.get_content_id(name)] = name
end
end
mapping._protected_content_ids[minetest.get_content_id("default:ice")] = nil --allow ice removal
mapping._over_surface_content_ids[minetest.get_content_id("air")] = "air"
mapping._over_surface_content_ids[minetest.get_content_id("default:snow")] = "default:snow"
mapping._over_surface_content_ids[minetest.get_content_id("default:snowblock")] = "default:snowblock"
mapping._volatile_contend_ids[minetest.get_content_id("air")] = "air"
mapping._volatile_contend_ids[minetest.get_content_id("default:snow")] = "default:snow"
mapping._airlike_contend_ids[minetest.get_content_id("air")] = "air"
mapping._airlike_contend_ids[minetest.get_content_id("default:snow")] = "default:snow"
end)
------------------------------------------
return mapping