Un pack de mods es una simple base de datos SQLite. El editor de mods es la forma cómoda de escribir uno, pero nada te impide abrir el archivo tú mismo — y para ciertas tareas es con diferencia el camino más rápido:
- importar una temporada real desde una hoja de cálculo o un CSV;
- renombrar cuarenta patrocinadores, o subir un 10 % el salario de cada piloto;
- generar un pack desde un script, para rehacerlo cada vez que cambien tus datos de origen;
- leer el pack de otra persona para ver cómo lo hizo.
Esta página es la referencia para eso. Documenta lo que el juego lee realmente — columna por columna — y las reglas que sigue. Nada de esto es un detalle interno: el cargador es deliberadamente tolerante, y saber cuánto lo es es justo lo que permite escribir un pack a mano con confianza.
Nunca necesitas esta página para hacer un mod. El editor de mods escribe todas las tablas descritas aquí, comprueba tu trabajo y actualiza los packs antiguos. Recurre a SQL cuando quieras cambios masivos o generación por script.
Abrir un pack
Sirve cualquier herramienta SQLite — el archivo no tiene cabecera propia, ni compresión, ni cifrado.
Gráfico — DB Browser for SQLite es gratuito, va en Windows, macOS y Linux, y edita tablas como una hoja de cálculo. Es la entrada más suave si nunca has escrito SQL: abre el archivo, ve a Examinar datos, elige una tabla y escribe. Acuérdate de Escribir cambios antes de cerrar.
Línea de comandos — sqlite3 viene con macOS y con casi todas las distribuciones de Linux, y en Windows es una descarga pequeña:
sqlite3 my_pack.db
sqlite> .tables
sqlite> .schema teams
sqlite> SELECT name, country FROM teams ORDER BY sort;
sqlite> .quit
Desde un script — Python lleva SQLite incorporado, lo que convierte un pack en una salida de build natural:
import sqlite3
db = sqlite3.connect("my_pack.db")
db.execute("UPDATE drivers SET salary = CAST(salary * 1.1 AS INTEGER)")
db.commit()
db.close()
Trabaja siempre sobre una copia. Un pack es un solo archivo — respaldarlo es arrastrarlo.
Las reglas que sigue el cargador
Estas seis reglas son lo que hace segura la edición a mano. Conviene leerlas antes que el esquema.
1 — Toda tabla es opcional. Un pack con solo una tabla drivers es válido. Una tabla ausente significa «esa sección sigue siendo procedural», nunca un error.
2 — Toda columna es opcional. El cargador pregunta a SQLite qué columnas tiene realmente tu tabla y sirve el resto como NULL. Así que CREATE TABLE teams(name TEXT) funciona. También significa que un pack escrito para una versión anterior se sigue cargando, y que una errata en un nombre de columna no es un error — esa columna simplemente nunca se lee, y ese es el único modo de fallo que hay que vigilar.
3 — Los tipos son tolerantes. Cada valor se lee como texto, se guarde como se guarde. 12, "12" e incluso 12.0 llegan todos como el número 12 donde se espera un número. Guarda lo que te resulte cómodo.
4 — Las filas se ordenan por sort. Añade una columna entera sort y las filas se leen en ese orden; sin ella llegan en orden de inserción. El orden importa en las escuderías (la parrilla se construye con él) y en las rondas del calendario.
5 — Vacío significa «conservar lo que generó el juego». Es la regla más útil de todas. Un color vacío conserva la decoración generada, un car_index vacío conserva el modelo generado, un potencial a 0 deja que el generador fije el techo. Sobrescribes lo que te importa y dejas el resto en paz.
6 — Una fila defectuosa se descarta, no es fatal. Una escudería sin nombre, un circuito con menos de tres puntos, una línea de historial mal formada — cada una cae por su cuenta. El resto del pack se carga igual.
meta — los ajustes del propio pack
Dos columnas, key y value, una fila por ajuste. Las claves no distinguen mayúsculas.
| Clave | Valor | Por defecto |
|---|---|---|
name | El nombre que se muestra en el selector | el nombre del archivo |
author | Tu nombre — se muestra con el pack | — |
schema_version | Versión de formato de este pack (actual: 2) | 1 |
min_game_version | Build mínimo que lo entiende, p. ej. 0.5.4-6 | ninguno |
scenario | new_series (entras como escudería nueva) o imposed (tomas el mando de una parrilla escrita) | new_series |
start_year | Año natural de la temporada 1 | el del juego |
teams_mode · drivers_mode · sponsors_mode · suppliers_mode · circuits_mode | extend (se suma al mundo generado) o replace (solo los tuyos) | extend |
active_series | Lista CSV de campeonatos a disputar, p. ej. PFS,PF2 | todos los activos |
rules | Lista CSV de identificadores de reglamento, p. ej. points_classic_top6,quali_107 | los de la serie |
replace acepta también only; imposed acepta también takeover o existing. Un valor desconocido cae al valor por defecto en vez de fallar.
Dos claves son un apretón de manos con el juego, y por eso un pack nunca falla en silencio:
- si
schema_versionsupera lo que el build entiende, la fila del pack en el selector lo dice — «escrito para un formato más nuevo» — y las partes ilegibles se ignoran; - si
min_game_versiones más nueva que el build, la fila dice «necesita el juego X o posterior».
Rellena las dos. Cuestan dos filas y convierten un pack a medias y desconcertante en un mensaje claro.
CREATE TABLE meta(key TEXT, value TEXT);
INSERT INTO meta VALUES
('name', 'Temporada 1994'),
('author', 'Tu nombre'),
('schema_version', '2'),
('min_game_version', '0.5.4-6'),
('scenario', 'imposed'),
('start_year', '1994'),
('teams_mode', 'replace'),
('drivers_mode', 'replace');
teams
| Columna | Significado |
|---|---|
id | Clave estable. A lo que apuntan pilotos, patrocinadores y proveedores. Cualquier cadena única. |
name | Nombre visible. Una fila sin nombre se descarta. |
country | Nombre de país (Germany) o código ISO (de) — valen ambos |
budget_tier | small · medium · large — el comportamiento del equipo, no solo su caja |
budget_musd | Presupuesto inicial en millones. Fija también el nivel, salvo que budget_tier diga otra cosa |
reputation | 0-100 |
color1 · color2 · color3 | Hexadecimal, p. ej. #1A5FB4. Los tres vacíos = conservar la decoración generada |
car_index | Modelo de coche 0-11. Vacío = conservar el generado (0 es un coche real, no «sin definir») |
livery · suit | Índices de variante; 255 = generado |
logo | Un nombre de fila images, una ruta relativa a la carpeta de mods, o un simple número para un logo integrado |
car_image | Un nombre de fila images para un sprite de coche propio |
infra_engineering · _rnd · _chassis · _handling · _aero · _engine · _marketing · _scouting | Niveles de departamento 0-10. 0 = conservar el generado |
infra_academy | Igual, con tope 3 |
career_wins · career_titles · best_championship · founding_year | Palmarés, para un historial escrito |
history | Temporadas pasadas como temporada:posición:victorias, separadas por ; o saltos de línea |
La infraestructura y el palmarés solo importan de verdad en un escenario imposed, donde la parrilla debe ser un negocio en marcha desde la primera carrera.
drivers
| Columna | Significado |
|---|---|
id | Clave estable |
first_name · last_name | Una fila sin ninguno de los dos se descarta |
code | Código de tres letras. Se pasa a mayúsculas al cargar; un duplicado se renombra en silencio |
country | Código ISO — aquí el valor ES la clave de la bandera |
age | 1-55. Menos de 16 se permite para una promesa: envejece, queda oculto al Scouting hasta los 14, y no puede ocupar un asiento antes de que lo permitan las reglas de edad de la serie |
intelligence · pace · consistency · adaptability · stamina · aggressivity | Las seis aptitudes, 1-20 |
pot_intelligence … pot_aggressivity | Sus techos, 0-20. 0 = deja decidir al generador |
curve_intelligence … curve_aggressivity | Identificadores de curva de progresión; 255 = por defecto. Un identificador desconocido cae al valor por defecto en vez de congelar la estadística |
salary | Por temporada |
traits | Pares tipo:nivel separados por comas, p. ej. 3:1,7:2 |
face_sheet · face_index · helmet_index | Retrato; 255 = generado |
helmet_hue_0 · _1 · _2 | Tonos del casco. Los tres vacíos = generado |
team · team_id | El asiento. team_id gana si están los dos |
role | primary · secondary · reserve |
contract_years | 0-5 |
career_starts · career_wins · career_podiums · career_titles · best_finish | Palmarés |
fame | 0-100; 0 conserva el valor calculado |
Dos pilotos por escudería, uno por asiento. Dos pilotos primary en el mismo equipo dejan el coche 2 vacío — y un coche sin piloto no toma la salida.
sponsors
| Columna | Significado |
|---|---|
id | Clave estable |
name | Si está vacío se descarta |
sector | Sector de actividad — guía el logo procedural |
color | Hexadecimal |
budget · prominence | 1-10 |
origin | Nombre de país o código ISO |
logo | Un nombre de fila images o una ruta |
team · team_id | Firmarlo de antemano con una escudería. Acepta una lista separada por ; o , |
El primer patrocinador de un equipo pasa a ser su Principal, y los demás Secundarios.
suppliers
| Columna | Significado |
|---|---|
id | Clave estable |
name | Si está vacío se descarta |
category | engine · tires · fuel |
color · origin · logo | Como en patrocinadores |
budget · size | 1-10 |
money_per_gp | Dinero por carrera. Positivo = te paga, negativo = le pagas |
contract | partnership (exclusivo) o client. Gana sobre el signo de money_per_gp |
duration | 0-5 temporadas |
team · team_id | Firma previa; una lista, como en patrocinadores |
Las estadísticas técnicas tienen dos escrituras, y las columnas con nombre son la razón de ser de esta página. Cuatro casillas genéricas (stat_a … stat_d) significaban algo distinto según la categoría, algo que ninguna herramienta externa podía adivinar. Escribe mejor las columnas con nombre — ganan en cuanto están puestas y no valen cero:
| Categoría | Columnas con nombre (0-10) |
|---|---|
engine | power · reliability · endurance · potential |
tires | performance · endurance · reliability · heat |
fuel | efficiency |
circuits
Trazados dibujados a mano que lleva el pack. El editor de circuitos escribe estas filas, pero la geometría es texto plano: un script también puede.
| Columna | Significado |
|---|---|
id | Clave estable — a lo que apunta una ronda del calendario |
name | Si está vacío se descarta |
points | La línea central. Pares x,y unidos por ;. Con menos de tres puntos la fila se descarta |
country · city | Vacío da un lugar aleatorio pero estable |
target_km | Longitud de vuelta; por debajo de 1 vuelve a 5 km |
character | El carácter del trazado — es lo que la simulación lee de verdad |
preset | Identificador de preajuste visual |
start_finish · pit_entry · pit_exit | Posiciones a lo largo de la vuelta; negativo o ausente = deducido |
year · downforce · tire_wear · overtaking | Se guardan y se muestran, pero no se simulan — en juego esos tres salen de character |
calendar
Una fila por ronda, en orden sort, hasta 24.
| Columna | Significado |
|---|---|
kind | circuit = usar un circuito del pack; cualquier otro valor = trazado generado |
circuit · circuit_id | Cuál. Se prueba circuit_id primero |
character · target_km | Para una ronda generada |
Un pack que lleva calendario sustituye la temporada. Un pack que lleva circuitos sin calendario vierte sus trazados al fondo mundial y deja que ganen rondas por sí solos.
images
name (la clave a la que apuntan las otras tablas) y data, los bytes del PNG como BLOB. Los logos se dibujan a 195×195; un sprite de coche propio es una vista de perfil mirando a la derecha sobre transparencia, de 256 px de alto.
Insertar una imagen desde la línea de comandos:
sqlite3 my_pack.db "INSERT INTO images(name, data) VALUES('lotus.png', readfile('lotus.png'))"
…o desde Python:
db.execute("INSERT INTO images(name, data) VALUES(?, ?)",
("lotus.png", open("lotus.png", "rb").read()))
Luego haz que una fila apunte ahí: UPDATE teams SET logo = 'lotus.png' WHERE name = 'Lotus'.
Dos nombres que solo se diferencian en la puntuación (mi logo.png y mi-logo.png) se extraen al mismo archivo; el primero se lo queda y el segundo recibe un sufijo numerado, así que nada se sobrescribe en silencio.
Un pack mínimo, de principio a fin
CREATE TABLE meta(key TEXT, value TEXT);
INSERT INTO meta VALUES
('name','Dos escuderías'), ('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');
Eso es un pack completo y válido. Todo lo que no se menciona sigue siendo procedural.
Comprobar tu trabajo
Pregúntale al juego qué ve. Ejecútalo una vez desde un terminal con --list-mods: imprime las carpetas que recorre en orden, y después cada pack, circuito e idioma que ha encontrado. Es lo primero que hay que lanzar cuando un pack no aparece.
mod folders (read in this order):
/home/tu/.local/share/TheUndercut/mods
/ruta/del/juego/mods (does not exist)
packs:
my_pack
Lee la fila del pack en el selector. Ahí el juego dice qué ha entendido solo a medias — un formato más nuevo, una versión de juego que necesita, o dos escuderías con el mismo nombre, lo que vuelve ambiguos los vínculos.
Ábrelo una vez en el editor de mods. Su pestaña Audit pilla lo que el SQL no puede ver: un segundo asiento vacío, un piloto vinculado a una escudería inexistente, un código repetido. Abrir un pack escrito a mano también le estampa identificadores estables en las filas que no los tienen, que es lo mejor que se le puede hacer a un pack escrito a mano.
Trampas que conviene conocer
- Una columna mal escrita es silenciosa.
colour1no escolor1; simplemente nunca se lee. Si un cambio no parece hacer nada, comprueba primero la ortografía contra esta página —PRAGMA table_info(teams)lista lo que tu tabla tiene de verdad. - Los vínculos siguen primero
idy después el nombre. Dale un identificador a cada fila y renombrar una escudería le conserva sus pilotos. Sin identificadores, renombrarla manda sus pilotos al grupo de agentes libres. 0no quiere decir «sin definir» en todas partes. Significa conservar lo generado en potenciales, infraestructura y fama — perocar_indexa0es un coche real: deja esa columna vacía para conservar el modelo generado.- Un pack solo se aplica al crear la carrera. Editarlo no cambia nada en una carrera ya empezada. Empieza otra.
- El archivo debe quedarse donde está. Los logos y los sprites de coche se leen de él durante toda la carrera.
- Escribe tus cambios. Un navegador gráfico los guarda en una transacción pendiente — ciérralo sin Escribir cambios y no se habrá guardado nada.
Véase también
- Packs de mods — qué significa cada sección dentro del juego
- Editor de mods — la herramienta que escribe todo esto por ti
- Modding de circuitos — dibujar los trazados que lleva un pack
- Publicar en el Steam Workshop — compartir el pack terminado