# Uma Certa Engine de Visual Novel Programável (Go) Uma engine de visual novel implementada em Go usando `ebiten`, com scripts YAML para dialogos, ramificacoes, imports, variaveis tipadas, salvar/carregar, fundos e sprites de personagem. ## Recursos - Tela de carregamento na inicializacao + validação automatica - A tela de titulo fica bloqueada ate o validação terminar - Imports YAML recursivos para dividir a historia em varios arquivos - Profundidade maxima de import configuravel (`MaxImportNesting` em `internal/vn/script.go`) - Execucao de script por cenas com ramificacoes - Variaveis tipadas: `string`, `bool`, `int`, `float` - Comando `if` com blocos `then`/`else` - Salvamento/carregamento do estado do jogo em JSON - Modo debug (`F2`) para inspecionar variaveis e pular para cenas - Fundos por chave de cor ou caminho de imagem - Sprites de personagem por caminho de imagem ## Inicio rapido ```bash go mod tidy go run ./cmd/vnengine ``` Por padrao, a engine sempre carrega `default/script.yaml`. Todos os textos da interface/debug visiveis ao usuario sao carregados de `default/ui.yaml`. ## Controles - Tela de carregamento: validação automatica ao iniciar - Tela de titulo: `Up`/`Down` + `Enter` - Historia `Enter`: avancar dialogo / confirmar escolha selecionada - Historia `Up`/`Down`: navegar pelas escolhas - Historia `Left Click`: avancar dialogo (quando nao estiver em escolhas) - `F2`: alterna modo debug (mostra variaveis, digita ID da cena e aperta `Enter` para pular) - `F5`: salvar - `F9`: carregar - `Esc`: voltar para a tela de titulo ## Imports de script Use `imports` em qualquer arquivo de script. Os caminhos sao relativos ao arquivo que declara o import. ```yaml title: "Minha Historia" start: intro imports: - chapters/act1.yaml ``` Os imports podem ser aninhados recursivamente ate `MaxImportNesting`. ## Variaveis Defina variaveis com valores YAML tipados: ```yaml - type: set key: player_name value: "Mira" # string - type: set key: trust value: true # bool - type: set key: coins value: 3 # int - type: set key: luck value: 1.5 # float ``` Interpolacao em campos de texto/sprite/fundo usa `{var_name}`. ## Condicoes e fluxo if/else Condicao inline (guarda no nivel do comando): ```yaml - type: say if: "coins >= 2" speaker: Narrador text: "Voce consegue pagar o bonde." ``` `if/else` estruturado: ```yaml - type: if if: "trust == true" then: - type: say speaker: Mira text: "Entao me siga." else: - type: say speaker: Mira text: "Mantenha distancia." ``` Operadores suportados: `==`, `!=`, `>`, `<`, `>=`, `<=`. ## Validação Na inicializacao, a engine verifica: - se todos os arquivos de script carregados existem - se todos os alvos de `goto` e `choice` existem - se os assets de fundo/sprite referenciados existem (para caminhos estaticos) Caminhos dinamicos de asset contendo variaveis (ex.: `{mood}.png`) sao ignorados na verificacao estatica de existencia. ## Referencia de comandos - `say` - `background` (`background` ou `background_image`) - `character` (`character`, `emotion`, `sprite` opcional) - `set` - `if` (`if`, `then`, `else`) - `goto` - `choice` - `end` ## Cena de menu interativo (`menu`) Voce pode criar um menu em cena com sprites posicionados e navegacao por setas (`Left`/`Right`/`Up`/`Down`) + `Enter`. ```yaml - type: menu background_image: assets/bg_hub.png menu_items: - id: oficina sprite: assets/menu_oficina.png x: 0.25 y: 0.45 selectable: true commands: - type: set key: destino value: oficina - type: goto target: cena_oficina - id: mercado sprite: assets/menu_mercado.png x: 0.65 y: 0.45 if: "coins >= 2" selectable: true commands: - type: say speaker: Narrador text: "Voce vai para o mercado." - id: decoracao sprite: assets/menu_estatua.png x: 0.45 y: 0.2 selectable: false commands: - type: say speaker: Narrador text: "Isto nao deve executar porque nao e selecionavel." ``` Notas: - `x`/`y` entre `0` e `1` sao tratados como proporcao da tela. - `x`/`y` acima de `1` sao tratados como pixels absolutos. - Itens com `if` falso nao aparecem. - Itens com `selectable: false` aparecem, mas nao recebem destaque nem selecao. - `commands` de um item aceitam qualquer fluxo suportado (`set`, `if`, `goto`, `say`, etc.).