// ========================================================= // ГЕНЕРАЦИЯ ПОРЯДКА ЗАГРУЗКИ // ========================================================= let modsData = []; let currentVersion = '1.60'; let currentSubVersion = '1.60-1.0.0.0'; function gotoaltlink() { window.open('combo/altlink.html', '_blank'); } // ========== ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ========== function cleanModFileName(filename) { if (!filename) return 'default'; let cleanName = filename.replace(/\.(scs|zip)$/i, ''); cleanName = cleanName.replace(/\.(scs|zip)\./i, '.'); return cleanName; } function escapeHtml(text) { if (!text && text !== 0) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function escapeAttr(text) { if (!text && text !== 0) return ''; return String(text).replace(/&/g, '&') .replace(/"/g, '"') .replace(/'/g, ''') .replace(//g, '>'); } function getIconPath(modFile) { if (!modFile) return 'combo/icons/default.webp'; const cleanName = cleanModFileName(modFile); const currentVersion = localStorage.getItem('comboVersion') || '1.60'; if (currentVersion === '1.59') { return `combo/prevVer/1.59/icons/${cleanName}.webp`; } return `combo/icons/${cleanName}.webp`; } function getIconHTML(modFile, className = 'mod-icon') { const iconPath = getIconPath(modFile); return `${escapeAttr(modFile)}`; } function getGroupItemHTML(modFile, modName, showFilename = true) { const iconHTML = getIconHTML(modFile, 'group-item-icon'); const escapedFileName = escapeHtml(modFile); const escapedModName = escapeHtml(modName); return `
${iconHTML}
${escapedModName}
${showFilename ? `
${escapedFileName}
` : ''}
`; } function getTooltipText(tag) { const currentLang = localStorage.getItem('lang') || 'ru'; const translations = { ru: { '📝': 'У мода есть примечание', '🆕': 'Недавно добавленный мод', '🔄': 'Недавно обновлённый мод', '⚠️': 'Мод имеет критические ошибки', '🔧': 'Опциональный мод', '💰': 'Мод платный', '📎': 'Мод имеет альтернативные ссылки', '📍': 'Недавно изменено положение' }, en: { '📝': 'The mod has a note', '🆕': 'Recently added mod', '🔄': 'Recently updated mod', '⚠️': 'The mod has critical errors', '🔧': 'Optional mod', '💰': 'Paid mod', '📎': 'The mod has alternative links', '📍': 'Recently changed position' } }; return translations[currentLang]?.[tag] || ''; } // ========== ФУНКЦИИ ДЛЯ ТЭГОВ (вызывают функции из animations.js) ========== function addTagToMod(modName, tag) { if (!modName || !tag) return false; const priorityTags = ['🆕', '🔄', '📍']; let found = false; const cleanName = modName.trim(); function addTagWithPriority(item) { if (!item.tags) item.tags = []; if (item.tags.includes(tag)) return false; item.tags.push(tag); item.tags.sort((a, b) => { const indexA = priorityTags.indexOf(a); const indexB = priorityTags.indexOf(b); if (indexA !== -1 && indexB !== -1) return indexA - indexB; if (indexA !== -1) return -1; if (indexB !== -1) return 1; return 0; }); return true; } for (let i = 0; i < modsData.length; i++) { const item = modsData[i]; if (item.group) { if (item.group === cleanName || item.name === cleanName) { found = addTagWithPriority(item); break; } if (item.items) { for (let j = 0; j < item.items.length; j++) { if (item.items[j].name === cleanName || item.items[j].file === cleanName) { found = addTagWithPriority(item.items[j]); break; } } } } else { if (item.name === cleanName || item.file === cleanName) { found = addTagWithPriority(item); break; } } if (found) break; } if (!found) { for (let i = 0; i < modsData.length; i++) { const item = modsData[i]; if (item.group) { if (item.group.toLowerCase().includes(cleanName.toLowerCase()) || (item.name && item.name.toLowerCase().includes(cleanName.toLowerCase()))) { found = addTagWithPriority(item); break; } if (item.items) { for (let j = 0; j < item.items.length; j++) { if (item.items[j].name.toLowerCase().includes(cleanName.toLowerCase()) || item.items[j].file.toLowerCase().includes(cleanName.toLowerCase())) { found = addTagWithPriority(item.items[j]); break; } } } } else { if (item.name && item.name.toLowerCase().includes(cleanName.toLowerCase())) { found = addTagWithPriority(item); break; } } if (found) break; } } return found; } function removeTagFromMod(modName, tag) { if (!modName || !tag) return false; let found = false; const cleanName = modName.trim(); function removeTag(item) { if (!item.tags) return false; const index = item.tags.indexOf(tag); if (index !== -1) { item.tags.splice(index, 1); return true; } return false; } for (let i = 0; i < modsData.length; i++) { const item = modsData[i]; if (item.group) { if (item.group === cleanName || item.name === cleanName) { found = removeTag(item); break; } if (item.items) { for (let j = 0; j < item.items.length; j++) { if (item.items[j].name === cleanName || item.items[j].file === cleanName) { found = removeTag(item.items[j]); break; } } } } else { if (item.name === cleanName || item.file === cleanName) { found = removeTag(item); break; } } if (found) break; } if (!found) { for (let i = 0; i < modsData.length; i++) { const item = modsData[i]; if (item.group) { if (item.group.toLowerCase().includes(cleanName.toLowerCase()) || (item.name && item.name.toLowerCase().includes(cleanName.toLowerCase()))) { found = removeTag(item); break; } if (item.items) { for (let j = 0; j < item.items.length; j++) { if (item.items[j].name.toLowerCase().includes(cleanName.toLowerCase()) || item.items[j].file.toLowerCase().includes(cleanName.toLowerCase())) { found = removeTag(item.items[j]); break; } } } } else { if (item.name && item.name.toLowerCase().includes(cleanName.toLowerCase())) { found = removeTag(item); break; } } if (found) break; } } return found; } function removeAllPriorityTags() { const priorityTags = ['🆕', '🔄', '📍']; function removePriorityTagsFromItem(item) { if (!item.tags) return; priorityTags.forEach(tag => { const index = item.tags.indexOf(tag); if (index !== -1) { item.tags.splice(index, 1); } }); } modsData.forEach(item => { if (item.group) { removePriorityTagsFromItem(item); if (item.items) { item.items.forEach(subItem => { removePriorityTagsFromItem(subItem); }); } } else { removePriorityTagsFromItem(item); } }); } // ========== РЕНДЕРИНГ ========== function renderLoadOrder() { const container = document.getElementById('loadOrderList'); if (!container) { console.error('Контейнер loadOrderList не найден!'); return; } container.innerHTML = ''; if (!modsData || modsData.length === 0) { container.innerHTML = '
📦 Нет данных для отображения
'; return; } const currentLang = localStorage.getItem('lang') || 'ru'; const t = translations[currentLang]; const currentVersion = localStorage.getItem('comboVersion') || '1.60'; const iconsPath = currentVersion === '1.59' ? 'combo/prevVer/1.59/icons/' : 'combo/icons/'; modsData.forEach((item) => { const isGroup = !!item.group; const getLocalizedText = (item, fieldName) => { if (currentLang === 'ru' && item[`${fieldName}_ru`]) { return item[`${fieldName}_ru`]; } return item[fieldName] || ''; }; const dateLabel = typeof getModDateLabel === 'function' ? getModDateLabel(item.name || item.group) : ''; if (isGroup) { let groupTagsHtml = ''; let groupNoteIcon = ''; let groupAltIcon = ''; let hasPaidTag = false; let tagMarkers = ''; (item.tags || []).forEach(tag => { if (tag === '📝') { const noteText = (getLocalizedText(item, 'note') || (currentLang === 'ru' ? 'Нет примечания' : 'No note')).replace(/'/g, "\\'"); groupNoteIcon = `📝`; } else if (tag === '📎') { groupAltIcon = `📎`; } else if (tag === '💰') { hasPaidTag = true; tagMarkers += '-paid'; groupTagsHtml += `${tag}`; } else { let tagClass = ''; if (tag === '🆕') { tagClass = 'tag-new'; tagMarkers += '-new'; } else if (tag === '🔄') { tagClass = 'tag-updated'; tagMarkers += '-updated'; } else if (tag === '⚠️') { tagClass = 'tag-critical'; tagMarkers += '-critical'; } else if (tag === '🔧') { tagClass = 'tag-optional'; tagMarkers += '-optional'; } else if (tag === '📍') { tagClass = 'tag-moved'; tagMarkers += '-moved'; } groupTagsHtml += `${tag}`; } }); let modlink = ''; if (hasPaidTag) { modlink = `${t.buymod}`; } else { modlink = `${t.download}`; } let leftColumnHtml = `

