loot.lua 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. -- Localize for performance.
  2. local math_random = math.random
  3. local function get_max_loot(loot_list, depth)
  4. local loot_type = loot_list[1].name
  5. local loot_min_depth = loot_list[1].min_depth
  6. for i,v in ipairs(loot_list) do
  7. if v.min_depth < depth then
  8. loot_type = v.name
  9. loot_min_depth = v.min_depth
  10. else
  11. break
  12. end
  13. end
  14. return loot_type, loot_min_depth
  15. end
  16. local function get_basic_loot(loot_list, depth)
  17. local loot_type = ""
  18. local loot_amount = 0
  19. local total_chance = 0
  20. for i,v in ipairs(loot_list) do
  21. if v.chance_and_amount then
  22. total_chance = total_chance + v.chance_and_amount
  23. elseif v.chance then
  24. total_chance = total_chance + v.chance
  25. else
  26. error("No chance_and_amount or chance found in basic_list table.")
  27. return nil, 0
  28. end
  29. end
  30. local leftover = math_random(1,total_chance)
  31. local type_amount = 0
  32. for i,v in ipairs(loot_list) do
  33. if v.chance_and_amount then
  34. leftover = leftover - v.chance_and_amount
  35. elseif v.chance then
  36. leftover = leftover - v.chance
  37. end
  38. if leftover < 1 then
  39. loot_type = v.name
  40. if v.chance_and_amount then
  41. type_amount = v.chance_and_amount
  42. else
  43. type_amount = v.amount
  44. end
  45. break
  46. end
  47. end
  48. if loot_type == "" then -- Paranoia
  49. error("Unable to choose a loot_type from basic_list table.")
  50. return nil, 0
  51. end
  52. loot_amount = math_random(1,math.ceil(type_amount/2))
  53. if depth > dungeon_loot.depth_first_basic_increase then
  54. loot_amount = math_random(1,type_amount)
  55. end
  56. if depth > dungeon_loot.depth_second_basic_increase then
  57. loot_amount = math_random(1,type_amount*2)
  58. end
  59. return loot_type, loot_amount
  60. end
  61. local function get_item_and_amount(list_item, actual_depth)
  62. if list_item.chance < math_random() then
  63. return nil, 0
  64. end
  65. -- This must point to a table.
  66. local list_key = list_item.name .. "_list"
  67. local list_name = dungeon_loot[list_key]
  68. -- Suspicious trickery.
  69. --[[
  70. list_name_string = "dungeon_loot." .. list_item.name .. "_list"
  71. -- list_name = _G[list_name_string]
  72. lsf = loadstring("list_name = " .. list_name_string)
  73. lsf()
  74. --]]
  75. -- ^ What the H. - MustTest.
  76. if list_name == nil then
  77. error("Unable to connect \"" .. list_key .. "\" to actual table")
  78. return nil, 0
  79. end
  80. local amount = 0
  81. local loot_type = ""
  82. local loot_depth = 0
  83. local max_depth = 1
  84. if actual_depth < 0 then
  85. max_depth = math.ceil(math.abs(actual_depth))
  86. end
  87. if list_item.type == "depth_cutoff" then
  88. local rnd_depth = math_random(1,max_depth)
  89. loot_type, loot_depth = get_max_loot(list_name, rnd_depth)
  90. if list_item.max_amount == 1 then -- For tools & weapons
  91. amount = 1
  92. else
  93. -- Stop large amounts of the first item
  94. if loot_depth < 1 then
  95. loot_depth = 5
  96. end
  97. local leftover = rnd_depth
  98. while leftover > 0 do
  99. amount = amount + 1
  100. leftover = leftover - math_random(1,loot_depth)
  101. leftover = leftover - math.ceil(loot_depth/2)
  102. end
  103. end
  104. elseif list_item.type == "basic_list" then
  105. loot_type, amount = get_basic_loot(list_name, max_depth)
  106. else
  107. error("Got unknown loot table type " .. list_item.type)
  108. loot_type = nil
  109. end
  110. -- Hey, if you leave out the max_amount, you deserve what you get
  111. if list_item.max_amount and amount > list_item.max_amount then
  112. amount = list_item.max_amount
  113. end
  114. return loot_type, amount
  115. end
  116. function dungeon_loot.fill_chest(pos)
  117. local meta = minetest.get_meta(pos)
  118. local inv = meta:get_inventory()
  119. for i, v in ipairs(dungeon_loot.loot_types) do
  120. local item, num = get_item_and_amount(v, pos.y)
  121. if item then
  122. if minetest.registered_items[item] then -- Ensure not unknown item.
  123. local stack = ItemStack({name = item, count = num, wear = 0, metadata = ""})
  124. inv:set_stack("main", i, stack)
  125. end
  126. end
  127. end
  128. end
  129. -- Place chest in dungeons
  130. function dungeon_loot.place_loot_chest(tab)
  131. if tab == nil or #tab < 1 then
  132. return
  133. end
  134. -- Random number of chests.
  135. local count = math_random(2, 5)
  136. for k = 1, count do
  137. local pos = tab[math_random(1, #tab)]
  138. local minp = vector.offset(pos, -5, -5, -5)
  139. local maxp = vector.offset(pos, 5, 5, 5)
  140. local targets = minetest.find_nodes_in_area_under_air(minp, maxp, dungeon_loot.DUNGEON_NODES)
  141. if targets and #targets > 0 then
  142. local target = targets[math_random(1, #targets)]
  143. local param2 = math_random(0, 3)
  144. local above = vector.offset(target, 0, 1, 0)
  145. if minetest.get_node(above).name == "air" then
  146. local cnodes = dungeon_loot.CHEST_NODES
  147. local chest_node = cnodes[math_random(1, #cnodes)]
  148. minetest.set_node(above, {name = chest_node, param2 = param2})
  149. dungeon_loot.fill_chest(above)
  150. end
  151. end
  152. end
  153. end