Wiki en construction. De nombreux concepts décrits ici viennent de l'alpha 0.2 et peuvent encore changer. Le wiki sera finalisé pour la version 1.0 — pour l'instant il sert à aider les testeurs fermés puis, plus tard, les joueurs de l'accès anticipé à s'y retrouver. Pour les informations les plus à jour et les plus fiables, rejoignez le Discord — c'est là que les changements sont annoncés en premier et que vous pouvez poser vos questions directement.

Rejoindre le Discord pour les dernières infos

Éditer un pack en SQL

Le schéma complet d'un pack de mods, table par table, les outils pour l'ouvrir — sqlite3, DB Browser, un script Python — et les règles que suit le chargeur.

Sur cette page

Un pack de mods est une simple base SQLite. L’éditeur de mods est la façon confortable d’en écrire un, mais rien ne vous empêche d’ouvrir le fichier vous-même — et pour certains travaux c’est de loin le chemin le plus rapide :

  • importer une saison réelle depuis un tableur ou un CSV ;
  • renommer quarante sponsors, ou augmenter tous les salaires de 10 % ;
  • générer un pack depuis un script, pour le régénérer dès que vos données sources changent ;
  • lire le pack de quelqu’un d’autre pour voir comment il s’y est pris.

Cette page est la référence pour cela. Elle documente ce que le jeu lit réellement — colonne par colonne — et les règles qu’il suit. Rien ici n’est un détail privé : le chargeur est délibérément tolérant, et savoir à quel point il l’est, c’est ce qui permet d’écrire un pack à la main en confiance.

Vous n’avez jamais besoin de cette page pour faire un mod. L’éditeur de mods écrit toutes les tables décrites ici, vérifie votre travail et met à jour les packs anciens. Passez au SQL quand vous voulez des modifications en masse ou de la génération par script.


Ouvrir un pack

N’importe quel outil SQLite fonctionne — le fichier n’a ni en-tête maison, ni compression, ni chiffrement.

Éditeur de mods en jeu · vérifié · sûr DB Browser édition façon tableur sqlite3 · Python masse · génération my_pack.db un fichier SQLite Le jeu lu à la création

En graphique — DB Browser for SQLite est gratuit, tourne sous Windows, macOS et Linux, et édite les tables comme un tableur. C’est l’entrée la plus douce si vous n’avez jamais écrit de SQL : ouvrez le fichier, allez dans Parcourir les données, choisissez une table, tapez. Pensez à Écrire les modifications avant de fermer.

En ligne de commande — sqlite3 est livré avec macOS et la plupart des distributions Linux, et se télécharge en un petit fichier sous Windows :

sqlite3 my_pack.db
sqlite> .tables
sqlite> .schema teams
sqlite> SELECT name, country FROM teams ORDER BY sort;
sqlite> .quit

Depuis un script — Python embarque SQLite, ce qui fait d’un pack une sortie de build naturelle :

import sqlite3
db = sqlite3.connect("my_pack.db")
db.execute("UPDATE drivers SET salary = CAST(salary * 1.1 AS INTEGER)")
db.commit()
db.close()

Travaillez toujours sur une copie. Un pack est un seul fichier — le sauvegarder, c’est un glisser-déposer.


Les règles que suit le chargeur

Ces six règles sont ce qui rend l’édition à la main sûre. Elles méritent d’être lues avant le schéma lui-même.

1 — Toute table est optionnelle. Un pack qui n’a qu’une table drivers est valide. Une table absente signifie « cette section reste procédurale », jamais une erreur.

2 — Toute colonne est optionnelle. Le chargeur demande à SQLite quelles colonnes votre table possède réellement et sert le reste en NULL. Donc CREATE TABLE teams(name TEXT) fonctionne. Cela veut aussi dire qu’un pack écrit pour une version plus ancienne continue de se charger, et qu’une faute de frappe dans un nom de colonne n’est pas une erreur — la colonne n’est simplement jamais lue, et c’est le seul mode d’échec à surveiller.

3 — Les types sont tolérants. Chaque valeur est lue comme du texte, quel que soit le stockage. 12, "12" et même 12.0 arrivent tous comme le nombre 12 là où un nombre est attendu. Stockez ce qui vous arrange.

