Wiki em construção. Muitos conceitos aqui vêm da alpha 0.2 e ainda podem mudar. A wiki será finalizada para a versão 1.0 — por agora serve para ajudar os testadores fechados e, mais tarde, os jogadores do acesso antecipado a orientar-se. Para as informações mais atuais e fiáveis, entre no Discord — é lá que as mudanças são anunciadas primeiro e onde pode perguntar diretamente.

Entrar no Discord para as últimas novidades

Editar um pack em SQL

O esquema completo de um pack de mods, tabela a tabela, as ferramentas para abri-lo — sqlite3, DB Browser, um script Python — e as regras que o carregador segue.

Nesta página

Um pack de mods é um simples banco SQLite. O editor de mods é o jeito confortável de escrever um, mas nada impede você de abrir o arquivo por conta própria — e para certos trabalhos esse é de longe o caminho mais rápido:

  • importar uma temporada real de uma planilha ou de um CSV;
  • renomear quarenta patrocinadores, ou aumentar em 10 % o salário de cada piloto;
  • gerar um pack a partir de um script, para refazê-lo sempre que os dados de origem mudarem;
  • ler o pack de outra pessoa para ver como ela fez.

Esta página é a referência para isso. Ela documenta o que o jogo realmente lê — coluna por coluna — e as regras que segue. Nada aqui é detalhe interno: o carregador é deliberadamente tolerante, e saber o quanto ele é é justamente o que permite escrever um pack à mão com confiança.

Você nunca precisa desta página para fazer um mod. O editor de mods escreve todas as tabelas descritas aqui, confere seu trabalho e atualiza packs antigos. Recorra ao SQL quando quiser alterações em massa ou geração por script.


Abrir um pack

Qualquer ferramenta SQLite serve — o arquivo não tem cabeçalho próprio, nem compressão, nem criptografia.

Editor de mods no jogo · conferido DB Browser edição tipo planilha sqlite3 · Python em massa · geração my_pack.db um arquivo SQLite O jogo lê ao criar a carreira

Gráfico — o DB Browser for SQLite é gratuito, roda em Windows, macOS e Linux, e edita tabelas como uma planilha. É a entrada mais suave se você nunca escreveu SQL: abra o arquivo, vá em Navegar dados, escolha uma tabela e digite. Lembre-se de Gravar alterações antes de fechar.

Linha de comando — o sqlite3 vem com o macOS e com a maioria das distribuições Linux, e no Windows é um download pequeno:

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

A partir de um script — o Python já traz SQLite, o que torna um pack uma saída 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()

Trabalhe sempre numa cópia. Um pack é um único arquivo — fazer backup dele é um arrastar.


As regras que o carregador segue

Estas seis regras são o que torna segura a edição à mão. Vale lê-las antes do próprio esquema.

1 — Toda tabela é opcional. Um pack só com a tabela drivers é válido. Uma tabela ausente significa «aquela seção continua procedural», nunca um erro.

2 — Toda coluna é opcional. O carregador pergunta ao SQLite quais colunas sua tabela realmente tem e serve o resto como NULL. Então CREATE TABLE teams(name TEXT) funciona. Isso também significa que um pack escrito para uma versão mais antiga continua carregando, e que um erro de digitação num nome de coluna não é um erro — a coluna simplesmente nunca é lida, e esse é o único modo de falha a vigiar.

3 — Os tipos são tolerantes. Cada valor é lido como texto, não importa como foi guardado. 12, "12" e até 12.0 chegam todos como o número 12 onde se espera um número. Guarde o que for conveniente.

4 — As linhas são ordenadas por sort. Acrescente uma coluna inteira sort e as linhas são lidas nessa ordem; sem ela, vêm na ordem de inserção. A ordem importa para as equipes (o grid é construído nela) e para as etapas do calendário.

5 — Vazio significa «manter o que o jogo gerou». É a regra mais útil de todas. Uma cor vazia mantém a pintura gerada, um car_index vazio mantém o modelo gerado, um potencial em 0 deixa o gerador definir o teto. Você sobrescreve o que lhe interessa e deixa o resto em paz.

6 — Uma linha ruim é descartada, não é fatal. Uma equipe sem nome, um circuito com menos de três pontos, uma linha de histórico malformada — cada uma cai sozinha. O resto do pack carrega assim mesmo.


meta — as configurações do próprio pack

Duas colunas, key e value, uma linha por configuração. As chaves não diferenciam maiúsculas.

ChaveValorPadrão
nameO nome exibido no seletoro nome do arquivo
authorSeu nome — exibido com o pack—
schema_versionVersão de formato deste pack (atual: 2)1
min_game_versionBuild mínima que o entende, ex. 0.5.4-6nenhuma
scenarionew_series (você entra como equipe nova) ou imposed (você assume um grid já escrito)new_series
start_yearAno civil da temporada 1o do jogo
teams_mode · drivers_mode · sponsors_mode · suppliers_mode · circuits_modeextend (soma-se ao mundo gerado) ou replace (só os seus)extend
active_seriesLista CSV dos campeonatos a disputar, ex. PFS,PF2todos os ativos
rulesLista CSV de identificadores de regulamento, ex. points_classic_top6,quali_107os da série

