252 lines
6.6 KiB
JavaScript
252 lines
6.6 KiB
JavaScript
/**
|
||
* MGT2 Commerce – Parseur UWP (Universal World Profile)
|
||
*
|
||
* Format standard : SAAHPGL-T
|
||
* Exemples : A788899-C B200400-A
|
||
*
|
||
* S = Astroport (A B C D E X)
|
||
* A = Taille (0–A hex, 0–10)
|
||
* A = Atmosphère (0–F hex, 0–15)
|
||
* H = Hydrographie (0–A hex, 0–10)
|
||
* P = Population (0–C hex, 0–12)
|
||
* G = Gouvernement (0–F hex, 0–15)
|
||
* L = Niveau de loi(0–J hex, 0–19)
|
||
* T = Niveau tech (0–F hex, 0–15) — après le tiret
|
||
*/
|
||
|
||
import { TRADE_CODES } from './data/tradeTables.js';
|
||
|
||
/**
|
||
* Convertit un caractère de code UWP en valeur numérique.
|
||
* Utilise la base 16 pour les chiffres 0–9 et lettres A–F.
|
||
* Pour le Niveau de loi : G=16, H=17, J=18 (pas de I).
|
||
*/
|
||
function uwpCharToInt(char) {
|
||
if (!char) return 0;
|
||
const c = char.toUpperCase();
|
||
if (c === 'G') return 16;
|
||
if (c === 'H') return 17;
|
||
if (c === 'J') return 18;
|
||
const n = parseInt(c, 16);
|
||
return isNaN(n) ? 0 : n;
|
||
}
|
||
|
||
/**
|
||
* Parse une chaîne UWP et retourne un objet avec tous les attributs.
|
||
* @param {string} uwp Ex. "A788899-C"
|
||
* @returns {{
|
||
* raw: string,
|
||
* valid: boolean,
|
||
* error: string|null,
|
||
* starport: string,
|
||
* size: number,
|
||
* atmosphere: number,
|
||
* hydrographics: number,
|
||
* population: number,
|
||
* government: number,
|
||
* lawLevel: number,
|
||
* techLevel: number,
|
||
* tradeCodes: string[],
|
||
* zone: string,
|
||
* }}
|
||
*/
|
||
export function parseUWP(uwp, zone = 'normal') {
|
||
const result = {
|
||
raw: uwp,
|
||
valid: false,
|
||
error: null,
|
||
starport: '',
|
||
size: 0,
|
||
atmosphere: 0,
|
||
hydrographics: 0,
|
||
population: 0,
|
||
government: 0,
|
||
lawLevel: 0,
|
||
techLevel: 0,
|
||
tradeCodes: [],
|
||
zone,
|
||
};
|
||
|
||
if (!uwp || typeof uwp !== 'string') {
|
||
result.error = 'UWP manquant';
|
||
return result;
|
||
}
|
||
|
||
// Normalise : retire espaces, met en majuscules
|
||
const s = uwp.trim().toUpperCase();
|
||
|
||
// Accepte SAAHPGL-T ou SAAHPGL (sans tech level)
|
||
const match = s.match(/^([ABCDEX])([0-9A-F])([0-9A-F])([0-9A])([0-9A-C])([0-9A-F])([0-9A-J])(?:-([0-9A-F]))?$/i);
|
||
if (!match) {
|
||
result.error = `Format UWP invalide : "${uwp}". Attendu : SAAHPGL-T (ex. A788899-C)`;
|
||
return result;
|
||
}
|
||
|
||
result.starport = match[1];
|
||
result.size = uwpCharToInt(match[2]);
|
||
result.atmosphere = uwpCharToInt(match[3]);
|
||
result.hydrographics = uwpCharToInt(match[4]);
|
||
result.population = uwpCharToInt(match[5]);
|
||
result.government = uwpCharToInt(match[6]);
|
||
result.lawLevel = uwpCharToInt(match[7]);
|
||
result.techLevel = match[8] ? uwpCharToInt(match[8]) : 0;
|
||
result.valid = true;
|
||
|
||
result.tradeCodes = deriveTradeCodes(result);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Dérive les codes commerciaux d'un monde à partir de ses attributs UWP.
|
||
* @param {object} w Objet retourné par parseUWP
|
||
* @returns {string[]}
|
||
*/
|
||
export function deriveTradeCodes(w) {
|
||
const codes = [];
|
||
|
||
// Ag – Agricole : Atm 4–9, Hyd 4–8, Pop 5–7
|
||
if (w.atmosphere >= 4 && w.atmosphere <= 9 &&
|
||
w.hydrographics >= 4 && w.hydrographics <= 8 &&
|
||
w.population >= 5 && w.population <= 7) {
|
||
codes.push('Ag');
|
||
}
|
||
|
||
// As – Astéroïdes : Taille 0, Atm 0, Hyd 0
|
||
if (w.size === 0 && w.atmosphere === 0 && w.hydrographics === 0) {
|
||
codes.push('As');
|
||
}
|
||
|
||
// Ba – Stérile : Pop 0, Gov 0, Loi 0
|
||
if (w.population === 0 && w.government === 0 && w.lawLevel === 0) {
|
||
codes.push('Ba');
|
||
}
|
||
|
||
// De – Désert : Atm 2+, Hyd 0
|
||
if (w.atmosphere >= 2 && w.hydrographics === 0) {
|
||
codes.push('De');
|
||
}
|
||
|
||
// Fl – Océans fluides : Atm A (10)+, Hyd 1+
|
||
if (w.atmosphere >= 10 && w.hydrographics >= 1) {
|
||
codes.push('Fl');
|
||
}
|
||
|
||
// Ga – Jardin : Taille 6–8, Atm 5 ou 6 ou 8, Hyd 5–7
|
||
if (w.size >= 6 && w.size <= 8 &&
|
||
[5, 6, 8].includes(w.atmosphere) &&
|
||
w.hydrographics >= 5 && w.hydrographics <= 7) {
|
||
codes.push('Ga');
|
||
}
|
||
|
||
// Hi – Pop. élevée : Pop A (10)+
|
||
if (w.population >= 10) {
|
||
codes.push('Hi');
|
||
}
|
||
|
||
// Ht – Haute tech : TL C (12)+
|
||
if (w.techLevel >= 12) {
|
||
codes.push('Ht');
|
||
}
|
||
|
||
// IC – Calotte glaciaire : Atm 0–1, Hyd 1+
|
||
if (w.atmosphere <= 1 && w.hydrographics >= 1) {
|
||
codes.push('IC');
|
||
}
|
||
|
||
// In – Industriel : Atm ∈ {0,1,2,4,7,9}, Pop 9+
|
||
if ([0, 1, 2, 4, 7, 9].includes(w.atmosphere) && w.population >= 9) {
|
||
codes.push('In');
|
||
}
|
||
|
||
// Lo – Pop. basse : Pop 1–3
|
||
if (w.population >= 1 && w.population <= 3) {
|
||
codes.push('Lo');
|
||
}
|
||
|
||
// Lt – Basse tech : TL ≤ 5
|
||
if (w.techLevel <= 5) {
|
||
codes.push('Lt');
|
||
}
|
||
|
||
// Na – Non-Agricole : Atm 0–3, Hyd 0–3, Pop 6+
|
||
if (w.atmosphere <= 3 && w.hydrographics <= 3 && w.population >= 6) {
|
||
codes.push('Na');
|
||
}
|
||
|
||
// Ni – Non-Industriel : Pop 4–6
|
||
if (w.population >= 4 && w.population <= 6) {
|
||
codes.push('Ni');
|
||
}
|
||
|
||
// Po – Pauvre : Atm 2–5, Hyd 0–3
|
||
if (w.atmosphere >= 2 && w.atmosphere <= 5 && w.hydrographics <= 3) {
|
||
codes.push('Po');
|
||
}
|
||
|
||
// Ri – Riche : Gov ∈ {4,5,6,10}, Pop 6–8, Atm ∈ {6,8}
|
||
if ([4, 5, 6, 10].includes(w.government) &&
|
||
w.population >= 6 && w.population <= 8 &&
|
||
[6, 8].includes(w.atmosphere)) {
|
||
codes.push('Ri');
|
||
}
|
||
|
||
// Wa – Monde aquatique : Hyd A (10)
|
||
if (w.hydrographics === 10) {
|
||
codes.push('Wa');
|
||
}
|
||
|
||
// Va – Vide : Atm 0
|
||
if (w.atmosphere === 0) {
|
||
codes.push('Va');
|
||
}
|
||
|
||
return codes;
|
||
}
|
||
|
||
/**
|
||
* Retourne le modificateur d'astroport pour les tables de trafic.
|
||
* @param {string} starport 'A'|'B'|'C'|'D'|'E'|'X'
|
||
* @param {string} table 'passenger'|'cargo'|'supplier'
|
||
* @returns {number}
|
||
*/
|
||
export function starportModifier(starport, table = 'passenger') {
|
||
if (table === 'supplier') {
|
||
return { A: 6, B: 4, C: 2, D: 0, E: 0, X: 0 }[starport] ?? 0;
|
||
}
|
||
// passenger & cargo
|
||
return { A: 2, B: 1, C: 0, D: 0, E: -1, X: -3 }[starport] ?? 0;
|
||
}
|
||
|
||
/**
|
||
* Retourne le modificateur de population pour les tables de trafic.
|
||
* @param {number} pop Valeur numérique de la population
|
||
* @param {string} table 'passenger'|'cargo'
|
||
* @returns {number}
|
||
*/
|
||
export function populationModifier(pop, table = 'passenger') {
|
||
if (table === 'cargo') {
|
||
if (pop <= 1) return -4;
|
||
if (pop >= 6 && pop <= 7) return 2;
|
||
if (pop >= 8) return 4;
|
||
return 0;
|
||
}
|
||
// passenger
|
||
if (pop <= 1) return -4;
|
||
if (pop >= 6 && pop <= 7) return 1;
|
||
if (pop >= 8) return 3;
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Retourne le modificateur de zone (Ambre/Rouge/Normal) pour les tables de trafic.
|
||
* @param {string} zone 'normal'|'amber'|'red'
|
||
* @param {string} table 'passenger'|'cargo'
|
||
* @returns {number}
|
||
*/
|
||
export function zoneModifier(zone, table = 'passenger') {
|
||
if (table === 'cargo') {
|
||
return { normal: 0, amber: -2, red: -6 }[zone] ?? 0;
|
||
}
|
||
return { normal: 0, amber: 1, red: -4 }[zone] ?? 0;
|
||
}
|