4 — Les lignes sont triées par sort. Ajoutez une colonne entière sort et les lignes sont lues dans cet ordre ; sans elle, elles viennent dans l’ordre d’insertion. L’ordre compte pour les écuries (la grille se construit dedans) et pour les manches du calendrier.

5 — Vide signifie « garder ce que le jeu a généré ». C’est la règle la plus utile de toutes. Une couleur vide garde la livrée générée, un car_index vide garde le modèle généré, un potentiel à 0 laisse le générateur fixer le plafond. Vous surchargez ce qui vous importe et laissez le reste tranquille.

6 — Une ligne fautive est ignorée, pas fatale. Une écurie sans nom, un circuit à moins de trois points, une ligne d’historique malformée — chacune est écartée seule. Le reste du pack se charge quand même.


meta — les réglages du pack lui-même

Deux colonnes, key et value, une ligne par réglage. Les clés ne sont pas sensibles à la casse.

CléValeurDéfaut
nameLe nom affiché dans le sélecteurle nom du fichier
authorVotre nom — affiché avec le pack—
schema_versionVersion de format de ce pack (actuelle : 2)1
min_game_versionBuild minimum qui le comprend, ex. 0.5.4-6aucun
scenarionew_series (vous arrivez en nouvelle écurie) ou imposed (vous reprenez une grille écrite)new_series
start_yearAnnée civile de la saison 1celle du jeu
teams_mode · drivers_mode · sponsors_mode · suppliers_mode · circuits_modeextend (s’ajoute au monde généré) ou replace (les vôtres seuls)extend
active_seriesListe CSV des championnats à faire courir, ex. PFS,PF2tous les actifs
rulesListe CSV d’identifiants de règlements, ex. points_classic_top6,quali_107ceux de la série

replace accepte aussi only ; imposed accepte aussi takeover ou existing. Une valeur inconnue retombe sur le défaut au lieu d’échouer.

Deux clés sont une poignée de main avec le jeu, et c’est la raison pour laquelle un pack n’échoue jamais en silence :

  • si schema_version dépasse ce que le build comprend, la ligne du pack dans le sélecteur le dit — « écrit pour un format plus récent » — et les parties illisibles sont ignorées ;
  • si min_game_version est plus récent que le build, la ligne dit « nécessite le jeu X ou plus récent ».

Renseignez les deux. Elles coûtent deux lignes et transforment un pack à moitié fonctionnel et mystérieux en un message clair.

CREATE TABLE meta(key TEXT, value TEXT);
INSERT INTO meta VALUES
  ('name', 'Saison 1994'),
  ('author', 'Votre nom'),
  ('schema_version', '2'),
  ('min_game_version', '0.5.4-6'),
  ('scenario', 'imposed'),
  ('start_year', '1994'),
  ('teams_mode', 'replace'),
  ('drivers_mode', 'replace');

teams

ColonneSignification
idClé stable. Ce que visent pilotes, sponsors et fournisseurs. N’importe quelle chaîne unique.
nameNom affiché. Une ligne sans nom est ignorée.
countryNom de pays (Germany) ou code ISO (de) — les deux marchent
budget_tiersmall · medium · large — le comportement de l’écurie, pas seulement sa trésorerie
budget_musdBudget de départ en millions. Fixe aussi le palier, sauf si budget_tier dit autre chose
reputation0-100
color1 · color2 · color3Hexadécimal, ex. #1A5FB4. Les trois vides = garder la livrée générée
car_indexModèle de voiture 0-11. Vide = garder le modèle généré (0 est une vraie voiture, pas « non défini »)
livery · suitIndices de variante ; 255 = généré
logoUn nom de ligne images, un chemin relatif au dossier mods, ou un simple nombre pour un logo intégré
car_imageUn nom de ligne images pour un sprite de voiture personnalisé
infra_engineering · _rnd · _chassis · _handling · _aero · _engine · _marketing · _scoutingNiveaux de département 0-10. 0 = garder le généré
infra_academyIdem, plafonné à 3
career_wins · career_titles · best_championship · founding_yearPalmarès, pour une histoire écrite
historySaisons passées en saison:position:victoires, séparées par ; ou des retours à la ligne

L’infrastructure et le palmarès ne comptent vraiment qu’en scénario imposé, où la grille doit être une affaire qui tourne dès la première course.


drivers