replace também aceita only; imposed também aceita takeover ou existing. Um valor desconhecido cai no padrão em vez de falhar.

Duas chaves são um aperto de mão com o jogo, e é por isso que um pack nunca falha em silêncio:

  • se schema_version for maior do que a build entende, a linha do pack no seletor diz isso — «escrito para um formato mais novo» — e as partes ilegíveis são ignoradas;
  • se min_game_version for mais nova que a build, a linha diz «precisa do jogo X ou mais recente».

Preencha as duas. Custam duas linhas e transformam um pack meio funcionando e enigmático numa mensagem clara.

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

teams

ColunaSignificado
idChave estável. Aquilo a que pilotos, patrocinadores e fornecedores apontam. Qualquer texto único.
nameNome exibido. Uma linha sem nome é descartada.
countryNome do país (Germany) ou código ISO (de) — os dois funcionam
budget_tiersmall · medium · large — o comportamento da equipe, não só o caixa
budget_musdOrçamento inicial em milhões. Define também a faixa, a menos que budget_tier diga outra coisa
reputation0-100
color1 · color2 · color3Hexadecimal, ex. #1A5FB4. Os três vazios = manter a pintura gerada
car_indexModelo de carro 0-11. Vazio = manter o gerado (0 é um carro de verdade, não «indefinido»)
livery · suitÍndices de variante; 255 = gerado
logoUm nome de linha images, um caminho relativo à pasta de mods, ou um simples número para um logo embutido
car_imageUm nome de linha images para um sprite de carro próprio
infra_engineering · _rnd · _chassis · _handling · _aero · _engine · _marketing · _scoutingNíveis de departamento 0-10. 0 = manter o gerado
infra_academyIdem, com teto 3
career_wins · career_titles · best_championship · founding_yearPalmarés, para um histórico escrito
historyTemporadas passadas como temporada:posição:vitórias, separadas por ; ou quebras de linha

Infraestrutura e palmarés só importam de verdade num cenário imposed, em que o grid precisa ser um negócio em andamento desde a primeira corrida.


drivers

ColunaSignificado
idChave estável
first_name · last_nameUma linha sem nenhum dos dois é descartada
codeSigla de três letras. Passa a maiúsculas ao carregar; uma repetição é renomeada em silêncio
countryCódigo ISO — aqui o valor É a chave da bandeira
age1-55. Menos de 16 é permitido para uma promessa: ele envelhece, fica oculto ao Scouting até os 14, e não pode ocupar uma vaga antes que as regras de idade da série permitam
intelligence · pace · consistency · adaptability · stamina · aggressivityAs seis aptidões, 1-20
pot_intelligence … pot_aggressivitySeus tetos, 0-20. 0 = deixe o gerador decidir
curve_intelligence … curve_aggressivityIdentificadores de curva de evolução; 255 = padrão. Um identificador desconhecido cai no padrão em vez de congelar o atributo
salaryPor temporada
traitsPares tipo:nível separados por vírgulas, ex. 3:1,7:2
face_sheet · face_index · helmet_indexRetrato; 255 = gerado
helmet_hue_0 · _1 · _2Tons do capacete. Os três vazios = gerado
team · team_idA vaga. team_id vence se os dois estiverem preenchidos
roleprimary · secondary · reserve
contract_years0-5
career_starts · career_wins · career_podiums · career_titles · best_finishPalmarés
fame0-100; 0 mantém o valor calculado

Dois pilotos por equipe, um por vaga. Dois pilotos primary na mesma equipe deixam o carro 2 vazio — e um carro sem piloto não larga.


sponsors

ColunaSignificado
idChave estável
nameVazio, a linha é descartada
sectorSetor de atuação — orienta o logo procedural
colorHexadecimal
budget · prominence1-10
originNome do país ou código ISO
logoUm nome de linha images ou um caminho
team · team_idAssiná-lo de antemão com uma equipe. Aceita uma lista separada por ; ou ,

O primeiro patrocinador de uma equipe vira o Principal, os demais Secundários.


suppliers

ColunaSignificado
idChave estável
nameVazio, a linha é descartada
categoryengine · tires · fuel
color · origin · logoComo nos patrocinadores
budget · size1-10
money_per_gpDinheiro por corrida. Positivo = ele paga você, negativo = você paga ele
contractpartnership (exclusivo) ou client. Vence sobre o sinal de money_per_gp
duration0-5 temporadas
team · team_idAssinatura prévia; uma lista, como nos patrocinadores

