You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
RE: headless Ghidra export of every non-thunk function as decompiled C with our names (re/scripts/export_decomp.sh, re/db/decomp) for parallel grep-based analysis.
Feature: PK2 archive reader with filename-hash lookup and the rt2-extract tool.
Feature: LNG string-table parser (last definition wins, named ;t<NAME>_0 tables).
RE: PK2 filename hash, archive load order and precedence recovered from the executable.
Docs: development plan, file-format specs for PK2 and LNG, project README.
RE: PK2 contents classified: LAD sprite format (8-bit indexed, per-row RLE, layered), palette banks, RGB palettes, IMB layouts and raw PCM audio.
Docs: game rules, formulas and data tables extracted from the manual, strategy guide and editor notes (docs/reference/manual-rules.md).
RE: sprite palette rule recovered: a LAD record's second header word selects the bank PALT%04d.PAL (loader at 0x4f8b80, palette reader at 0x4f8ed0); palette words are XRGB1555.
RE: LAD layout corrected (records of image groups with frame maps); all 1990 sprite banks parse to the last byte.
Feature: LAD sprite and palette-bank parsers with RGBA conversion in rt2-formats, and the rt2-sprite tool that renders an entry to PNG.
Docs: docs/formats/lad.md with the sprite layout, palette rule and source addresses.
Feature: rt2-oracle differential-testing harness: a PE32 loader plus Unicorn emulation that runs single functions of the original executable (cdecl/stdcall/thiscall, IAT stubs that name any OS import touched, .data snapshot/restore, x87 ST0 readout).
RE: the PK2 name-hash case fold (0x4f0d70) matches rt2_formats::pk2::fold_name_byte for all 256 byte values, checked against the original in the emulator.
Docs: docs/oracle.md explains how to write a differential test.
RE: maps/*.MAP and games/*.GAM are uncompressed: header with map size at 0x231, 10-byte tile records (ground, trees, structure, track, territory) from 0xB2D7 and an i16 corner heightmap of (w+1)*(h+1); renders reproduce Britain, Chesapeake and the other 31 maps, see docs/formats/map-gam.md and re/scripts/mapgam.py.
RE: automatic first-pass classification of all 2945 functions Ghidra finds in RT2_PLAT.EXE (re/coverage.toml: 680 classified, 262 lib, 4 sim candidates), produced by re/scripts/dump_program.sh and re/scripts/classify.py.
Feature: .MAP/.GAM parser (rt2_formats::map): header, tile records and corner elevations for all 31 maps and both saves.
Feature: rt2-render (wgpu terrain mesh, 2:1 isometric camera) and rt2-viewer, which opens an original map with pan, zoom and 90-degree rotation, or writes a screenshot with --screenshot.
RE: calendar recovered from the executable: 12 months of 28 days, minute resolution, absolute minutes ((((y*12+m)*28+d-29)*24+h)*60)+min (0x4a4950, 0x4a4990, 0x4a4a30), checked against the original in the emulator for 20000 dates.
RE: game speed is an index 0..10 (default 3) into the table 0, 0.3, 0.6, 1, 1.7, 2.1, 3, 5, 8, 12, 18; game minutes per frame = ftol(table * ms * 3.2), so one day lasts 450 ms at speed 3 (0x46c650, 0x536508).
RE: main loop and tick structure documented in docs/spec/time.md: frame gate every >100 ms (0x404e30), sim_advance (0x4a5cb0) with week end on days 7/14/21/28, month end on day 28 and year end on 28 December, all at 23:59, plus the scenario-event trigger kinds fired around each.
RE: the game RNG is an ANSI C LCG (state 0x55d2c0, s*0x41c64e6d+0x3039, output (s>>16)&0x7fff) with an inclusive-range wrapper (0x4f0660), a stateless seed-hash variant (0x4f06f0) and the MSVC CRT rand (0x51c137) for audio, UI and session ids; all four match the original in 20000+ emulated calls each (docs/spec/rng.md).
RE: first simulation functions moved to spec/verified in re/coverage.toml (22 of 31 classified simulation functions), 73 symbols in re/symbols.toml.
Docs: docs/spec/time.md and docs/spec/rng.md, the first P0 simulation specs, with open questions (x87 precision, entity list identities, CRT rand in train code).
RE: cargo table found in the executable's .data (0x5404b1, 46 records of 33 bytes: price, delivery days, distance sensitivity, first year, town/city cut-off years, demand per house, storage-upgrade bit); prices are multiplied by 1.4 at start-up, so the effective base price differs from the manual (passengers 56000 raw, 78400 effective).
RE: delivery revenue formula recovered and verified bit-exact against the original (0x4bf760, 8000 random deliveries): distance factor X = 1 - s + s*1.4*d/(15 + 0.5*(year-1800)) applied twice, a time penalty 0.3 + 0.7*(allowed - elapsed)/allowed, demand-level price table 0.5..1.4 (expert), manager/event effects, economy state, human/computer sliders and a progressive cut above $80000 per load.
RE: manager, event and territory effect multiplier (0x46b480) verified: product of (1 + level/100) over global, company, person and territory levels with a 0.01 floor.
RE: industry production decoded: a table of 53 types x 4 output slots (0x541ae0) gives primary rates, converter ratios, bonus inputs (fertilizer 0.5/0.25, grain 0.5) and demand weights; lots are created from 483840 / (rate * effects * economy) minutes (faster after 1930, 1950 and 1970), at most 50 waiting per slot; rate and input-list rebuild verified against the original.
RE: cargo waits in the industry's pile, not in the station; stations load the oldest lot in their catchment, price levels 0..9 come from demand weight over a delivery counter that decays by 0.94 per month, and the economic state (0x46a010, every six months) scales production (0.84..1.16) and revenue (0.8..1.2).
RE: code and manual disagree on cargo economy details: $2000 station fee per loaded car at each end (manual $1000), passenger-bonus buildings pay the station owner 10/15/5/15/25% (manual 20/30/10/20/40%) and several cargo prices and cut-off years differ; see docs/spec/cargo.md section 11.
Docs: docs/spec/cargo.md, the cargo economy spec, with the cargo and industry tables extracted from the executable, differential tests in crates/rt2-oracle/tests/cargo.rs and open questions (x87 precision changes about 10% of revenues, commit-path functions untested).
RE: formato completo do .MAP/.GAM decodificado a partir do carregador 0x477a60 e do gravador 0x477540: blocos globais, tiles, elevacao, 15 pools de slots (estruturas, estacoes, pessoas, empresas, objetos, pecas de trilho, trens, lugares, territorios...), extras de trens e regras de cenario; data/hora e game_seed localizados (o estado do RNG nao e salvo)
Feature: rt2_formats::map::Save le data e hora do jogo, game_seed, lugares (cidades) com coordenadas, empresas, pessoas, estacoes, trens e regras de cenario; os 33 .MAP/.GAM originais sao consumidos ate o ultimo byte
RE: simulação de trens em docs/spec/trains.md: tabela de 66 locomotivas (0x53cec0) e 175 tipos de veículo (0x53ddb8) no .data, curva de velocidade 0x4cfea0 (reproduz a tabela A-1 do guia), rampa por trecho 0x4284e0, passo de aceleração 0x4d0400, probabilidade e consequências de quebra/acidente (0x4cf030, 0x4cf390), custos mensais de combustível e manutenção (0x4d4390)
RE: o crt_rand_range(0, 3) dos trens (0x4d0400, 0x4d2360, 0x4d29e0) só escolhe som; quebras usam o RNG do jogo; /nowreck multiplica a chance por 1e-4 em vez de zerar
RE: oráculo tests/trains.rs: rampa, curva de velocidade, passo de aceleração e chance de quebra idênticos ao original em 70 000 casos aleatórios
Docs: preços do apêndice do guia que divergem do executável (GP9, SD45, E60CP, Eurostar, TGVs) anotados em docs/spec/trains.md
RE: precisão x87 medida no original sob Wine (winedbg --gdb + gdb): thread principal em FPCW 0x27F (53 bits) no porteiro de quadros e em sim_advance; sandbox e sondas em re/scripts/wine/ (docs/dynamic-analysis.md)
Feature: novo crate rt2-sim, nucleo de simulacao deterministico: RNG do jogo (LCG e hash), calendario e velocidade, multiplicador de efeitos, receita de entrega, taxa de producao e reconstrucao de entradas das industrias, curva de velocidade, aceleracao, chance de quebra e custos mensais dos trens, camada de comandos (Command, World::apply) e carregador em tempo de execucao das tabelas do EXE
Improved: os testes diferenciais do oraculo (sim_time_rng, cargo, trains) agora exercitam as funcoes publicas do rt2-sim em vez de copias locais, e conferem o carregador de tabelas contra a memoria emulada
Docs: docs/spec/time.md registra a divergencia intencional do clone (quadro nominal fixo de 100 ms)
RE: bitmap fonts: font%s.dat is only a name (hash) selecting one of 10 built-in definitions (0x4f24c0) over LAD banks copp6/8/10/12/14/24.imb, scri11, fran13, haet46, htra46; glyph = record ch-0x20, group 0 alpha mask, group 1 shadow; metrics in docs/formats/font.md
RE: glyph RLE (0x4fff00) has tokens beyond plain LAD: 0x80-0x9f darken the destination, 0xa0-0xbf are alpha runs over the text colour
RE: .win UI layouts (46 files) decoded from the loader 0x507600: 65-byte window struct, 10 control types with action id, rectangle, font and sprite bank; see docs/formats/ui.md
Feature: bitmap font reader (rt2_formats::font) and the rt2-font tool that renders text to PNG
Feature: UI layout parser (rt2_formats::ui) and the rt2-ui tool that draws a window's geometry with its sprites
Docs: docs/formats/font.md and docs/formats/ui.md
RE: advance_save.py avança um save N dias no original (Wine+gdb, sem GUI) via carga do menu 0x479710, sim_advance 0x4a5cb0 e gravador 0x477540; determinístico byte a byte com a mesma semente (docs/dynamic-analysis.md seção 5)
RE: especificacao de trilho, pontes, terraplenagem e estacoes em docs/spec/terrain-track.md: custo por tile (0x463520), formas de aresta validas (0x5365e8), pontes por tipo (0x53ce60), custo de estacao e captacao (0x407030, raios 2/4/8)
RE: oraculo tests/track.rs: custo de trilho por tile (30 000 casos) e teste de captacao de estacao (20 000 casos) identicos ao original
Docs: divergencias do manual no custo de trilho (base 2x2000 por tile, terreno por classe, ponte por tile, vao 120 000) anotadas em docs/spec/terrain-track.md
Feature: rt2_formats::map::Save::parse e Map::parse leem a versao 0x2348 (os 95 .MP2 e os saves gravados pelo proprio jogo) alem da 0x233C, via Layout; checksum do arquivo (checksum, file_checksum) confere nos 95 .MP2
RE: diferencas 0x233C vs 0x2348 do carregador 0x477a60: cabecalho 0x898a, estado 0x3a74, registros de pool maiores (estacao 0x4c7, pessoa 0x576, empresa 0x4e86, trem 0x14d, lugar 0xb4, territorio 0x314), carro de trem de 14 bytes, passo de rota de 8 bytes, parte fixa de regra 0x362; checksum em +0x86f7 (0x4ef4d0)
RE: finance spec completa: preco fundamental e de negociacao da acao, rating de credito, taxa de bonds, dividendos trimestrais (meses 3/6/9/12, resolve a pendencia de time.md), falencia, margem, fim de ano e desdobramento, fusao e eleicao de chairman
Improved: novo teste diferencial tests/finance.rs cobre taxa prime, preco de negociacao, preco fundamental, rating de credito e taxa de bond contra o original
Feature: rt2-savediff compares two saves (0x233C or 0x2348) field by field with a versioned mask of volatile bytes; Save::fields() walks every byte of a save
RE: volatile bytes of a save written by the original located (rule and train heap pointers, one person field, preview, checksum); fields that change per day/month documented in docs/dynamic-analysis.md
Change: rt2-sim pow is now a deterministic integer implementation of the CRT _CIpow x87 sequence (no libm); matches the host x87 within 1 ulp and exactly after ftol
Feature: rt2-sim track module (direction/edge-mask types, valid shapes, track tile cost, station catchment) with tables read from the EXE at run time
Feature: rt2-sim breakdown_check reproduces the whole 0x4cf390 dice including the theft roll and the RNG sequence
Improved: differential tests for monthly train costs, purchase price, production period and the breakdown/theft dice
RE: names for the CRT pow routines (crt_ci_pow 0x51bab0, crt_pow 0x51bad2, crt_exp2_tail 0x51f120) and the theft-roll details of 0x4cf390
Docs: docs/spec/world-tick.md specifies the world update order: sim_advance passes (animations, then trains in linked-list order), day/week/month/year hooks with every callee in order, game-RNG call sites per tick, confirmed against the original with a gdb call trace (Tutorial and Example saves).
RE: world tick list iteration (linked-list order, three removal-safe patterns), one minute per day without train movement, December month end also fires trigger 2 after the year end, monthly personal interest (prime - 4%)/12.
Feature: re/scripts/wine/trace_save.py traces call order and counts inside the original (gdb breakpoints that never stop) while advancing a save headless.
Feature: modulo rt2-sim::finance com preco fundamental e de negociacao da acao, rating de credito, taxa prime e de bonds, juros do caixa, dividendos trimestrais e teto do conselho, desdobramento, falencia e passo mensal da empresa
Improved: tests/finance.rs agora testa o codigo de rt2-sim contra o original e cobre lancamentos contabeis, anualizacao, teto de dividendos e falencia
RE: teto de dividendos 0x43edf0, anualizacao 0x43a440, lancamentos 0x439970/0x4398d0 e falencia 0x43bc30 verificados bit a bit; leitura exata dos maximos de 0x43edf0 resolvida
RE: sprite catalog of all 1987 LAD banks: 1739 more filenames recovered from the cr%s%s, bl%s%s/bn%s%s and tree/portrait/logo sprintf patterns (1855 of 1987 banks now named); terrain banks are 64x64 mip-mapped textures projected onto 128x64 tile diamonds (2 px per elevation unit, 4 view rotations), tracks use edge_shape_table x 0x536594, vehicles have 8 (locomotives) or 4 (wagons) directions per rotation bank.
Feature: rt2-sheet tool (bank listing, record dump, palette-index histogram, contact sheets) and re/names/sprite_catalog.tsv (hash, name, category, notes).
RE: crescimento do mundo em docs/spec/world-growth.md: passo anual de cidades e regiões (0x430a40/0x430540: alvo de casas e de tamanho de indústrias x índice de serviço 50..300%, chance de criar/demolir por ano), escolha do tipo (pesos do mapa x escassez x ano inicial, 0x42ffc0) e do terreno (0x42fcb0, 0x42fb10), demolição do prédio menos lucrativo (0x4302c0), lucratividade anual da indústria (0x40b450), compra/venda (0x43eb60, venda devolve metade) e compra pela IA (0x436950), oferta mensal de bônus de conexão (0x431660) e a sequência de chamadas do RNG; não existem desastres no código base
RE: finance.md rotula as contas 4 e 5 trocadas: train_create (0x4cdf80) usa a conta 4 e a compra de indústrias (0x43eb60) a conta 5
Improved: novo módulo rt2-sim::growth e teste diferencial tests/growth.rs (10 testes) com stubs de código de máquina sobre os callees: passo de crescimento, escolha de tipo e de local, demolição, estatísticas, classes de terreno, lucratividade, relógios iniciais e oferta de bônus idênticos ao original, inclusive o estado do RNG
Feature: world loop in rt2-sim (sim_advance with midnight split, day/week/month/year hooks, weekly industry production, economy state step, town bonus roll, personal cash interest), counters for implemented and missing steps
Feature: Save::to_bytes writes 0x233C/0x2348 saves byte for byte (checksum 0x4ef4d0 included); rt2-advance tool advances a save N days like advance_save.py
RE: first end-to-end comparison against the original (docs/fidelity-status.md): Tutorial 1 day equal, 7 and 30 days differ in 3 fields; runtime industry type row 28 differs from the exe .data
Docs: fidelity scoreboard docs/fidelity-status.md
Feature: rt2-viewer draws original maps with the game's own graphics (ground, ocean and track textures, trees, houses, industries, stations) read from the install dir (--game-dir / RT2_DIR)
Improved: terrain relief now uses the original's 2 px per elevation unit at native zoom; view rotation 0 matches the original projection
Feature: sprite upscaling for high DPI: Scale2x bake into an atlas at load plus a sharp-bilinear sampler
RE: ground ids are ordered like ground.imb records (ground 0x00 only uses ids 0-2); ground.imb families listed in code; map object pool (0x574c74) byte 6 = building type, i16 x/y at +0x22/+0x24
Docs: spec da IA (docs/spec/ai.md): turno mensal, expansao (primeira linha, ligacao de cidades), gestao de trens e escolha de paradas/composicao, gerente, compra de industria, financas e bolsa, personas do .data e ordem do RNG
RE: 37 funcoes, tabelas e globais da IA nomeadas (ai_extend_network, ai_pick_stop, ai_manage_trains, ai_persona_table...); ai_pick_engine e ai_town_value verificados no oraculo (tests/ai.rs)
RE: industry_load_fixups (0x4719e0) encontrada por watchpoint no Wine: na carga copia a linha do Port (tipo 28) do cabecalho do save (0x57023b), recalcula os anos dos slots e ajusta as taxas das casas pela dificuldade (docs/spec/cargo.md 7.1.1)
Improved: rt2-sim aplica industry_load_fixups; Tutorial 7 e 30 dias passam a bater com o original em todos os campos (0 diferencas)
RE: sistema de cenarios em docs/spec/scenarios.md: registro de regra de 0x362 bytes (gatilhos 0..7, filtros de jogador/empresa/territorio, "uma vez so", mensagem, dois conjuntos de 350 efeitos), laco jogador > empresa > territorio, linguagem de condicao (tokenizador, tabela de 118 tokens em 0x53b330 com 101 funcoes, redutor por 8 passes, parametro IsHighestInClass/IsLowestInClass estrito), tabela de 350 efeitos em 0x550550, regras de desfazer de efeitos temporarios, fim de jogo ([0x573d70], medalhas 1/2/3 e derrota) e medalhas da campanha, ordem do RNG (Random1To10000, rand() do CRT nas avaliacoes locais)
RE: o compilador reproduz os tokens gravados das 3790 regras dos 128 mapas e saves do jogo (nenhum id desconhecido; 6 regras mal formadas de mapas de usuario falham igual no original); divergencias do manual: divisao por zero devolve o dividendo, != e inalcancavel pelo texto, CompanyTerritoryLoadsHauledFromThisYear/Lifetime valem 0, PlayerId devolve o id da empresa
Improved: teste diferencial tests/scenarios.rs no rt2-oracle (9 testes: tabelas de tokens e efeitos, redutor com 10000 expressoes e 3649 condicoes reais, agregacao de classe sobre pools, escala de dinheiro) e tests/scenarios.rs no rt2-formats (128 arquivos); o codigo de apoio fica em crates/rt2-formats/tests/scenarios/lang.rs
Feature: rt2-sim scenario rule engine (scenario module): condition compiler and 8-pass reducer promoted from the test support, 350-row effect table loaded from the executable, rule evaluation with player/company/territory loops, messages, effects, undo rules for temporary effects, victory/loss state, and fire_trigger for the world hooks.
Change: scenario tests now exercise the rt2-sim module (rt2-formats/tests/scenarios* moved to rt2-sim/tests/scenarios.rs; the oracle tests use rt2_sim::scenario).
Feature: rrt2 game binary (crates/rt2-game): main menu with the original backdrop, scenario and save lists, map view with a top-bar HUD (date, cash, speed, pause), fixed-timestep simulation through Command, saves in ~/.local/share/rrt2/saves, rrt2 set-path, configurable keys in config.toml, --screenshot offscreen path
Feature: rt2-ui retained UI layer on wgpu with glyphon text, 100-300% UI scale from the monitor DPI, 9-slice skin from the original UI sprites (flat fallback), vendored OFL fonts (Cinzel, Libre Franklin, Anton, Dancing Script) mapped to the game's 10 bitmap fonts
Docs: docs/ui.md (UI architecture, font mapping, scaling, screens vs .win layouts)
Feature: crate rt2-audio (kira): efeitos a partir dos PCM dos PK2, musica de data2 com as regras do original (categorias, fade, sem repetir as 3 ultimas), volume/skip/ordem sequencial como opcoes, som posicional opcional; rt2-play (--list, efeito, music, --video)
Feature: videos Smacker de anim convertidos por ffmpeg para ~/.cache/rrt2/video na primeira vez
Docs: formato dos sons (docs/formats/sound.md): descritores de 0x12 bytes, 123 efeitos PCM cru (11025 Hz mono 16 bit; clock82m 22050 Hz 8 bit), tabela de eventos, regras de musica e tabela de videos
RE: 28 funcoes, tabelas e globais de audio nomeadas (sound_play, music_request_category, music_pick_random, sound_table, video_table...); a taxa de amostragem e o formato dos blobs de audio dos PK2 vem da tabela de descritores em 0x55e7b0
RE: tabela id de terreno -> classe/registro de ground.imb decodificada (0x471b10) e as passadas de overlay do carregador (0x42a7d0 transicoes e praias, 0x4294d0 rios, 0x428fe0 estradas) portadas e validadas bit a bit contra o original no emulador
Fix: o viewer usa os ids de terreno reais (fim das manchas azuladas na grama), com transicoes de solo, praias animadas, rios, estradas, estilo de estacao do registro e sombras de arvores
Docs: map-gam.md 3.2 (id de terreno, classes, overlays), sprite-catalog.md 4.1 (tabela id -> registro), terrain-track.md (tabela de classes resolvida)
Feature: rrt2 plays menu/game music with the original fades and UI click sounds; [audio] master/music/sfx/mute in config.toml, ctrl+M mutes, ctrl+N skips the track; the game runs silently without a sound device
Improved: scripts/fidelity.py automates the level-2 fidelity scoreboard (cached original runs, rt2-savediff comparison, docs/fidelity-status.md rewrite, regression exit code)
RE: station improvement table decoded (0x5500c8: 30 rows, cost/year/exclusion per bit of station+0x49), availability filter 0x468310 (month >= 9 of the first year), cumulative ftol purchase price with effect 8 and the ledger entries of 0x46aef0; every effect located (turnaround x0.5/x0.75, customs 8 to 4 days, sand/water/oil refill, storage halves pickup wait, passenger bonus 10/15/5/25/15 to the station owner)
RE: refunds specified from the executable: bulldozing and station removal never refund cash (book value written off to the Track category), trains are written off without cash, an industry sells for half (V - V/2); bulldozer cost 1000 per track tile and tree, 10% (own) or 75% (neutral) of a building's price
RE: no track usage fee exists: revenue is split by tiles stepped per leg (up to 4 foreign owners, extra owners count as own, inactive owners lose their share); station fee $2000 per car is lost when the station has no owner
RE: no block signals; each tile is a block reserved by one train per lane (two lanes on double track); the train class (Halted/Slow/Normal/Express) sets priority 0..3, +4 on own track, 0 below 65% throttle, 20 when broken; a train wins a conflict only with strictly higher priority (>= 2), and equal priorities deadlock
RE: effect id 0xd is the industry purchase price; custo2 of track_tile_cost is only a "something was built" flag; max-bridge option +0x1bf is a scenario setting (0 = by year)
Docs: terrain-track.md sections 2.4, 3.4, 5 and 6 rewritten from the executable; cargo.md corrected (the final LNG agrees with the code on passenger bonuses)
Feature: rt2-oracle tests/stations.rs checks the improvement table, availability, purchase, station removal, industry trade and the tile-priority conflict against the original (6 tests)
RE: finance.md 13..17 documenta a revisao anual da empresa 0x43c760 (desempenho, salario, bonus, posicao nos territorios, multiplicador de receita, aviso/demissao do chairman, liquidacao), verificada bit a bit com 8000 casos.
RE: 0x438450 (person_generate) escolhe um gerente da tabela fixa de 40, nao cria pessoas; spec do sorteio, da tabela de gerentes e do ciclo de vida das pessoas (sem envelhecimento nem morte).
RE: votacoes de fusao 0x48b5d0 e de presidencia 0x42ee00 com constantes e formulas exatas, testadas contra o executavel.
RE: capital inicial de empresas (sliders Player/Outside Investment, company_init 0x438a10) especificado e testado; ano 9001 = acumulador de vida inteira; contas 4/5 corrigidas (4 trens, 5 industrias).
Feature: rt2-sim ports train_step (movement, track reservations, pathfinder in train mode, station dwell) and anim_object_step (smoke puffs); the Example save advanced 1 day is identical to the original field by field
RE: train_step 0x4d0ce0 and its 50 callees specified (docs/spec/trains.md section 10): car/route/stop/reservation records, bucket-queue pathfinder, smoke puffs drawn with the CRT rand (saved state)
Fix: rt2-savediff masks route-step flag bits filled with uninitialized heap memory by the original pathfinder
Feature: train arrivals in rt2-sim: unloading, delivery revenue with its side effects (lots, station and town counters, station fees, track-sharing income, company ledgers and delivery statistics), loading at the station, AI consist choice, breakdowns, monthly train costs, yearly statistics and track wear rotation
RE: function snapshots of the original (re/scripts/wine/snap_call.py): the game is saved right before and after one call; crates/rt2-sim/tests/trainstep_snapshots.rs checks the port of train_step, train_arrive, consist and loading, leaving a station, monthly costs and the year step against them
Feature: station supply and demand (0x4bebf0) every week, every month and after each lot produced: the Example save advanced 7 days is identical to the original
Feature: information screens in rrt2: company finance report (income statement this year / last year / lifetime, balance sheet, share price, book value, rating, bonds), stock market overview, train list and detail, station list and detail (supply and demand per cargo, decoded improvements), city and industry lists and details, territory page; opened with F, M, T, G, C, I or the toolbar under the HUD, Esc closes, Left/Right changes company, a click on the map opens the page of the industry, station, city or territory under the cursor
Feature: rrt2 --screenshot --screen info --info finance|stock|trains|train|stations|station|cities|city|industries|industry|territory, and --click X,Y to try the map click, for screenshots at any size and UI scale
Docs: docs/ui.md describes the information screens, their shortcuts and which fields are still TODO (train profit, city population, economy state, old 0x233C record layout)
Improved: o laco do mundo agora liga os ganchos mensais e anuais ao estado cru do save (passo mensal das empresas e dividendos aos acionistas, revisao anual da diretoria, fim de ano da empresa, arquivo de patrimonio das pessoas, lucratividade e reinicio anual das construcoes, expiracao de lotes, chamadas de margem, gatilhos de cenario com efeitos e crescimento anual das cidades); Alaska, Austria, Atlantis e Brazil batem com o original em 30 dias
Improved: Example em 30 dias (10/dez/1875 a 12/jan/1876) cai de 4684 para cerca de 1500 campos diferentes; restam o historico anual (history_snapshot), o turno da IA e a marcacao de terreno de prédios criados/demolidos
RE: finance.md 5 confirmado contra o original: o passo mensal multiplica por 1/12 (0x535540) em vez de dividir por 12 (diferenca de 1 ulp no salario); a rotina de fim de ano desloca as linhas de metricas antes de gravar a linha 1, e a metrica 5 (retorno ponderado) ja enxerga o preco novo na linha 1
RE: building_can_place (0x4087a0) rejeita tile com tile+0 & 8 (alem de rio e predio): com isso o crescimento anual das cidades do Example reproduz os mesmos 2 prédios criados, as 2 demolicoes e todos os campos de places
RE: building_destroy limpa +2 (lugar), +0x2f/+0x33 (elos de estacao) e libera os elos de pool_58; 0x4c8540 mantem bytes de resumo em empresa+0x422d/+0x422e (inferido)
Feature: Brazilian Portuguese translation of all 2807 game strings.
Feature: Simplified Chinese translation of all 2807 game strings and a Chinese README.
Feature: Spanish translation of all 2807 game strings and a Spanish README.
Feature: Russian translation of all 2807 game strings and a Russian README.
Feature: German translation of all 2807 game strings and a German README.
Feature: computer opponents' monthly turn in the simulation (crates/rt2-sim/src/ai): engine pick, expansion timer, network extension scoring, build-mode A* track pathfinder with cost, station site search, train management and stop/consist choice, industry purchase, AI finances; wired into sim_month_end
RE: AI turn verified against the original with function snapshots (Example: December, January and forced expansion with 635 draws and a priced A* path all byte-identical); during the AI turn the planner prices double track with wooden bridges (build_preview_suspend globals)
Feature: The game is multilingual: translation files overlay the game strings by id, the main menu has a language selector (native language names) that switches at runtime, and language in config.toml (default: system locale) remembers the choice.
Improved: Vendored Cyrillic (Cormorant SC, Oswald, Marck Script) and Chinese (Noto Sans SC subset) fonts so Russian and Chinese text renders in every UI style.
Change: The clone's own UI texts (Menu, Save, screen titles, hints) are translatable through an [app] table with ids from 100000.
Feature: clone-only interface strings translated to Spanish, German, Chinese and Russian.
Improved: o registro anual do jogador (history_snapshot, 0x4e9770: classificacoes de empresas e pessoas, 10 anos de historico, metricas da empresa local) e a marcacao do terreno dos predios criados e demolidos (cadeias de estruturas, nivelamento da elevacao, flags dos tiles, elos de estacao) agora seguem o original; Example em 30 dias cai de 1495 para 7 campos diferentes (so a empresa de IA 5 e seu chairman)
RE: history_snapshot (0x4e9770) especificado em world-tick.md 3.4.1: grava do zero 0x3283 bytes em 0x570a82 (ano, empresa local, receita e resultado, degrau, salario, velocidade media, rankings por receita, resultado e patrimonio com os ultimos 10 anos); sem RNG, roda antes dos arquivos serem deslocados
RE: building_construct/building_destroy especificados em world-growth.md 4.5: estrutura tipo 3 em cada celula da pegada (ordem de alocacao decide os ids dos marcadores dos trens), cantos de elevacao puxados para (h + media + 1) >> 1, 0x424c10 recalcula os bits 4/2/3 de tile+6 numa janela 9x9, tile+6 & 1 e o tile plano, elos pool_58 por station_catchment_test; a demolicao nao devolve a elevacao
RE: building_can_place (0x4087a0) provado contra o original no emulador (78 400 casos): alem de rio e tile+0 & 8, rejeita estrada com celula & 1, ponte/vao/trilho (0x415f80) e, com o argumento tentativas > 300, celula & 0x200 fora de estrada
RE: 0x4beae0 zera tambem +0x59 e +0x5d (receitas do ano da estacao como origem e destino), alem dos tres contadores u16
Feature: the in-game map is live: engines, tenders and wagons are drawn from the car pool at their interpolated positions (record by direction and view rotation, depth-sorted with buildings and trees), with steam puffs from the animation pool
Improved: static map layers (buildings, track, stations) rebuild when the save's building/track/tile fingerprint changes
Feature: rrt2 --screenshot accepts --focus X,Y, --zoom, --rotation and --bench N for map shots and frame timing
Fix: the language selector in the main menu no longer clips its labels at any UI scale or language (it stacks into two lines when the canvas is narrow)
Fix: Chinese dates read "1876年1月12日" (the date string can use the abbreviated month with %4)
Docs: the stacked cars near the Example station curve are not a drawing bug: a diagonal map direction is vertical on screen and the double-track lanes are 0.54 tile apart (docs/ui.md)
Docs: inventory of the original game's screens with references and implementation status (docs/reference/screens.md).
Docs: new docs/spec/commands.md lists every command of cmd_execute (0x4b0210): the packet layout, executor, validation, ledger effect and issuing window of the 39 executed ids (1, 0xa..0x2f) and the 8 lobby ids, with the answer to what the player can build and buy (stations only in play; buildings only in the editors; 41 buyable industry types; trains, territory rights and station improvements)
RE: the executable never validates permissions, cash or year inside cmd_execute; every scenario restriction (0x5706a9..) is checked by the issuing window, the merger button reads "Retiring a train" (0x5706b4) instead of "Merging companies" (0x5706bd), and the building purchase and station placement both test territory-rights bit 1 (track), not the building or station bits
RE: territory rights price (0x440fb0) = 1000 * per-right base * f*f (f = (15000 - goodwill) / 10000, tripled above 1), rounded down to thousands; the bridge limit (0x469ef0), electric track gate (0x469f30) and engine availability (0x4683a0) verified against the original
RE: 45 window packets have their (id, size) checked in crates/rt2-oracle/tests/commands.rs, which also exercises building_buy_request, territory_rights_request and cmd_execute for ids 0x12, 0x1b, 0x28, 0x29, 0x2b, 0x2c and 0x2f
Feature: construction primitives in rt2-sim (crates/rt2-sim/src/build/): track laying with earthwork, piece merging and double track (track_lay_route), station and building creation with catchment links and supply/demand, station improvements, station networks, train purchase/sale, stop insertion/deletion, shared by the AI and the player
Feature: player construction commands (Command::Build) mirroring the cmd_execute packets 0x16..0x20 and 0x2d, with the original's validation (placement, no path, cash, ids)
RE: track_lay_route 0x4cc060, the tile rebuild 0x4cb090 (track overlays, bridge sprites, straight axis), the earthwork log and levelling helpers, tile shading 0x416bf0/0x416d40, station_init 0x4be840 and station names, train creation/stops/deletion: 15 function snapshots of the original identical (Example and Austria)
Fix: AI construction now real: dl0_rich_c5 AI snapshot (first real expansion) identical to the original
Fix: footprint extents of the building shapes (+12..+15) are computed at start-up by 0x471b10 (zero in the executable); tilemark now derives them
Feature: bulldozer (bulldoze_area 0x428930: validation with restore, track removal, tree clearing, costs and reputation), territory rights purchase (0x2a) and industry sale (0x2d), verified against the original
RE: tile light level 0x416bf0 checked against the emulated executable (20000 cases, tests/build.rs)
Feature: main window with the eight action icons, clickable terrain radar, center list box with four tabs, activity box and rotate/zoom buttons
Feature: single-player menu flow (Single Player submenu, New Scenario with map list, description, thumbnail, difficulty and options, New Campaign with the 18 scenarios and bonuses)
Feature: briefing and goals popup from the scenario rules, Start New Company dialog with the finance.md 17 sliders, File Options, year-end report, newspaper and win/lose dialogs using the original art
Improved: UI toolkit gains toggle buttons, icon buttons, cell grids with pointer events and scrolling text
Docs: screens.md status updated for A1-A5, B1-B4, C1-C2, G1, I1-I4, J1
Feature: rt2-sim output queue World::take_messages (scenario dialogs/newspapers/choices, year-end historical notices, economy change, first building of a type, town bonus offers, AI company started/connected/bankrupt, stock split) and World::game_over (bronze/silver/gold/lose)
Feature: rt2-sim command 0x26 (start company) with the window checks of 0x4bd950, company_init and the founder's share purchase (World::apply_found)
RE: the founding dialog "You buy" rounds the founder's shares to the nearest 1000 (half up), so the cost can exceed the investment (150,000 buys 3,000 shares for 157,500 at 52.50); rt2_sim::found::founding_preview is the single source for the UI
Feature: construction tools in the main window: Lay Track (single/double, electric, bridge by year, drag from track or station with a live path and cost preview), Build Station (size, direction, style, catchment overlay), Bulldozer
Feature: station window with the station picture and its purchased improvements, Buy dialog (0x18), Purchase Train (0x19) with route copy, editable train window with map router, stop insert/delete (0x1d, 0x1e), engine replacement (0x20) and sale (0x1f)
Feature: industry window with Buy and Sell (0x2d) and territory rights window (0x2a)
Improved: construction previews run the real command on a clone of the world, so the shown path, cost and refusal always match the result
Docs: docs/reference/screens.md and docs/ui.md updated for the construction and train screens
RE: the original Example save is in the old 0x233C record layout, which rt2-sim cannot play; a new bought train is not yet put on the track by the train step (vehicle_place head branch), so it does not earn
Feature: a bought train is put on the track at its first stop's station and runs (vehicle_place head branch and consist change of train_consist_at_stop, matching the original over 300 passes), once the purchase window's mark (command 0x2c) is sent
Feature: train commands 0x1a (go to stop), 0x1b (stop wait mode), 0x1c (cargo per stop), 0x21 (class), 0x2c (mark) and 0x2f (sell mode) in the simulation, each checked against a snapshot of the original
RE: a new train's route ring is allocated by the pathfinder on first use (0x462830/0x4627f0 named); the uninitialized malloc and pool_grow memory of the original reads 0xBAADF00D and is now reproduced; an electric engine between stations without catenary finds no route
Fix: trains bought from the Purchase Train window are marked ready (command 0x2c) so they leave the station.
Feature: saves and maps of the shipped 0x233C layout are converted on load like the original (World::from_save_seeded); all 33 shipped .MAP/.GAM match the original's 0-day save field by field
Feature: World::new_game starts a scenario from a map (load, setup options, players, game_set_date, initial town growth, scenario triggers 6/0/2); initial growth still diverges in building field textures
RE: loader record conversion of 0x477a60 (header, state, 7 pool record types, cars, routes, rules, terrain with track overlays, six hard-coded scenario patches) and saver refresh documented in map-gam.md 9
RE: New Game sequence 0x410de0 -> 0x479b20 -> 0x473590/0x474280/game_set_date documented in world-tick.md 10; advance_save.py --preseed/--new-game drive it headlessly
Feature: Load Game opens any shipped .GAM (the old 0x233C layout is converted on load) and New Scenario / New Campaign start through World::new_game with the setup screens' financial and industrial models, game seed, start year and the campaign block; the "0x233C not playable" notice and the clock-only scenario fallback are gone.
Feature: Start New Company sends command 0x26 with the typed company name (default from TEMP_COMPANY_NAMES), shows the numbers of founding_preview (founder shares rounded to the nearest 1000) and the refusals of the original (already chairman, too many companies, two-year wait, not enough money).
Feature: simulation messages open scenario dialogs, newspapers (economy, first building of a type, town bonus offers) and notices, and every message is a line of the Activity Box; the win / lose plaque opens from World::game_over() with the rule's text.
Fix: a new game starts in the scenario's own year (the map file's option block held a stale year, B&O 1880 instead of 1830).
Docs: docs/ui.md and docs/reference/screens.md updated for the play flow; gaps listed (sandbox, revenue modifiers, extra computer players, campaign bonus, choice answers).
Fix: a new campaign game is now identical to the original: building construction writes the field tiles (pool_88, crop rows, forced forest/field ground and the blend pass around it), the existing buildings restart their clocks when the start date is set, and the first map redraw recomputes the shade bit; B&O, Hannibal, Silver and Birmingham New Game give 0 differing fields after 0 and 7 days (scoreboard 33 of 34).
RE: the per-tile overlay lists are runtime state (the tile+6 & 0x80 bit of a map file can be stale), building_can_place sees the track pieces a neighbour draws into the tile, and slots grown by the building pool keep Wine's heap fill in the bytes 0x409a30 never writes (world-growth.md 4.5.1).
Fix: a stock split at year end takes a second committed quote at the new share count (0x43d800), so the price cache and the chairman's net worth archive match; Example save 30 days identical to the original
Feature: scenario starts name every player from the persona table of default2.lng, remove unused player slots (player_remove 0x4a6a00), reset each company's territory blocks (0x43ddb0) and apply the start rules' manager hires (0x438780) and train retirements (0x4cdd50)
Feature: sandbox production (lot stock at +0x9e), CompanyGoodwill / CompanyTerritoryGoodwill (0x43eca0), territory rights effects through territory_set_rights, and the loader's every-load fixes on 0x2348 maps
Improved: fidelity scoreboard covers New Game of all 18 original campaign scenarios and the 18 expansion ones: 86 of 98 cases identical (the 18 original campaigns and 12 expansion scenarios at 0 and 7 days)
RE: CompanyTerritoryGoodwill averages with the territory's standing (not the same value as CompanyGoodwill); a non-existent company quotes 0.0 without touching its price cache (0x43b410)
Feature: financial commands in rt2-sim (stock trades with margin and short selling, bonds, stock issue and buy-back, dividend, bankruptcy, manager hire, mergers, chairman elections and takeover) with the checks of the original's windows, verified against 25 snapshots of the original (tests/fincmd_snapshots.rs)
Feature: the broker's margin calls (warning, deadline, forced sales and covers, short squeeze) run after each trade and every month
Feature: finance screens in the game: company book actions (issue bonds, repay, issue stock, buy back, dividend, merger, bankruptcy, managers, chairmanship), personal stock trading with margin, vote dialogs, margin and merger messages
Fix: the board's dividend suspension and cut are written back to the company (0x4399d0); the Example save now stays identical to the original after 30 days
RE: finance windows and rules read from the executable: trade lot 0x4a6e00 (4% of the position + 1000), buy-back lot (cash / (price * 1.2)), dividend buttons 0x449300, bankruptcy rule (two losing years), chairman buttons by stake (50% assume, 10% election), news counter and local company copy
Fix: AI players in a new scenario get their persona names and bios from the game text instead of "Unassigned".
Fix: the minimap (radar) colours every cell by the terrain class of the loaded map (water = class 18) with one colour per land class and light elevation shading; maps with new terrain ids such as Africa After the Flood no longer show as a beige blotch
Fix: one-line texts that do not fit their box (column headers such as IMPROVEMENTS and CARGO WAITING, button captions, table cells) shrink to fit and end in an ellipsis at the smallest size, at every UI scale and in all six languages
Feature: the station detail picture is the original's 1024x569 scene (backdrop of the site class plus one overlay per building and improvement, in the original's drawing order, with the derived track, catenary, road and turntable layers) instead of labelled chips
Feature: stock market list has Buy and Sell buttons on every row that open the trade dialog of that company
Feature: scenario Choice messages show both buttons and queue the answer (AppState::take_choice_answers); the simulation still applies the effects of button 0 until it gets an AnswerChoice command
Docs: formats/sprite-catalog.md 6.1 catalogues the 43 station-view overlay banks (SD<style>.imb) and 13 backdrops (sdmbkg.imb): file-name format, draw order, style letters and derived bits of the improvement word
RE: the station detail window composes SD%s%s.imb overlays from the improvement table (0x4c0c00), the backdrop sdmbkg%s.imb from station +0x4d (0x4c0ed0) and derives bits 12..14 and 23..27 of station +0x49 on each refresh (0x4c1da0, 0x4c0a50)
Fix: every game load moves the first year of engine 3 to 1955 like the original loader (0x477a60), so its availability byte matches; expansion campaigns #E07 New Game identical
Feature: scenario newspaper messages post to the news list (news_post 0x4a42f0: CRT draw, news flag and counter); #E13 New Game identical
Feature: territory confiscation effects 55..59 and destruction 299..303 (0x437d40, 0x437db0, 0x437f50, 0x4380a0) and the TerritoryCompletelyFlooded condition function; #E09 and #E15 New Game identical
Feature: undo rules of temporary scenario effects join the saved rule pool (last made first, kept on an evaluation error); #E08 New Game identical
Fix: the expansion industry set (0x5704ac = 1) takes its own industry type table, without the set-0 load fix-ups; #E08 and #E11 New Game identical
RE: a pool step whose block reaches Wine's large-block size (about 0x7f000 bytes) is zero-filled instead of 0xBAADF00D; the buildings grown in that step keep zeros at +0x38
Feature: scenario two-button choices can wait for the player's answer (World::set_interactive_choices, World::pending_choice, Command::AnswerChoice); the step is replayed with the answer so the order matches the original's modal window, and a local game with AI players no longer skips the choice as if it were a network game
Feature: Options screen (menu, File Options, F10) with Display (window/borderless fullscreen, window size, monitor, vsync, UI scale 100-300%), Audio (master, music, effects, mute), Language, Keys and Gameplay tabs; every change applies at once and is written to ~/.config/rrt2/config.toml.
Feature: remappable keys with conflict detection (a key another action uses is reported and only moved on a second press), alternate keys, per-key and global reset; new bindable actions for quick save, quick load, the Save/Load dialogs and Options.
Feature: Save Game and Load Game dialogs for the clone's own saves (~/.local/share/rrt2/saves) with date, scenario, company, cash, game date and a terrain thumbnail; the Load dialog also lists and opens the original's .GAM games.
Feature: quick save (F5) and quick load (F9), and autosave every N game months with rotation that keeps the last K autosaves.
Feature: gameplay preferences: game speed at start, edge scrolling, camera speed, reversed mouse drag and wheel zoom, wheel zoom speed.
Improved: scenario Choice messages now wait for the player: the dialog shows the rule's two buttons and the answer goes to the simulation as Command::AnswerChoice (headless runs keep answering button 0).
Improved: window size, mode, monitor and vsync are remembered; the mute key and Ctrl +/- UI scale are saved too.
Docs: docs/ui.md "Opções e saves" and the J1/J3/J5/A6/A7 rows of docs/reference/screens.md.
Feature: release packaging: .github/workflows/release.yml builds rrt2 for Linux, Windows and macOS (Apple Silicon and Intel) on every push to main (workflow artifacts) and on v* tags (GitHub Release with the CHANGELOG section as notes); scripts/package-release.sh stages the archive.
Feature: rrt2 --version prints the crate version and git commit, and the main menu footer shows it.
Docs: scripts/cut-release.sh <version> turns "Unreleased" into a dated ## v<version> section and bumps the workspace version; "Installing" section in the six READMEs.
Feature: fidelity scoreboard extended to long horizons (Example 90/180/365/730 days, Lenin and NewJapan maps 365/730, campaign and Second Century New Games 365/730)
Fix: a car appended to a standing train is placed on the track at once (vehicle_init -> vehicle_place), and a reused car slot keeps the bytes of the car freed there
Fix: year end clears the per-territory u16 +0x572 of every company and recounts type-0 buildings (rating 100)
Fix: economy state changes and stock splits of the player's company post their news (CRT draw, news flag and counter)
Fix: the light pass runs when a game is loaded and when it is saved, as the original's map paint does
Fix: trigger-7 scenario rules write their status text into the yearly history record; (TRIGGER_TF) reads True/False and (TRIGGER_MONEY) has thousands separators
Fix: the scenario functions see the live date (GameYear stayed at the load year), and local-player rules use the human player
Fix: AI companies review their manager in odd years (ai_review_manager / ai_manager_value ported)
Fix: a broken-down train decelerates with the restricted rate (the original reads stack garbage there)
Fix: the cash register sound of the player's deliveries draws the CRT rand
RE: the original's message-box window depends on the host clock; advance_save.py now keeps it open and choice skipping is opt-in (--skip-choices); rt2-savediff masks the interface view and train sound handle bits
Change: the project is licensed under GPL-3.0-or-later (LICENSE).