local S = minetest.get_translator "advtrains_doc_integration" local D = advtrains_doc_integration.describe local H = advtrains_doc_integration.hypertext local utils = advtrains_doc_integration.utils local fsescape = minetest.formspec_escape local function S2(a, b) return S(a, S(b)) end local function addlist(lst, tbl, title, fallback1, fallback2, mapf) if not tbl then if fallback2 then table.insert(lst, fallback2) elseif fallback2 == false and fallback1 then table.insert(lst, fallback1) end elseif next(tbl) ~= nil then table.insert(lst, title) for k, v in pairs(tbl) do if mapf then k = mapf(k, v) end table.insert(lst, H.listitem(k, true)) end elseif fallback1 then table.insert(lst, fallback1) end end local function list_itemstring(x) local item = ItemStack(x) if item:is_empty() then return S("Emptyness") end return string.format("%s: %d", item:get_short_description(), item:get_count()) end local function blankline(st) return table.insert(st, "") end local wlivprev = {} local function get_livery_preview_selection(pname, itemname) return (wlivprev[pname] or {})[itemname] or 0 end local function get_livery_preview(itemname, id) local tx = (advtrains_doc_integration.prototypes[itemname] or {}).livery_textures return tx[id] or tx[0] end local function render_livery_textures(pname, itemname) local str = table.concat(utils.map(get_livery_preview(itemname, get_livery_preview_selection(pname, itemname)), fsescape), ",") return str end local function set_livery_preview_selection(pname, itemname, id) local t = wlivprev[pname] if not t then t = {} wlivprev[pname] = t end t[itemname] = id end local function doc_render_wagon_information(prototype, pname) local desctext = {} if prototype._doc_wagon_longdesc then table.insert(desctext, tostring(prototype._doc_wagon_longdesc)) blankline(desctext) end table.insert(desctext, H.header(S("Basic Information"))) table.insert(desctext, S("Itemstring: @1", H.mono(prototype.name))) addlist(desctext, prototype.drops, S("Drops:"), S("Drops nothing"), false, function(_, v) return list_itemstring(v) end) addlist(desctext, prototype.drives_on, S("Drives on:"), nil, nil, H.mono) addlist(desctext, prototype.coupler_types_front, S("Compatible front couplers:"), S2("Front coupler: @1", "Absent"), S2("Front coupler: @1", "Universal"), utils.get_coupler_name) addlist(desctext, prototype.coupler_types_back, S("Compatible rear couplers:"), S2("Rear coupler: @1", "Absent"), S2("Rear coupler: @1", "Universal"), utils.get_couple_name) table.insert(desctext, S("Wagon span: @1", prototype.wagon_span and D.length(2*prototype.wagon_span) or S("Undefined"))) table.insert(desctext, S("Maximum speed: @1", prototype.max_speed and D.speed(prototype.max_speed) or S("Undefined"))) table.insert(desctext, S2("Motive power: @1", prototype.is_locomotive and "Present" or "Absent")) table.insert(desctext, S("Horn sound: @1", H.describe_sound("playhorn", prototype.horn_sound))) if prototype.doors.open.sound or prototype.doors.close.sound then table.insert(desctext, S("Door sound: @1 (when opening), @2 (when closing)", H.describe_sound("playdooropen", prototype.doors.open.sound), H.describe_sound("playdoorclose", prototype.doors.close.sound))) else table.insert(desctext, S2("Door sound: @1", "Undefined")) end blankline(desctext) table.insert(desctext, H.header(S("Wagon Capacity"))) table.insert(desctext, S("Passenger seats: @1", prototype.max_passengers)) table.insert(desctext, S("Driver seats: @1", prototype.max_drivers)) if prototype.has_inventory then addlist(desctext, prototype.inventory_list_sizes, S("Cargo inventory size:"), S2("Cargo inventory: @1", "Present"), false, function(k, v) return string.format("%s: %d", H.mono(k), v) end) else table.insert(desctext, S2("Cargo inventory: @1", "Absent")) end if techage and prototype.techage_liquid_capacity then table.insert(desctext, S("Liquid Capacity (Techage): @1", string.format("%d", prototype.techage_liquid_capacity))) end blankline(desctext) table.insert(desctext, H.header(S("Wagon Appearance"))) table.insert(desctext, S("Mesh: @1", prototype.mesh and H.mono(prototype.mesh) or "None")) addlist(desctext, prototype.textures, S("Textures:"), S("No textures"), false, function(_, v) return H.mono(v) end) local livsel = get_livery_preview_selection(pname, prototype.name) local livrst = (livsel ~= 0 and not prototype.dlxtrains_livery) and " " .. H.action("preview_0", S("[Reset Preview]")) or "" local livids = 0 local function livprev(desc) livids = livids+1 local label = H.plain(desc) if livids == livsel then label = H.bold(desc) end return H.action(string.format("preview_%d", livids), label, true) end local dlxlivdef = prototype.dlxtrains_livery table.insert(desctext, S2("DlxTrains livery system: @1", dlxlivdef and "Supported" or "Unsupported")) if dlxlivdef then livids = -1 table.insert(desctext, "Livery presets:") for k = 0, dlxlivdef.count-1 do table.insert(desctext, H.listitem(string.format("%s (%s, %s)", H.mono(dlxlivdef[k].code), livprev(S("default")), livprev(S("weathered"))), true)) end end local bikeliv = S("Unsupported") local bikelivdesc = nil if prototype.set_livery then if prototype.livery_definition then bikeliv = S("Supported by the multi_component_liveries mod") bikelivdesc = {} addlist(bikelivdesc, prototype.livery_definition.components, S("Livery components:"), nil, nil, function(_, v) return H.plain(v.description) end) addlist(bikelivdesc, prototype.livery_definition.presets, S("Livery presets:") .. livrst, nil, nil, function(_, v) return livprev(v.description) end) bikelivdesc = table.concat(bikelivdesc, "\n") else bikeliv = S("Supported") end end table.insert(desctext, S("Livery system with bike painter: @1", bikeliv)) table.insert(desctext, bikelivdesc) local atlivdef = prototype.advtrains_livery_tools table.insert(desctext, S2("Advtrains livery tools (Marnack): @1", atlivdef and "Supported" or "Unsupported")) if atlivdef then addlist(desctext, atlivdef.template_names, S("Livery templates:"), nil, nil, function(_, v) return H.plain(v) end) addlist(desctext, atlivdef.livery_names, S("Livery presets:") .. livrst, nil, nil, function(_, v) return livprev(v) end) end blankline(desctext) table.insert(desctext, H.header(S("Implementation Details"))) local attachment_offset_support = S("Unsupported") if advtrains_attachment_offset_patch then local t = advtrains_attachment_offset_patch if prototype.get_on == t.get_on_override and prototype.get_off == t.get_off_override then attachment_offset_support = S("Supported") end end table.insert(desctext, S("Proper player attachment positioning: @1", attachment_offset_support)) for k, v in pairs { custom_on_activate = "Custom instantiation callback", custom_on_step = "Custom step function", custom_on_velocity_change = "Custom velocity change callback", } do table.insert(desctext, S2(v .. ": @1", prototype[k] and "Defined" or "Undefined")) end local x0, y0 = doc.FORMSPEC.ENTRY_START_X+0.25, doc.FORMSPEC.ENTRY_START_Y local x1, y1 = doc.FORMSPEC.ENTRY_END_X+0.75, doc.FORMSPEC.ENTRY_END_Y+0.625 local width, height = x1-x0, y1-y0 local mside = height/2 local mesh = fsescape(prototype.mesh or "") local textures = render_livery_textures(pname, prototype.name) local fstext = { string.format("hypertext[%f,%f;%f,%f;entry_body;%s]", x0, y0, width-mside, height+0.875, fsescape(table.concat(desctext, "\n"))), string.format("item_image[%f,%f;%f,%f;%s]", x1-mside, y0+0.0625, mside, mside, fsescape(prototype.name)), string.format("model[%f,%f;%f,%f;%s;%s;%s;%f,%f]", x1-mside, y1-mside, mside, mside, "wagon_model", mesh, textures, -30, 135), } return table.concat(fstext, "\n") end if doc then advtrains_doc_integration.register_on_prototype_loaded(function(itemname, prototype) minetest.override_item(itemname, {_doc_items_create_entry = false}) doc.add_entry("advtrains_wagons", itemname, { name = ItemStack(itemname):get_short_description(), data = prototype, }) if doc.sub.identifier then doc.sub.identifier.register_object(itemname, "advtrains_wagons", itemname) end end) if doc.sub.items then local register_factoid = doc.sub.items.register_factoid local function ndef_field_factoid(cat, ftype, f, ...) local ftp = type(f) if ftp == "string" then local desc = f f = function(x) if x ~= nil then return desc end end end local keys = {...} local idx = function(t) for _, k in ipairs(keys) do if type(t) ~= "table" then return nil end t = t[k] end return t end local function fgen(_, def) return f(idx(def)) or "" end return register_factoid(cat, ftype, fgen) end local function group_factoid(cat, gr, f) local function func(x) return f(x or 0) end return ndef_field_factoid(cat, "groups", func, "groups", gr) end for cat, cinfo in pairs{ nodes = { not_blocking_trains = S("This block does not block trains."), save_in_at_nodedb = S("This block is saved in the Advtrains node database."), }, } do for group, ginfo in pairs(cinfo) do local tp = type(ginfo) if tp == "string" then group_factoid(cat, group, function(x) if x > 0 then return ginfo end end) elseif tp == "function" then group_factoid(cat, group, ginfo) end end end for fname, t in pairs { advtrains = { on_train_enter = S("This track reacts to passing trains."), on_train_approach = S("This track reacts to approaching trains."), }, luaautomation = { fire_event = S("This block handles LuaATC events."), }, } do for subfname, val in pairs(t) do local function f(x) if x ~= nil then return val end end ndef_field_factoid("nodes", "groups", f, fname, subfname) end end register_factoid("nodes", "groups", function(_, ndef) if ndef.advtrains then local atdef = ndef.advtrains if atdef.set_aspect then return S("This is a signal with a variable aspect.") elseif atdef.get_aspect then return S("This is a signal with a static aspect.") end end if ndef.at_conns then return S("This track has the following conns table by default: @1", D.conns(ndef.at_conns) or "?") end return "" end) end doc.add_category("advtrains_wagons", { name = S("Wagons"), build_formspec = doc_render_wagon_information, }) end minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= "doc:entry" then return end local pname = player:get_player_name() local cat, ent = doc.get_selection(pname) if cat ~= "advtrains_wagons" or ent == nil then return end local act = fields.entry_body local prototype = advtrains_doc_integration.prototypes[ent] local sounds = { ["action:playhorn"] = prototype.horn_sound, ["action:playdooropen"] = prototype.doors.open.sound, ["action:playdoorclose"] = prototype.doors.close.sound, } if not act then return elseif sounds[act] then minetest.sound_play(sounds[act], {to_player = pname}, true) else local txid = string.match(act, [[^action:preview_(%d+)$]]) txid = tonumber(txid) if txid then set_livery_preview_selection(pname, ent, txid) doc.show_entry(pname, cat, ent) end end end)