Wiki en construcción. Muchos conceptos de aquí provienen de la alpha 0.2 y todavía pueden cambiar. La wiki se finalizará para la versión 1.0 — por ahora está para ayudar a los testers cerrados y, más adelante, a los jugadores del acceso anticipado a orientarse. Para la información más actual y fiable, únete al Discord — es donde se anuncian los cambios primero y donde puedes preguntar directamente.

Únete al Discord para las últimas novedades

Editar un pack en SQL

El esquema completo de un pack de mods, tabla por tabla, las herramientas para abrirlo — sqlite3, DB Browser, un script de Python — y las reglas que sigue el cargador.

En esta página

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.

Editor de mods en el juego · comprobado DB Browser edición tipo hoja de cálculo sqlite3 · Python cambios masivos · generación my_pack.db un archivo SQLite El juego lo lee al crear

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.

ClaveValorPor defecto
nameEl nombre que se muestra en el selectorel nombre del archivo
authorTu nombre — se muestra con el pack—
schema_versionVersión de formato de este pack (actual: 2)1
min_game_versionBuild mínimo que lo entiende, p. ej. 0.5.4-6ninguno
scenarionew_series (entras como escudería nueva) o imposed (tomas el mando de una parrilla escrita)new_series
start_yearAño natural de la temporada 1el del juego
teams_mode · drivers_mode · sponsors_mode · suppliers_mode · circuits_modeextend (se suma al mundo generado) o replace (solo los tuyos)extend
active_seriesLista CSV de campeonatos a disputar, p. ej. PFS,PF2todos los activos
rulesLista CSV de identificadores de reglamento, p. ej. points_classic_top6,quali_107los 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_version supera 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_version es 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

ColumnaSignificado
idClave estable. A lo que apuntan pilotos, patrocinadores y proveedores. Cualquier cadena única.
nameNombre visible. Una fila sin nombre se descarta.
countryNombre de país (Germany) o código ISO (de) — valen ambos
budget_tiersmall · medium · large — el comportamiento del equipo, no solo su caja
budget_musdPresupuesto inicial en millones. Fija también el nivel, salvo que budget_tier diga otra cosa
reputation0-100
color1 · color2 · color3Hexadecimal, p. ej. #1A5FB4. Los tres vacíos = conservar la decoración generada
car_indexModelo de coche 0-11. Vacío = conservar el generado (0 es un coche real, no «sin definir»)
livery · suitÍndices de variante; 255 = generado
logoUn nombre de fila images, una ruta relativa a la carpeta de mods, o un simple número para un logo integrado
car_imageUn nombre de fila images para un sprite de coche propio
infra_engineering · _rnd · _chassis · _handling · _aero · _engine · _marketing · _scoutingNiveles de departamento 0-10. 0 = conservar el generado
infra_academyIgual, con tope 3
career_wins · career_titles · best_championship · founding_yearPalmarés, para un historial escrito
historyTemporadas 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

ColumnaSignificado
idClave estable
first_name · last_nameUna fila sin ninguno de los dos se descarta
codeCódigo de tres letras. Se pasa a mayúsculas al cargar; un duplicado se renombra en silencio
countryCódigo ISO — aquí el valor ES la clave de la bandera
age1-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 · aggressivityLas seis aptitudes, 1-20
pot_intelligence … pot_aggressivitySus techos, 0-20. 0 = deja decidir al generador
curve_intelligence … curve_aggressivityIdentificadores de curva de progresión; 255 = por defecto. Un identificador desconocido cae al valor por defecto en vez de congelar la estadística
salaryPor temporada
traitsPares tipo:nivel separados por comas, p. ej. 3:1,7:2
face_sheet · face_index · helmet_indexRetrato; 255 = generado
helmet_hue_0 · _1 · _2Tonos del casco. Los tres vacíos = generado
team · team_idEl asiento. team_id gana si están los dos
roleprimary · secondary · reserve
contract_years0-5
career_starts · career_wins · career_podiums · career_titles · best_finishPalmarés
fame0-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

ColumnaSignificado
idClave estable
nameSi está vacío se descarta
sectorSector de actividad — guía el logo procedural
colorHexadecimal
budget · prominence1-10
originNombre de país o código ISO
logoUn nombre de fila images o una ruta
team · team_idFirmarlo 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

ColumnaSignificado
idClave estable
nameSi está vacío se descarta
categoryengine · tires · fuel
color · origin · logoComo en patrocinadores
budget · size1-10
money_per_gpDinero por carrera. Positivo = te paga, negativo = le pagas
contractpartnership (exclusivo) o client. Gana sobre el signo de money_per_gp
duration0-5 temporadas
team · team_idFirma 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íaColumnas con nombre (0-10)
enginepower · reliability · endurance · potential
tiresperformance · endurance · reliability · heat
fuelefficiency

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.

ColumnaSignificado
idClave estable — a lo que apunta una ronda del calendario
nameSi está vacío se descarta
pointsLa línea central. Pares x,y unidos por ;. Con menos de tres puntos la fila se descarta
country · cityVacío da un lugar aleatorio pero estable
target_kmLongitud de vuelta; por debajo de 1 vuelve a 5 km
characterEl carácter del trazado — es lo que la simulación lee de verdad
presetIdentificador de preajuste visual
start_finish · pit_entry · pit_exitPosiciones a lo largo de la vuelta; negativo o ausente = deducido
year · downforce · tire_wear · overtakingSe 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.

ColumnaSignificado
kindcircuit = usar un circuito del pack; cualquier otro valor = trazado generado
circuit · circuit_idCuál. Se prueba circuit_id primero
character · target_kmPara 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. colour1 no es color1; 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 id y 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.
  • 0 no quiere decir «sin definir» en todas partes. Significa conservar lo generado en potenciales, infraestructura y fama — pero car_index a 0 es 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