ore_carts.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. carts:register_rail("mining:dump_rail", {
  2. description = "Rail",
  3. tiles = {
  4. "carts_rail_straight.png^[colorize:blue:80", "carts_rail_curved.png^[colorize:blue:80",
  5. "carts_rail_t_junction.png^[colorize:blue:80", "carts_rail_crossing.png^[colorize:blue:80"
  6. },
  7. inventory_image = "carts_rail_straight.png",
  8. wield_image = "carts_rail_straight.png",
  9. groups = {
  10. choppy = 2,
  11. rail = 1,
  12. connect_to_raillike = minetest.raillike_group("rail")
  13. },
  14. }, {})
  15. minetest.register_craft({
  16. output = "mining:dump_rail 3",
  17. recipe = {
  18. {"default:steel_ingot", "group:wood", "default:steel_ingot"},
  19. {"default:steel_ingot", "default:copper_ingot", "default:steel_ingot"},
  20. {"default:steel_ingot", "group:wood", "default:steel_ingot"},
  21. }
  22. })
  23. local function is_rail(name)
  24. local d = minetest.registered_nodes[name]
  25. return (d and d.groups.rail ~= nil)
  26. end
  27. local function lift_above(pos)
  28. local n = minetest.get_node({x=pos.x, y=pos.y+1, z=pos.z})
  29. return n and n.name == "mining:cart_lift"
  30. end
  31. local function printl(str, v)
  32. print(str .. " ["..v.x..", "..v.y..", "..v.z.."]")
  33. end
  34. local node_speeds = {
  35. ["carts:rail"] = 2,
  36. ["mining:cart_lift"] = .5,
  37. ["default"] = 2,
  38. }
  39. local function get_node_speed(name)
  40. return node_speeds[name] or node_speeds.default
  41. end
  42. local function find_new_direction(cart, data, pos, rpos)
  43. local npos = vector.add(pos, data.direction)
  44. print("no direction")
  45. local n
  46. n = minetest.get_node({x=rpos.x + 1, y=rpos.y, z=rpos.z})
  47. if is_rail(n.name) then
  48. return {x=1, y=0, z=0}, "moving"
  49. else
  50. n = minetest.get_node({x=rpos.x - 1, y=rpos.y, z=rpos.z})
  51. if is_rail(n.name) then
  52. return {x=-1, y=0, z=0}, "moving"
  53. else
  54. n = minetest.get_node({x=rpos.x, y=rpos.y, z=rpos.z + 1})
  55. if is_rail(n.name) then
  56. return {x=0, y=0, z=1}, "moving"
  57. else
  58. n = minetest.get_node({x=rpos.x, y=rpos.y, z=rpos.z-1})
  59. if is_rail(n.name) then
  60. return {x=0, y=0, z=-1}, "moving"
  61. else
  62. print("checking below")
  63. --below
  64. local below = vector.add(nextp, {x=0, y=-1, z=0})
  65. local bn = minetest.get_node(below)
  66. local cross = vector.normalize({x=self.direction.z, y=0, z= -self.direction.x})
  67. local bleft = vector.add(vector.add(rpos, cross), {x=0, y=-1, z=0})
  68. local bright = vector.add(vector.subtract(rpos, cross), {x=0, y=-1, z=0})
  69. local bln = minetest.get_node(bleft)
  70. local brn = minetest.get_node(bright)
  71. print("belowleft: "..bln.name)
  72. print("belowright: "..brn.name)
  73. if is_rail(bn.name) then
  74. print("angle down")
  75. local dir = vector.normalize(vector.add(self.direction, {x=0, y=-1, z=0}))
  76. return dir, "moving"
  77. elseif is_rail(bln.name) then
  78. local dir = vector.normalize(vector.add(cross, {x=0, y=-1, z=0}))
  79. return dir, "moving"
  80. elseif is_rail(brn.name) then
  81. local dir = vector.normalize(vector.add(vector.multiply(cross, -1), {x=0, y=-1, z=0}))
  82. return dir, "moving"
  83. else
  84. -- check for lifting
  85. local apos = vector.add(pos, {x=0,y=1,z=0})
  86. local anode = minetest.get_node(apos)
  87. if anode.name == "mining:cart:lift" then
  88. return {x=0,y=1,z=0}, "moving"
  89. end
  90. print("isolated cart")
  91. return nil, "stop"
  92. end
  93. end
  94. end
  95. end
  96. end
  97. end
  98. local operations = {
  99. ["carts:rail"] = function(cart, data, pos, rpos)
  100. -- see if we can just keep going
  101. local npos = vector.add(pos, data.direction)
  102. local node = minetest.get_node(npos)
  103. if is_rail(node.name) then
  104. -- good, keep going
  105. return
  106. end
  107. local dir, state = find_new_direction(cart, data, pos, rpos)
  108. data.direction = dir
  109. data.state = state
  110. data.speed = get_node_speed(node.name)
  111. if state == "moving" then
  112. self.object:setvelocity(vector.multiply(dir, data.speed))
  113. -- TODO: fix positions not in direction of travel
  114. end
  115. end,
  116. ["mining:cart_lift"] = function(cart, data, pos, rpos) -- go up, then go out
  117. local upos = vector.add(pos, {x=0,y=1,z=0})
  118. local unode = minetest.get_node(upos)
  119. if unode.name == "mining:cart_lift" then
  120. -- keep going up
  121. return
  122. end
  123. -- look for new direction
  124. local dir, state = find_new_direction(cart, data, pos, rpos)
  125. data.direction = dir
  126. data.state = state
  127. data.speed = get_node_speed(node.name)
  128. if state == "moving" then
  129. self.object:setvelocity(vector.multiply(dir, data.speed))
  130. -- TODO: fix positions not in direction of travel
  131. end
  132. end,
  133. ["mining:rail_switch"] = function(cart, data, pos, rpos) -- internal switching state
  134. end,
  135. ["mining:rail_multiplexer"] = function(cart, data, pos, rpos) -- alternate exits
  136. end,
  137. ["mining:dump_rail"] = function(cart, data, pos, rpos) -- alternate exits
  138. if #data.contents == 0 then
  139. return
  140. end
  141. if not vector.equals(rpos, data.last_dump_pos) then
  142. local below = vector.subtract(rpos, {x=0,y=1,z=0})
  143. local bn = minetest.get_node(below)
  144. if bn.name == "air" then
  145. local c = table.remove(data.contents)
  146. minetest.set_node(below, {name = c})
  147. minetest.spawn_falling_node(below)
  148. cart.object:set_animation({x = 1, y = 15}, 10, 0, false)
  149. data.last_dump_pos = rpos
  150. end
  151. end
  152. end,
  153. ["carts:brake_rail"] = function(cart, data, pos, rpos) -- pause until restarted
  154. data.state = "paused"
  155. cart.object:setvelocity({x=0,y=0,z=0})
  156. cart.object:setpos(rpos)
  157. return data.direction, "paused"
  158. end,
  159. ["default"] = function() -- unknown node underneath
  160. end,
  161. }
  162. -- obsolete
  163. local function check_new_direction(self, rpos)
  164. if self.direction == nil or self.direction.x == nil then
  165. print("no direction")
  166. local n
  167. n = minetest.get_node({x=rpos.x + 1, y=rpos.y, z=rpos.z})
  168. if is_rail(n.name) then
  169. self.direction = {x=1, y=0, z=0}
  170. else
  171. n = minetest.get_node({x=rpos.x - 1, y=rpos.y, z=rpos.z})
  172. if is_rail(n.name) then
  173. self.direction = {x=-1, y=0, z=0}
  174. else
  175. n = minetest.get_node({x=rpos.x, y=rpos.y, z=rpos.z + 1})
  176. if is_rail(n.name) then
  177. self.direction = {x=0, y=0, z=1}
  178. else
  179. n = minetest.get_node({x=rpos.x, y=rpos.y, z=rpos.z-1})
  180. if is_rail(n.name) then
  181. self.direction = {x=0, y=0, z=-1}
  182. else
  183. print("isolated cart")
  184. return
  185. end
  186. end
  187. end
  188. end
  189. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  190. self.last_pos = rpos
  191. end
  192. end
  193. -- for debugging
  194. local counter = 0
  195. local function stepfn(self, dtime)
  196. local pos = self.object:getpos()
  197. local data = self.data
  198. if data == nil then
  199. return
  200. end
  201. local d = vector.distance(data.last_pos, pos)
  202. local rpos = vector.round(pos)
  203. if d > 1.0 then
  204. -- crossed block lines
  205. local posnode = minetest.get_node(pos)
  206. local fn = operations[posnode.name] or operations.default
  207. fn(self, data, pos, rpos)
  208. end
  209. if 1==1 then return end
  210. --- old algorithm
  211. --print(" ---- ")
  212. if self.speed == nil then
  213. self.speed = 2
  214. end
  215. local pos = self.object:getpos()
  216. local rpos = vector.round(pos)
  217. -- printl("pos", pos)
  218. -- printl("rpos", rpos)
  219. check_new_direction(self, rpos)
  220. local d = vector.distance(self.last_pos, pos)
  221. if self.state == "lifting" then
  222. self.speed = .5
  223. elseif self.state ~= "stop" then
  224. self.speed = 2
  225. end
  226. if d < 1.0 then
  227. if self.state ~= "stop" then
  228. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  229. end
  230. -- TODO: timer to occasionally fix y-height
  231. return
  232. end
  233. self.last_pos = rpos
  234. -- print("crossed")
  235. --self.object:setvelocity({x=0, y=0, z=0})
  236. --if counter == 1 then return end
  237. --counter = 1
  238. --local ceiln = minetest.get_node({x=math.ceil(pos.x), y=pos.y, z=math.ceil(pos.z)})
  239. --local floorn = minetest.get_node({x=math.floor(pos.x), y=pos.y, z=math.floor(pos.z)})
  240. local cross = vector.normalize({x=self.direction.z, y=0, z= -self.direction.x})
  241. local hdir = vector.multiply(self.direction, .5)
  242. -- check for dumping contents
  243. if #self.contents > 0 then
  244. local rpos = vector.round(pos)
  245. if not vector.equals(rpos, self.last_dump_pos) then
  246. local posnode = minetest.get_node(pos)
  247. if posnode.name == "mining:dump_rail" then
  248. local below = vector.subtract(pos, {x=0,y=1,z=0})
  249. local bn = minetest.get_node(below)
  250. if bn.name == "air" then
  251. local c = table.remove(self.contents)
  252. minetest.set_node(below, {name = c})
  253. minetest.spawn_falling_node(below)
  254. self.object:set_animation({x = 1, y = 15}, 10, 0, false)
  255. self.last_dump_pos = rpos
  256. end
  257. end
  258. end
  259. end
  260. local nextp = vector.round(
  261. vector.add(pos,
  262. vector.multiply(
  263. -- vector.normalize({x=self.direction.x, y=0, z=self.direction.z}),
  264. self.direction,
  265. 1.0)
  266. )
  267. )
  268. local pn = minetest.get_node(nextp)
  269. if is_rail(pn.name) then
  270. -- print("straight")
  271. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  272. -- fix sideways errors
  273. if self.direction.x == 0 then
  274. pos.x = math.floor(pos.x+0.5)
  275. end
  276. if self.direction.z == 0 then
  277. pos.z = math.floor(pos.z+0.5)
  278. end
  279. self.object:setpos(pos)
  280. self.state = "straight"
  281. elseif self.state == "lifting" then
  282. if lift_above(rpos) then
  283. -- keep lifting
  284. print("still lifting")
  285. else
  286. print("looking for new direction at end of lift")
  287. self.direction = nil
  288. check_new_direction(self, rpos)
  289. end
  290. else
  291. -- print("checking sides")
  292. -- check sides
  293. -- printl("pos", pos)
  294. local left = vector.add(pos, cross)
  295. local right = vector.subtract(pos, cross)
  296. -- printl("left", left )
  297. -- printl("right", right )
  298. local ln = minetest.get_node(left)
  299. local rn = minetest.get_node(right)
  300. -- print("ln "..ln.name)
  301. -- print("rn "..rn.name)
  302. --front
  303. local front = vector.add(rpos, vector.normalize({x=self.direction.x, y=0, z=self.direction.z}))
  304. local fn = minetest.get_node(front)
  305. --self.state = "turning"
  306. if ln.name == rn.name and is_rail(ln.name) then
  307. if math.random(0, 1) == 1 then
  308. self.direction = cross
  309. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  310. else
  311. self.direction = vector.multiply(cross, -1)
  312. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  313. end
  314. self.object:setpos(rpos)
  315. print("random")
  316. elseif is_rail(ln.name) then
  317. self.object:setpos(rpos)
  318. self.direction = cross
  319. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  320. print("left")
  321. elseif is_rail(rn.name) then
  322. self.object:setpos(rpos)
  323. self.direction = vector.multiply(cross, -1)
  324. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  325. print("right")
  326. elseif is_rail(fn.name) then
  327. self.object:setpos(rpos)
  328. self.direction = vector.normalize({x=self.direction.x, y=0, z=self.direction.z})
  329. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  330. elseif lift_above(rpos) then
  331. self.object:setpos(rpos)
  332. self.direction = {x=0, y=1, z=0}
  333. self.speed = .5
  334. self.object:setvelocity(vector.multiply({x=0, y=1, z=0}, self.speed))
  335. self.state = "lifting"
  336. print("lifting")
  337. else
  338. print("checking below")
  339. --below
  340. local below = vector.add(nextp, {x=0, y=-1, z=0})
  341. local bn = minetest.get_node(below)
  342. local bleft = vector.add(vector.add(rpos, cross), {x=0, y=-1, z=0})
  343. local bright = vector.add(vector.subtract(rpos, cross), {x=0, y=-1, z=0})
  344. local bln = minetest.get_node(bleft)
  345. local brn = minetest.get_node(bright)
  346. print("belowleft: "..bln.name)
  347. print("belowright: "..brn.name)
  348. if is_rail(bn.name) then
  349. print("angle down")
  350. local dir = vector.normalize(vector.add(self.direction, {x=0, y=-1, z=0}))
  351. self.direction = dir
  352. printl("dir", dir)
  353. self.object:setvelocity(vector.multiply(dir, self.speed))
  354. elseif is_rail(bln.name) then
  355. self.object:setpos(rpos)
  356. local dir = vector.normalize(
  357. vector.add(cross, {x=0, y=-1, z=0}))
  358. self.direction = dir
  359. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  360. print("down left")
  361. elseif is_rail(brn.name) then
  362. self.object:setpos(rpos)
  363. local dir = vector.normalize(
  364. vector.add(vector.multiply(cross, -1),
  365. {x=0, y=-1, z=0}))
  366. self.object:setvelocity(vector.multiply(self.direction, self.speed))
  367. print("down right")
  368. else
  369. --stop
  370. self.object:setpos(pos)
  371. self.object:setvelocity({x=0, y=0, z=0})
  372. print("stop")
  373. self.state = "stop"
  374. end
  375. end
  376. end
  377. end
  378. local ore_cart_defaults = {
  379. contents = {},
  380. direction = {},
  381. last_dump_pos = {x=999999, y=999999, z=999999},
  382. last_pos = {x=999999, y=999999, z=999999},
  383. state = "straight",
  384. }
  385. local ore_cart_entity = {
  386. hp_max = 2,
  387. visual = "mesh",
  388. mesh = "mining_cart.x",
  389. visual_size = {x=1, y=1},
  390. collisionbox = {-0.45, -0.5, -0.45, 0.45, 0.4, 0.45},
  391. physical = true,
  392. textures = {"mining_cart.png", "mining_cart.png"},
  393. on_step = function(self, dtime)
  394. return stepfn(self, dtime)
  395. end,
  396. on_punch = function(self, puncher)
  397. local look = vector.round(puncher:get_look_dir())
  398. self.direction = look
  399. end,
  400. get_staticdata = function(self)
  401. local temp = {}
  402. for k,_ in pairs(ore_cart_defaults) do
  403. temp[k] = self[k]
  404. end
  405. print(dump2(temp))
  406. return minetest.serialize(temp)
  407. end,
  408. on_activate = function(self, staticdata)
  409. -- self.object:set_armor_groups({immortal = 1})
  410. print(dump2(staticdata))
  411. if staticdata then
  412. local temp = minetest.deserialize(staticdata)
  413. print(dump2(temp))
  414. if temp ~= nil then
  415. for k,v in pairs(temp) do
  416. if v ~= nil then
  417. self[k] = v
  418. end
  419. end
  420. end
  421. end
  422. end,
  423. push = function(self)
  424. print("ore cart push called")
  425. end,
  426. }
  427. for k,v in pairs(ore_cart_defaults) do
  428. ore_cart_entity[k] = v
  429. end
  430. minetest.register_entity("mining:ore_cart", ore_cart_entity)
  431. minetest.register_craftitem("mining:ore_cart", {
  432. description = "Ore Cart",
  433. inventory_image = "default_sand.png^[colorize:green:80",
  434. -- wield_image = "boats_tin_wield.png",
  435. wield_scale = {x = 1, y = 1, z = 1},
  436. groups = {},
  437. stack_max = 1,
  438. on_place = function(itemstack, placer, pointed_thing)
  439. local under = pointed_thing.under
  440. local node = minetest.get_node(under)
  441. local udef = minetest.registered_nodes[node.name]
  442. if udef.name ~= "carts:rail" then
  443. return
  444. end
  445. if pointed_thing.type ~= "node" then
  446. return itemstack
  447. end
  448. pointed_thing.under.y = pointed_thing.under.y
  449. local cart = minetest.add_entity(pointed_thing.under, "mining:ore_cart")
  450. if cart then
  451. local player_name = placer and placer:get_player_name() or ""
  452. if not (creative and creative.is_enabled_for and
  453. creative.is_enabled_for(player_name)) then
  454. itemstack:take_item()
  455. end
  456. end
  457. return itemstack
  458. end,
  459. })
  460. minetest.register_craft({
  461. output = "mining:ore_cart",
  462. recipe = {
  463. {'', '', '', },
  464. {'group:wood', 'default:cobble', 'group:wood', },
  465. {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot', },
  466. },
  467. })
  468. minetest.register_node("mining:cart_lift", {
  469. description = "Cart Lift",
  470. tiles = { "default_bronze_block.png" },
  471. is_ground_content = true,
  472. groups = {cracky=1, level=3 },
  473. sounds = default.node_sound_stone_defaults(),
  474. paramtype = "light",
  475. drawtype = "nodebox",
  476. node_box = {
  477. type = "fixed",
  478. fixed = {
  479. {-0.55, -0.5, -0.55, -0.51, 0.5, -0.51},
  480. {-0.55, -0.5, 0.55, -0.51, 0.5, 0.51},
  481. { 0.55, -0.5, -0.55, 0.51, 0.5, -0.51},
  482. { 0.55, -0.5, 0.55, 0.51, 0.5, 0.51},
  483. },
  484. -- fixed = {
  485. -- {-0.5, -0.5, -0.5, -0.45, 0.5, -0.45},
  486. -- {-0.5, -0.5, 0.5, -0.45, 0.5, 0.45},
  487. -- { 0.5, -0.5, -0.5, 0.45, 0.5, -0.45},
  488. -- { 0.5, -0.5, 0.5, 0.45, 0.5, 0.45},
  489. -- },
  490. },
  491. selection_box = {
  492. type = "fixed",
  493. fixed = {
  494. {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
  495. },
  496. },
  497. })
  498. minetest.register_craft({
  499. output = "mining:cart_lift",
  500. recipe = {
  501. {'default:bronze_ingot', '', 'default:bronze_ingot' },
  502. {'', 'mining:ore_cart', ''},
  503. {'default:bronze_ingot', '', 'default:bronze_ingot' },
  504. },
  505. })