aboutsummaryrefslogtreecommitdiff
path: root/init.lua
blob: 06696774ae9cc3cce91b997f08bb71dc97f20897 (plain)
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
local storage = minetest.get_mod_storage()
local pos1, pos2
local min, max = math.min, math.max
local building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks, last_good_block
local autodupe = rawget(_G, "autodupe")
local autoeat = rawget(_G, "autoeat")

minetest.register_chatcommand("pos1", {
	description = "Set schematicas position 1 at your current location",
	func = function()
		pos1 = vector.round(minetest.localplayer:get_pos())
		return true, "Position 1 set to " .. minetest.pos_to_string(pos1)
	end
})

minetest.register_chatcommand("pos2", {
	description = "Set schematicas position 2 at your current location",
	func = function()
		pos2 = vector.round(minetest.localplayer:get_pos())
		return true, "Position 2 set to " .. minetest.pos_to_string(pos2)
	end
})


minetest.register_chatcommand("schemesave", {
	description = "Save a schematica",
	param = "<name>",
	func = function(name)
		if not pos1 or not pos2 then
			return false, "Position 1 or 2 not set."
		end

		local data = {}

		local lx, ly, lz, hx, hy, hz = min(pos1.x, pos2.x), min(pos1.y, pos2.y), min(pos1.z, pos2.z), max(pos1.x, pos2.x), max(pos1.y, pos2.y), max(pos1.z, pos2.z)

		for x = lx, hx do
			local rx = x - lx
			for y = ly, hy do
				local ry = y - ly
				for z = lz, hz do
					local rz = z - lz
					local node = minetest.get_node_or_nil({x = x, y = y, z = z})
					if node and node.name ~= "air" then
						table.insert(data, {pos = {x = rx, y = ry, z = rz}, node = node.name})
					end
				end
			end
		end

		storage:set_string(name, minetest.serialize(data))
		return true, "Scheme saved successfully as '" .. name .. "'."
	end
})

minetest.register_chatcommand("schemebuild", {
	description = "Build a schematica",
	param = "<name>",
	func = function(name)
		if not pos1 then
			return false, "Position 1 not set."
		end
		if building then
			return false, "Still building a scheme. Use .schemeabort to stop it."
		end
		local rawdata = storage:get(name)
		if not rawdata then
			return false, "Schematica '" .. name .. "' not found."
		end
		building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks  = true, 1, minetest.deserialize(rawdata), vector.new(pos1), false, 0, false
	end
})

minetest.register_chatcommand("schemerecipe", {
	description = "Print the recipe for a schematica",
	param = "<name>",
	func = function(name)
		local rawdata = storage:get(name)
		if not rawdata then
			return false, "Schematica '" .. name .. "' not found."
		end
		local data = minetest.deserialize(rawdata)
		local sorted = {}
		for _, d in ipairs(data) do
		end
	end
})

minetest.register_chatcommand("schemeresume", {
	description = "Resume constructing a schematica",
	func = function()
		if not build_data then
			return false, "Currently not building a scheme."
		end
		building, out_of_blocks = true, false
		return true, "Resumed."
	end
})

minetest.register_chatcommand("schemepause", {
	description = "Pause constructing a schematica",
	func = function()
		if not build_data then
			return false, "Currently not building a scheme."
		end
		building = false
		return true, "Paused."
	end
})

minetest.register_chatcommand("schemeabort", {
	description = "Abort constructing a schematica",
	param = "<name>",
	func = function()
		if not build_data then
			return false, "Currently not building a scheme."
		end
		building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nilw
		return true, "Aborted."
	end
})

minetest.register_chatcommand("schemeskip", {
	description = "Skip a step in constructing a schematica",
	param = "<name>",
	func = function()
		if not build_data then
			return false, "Currently not building a scheme."
		end
		building, build_index = true, build_index + 1
		return true, "Skipped."
	end
})

minetest.register_chatcommand("schemegetindex", {
	description = "Output the build index of the schematica",
	func = function()
		return build_index and true or false, build_index
	end
})

minetest.register_chatcommand("schemesetindex", {
	description = "Set the build index of the schematica",
	param = "<index>",
	func = function(param)
		local index = tonumber(param)
		if not index then return false, "Invalid usage." end
		build_index = index
		last_good_block = index
		return true, "Index Changed"
	end
})

local function step(stack)
	if building then
		local data = build_data[build_index]
		if not data then
			building, build_index, build_data, build_pos, just_placed_node, failed_count, out_of_blocks = nil
			minetest.display_chat_message("Completed Schematica.")
			return
		end
		if autoeat and autoeat.lock then
			return
		end
		local player = minetest.localplayer
		local pos, node = vector.add(build_pos, data.pos), data.node
		local free_pos = minetest.find_node_near(pos, 4, {"air"}, false)
		local player_pos = vector.subtract(free_pos or pos, vector.new(0, 1.5, 0))
		local map_node = minetest.get_node_or_nil(pos)
		if not map_node then
			player:set_pos(player_pos)
			minetest.interact("start_digging", {type = "node", under = pos, above = pos})
			minetest.interact("stop_digging", {type = "node", under = pos, above = pos})
			return
		end
		local map_node_name = map_node.name
		local is_good = map_node_name == node
		if not is_good then
			local def = minetest.get_node_def(map_node_name)
			if not def or not def.buildable_to then
				player:set_pos(player_pos)
				autotool.select_best_tool(map_node_name)
				minetest.dig_node(pos)
				return
			end
		end
		if just_placed_node then
			just_placed_node = false
			if is_good or build_index % 50 == 0 then
				local lgb = last_good_block or 0
				if lgb < build_index - 1 then
					build_index = lgb + 1
				else
					if is_good then
						if build_index % 500 == 0 then
							minetest.send_chat_message("[Schematicas] " .. build_index .. " of " .. #build_data .. " blocks placed")
						end
						last_good_block = build_index
						build_index = build_index + 1
						just_placed_node = true
						if stack < 1000 then
							step(stack + 1)
						end
					end
				end
				return
			else
				failed_count = failed_count + 1
			end
			if reliable and failed_count < 10 then
				return
			end
			if not reliable and not map_node then
				return
			end
			build_index = build_index + 1
		end
		failed_count = 0
		local new_index
		local item_count = 0
		local item_name
		local inventory = minetest.get_inventory("current_player").main
		for index, stack in ipairs(inventory) do
			local stackname = stack:get_name()
			if minetest.get_item_def(stackname).node_placement_prediction == node then
				new_index = new_index or index
				item_name = item_name or stackname
				item_count = item_count + 1
				if item_count > 1 then
					break
				end
			end
		end
		if item_count <= 1 then
			if not out_of_blocks then
				minetest.display_chat_message("Out of blocks for schematica. Missing ressource: '" .. node .. "' (You need at least two stacks of it). It will resume as soon as you got it or use .schemeskip to skip it.")
			end
			if autodupe and item_name then
				autodupe.needed(new_index)
			end
			out_of_blocks = true
			return
		end
		local was_out_of_blocks = out_of_blocks
		out_of_blocks = out_of_blocks and autodupe and not autodupe.cleanup()
		if out_of_blocks then
			return
		end
		if was_out_of_blocks and not out_of_blocks then
			minetest.display_chat_message("Resuming.")
		end
		out_of_blocks = false
		player:set_wield_index(new_index)
		player:set_pos(player_pos)
		minetest.place_node(pos)
		just_placed_node = true
	end
end

minetest.register_globalstep(function()
	step(0)
end)