${item.group}

`; (item.items || []).forEach(subItem => { let subItemName = subItem.name; if (currentLang === 'ru' && subItem.name_ru) { subItemName = subItem.name_ru; } const cleanFile = cleanModFileName(subItem.file); leftColumnHtml += `
${subItem.file}
${subItemName}
${subItem.file}
`; }); leftColumnHtml += `
`; const groupDescription = getLocalizedText(item, 'description'); let groupAuthorHtml = ''; if (item.author) { groupAuthorHtml = `

${t.author || 'Author:'} ${item.author}

`; } const rightColumnHtml = `
${groupDescription || ''}
${t.version} ${item.version} ${dateLabel ? `${dateLabel}` : ''} ${groupNoteIcon} ${groupAltIcon}
${groupTagsHtml}
${groupAuthorHtml}
`; let groupDiv = document.createElement('div'); if (tagMarkers) { const wrapper = document.createElement('div'); wrapper.className = `load-order-row-tags tag-marker${tagMarkers}`; groupDiv.className = 'load-order-group'; wrapper.appendChild(groupDiv); groupDiv.innerHTML = leftColumnHtml + rightColumnHtml; container.appendChild(wrapper); } else { groupDiv.className = 'load-order-group'; groupDiv.innerHTML = leftColumnHtml + rightColumnHtml; container.appendChild(groupDiv); } } else { const cleanFile = cleanModFileName(item.file); const imageHtml = `
combo/icons/default.webp
`; let tagsHtml = ''; let noteIcon = ''; let altIcon = ''; let modlink = ''; let hasPaidTag = false; let tagMarkers = ''; const modNote = getLocalizedText(item, 'note'); const modDesc = getLocalizedText(item, 'desc'); (item.tags || []).forEach(tag => { if (tag === '📝') { const noteText = (modNote || (currentLang === 'ru' ? 'Нет примечания' : 'No note')).replace(/'/g, "\\'"); noteIcon = `📝`; } else if (tag === '📎') { altIcon = `📎`; } else if (tag === '💰') { hasPaidTag = true; tagMarkers += '-paid'; tagsHtml += `${tag}`; } else { let tagClass = ''; if (tag === '🆕') { tagClass = 'tag-new'; tagMarkers += '-new'; } else if (tag === '🔄') { tagClass = 'tag-updated'; tagMarkers += '-updated'; } else if (tag === '⚠️') { tagClass = 'tag-critical'; tagMarkers += '-critical'; } else if (tag === '🔧') { tagClass = 'tag-optional'; tagMarkers += '-optional'; } else if (tag === '📍') { tagClass = 'tag-moved'; tagMarkers += '-moved'; } tagsHtml += `${tag}`; } }); if (hasPaidTag) { modlink = `${t.buymod}`; } else { modlink = `${t.download}`; } let authorHtml = ''; let fileHtml = ''; if (item.author) { authorHtml = `
${t.author || 'Author:'} ${item.author}
`; } if (item.file) { fileHtml = `
${t.file || 'File:'} ${item.file}
`; } const rowHtml = ` ${imageHtml}
${item.name}
${modDesc || ''}
${t.version} ${item.version} ${dateLabel ? `${dateLabel}` : ''} ${noteIcon} ${altIcon}
${authorHtml} ${fileHtml}
${tagsHtml}
`; const row = document.createElement('div'); row.className = 'load-order-row'; row.innerHTML = rowHtml; if (tagMarkers) { const wrapper = document.createElement('div'); wrapper.className = `load-order-row-tags tag-marker${tagMarkers}`; wrapper.appendChild(row); container.appendChild(wrapper); } else { container.appendChild(row); } } }); // Вызываем функцию из animations.js if (typeof generateTagMarkerStyles === 'function') { generateTagMarkerStyles(); } } // ========== ВЕРСИИ ДЛЯ ПРОФИЛЕЙ ========== const versionData = { v1_60: { name: 'Версия 1.60', buttons: [ { text: '1.60-1.0.0.2', url: 'https://modsfire.com/V9D7vM08N3xd0VN' }, { text: '1.60-1.0.0.1', url: 'https://modsfire.com/f10K35A82F39OSk' }, { text: '1.60-1.0.0.0', url: 'https://modsfire.com/mp23Zy29E8QJPn6' } ] }, v1_59: { name: 'Версия 1.59', buttons: [ { text: '1.59-1.0.0.2', url: 'https://modsfire.com/IKo7Ts92YWrtn31' }, { text: '1.59-1.0.0.1', url: 'https://modsfire.com/6DZY9n7jH9olnO2' }, { text: '1.59-1.0.0.0', url: 'https://modsfire.com/75g5XgOIEgEA7Oi' } ] }, v1_58: { name: 'Версия 1.58', buttons: [ { text: '1.58-1.3.1.0', url: 'https://modsfire.com/Hd8HA4Fm6T73Kt9' }, { text: '1.58-1.3.0.0', url: 'https://modsfire.com/792ki398g8UXE8F' }, { text: '1.58-1.2.0.0', url: 'https://modsfire.com/X29Uvg2qS0lTyEl' }, { text: '1.58-1.1.0.0', url: 'https://modsfire.com/D1wsZ4GL3O8P7QV' }, { text: '1.58-1.0.0.0', url: 'https://modsfire.com/x8X2Qr036RMu7X6' } ] }, v1_57: { name: 'Версия 1.57', buttons: [ { text: '1.57-2.1.0.0', url: 'https://modsfire.com/hOR4VgW97Mm352n' }, { text: '1.57-2.0.0.1', url: 'https://modsfire.com/fO6tCNjDzzl704l' }, { text: '1.57-2.0.0.0', url: 'https://modsfire.com/9tE225t74B27z3o' }, { text: '1.57-1.0.2.0', url: 'https://modsfire.com/Dlx75WA2C5k49Mt' }, { text: '1.57-1.0.1.0', url: 'https://modsfire.com/knJy5qg0V92oTHf' }, { text: '1.57-1.0.0.1', url: 'https://modsfire.com/5FKioFXjKNBLqxe' }, { text: '1.57-1.0.0.0', url: 'https://modsfire.com/ii8CrD01nDB92RN' } ] }, v1_56: { name: 'Версия 1.56', buttons: [ { text: '1.56-1.2.2.1', url: 'https://modsfire.com/m19I48w6S71oClU' }, { text: '1.56-1.2.2.0', url: 'https://modsfire.com/kr41PZv8b50gC2M' }, { text: '1.56-1.2.1.0', url: 'https://modsfire.com/Kq25WL3BazP9470' }, { text: '1.56-1.2.0.1', url: 'https://modsfire.com/9v2jrF3j7Anzk3n' }, { text: '1.56-1.2.0.0', url: 'https://modsfire.com/43H05ik08b01m3y' }, { text: '1.56-1.1.2.0', url: 'https://modsfire.com/5oNH3U5G5a620qH' }, { text: '1.56-1.1.1.0', url: 'https://modsfire.com/3nVG66RWb9fkIo4' }, { text: '1.56-1.1.0.1', url: 'https://modsfire.com/tBm5su7uG5M2N4t' }, { text: '1.56-1.1.0.0', url: 'https://modsfire.com/6x4ev53MJn3Zn9x' }, { text: '1.56-1.0.2.0', url: 'https://modsfire.com/2697EwvMhI6YMeh' }, { text: '1.56-1.0.1.0', url: 'https://modsfire.com/rUi97hNOpKybw9d' }, { text: '1.56-1.0.0.0', url: 'https://modsfire.com/Ge4X61le4nbXfB8' } ] } }; function renderVersionButtons() { const container = document.getElementById('versionButtons'); if (!container) return; container.innerHTML = ''; const currentLang = localStorage.getItem('lang') || 'ru'; const t = translations[currentLang]; for (const [key, data] of Object.entries(versionData)) { const versionBlock = document.createElement('div'); versionBlock.className = 'version-block'; let versionName = data.name; const versionKey = key.replace('v', 'version_'); if (t[versionKey]) { versionName = t[versionKey]; } versionBlock.innerHTML = `
${versionName}
${data.buttons.map(btn => ` `).join('')}
`; container.appendChild(versionBlock); } } function renderVersionList() { const container = document.getElementById('versionList'); if (!container) return; const versions = [ { id: 'v1_60', nameKey: 'version_1_60' }, { id: 'v1_59', nameKey: 'version_1_59' }, { id: 'v1_58', nameKey: 'version_1_58' }, { id: 'v1_57', nameKey: 'version_1_57' }, { id: 'v1_56', nameKey: 'version_1_56' } ]; container.innerHTML = ''; const currentLang = localStorage.getItem('lang') || 'ru'; const t = translations[currentLang]; versions.forEach(version => { const versionBlock = document.createElement('div'); versionBlock.className = 'version-block'; versionBlock.innerHTML = `
${t[version.nameKey]}
`; container.appendChild(versionBlock); }); } function copyLink(inputId) { const input = document.getElementById(inputId); if (input && input.value) { navigator.clipboard.writeText(input.value); const btn = input.nextElementSibling; const originalText = btn.textContent; const currentLang = localStorage.getItem('lang') || 'ru'; btn.textContent = translations[currentLang].copiedMsg; setTimeout(() => { btn.textContent = originalText; }, 2000); } } function addLinkToVersion(versionId) { const container = document.getElementById(versionId); const linkDiv = document.createElement('div'); linkDiv.className = 'version-link-item'; linkDiv.innerHTML = ` `; container.appendChild(linkDiv); }