init.lua 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. -- mod check
  2. local def = minetest.get_modpath("default")
  3. local mcl = minetest.get_modpath("mcl_core")
  4. -- global
  5. lucky_block = {
  6. mod_def = def,
  7. mod_mcl = mcl,
  8. snd_stone = def and default.node_sound_stone_defaults(),
  9. snd_wood = def and default.node_sound_wood_defaults(),
  10. snd_glass = def and default.node_sound_glass_defaults(),
  11. snd_pop = "default_hard_footstep",
  12. snd_pop2 = "default_place_node",
  13. def_item = "default:coal_lump",
  14. def_node = mcl and "mcl_core:dirt" or "default:dirt",
  15. def_flame = mcl and "mcl_fire:fire" or "fire:basic_flame",
  16. def_gold = mcl and "mcl_core:goldblock" or "default:goldblock",
  17. def_glass = mcl and "mcl_core:glass" or "default:glass",
  18. green = minetest.get_color_escape_sequence("#1eff00")
  19. }
  20. lucky_schems = {}
  21. -- quick sound setup
  22. if mcl then
  23. lucky_block.snd_glass = mcl_sounds.node_sound_glass_defaults()
  24. lucky_block.snd_wood = mcl_sounds.node_sound_wood_defaults()
  25. lucky_block.snd_stone = mcl_sounds.node_sound_stone_defaults()
  26. end
  27. -- translation support
  28. local S
  29. if minetest.get_translator ~= nil then
  30. S = minetest.get_translator("lucky_block") -- 5.x translation function
  31. else
  32. if minetest.get_modpath("intllib") then
  33. dofile(minetest.get_modpath("intllib") .. "/init.lua")
  34. if intllib.make_gettext_pair then
  35. gettext, ngettext = intllib.make_gettext_pair() -- new gettext method
  36. else
  37. gettext = intllib.Getter() -- old text file method
  38. end
  39. S = gettext
  40. else -- boilerplate function
  41. S = function(str, ...)
  42. local args = {...}
  43. return str:gsub("@%d+", function(match)
  44. return args[tonumber(match:sub(2))]
  45. end)
  46. end
  47. end
  48. end
  49. lucky_block.intllib = S
  50. -- default blocks
  51. local lucky_list = {
  52. {"nod", "lucky_block:super_lucky_block", 0}
  53. }
  54. -- ability to add new blocks to list
  55. function lucky_block:add_blocks(list)
  56. for s = 1, #list do
  57. table.insert(lucky_list, list[s])
  58. end
  59. end
  60. -- call to purge the block list
  61. function lucky_block:purge_block_list()
  62. lucky_list = {
  63. {"nod", "lucky_block:super_lucky_block", 0}
  64. }
  65. end
  66. -- add schematics to global list
  67. function lucky_block:add_schematics(list)
  68. for s = 1, #list do
  69. table.insert(lucky_schems, list[s])
  70. end
  71. end
  72. -- for random colour selection
  73. local all_colours = {
  74. "grey", "black", "red", "yellow", "green", "cyan", "blue", "magenta",
  75. "orange", "violet", "brown", "pink", "dark_grey", "dark_green", "white"
  76. }
  77. if lucky_block.mcl then
  78. all_colours = {
  79. "red", "blue", "cyan", "grey", "silver", "black", "yellow", "green", "magenta",
  80. "orange", "purple", "brown", "pink", "lime", "light_blue", "white"
  81. }
  82. end
  83. -- default chests items
  84. local chest_stuff = {}
  85. -- call to purge the chest item list
  86. function lucky_block:purge_chest_items()
  87. chest_stuff = {}
  88. end
  89. -- ability to add to chest item list
  90. function lucky_block:add_chest_items(list)
  91. for s = 1, #list do
  92. table.insert(chest_stuff, list[s])
  93. end
  94. end
  95. -- particle effects
  96. local effect = function(pos, amount, texture, min_size, max_size, radius, gravity, glow)
  97. radius = radius or 2
  98. gravity = gravity or -10
  99. minetest.add_particlespawner({
  100. amount = amount,
  101. time = 0.25,
  102. minpos = pos,
  103. maxpos = pos,
  104. minvel = {x = -radius, y = -radius, z = -radius},
  105. maxvel = {x = radius, y = radius, z = radius},
  106. minacc = {x = 0, y = gravity, z = 0},
  107. maxacc = {x = 0, y = gravity, z = 0},
  108. minexptime = 0.1,
  109. maxexptime = 1,
  110. minsize = min_size or 0.5,
  111. maxsize = max_size or 1.0,
  112. texture = texture,
  113. glow = glow
  114. })
  115. end
  116. -- temp entity for mob damage
  117. minetest.register_entity("lucky_block:temp", {
  118. physical = true,
  119. collisionbox = {0, 0, 0, 0, 0, 0},
  120. visual_size = {x = 0, y = 0},
  121. visual = "sprite",
  122. textures = {"tnt_smoke.png"},
  123. _is_arrow = true,
  124. on_step = function(self, dtime)
  125. self.timer = (self.timer or 0) + dtime
  126. if self.timer > 0.5 then
  127. self.object:remove()
  128. end
  129. end
  130. })
  131. -- modified from TNT mod to deal entity damage only
  132. local function entity_physics(pos, radius)
  133. radius = radius * 2
  134. local objs = minetest.get_objects_inside_radius(pos, radius)
  135. local obj_pos, dist
  136. -- add temp entity to cause damage
  137. local tmp_ent = minetest.add_entity(pos, "lucky_block:temp")
  138. for n = 1, #objs do
  139. obj_pos = objs[n]:get_pos()
  140. dist = vector.distance(pos, obj_pos)
  141. if dist < 1 then dist = 1 end
  142. local damage = math.floor((4 / dist) * radius)
  143. local ent = objs[n]:get_luaentity()
  144. objs[n]:punch(tmp_ent, 1.0, {
  145. full_punch_interval = 1.0,
  146. damage_groups = {fleshy = damage}
  147. }, pos)
  148. end
  149. end
  150. -- function to fill chest at position
  151. local function fill_chest(pos, items)
  152. local stacks = items or chest_stuff
  153. local meta = minetest.get_meta(pos)
  154. local inv = meta and meta:get_inventory()
  155. local size = inv and inv:get_size("main")
  156. local stack
  157. if not inv then return end
  158. -- loop through inventory
  159. for _, def in ipairs(stacks) do
  160. if math.random((def.chance or 1)) == 1 then
  161. -- only add if item existd
  162. if minetest.registered_items[def.name] then
  163. stack = ItemStack(def.name .. " " .. math.random((def.max or 1)))
  164. -- if wear levels found choose random wear between both values
  165. if def.max_wear and def.min_wear then
  166. stack:set_wear(65535 - (math.random(def.max_wear, def.min_wear)))
  167. end
  168. -- set stack in random position
  169. inv:set_stack("main", math.random(size), stack)
  170. end
  171. end
  172. end
  173. end
  174. -- explosion with protection check
  175. local function explode(pos, radius, sound)
  176. sound = sound or "tnt_explode"
  177. if minetest.get_modpath("tnt") and tnt and tnt.boom
  178. and not minetest.is_protected(pos, "") then
  179. tnt.boom(pos, {radius = radius, damage_radius = radius, sound = sound})
  180. else
  181. minetest.sound_play(sound, {pos = pos, gain = 1.0, max_hear_distance = 32}, true)
  182. entity_physics(pos, radius)
  183. effect(pos, 32, "tnt_smoke.png", radius * 3, radius * 5, radius, 1, 0)
  184. end
  185. end
  186. local lb_schematic = function(pos, digger, def)
  187. if #lucky_schems == 0 then
  188. print ("[lucky block] No schematics")
  189. return
  190. end
  191. local schem = def[2]
  192. local switch = def[3] or 0
  193. local force = def[4]
  194. local reps = def[5] or {}
  195. if switch == 1 then
  196. pos = vector.round(digger:get_pos())
  197. end
  198. for i = 1, #lucky_schems do
  199. if schem == lucky_schems[i][1] then
  200. local p1 = vector.subtract(pos, lucky_schems[i][3])
  201. minetest.place_schematic(p1, lucky_schems[i][2], "", reps, force)
  202. break
  203. end
  204. end
  205. if switch == 1 then
  206. digger:set_pos(pos, false)
  207. end
  208. end
  209. local lb_node = function(pos, digger, def)
  210. local nod = def[2]
  211. local switch = def[3]
  212. local items = def[4]
  213. if switch == 1 then
  214. pos = digger:get_pos()
  215. end
  216. if not minetest.registered_nodes[nod] then
  217. nod = lucky_block.def_node
  218. end
  219. effect(pos, 25, "tnt_smoke.png", 8, 8, 2, 1, 0)
  220. minetest.set_node(pos, {name = nod})
  221. if nod == "default:chest"
  222. or nod == "mcl_chests:chest_small" then
  223. fill_chest(pos, items)
  224. end
  225. end
  226. local lb_spawn = function(pos, digger, def)
  227. local pos2 = {}
  228. local num = def[3] or 1
  229. local tame = def[4]
  230. local own = def[5]
  231. local range = def[6] or 5
  232. local name = def[7]
  233. for i = 1, num do
  234. pos2.x = pos.x + math.random(-range, range)
  235. pos2.y = pos.y + 1
  236. pos2.z = pos.z + math.random(-range, range)
  237. local nod = minetest.get_node(pos2)
  238. local nodef = minetest.registered_nodes[nod.name]
  239. if nodef and nodef.walkable == false then
  240. local entity
  241. -- select between random or single entity
  242. if type(def[2]) == "table" then
  243. entity = def[2][math.random(#def[2])]
  244. else
  245. entity = def[2]
  246. end
  247. -- coloured sheep
  248. if entity == "mobs:sheep" then
  249. local colour = "_" .. all_colours[math.random(#all_colours)]
  250. entity = "mobs:sheep" .. colour
  251. end
  252. if entity == "mobs_animal:sheep" then
  253. local colour = "_" .. all_colours[math.random(#all_colours)]
  254. entity = "mobs_animal:sheep" .. colour
  255. end
  256. -- has entity been registered?
  257. if minetest.registered_entities[entity] then
  258. local obj = minetest.add_entity(pos2, entity)
  259. if obj then
  260. local ent = obj:get_luaentity()
  261. if tame then
  262. ent.tamed = true
  263. end
  264. if own then
  265. ent.owner = digger:get_player_name()
  266. end
  267. if name then
  268. ent.nametag = name
  269. ent.object:set_properties({
  270. nametag = name,
  271. nametag_color = "#FFFF00"
  272. })
  273. end
  274. else
  275. print ("[lucky_block] " .. entity .. " could not be spawned")
  276. end
  277. end
  278. end
  279. end
  280. end
  281. local lb_explode = function(pos, def)
  282. local rad = def[2] or 2
  283. local snd = def[3] or "tnt_explode"
  284. explode(pos, rad, snd)
  285. end
  286. local lb_teleport = function(pos, digger, def)
  287. local xz_range = def[2] or 10
  288. local y_range = def[3] or 5
  289. pos.x = pos.x + math.random(-xz_range, xz_range)
  290. pos.y = pos.y + math.random(-y_range, y_range)
  291. pos.z = pos.z + math.random(-xz_range, xz_range)
  292. effect(pos, 25, "tnt_smoke.png", 8, 8, 1, -10, 0)
  293. digger:set_pos(pos, false)
  294. effect(pos, 25, "tnt_smoke.png", 8, 8, 1, -10, 0)
  295. minetest.chat_send_player(digger:get_player_name(),
  296. lucky_block.green .. S("Random Teleport!"))
  297. end
  298. local lb_drop = function(pos, digger, def)
  299. local num = def[3] or 1
  300. local colours = def[4]
  301. local items = #def[2]
  302. -- drop multiple different items or colours
  303. if items > 1 or colours then
  304. for i = 1, num do
  305. local item = def[2][math.random(items)]
  306. if colours then
  307. item = item .. all_colours[math.random(#all_colours)]
  308. end
  309. if not minetest.registered_items[item] then
  310. item = lucky_block.def_item
  311. end
  312. local obj = minetest.add_item(pos, item)
  313. if obj then
  314. obj:set_velocity({
  315. x = math.random(-10, 10) / 9,
  316. y = 5,
  317. z = math.random(-10, 10) / 9
  318. })
  319. end
  320. end
  321. else -- drop single item in a stack
  322. local item = def[2][1]
  323. if not minetest.registered_items[item] then
  324. item = ItemStack(lucky_block.def_item .. " " .. tonumber(num))
  325. else
  326. item = ItemStack(item .. " " .. tonumber(num))
  327. end
  328. local obj = minetest.add_item(pos, item)
  329. if obj then
  330. obj:set_velocity({
  331. x = math.random(-10, 10) / 9,
  332. y = 5,
  333. z = math.random(-10, 10) / 9
  334. })
  335. end
  336. end
  337. end
  338. local lb_lightning = function(pos, digger, def)
  339. local nod = def[2]
  340. if not minetest.registered_nodes[nod] then
  341. nod = lucky_block.def_flame
  342. end
  343. pos = digger:get_pos()
  344. local bnod = minetest.get_node_or_nil(pos)
  345. local bref = bnod and minetest.registered_items[bnod.name]
  346. if bref and bref.buildable_to then
  347. minetest.set_node(pos, {name = nod})
  348. end
  349. minetest.add_particle({
  350. pos = pos,
  351. velocity = {x = 0, y = 0, z = 0},
  352. acceleration = {x = 0, y = 0, z = 0},
  353. expirationtime = 1.0,
  354. collisiondetection = false,
  355. texture = "lucky_lightning.png",
  356. size = math.random(100, 150),
  357. glow = 15
  358. })
  359. entity_physics(pos, 2)
  360. minetest.sound_play("lightning", {
  361. pos = pos, gain = 1.0, max_hear_distance = 25}, true)
  362. end
  363. local lb_falling = function(pos, digger, def)
  364. local nods = def[2]
  365. local switch = def[3]
  366. local spread = def[4]
  367. local range = def[5] or 5
  368. if switch == 1 then
  369. pos = digger:get_pos()
  370. end
  371. if spread then
  372. pos.y = pos.y + 10
  373. else
  374. pos.y = pos.y + #nods
  375. end
  376. minetest.remove_node(pos)
  377. local pos2 = {x = pos.x, y = pos.y, z = pos.z}
  378. for s = 1, #nods do
  379. minetest.after(0.5 * s, function()
  380. if spread then
  381. pos2.x = pos.x + math.random(-range, range)
  382. pos2.z = pos.z + math.random(-range, range)
  383. end
  384. local n = table.copy(minetest.registered_nodes[nods[s]])
  385. if n then
  386. local obj = minetest.add_entity(pos2, "__builtin:falling_node")
  387. if obj then
  388. local ent = obj:get_luaentity()
  389. if ent then
  390. n.param2 = 1 -- set default rotation
  391. ent:set_node(n)
  392. end
  393. end
  394. end
  395. end)
  396. end
  397. end
  398. local lb_troll = function(pos, def)
  399. local nod = def[2]
  400. local snd = def[3]
  401. local exp = def[4]
  402. if not minetest.registered_nodes[nod] then
  403. nod = lucky_block.def_gold
  404. end
  405. minetest.set_node(pos, {name = nod})
  406. if snd then
  407. minetest.sound_play(snd, {pos = pos, gain = 1.0, max_hear_distance = 10}, true)
  408. end
  409. minetest.after(2.0, function()
  410. if exp then
  411. minetest.set_node(pos, {name = "air"})
  412. explode(pos, 2)
  413. else
  414. minetest.set_node(pos, {name = "air"})
  415. minetest.sound_play(lucky_block.snd_pop, {
  416. pos = pos, gain = 1.0, max_hear_distance = 10}, true)
  417. end
  418. end)
  419. end
  420. local lb_floor = function(pos, def)
  421. local size = def[2] or 1
  422. local nods = def[3] or {lucky_block.def_node}
  423. local offs = def[4] or 0
  424. local num = 1
  425. for x = 0, size - 1 do
  426. for z = 0, size - 1 do
  427. minetest.after(0.5 * num, function()
  428. local nod = nods[math.random(#nods)]
  429. local def = minetest.registered_nodes[nod]
  430. local snd = def and def.sounds and def.sounds.place
  431. minetest.set_node({
  432. x = (pos.x + x) - offs,
  433. y = pos.y - 1,
  434. z = (pos.z + z) - offs}, {name = nod})
  435. minetest.sound_play(snd, {
  436. pos = pos, gain = 1.0, max_hear_distance = 10}, true)
  437. end)
  438. num = num + 1
  439. end
  440. end
  441. end
  442. -- this is what happens when you dig a lucky block
  443. function lucky_block:open(pos, digger, blocks_list)
  444. -- check for custom blocks list or use default
  445. blocks_list = blocks_list or lucky_list
  446. -- make sure it's really random
  447. math.randomseed(minetest.get_timeofday() + pos.x + pos.z - os.time())
  448. local luck = math.random(#blocks_list) ; -- luck = 1
  449. local result = blocks_list[luck]
  450. local action = result[1]
  451. -- print ("luck ["..luck.." of "..#blocks_list.."]", action)
  452. -- place schematic
  453. if action == "sch" then lb_schematic(pos, digger, result)
  454. -- place node (if chest then fill chest)
  455. elseif action == "nod" then lb_node(pos, digger, result)
  456. -- place entity
  457. elseif action == "spw" then lb_spawn(pos, digger, result)
  458. -- explosion
  459. elseif action == "exp" then lb_explode(pos, result)
  460. -- teleport
  461. elseif action == "tel" then lb_teleport(pos, digger, result)
  462. -- drop items
  463. elseif action == "dro" then lb_drop(pos, digger, result)
  464. -- lightning strike
  465. elseif action == "lig" then lb_lightning(pos, digger, result)
  466. -- falling nodes
  467. elseif action == "fal" then lb_falling(pos, digger, result)
  468. -- troll block, disappears or explodes after 2 seconds
  469. elseif action == "tro" then lb_troll(pos, result)
  470. -- floor paint
  471. elseif action == "flo" then lb_floor(pos, result)
  472. -- custom function
  473. elseif action == "cus" then
  474. if result[2] then result[2](pos, digger, result[3]) end
  475. end
  476. end
  477. -- lucky block itself
  478. minetest.register_node("lucky_block:lucky_block", {
  479. description = S("Lucky Block"),
  480. tiles = {{
  481. name = "lucky_block_animated.png",
  482. animation = {
  483. type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 1
  484. }
  485. }},
  486. inventory_image = minetest.inventorycube("lucky_block.png"),
  487. sunlight_propagates = false,
  488. is_ground_content = false,
  489. paramtype = "light",
  490. light_source = 3,
  491. groups = {handy = 2, oddly_breakable_by_hand = 3, unbreakable = 1},
  492. drop = {},
  493. sounds = lucky_block.snd_wood,
  494. on_dig = function(pos, node, digger)
  495. minetest.set_node(pos, {name = "air"})
  496. lucky_block:open(pos, digger)
  497. end,
  498. on_blast = function() end,
  499. _mcl_hardness = 1,
  500. _mcl_blast_resistance = 1200
  501. })
  502. local gitem = mcl and "mcl_core:gold_ingot" or "default:gold_ingot"
  503. local citem = mcl and "mcl_chests:chest" or "default:chest"
  504. minetest.register_craft({
  505. output = "lucky_block:lucky_block",
  506. recipe = {
  507. {gitem, gitem, gitem},
  508. {gitem, citem, gitem},
  509. {gitem, gitem, gitem}
  510. }
  511. })
  512. local grp = {cracky = 1, level = 2, unbreakable = 1}
  513. -- change super lucky block groups for mineclone
  514. if mcl then
  515. grp.handy = 5
  516. grp.level = nil
  517. end
  518. -- super lucky block
  519. minetest.register_node("lucky_block:super_lucky_block", {
  520. description = S("Super Lucky Block (use pick)"),
  521. tiles = {{
  522. name = "lucky_block_super_animated.png",
  523. animation = {
  524. type = "vertical_frames", aspect_w = 16, aspect_h = 16, length = 1
  525. }
  526. }},
  527. inventory_image = minetest.inventorycube("lucky_block_super.png"),
  528. sunlight_propagates = false,
  529. is_ground_content = false,
  530. paramtype = "light",
  531. groups = grp,
  532. drop = {},
  533. sounds = lucky_block.snd_stone,
  534. on_construct = function(pos)
  535. local meta = minetest.get_meta(pos)
  536. meta:set_string("infotext", "Super Lucky Block")
  537. end,
  538. on_dig = function(pos)
  539. if math.random(10) < 8 then
  540. minetest.set_node(pos, {name = "air"})
  541. effect(pos, 25, "tnt_smoke.png", 8, 8, 1, -10, 0)
  542. minetest.sound_play("fart1", {
  543. pos = pos, gain = 1.0, max_hear_distance = 10}, true)
  544. if math.random(5) == 1 then
  545. pos.y = pos.y + 0.5
  546. minetest.add_item(pos, lucky_block.def_gold .. " " .. math.random(5))
  547. end
  548. else
  549. minetest.set_node(pos, {name = "lucky_block:lucky_block"})
  550. end
  551. end,
  552. on_blast = function() end,
  553. _mcl_hardness = 8,
  554. _mcl_blast_resistance = 1200
  555. })
  556. local path = minetest.get_modpath("lucky_block")
  557. -- import schematics
  558. dofile(path .. "/lb_schems.lua")
  559. -- wishing well & drops
  560. dofile(path .. "/lb_well.lua")
  561. -- lucky block special items and blocks
  562. dofile(path .. "/lb_special.lua")
  563. -- if mineclone detected then load specific lucky blocks
  564. if mcl then
  565. dofile(path .. "/lb_mineclone.lua")
  566. else
  567. dofile(path .. "/lb_default.lua")
  568. end
  569. -- 3rd party mod lucky blocks
  570. dofile(path .. "/lb_other.lua")
  571. minetest.after(0, function()
  572. print("[MOD] Lucky Blocks loaded: ", #lucky_list)
  573. end)