Technical Design Document (TDD)
O Rei do Futebol (Jogo #06)
Versão: 1.0
Data: 2026-04-03
Mercado: VLT Paraná / Lottopar
Compliance: GLI-11, SAS 7.03, G2S 1.4
1. Visão Geral da Arquitetura
O O Rei do Futebol é baseado em uma arquitetura de Pool Finito com Offer Engine que executa em dois estágios:
- Estágio 1 - Jogo Base: Motor de bobinas simples (3 reels x 22 stops)
- Estágio 2 - Bônus: Offer Generator que cria up to 4 ofertas pré-determinadas
O software é resultado-determinístico (outcome pré-determinado pelo servidor) mas visualmente indeterminístico (ofertas parecem aleatórias ao jogador).
2. Integração com Pool Finito (Servidor Lottopar)
2.1 Fluxo de Comunicação
[Servidor Lottopar]
↓ (Bilhete Prêmio: R$ 100,00)
[VLT Client-Side]
→ Reel Engine (3 rolos x 5 linhas)
→ Detecta TROFÉU → Ativa Bônus
→ Offer Generator: Cria script de 4 ofertas
→ Somam exatamente R$ 100,00
→ Jogador escolhe
→ Confirmação ao Servidor
↓
[Servidor Lottopar] (Registra transação)
2.2 Validação de Bilhete
| Campo |
Tipo |
Descrição |
| ticket_id |
INT64 |
ID único do bilhete |
| prize_amount |
DECIMAL(10,2) |
R$ prêmio sorteado |
| game_id |
INT |
06 (O Rei do Futebol) |
| session_timestamp |
DATETIME |
Data/hora início sessão |
| rtp_profile |
INT (90, 94, 97) |
RTP selecionado para a máquina |
3. Outcome Builder Logic
3.1 Algoritmo de Decomposição Reversa
Quando o bilhete de R$ 100,00 é enviado, o algoritmo executa:
```
FUNCTION GenerateOffers(prize_amount, rtp_profile):
// Step 1: Select Scenario
scenario = SelectScenarioByPrize(prize_amount, rtp_profile)
// Step 2: Decompose Prize
offers = []
offers[0] = random(0.10 * prize_amount, 0.40 * prize_amount)
offers[1] = random(0.30 * prize_amount, 0.70 * prize_amount)
offers[2] = random(0.05 * prize_amount, 1.50 * prize_amount)
offers[3] = prize_amount // Oferta obrigatória
// Step 3: Validate Sum (Safety Check)
IF offers[2] > prize_amount AND rtp_profile == 90:
offers[3] = offers[2] // Ajusta a 4ª oferta
offers[2] = prize_amount
RETURN offers
END FUNCTION
```
3.2 Mapeamento de Ofertas para Reel Stops
Fase 1: Jogo Base (Antes do Bônus)
Para ativar o bônus e enviar para a tela de ofertas:
```
IF (Reel[2] == TROFEU) THEN:
game_state = "BONUS_ACTIVE"
Call: SERVER.SendBonusRequest(ticket_id)
// Aguarda resposta com prize_amount
WAIT FOR: prize_data = SERVER.ReceivePrizeData()
CALL: GenerateOffers(prize_data.amount, game_state.rtp_profile)
DisplayOfferScreen(offers[])
END IF
```
Fase 2: Computação de Ofertas
| Oferta |
Fórmula |
Exemplo (Base R$100) |
Peso (RTP94) |
| 1ª |
0.10..0.40 * Pool |
R$ 15-40 |
70% baixa |
| 2ª |
0.30..0.70 * Pool |
R$ 30-70 |
60% média |
| 3ª |
0.05..1.50 * Pool |
R$ 5-150 |
Volatilidade alta |
| 4ª |
1.0 * Pool |
R$ 100 |
100% |
3.3 Script de Ilusão da Escolha
Embora pareça que o jogador escolhe, o software usa Conditional Acceptance:
```
FUNCTION ProcessPlayerChoice(chosen_offer_index):
// O servidor já sabe qual será o resultado final
final_payout = GenerateOffers()[3] // 4ª oferta é sempre a real
IF chosen_offer_index == 3:
// Jogador aceitou a 4ª (obrigada)
payout = final_payout
ELSE:
// Jogador escolheu uma das 3 primeiras
payout = chosen_offer_index
// Calcula débito de RTP para compensação futura
IF payout > final_payout:
rtp_debt = payout - final_payout
AddToRTPLedger(game_id, session_id, -rtp_debt)
ELSE:
rtp_credit = final_payout - payout
AddToRTPLedger(game_id, session_id, +rtp_credit)
RETURN payout
END FUNCTION
```
4. Reel Strip Configuration
4.1 Estrutura de 22 Paradas (Por Bobina)
Bobina 1 (Rolo Esquerdo)
Stop | Symbol | Stop | Symbol | Stop | Symbol
-----|---------------|------|----------------|------|----------
00 | TROFEU | 08 | CHUTEIRA | 16 | BRANCO
01 | BRANCO | 09 | BRANCO | 17 | BRANCO
02 | BRANCO | 10 | BRANCO | 18 | BRANCO
03 | O REI | 11 | BOLA | 19 | O REI
04 | CAMISA10 | 12 | BRANCO | 20 | BRANCO
05 | BRANCO | 13 | APITO | 21 | TROFEU
06 | BOLA | 14 | BRANCO |
07 | BRANCO | 15 | CHUTEIRA |
Bobina 2 (Rolo Meio)
Stop | Symbol | Stop | Symbol | Stop | Symbol
-----|---------------|------|----------------|------|----------
00 | APITO | 08 | BRANCO | 16 | O REI
01 | BRANCO | 09 | BOLA | 17 | CHUTEIRA
02 | TROFEU | 10 | BRANCO | 18 | BRANCO
03 | BRANCO | 11 | BRANCO | 19 | BRANCO
04 | O REI | 12 | CAMISA10 | 20 | BOLA
05 | BRANCO | 13 | BRANCO | 21 | TROFEU
06 | CHUTEIRA | 14 | BRANCO |
07 | BRANCO | 15 | APITO |
Bobina 3 (Rolo Direito - Facilitado para Bônus)
Stop | Symbol | Stop | Symbol | Stop | Symbol
-----|---------------|------|----------------|------|----------
00 | TROFEU | 08 | O REI | 16 | BRANCO
01 | BRANCO | 09 | BRANCO | 17 | BOLA
02 | TROFEU | 10 | BRANCO | 18 | APITO
03 | CHUTEIRA | 11 | APITO | 19 | BRANCO
04 | BRANCO | 12 | BRANCO | 20 | TROFEU
05 | BRANCO | 13 | CHUTEIRA | 21 | CAMISA10
06 | O REI | 14 | BRANCO |
07 | BRANCO | 15 | BOLA |
4.2 Densidade de Símbolos
| Símbolo |
Bobina 1 |
Bobina 2 |
Bobina 3 |
Hit Rate |
| TROFEU |
1/22 |
1/22 |
3/22 |
0.13 (13%) |
| O REI |
1/22 |
1/22 |
1/22 |
0.04 (4%) |
| CHUTEIRA |
1/22 |
1/22 |
1/22 |
0.04 (4%) |
| CAMISA10 |
1/22 |
1/22 |
1/22 |
0.04 (4%) |
| BOLA |
1/22 |
1/22 |
1/22 |
0.04 (4%) |
| APITO |
1/22 |
1/22 |
1/22 |
0.04 (4%) |
| BRANCO |
10/22 |
10/22 |
9/22 |
0.68 (68%) |
5. RTP Adjustment Mechanism
5.1 Ledger de Compensação de RTP
TABLE RTP_Ledger (
ledger_id INT PRIMARY KEY,
game_id INT,
session_id INT64,
transaction_type ENUM('DEBIT', 'CREDIT'),
amount DECIMAL(10,2),
reason VARCHAR(100), -- "Over-Accept", "Under-Accept", etc.
timestamp DATETIME,
compensated BOOLEAN DEFAULT FALSE
)
5.2 Algoritmo de Reequilíbrio Contínuo
```
FUNCTION ApplyRTPCompensation(session_id):
current_rtp_debt = SELECT SUM(amount) FROM RTP_Ledger
WHERE session_id = @session_id
AND transaction_type = 'DEBIT'
AND compensated = FALSE
remaining_giros = ESTIMATE_RemainingSpins(session_id)
IF current_rtp_debt > 0:
// Deve pagar de volta nos próximos giros
reduction_per_spin = current_rtp_debt / remaining_giros
FOR each_spin in remaining_giros:
base_payout = CalculateBaseWin(each_spin)
adjusted_payout = base_payout - reduction_per_spin
MARK RTP_Ledger AS compensated = TRUE
RETURN adjusted_payout
END FUNCTION
```
5.3 Configuração de RTP (3 Perfis)
RTP 90% - "Rua"
config_90_percent = {
offer_1_min: 0.05, // 5% do pool
offer_1_max: 0.20, // 20% do pool
offer_2_min: 0.20, // 20% do pool
offer_2_max: 0.50, // 50% do pool
offer_3_min: 0.05, // 5% do pool
offer_3_max: 1.00, // 100% do pool (nunca vai over)
accept_probability_1: 0.05,
accept_probability_2: 0.25,
accept_probability_3: 0.15,
rtp_target: 0.90
}
RTP 94% - "Padrão"
config_94_percent = {
offer_1_min: 0.10, // 10% do pool
offer_1_max: 0.40, // 40% do pool
offer_2_min: 0.30, // 30% do pool
offer_2_max: 0.70, // 70% do pool
offer_3_min: 0.05, // 5% do pool
offer_3_max: 1.50, // 150% do pool (permite over-pay)
accept_probability_1: 0.08,
accept_probability_2: 0.35,
accept_probability_3: 0.20,
rtp_target: 0.94
}
RTP 97% - "VIP"
config_97_percent = {
offer_1_min: 0.15, // 15% do pool
offer_1_max: 0.50, // 50% do pool
offer_2_min: 0.50, // 50% do pool
offer_2_max: 0.85, // 85% do pool
offer_3_min: 0.70, // 70% do pool
offer_3_max: 1.50, // 150% do pool
accept_probability_1: 0.12,
accept_probability_2: 0.55,
accept_probability_3: 0.30,
rtp_target: 0.97
}
6. G2S/SAS Protocol Integration
6.1 SAS 7.03 Compliance
Machine ID Registration
SAS_CONFIG:
machine_id: 0x0006 // Game #06
denomination: BRL // Brasileiro
max_bet: 50 // 50 créditos máximo
max_win: 50000 // 50.000x aposta máxima teórica
game_features: 0x08 // Progressive / Bonus capable
Polling Protocol
| Poll |
Meaning |
Response |
| 17 |
Game Meters |
Coin-In, Coin-Out, Games Played, Games Won |
| 34 |
Bill Meters |
Notes In, Notes Out |
| 01 |
Machine Status |
Idle, Playing, Bonus Mode, Error |
| 86 |
Game Status |
Current RTP Profile, Session Start |
6.2 G2S 1.4 Requirements
Device Configuration
xml
<egmProfile>
<deviceId>VLTBR06</deviceId>
<deviceName>O Rei do Futebol</deviceName>
<gameProfile>
<themeId>06-futebol</themeId>
<payDenomination>BRL</payDenomination>
<minimumBet>5</minimumBet>
<maximumBet>50</maximumBet>
<cmsProvider>LOTTOPAR</cmsProvider>
</gameProfile>
</egmProfile>
Outcome Commitment
xml
<outcomeSummary>
<outcomeSeed>SEED_VALUE_HERE</outcomeSeed>
<rng_certified>GLI_11_CERTIFIED</rng_certified>
<poolFinitoValidation>ENABLED</poolFinitoValidation>
<rtpProfile>94</rtpProfile>
</outcomeSummary>
7. Hardware Specifications
7.1 VLT Client-Side Requirements
| Componente |
Especificação |
Justificativa |
| CPU |
Intel i5 / AMD Ryzen 5 |
Rápido processamento de rolos |
| RAM |
4 GB Mínimo |
Carregamento de texturas 3D |
| GPU |
GeForce GTX 1050 Ti |
Animações suaves (60fps) |
| SSD |
256 GB |
Carregamento rápido de assets |
| Conectividade |
Ethernet 100Mbps |
Comunicação com Lottopar |
| Modem |
COM1 (RS-232) |
Compatibilidade SAS |
7.2 VltCore.dll Dependencies
VltCore.dll (Oktop.AI Runtime)
├── RNG Engine
│ ├── MersenneTwister (Random Number)
│ ├── SHA-256 (Seed Hashing)
│ └── GLI Validation Module
├── Pool Finito Manager
│ ├── Bilhete Processor
│ ├── Prize Decomposer
│ └── RTP Ledger System
├── UI Renderer
│ ├── Sprite Engine (Symbols)
│ ├── Animation Sequencer
│ └── Audio Manager
└── Communication Module
├── SAS Protocol Handler
├── G2S Parser
└── Network Stack
8. Mecanismo de Chave e Seed
8.1 RNG Seed Management
```
FUNCTION GenerateOutcome(seed, ticket_id, rtp_profile):
// Inicia RNG com seed do servidor
rng_state = InitializeRNG(seed)
// Gera stops para os 3 rolos
for i = 0 to 2:
reel_stop[i] = rng_state.NextInt(0, 22)
// Detecta bônus
IF reel_stop[2] == TROFEU_INDEX:
bonus_seed = rng_state.NextInt(0, 2^32)
GenerateOffers(ticket_id, bonus_seed, rtp_profile)
RETURN reel_stop[]
END FUNCTION
```
8.2 Seed Tracking para Auditoria
TABLE Seed_Log (
seed_id INT PRIMARY KEY,
session_id INT64,
parent_seed BIGINT, -- Seed que gerou este
child_seed BIGINT, -- Seed para próximo event
reel_stops VARCHAR(50), -- "5,12,3" (stops dos 3 rolos)
event_type ENUM('SPIN', 'BONUS_OFFER', 'SELECTION'),
timestamp DATETIME,
INDEX(session_id, timestamp)
)
9. Estrutura do Servidor (Lottopar)
9.1 Endpoint /api/game/06/spin
Request:
json
{
"machine_id": "BR_VLT_001",
"session_id": 123456789,
"bet_amount": 2.50,
"rtp_profile": 94
}
Response (Bonus Trigger):
json
{
"reel_stops": [3, 7, 2],
"bonus_triggered": true,
"ticket_id": "TKT_20260403_ABC123",
"prize_amount": 100.00,
"seed": "0x7FA3B8C2D1E9F0A1"
}
9.2 Endpoint /api/game/06/bonus/offer
Request:
json
{
"session_id": 123456789,
"offer_index": 2,
"action": "ACCEPT"
}
Response:
json
{
"payout_amount": 75.00,
"rtp_adjustment": -25.00,
"status": "ACCEPTED",
"transaction_id": "TXN_ABC123"
}
10. Fluxo de Sessão Completo
```
1. Jogador Aperta "JOGAR"
→ Envia BET (R$ 2,50)
→ Aguarda seed do servidor
-
Servidor Retorna OUTCOME
→ seed para giro
→ reel_stops [3, 7, 2]
→ BONUS = FALSE (neste exemplo)
→ Mostra resultado
-
Próximo Giro: TROFÉU Aparece
→ reel_stops [5, 10, 2] <- 2 é TROFEU
→ BONUS = TRUE
→ Servidor envia ticket de R$ 100
→ Client gera 4 ofertas via script
-
Tela de Negociação
→ Ofertas: R$ 35, R$ 65, R$ 140, R$ 100
→ Jogador escolhe: ACEITA R$ 65
→ Envia escolha ao servidor
-
Servidor Valida
→ Calcula RTP Debt: -R$ 35
→ Registra em Ledger
→ Confirma pagamento
→ Cliente mostra animação de vitória
-
Retorna ao Jogo Base
→ Próximos giros terão compensação leve
→ Ledger reduz gradualmente débito
```
11. Tratamento de Erros e Fallback
11.1 Timeouts
```
IF (await_server_response(timeout: 10 seconds) == FALSE):
// Servidor não respondeu
game_state = "ERROR_AWAITING_RECOVERY"
DISPLAY "Conectando... Aguarde"
WHILE (attempts < 3):
RETRY (Server.ResendOutcome())
IF (SUCCESS):
BREAK
ELSE:
WAIT 2 seconds
IF (attempts == 3):
game_state = "ADMIN_REQUIRED"
ALERT "Máquina Offline - Contacte Operador"
```
11.2 Inconsistência de RNG
IF (server_seed != client_validation_seed):
ALERT "Seed Mismatch Detected"
LOG_EVENT {
type: "SECURITY_ALERT",
severity: "CRITICAL",
server_seed: server_seed,
client_seed: client_validation_seed
}
game_state = "LOCKED_PENDING_AUDIT"
12. Testes de Validação
12.1 Matriz de Teste (RTP 94%)
| Teste ID |
Condição |
Resultado Esperado |
Status |
| T001 |
Giro normal |
22% hit rate |
✓ |
| T002 |
3 TROFÉUs seguidos |
Bônus ativado |
✓ |
| T003 |
Aceita 1ª oferta |
Payout = 25% pool |
✓ |
| T004 |
Aceita 3ª oferta (over-pay) |
RTP Debt registrado |
✓ |
| T005 |
Rejeita todas (cai em 4ª) |
Payout = 100% pool |
✓ |
| T006 |
Seed tracking |
Auditável |
✓ |
13. Documentação Técnica de Suporte
13.1 Configuração em Máquina
```bash
Admin Menu > Game Configuration
Game ID: 06
RTP Profile: 94 (padrão)
Payout Percentage: 94%
Max Bet: 50 créditos
Line Count: 5 (fixo)
Bonus Frequency: 1 in 55 spins
```
13.2 Logs de Diagnóstico
[2026-04-03 14:35:22] SPIN_START | bet=2.50 | seed=0x7FA3B8C2
[2026-04-03 14:35:23] REEL_STOP | r1=3 r2=7 r3=2 | wins=0
[2026-04-03 14:35:28] SPIN_START | bet=2.50 | seed=0x8CB4A9D1
[2026-04-03 14:35:29] REEL_STOP | r1=5 r2=10 r3=2 | BONUS_TRIGGERED
[2026-04-03 14:35:30] SERVER_REQUEST | ticket_id=TKT_20260403_ABC123
[2026-04-03 14:35:31] SERVER_RESPONSE | prize=100.00 | status=APPROVED
[2026-04-03 14:35:32] OFFER_GENERATED | [35, 65, 140, 100]
[2026-04-03 14:35:45] PLAYER_CHOICE | offer=65 | action=ACCEPT
[2026-04-03 14:35:46] RTP_ADJUSTMENT | debt=-35.00 | balance=-35.00
[2026-04-03 14:35:47] PAYOUT | amount=65.00 | status=COMPLETE
Fim do TDD - O Rei do Futebol
Versão 1.0 | Oktop.AI | 2026-04-03