init.lua 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342
  1. -- Boilerplate to support localized strings if intllib mod is installed.
  2. local S
  3. if minetest.get_modpath("intllib") then
  4. S = intllib.Getter()
  5. else
  6. S = function(s,a,...)a={a,...}return s:gsub("@(%d+)",function(n)return a[tonumber(n)]end)end
  7. end
  8. doc.sub.items = {}
  9. -- Template texts
  10. doc.sub.items.temp = {}
  11. doc.sub.items.temp.deco = S("This is a decorational block.")
  12. doc.sub.items.temp.build = S("This block is a building block for creating various buildings.")
  13. doc.sub.items.temp.craftitem = S("This item is primarily used for crafting other items.")
  14. doc.sub.items.temp.eat = S("Hold it in your hand, then leftclick to eat it.")
  15. doc.sub.items.temp.eat_bad = S("Hold it in your hand, then leftclick to eat it. But why would you want to do this?")
  16. doc.sub.items.settings = {}
  17. doc.sub.items.settings.friendly_group_names = false
  18. local setting = minetest.setting_getbool("doc_items_friendly_group_names")
  19. if setting ~= nil then
  20. doc.sub.items.settings.friendly_group_names = setting
  21. end
  22. doc.sub.items.settings.itemstring = false
  23. setting = minetest.setting_getbool("doc_items_show_itemstrings")
  24. if setting ~= nil then
  25. doc.sub.items.settings.itemstring = setting
  26. end
  27. -- Local stuff
  28. local groupdefs = {}
  29. local mininggroups = {}
  30. local miscgroups = {}
  31. local item_name_overrides = {
  32. [""] = S("Hand"),
  33. ["air"] = S("Air")
  34. }
  35. local suppressed = {
  36. ["ignore"] = true,
  37. }
  38. -- Helper functions
  39. local yesno = function(bool)
  40. if bool==true then return S("Yes")
  41. elseif bool==false then return S("No")
  42. else return "N/A" end
  43. end
  44. local groups_to_string = function(grouptable, filter)
  45. local gstring = ""
  46. local groups_count = 0
  47. for id, value in pairs(grouptable) do
  48. if (filter == nil or filter[id] == true) then
  49. -- Readable group name
  50. if groups_count > 0 then
  51. -- List seperator
  52. gstring = gstring .. S(", ")
  53. end
  54. if groupdefs[id] ~= nil and doc.sub.items.settings.friendly_group_names == true then
  55. gstring = gstring .. groupdefs[id]
  56. else
  57. gstring = gstring .. id
  58. end
  59. groups_count = groups_count + 1
  60. end
  61. end
  62. if groups_count == 0 then
  63. return nil, 0
  64. else
  65. return gstring, groups_count
  66. end
  67. end
  68. -- Replaces all newlines with spaces
  69. local scrub_newlines = function(text)
  70. local new, x = string.gsub(text, "\n", " ")
  71. return new
  72. end
  73. --[[ Append a newline to text, unless it already ends with a newline. ]]
  74. local newline = function(text)
  75. if string.sub(text, #text, #text) == "\n" or text == "" then
  76. return text
  77. else
  78. return text .. "\n"
  79. end
  80. end
  81. --[[ Make sure the text ends with two newlines by appending any missing newlines at the end, if neccessary. ]]
  82. local newline2 = function(text)
  83. if string.sub(text, #text-1, #text) == "\n\n" or text == "" then
  84. return text
  85. elseif string.sub(text, #text, #text) == "\n" then
  86. return text .. "\n"
  87. else
  88. return text .. "\n\n"
  89. end
  90. end
  91. -- Extract suitable item description for formspec
  92. local description_for_formspec = function(itemstring)
  93. if minetest.registered_items[itemstring] == nil then
  94. -- Huh? The item doesn't exist for some reason. Better give a dummy string
  95. minetest.log("warning", "[doc] Unknown item detected: "..tostring(itemstring))
  96. return S("Unknown item (@1)", tostring(itemstring))
  97. end
  98. local description = minetest.registered_items[itemstring].description
  99. if description == nil or description == "" then
  100. return minetest.formspec_escape(itemstring)
  101. else
  102. return minetest.formspec_escape(scrub_newlines(description))
  103. end
  104. end
  105. local get_entry_name = function(itemstring)
  106. local def = minetest.registered_items[itemstring]
  107. if def._doc_items_entry_name ~= nil then
  108. return def._doc_items_entry_name
  109. elseif item_name_overrides[itemstring] ~= nil then
  110. return item_name_overrides[itemstring]
  111. else
  112. return def.description
  113. end
  114. end
  115. doc.sub.items.get_group_name = function(groupname)
  116. if groupdefs[groupname] ~= nil and doc.sub.items.settings.friendly_group_names == true then
  117. return groupdefs[groupname]
  118. else
  119. return groupname
  120. end
  121. end
  122. local burntime_to_text = function(burntime)
  123. if burntime == nil then
  124. return S("unknown")
  125. elseif burntime == 1 then
  126. return S("1 second")
  127. else
  128. return S("@1 seconds", burntime)
  129. end
  130. end
  131. --[[ Convert tool capabilities to readable text. Extracted information:
  132. * Mining capabilities
  133. * Durability (when mining
  134. * Full punch interval
  135. * Damage groups
  136. ]]
  137. local factoid_toolcaps = function(tool_capabilities, check_uses)
  138. local formstring = ""
  139. if check_uses == nil then check_uses = false end
  140. if tool_capabilities ~= nil and tool_capabilities ~= {} then
  141. local groupcaps = tool_capabilities.groupcaps
  142. if groupcaps ~= nil then
  143. local miningcapstr = ""
  144. local miningtimesstr = ""
  145. local miningusesstr = ""
  146. local caplines = 0
  147. local timelines = 0
  148. local useslines = 0
  149. for k,v in pairs(groupcaps) do
  150. -- Mining capabilities
  151. local minrating, maxrating
  152. for rating, time in pairs(v.times) do
  153. if minrating == nil then minrating = rating else
  154. if minrating > rating then minrating = rating end
  155. end
  156. if maxrating == nil then maxrating = rating else
  157. if maxrating < rating then maxrating = rating end
  158. end
  159. end
  160. local maxlevel = v.maxlevel
  161. if not maxlevel then
  162. -- Default from tool.h
  163. maxlevel = 1
  164. end
  165. miningcapstr = miningcapstr .. S("• @1: @2", doc.sub.items.get_group_name(k), maxlevel)
  166. miningcapstr = miningcapstr .. "\n"
  167. caplines = caplines + 1
  168. for rating=3, 1, -1 do
  169. if v.times ~= nil and v.times[rating] ~= nil then
  170. local maxtime = v.times[rating]
  171. local mintime
  172. local mintimestr, maxtimestr
  173. local maxlevel_calc = maxlevel
  174. if maxlevel_calc < 1 then
  175. maxlevel_calc = 1
  176. end
  177. mintime = maxtime / maxlevel_calc
  178. mintimestr = string.format("%.1f", mintime)
  179. maxtimestr = string.format("%.1f", maxtime)
  180. if mintimestr ~= maxtimestr then
  181. miningtimesstr = miningtimesstr ..
  182. S("• @1, rating @2: @3 s - @4 s",
  183. doc.sub.items.get_group_name(k), rating,
  184. mintimestr, maxtimestr)
  185. else
  186. miningtimesstr = miningtimesstr ..
  187. S("• @1, rating @2: @3 s",
  188. doc.sub.items.get_group_name(k), rating,
  189. mintimestr)
  190. end
  191. miningtimesstr = miningtimesstr.. "\n"
  192. timelines = timelines + 1
  193. end
  194. end
  195. -- Number of mining uses
  196. local base_uses = v.uses
  197. if not base_uses then
  198. -- Default from tool.h
  199. base_uses = 20
  200. end
  201. if check_uses and base_uses > 0 then
  202. for level=0, maxlevel do
  203. local real_uses = base_uses * math.pow(3, maxlevel - level)
  204. if real_uses < 65535 then
  205. miningusesstr = miningusesstr .. S("• @1, level @2: @3 uses", doc.sub.items.get_group_name(k), level, real_uses)
  206. else
  207. miningusesstr = miningusesstr .. S("• @1, level @2: Unlimited", doc.sub.items.get_group_name(k), level)
  208. end
  209. miningusesstr = miningusesstr .. "\n"
  210. useslines = useslines + 1
  211. end
  212. end
  213. end
  214. if caplines > 0 then
  215. formstring = formstring .. S("This tool is capable of mining.") .. "\n"
  216. formstring = formstring .. S("Maximum toughness levels:") .. "\n"
  217. formstring = formstring .. miningcapstr
  218. formstring = newline(formstring)
  219. end
  220. if timelines > 0 then
  221. formstring = formstring .. S("Mining times:") .. "\n"
  222. formstring = formstring .. miningtimesstr
  223. end
  224. if useslines > 0 then
  225. formstring = formstring .. S("Mining durability:") .. "\n"
  226. formstring = formstring .. miningusesstr
  227. end
  228. if caplines > 0 or useslines > 0 or timelines > 0 then
  229. formstring = newline2(formstring)
  230. end
  231. end
  232. -- Weapon data
  233. local damage_groups = tool_capabilities.damage_groups
  234. if damage_groups ~= nil then
  235. formstring = formstring .. S("This is a melee weapon which deals damage by punching.") .. "\n"
  236. -- Damage groups
  237. formstring = formstring .. S("Maximum damage per hit:") .. "\n"
  238. for k,v in pairs(damage_groups) do
  239. formstring = formstring .. S("• @1: @2 HP", doc.sub.items.get_group_name(k), v)
  240. formstring = formstring .. "\n"
  241. end
  242. -- Full punch interval
  243. local punch = 1.0
  244. if tool_capabilities.full_punch_interval ~= nil then
  245. punch = tool_capabilities.full_punch_interval
  246. end
  247. formstring = formstring .. S("Full punch interval: @1 s", string.format("%.1f", punch))
  248. formstring = formstring .. "\n"
  249. end
  250. end
  251. return formstring
  252. end
  253. -- Pointing range of itmes
  254. local range_factoid = function(itemstring, def)
  255. local handrange = minetest.registered_items[""].range
  256. local itemrange = def.range
  257. if itemstring == "" then
  258. if handrange ~= nil then
  259. return S("Range: @1", itemrange)
  260. else
  261. return S("Range: 4")
  262. end
  263. else
  264. if handrange == nil then handrange = 4 end
  265. if itemrange ~= nil then
  266. return S("Range: @1", itemrange)
  267. else
  268. return S("Range: @1 (@2)", get_entry_name(""), handrange)
  269. end
  270. end
  271. end
  272. -- Smelting fuel factoid
  273. local factoid_fuel = function(itemstring, ctype)
  274. local formstring = ""
  275. local result, decremented = minetest.get_craft_result({method = "fuel", items = {itemstring}})
  276. if result ~= nil and result.time > 0 then
  277. local base
  278. local burntext = burntime_to_text(result.time)
  279. if ctype == "tools" then
  280. base = S("This tool can serve as a smelting fuel with a burning time of @1.", burntext)
  281. elseif ctype == "nodes" then
  282. base = S("This block can serve as a smelting fuel with a burning time of @1.", burntext)
  283. else
  284. base = S("This item can serve as a smelting fuel with a burning time of @1.", burntext)
  285. end
  286. formstring = formstring .. base
  287. local replaced = decremented.items[1]:get_name()
  288. if not decremented.items[1]:is_empty() and replaced ~= itemstring then
  289. formstring = formstring .. S(" Using it as fuel turns it into: @1.", description_for_formspec(replaced))
  290. end
  291. formstring = newline(formstring)
  292. end
  293. return formstring
  294. end
  295. -- Shows the itemstring of an item
  296. local factoid_itemstring = function(itemstring, playername)
  297. local privs = minetest.get_player_privs(playername)
  298. if doc.sub.items.settings.itemstring or (privs.give or privs.debug) then
  299. return S("Itemstring: \"@1\"", itemstring)
  300. else
  301. return ""
  302. end
  303. end
  304. local entry_image = function(data)
  305. local formstring = ""
  306. -- No image for air
  307. if data.itemstring ~= "air" then
  308. -- Hand
  309. if data.itemstring == "" then
  310. formstring = formstring .. "image["..(doc.FORMSPEC.ENTRY_END_X-1)..","..doc.FORMSPEC.ENTRY_START_Y..";1,1;"..
  311. minetest.registered_items[""].wield_image.."]"
  312. -- Other items
  313. elseif data.image ~= nil then
  314. formstring = formstring .. "image["..(doc.FORMSPEC.ENTRY_END_X-1)..","..doc.FORMSPEC.ENTRY_START_Y..";1,1;"..data.image.."]"
  315. else
  316. formstring = formstring .. "item_image["..(doc.FORMSPEC.ENTRY_END_X-1)..","..doc.FORMSPEC.ENTRY_START_Y..";1,1;"..data.itemstring.."]"
  317. end
  318. end
  319. return formstring
  320. end
  321. -- Stuff for factoids
  322. local factoid_generators = {}
  323. factoid_generators.nodes = {}
  324. factoid_generators.tools = {}
  325. factoid_generators.craftitems = {}
  326. --[[ Returns a list of all registered factoids for the specified category and type
  327. * category_id: Identifier of the Documentation System category in which the factoid appears
  328. * factoid_type: If set, oly returns factoid with a matching factoid_type.
  329. If nil, all factoids for this category will be generated
  330. * data: Entry data to parse ]]
  331. local factoid_custom = function(category_id, factoid_type, data)
  332. local ftable = factoid_generators[category_id]
  333. local datastring = ""
  334. -- Custom factoids are inserted here
  335. for i=1,#ftable do
  336. if factoid_type == nil or ftable[i].ftype == factoid_type then
  337. datastring = datastring .. ftable[i].fgen(data.itemstring, data.def)
  338. if datastring ~= "" then
  339. datastring = newline(datastring)
  340. end
  341. end
  342. end
  343. return datastring
  344. end
  345. -- Shows core information shared by all items, to be inserted at the top
  346. local factoids_header = function(data, ctype)
  347. local longdesc = data.longdesc
  348. local usagehelp = data.usagehelp
  349. local crafting = data.crafting
  350. local datastring = ""
  351. if longdesc ~= nil then
  352. datastring = datastring .. S("Description: @1", longdesc)
  353. datastring = newline2(datastring)
  354. end
  355. if usagehelp ~= nil then
  356. datastring = datastring .. S("Usage help: @1", usagehelp)
  357. datastring = newline2(datastring)
  358. end
  359. if crafting ~= nil then
  360. datastring = datastring .. crafting
  361. datastring = newline2(datastring)
  362. end
  363. datastring = datastring .. factoid_custom(ctype, "use", data)
  364. datastring = newline2(datastring)
  365. if data.itemstring ~= "" then
  366. datastring = datastring .. S("Maximum stack size: @1", data.def.stack_max)
  367. datastring = newline(datastring)
  368. end
  369. datastring = datastring .. range_factoid(data.itemstring, data.def)
  370. datastring = newline2(datastring)
  371. if data.def.liquids_pointable == true then
  372. if ctype == "nodes" then
  373. datastring = datastring .. S("This block points to liquids.").."\n"
  374. elseif ctype == "tools" then
  375. datastring = datastring .. S("This tool points to liquids.").."\n"
  376. elseif ctype == "craftitems" then
  377. datastring = datastring .. S("This item points to liquids.").."\n"
  378. end
  379. end
  380. if data.def.on_use ~= nil then
  381. if ctype == "nodes" then
  382. datastring = datastring .. S("Punches with this block don't work as usual; melee combat and mining are either not possible or work differently.").."\n"
  383. elseif ctype == "tools" then
  384. datastring = datastring .. S("Punches with this tool don't work as usual; melee combat and mining are either not possible or work differently.").."\n"
  385. elseif ctype == "craftitems" then
  386. datastring = datastring .. S("Punches with this item don't work as usual; melee combat and mining are either not possible or work differently.").."\n"
  387. end
  388. end
  389. datastring = newline(datastring)
  390. -- Show tool capability stuff, including durability if not overwritten by custom field
  391. local check_uses = false
  392. if ctype == "tools" then
  393. check_uses = data.def._doc_items_durability == nil
  394. end
  395. datastring = datastring .. factoid_toolcaps(data.def.tool_capabilities, check_uses)
  396. datastring = newline2(datastring)
  397. return datastring
  398. end
  399. -- Shows less important information shared by all items, to be inserted at the bottom
  400. local factoids_footer = function(data, playername, ctype)
  401. local datastring = ""
  402. datastring = datastring .. factoid_custom(ctype, "groups", data)
  403. datastring = newline2(datastring)
  404. -- Show other “exposable” groups
  405. local gstring, gcount = groups_to_string(data.def.groups, miscgroups)
  406. if gstring ~= nil then
  407. if gcount == 1 then
  408. if ctype == "nodes" then
  409. datastring = datastring .. S("This block belongs to the @1 group.", gstring) .. "\n"
  410. elseif ctype == "tools" then
  411. datastring = datastring .. S("This tool belongs to the @1 group.", gstring) .. "\n"
  412. elseif ctype == "craftitems" then
  413. datastring = datastring .. S("This item belongs to the @1 group.", gstring) .. "\n"
  414. end
  415. else
  416. if ctype == "nodes" then
  417. datastring = datastring .. S("This block belongs to these groups: @1.", gstring) .. "\n"
  418. elseif ctype == "tools" then
  419. datastring = datastring .. S("This tool belongs to these groups: @1.", gstring) .. "\n"
  420. elseif ctype == "craftitems" then
  421. datastring = datastring .. S("This item belongs to these groups: @1.", gstring) .. "\n"
  422. end
  423. end
  424. end
  425. datastring = newline2(datastring)
  426. -- Show fuel recipe
  427. datastring = datastring .. factoid_fuel(data.itemstring, ctype)
  428. datastring = newline2(datastring)
  429. -- Other custom factoids
  430. datastring = datastring .. factoid_custom(ctype, "misc", data)
  431. datastring = newline2(datastring)
  432. -- Itemstring
  433. datastring = datastring .. factoid_itemstring(data.itemstring, playername)
  434. return datastring
  435. end
  436. function doc.sub.items.register_factoid(category_id, factoid_type, factoid_generator)
  437. local ftable = { fgen = factoid_generator, ftype = factoid_type }
  438. if category_id == "nodes" or category_id == "tools" or category_id == "craftitems" then
  439. table.insert(factoid_generators[category_id], ftable)
  440. return true
  441. elseif category_id == nil then
  442. table.insert(factoid_generators.nodes, ftable)
  443. table.insert(factoid_generators.tools, ftable)
  444. table.insert(factoid_generators.craftitems, ftable)
  445. return false
  446. end
  447. end
  448. doc.add_category("nodes", {
  449. hide_entries_by_default = true,
  450. name = S("Blocks"),
  451. description = S("Item reference of blocks and other things which are capable of occupying space"),
  452. build_formspec = function(data, playername)
  453. if data then
  454. local formstring = ""
  455. local datastring = ""
  456. formstring = entry_image(data)
  457. datastring = factoids_header(data, "nodes")
  458. datastring = datastring .. S("Collidable: @1", yesno(data.def.walkable)) .. "\n"
  459. local liquid
  460. if data.def.liquidtype ~= "none" then liquid = true else liquid = false end
  461. if data.def.pointable == true then
  462. datastring = datastring .. S("Pointable: Yes") .. "\n"
  463. elseif liquid then
  464. datastring = datastring .. S("Pointable: Only by special items") .. "\n"
  465. else
  466. datastring = datastring .. S("Pointable: No") .. "\n"
  467. end
  468. datastring = newline2(datastring)
  469. if liquid then
  470. datastring = newline(datastring, false)
  471. datastring = datastring .. S("This block is a liquid with these properties:") .. "\n"
  472. local range, renew, viscos
  473. if data.def.liquid_range then range = data.def.liquid_range else range = 8 end
  474. if data.def.liquid_renewable ~= nil then renew = data.def.liquid_renewable else renew = true end
  475. if data.def.liquid_viscosity then viscos = data.def.liquid_viscosity else viscos = 0 end
  476. if renew then
  477. datastring = datastring .. S("• Renewable") .. "\n"
  478. else
  479. datastring = datastring .. S("• Not renewable") .. "\n"
  480. end
  481. if range == 0 then
  482. datastring = datastring .. S("• No flowing") .. "\n"
  483. else
  484. datastring = datastring .. S("• Flowing range: @1", range) .. "\n"
  485. end
  486. datastring = datastring .. S("• Viscosity: @1", viscos) .. "\n"
  487. end
  488. datastring = newline2(datastring)
  489. -- Global factoids
  490. --- Direct interaction with the player
  491. ---- Damage (very important)
  492. if data.def.damage_per_second ~= nil and data.def.damage_per_second > 1 then
  493. datastring = datastring .. S("This block causes a damage of @1 hit points per second.", data.def.damage_per_second) .. "\n"
  494. elseif data.def.damage_per_second == 1 then
  495. datastring = datastring .. S("This block causes a damage of @1 hit point per second.", data.def.damage_per_second) .. "\n"
  496. end
  497. if data.def.drowning then
  498. if data.def.drowning > 1 then
  499. datastring = datastring .. S("This block decreases your breath and causes a drowning damage of @1 hit points every 2 seconds.", data.def.drowning) .. "\n"
  500. elseif data.def.drowning == 1 then
  501. datastring = datastring .. S("This block decreases your breath and causes a drowning damage of @1 hit point every 2 seconds.", data.def.drowning) .. "\n"
  502. end
  503. end
  504. local fdap = data.def.groups.fall_damage_add_percent
  505. if fdap ~= nil then
  506. if fdap > 0 then
  507. datastring = datastring .. S("The fall damage on this block is increased by @1%.", fdap) .. "\n"
  508. elseif fdap <= -100 then
  509. datastring = datastring .. S("This block negates all fall damage.") .. "\n"
  510. else
  511. datastring = datastring .. S("The fall damage on this block is reduced by @1%.", math.abs(fdap)) .. "\n"
  512. end
  513. end
  514. datastring = datastring .. factoid_custom("nodes", "damage", data)
  515. datastring = newline2(datastring)
  516. ---- Movement
  517. if data.def.groups.disable_jump == 1 then
  518. datastring = datastring .. S("You can not jump while standing on this block.").."\n"
  519. end
  520. if data.def.climbable == true then
  521. datastring = datastring .. S("This block can be climbed.").."\n"
  522. end
  523. local bouncy = data.def.groups.bouncy
  524. if bouncy ~= nil then
  525. datastring = datastring .. S("This block will make you bounce off with an elasticity of @1%.", bouncy).."\n"
  526. end
  527. datastring = datastring .. factoid_custom("nodes", "movement", data)
  528. datastring = newline2(datastring)
  529. ---- Sounds
  530. local function is_silent(def, soundtype)
  531. return type(def.sounds) ~= "table" or def.sounds[soundtype] == nil or def.sounds[soundtype] == "" or (type(data.def.sounds[soundtype]) == "table" and (data.def.sounds[soundtype].name == nil or data.def.sounds[soundtype].name == ""))
  532. end
  533. local silentstep, silentdig, silentplace = false, false, false
  534. if data.def.walkable and is_silent(data.def, "footstep") then
  535. silentstep = true
  536. end
  537. if data.def.diggable and is_silent(data.def, "dig") and is_silent(data.def, "dug") then
  538. silentdig = true
  539. end
  540. if is_silent(data.def, "place") and is_silent(data.def, "place_failed") and data.itemstring ~= "air" then
  541. silentplace = true
  542. end
  543. if silentstep and silentdig and silentplace then
  544. datastring = datastring .. S("This block is completely silent when walked on, mined or built.").."\n"
  545. elseif silentdig and silentplace then
  546. datastring = datastring .. S("This block is completely silent when mined or built.").."\n"
  547. else
  548. if silentstep then
  549. datastring = datastring .. S("Walking on this block is completely silent.").."\n"
  550. end
  551. if silentdig then
  552. datastring = datastring .. S("Mining this block is completely silent.").."\n"
  553. end
  554. if silentplace then
  555. datastring = datastring .. S("Building this block is completely silent.").."\n"
  556. end
  557. end
  558. datastring = datastring .. factoid_custom("nodes", "sound", data)
  559. datastring = newline2(datastring)
  560. -- Block activity
  561. --- Gravity
  562. if data.def.groups.falling_node == 1 then
  563. datastring = datastring .. S("This block is affected by gravity and can fall.").."\n"
  564. end
  565. datastring = datastring .. factoid_custom("nodes", "gravity", data)
  566. datastring = newline2(datastring)
  567. --- Dropping and destruction
  568. if data.def.buildable_to == true then
  569. datastring = datastring .. S("Building another block at this block will place it inside and replace it.").."\n"
  570. if data.def.walkable then
  571. datastring = datastring .. S("Falling blocks can go through this block; they destroy it when doing so.").."\n"
  572. end
  573. end
  574. if data.def.walkable == false then
  575. if data.def.buildable_to == false and data.def.drop ~= "" then
  576. datastring = datastring .. S("This block will drop as an item when a falling block ends up inside it.").."\n"
  577. else
  578. datastring = datastring .. S("This block is destroyed when a falling block ends up inside it.").."\n"
  579. end
  580. end
  581. if data.def.groups.attached_node == 1 then
  582. if data.def.paramtype2 == "wallmounted" then
  583. datastring = datastring .. S("This block will drop as an item when it is not attached to a surrounding block.").."\n"
  584. else
  585. datastring = datastring .. S("This block will drop as an item when no collidable block is below it.").."\n"
  586. end
  587. end
  588. if data.def.floodable == true then
  589. datastring = datastring .. S("Liquids can flow into this block and destroy it.").."\n"
  590. end
  591. datastring = datastring .. factoid_custom("nodes", "drop_destroy", data)
  592. datastring = newline2(datastring)
  593. -- Block appearance
  594. --- Light
  595. if data.def.light_source then
  596. if data.def.light_source > 3 then
  597. datastring = datastring .. S("This block is a light source with a light level of @1.", data.def.light_source).."\n"
  598. elseif data.def.light_source > 0 then
  599. datastring = datastring .. S("This block glows faintly with a light level of @1.", data.def.light_source).."\n"
  600. end
  601. if data.def.paramtype == "light" and data.def.sunlight_propagates then
  602. datastring = datastring .. S("This block allows light to propagate with a small loss of brightness, and sunlight can even go through losslessly.").."\n"
  603. elseif data.def.paramtype == "light" then
  604. datastring = datastring .. S("This block allows light to propagate with a small loss of brightness.").."\n"
  605. elseif data.def.sunlight_propagates then
  606. datastring = datastring .. S("This block allows sunlight to propagate without loss in brightness.").."\n"
  607. end
  608. end
  609. datastring = datastring .. factoid_custom("nodes", "light", data)
  610. datastring = newline2(datastring)
  611. --- List nodes/groups to which this node connects to
  612. if data.def.connects_to ~= nil then
  613. local nodes = {}
  614. local groups = {}
  615. for c=1,#data.def.connects_to do
  616. local itemstring = data.def.connects_to[c]
  617. if string.sub(itemstring,1,6) == "group:" then
  618. groups[string.sub(itemstring,7,#itemstring)] = 1
  619. else
  620. table.insert(nodes, itemstring)
  621. end
  622. end
  623. local nstring = ""
  624. for n=1,#nodes do
  625. local name
  626. if item_name_overrides[nodes[n]] ~= nil then
  627. name = item_name_overrides[nodes[n]]
  628. else
  629. name = description_for_formspec(minetest.registered_nodes[nodes[n]])
  630. end
  631. if n > 1 then
  632. nstring = nstring .. S(", ")
  633. end
  634. if name ~= nil then
  635. nstring = nstring .. name
  636. else
  637. nstring = nstring .. S("Unknown Node")
  638. end
  639. end
  640. if #nodes == 1 then
  641. datastring = datastring .. S("This block connects to this block: @1.", nstring) .. "\n"
  642. elseif #nodes > 1 then
  643. datastring = datastring .. S("This block connects to these blocks: @1.", nstring) .. "\n"
  644. end
  645. local gstring, gcount = groups_to_string(groups)
  646. if gcount == 1 then
  647. datastring = datastring .. S("This block connects to blocks of the @1 group.", gstring) .. "\n"
  648. elseif gcount > 1 then
  649. datastring = datastring .. S("This block connects to blocks of the following groups: @1.", gstring) .. "\n"
  650. end
  651. end
  652. datastring = newline2(datastring)
  653. -- Mining groups
  654. datastring = datastring .. factoid_custom("nodes", "mining", data)
  655. datastring = newline(datastring)
  656. if data.def.pointable ~= false and (data.def.liquid_type == "none" or data.def.liquid_type == nil) then
  657. -- Check if there are no mining groups at all
  658. local nogroups = true
  659. for groupname,_ in pairs(mininggroups) do
  660. if data.def.groups[groupname] ~= nil or groupname == "dig_immediate" then
  661. nogroups = false
  662. break
  663. end
  664. end
  665. -- dig_immediate
  666. if data.def.drop ~= "" then
  667. if data.def.groups.dig_immediate == 2 then
  668. datastring = datastring .. S("This block can be mined by any mining tool in half a second.").."\n"
  669. elseif data.def.groups.dig_immediate == 3 then
  670. datastring = datastring .. S("This block can be mined by any mining tool immediately.").."\n"
  671. -- Note: “unbreakable” is an unofficial group for undiggable blocks
  672. elseif data.def.diggable == false or nogroups or data.def.groups.immortal == 1 or data.def.groups.unbreakable == 1 then
  673. datastring = datastring .. S("This block can not be mined by ordinary mining tools.").."\n"
  674. end
  675. else
  676. if data.def.groups.dig_immediate == 2 then
  677. datastring = datastring .. S("This block can be destroyed by any mining tool in half a second.").."\n"
  678. elseif data.def.groups.dig_immediate == 3 then
  679. datastring = datastring .. S("This block can be destroyed by any mining tool immediately.").."\n"
  680. elseif data.def.diggable == false or nogroups or data.def.groups.immortal == 1 or data.def.groups.unbreakable == 1 then
  681. datastring = datastring .. S("This block can not be destroyed by ordinary mining tools.").."\n"
  682. end
  683. end
  684. -- Expose “ordinary” mining groups (crumbly, cracky, etc.) and level group
  685. -- Skip this for immediate digging to avoid redundancy
  686. if data.def.groups.dig_immediate ~= 3 then
  687. local mstring = S("This block can be mined by mining tools which match any of the following mining ratings and its toughness level.").."\n"
  688. mstring = mstring .. S("Mining ratings:").."\n"
  689. local minegroupcount = 0
  690. for group,_ in pairs(mininggroups) do
  691. local rating = data.def.groups[group]
  692. if rating ~= nil then
  693. mstring = mstring .. S("• @1: @2", doc.sub.items.get_group_name(group), rating).."\n"
  694. minegroupcount = minegroupcount + 1
  695. end
  696. end
  697. local level = data.def.groups.level
  698. if not level then
  699. level = 0
  700. end
  701. mstring = mstring .. S("Toughness level: @1", level).."\n"
  702. if minegroupcount > 0 then
  703. datastring = datastring .. mstring
  704. end
  705. end
  706. end
  707. datastring = newline2(datastring)
  708. -- Non-default drops
  709. --[[
  710. if data.def.drop ~= nil and data.def.drop ~= data.itemstring and data.itemstring ~= "air" then
  711. -- TODO: Calculate drop probabilities of max > 1 like for max == 1
  712. local get_desc = function(stack)
  713. return description_for_formspec(stack:get_name())
  714. end
  715. if data.def.drop == "" then
  716. datastring = datastring .. S("This block won't drop anything when mined.").."\n"
  717. elseif type(data.def.drop) == "string" then
  718. local dropstack = ItemStack(data.def.drop)
  719. if dropstack:get_name() ~= data.itemstring and dropstack:get_name() ~= 1 then
  720. local desc = get_desc(dropstack)
  721. local count = dropstack:get_count()
  722. if count > 1 then
  723. datastring = datastring .. S("This block will drop the following when mined: @1×@2.", count, desc).."\n"
  724. else
  725. datastring = datastring .. S("This block will drop the following when mined: @1.", desc).."\n"
  726. end
  727. end
  728. elseif type(data.def.drop) == "table" and data.def.drop.items ~= nil then
  729. local max = data.def.drop.max_items
  730. local dropstring = ""
  731. local dropstring_base = ""
  732. if max == nil then
  733. dropstring_base = S("This block will drop the following items when mined: %s.")
  734. elseif max == 1 then
  735. if #data.def.drop.items == 1 then
  736. dropstring_base = S("This block will drop the following when mined: %s.")
  737. else
  738. dropstring_base = S("This block will randomly drop one of the following when mined: %s.")
  739. end
  740. else
  741. dropstring_base = S("This block will randomly drop up to %d drops of the following possible drops when mined: %s.")
  742. end
  743. -- Save calculated probabilities into a table for later output
  744. local probtables = {}
  745. local probtable
  746. local rarity_history = {}
  747. for i=1,#data.def.drop.items do
  748. local local_rarity = data.def.drop.items[i].rarity
  749. local chance = 1
  750. local rarity = 1
  751. if local_rarity == nil then
  752. local_rarity = 1
  753. end
  754. if max == 1 then
  755. -- Chained probability
  756. table.insert(rarity_history, local_rarity)
  757. chance = 1
  758. for r=1, #rarity_history do
  759. local chance_factor
  760. if r > 1 and rarity_history[r-1] == 1 then
  761. chance = 0
  762. break
  763. end
  764. if r == #rarity_history then
  765. chance_factor = 1/rarity_history[r]
  766. else
  767. chance_factor = (rarity_history[r]-1)/rarity_history[r]
  768. end
  769. chance = chance * chance_factor
  770. end
  771. if chance > 0 then
  772. rarity = 1/chance
  773. end
  774. else
  775. rarity = local_rarity
  776. chance = 1/rarity
  777. end
  778. -- Exclude impossible drops
  779. if chance > 0 then
  780. probtable = {}
  781. probtable.items = {}
  782. for j=1,#data.def.drop.items[i].items do
  783. local dropstack = ItemStack(data.def.drop.items[i].items[j])
  784. local itemstring = dropstack:get_name()
  785. local desc = get_desc(dropstack)
  786. local count = dropstack:get_count()
  787. if not(itemstring == nil or itemstring == "" or count == 0) then
  788. if probtable.items[itemstring] == nil then
  789. probtable.items[itemstring] = {desc = desc, count = count}
  790. else
  791. probtable.items[itemstring].count = probtable.items[itemstring].count + count
  792. end
  793. end
  794. end
  795. probtable.rarity = rarity
  796. if #data.def.drop.items[i].items > 0 then
  797. table.insert(probtables, probtable)
  798. end
  799. end
  800. end
  801. -- Do some cleanup of the probability table
  802. if max == 1 or max == nil then
  803. -- Sort by rarity
  804. local comp = function(p1, p2)
  805. return p1.rarity < p2.rarity
  806. end
  807. table.sort(probtables, comp)
  808. end
  809. -- Output probability table
  810. local pcount = 0
  811. for i=1, #probtables do
  812. if pcount > 0 then
  813. -- List seperator
  814. dropstring = dropstring .. S(", ")
  815. end
  816. local probtable = probtables[i]
  817. local icount = 0
  818. local dropstring_this = ""
  819. for _, itemtable in pairs(probtable.items) do
  820. if icount > 0 then
  821. -- Final list seperator
  822. dropstring_this = dropstring_this .. S(" and ")
  823. end
  824. local desc = S(itemtable.desc)
  825. local count = itemtable.count
  826. if count ~= 1 then
  827. desc = S("@1×@2", count, desc)
  828. end
  829. dropstring_this = dropstring_this .. desc
  830. icount = icount + 1
  831. end
  832. local rarity = probtable.rarity
  833. local raritystring = ""
  834. -- No percentage if there's only one possible guaranteed drop
  835. if not(rarity == 1 and #data.def.drop.items == 1) then
  836. local chance = (1/rarity)*100
  837. if rarity > 200 then -- <0.5%
  838. -- For very low percentages
  839. dropstring_this = S("@1 (<0.5%)", dropstring_this)
  840. else
  841. -- Add circa indicator for percentages with decimal point
  842. local fchance = string.format("%.0f", chance)
  843. if math.fmod(chance, 1) > 0 then
  844. dropstring_this = S("@1 (ca. @2%)", dropstring_this, fchance)
  845. else
  846. dropstring_this = S("@1 (@2%)", dropstring_this, fchance)
  847. end
  848. end
  849. end
  850. dropstring = dropstring .. dropstring_this
  851. pcount = pcount + 1
  852. end
  853. if max ~= nil and max > 1 then
  854. datastring = datastring .. string.format(dropstring_base, max, dropstring)
  855. else
  856. datastring = datastring .. string.format(dropstring_base, dropstring)
  857. end
  858. datastring = newline(datastring)
  859. end
  860. --]]
  861. --end
  862. --datastring = newline2(datastring)
  863. datastring = datastring .. factoids_footer(data, playername, "nodes")
  864. formstring = formstring .. doc.widgets.text(datastring, nil, nil, doc.FORMSPEC.ENTRY_WIDTH - 1.2)
  865. return formstring
  866. else
  867. return "label[0,1;NO DATA AVALIABLE!]"
  868. end
  869. end
  870. })
  871. doc.add_category("tools", {
  872. hide_entries_by_default = true,
  873. name = S("Tools and weapons"),
  874. description = S("Item reference of all wieldable tools and weapons"),
  875. sorting = "function",
  876. -- Roughly sort tools based on their capabilities. Tools which dig the same stuff end up in the same group
  877. sorting_data = function(entry1, entry2)
  878. local entries = { entry1, entry2 }
  879. -- Hand beats all
  880. if entries[1].eid == "" then return true end
  881. if entries[2].eid == "" then return false end
  882. local comp = {}
  883. for e=1, 2 do
  884. comp[e] = {}
  885. end
  886. -- No tool capabilities: Instant loser
  887. if entries[1].data.def.tool_capabilities == nil and entries[2].data.def.tool_capabilities ~= nil then return false end
  888. if entries[2].data.def.tool_capabilities == nil and entries[1].data.def.tool_capabilities ~= nil then return true end
  889. -- No tool capabilities for both: Compare by uses
  890. if entries[1].data.def.tool_capabilities == nil and entries[2].data.def.tool_capabilities == nil then
  891. for e=1, 2 do
  892. if type(entries[e].data.def._doc_items_durability) == "number" then
  893. comp[e].uses = entries[e].data.def._doc_items_durability
  894. else
  895. comp[e].uses = 0
  896. end
  897. end
  898. return comp[1].uses > comp[2].uses
  899. end
  900. for e=1, 2 do
  901. comp[e].gc = entries[e].data.def.tool_capabilities.groupcaps
  902. end
  903. -- No group capabilities = instant loser
  904. if comp[1].gc == nil then return false end
  905. if comp[2].gc == nil then return true end
  906. for e=1, 2 do
  907. local groups = {}
  908. local gc = comp[e].gc
  909. local group = nil
  910. local mintime = nil
  911. local groupcount = 0
  912. local uses = nil
  913. for k,v in pairs(gc) do
  914. local maxlevel = v.maxlevel
  915. if maxlevel == nil then
  916. maxlevel = 1
  917. end
  918. if groupcount == 0 then
  919. group = k
  920. uses = v.uses * math.pow(3, v.maxlevel)
  921. end
  922. for rating, time in pairs(v.times) do
  923. local realtime = time / v.maxlevel
  924. if mintime == nil or realtime < mintime then
  925. mintime = realtime
  926. end
  927. end
  928. if groups[k] ~= true then
  929. groupcount = groupcount + 1
  930. groups[k] = true
  931. end
  932. end
  933. comp[e].count = groupcount
  934. comp[e].group = group
  935. comp[e].mintime = mintime
  936. if uses ~= nil then
  937. comp[e].uses = uses
  938. elseif type(entries[e].data.def._doc_items_durability) == "number" then
  939. comp[e].uses = entries[e].data.def._doc_items_durability
  940. else
  941. comp[e].uses = 0
  942. end
  943. end
  944. -- We want to sort out digging tools with multiple capabilities
  945. if comp[1].count > 1 and comp[1].count > comp[2].count then
  946. return false
  947. elseif comp[1].group == comp[2].group then
  948. -- Tiebreaker 1: Minimum digging time
  949. if comp[1].mintime == comp[2].mintime then
  950. -- Tiebreaker 2: Use count
  951. return comp[1].uses > comp[2].uses
  952. else
  953. return comp[1].mintime < comp[2].mintime
  954. end
  955. -- Final tiebreaker: Sort by group name
  956. else
  957. return comp[1].group < comp[2].group
  958. end
  959. end,
  960. build_formspec = function(data, playername)
  961. if data then
  962. local formstring = ""
  963. local datastring = ""
  964. formstring = entry_image(data)
  965. datastring = factoids_header(data, "tools")
  966. -- Overwritten durability info
  967. if type(data.def._doc_items_durability) == "number" then
  968. -- Fixed number of uses
  969. datastring = datastring .. S("Durability: @1 uses", data.def._doc_items_durability)
  970. datastring = newline2(datastring)
  971. elseif type(data.def._doc_items_durability) == "string" then
  972. -- Manually described durability
  973. datastring = datastring .. S("Durability: @1", data.def._doc_items_durability)
  974. datastring = newline2(datastring)
  975. end
  976. datastring = datastring .. factoids_footer(data, playername, "tools")
  977. formstring = formstring .. doc.widgets.text(datastring, nil, nil, doc.FORMSPEC.ENTRY_WIDTH - 1.2)
  978. return formstring
  979. else
  980. return "label[0,1;NO DATA AVALIABLE!]"
  981. end
  982. end
  983. })
  984. doc.add_category("craftitems", {
  985. hide_entries_by_default = true,
  986. name = S("Miscellaneous items"),
  987. description = S("Item reference of items which are neither blocks, tools or weapons (esp. crafting items)"),
  988. build_formspec = function(data, playername)
  989. if data then
  990. local formstring = ""
  991. local datastring = ""
  992. formstring = entry_image(data)
  993. datastring = factoids_header(data, "craftitems")
  994. datastring = datastring .. factoids_footer(data, playername, "craftitems")
  995. formstring = formstring .. doc.widgets.text(datastring, nil, nil, doc.FORMSPEC.ENTRY_WIDTH - 1.2)
  996. return formstring
  997. else
  998. return "label[0,1;NO DATA AVALIABLE!]"
  999. end
  1000. end
  1001. })
  1002. -- Register group definition stuff
  1003. -- More (user-)friendly group names to replace the rather technical names
  1004. -- for better understanding
  1005. function doc.sub.items.add_friendly_group_names(groupnames)
  1006. for internal, real in pairs(groupnames) do
  1007. groupdefs[internal] = real
  1008. end
  1009. end
  1010. -- Adds groups to be displayed in the generic “misc.” groups
  1011. -- factoid. Those groups should be neither be used as mining
  1012. -- groups nor as damage groups and should be relevant to the
  1013. -- player in someway.
  1014. function doc.sub.items.add_notable_groups(groupnames)
  1015. for g=1,#groupnames do
  1016. miscgroups[groupnames[g]] = true
  1017. end
  1018. end
  1019. -- Collect information about all items
  1020. local function gather_descs()
  1021. -- Internal help texts for default items
  1022. local help = {
  1023. longdesc = {},
  1024. usagehelp = {},
  1025. }
  1026. -- 1st pass: Gather groups of interest
  1027. for id, def in pairs(minetest.registered_items) do
  1028. -- Gather all groups used for mining
  1029. if def.tool_capabilities ~= nil then
  1030. local groupcaps = def.tool_capabilities.groupcaps
  1031. if groupcaps ~= nil then
  1032. for k,v in pairs(groupcaps) do
  1033. if mininggroups[k] ~= true then
  1034. mininggroups[k] = true
  1035. end
  1036. end
  1037. end
  1038. end
  1039. -- ... and gather all groups which appear in crafting recipes
  1040. local crafts = minetest.get_all_craft_recipes(id)
  1041. if crafts ~= nil then
  1042. for c=1,#crafts do
  1043. for k,v in pairs(crafts[c].items) do
  1044. if string.sub(v,1,6) == "group:" then
  1045. local groupstring = string.sub(v,7,-1)
  1046. local groups = string.split(groupstring, ",")
  1047. for g=1, #groups do
  1048. miscgroups[groups[g]] = true
  1049. end
  1050. end
  1051. end
  1052. end
  1053. end
  1054. -- ... and gather all groups used in connects_to
  1055. if def.connects_to ~= nil then
  1056. for c=1, #def.connects_to do
  1057. if string.sub(def.connects_to[c],1,6) == "group:" then
  1058. local group = string.sub(def.connects_to[c],7,-1)
  1059. miscgroups[group] = true
  1060. end
  1061. end
  1062. end
  1063. end
  1064. -- 2nd pass: Add entries
  1065. -- Set default air text
  1066. -- Custom longdesc and usagehelp may be set by mods through the add_helptexts function
  1067. if minetest.registered_items["air"]._doc_items_longdesc then
  1068. help.longdesc["air"] = minetest.registered_items["air"]._doc.items_longdesc
  1069. else
  1070. help.longdesc["air"] = S("A transparent block, basically empty space. It is usually left behind after digging something.")
  1071. end
  1072. if minetest.registered_items["ignore"]._doc_items_create_entry ~= nil then
  1073. suppressed["ignore"] = minetest.registered_items["ignore"]._doc_items_create_entry == true
  1074. end
  1075. -- Add entry for the default tool (“hand”)
  1076. -- Custom longdesc and usagehelp may be set by mods through the add_helptexts function
  1077. local handdef = minetest.registered_items[""]
  1078. if handdef._doc_items_create_entry ~= false then
  1079. if handdef._doc_items_longdesc then
  1080. help.longdesc[""] = handdef._doc_items_longdesc
  1081. else
  1082. -- Default text
  1083. help.longdesc[""] = S("Whenever you are not wielding any item, you use the hand which acts as a tool with its own capabilities. When you are wielding an item which is not a mining tool or a weapon it will behave as if it would be the hand.")
  1084. end
  1085. if handdef._doc_items_entry_name then
  1086. item_name_overrides[""] = handdef._doc_items_entry_name
  1087. end
  1088. doc.add_entry("tools", "", {
  1089. name = item_name_overrides[""],
  1090. hidden = handdef._doc_items_hidden == true,
  1091. data = {
  1092. longdesc = help.longdesc[""],
  1093. usagehelp = help.usagehelp[""],
  1094. itemstring = "",
  1095. def = handdef,
  1096. }
  1097. })
  1098. end
  1099. local add_entries = function(deftable, category_id)
  1100. for id, def in pairs(deftable) do
  1101. local name, ld, uh, im, cr
  1102. local forced = false
  1103. if def._doc_items_create_entry == true and def ~= nil then forced = true end
  1104. name = get_entry_name(id)
  1105. if not (((def.description == nil or def.description == "") and def._doc_items_entry_name == nil) or (def._doc_items_create_entry == false) or (suppressed[id] == true)) or forced then
  1106. if def._doc_items_longdesc then
  1107. ld = def._doc_items_longdesc
  1108. end
  1109. if help.longdesc[id] ~= nil then
  1110. ld = help.longdesc[id]
  1111. end
  1112. if def._doc_items_usagehelp then
  1113. uh = def._doc_items_usagehelp
  1114. end
  1115. if help.usagehelp[id] ~= nil then
  1116. uh = help.usagehelp[id]
  1117. end
  1118. if def._doc_items_image then
  1119. im = def._doc_items_image
  1120. end
  1121. if def._doc_items_crafting then
  1122. cr = def._doc_items_crafting
  1123. end
  1124. local hidden
  1125. if id == "air" or id == "" then hidden = false end
  1126. if type(def._doc_items_hidden) == "boolean" then
  1127. hidden = def._doc_items_hidden
  1128. end
  1129. local custom_image
  1130. name = scrub_newlines(name)
  1131. local infotable = {
  1132. name = name,
  1133. hidden = hidden,
  1134. data = {
  1135. longdesc = ld,
  1136. usagehelp = uh,
  1137. crafting = cr,
  1138. image = im,
  1139. itemstring = id,
  1140. def = def,
  1141. }
  1142. }
  1143. doc.add_entry(category_id, id, infotable)
  1144. end
  1145. end
  1146. end
  1147. -- Add node entries
  1148. add_entries(minetest.registered_nodes, "nodes")
  1149. -- Add tool entries
  1150. add_entries(minetest.registered_tools, "tools")
  1151. -- Add craftitem entries
  1152. add_entries(minetest.registered_craftitems, "craftitems")
  1153. end
  1154. --[[ Reveal items as the player progresses through the game.
  1155. Items are revealed by:
  1156. * Digging, punching or placing node,
  1157. * Crafting
  1158. * Having item in inventory (not instantly revealed) ]]
  1159. local function reveal_item(playername, itemstring)
  1160. local category_id
  1161. if itemstring == nil or itemstring == "" or playername == nil or playername == "" then
  1162. return false
  1163. end
  1164. if minetest.registered_nodes[itemstring] ~= nil then
  1165. category_id = "nodes"
  1166. elseif minetest.registered_tools[itemstring] ~= nil then
  1167. category_id = "tools"
  1168. elseif minetest.registered_craftitems[itemstring] ~= nil then
  1169. category_id = "craftitems"
  1170. elseif minetest.registered_items[itemstring] ~= nil then
  1171. category_id = "craftitems"
  1172. else
  1173. return false
  1174. end
  1175. doc.mark_entry_as_revealed(playername, category_id, itemstring)
  1176. return true
  1177. end
  1178. local function reveal_items_in_inventory(player)
  1179. local inv = player:get_inventory()
  1180. local list = inv:get_list("main")
  1181. for l=1, #list do
  1182. reveal_item(player:get_player_name(), list[l]:get_name())
  1183. end
  1184. end
  1185. minetest.register_on_dignode(function(pos, oldnode, digger)
  1186. if digger == nil then return end
  1187. local playername = digger:get_player_name()
  1188. if playername ~= nil and playername ~= "" and oldnode ~= nil then
  1189. reveal_item(playername, oldnode.name)
  1190. reveal_items_in_inventory(digger)
  1191. end
  1192. end)
  1193. minetest.register_on_punchnode(function(pos, node, puncher, pointed_thing)
  1194. if puncher == nil then return end
  1195. local playername = puncher:get_player_name()
  1196. if playername ~= nil and playername ~= "" and node ~= nil then
  1197. reveal_item(playername, node.name)
  1198. end
  1199. end)
  1200. minetest.register_on_placenode(function(pos, newnode, placer, oldnode, itemstack, pointed_thing)
  1201. if placer == nil then return end
  1202. local playername = placer:get_player_name()
  1203. if playername ~= nil and playername ~= "" and itemstack ~= nil and not itemstack:is_empty() then
  1204. reveal_item(playername, itemstack:get_name())
  1205. end
  1206. end)
  1207. minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
  1208. if player == nil then return end
  1209. local playername = player:get_player_name()
  1210. if playername ~= nil and playername ~= "" and itemstack ~= nil and not itemstack:is_empty() then
  1211. reveal_item(playername, itemstack:get_name())
  1212. end
  1213. end)
  1214. minetest.register_on_item_eat(function(hp_change, replace_with_item, itemstack, user, pointed_thing)
  1215. if user == nil then return end
  1216. local playername = user:get_player_name()
  1217. if playername ~= nil and playername ~= "" and itemstack ~= nil and not itemstack:is_empty() then
  1218. reveal_item(playername, itemstack:get_name())
  1219. if replace_with_item ~= nil then
  1220. reveal_item(playername, replace_with_item)
  1221. end
  1222. end
  1223. end)
  1224. minetest.register_on_joinplayer(function(player)
  1225. reveal_items_in_inventory(player)
  1226. end)
  1227. --[[ Periodically check all items in player inventory and reveal them all.
  1228. TODO: Check whether there's a serious performance impact on servers with many players.
  1229. TODO: If possible, try to replace this functionality by updating the revealed items as
  1230. soon the player obtained a new item (probably needs new Minetest callbacks). ]]
  1231. local checktime = 8
  1232. local timer = 0
  1233. minetest.register_globalstep(function(dtime)
  1234. timer = timer + dtime
  1235. if timer > checktime then
  1236. local players = minetest.get_connected_players()
  1237. for p=1, #players do
  1238. reveal_items_in_inventory(players[p])
  1239. end
  1240. timer = math.fmod(timer, checktime)
  1241. end
  1242. end)
  1243. minetest.after(0, gather_descs)