init.lua 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. local settings = minetest.settings
  2. -- Automatically detect and overwrite core settings for Mineclone game.
  3. local mineclone = settings:get_bool("coolbar.mineclone_autodetect", true)
  4. -- Visible bar size (excluding inventory and hidden slots).
  5. local bar_size = tonumber(settings:get "coolbar.bar_size" or 8) --[[@as integer]]
  6. -- The number of visible inventory rows (excluding bar and hidden slots).
  7. local inv_rows = tonumber(settings:get "coolbar.inv_rows" or 3) --[[@as integer]]
  8. -- Visible inventory size (excluding bar and hidden slots).
  9. local inv_size = bar_size * inv_rows
  10. -- Index of the first slot on a bar.
  11. local bar_start = tonumber(settings:get "coolbar.bar_start" or 1) --[[@as integer]]
  12. -- Index of the first inventory slot.
  13. local inv_start = tonumber(settings:get "coolbar.inv_start" or 9) --[[@as integer]]
  14. -- The last slot on bar
  15. local bar_end = bar_start + bar_size - 1
  16. -- The last inventory slot
  17. local inv_end = inv_start + inv_size - 1
  18. -- Default builtin array of itemstrings preferred to keep on the bar.
  19. local default_bar_slots = {
  20. "group:sword",
  21. "group:shovel",
  22. "group:pickaxe",
  23. "group:axe",
  24. "default:water_bucket",
  25. "group:soil",
  26. "group:food|group:food_apple|group:food_mushroom",
  27. "group:torch",
  28. }
  29. -- Items preferred to keep on the bar.
  30. ---@type string[][]
  31. local preferred_bar_slots = {}
  32. for i = 1, bar_size do
  33. local slot =
  34. tostring(settings:get("coolbar.slot_" .. i) or default_bar_slots[i] or "")
  35. preferred_bar_slots[i] = slot:split "|"
  36. end
  37. -- Check if item corresponds to itemstring, including "group:something" format.
  38. ---@param item mt.ItemStack
  39. ---@param is string|string[]
  40. ---@return boolean
  41. local function item_is(item, is)
  42. if type(is) == "table" then
  43. for _, value in ipairs(is) do
  44. if item_is(item, value) then return true end
  45. end
  46. return false
  47. end
  48. if is:find "^group:" then
  49. local group = is:sub(7)
  50. if item:get_definition().groups[group] then return true end
  51. return false
  52. end
  53. if item:get_name() == is then return true end
  54. return false
  55. end
  56. ---@param player mt.PlayerObjectRef
  57. ---@param old_item mt.ItemStack
  58. ---@param new_item mt.ItemStack
  59. ---@param index integer
  60. local function handle_item_increase(player, old_item, new_item, index)
  61. ---@return boolean is_it, integer|nil should_be
  62. local function is_new_item_position_correct()
  63. if old_item:get_name() == new_item:get_name() then return true, index end
  64. local should_be
  65. for i, preferred in ipairs(preferred_bar_slots) do
  66. if item_is(new_item, preferred) then
  67. should_be = i
  68. break
  69. end
  70. end
  71. if should_be == index then return true, should_be end
  72. if index >= inv_start and index <= inv_end then
  73. if should_be then return false, should_be end
  74. return true, should_be
  75. end
  76. return false, should_be
  77. end
  78. local is_it, should_be = is_new_item_position_correct()
  79. -- log(("[%s] : [%s == %s]"):format(is_it, item_index, should_be))
  80. if is_it then return end
  81. local inv = player:get_inventory()
  82. local list = inv:get_list "main"
  83. if should_be and list[should_be]:get_free_space() == 0 then
  84. should_be = nil
  85. end
  86. local new_item_name = new_item:get_name()
  87. local slot_empty, slot_same ---@type integer, integer|nil
  88. for i = inv_start, inv_end do
  89. local name = list[i]:get_name()
  90. if not slot_empty and name == "" then
  91. slot_empty = i
  92. elseif
  93. not slot_same
  94. and name == new_item_name
  95. and list[i]:get_free_space() > 0
  96. then
  97. slot_same = i
  98. end
  99. if slot_same and slot_empty then break end
  100. end
  101. if not slot_empty then return end
  102. -- log(("empty: [%s], same: [%s]"):format(slot_empty, slot_same))
  103. local stack_from = list[index]
  104. local stack_to = list[should_be or slot_same or slot_empty]
  105. local taken = stack_from:take_item(stack_from:get_count())
  106. local leftover = stack_to:add_item(taken)
  107. list[slot_empty]:add_item(leftover)
  108. inv:set_list("main", list)
  109. rr.player_inventory_main_lists[player:get_player_name()] = list
  110. end
  111. ---@param player mt.PlayerObjectRef
  112. ---@param old_item mt.ItemStack
  113. ---@param new_item mt.ItemStack
  114. ---@param item_index integer
  115. local function handle_bar_decrease(player, old_item, new_item, item_index)
  116. local inv = player:get_inventory()
  117. local list = inv:get_list "main"
  118. ---@type string|string[]
  119. local target_item = new_item:get_name()
  120. if target_item == "" then
  121. local bar_index = item_index - bar_start + 1
  122. local preferred = preferred_bar_slots[bar_index]
  123. if not item_is(old_item, preferred) then
  124. target_item = old_item:get_name()
  125. else
  126. target_item = preferred
  127. end
  128. end
  129. for i = inv_start, inv_end do
  130. local inv_stack = list[i]
  131. if item_is(inv_stack, target_item) then
  132. local bar_stack = list[item_index]
  133. local leftover = bar_stack:add_item(inv_stack)
  134. list[i] = leftover
  135. if bar_stack:get_count() == bar_stack:get_stack_max() then break end
  136. if not leftover or leftover:get_name() ~= "" then break end
  137. end
  138. end
  139. inv:set_list("main", list)
  140. rr.player_inventory_main_lists[player:get_player_name()] = list
  141. end
  142. ---@type rr.on_player_inventory_change
  143. local function on_player_inv_change(player, old_item, new_item, i, action, info)
  144. if info and info.from_list == "main" then return end
  145. if new_item:get_count() >= old_item:get_count() then
  146. handle_item_increase(player, old_item, new_item, i)
  147. return
  148. end
  149. if i >= bar_start and i <= bar_end then
  150. handle_bar_decrease(player, old_item, new_item, i)
  151. end
  152. end
  153. rr.register_on_player_inventory_change(on_player_inv_change)
  154. minetest.register_on_mods_loaded(function()
  155. ---@diagnostic disable-next-line: undefined-global
  156. if mcl_vars and mineclone then
  157. bar_size = 9
  158. inv_start = 10
  159. end
  160. rr.auto_detect_inventory_changes()
  161. end)
  162. --[[ Debug
  163. minetest.log(
  164. (
  165. "bar_size: %s, inv_rows: %s, inv_size: %s, "
  166. .. "bar_start: %s, bar_end: %s, "
  167. .. "inv_start: %s, inv_end: %s"
  168. ):format(
  169. bar_size,
  170. inv_rows,
  171. inv_size,
  172. bar_start,
  173. bar_end,
  174. inv_start,
  175. inv_end
  176. )
  177. )
  178. ]]