inventory.lua 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. -- creative/inventory.lua
  2. -- support for MT game translation.
  3. local S = creative.get_translator
  4. local player_inventory = {}
  5. local inventory_cache = {}
  6. local function init_creative_cache(items)
  7. inventory_cache[items] = {}
  8. local i_cache = inventory_cache[items]
  9. for name, def in pairs(items) do
  10. if def.groups.not_in_creative_inventory ~= 1 and def.description and def.description ~= "" then
  11. i_cache[name] = def
  12. end
  13. end
  14. table.sort(i_cache)
  15. return i_cache
  16. end
  17. function creative.init_creative_inventory(player)
  18. local player_name = player:get_player_name()
  19. player_inventory[player_name] = {
  20. size = 0,
  21. filter = "",
  22. start_i = 0,
  23. old_filter = nil, -- use only for caching in update_creative_inventory
  24. old_content = nil
  25. }
  26. minetest.create_detached_inventory("creative_" .. player_name, {
  27. allow_move = function(inv, from_list, from_index, to_list, to_index, count, player2)
  28. local name = player2 and player2:get_player_name() or ""
  29. if not creative.is_enabled_for(name) or
  30. to_list == "main" then
  31. return 0
  32. end
  33. return count
  34. end,
  35. allow_put = function(inv, listname, index, stack, player2)
  36. return 0
  37. end,
  38. allow_take = function(inv, listname, index, stack, player2)
  39. local name = player2 and player2:get_player_name() or ""
  40. if not creative.is_enabled_for(name) then
  41. return 0
  42. end
  43. return -1
  44. end,
  45. on_move = function(inv, from_list, from_index, to_list, to_index, count, player2)
  46. end,
  47. on_take = function(inv, listname, index, stack, player2)
  48. if stack and stack:get_count() > 0 then
  49. minetest.log("action", player_name .. " takes " .. stack:get_name().. " from creative inventory")
  50. end
  51. end,
  52. }, player_name)
  53. return player_inventory[player_name]
  54. end
  55. local NO_MATCH = 999
  56. local function match(s, filter)
  57. if filter == "" then
  58. return 0
  59. end
  60. if s:lower():find(filter, 1, true) then
  61. return #s - #filter
  62. end
  63. return NO_MATCH
  64. end
  65. local function description(def, lang_code)
  66. local s = def.description
  67. if lang_code then
  68. s = minetest.get_translated_string(lang_code, s)
  69. end
  70. return s:gsub("\n.*", "") -- First line only
  71. end
  72. function creative.update_creative_inventory(player_name, tab_content)
  73. local inv = player_inventory[player_name] or
  74. creative.init_creative_inventory(minetest.get_player_by_name(player_name))
  75. local player_inv = minetest.get_inventory({type = "detached", name = "creative_" .. player_name})
  76. if inv.filter == inv.old_filter and tab_content == inv.old_content then
  77. return
  78. end
  79. inv.old_filter = inv.filter
  80. inv.old_content = tab_content
  81. local items = inventory_cache[tab_content] or init_creative_cache(tab_content)
  82. local lang
  83. local player_info = minetest.get_player_information(player_name)
  84. if player_info and player_info.lang_code ~= "" then
  85. lang = player_info.lang_code
  86. end
  87. local creative_list = {}
  88. local order = {}
  89. for name, def in pairs(items) do
  90. local m = match(description(def), inv.filter)
  91. if m > 0 then
  92. m = math.min(m, match(description(def, lang), inv.filter))
  93. end
  94. if m > 0 then
  95. m = math.min(m, match(name, inv.filter))
  96. end
  97. if m < NO_MATCH then
  98. creative_list[#creative_list+1] = name
  99. order[name] = name
  100. end
  101. end
  102. table.sort(creative_list, function(a, b) return order[a] < order[b] end)
  103. player_inv:set_size("main", #creative_list)
  104. player_inv:set_list("main", creative_list)
  105. inv.size = #creative_list
  106. end
  107. -- Create the trash field
  108. local trash = minetest.create_detached_inventory("creative_trash", {
  109. -- Allow the stack to be placed and remove it in on_put()
  110. -- This allows the creative inventory to restore the stack
  111. allow_put = function(inv, listname, index, stack, player)
  112. return stack:get_count()
  113. end,
  114. on_put = function(inv, listname)
  115. inv:set_list(listname, {})
  116. end,
  117. })
  118. trash:set_size("main", 1)
  119. creative.formspec_add = ""
  120. function creative.register_tab(name, title, items)
  121. sfinv.register_page("creative:" .. name, {
  122. title = title,
  123. is_in_nav = function(self, player, context)
  124. return creative.is_enabled_for(player:get_player_name())
  125. end,
  126. get = function(self, player, context)
  127. local player_name = player:get_player_name()
  128. creative.update_creative_inventory(player_name, items)
  129. player:get_inventory():set_size('main', 8*4)
  130. local inv = player_inventory[player_name]
  131. local pagenum = math.floor(inv.start_i / (4*8) + 1)
  132. local pagemax = math.ceil(inv.size / (4*8))
  133. local esc = minetest.formspec_escape
  134. return sfinv.make_formspec(player, context,
  135. "label[5.8,4.15;" .. minetest.colorize("#FFFF00", tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" ..
  136. [[
  137. image[4.08,4.2;0.8,0.8;creative_trash_icon.png]
  138. listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]
  139. list[detached:creative_trash;main;4.02,4.1;1,1;]
  140. listring[]
  141. image_button[5,4.05;0.8,0.8;creative_prev_icon.png;creative_prev;]
  142. image_button[7.2,4.05;0.8,0.8;creative_next_icon.png;creative_next;]
  143. image_button[2.63,4.05;0.8,0.8;creative_search_icon.png;creative_search;]
  144. image_button[3.25,4.05;0.8,0.8;creative_clear_icon.png;creative_clear;]
  145. ]] ..
  146. "tooltip[creative_search;" .. esc(S("Search")) .. "]" ..
  147. "tooltip[creative_clear;" .. esc(S("Reset")) .. "]" ..
  148. "tooltip[creative_prev;" .. esc(S("Previous page")) .. "]" ..
  149. "tooltip[creative_next;" .. esc(S("Next page")) .. "]" ..
  150. "listring[current_player;main]" ..
  151. "field_close_on_enter[creative_filter;false]" ..
  152. "field[0.3,4.2;2.8,1.2;creative_filter;;" .. esc(inv.filter) .. "]" ..
  153. "listring[detached:creative_" .. player_name .. ";main]" ..
  154. "list[detached:creative_" .. player_name .. ";main;0,0;8,4;" .. tostring(inv.start_i) .. "]" ..
  155. creative.formspec_add, true)
  156. end,
  157. on_enter = function(self, player, context)
  158. local player_name = player:get_player_name()
  159. local inv = player_inventory[player_name]
  160. if inv then
  161. inv.start_i = 0
  162. end
  163. end,
  164. on_player_receive_fields = function(self, player, context, fields)
  165. local player_name = player:get_player_name()
  166. local inv = player_inventory[player_name]
  167. assert(inv)
  168. if fields.creative_clear then
  169. inv.start_i = 0
  170. inv.filter = ""
  171. sfinv.set_player_inventory_formspec(player, context)
  172. elseif fields.creative_search or
  173. fields.key_enter_field == "creative_filter" then
  174. inv.start_i = 0
  175. inv.filter = fields.creative_filter:lower()
  176. sfinv.set_player_inventory_formspec(player, context)
  177. elseif not fields.quit then
  178. local start_i = inv.start_i or 0
  179. if fields.creative_prev then
  180. start_i = start_i - 4*8
  181. if start_i < 0 then
  182. start_i = inv.size - (inv.size % (4*8))
  183. if inv.size == start_i then
  184. start_i = math.max(0, inv.size - (4*8))
  185. end
  186. end
  187. elseif fields.creative_next then
  188. start_i = start_i + 4*8
  189. if start_i >= inv.size then
  190. start_i = 0
  191. end
  192. end
  193. inv.start_i = start_i
  194. sfinv.set_player_inventory_formspec(player, context)
  195. end
  196. end
  197. })
  198. end
  199. -- Sort registered items
  200. local registered_nodes = {}
  201. local registered_decals = {}
  202. local registered_tasks = {}
  203. local registered_lights = {}
  204. local registered_artwork = {}
  205. local registered_tools = {}
  206. minetest.register_on_mods_loaded(function()
  207. for name, def in pairs(minetest.registered_items) do
  208. local group = def.groups or {}
  209. local nogroup = not (group.node or group.tool or group.craftitem)
  210. local mod = def.mod_origin
  211. if mod == 'decals' then
  212. registered_decals[name] = def
  213. elseif mod == 'tasks' then
  214. registered_tasks[name] = def
  215. elseif mod == 'lights' then
  216. registered_lights[name] = def
  217. elseif mod == 'artwork' then
  218. registered_artwork[name] = def
  219. elseif group.node or (nogroup and minetest.registered_nodes[name]) then
  220. registered_nodes[name] = def
  221. end
  222. if def.type == 'tool' then
  223. registered_tools[name] = def
  224. end
  225. end
  226. end)
  227. creative.register_tab("all", "All", minetest.registered_items)
  228. creative.register_tab('artwork', 'Artwork', registered_artwork)
  229. creative.register_tab('decals', 'Decals', registered_decals)
  230. creative.register_tab('lights', 'Lights', registered_lights)
  231. creative.register_tab("nodes", "Nodes", registered_nodes)
  232. creative.register_tab('tasks', 'Tasks', registered_tasks)
  233. creative.register_tab('tools', 'Tools', registered_tools)
  234. local old_homepage_name = sfinv.get_homepage_name
  235. function sfinv.get_homepage_name(player)
  236. if creative.is_enabled_for(player:get_player_name()) then
  237. return "creative:all"
  238. else
  239. return old_homepage_name(player)
  240. end
  241. end