As estatísticas técnicas têm duas escritas, e as colunas nomeadas são a razão de ser desta página. Quatro casas genéricas (stat_a … stat_d) significavam coisas diferentes conforme a categoria, algo que nenhuma ferramenta de terceiros conseguia adivinhar. Escreva de preferência as colunas nomeadas — elas vencem assim que estiverem preenchidas e diferentes de zero:

CategoriaColunas nomeadas (0-10)
enginepower · reliability · endurance · potential
tiresperformance · endurance · reliability · heat
fuelefficiency

circuits

Os traçados desenhados à mão que o pack carrega. O editor de circuitos escreve essas linhas, mas a geometria é texto puro: um script também consegue.

ColunaSignificado
idChave estável — aquilo a que uma etapa do calendário aponta
nameVazio, a linha é descartada
pointsA linha central. Pares x,y unidos por ;. Com menos de três pontos a linha é descartada
country · cityVazio dá um lugar aleatório, porém estável
target_kmComprimento da volta; abaixo de 1 volta a 5 km
characterO caráter do traçado — é o que a simulação realmente lê
presetIdentificador de predefinição visual
start_finish · pit_entry · pit_exitPosições ao longo da volta; negativo ou ausente = deduzido
year · downforce · tire_wear · overtakingGuardados e exibidos, mas não simulados — em jogo esses três derivam do character

calendar

Uma linha por etapa, em ordem sort, até 24.

ColunaSignificado
kindcircuit = usar um circuito do pack; qualquer outro valor = traçado gerado
circuit · circuit_idQual. circuit_id é tentado primeiro
character · target_kmPara uma etapa gerada

Um pack que carrega um calendário substitui a temporada. Um pack que carrega circuitos sem calendário despeja seus traçados no acervo mundial e os deixa conquistar etapas sozinhos.


images

name (a chave a que as outras tabelas apontam) e data, os bytes do PNG como BLOB. Os logos são desenhados em 195×195; um sprite de carro próprio é uma vista de perfil voltada para a direita sobre transparência, com 256 px de altura.

Inserir uma imagem pela linha de comando:

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

…ou pelo Python:

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

Depois aponte uma linha para lá: UPDATE teams SET logo = 'lotus.png' WHERE name = 'Lotus'.

Dois nomes que só diferem na pontuação (meu logo.png e meu-logo.png) vão parar no mesmo arquivo; o primeiro fica com ele e o segundo recebe um sufixo numerado, de modo que nada é sobrescrito em silêncio.


Um pack mínimo, do início ao fim

CREATE TABLE meta(key TEXT, value TEXT);
INSERT INTO meta VALUES
  ('name','Duas equipes'), ('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');

Esse é um pack completo e válido. Tudo o que não for mencionado continua procedural.


Conferir o seu trabalho

Pergunte ao jogo o que ele vê. Rode-o uma vez a partir de um terminal com --list-mods: ele imprime as pastas que percorre na ordem, e depois cada pack, circuito e idioma encontrados. É a primeira coisa a rodar quando um pack não aparece.

mod folders (read in this order):
  /home/voce/.local/share/TheUndercut/mods
  /caminho/do/jogo/mods   (does not exist)
packs:
  my_pack

Leia a linha do pack no seletor. Ali o jogo diz o que entendeu só pela metade — um formato mais novo, uma versão de jogo de que precisa, ou duas equipes com o mesmo nome, o que torna os vínculos ambíguos.

Abra-o uma vez no editor de mods. A aba Audit pega o que o SQL não enxerga: uma segunda vaga vazia, um piloto ligado a uma equipe inexistente, uma sigla repetida. Abrir um pack escrito à mão também carimba identificadores estáveis nas linhas que não os têm, e essa é a melhor coisa que se pode fazer a um pack escrito à mão.


Armadilhas que vale conhecer

  • Uma coluna escrita errado é silenciosa. colour1 não é color1; ela simplesmente nunca é lida. Se uma alteração parece não fazer nada, confira primeiro a grafia contra esta página — PRAGMA table_info(teams) lista o que sua tabela tem de verdade.
  • Os vínculos seguem primeiro o id, depois o nome. Dê um identificador a cada linha e renomear uma equipe preserva os pilotos dela. Sem identificadores, renomeá-la joga seus pilotos no grupo de agentes livres.
  • 0 não quer dizer «indefinido» em todo lugar. Significa manter o gerado para potenciais, infraestrutura e fama — mas car_index em 0 é um carro de verdade: deixe essa coluna vazia para manter o modelo gerado.
  • Um pack só se aplica na criação da carreira. Editá-lo não muda nada numa carreira já em andamento. Comece outra.
  • O arquivo precisa ficar onde está. Logos e sprites de carro são lidos dele durante toda a vida da carreira.
  • Grave suas alterações. Um navegador gráfico as mantém numa transação pendente — feche-o sem Gravar alterações e nada terá sido salvo.

Veja também