333 lines
10 KiB
Lua
333 lines
10 KiB
Lua
--- Code related to LaTeX generation.
|
|
-- @module advtrains_doc_integration.latex
|
|
local latex = {}
|
|
local utils = advtrains_doc_integration.utils
|
|
|
|
--- Escape string in LaTeX.
|
|
-- @tparam string str The string to escape.
|
|
-- @treturn string The escaped string.
|
|
function latex.escape(str)
|
|
return (string.gsub(str, ".", {
|
|
["&"] = [[\&]],
|
|
["%"] = [[\%]],
|
|
["$"] = [[\$]],
|
|
["#"] = [[\#]],
|
|
["_"] = [[\_]],
|
|
["{"] = [[\{]],
|
|
["}"] = [[\}]],
|
|
["~"] = [[\textasciitilde]],
|
|
["^"] = [[\textasciicircum]],
|
|
["\\"] = [[\textbackslash]],
|
|
}))
|
|
end
|
|
|
|
--- Escape a translated string in LaTeX.
|
|
-- @tparam string lang The language to use for server-side translation
|
|
-- @tparam string str The string to escape.
|
|
-- @treturn The escaped string.
|
|
function latex.escape_translated(lang, str)
|
|
return latex.escape(minetest.get_translated_string(lang, str))
|
|
end
|
|
|
|
local function SL(str)
|
|
return latex.escape_translated("en", str)
|
|
end
|
|
|
|
--- Describe a color in LaTeX.
|
|
-- @tparam string cstr The color string.
|
|
-- @treturn string The string describing the color.
|
|
function latex.describe_color(cstr)
|
|
local color = string.match(cstr,"^#(%x%x%x%x%x%x)$")
|
|
cstr = SL(cstr)
|
|
if color then
|
|
color = SL(string.upper(color))
|
|
return string.format([[\tikz \definecolor{c}{HTML}{%s} \draw[fill=c] (0,0) rectangle (1em,1em); \texttt{%s}]], color, cstr)
|
|
else
|
|
return string.format([[\texttt{%s}]], cstr)
|
|
end
|
|
end
|
|
|
|
--- Describe a coupler in LaTeX.
|
|
-- @tparam string coupler The name of the coupler.
|
|
-- @treturn string The string describing the coupler.
|
|
function latex.describe_coupler(coupler)
|
|
local name = utils.get_coupler_name(coupler)
|
|
if name then
|
|
return ([[%s (\texttt{%s})]]):format(SL(name), SL(coupler))
|
|
else
|
|
return ([[\texttt{%s}]]):format(SL(coupler))
|
|
end
|
|
end
|
|
|
|
--- Describe a wagon prototype in LaTeX.
|
|
-- @tparam string itemname The item name of the wagon prototype.
|
|
-- @treturn string The description of the prototype.
|
|
function latex.describe_wagon_prototype(itemname)
|
|
local prototype = advtrains_doc_integration.prototypes[itemname]
|
|
local wname = ItemStack(itemname):get_short_description()
|
|
local st = {string.format([[
|
|
\documentclass{article}
|
|
\usepackage[a4paper,margin=1in,bottom=1.5in]{geometry}
|
|
\usepackage[T1]{fontenc}
|
|
\usepackage{tikz}
|
|
\usepackage{booktabs,multirow,tabularx}
|
|
\renewcommand{\arraystretch}{1.5}
|
|
\usepackage{hyperref}
|
|
\hypersetup{pdftitle={Wagon Datasheet: %s}}
|
|
\title{Wagon Datasheet}
|
|
\author{%s}
|
|
\setlength{\parindent}{0pt}
|
|
\begin{document}
|
|
\maketitle
|
|
]], SL(wname), SL(wname))}
|
|
|
|
table.insert(st, [[\section{Basic Information}]])
|
|
if prototype.longdesc then
|
|
table.insert(st, SL(prototype.longdesc) .. "\n")
|
|
end
|
|
table.insert(st, [[\begin{tabularx}{\textwidth}{l X}]])
|
|
table.insert(st, string.format([[Itemstring & \texttt{%s}\\]], SL(itemname)))
|
|
if prototype.drives_on then
|
|
local i0 = #st+1
|
|
local count = 0
|
|
for k in pairs(prototype.drives_on) do
|
|
table.insert(st, string.format([[& \texttt{%s}\\]], SL(k)))
|
|
count = count + 1
|
|
end
|
|
if count > 0 then
|
|
st[i0] = string.format([[Drives on %s]], st[i0])
|
|
end
|
|
end
|
|
if prototype.wagon_span then
|
|
table.insert(st, string.format([[Wagon span & %d mm\\]], prototype.wagon_span*2000))
|
|
end
|
|
if prototype.max_speed then
|
|
table.insert(st, string.format([[Maximum speed & %d m/s\\]], prototype.max_speed))
|
|
end
|
|
table.insert(st, string.format([[Motive power & %s\\]], prototype.is_locomotive and "Present" or "Absent"))
|
|
if prototype.horn_sound then
|
|
table.insert(st, string.format([[Horn sound & \texttt{%s}\\]], SL(prototype.horn_sound.name)))
|
|
else
|
|
table.insert(st, [[Horn sound & Undefined\\]])
|
|
end
|
|
if prototype.mesh then
|
|
table.insert(st, string.format([[Mesh & \texttt{%s}\\]], SL(prototype.mesh)))
|
|
end
|
|
if prototype.textures then
|
|
local i0 = #st+1
|
|
local count = 0
|
|
for _, i in pairs(prototype.textures) do
|
|
table.insert(st, string.format([[& \texttt{%s}\\]], SL(i)))
|
|
count = count + 1
|
|
end
|
|
if count > 0 then
|
|
st[i0] = string.format([[Textures %s]], st[i0])
|
|
end
|
|
end
|
|
do
|
|
local i0 = #st+1
|
|
local count = 0
|
|
for _, i in ipairs(prototype.drops or {}) do
|
|
local item = ItemStack(i)
|
|
if not item:is_empty() then
|
|
local desc = string.format([[\texttt{%s}]], SL(item:get_name()))
|
|
if item:is_known() then
|
|
desc = SL(item:get_short_description())
|
|
end
|
|
table.insert(st, string.format([[& %s: %d\\]], desc, item:get_count()))
|
|
count = count + 1
|
|
end
|
|
end
|
|
if count > 0 then
|
|
st[i0] = [[Drops ]] .. st[i0]
|
|
else
|
|
table.insert(st, [[Drops & Nothing \\]])
|
|
end
|
|
end
|
|
table.insert(st, [[\end{tabularx}]])
|
|
|
|
table.insert(st, [[\section{Coupler Compatibility}]])
|
|
do
|
|
local fcouplers = prototype.coupler_types_front
|
|
local rcouplers = prototype.coupler_types_back
|
|
local ccouplers = {}
|
|
local lcouplers = {}
|
|
local couplerid = {}
|
|
local flim, rlim
|
|
for k in pairs(fcouplers or {}) do
|
|
flim = true
|
|
ccouplers[k] = true
|
|
end
|
|
for k in pairs(rcouplers or {}) do
|
|
rlim = true
|
|
ccouplers[k] = true
|
|
end
|
|
for k in pairs(ccouplers) do
|
|
local desc = latex.describe_coupler(k)
|
|
table.insert(lcouplers, desc)
|
|
couplerid[desc] = k
|
|
end
|
|
table.sort(lcouplers)
|
|
table.insert(st, [[
|
|
\begin{tabularx}{\textwidth}{X c c}
|
|
\toprule
|
|
\multirow[t]{2}{*}{\bfseries Coupler Type} & \multicolumn{2}{c}{\bfseries Compatibility}\\
|
|
\cmidrule(lr){2-3}
|
|
& {\bfseries Front Coupler} & {\bfseries Rear Coupler}\\\midrule
|
|
]])
|
|
if not (fcouplers and rcouplers) then
|
|
local fd = fcouplers and "" or [[$\bullet$]]
|
|
local rd = rcouplers and "" or [[$\bullet$]]
|
|
table.insert(st, string.format([[\textit{Universal}&%s&%s\\]], fd, rd))
|
|
end
|
|
for i = 1, #lcouplers do
|
|
local cdesc = lcouplers[i]
|
|
local cid = couplerid[cdesc]
|
|
local fd, rd = "", ""
|
|
if flim then
|
|
fd = fcouplers[cid] and [[$\bullet$]] or ""
|
|
elseif not fcouplers then
|
|
fd = [[$\Uparrow$]]
|
|
end
|
|
if rlim then
|
|
rd = rcouplers[cid] and [[$\bullet$]] or ""
|
|
elseif not rcouplers then
|
|
rd = [[$\Uparrow$]]
|
|
end
|
|
table.insert(st, string.format([[%s&%s&%s\\]], cdesc, fd, rd))
|
|
end
|
|
table.insert(st, [[\bottomrule]])
|
|
table.insert(st, [[\end{tabularx}]])
|
|
end
|
|
|
|
local hasinv = prototype.has_inventory
|
|
local hasseats = prototype.max_seats>0
|
|
local taliquid = prototype.techage_liquid_capacity or 0
|
|
if hasinv or hasseats or taliquid>0 then
|
|
table.insert(st, [[\section{Wagon Capacity}]])
|
|
if hasseats then
|
|
table.insert(st, [[
|
|
\begin{tabularx}{\textwidth}{X c c}
|
|
\toprule
|
|
{\bfseries Seat Group} & {\bfseries Driver Stand} & {\bfseries Seat Count}\\\midrule
|
|
]])
|
|
for _, d in pairs(prototype.seat_groups) do
|
|
table.insert(st, string.format([[%s & %s & %d\\]], SL(d.name), d.driving_ctrl_access and [[$\bullet$]] or "", d.count))
|
|
end
|
|
table.insert(st, [[\bottomrule]])
|
|
table.insert(st, [[\end{tabularx}]])
|
|
end
|
|
if hasinv then
|
|
if next(prototype.inventory_list_sizes or {}) ~= nil then
|
|
table.insert(st, [[
|
|
\begin{tabularx}{\textwidth}{X c}
|
|
\toprule
|
|
{\bfseries Inventory Name} & {\bfseries Capacity}\\\midrule
|
|
]])
|
|
for k, v in pairs(prototype.inventory_list_sizes) do
|
|
table.insert(st, string.format([[\texttt{%s} & %d\\]], SL(k), v))
|
|
end
|
|
table.insert(st, [[\bottomrule]])
|
|
table.insert(st, [[\end{tabularx}]])
|
|
else
|
|
table.insert(st, [[This wagon has an inventory of unknown size.]])
|
|
end
|
|
end
|
|
if taliquid > 0 then
|
|
table.insert(st, string.format([[
|
|
\begin{tabularx}{\textwidth}{X l}
|
|
{Liquid Capacity (Techage)} & %d
|
|
\end{tabularx}
|
|
]], taliquid))
|
|
end
|
|
end
|
|
|
|
if prototype.set_livery then
|
|
if prototype.livery_definition then
|
|
table.insert(st, [[\section{Multi-Component Liveries}]])
|
|
local components = prototype.livery_definition.components
|
|
local presets = prototype.livery_definition.presets
|
|
table.insert(st, [[\subsection*{Components}]])
|
|
table.insert(st, [[\begin{itemize}]])
|
|
for _, c in ipairs(components) do
|
|
table.insert(st, string.format([[\item %s]], SL(c.description)))
|
|
end
|
|
table.insert(st, [[\end{itemize}]])
|
|
for _, p in ipairs(presets) do
|
|
table.insert(st, string.format([[\subsection*{Preset: %s}]], SL(p.description)))
|
|
table.insert(st, [[
|
|
\begin{tabularx}{\textwidth}{X c}
|
|
\toprule
|
|
{\bfseries Component} & {\bfseries Color} \\\midrule
|
|
]])
|
|
for _, c in ipairs(p.livery_stack.layers) do
|
|
local cdesc = SL(components[c.component].description)
|
|
table.insert(st, string.format([[%s & %s\\]], cdesc, latex.describe_color(c.color)))
|
|
end
|
|
table.insert(st, [[
|
|
\bottomrule
|
|
\end{tabularx}
|
|
]])
|
|
end
|
|
else
|
|
table.insert(st, [[\section{Livery System (Bike Painter)}]])
|
|
table.insert(st, [[This wagon can be painted by the bike painter.]])
|
|
end
|
|
end
|
|
|
|
local dlxlivdef = prototype.dlxtrains_livery
|
|
if dlxlivdef then
|
|
table.insert(st, [[
|
|
\section{DlxTrains Livery Sytem}
|
|
This wagon can be customized with DlxTrains' livery system.
|
|
]])
|
|
end
|
|
|
|
local atlivdef = prototype.advtrains_livery_tools
|
|
if atlivdef then
|
|
table.insert(st, [[\section{Advtrains Livery Tool (Marnack)}]])
|
|
for _, tname in ipairs(atlivdef.template_names) do
|
|
local tdef = atlivdef.templates[tname]
|
|
table.insert(st, string.format([[\subsection*{Template: %s}]], SL(tname)))
|
|
table.insert(st, SL(tdef.notes))
|
|
table.insert(st, "")
|
|
if #tdef.overlays > 0 then
|
|
table.insert(st, "This template contains the following components:")
|
|
table.insert(st, [[\begin{itemize}]])
|
|
for _, overlay in ipairs(tdef.overlays) do
|
|
table.insert(st, string.format([[\item %s]], SL(overlay.name)))
|
|
end
|
|
table.insert(st, [[\end{itemize}]])
|
|
else
|
|
table.insert(st, "This template does not appear to contain any (customizable) component.")
|
|
end
|
|
end
|
|
for _, lname in ipairs(atlivdef.livery_names) do
|
|
local ldef = atlivdef.liveries[lname]
|
|
local tname = ldef.livery_template_name
|
|
table.insert(st, string.format([[\subsection*{Preset: %s}]], SL(lname)))
|
|
table.insert(st, string.format([[Template: %s]], SL(tname)))
|
|
table.insert(st, "")
|
|
table.insert(st, [[
|
|
\begin{tabularx}{\textwidth}{X c}
|
|
\toprule
|
|
{\bfseries Component} & {\bfseries Color}\\\midrule]])
|
|
for _, overlay in pairs(ldef.overlays) do
|
|
local cname = atlivdef.templates[tname].overlays[overlay.id].name
|
|
table.insert(st, string.format([[%s & %s\\]], SL(cname), latex.describe_color(overlay.color)))
|
|
end
|
|
table.insert(st, [[
|
|
\bottomrule
|
|
\end{tabularx}
|
|
]])
|
|
end
|
|
end
|
|
|
|
table.insert(st, [[
|
|
\end{document}
|
|
]])
|
|
return table.concat(st, "\n")
|
|
end
|
|
|
|
return latex
|