ColonneSignification
idClé stable
first_name · last_nameUne ligne sans ni l’un ni l’autre est ignorée
codeCode à trois lettres. Mis en majuscules au chargement ; un doublon est renommé en silence
countryCode ISO — ici la valeur EST la clé du drapeau
age1-55. Moins de 16 est permis pour un espoir : il vieillit, reste caché au Scouting jusqu’à 14 ans, et ne peut être titularisé avant que les règles d’âge de la série ne l’autorisent
intelligence · pace · consistency · adaptability · stamina · aggressivityLes six aptitudes, 1-20
pot_intelligence … pot_aggressivityLeurs plafonds, 0-20. 0 = laisser le générateur décider
curve_intelligence … curve_aggressivityIdentifiants de courbe de progression ; 255 = défaut. Un identifiant inconnu retombe sur le défaut au lieu de geler la stat
salaryPar saison
traitsPaires genre:palier séparées par des virgules, ex. 3:1,7:2
face_sheet · face_index · helmet_indexPortrait ; 255 = généré
helmet_hue_0 · _1 · _2Teintes du casque. Les trois vides = généré
team · team_idLe baquet. team_id l’emporte si les deux sont renseignés
roleprimary · secondary · reserve
contract_years0-5
career_starts · career_wins · career_podiums · career_titles · best_finishPalmarès
fame0-100 ; 0 garde la valeur calculée

Deux pilotes par écurie, un par baquet. Deux pilotes primary dans la même écurie laissent la voiture 2 vide — et une voiture sans pilote ne prend pas le départ.


sponsors

ColonneSignification
idClé stable
nameIgnorée si vide
sectorSecteur d’activité — pilote le logo procédural
colorHexadécimal
budget · prominence1-10
originNom de pays ou code ISO
logoUn nom de ligne images ou un chemin
team · team_idLe pré-signer à une écurie. Accepte une liste séparée par ; ou ,

Le premier sponsor d’une écurie devient son Principal, les suivants des Secondaires.


suppliers

ColonneSignification
idClé stable
nameIgnorée si vide
categoryengine · tires · fuel
color · origin · logoComme les sponsors
budget · size1-10
money_per_gpArgent par course. Positif = il vous paie, négatif = vous le payez
contractpartnership (exclusif) ou client. L’emporte sur le signe de money_per_gp
duration0-5 saisons
team · team_idPré-signature ; une liste, comme les sponsors

Les statistiques techniques ont deux écritures, et les colonnes nommées sont la raison d’être de cette page. Quatre cases génériques (stat_a … stat_d) signifiaient autre chose selon la catégorie, ce qu’aucun outil tiers ne pouvait deviner. Écrivez plutôt les colonnes nommées — elles l’emportent dès qu’elles sont renseignées et non nulles :

CatégorieColonnes nommées (0-10)
enginepower · reliability · endurance · potential
tiresperformance · endurance · reliability · heat
fuelefficiency

circuits

Les tracés dessinés à la main que porte le pack. L’éditeur de circuits écrit ces lignes, mais la géométrie est du texte brut : un script le peut aussi.

ColonneSignification
idClé stable — ce que vise une manche du calendrier
nameIgnorée si vide
pointsLa ligne médiane. Paires x,y jointes par ;. Moins de trois points et la ligne est écartée
country · cityVide donne un lieu aléatoire mais stable
target_kmLongueur du tour ; en dessous de 1, retombe à 5 km
characterLe caractère du tracé — c’est ce que la simulation lit réellement
presetIdentifiant de préréglage visuel
start_finish · pit_entry · pit_exitPositions le long du tour ; négatif ou absent = déduit
year · downforce · tire_wear · overtakingStockés et affichés, mais non simulés — en jeu ces trois-là découlent du character

calendar

Une ligne par manche, dans l’ordre sort, jusqu’à 24.

ColonneSignification
kindcircuit = utiliser un circuit du pack ; toute autre valeur = tracé généré
circuit · circuit_idLequel. circuit_id est essayé en premier
character · target_kmPour une manche générée

Un pack qui porte un calendrier remplace la saison. Un pack qui porte des circuits sans calendrier verse ses tracés dans le pool mondial et les laisse gagner des manches tout seuls.


images

name (la clé que visent les autres tables) et data, les octets du PNG en BLOB. Les logos se dessinent en 195×195 ; un sprite de voiture personnalisé est une vue de profil tournée vers la droite sur fond transparent, 256 px de haut.

