init.lua 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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. -- Suspicious trickery
  92. list_name = nil
  93. list_name_string = "dungeon_loot." .. list_item.name .. "_list"
  94. -- list_name = _G[list_name_string]
  95. lsf = loadstring("list_name = " .. list_name_string)
  96. lsf()
  97. if list_name == nil then
  98. error("Unable to connect " .. list_name_string .. " to actual table")
  99. return nil, 0
  100. end
  101. local amount = 0
  102. local loot_type = ""
  103. local loot_depth = 0
  104. local max_depth = 1
  105. if actual_depth < 0 then
  106. max_depth = math.ceil(math.abs(actual_depth))
  107. end
  108. if list_item.type == "depth_cutoff" then
  109. local rnd_depth = math_random(1,max_depth)
  110. loot_type, loot_depth = get_max_loot(list_name, rnd_depth)
  111. if list_item.max_amount == 1 then -- For tools & weapons
  112. amount = 1
  113. else
  114. -- Stop large amounts of the first item
  115. if loot_depth < 1 then
  116. loot_depth = 5
  117. end
  118. local leftover = rnd_depth
  119. while leftover > 0 do
  120. amount = amount + 1
  121. leftover = leftover - math_random(1,loot_depth)
  122. leftover = leftover - math.ceil(loot_depth/2)
  123. end
  124. end
  125. elseif list_item.type == "basic_list" then
  126. loot_type, amount = get_basic_loot(list_name, max_depth)
  127. else
  128. error("Got unknown loot table type " .. list_item.type)
  129. loot_type = nil
  130. end
  131. -- Hey, if you leave out the max_amount, you deserve what you get
  132. if list_item.max_amount and amount > list_item.max_amount then
  133. amount = list_item.max_amount
  134. end
  135. return loot_type, amount
  136. end
  137. local function fill_chest(pos)
  138. minetest.after(2, function()
  139. local n = minetest.get_node(pos)
  140. if n and n.name and n.name == "chests:chest_public_closed" then
  141. local meta = minetest.get_meta(pos)
  142. local inv = meta:get_inventory()
  143. -- The inventory size is set in the chest constructor.
  144. --inv:set_size("main", 8*4)
  145. for i,v in ipairs(dungeon_loot.loot_types) do
  146. local item, num = get_item_and_amount(v,pos.y)
  147. if item then
  148. if minetest.registered_items[item] then -- Ensure not unknown item.
  149. local stack = ItemStack({name = item, count = num, wear = 0, metadata = ""})
  150. inv:set_stack("main",i,stack)
  151. end
  152. end
  153. end
  154. end
  155. end)
  156. end
  157. -- Place chest in dungeons
  158. local function place_spawner(tab)
  159. if tab == nil or #tab < 1 then
  160. return
  161. end
  162. local pos = tab[math_random(1, #tab)]
  163. pos.y = pos.y - 1
  164. local below = core.get_node_or_nil(pos)
  165. if below and below.name ~= "air" then
  166. pos.y = pos.y + 1
  167. core.set_node(pos, {name = "chests:chest_public_closed"})
  168. fill_chest(pos)
  169. end
  170. end
  171. core.set_gen_notify("dungeon")
  172. core.register_on_generated(function(minp, maxp, blockseed)
  173. local ntf = core.get_mapgen_object("gennotify")
  174. if ntf and ntf.dungeon and #ntf.dungeon >= dungeon_loot.min_num_of_rooms then
  175. core.after(3, place_spawner, table.copy(ntf.dungeon))
  176. end
  177. end)