Module:Engineers
-- Module:Engineers -- Reads canonical Engineer facts from Module:Data/Engineers/<Name> (JSON -- content-model pages) and formats them for three consumers: an Engineer's -- own infobox (via Template:Engineer infobox), List of Engineers, and -- Engineer Capability Comparison. One record, one module, three consumers -- -- see Elite Dangerous Field Manual:Adding Structured Data. -- -- Adding a new engineer: create Module:Data/Engineers/<Name> in the same -- shape as the existing four, then append the name to -- Module:Data/Engineers/index. Don't edit this module unless you're -- changing the schema itself.
local p = {}
-- Field order/labels shared by both the JSON-backed path and the manual
-- fallback path, so
produces
-- the same shape of infobox whether or not a JSON record exists yet. local FIELD_ORDER = { { key = 'engineer_type', label = 'Engineer type', group = 'ENGINEER' }, { key = 'system', label = 'System' }, { key = 'body', label = 'Body' }, { key = 'facility', label = 'Facility' }, { key = 'region', label = 'Region' }, { key = 'allegiance', label = 'Allegiance' }, { key = 'specialties', label = 'Specialties' }, { key = 'max_grade', label = 'Maximum grade' }, { key = 'prerequisite_engineer', label = 'Prerequisite', group = 'ACCESS' }, { key = 'discovery_requirement', label = 'Discovery' }, { key = 'invitation_requirement', label = 'Invitation' }, { key = 'unlock_requirement', label = 'Unlock' }, }
local function loadRecord(name) local title = mw.title.new('Data/Engineers/' .. name, 'Module') if not title then return nil end local content = title:getContent() if not content then return nil end local ok, data = pcall(mw.text.jsonDecode, content) if not ok then return nil end return data end
local function loadIndex() local title = mw.title.new('Data/Engineers/index', 'Module') local content = title and title:getContent() if not content then return {} end local ok, data = pcall(mw.text.jsonDecode, content) if not ok then return {} end return data end
local function joinSpecialties(d) if d.specialties and type(d.specialties) == 'table' then return table.concat(d.specialties, ', ') end return d.specialties end
-- Builds a plain { key = displayValue } table from either a JSON record -- or manually-supplied template args, using the same FIELD_ORDER either -- way. local function buildFields(d, pargs) local fields = {} if d then for _, f in ipairs(FIELD_ORDER) do fields[f.key] = d[f.key] end fields.specialties = joinSpecialties(d) if d.prerequisite_engineer then local note = d.prerequisite_engineer_note and (' ' .. d.prerequisite_engineer_note) or fields.prerequisite_engineer = '' .. d.prerequisite_engineer .. '' .. note else fields.prerequisite_engineer = d.prerequisite_engineer_display or 'None — available from the start' end else for _, f in ipairs(FIELD_ORDER) do fields[f.key] = pargs[f.key] end end
-- Infobox pages may override the structured data directly in the article -- template call. This keeps the sidebar editable from page edit/source -- while still letting JSON records provide defaults and power comparison -- tables. Empty parameters do not erase structured defaults. for _, f in ipairs(FIELD_ORDER) do if pargs[f.key] ~= nil and pargs[f.key] ~= then fields[f.key] = pargs[f.key] end end
return fields end
--
, called from Template:Engineer infobox.
-- Falls back to whatever manual named params were passed if no JSON -- record exists yet, so the wrapper template is safe to adopt one page at -- a time rather than needing every engineer's data backfilled first. function p.infobox(frame) local parent = frame:getParent() local pargs = parent and parent.args or {} local name = pargs.name or mw.title.getCurrentTitle().text local d = loadRecord(name) local fields = buildFields(d, pargs)
local image = pargs.image if ( image == nil or image == ) and d and d.image then image = d.image end
local args = { name = name, image = image } local n = 0 for _, f in ipairs(FIELD_ORDER) do local value = fields[f.key] if value ~= nil and value ~= then n = n + 1 if f.group then args['group' .. n] = f.group end args['label' .. n] = f.label args['row' .. n] = value end end
return frame:expandTemplate{ title = 'Infobox', args = args } end
--
| Engineer | System | Specialties | Maximum grade |
|---|---|---|---|
| Felicity Farseer | Deciat | Frame Shift Drive, Detailed Surface Scanner, Sensors, Thrusters, Frame Shift Drive Interdictor, Power Plant, Shield Booster | Grade 5 |
| Elvira Martuuk | Khun | Frame Shift Drive, Shield Generator, Thrusters, Shield Cell Bank | Grade 5 |
| Marco Qwent | Sirius | Power Plant, Power Distributor | Grade 4 |
| Professor Palin | Arque | Thrusters, Frame Shift Drive | Grade 5 |
| Chloe Sedesi | Shenve | Thrusters, Frame Shift Drive | Grade 5 |
| Lori Jameson | Shinrarta Dezhra | Sensors, Detailed Surface Scanner, Auto Field-Maintenance Unit, Fuel Scoop, Life Support, Refinery, Shield Cell Bank, Frame Shift Wake Scanner, Kill Warrant Scanner, Manifest Scanner | Grade 5 |
| The Dweller | Wyrd | Power Distributor, Pulse Laser, Beam Laser, Burst Laser | Grade 5 |
| Lei Cheung | Laksak | Shield Generator, Detailed Surface Scanner, Sensors, Shield Booster | Grade 5 |
| Ram Tah | Meene | Chaff Launcher, Collector Limpet Controller, Electronic Countermeasure, Fuel Transfer Limpet Controller, Heat Sink Launcher, Point Defence, Prospector Limpet Controller, Cargo Rack, Hatch Breaker Limpet Controller, Guardian Gauss Cannon, Guardian Plasma Charger, Guardian Shard Cannon | Grade 5 |
| Marsha Hicks | Tir | Cannon, Fragment Cannon, Multi-Cannon, Collector Limpet Controller, Fuel Scoop, Fuel Transfer Limpet Controller, Hatch Breaker Limpet Controller, Prospector Limpet Controller, Refinery | Grade 5 |
| Tod "The Blaster" McQuinn | Wolf 397 | Multi-Cannon, Rail Gun, Fragment Cannon, Cannon | Grade 5 |
| Selene Jean | Kuk | Armour, Hull Reinforcement Package, Module Reinforcement Package | Grade 5 |
| Bill Turner | Alioth | Plasma Accelerator, Sensors, Detailed Surface Scanner, Cargo Rack, Auto Field-Maintenance Unit, Frame Shift Wake Scanner, Fuel Scoop, Kill Warrant Scanner, Life Support, Manifest Scanner, Refinery | Grade 5 |
| Didi Vatermann | Leesti | Shield Booster, Shield Generator | Grade 5 |
| Petra Olmanova | Asura | Armour, Hull Reinforcement Package, Auto Field-Maintenance Unit, Chaff Launcher, Electronic Countermeasure, Heat Sink Launcher, Point Defence, Mine Launcher, Missile Rack, Seeker Missile Rack, Torpedo Pylon, Module Reinforcement Package | Grade 5 |
| Liz Ryder | Eurybia | Missile Rack, Seeker Missile Rack, Torpedo Pylon, Mine Launcher, Armour, Hull Reinforcement Package | Grade 5 |
| Hera Tani | Kuwemaki | Power Plant, Power Distributor, Sensors, Detailed Surface Scanner | Grade 5 |
| Broo Tarquin | Muang | Beam Laser, Burst Laser, Pulse Laser | Grade 5 |
| Tiana Fortune | Achenar | Collector Limpet Controller, Frame Shift Wake Scanner, Fuel Transfer Limpet Controller, Hatch Breaker Limpet Controller, Kill Warrant Scanner, Manifest Scanner, Prospector Limpet Controller, Sensors, Cargo Rack, Detailed Surface Scanner, Frame Shift Drive Interdictor | Grade 5 |
| Etienne Dorn | Los | Detailed Surface Scanner, Frame Shift Wake Scanner, Kill Warrant Scanner, Life Support, Manifest Scanner, Plasma Accelerator, Power Distributor, Power Plant, Rail Gun, Sensors | Grade 5 |
| Juri Ishmaak | Giryak | Detailed Surface Scanner, Mine Launcher, Sensors, Abrasion Blaster, Enzyme Missile Rack, Mining Laser, Seeker Missile Rack, Frame Shift Wake Scanner, Kill Warrant Scanner, Manifest Scanner, Missile Rack, Torpedo Pylon | Grade 5 |
| The Sarge | Beta-3 Tucani | Cannon, Collector Limpet Controller, Fuel Transfer Limpet Controller, Hatch Breaker Limpet Controller, Prospector Limpet Controller, Rail Gun | Grade 5 |
| Colonel Bris Dekker | Sol | Frame Shift Drive Interdictor, Frame Shift Drive | Grade 4 |
| Mel Brandon | Luchtaine | Beam Laser, Burst Laser, Pulse Laser, Frame Shift Drive, Frame Shift Drive Interdictor, Shield Booster, Shield Generator, Thrusters, Shield Cell Bank | Grade 5 |
| Zacariah Nemo | Yoru | Fragment Cannon, Multi-Cannon, Plasma Accelerator | Grade 5 |
| Hero Ferrari | Siris | — | Not yet confirmed |
| Wellington Beck | Jolapa | — | Not yet confirmed |
| Uma Laszlo | Xuane | — | Not yet confirmed |
| Jude Navarro | Aurai | — | Not yet confirmed |
| Terra Velasquez | Shou Xing | — | Not yet confirmed |
| Oden Geiger | Candiaei | — | Not yet confirmed |
| Domino Green | Orishis | — | Not yet confirmed |
| Kit Fowler | Capoya | — | Not yet confirmed |
| Yarden Bond | Bayan | — | Not yet confirmed |
| Baltanos | Deriso | — | Not yet confirmed |
| Eleanor Bresa | Desy | — | Not yet confirmed |
| Rosa Dayette | Kojeara | — | Not yet confirmed |
| Yi Shen | Einheriar | — | Not yet confirmed |
, used by List of Engineers.
function p.list() local rows = {} for _, name in ipairs(loadIndex()) do local d = loadRecord(name) if d then table.insert(rows, string.format( '|-\n| %s || %s || %s || %s', d.name, d.system or '—', joinSpecialties(d) or '—', d.max_grade or 'Not yet confirmed' )) end end return '{| class="wikitable sortable"\n! Engineer !! System !! Specialties !! Maximum grade\n' .. table.concat(rows, '\n') .. '\n|}' end
--
| Engineer | Specialties | Prerequisite Engineer | Unlock requirement |
|---|---|---|---|
| Felicity Farseer | Frame Shift Drive, Detailed Surface Scanner, Sensors, Thrusters, Frame Shift Drive Interdictor, Power Plant, Shield Booster | None — independent starting Engineer | Not yet confirmed |
| Elvira Martuuk | Frame Shift Drive, Shield Generator, Thrusters, Shield Cell Bank | None — independent starting Engineer | Not yet confirmed |
| Marco Qwent | Power Plant, Power Distributor | Elvira Martuuk | Not yet confirmed |
| Professor Palin | Thrusters, Frame Shift Drive | Marco Qwent | Not yet confirmed |
| Chloe Sedesi | Thrusters, Frame Shift Drive | Marco Qwent | Not yet confirmed |
| Lori Jameson | Sensors, Detailed Surface Scanner, Auto Field-Maintenance Unit, Fuel Scoop, Life Support, Refinery, Shield Cell Bank, Frame Shift Wake Scanner, Kill Warrant Scanner, Manifest Scanner | Marco Qwent | Not yet confirmed |
| The Dweller | Power Distributor, Pulse Laser, Beam Laser, Burst Laser | None — independent starting Engineer | Not yet confirmed |
| Lei Cheung | Shield Generator, Detailed Surface Scanner, Sensors, Shield Booster | The Dweller | Not yet confirmed |
| Ram Tah | Chaff Launcher, Collector Limpet Controller, Electronic Countermeasure, Fuel Transfer Limpet Controller, Heat Sink Launcher, Point Defence, Prospector Limpet Controller, Cargo Rack, Hatch Breaker Limpet Controller, Guardian Gauss Cannon, Guardian Plasma Charger, Guardian Shard Cannon | Lei Cheung | Not yet confirmed |
| Marsha Hicks | Cannon, Fragment Cannon, Multi-Cannon, Collector Limpet Controller, Fuel Scoop, Fuel Transfer Limpet Controller, Hatch Breaker Limpet Controller, Prospector Limpet Controller, Refinery | The Dweller | Not yet confirmed |
| Tod "The Blaster" McQuinn | Multi-Cannon, Rail Gun, Fragment Cannon, Cannon | None — independent starting Engineer | Not yet confirmed |
| Selene Jean | Armour, Hull Reinforcement Package, Module Reinforcement Package | Tod "The Blaster" McQuinn | Not yet confirmed |
| Bill Turner | Plasma Accelerator, Sensors, Detailed Surface Scanner, Cargo Rack, Auto Field-Maintenance Unit, Frame Shift Wake Scanner, Fuel Scoop, Kill Warrant Scanner, Life Support, Manifest Scanner, Refinery | Selene Jean | Not yet confirmed |
| Didi Vatermann | Shield Booster, Shield Generator | Selene Jean | Not yet confirmed |
| Petra Olmanova | Armour, Hull Reinforcement Package, Auto Field-Maintenance Unit, Chaff Launcher, Electronic Countermeasure, Heat Sink Launcher, Point Defence, Mine Launcher, Missile Rack, Seeker Missile Rack, Torpedo Pylon, Module Reinforcement Package | Tod "The Blaster" McQuinn | Not yet confirmed |
| Liz Ryder | Missile Rack, Seeker Missile Rack, Torpedo Pylon, Mine Launcher, Armour, Hull Reinforcement Package | None — independent starting Engineer | Not yet confirmed |
| Hera Tani | Power Plant, Power Distributor, Sensors, Detailed Surface Scanner | Liz Ryder | Not yet confirmed |
| Broo Tarquin | Beam Laser, Burst Laser, Pulse Laser | Hera Tani | Not yet confirmed |
| Tiana Fortune | Collector Limpet Controller, Frame Shift Wake Scanner, Fuel Transfer Limpet Controller, Hatch Breaker Limpet Controller, Kill Warrant Scanner, Manifest Scanner, Prospector Limpet Controller, Sensors, Cargo Rack, Detailed Surface Scanner, Frame Shift Drive Interdictor | Hera Tani | Not yet confirmed |
| Etienne Dorn | Detailed Surface Scanner, Frame Shift Wake Scanner, Kill Warrant Scanner, Life Support, Manifest Scanner, Plasma Accelerator, Power Distributor, Power Plant, Rail Gun, Sensors | Liz Ryder | Not yet confirmed |
| Juri Ishmaak | Detailed Surface Scanner, Mine Launcher, Sensors, Abrasion Blaster, Enzyme Missile Rack, Mining Laser, Seeker Missile Rack, Frame Shift Wake Scanner, Kill Warrant Scanner, Manifest Scanner, Missile Rack, Torpedo Pylon | Felicity Farseer | 100,000 CR or 1,000,000 CR worth of Federal Combat Bonds — the determining condition is not established, so treat the value shown on your own Engineer invitation as authoritative |
| The Sarge | Cannon, Collector Limpet Controller, Fuel Transfer Limpet Controller, Hatch Breaker Limpet Controller, Prospector Limpet Controller, Rail Gun | Juri Ishmaak | Not yet confirmed |
| Colonel Bris Dekker | Frame Shift Drive Interdictor, Frame Shift Drive | Juri Ishmaak | Provide either 1,000,000 CR or 10,000,000 CR worth of Federal Combat Bonds — the determining condition is not currently established; use the value shown in your own Engineer invitation. |
| Mel Brandon | Beam Laser, Burst Laser, Pulse Laser, Frame Shift Drive, Frame Shift Drive Interdictor, Shield Booster, Shield Generator, Thrusters, Shield Cell Bank | Elvira Martuuk | Not yet confirmed |
| Zacariah Nemo | Fragment Cannon, Multi-Cannon, Plasma Accelerator | Elvira Martuuk | Not yet confirmed |
| Hero Ferrari | — | None — independent starting Odyssey Engineer | Not yet confirmed |
| Wellington Beck | — | Hero Ferrari | Not yet confirmed |
| Uma Laszlo | — | Wellington Beck | Not yet confirmed |
| Jude Navarro | — | None — independent starting Odyssey Engineer | Not yet confirmed |
| Terra Velasquez | — | Jude Navarro | Not yet confirmed |
| Oden Geiger | — | Terra Velasquez | Not yet confirmed |
| Domino Green | — | None — independent starting Odyssey Engineer | Not yet confirmed |
| Kit Fowler | — | Domino Green | Not yet confirmed |
| Yarden Bond | — | Kit Fowler | Not yet confirmed |
| Baltanos | — | None — independent Odyssey Engineer | Not yet confirmed |
| Eleanor Bresa | — | None — independent Odyssey Engineer | Not yet confirmed |
| Rosa Dayette | — | None — independent Odyssey Engineer | Not yet confirmed |
| Yi Shen | — | None | Not yet confirmed |
, used by Engineer Capability Comparison.
function p.comparison() local rows = {} for _, name in ipairs(loadIndex()) do local d = loadRecord(name) if d then local prereq = d.prerequisite_engineer and ('' .. d.prerequisite_engineer .. '') or ( d.prerequisite_engineer_display or 'None' ) table.insert(rows, string.format( '|-\n| %s || %s || %s || %s', d.name, joinSpecialties(d) or '—', prereq, d.unlock_requirement or 'Not yet confirmed' )) end end return '{| class="wikitable sortable"\n! Engineer !! Specialties !! Prerequisite Engineer !! Unlock requirement\n' .. table.concat(rows, '\n') .. '\n|}' end
-- 38, returns how many Engineers currently have a -- canonical JSON record in Module:Data/Engineers/index -- used so pages that
-- cite this number (e.g. List of Engineers'
uncertainty
-- text) stay correct automatically as records are added, instead of a -- hand-typed number silently going stale. function p.count() return tostring(#loadIndex()) end
return p