Insérer une image depuis la ligne de commande :

sqlite3 my_pack.db "INSERT INTO images(name, data) VALUES('lotus.png', readfile('lotus.png'))"

…ou depuis Python :

db.execute("INSERT INTO images(name, data) VALUES(?, ?)",
           ("lotus.png", open("lotus.png", "rb").read()))

Puis faites-y pointer une ligne : UPDATE teams SET logo = 'lotus.png' WHERE name = 'Lotus'.

Deux noms qui ne diffèrent que par la ponctuation (mon logo.png et mon-logo.png) se déballent vers le même fichier ; le premier le garde et le second reçoit un suffixe numéroté, si bien que rien n’est écrasé en silence.


Un pack minimal, de bout en bout

CREATE TABLE meta(key TEXT, value TEXT);
INSERT INTO meta VALUES
  ('name','Deux écuries'), ('schema_version','2'),
  ('min_game_version','0.5.4-6'), ('teams_mode','extend');

CREATE TABLE teams(sort INTEGER, id TEXT, name TEXT, country TEXT,
                   budget_tier TEXT, color1 TEXT, color2 TEXT);
INSERT INTO teams VALUES
  (1,'t_alba','Alba Corse','Italy','large','#B3122C','#F2E8D5'),
  (2,'t_nord','Nordwind GP','Germany','medium','#14304F','#C8D3DC');

CREATE TABLE drivers(sort INTEGER, id TEXT, first_name TEXT, last_name TEXT,
                     code TEXT, country TEXT, age INTEGER,
                     pace INTEGER, consistency INTEGER,
                     team_id TEXT, role TEXT);
INSERT INTO drivers VALUES
  (1,'d_ros','Elio','Rossi','ROS','it',27,17,15,'t_alba','primary'),
  (2,'d_ber','Karl','Berger','BER','de',31,15,17,'t_alba','secondary');

Voilà un pack complet et valide. Tout ce qui n’est pas mentionné reste procédural.


Vérifier son travail

Demandez au jeu ce qu’il voit. Lancez-le une fois depuis un terminal avec --list-mods : il affiche les dossiers qu’il scanne dans l’ordre, puis chaque pack, circuit et langue trouvés. C’est la première chose à lancer quand un pack n’apparaît pas.

mod folders (read in this order):
  /home/vous/.local/share/TheUndercut/mods
  /chemin/du/jeu/mods   (does not exist)
packs:
  my_pack

Lisez la ligne du pack dans le sélecteur. Le jeu y dit ce qu’il n’a compris qu’à moitié — un format plus récent, une version de jeu qu’il lui faut, ou deux écuries partageant un nom, ce qui rend les rattachements ambigus.

Ouvrez-le une fois dans l’éditeur de mods. Son onglet Audit attrape ce que le SQL ne peut pas voir : un second baquet vide, un pilote rattaché à une écurie inexistante, un code en double. Ouvrir un pack écrit à la main y appose aussi des identifiants stables là où il n’y en a pas, et c’est la meilleure chose qu’on puisse faire à un pack écrit à la main.


Pièges à connaître

  • Une colonne mal orthographiée est silencieuse. colour1 n’est pas color1 ; elle n’est simplement jamais lue. Si une modification semble sans effet, vérifiez d’abord l’orthographe contre cette page — PRAGMA table_info(teams) liste ce que votre table contient vraiment.
  • Les rattachements suivent id d’abord, le nom ensuite. Donnez un identifiant à chaque ligne et renommer une écurie lui garde ses pilotes. Sans identifiants, renommer une écurie verse ses pilotes chez les agents libres.
  • 0 ne veut pas dire « non défini » partout. Il signifie garder le généré pour les potentiels, l’infrastructure et la renommée — mais car_index à 0 est une vraie voiture : laissez cette colonne vide pour garder le modèle généré.
  • Un pack ne s’applique qu’à la création d’une carrière. L’éditer ne change rien à une carrière déjà lancée. Commencez-en une nouvelle.
  • Le fichier doit rester où il est. Logos et sprites de voiture y sont lus pendant toute la vie de la carrière.
  • Écrivez vos modifications. Un navigateur graphique garde les changements dans une transaction en attente — fermez-le sans Écrire les modifications et rien n’a été enregistré.

À voir aussi