init.lua 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. -- "Dungeon Loot" [dungeon_loot]
  2. -- Copyright (c) 2015 BlockMen <blockmen2015@gmail.com>
  3. --
  4. -- init.lua
  5. --
  6. -- This software is provided 'as-is', without any express or implied warranty. In no
  7. -- event will the authors be held liable for any damages arising from the use of
  8. -- this software.
  9. --
  10. -- Permission is granted to anyone to use this software for any purpose, including
  11. -- commercial applications, and to alter it and redistribute it freely, subject to the
  12. -- following restrictions:
  13. --
  14. -- 1. The origin of this software must not be misrepresented; you must not
  15. -- claim that you wrote the original software. If you use this software in a
  16. -- product, an acknowledgment in the product documentation is required.
  17. -- 2. Altered source versions must be plainly marked as such, and must not
  18. -- be misrepresented as being the original software.
  19. -- 3. This notice may not be removed or altered from any source distribution.
  20. --
  21. -- Following Code (everything before fill_chest) by Amoeba <amoeba@iki.fi>
  22. dungeon_loot = {}
  23. dungeon_loot.version = 1.2
  24. -- Localize for performance.
  25. local math_random = math.random
  26. -- Load other file(s)
  27. local modpath = minetest.get_modpath(minetest.get_current_modname())
  28. dofile(modpath.."/config.lua") -- All the constants for simple tuning
  29. local function get_max_loot(loot_list, depth)
  30. local loot_type = loot_list[1].name
  31. local loot_min_depth = loot_list[1].min_depth
  32. for i,v in ipairs(loot_list) do
  33. if v.min_depth < depth then
  34. loot_type = v.name
  35. loot_min_depth = v.min_depth
  36. else
  37. break
  38. end
  39. end
  40. return loot_type, loot_min_depth
  41. end
  42. local function get_basic_loot(loot_list, depth)
  43. local loot_type = ""
  44. local loot_amount = 0
  45. local total_chance = 0
  46. for i,v in ipairs(loot_list) do
  47. if v.chance_and_amount then
  48. total_chance = total_chance + v.chance_and_amount
  49. elseif v.chance then
  50. total_chance = total_chance + v.chance
  51. else
  52. error("No chance_and_amount or chance found in basic_list table.")
  53. return nil, 0
  54. end
  55. end
  56. local leftover = math_random(1,total_chance)
  57. local type_amount = 0
  58. for i,v in ipairs(loot_list) do
  59. if v.chance_and_amount then
  60. leftover = leftover - v.chance_and_amount
  61. elseif v.chance then
  62. leftover = leftover - v.chance
  63. end
  64. if leftover < 1 then
  65. loot_type = v.name
  66. if v.chance_and_amount then
  67. type_amount = v.chance_and_amount
  68. else
  69. type_amount = v.amount
  70. end
  71. break
  72. end
  73. end
  74. if loot_type == "" then -- Paranoia
  75. error("Unable to choose a loot_type from basic_list table.")
  76. return nil, 0
  77. end
  78. loot_amount = math_random(1,math.ceil(type_amount/2))
  79. if depth > dungeon_loot.depth_first_basic_increase then
  80. loot_amount = math_random(1,type_amount)
  81. end
  82. if depth > dungeon_loot.depth_second_basic_increase then
  83. loot_amount = math_random(1,type_amount*2)
  84. end
  85. return loot_type, loot_amount
  86. end
  87. local function get_item_and_amount(list_item, actual_depth)
  88. if list_item.chance < math_random() then
  89. return nil, 0
  90. end
  91. -- This must point to a table.
  92. local list_key = list_item.name .. "_list"
  93. local list_name = dungeon_loot[list_key]
  94. -- Suspicious trickery.
  95. --[[
  96. list_name_string = "dungeon_loot." .. list_item.name .. "_list"
  97. -- list_name = _G[list_name_string]
  98. lsf = loadstring("list_name = " .. list_name_string)
  99. lsf()
  100. --]]
  101. -- ^ What the H. - MustTest.
  102. if list_name == nil then
  103. error("Unable to connect \"" .. list_key .. "\" to actual table")
  104. return nil, 0
  105. end
  106. local amount = 0
  107. local loot_type = ""
  108. local loot_depth = 0
  109. local max_depth = 1
  110. if actual_depth < 0 then
  111. max_depth = math.ceil(math.abs(actual_depth))
  112. end
  113. if list_item.type == "depth_cutoff" then
  114. local rnd_depth = math_random(1,max_depth)
  115. loot_type, loot_depth = get_max_loot(list_name, rnd_depth)
  116. if list_item.max_amount == 1 then -- For tools & weapons
  117. amount = 1
  118. else
  119. -- Stop large amounts of the first item
  120. if loot_depth < 1 then
  121. loot_depth = 5
  122. end
  123. local leftover = rnd_depth
  124. while leftover > 0 do
  125. amount = amount + 1
  126. leftover = leftover - math_random(1,loot_depth)
  127. leftover = leftover - math.ceil(loot_depth/2)
  128. end
  129. end
  130. elseif list_item.type == "basic_list" then
  131. loot_type, amount = get_basic_loot(list_name, max_depth)
  132. else
  133. error("Got unknown loot table type " .. list_item.type)
  134. loot_type = nil
  135. end
  136. -- Hey, if you leave out the max_amount, you deserve what you get
  137. if list_item.max_amount and amount > list_item.max_amount then
  138. amount = list_item.max_amount
  139. end
  140. return loot_type, amount
  141. end
  142. local function fill_chest(pos)
  143. minetest.after(2, function()
  144. local n = minetest.get_node(pos)
  145. if n and n.name and n.name == "chests:chest_public_closed" then
  146. local meta = minetest.get_meta(pos)
  147. local inv = meta:get_inventory()
  148. -- The inventory size is set in the chest constructor.
  149. --inv:set_size("main", 8*4)
  150. for i,v in ipairs(dungeon_loot.loot_types) do
  151. local item, num = get_item_and_amount(v,pos.y)
  152. if item then
  153. if minetest.registered_items[item] then -- Ensure not unknown item.
  154. local stack = ItemStack({name = item, count = num, wear = 0, metadata = ""})
  155. inv:set_stack("main",i,stack)
  156. end
  157. end
  158. end
  159. end
  160. end)
  161. end
  162. -- Place chest in dungeons
  163. local function place_spawner(tab)
  164. if tab == nil or #tab < 1 then
  165. return
  166. end
  167. local pos = tab[math_random(1, #tab)]
  168. pos.y = pos.y - 1
  169. local below = core.get_node_or_nil(pos)
  170. if below and below.name ~= "air" then
  171. pos.y = pos.y + 1
  172. core.set_node(pos, {name = "chests:chest_public_closed"})
  173. fill_chest(pos)
  174. end
  175. end
  176. core.set_gen_notify("dungeon")
  177. core.register_on_generated(function(minp, maxp, blockseed)
  178. local ntf = core.get_mapgen_object("gennotify")
  179. if ntf and ntf.dungeon and #ntf.dungeon >= dungeon_loot.min_num_of_rooms then
  180. core.after(3, place_spawner, table.copy(ntf.dungeon))
  181. end
  182. end)