Die Dokumentation für dieses Modul kann unter Modul:CharArmor/Doku erstellt werden
local CharArmor = {} local metatable = {} local methodtable = {} metatable.__index = methodtable local objectData = mw.loadData( 'Module:CharArmor/Data' ) -- Extensions local common = require( 'Module:Common' ) local api = require( 'Module:Common/Api' ) local localized = require( 'Module:Localized' ) local TNT = require( 'Module:Translate' ):new() local log = require( 'Module:Log' ) local item = require( 'Module:Item' ) local commodity = require( 'Module:Commodity' ) --- Sorts all attachments into pre-defined groups --- Outputs a table containing the min and max size for the attachment port --- As well as the overall count of attachments for a group --- @param attachments table --- @return table local function makeArmorAttachmentTable( attachments ) local out = {} local sortedOut = {} for _, attachment in pairs( attachments ) do local attachmentName = CharArmor.translateArmorAttachment( attachment[ 'Halterungsname' ] ) local minNum = tonumber( attachment[ 'Minimalgröße' ] ) if minNum == nil then minNum = 0 end local maxNum = tonumber( attachment[ 'Maximalgröße' ] ) if maxNum == nil then maxNum = 0 end if attachmentName ~= nil then if out[ attachmentName ] == nil then out[ attachmentName ] = { name = attachmentName, min = minNum, max = maxNum, count = 1 } else out[ attachmentName ].count = out[ attachmentName ].count + 1 if minNum < out[ attachmentName ].min then out[ attachmentName ].min = minNum end if maxNum > out[ attachmentName ].max then out[ attachmentName ].max = maxNum end end end end for _, class in ipairs( objectData.attachmentOrder ) do if out[ class ] ~= nil then table.insert(sortedOut, out[ class ]) end end --[[ TODO remove comment to show all attachments for name, attachment in pairs( out ) do if order[ name ] == nil then table.insert( sortedOut, attachment ) end end ]]-- return sortedOut end --- Add manual smw data function methodtable.addManual( self ) if self.frameArgs == nil then return end local setObj = { [ 'Name' ] = self.frameArgs.Name or nil, [ 'Beschreibung' ] = self.frameArgs.Beschreibung or nil, [ 'Größe' ] = self.frameArgs[ 'Größe' ] or nil, [ 'Hersteller' ] = self.frameArgs[ 'Hersteller' ] or nil, [ 'Rüstungstyp' ] = self.frameArgs[ 'Rüstungstyp' ] or nil, [ 'Rüstungsklasse' ] = self.frameArgs[ 'Rüstungsklasse' ] or nil, [ 'Ist Basisversion' ] = self.frameArgs[ 'Ist Basisversion' ] or nil, [ 'Basisversion UUID' ] = self.frameArgs[ 'Basisversion UUID' ] or nil, [ 'SP' ] = self.frameArgs[ 'SP' ] or nil, [ 'Temperaturresistenz Minmal' ] = self.frameArgs[ 'Temperaturresistenz Minmal' ] or nil, [ 'Temperaturresistenz Maximal' ] = self.frameArgs[ 'Temperaturresistenz Maximal' ] or nil, [ 'Resistenzmultiplikator Physisch' ] = self.frameArgs[ 'Resistenzmultiplikator Physisch' ] or nil, [ 'Resistenzmultiplikator Energie' ] = self.frameArgs[ 'Resistenzmultiplikator Energie' ] or nil, [ 'Resistenzmultiplikator Distortion' ] = self.frameArgs[ 'Resistenzmultiplikator Distortion' ] or nil, [ 'Resistenzmultiplikator Thermisch' ] = self.frameArgs[ 'Resistenzmultiplikator Thermisch' ] or nil, [ 'Resistenzmultiplikator Biochemisch' ] = self.frameArgs[ 'Resistenzmultiplikator Biochemisch' ] or nil, [ 'Resistenzmultiplikator Betäubung' ] = self.frameArgs[ 'Resistenzmultiplikator Betäubung' ] or nil, [ 'Spielversion' ] = self.frameArgs[ 'Spielversion' ] or nil, } mw.smw.set( setObj ) end --- Request Api Data --- Using current subpage name --- @return table function methodtable.getApiDataForCurrentPage( self ) local name = self.frameArgs[ 'uuid' ] or self.frameArgs[ 'name' ] or mw.title.getCurrentTitle().text local json = mw.text.jsonDecode( mw.ext.Apiunto.get_raw( 'v2/armor/' .. name, { include = { 'shops.items' }, } ) ) api.checkResponseStructure( json, true, false ) self.apiData = json[ 'data' ] return self.apiData end --- Request armor attachments from SMW --- @param name string --- @return table function methodtable.getArmorAttachments( self, name ) local query = { '[[-Has subobject::' .. name .. ']][[Typ::Halterung]]', '?Halterungsname#-', '?Minimalgröße#-', '?Maximalgröße#-', 'mainlabel=-' } return mw.smw.ask( query ) end --- Queries the SMW Store --- @return table function methodtable.getSmwData( self ) -- Cache multiple calls if self.smwData ~= nil then return self.smwData end -- name from args or current page local queryName = self.frameArgs[ 'name' ] or localized.getMainTitle() local data = mw.smw.ask( { '[[' .. queryName .. ']][[Hersteller::+]]', '?#-=page', '?Name#-', '?Größe#-', '?Hersteller#-', '?Beschreibung', '+lang=' .. common.getLocaleForPage(), '?Schadensreduktion#-', '?SP', '?Rüstungstyp=type', '+lang=' .. common.getLocaleForPage(), '?Rüstungstyp=type_de', '+lang=de', '?Rüstungsklasse=class', '+lang=' .. common.getLocaleForPage(), '?Rüstungsklasse=class_de', '+lang=de', '?Temperaturresistenz#-n', '?Resistenzmultiplikator Physisch#-n', '?Resistenzmultiplikator Energie#-n', '?Resistenzmultiplikator Distortion#-n', '?Resistenzmultiplikator Thermisch#-n', '?Resistenzmultiplikator Biochemisch#-n', '?Resistenzmultiplikator Betäubung#-n', '?Länge', '?Breite', '?Höhe', '?Volumen', '?Spielversion#-=version', 'mainlabel=-' } ) if data == nil or data[ 1 ] == nil then return TNT.formatInLanguage( self.lang, 'Module:Common/i18n.json', 'msg_smw_loading' ) end self.smwData = data[ 1 ] self.smwData.attachments = self:getArmorAttachments( queryName ) self.smwData.price = commodity.getPrice( queryName ) if self.smwData.price ~= nil then self.smwData.price = self.smwData.price[ 1 ].price end return self.smwData end --- Base Properties that are shared across all Vehicles --- @return table SMW Result function methodtable.setSemanticProperties( self ) -- Api Error, don't set anything if self.apiData == nil then return end local item = item:new( '', self.apiData ) local setObj = item:makeSmwObject() setObj[ 'Set' ] = CharArmor.getArmorSet( self.apiData.name ) setObj[ 'Schadensreduktion' ] = self.apiData.clothing.damage_reduction or nil setObj[ 'Rüstungstyp' ] = api.mapTranslation( CharArmor.translateArmorType( self.apiData.clothing.armor_type or nil ) ) setObj[ 'Rüstungsklasse' ] = api.mapTranslation( CharArmor.translateClass( self.apiData.type or nil ) ) setObj[ 'Temperaturresistenz' ] = { CharArmor.formatTemperature( self.apiData.clothing.temp_resistance_min ), CharArmor.formatTemperature( self.apiData.clothing.temp_resistance_max ), } if type( self.apiData.clothing.resistances ) == 'table' then for _, resistance in pairs( self.apiData.clothing.resistances ) do if resistance.type == 'physical' then setObj['Resistenzmultiplikator Physisch'] = common.formatNum( resistance.multiplier ) end if resistance.type == 'energy' then setObj['Resistenzmultiplikator Energie'] = common.formatNum( resistance.multiplier ) end if resistance.type == 'distortion' then setObj['Resistenzmultiplikator Distortion'] = common.formatNum( resistance.multiplier ) end if resistance.type == 'thermal' then setObj['Resistenzmultiplikator Thermisch'] = common.formatNum( resistance.multiplier ) end if resistance.type == 'biochemical' then setObj['Resistenzmultiplikator Biochemisch'] = common.formatNum( resistance.multiplier ) end if resistance.type == 'stun' then setObj['Resistenzmultiplikator Betäubung'] = common.formatNum( resistance.multiplier ) end end end local result = mw.smw.set( setObj ) if self.apiData.ports ~= nil and type( self.apiData.ports ) == 'table' then for _, attachment in pairs( self.apiData.ports ) do if attachment.name ~= nil then mw.smw.subobject( { [ 'Typ' ] = { 'Halterung@de', 'Attachment@en', }, [ 'Halterungsname' ] = attachment.name, [ 'Minimalgröße' ] = attachment.min_size or 0, [ 'Maximalgröße' ] = attachment.max_size or 0, } ) end end end commodity:new():addShopData( self.apiData ) return result end --- Sets the main categories for this object function methodtable.setCategories( self, smwData ) if smwData.Hersteller == nil then table.insert( self.categories, '[[Category:Seiten mit Skriptfehlern]]' ) return end if self.lang == 'de' then table.insert( self.categories, '[[Category:' .. smwData.Hersteller .. '|' .. smwData.Name .. ' ]]' ) if smwData.class ~= nil then table.insert( self.categories, string.format('[[Kategorie:%s|%s]]', smwData.class_de, smwData.Name ) ) end if smwData.type ~= nil and smwData.type ~= 'Unbekannter Typ' then table.insert( self.categories, string.format('[[Kategorie:%s|%s]]', smwData.type_de, smwData.Name ) ) end else table.insert( self.categories, '[[Category:' .. smwData.Name ..'|' .. smwData.Name .. ' ]]' ) end end --- Entrypoint for {{#seo:}} function methodtable.setSeoData( self ) local data = self:getSmwData() if nil == data.Hersteller then -- Faulty SMW data, don't call #seo return end require( 'Module:SEO' ).set( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'seo_section' ), data.page, table.concat({ data.Name, data.Hersteller, self.currentFrame:preprocess( '{{SITENAME}}' ) }, ' - '), 'replace', { data.Name, data.type or '', data.class or '', data.Hersteller, require( 'Module:Hersteller' ).getCodeFromName( data.Hersteller ), TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'seo_section' ), }, nil, self.frameArgs[ 'image' ], data.page ) end --- Creates the infobox function methodtable.getInfoBox( self ) local data = self:getSmwData() if type( data ) == 'string' then return log.info( data ) end if nil == data.Hersteller then data.Hersteller = 'Unbekannter Hersteller' end -- Set Title common.setDisplayTitle( self.currentFrame, data.Name ) local box = require( 'Module:InfoboxNeue' ):new( { removeEmpty = true, emptyString = '-', placeholderImage = 'Platzhalter Rüstung.webp', } ) local nameNormalized, _ = mw.ustring.gsub( data.Name, "[^%w-]", ' ' ) nameNormalized, _ = mw.ustring.gsub( nameNormalized, "%s+", ' ' ) local nameCleaned, _ = mw.ustring.gsub( nameNormalized, "%(", '' ) nameCleaned, _ = mw.ustring.gsub( nameCleaned, "%)", '' ) box:renderImage( common.getImage( { self.frameArgs[ 'image' ], mw.text.trim( nameNormalized ) .. '.jpg', mw.text.trim( nameCleaned ) .. '.jpg', } ) ) box:renderHeader( { title = data.Name, subtitle = '[[' .. data.Hersteller .. ']]' .. api.getVersionInfoRef( data.version, self.lang ), } ) local tempMinRes, tempMaxRes = CharArmor.temperatureResistanceToText( data[ 'Temperaturresistenz' ] ) local armorClass = data.class if armorClass ~= nil then armorClass = string.format('[[:Kategorie:%s|%s]]', data.class_de, armorClass) end local armorType = data.type if armorType ~= nil then armorType = string.format('[[:Kategorie:%s|%s]]', data.type_de, armorType) end local set = CharArmor.getArmorSet( data.Name ) if set ~= nil then table.insert( self.categories, string.format('[[Kategorie:%s|%s]]', set, data.Name ) ) set = mw.ustring.format( '[[:Kategorie:%s|%s]]', set, set ) end local damageReduction = data[ 'Schadensreduktion' ] if damageReduction ~= nil then damageReduction = (100 * damageReduction) .. '%' else damageReduction = '-' end box:renderSection( { col = 2, content = { box:renderItem( TNT.formatInLanguage( self.lang, 'Module:Common/i18n.json', 'lbl_type' ), armorType or '-' ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:Common/i18n.json', 'lbl_price' ), data.price or TNT.formatInLanguage( self.lang, 'Module:Common/i18n.json', 'txt_cant_buy' ) ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:Common/i18n.json', 'lbl_carrying_capacity' ), data[ 'SP' ] or '-' ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:Common/i18n.json', 'lbl_weight' ), data[ 'Volumen' ] or '-' ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_damage_reduction' ), damageReduction ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:Common/i18n.json', 'lbl_class' ), armorClass or '-' ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_set' ), set or '-' ), } } ) box:renderSection( { title = TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_temperature_resistance' ), col = 2, content = { box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_temperature_resistance_min' ), tempMinRes or '-' ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_temperature_resistance_max' ), tempMaxRes or '-' ), } } ) box:renderSection( { title = TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_resistances' ), col = 3, content = { box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_physical' ), CharArmor.resistanceToString( data[ 'Resistenzmultiplikator Physisch' ] ) ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_energy' ), CharArmor.resistanceToString( data[ 'Resistenzmultiplikator Physisch' ] ) ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_distortion' ), CharArmor.resistanceToString( data[ 'Resistenzmultiplikator Distortion' ] ) ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_thermal' ), CharArmor.resistanceToString( data[ 'Resistenzmultiplikator Thermisch' ] ) ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_biochemical' ), CharArmor.resistanceToString( data[ 'Resistenzmultiplikator Biochemisch' ] ) ), box:renderItem( TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_stun' ), CharArmor.resistanceToString( data[ 'Resistenzmultiplikator Betäubung' ] ) ), } } ) if data.attachments ~= nil and type( data.attachments ) == 'table' and #data.attachments > 0 then local attachTable = makeArmorAttachmentTable( data.attachments ) if #attachTable > 0 then local attachs = {} for _, attachment in ipairs( attachTable ) do local size = '' if attachment.min ~= 0 and attachment.max ~= 0 then if attachment.min ~= attachment.max then size = string.format( '(S%s - S%s)', attachment.min, attachment.max ) end elseif attachment.min ~= nil and attachment.min ~= 1 then size = string.format( '(S%s)', attachment.min ) end if attachment.name == 'Abwerfbar' then attachment.name = 'Abwerfbar ' .. mw.smw.info( 'Granaten, Knicklichter, etc.' ) end table.insert( attachs, box:renderItem( attachment.name, string.format( '%dx %s', attachment.count, size ) ) ) end box:renderSection( { col = 3, title = TNT.formatInLanguage( self.lang, 'Module:CharArmor/i18n.json', 'lbl_attachments' ), content = attachs } ) end end return tostring( box ) end --- Set the frame and load args --- @param frame table function methodtable.setFrame( self, frame ) self.currentFrame = frame self.frameArgs = require( 'Module:Arguments' ).getArgs( frame ) if type( self.frameArgs[ 'Bild' ] ) == 'string' then self.frameArgs[ 'image' ] = self.frameArgs[ 'Bild' ] end end --- Get categories function methodtable.getCategories( self ) return tostring( table.concat( self.categories ) ) end --- Save Api Data to SMW store function methodtable.saveApiData( self ) if self.currentFrame == nil then error( 'No frame set. Call "setFrame" first.', 0 ) end local data = self:getApiDataForCurrentPage() self:setSemanticProperties() return data end --[[ Char Armor Methods ]]-- --- @param name string --- @return string function CharArmor.getArmorSet( name ) for _, setName in ipairs( objectData.armorSets ) do if mw.ustring.find( name, setName, 1, true ) then return setName end end return nil end --- @param class string --- @return table function CharArmor.translateClass( class ) if objectData.itemClassTranslations[ class ] == nil then return { de_DE = class, en_EN = class } end return objectData.itemClassTranslations[ class ] end --- @param type string --- @return table function CharArmor.translateArmorType( type ) return { de_DE = objectData.armorTypeTranslations[ type ] or type, en_EN = type } end --- Calculates the resistance --- @return number function CharArmor.calculateResistance( resistance ) if resistance == nil then return nil end return 100 * ( 1 - resistance ) end --- Resistance to string --- @return string function CharArmor.resistanceToString( resistance ) local res = CharArmor.calculateResistance( resistance ) local span = mw.html.create( 'span' ) if res == nil then return '-' end if res > 100 then -- Armor has negative resistance span:addClass( 'resistance-negative' ) else span:addClass( 'resistance-positive' ) end span:wikitext( res .. '%' ) return tostring( span:allDone() ) end --- Returns temperature resistances as strings containing °C --- @param resTable table containing an arbitrary amount of temperatures --- @return string, string function CharArmor.temperatureResistanceToText( resTable ) local tempMinRes = math.huge local tempMaxRes = -math.huge if resTable ~= nil and type( resTable ) == 'table' then for _, res in pairs( resTable ) do res = common.toNumber( res, 0 ) if res < tempMinRes then tempMinRes = res end if res > tempMaxRes then tempMaxRes = res end end end if tempMinRes == math.huge then tempMinRes = '-' else tempMinRes = tempMinRes .. '°C' end if tempMaxRes == -math.huge then tempMaxRes = '-' else tempMaxRes = tempMaxRes .. '°C' end return tempMinRes, tempMaxRes end --- Translates an internal attachment name to text --- @param name string The internal name --- @return string function CharArmor.translateArmorAttachment( name ) if name == nil then return name end local matchAttachName = mw.ustring.match(name, "(%w+)_attach_%d") local matchStockedName = mw.ustring.match(name, "(%w+)_stocked_%d") if matchAttachName ~= nil then name = matchAttachName elseif matchStockedName ~= nil then name = matchStockedName end if objectData.armorAttachmentTranslations[ name ] ~= nil then if common.getLocaleForPage() == 'de' then return objectData.armorAttachmentTranslations[ name ].de_DE end return objectData.armorAttachmentTranslations[ name ].en_EN end return name end --- Format the carrying capacity --- @param capacity string|number|nil --- @return string function CharArmor.formatCarryingCapacity( capacity ) if capacity == nil then return nil end if type( capacity ) == 'string' then capacity = mw.ustring.gsub( capacity, 'K SP', '' ) capacity = mw.ustring.gsub( capacity, 'K µSCU', '' ) capacity = common.toNumber( capacity ) if capacity ~= nil then capacity = capacity * 1000 end end capacity = common.toNumber( capacity ) if capacity == nil then return nil end return common.formatNum( capacity ) .. ' µSCU' end --- Format the emperature resistance --- @param temperature string|number|nil --- @return string function CharArmor.formatTemperature( temperature ) if temperature == nil then return nil end temperature = common.toNumber(temperature, false ) if temperature == nil then return nil end return common.formatNum( temperature ) .. ' °C' end --- Template entry function CharArmor.main( frame ) local instance = CharArmor:new() instance:setFrame( frame ) if not localized.isLanguagePage() then if instance.frameArgs[ 'Manuell' ] ~= nil then instance:addManual() else instance:saveApiData() end end instance:setCategories( instance:getSmwData() ) instance:setSeoData() return tostring( instance:getInfoBox() ) .. instance:getCategories() end --- New Instance function CharArmor.new( self, name ) local instance = { categories = {}, frameArgs = { [ 'name' ] = name }, lang = require( 'Module:Template translation' )._getLanguageSubpage( mw.title.getCurrentTitle() ) } setmetatable( instance, metatable ) return instance end return CharArmor