summaryrefslogtreecommitdiff
path: root/boost_cart/functions.lua
blob: 86f8535a70709a2c1a44965b6d807fc5bdad7d4d (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
function boost_cart:get_sign(z)
	if z == 0 then
		return 0
	else
		return z / math.abs(z)
	end
end

function boost_cart:manage_attachment(player, obj)
	if not player then
		return
	end
	local status = obj ~= nil
	local player_name = player:get_player_name()
	if default.player_attached[player_name] == status then
		return
	end
	default.player_attached[player_name] = status

	if status then
		-- player_api came after the new model. Check for it. 
		local y_pos = player_api and -4.5 or 6
		player:set_attach(obj, "", {x=0, y=y_pos, z=0}, {x=0, y=0, z=0})
		player:set_eye_offset({x=0, y=-4, z=0},{x=0, y=-4, z=0})
	else
		player:set_detach()
		player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
	end
end

function boost_cart:velocity_to_dir(v)
	if math.abs(v.x) > math.abs(v.z) then
		return {x=boost_cart:get_sign(v.x), y=boost_cart:get_sign(v.y), z=0}
	else
		return {x=0, y=boost_cart:get_sign(v.y), z=boost_cart:get_sign(v.z)}
	end
end

function boost_cart:is_rail(pos, railtype)
	local node = minetest.get_node(pos).name
	if node == "ignore" then
		local vm = minetest.get_voxel_manip()
		local emin, emax = vm:read_from_map(pos, pos)
		local area = VoxelArea:new{
			MinEdge = emin,
			MaxEdge = emax,
		}
		local data = vm:get_data()
		local vi = area:indexp(pos)
		node = minetest.get_name_from_content_id(data[vi])
	end
	if minetest.get_item_group(node, "rail") == 0 then
		return false
	end
	if not railtype then
		return true
	end
	return minetest.get_item_group(node, "connect_to_raillike") == railtype
end

function boost_cart:check_front_up_down(pos, dir_, check_up, railtype)
	local dir = vector.new(dir_)
	local cur = nil

	-- Front
	dir.y = 0
	cur = vector.add(pos, dir)
	if boost_cart:is_rail(cur, railtype) then
		return dir
	end
	-- Up
	if check_up then
		dir.y = 1
		cur = vector.add(pos, dir)
		if boost_cart:is_rail(cur, railtype) then
			return dir
		end
	end
	-- Down
	dir.y = -1
	cur = vector.add(pos, dir)
	if boost_cart:is_rail(cur, railtype) then
		return dir
	end
	return nil
end

function boost_cart:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
	local pos = vector.round(pos_)
	local cur = nil
	local left_check, right_check = true, true

	-- Check left and right
	local left = {x=0, y=0, z=0}
	local right = {x=0, y=0, z=0}
	if dir.z ~= 0 and dir.x == 0 then
		left.x = -dir.z
		right.x = dir.z
	elseif dir.x ~= 0 and dir.z == 0 then
		left.z = dir.x
		right.z = -dir.x
	end

	if ctrl then
		if old_switch == 1 then
			left_check = false
		elseif old_switch == 2 then
			right_check = false
		end
		if ctrl.left and left_check then
			cur = boost_cart:check_front_up_down(pos, left, false, railtype)
			if cur then
				return cur, 1
			end
			left_check = false
		end
		if ctrl.right and right_check then
			cur = boost_cart:check_front_up_down(pos, right, false, railtype)
			if cur then
				return cur, 2
			end
			right_check = true
		end
	end

	-- Normal
	cur = boost_cart:check_front_up_down(pos, dir, true, railtype)
	if cur then
		return cur
	end

	-- Left, if not already checked
	if left_check then
		cur = boost_cart:check_front_up_down(pos, left, false, railtype)
		if cur then
			return cur
		end
	end

	-- Right, if not already checked
	if right_check then
		cur = boost_cart:check_front_up_down(pos, right, false, railtype)
		if cur then
			return cur
		end
	end

	-- Backwards
	if not old_switch then
		cur = boost_cart:check_front_up_down(pos, {
				x = -dir.x,
				y = dir.y,
				z = -dir.z
			}, true, railtype)
		if cur then
			return cur
		end
	end

	return {x=0, y=0, z=0}
end

function boost_cart:pathfinder(pos_, old_pos, old_dir, ctrl, pf_switch, railtype)
	if vector.equals(old_pos, pos_) then
		return true
	end

	local pos = vector.round(pos_)
	local pf_pos = vector.round(old_pos)
	local pf_dir = vector.new(old_dir)

	for i = 1, 3 do
		pf_dir, pf_switch = boost_cart:get_rail_direction(
			pf_pos, pf_dir, ctrl, pf_switch, railtype)

		if vector.equals(pf_dir, {x=0, y=0, z=0}) then
			-- No way forwards
			return false
		end

		pf_pos = vector.add(pf_pos, pf_dir)

		if vector.equals(pf_pos, pos) then
			-- Success! Cart moved on correctly
			return true
		end
	end
	-- Cart not found
	return false
end

function boost_cart:boost_rail(pos, amount)
	minetest.get_meta(pos):set_string("cart_acceleration", tostring(amount))
	for _,obj_ in ipairs(minetest.get_objects_inside_radius(pos, 0.5)) do
		if not obj_:is_player() and
				obj_:get_luaentity() and
				obj_:get_luaentity().name == "carts:cart" then
			obj_:get_luaentity():on_punch()
		end
	end
end

function boost_cart:register_rail(name, def_overwrite)
	local def = {
		drawtype = "raillike",
		paramtype = "light",
		sunlight_propagates = true,
		is_ground_content = false,
		walkable = false,
		selection_box = {
			type = "fixed",
			fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
		}
	}
	for k, v in pairs(def_overwrite) do
		def[k] = v
	end
	if not def.inventory_image then
		def.wield_image = def.tiles[1]
		def.inventory_image = def.tiles[1]
	end

	minetest.register_node(name, def)
end

function boost_cart:get_rail_groups(additional_groups)
	-- Get the default rail groups and add more when a table is given
	local groups = {
		dig_immediate = 2,
		attached_node = 1,
		rail = 1,
		connect_to_raillike = 1
	}
	if minetest.raillike_group then
		groups.connect_to_raillike = minetest.raillike_group("rail")
	end
	if type(additional_groups) == "table" then
		for k, v in pairs(additional_groups) do
			groups[k] = v
		end
	end
	return groups
end