singe/docs/es/Manual.adoc

1509 lines
94 KiB
Text

= Manual de Singe
Scott Duensing <scott@kangaroopunch.com>
:revnumber: 3.00
:revdate: 2026
:doctype: book
:toc: left
:toclevels: 3
:sectnums:
:sectnumlevels: 3
:title-logo-image: image:images/singeLogo.png[Singe, pdfwidth=2.6in, align=center]
:source-highlighter: rouge
:icons: font
:experimental:
:lang: es
:imagesdir: ..
include::locale.adoc[]
[#_about_singe]
== Acerca de Singe
Singe (Scott's Increasingly Nifty Game Engine, «el motor de juegos cada vez más
ingenioso de Scott», que debe su nombre al dragón de Dragon's Lair) es un
sistema de scripts basado en Lua que permite crear rápidamente prototipos de
nuevos juegos de laserdisc, o crear juegos totalmente nuevos. El lenguaje es
fácil de aprender, muy potente y rápido. Todo lo necesario para desarrollar tu
propio juego está disponible a través de una sencilla interfaz de programación
de aplicaciones (API).
Singe ofrece numerosas funciones al desarrollador de juegos. Algunas de las más
interesantes son:
* Escenas 3D con modelos, animación, iluminación y sombras
* Física, con articulaciones, ragdolls, cuerpos blandos y vehículos
* Menús, pantallas de opciones y HUD construidos como páginas web
* Decodificación de vídeo por hardware, incluso en máquinas pequeñas
* Récords en línea y un catálogo de juegos para descargar y actualizar
* Juegos empaquetados en un solo archivo
* Lenguaje de programación orientado a objetos
* Sprites animados
* Compatibilidad con fuentes TrueType
* Espacio de color de 32 bits con transparencia
* Sonido estéreo multicanal y superpuesto, y MIDI
* Compatibilidad con dispositivos de entrada analógicos y digitales, incluidas las pistolas de luz
* Amplia compatibilidad con formatos de vídeo y audio
Singe funciona en Windows, macOS y Linux, con procesadores ARM además de Intel y
AMD: portátiles con Windows en ARM, la Raspberry Pi y consolas portátiles como la
R36S.
Para los jugadores, Singe permite disfrutar de muchos juegos nuevos y no
emulados con el front-end que prefieras o con el sistema de menús incluido.
Desde el lanzamiento original de Singe allá por 2006, se han publicado varias
revisiones, tanto oficiales como no oficiales. En 2020 se publicó Singe 2.00.
Era una reescritura total desde cero, que añadía numerosas funciones sin dejar
de ser compatible con los juegos 1.xx existentes. Singe 3.00 añade 3D, física,
interfaces de usuario y mucho más, y sigue ejecutando los juegos que vinieron
antes. En el momento de escribir este manual, la última versión es la
{revnumber}.
[#_installation_and_upgrading]
== Instalación y actualización
[#_installing_singe]
=== Instalar Singe
Para instalar Singe, basta con descargar el binario adecuado para tu sistema.
Ponlo solo en una carpeta nueva y ejecútalo. La primera vez que se ejecuta,
Singe crea todas las carpetas y archivos de soporte necesarios. Ya puedes
instalar algunos juegos. En un PC con Windows y procesador ARM, elige la versión `Windows-aarch64`: la
versión `Windows-x86_64` también funciona allí, emulada, pero más despacio.
[#_upgrading_singe]
=== Actualizar Singe
Para actualizar Singe a una versión más reciente, pon el binario nuevo en la
carpeta de instalación junto al antiguo y ejecútalo una vez con `--refresh`. La
carpeta de soporte que haya se aparta como `old-Singe-<version>`, con el nombre
de la versión que la escribió, y en su lugar se escribe una carpeta `Singe/`
nueva. No se borra nada: la carpeta apartada es tuya, para conservarla o
quitarla, y un segundo `--refresh` aparta la suya como `old-Singe-<version>-1`
en lugar de escribir encima de la primera.
El binario antiguo puede quedarse donde está. `Menu.sh` (o `Menu.bat`) ejecuta
el Singe más reciente que encuentra junto a sí mismo, y una beta cuenta como más
antigua que la versión final del mismo número, así que `Singe-v3.00b2` cede el
paso a `Singe-v3.00` en cuanto este llega. La herramienta Engine Update del menú
hace todo esto por ti; véase <<servicetools,Las herramientas de servicio>>.
WARNING: No ejecutes un binario nuevo de Singe con un conjunto de archivos de
soporte desactualizado. Renueva siempre la carpeta `Singe/` al actualizar.
[#_things_to_know]
=== Cosas que debes saber
No toques la carpeta `Singe/`. Los archivos de esta carpeta pertenecen a Singe y
pueden actualizarse o borrarse en cualquier momento.
[#_playing_games]
== Jugar
[#_installing_games]
=== Instalar juegos
Un juego es o bien un único archivo `.game` o bien una carpeta. Cópialo en la
misma carpeta en la que pusiste el binario de Singe. El sistema de menús
incluido lo detectará automáticamente y lo añadirá al menú.
[#_game_directory_layout]
=== Estructura de la carpeta de juegos
Una instalación de Singe es una carpeta de juegos que contiene la carpeta de
soporte `Singe` que el motor crea en la primera ejecución, una carpeta por
juego, los archivos `.game` empaquetados que haya y una carpeta `data` para
todo lo que escriben los juegos y el motor. El ejecutable suele estar ahí
también, pero no hace falta: `--gamedir` indica la carpeta de juegos desde
cualquier sitio, y el `Menu.sh` (o `Menu.bat`) que el motor escribe ahí ejecuta
entonces el ejecutable por su ruta completa. Si no, el lanzador busca junto a sí
mismo los archivos cuyos nombres empiezan por `Singe` y ejecuta el mejor de
ellos, al estilo de los lanzadores que escribe `BatMaker`, de modo que una
actualización que cambia la versión en el nombre del ejecutable no deja un
lanzador apuntando a un archivo que ya no está.
El mejor significa primero la arquitectura de esta máquina y después la versión.
La plataforma del nombre se compara con lo que informa el sistema, porque una
compilación más reciente para otra arquitectura no puede ejecutarse en absoluto,
y una misma carpeta de juegos en un recurso compartido puede leerla tanto una
Pi como un PC. El lanzador lo averigua cada vez que se ejecuta en lugar de que se
lo digan una sola vez, así que la misma carpeta sirve para todas las máquinas
que la abren. En un Mac, una compilación universal cuenta como nativa. Entre las
compilaciones que esta máquina puede ejecutar, gana la más reciente:
`Singe-v3.10` gana a `Singe-v3.09`, y una beta pierde frente a la versión final
a la que precede, así que `Singe-v3.00b2` pierde frente a `Singe-v3.00`. Una
compilación para otra arquitectura se ejecuta igualmente cuando es la única que
hay, ya que una queja real del motor es mejor que oír que no se encontró nada, y
lo mismo pasa con un nombre que el lanzador no consigue leer en absoluto.
----
Singe/ Archivos de soporte extraídos por el motor
Framework.singe Lo carga cada juego (con dofile)
Menu.singe El menú de juegos incluido
Tools.singe Las herramientas de servicio del menú (véase Las herramientas de servicio)
MenuDocument.singe El menú dibujado como documento de la GUI
MenuOverlay.singe El menú dibujado en el overlay, para una máquina sin GPU
Backdrop.singe La intro del menú y la cuadrícula de detrás, dibujadas en directo
menuBackground.mkv El mismo fondo grabado, para una máquina sin GPU
menuIntro.flac Su sonido, que se desvanece cuando el menú ocupa la pantalla
Menu.rml El documento RmlUi del renderizador de documentos
menu.rcss Su hoja de estilo, por encima de gui.rcss
gui.rcss El tema de la GUI incluido
controls.cfg.example Plantilla para las asignaciones de entrada
click.wav Lo usan las pruebas de retardo de audio y de sonido del menú
Manual.pdf Este manual
Manual-fr.pdf Este manual en francés
Manual-it.pdf Este manual en italiano
Manual-de.pdf Este manual en alemán
Manual-es.pdf Este manual en español
COPYING La Licencia Pública General de GNU, versión 3
LICENSES Avisos de terceros y créditos de los recursos
Collection/ Una carpeta de juegos
games.dat Entradas del menú para los juegos de esta carpeta
AsteroidPatrol.singe Un script
frame_AsteroidPatrol.txt Su framefile (o un vídeo con el mismo nombre base)
sprite_*.png, sound_*.wav, font_*.ttf
MyGame.game Un juego empaquetado en un solo archivo (véase Juegos en un solo archivo)
data/
machine.cfg El retardo de audio y la geometría de imagen de esta máquina
Collection/ Índices, trace.txt, capturas de pantalla y partidas guardadas de esos juegos
----
Dónde busca Singe los archivos de un script, y dónde puede escribir un script,
es asunto de quien escribe el script; la Referencia de Singe trata las dos
cosas en «Empaquetar tu juego».
[#bundledmenu]
=== El menú incluido
`Menu.sh` (o `Menu.bat`) inicia `Singe/Menu.singe`, el menú incluido: un
documento RmlUi, `Singe/Menu.rml` con el estilo de `Singe/menu.rcss`, dibujado
sobre un fondo 3D en directo (véase xref:Reference.adoc#gui[GUI]). El menú
funciona sin disco; una máquina sin GPU reproduce en su lugar
`Singe/menuBackground.mkv`, una grabación del mismo fondo, detrás de una página
más sencilla dibujada en el overlay. Lee el `games.dat` de cada carpeta de
juego y de cada archivo `.game` que tiene al lado y muestra todos los juegos que
encuentra, ordenados por título, a lo largo del lado izquierdo de la pantalla.
Junto a la lista están el arte de la recreativa del juego seleccionado, su
marquesina y su clip del modo de atracción, con el año, el género, la
plataforma, el desarrollador, el editor, los créditos de la conversión y la
descripción debajo, y una línea de indicaciones de teclas en la parte inferior.
Arriba y abajo mueven la selección de juego en juego, e izquierda y derecha la
mueven de página en página; ambas dan la vuelta de un extremo de la lista al
otro. Start o cualquier botón de acción inicia el juego seleccionado, y la tecla
asignada a `INPUT_SERVICE` (la tecla `9` por defecto) abre las herramientas de
servicio (véase <<servicetools,Las herramientas de servicio>>). Con un ratón, un
clic en una fila selecciona ese juego y un segundo clic en la misma fila lo
inicia; la rueda del ratón desplaza una descripción demasiado larga para su
panel. Si configuras `--quitchord`, mantener pulsados esos botones te saca de un
juego al menú, y del menú a tu sistema (véase <<handhelds,Consolas portátiles y
máquinas pequeñas>>). El menú guarda su selección en `menu.dat` en su carpeta
de datos, así que vuelve al mismo juego cuando sales de uno o la próxima vez que
se inicia Singe. Ese archivo es un fragmento de Lua que el menú lee al arrancar
y reescribe al cerrarse: `GAME_SELECTED` es el juego que estaba mostrando,
`SHOW_INTRO` es false cuando vuelve de un juego, para que no tengas que tragarte
la intro dos veces, y `MENU_OVERLAY` elige un renderizador (véase
<<menurenderers,Los dos renderizadores>>).
No todas las máquinas ejecutan todos los juegos. Un juego 3D en un aparato sin
3D, o un juego pesado en uno pequeño, fallaría o iría a paso de tortuga, así que
el menú te lo dice antes. Cuando seleccionas un juego que esta máquina no puede
ejecutar, la línea bajo sus detalles dice lo que necesita («Needs 3D, and this
machine has none.»), y al iniciarlo solo se repite eso en lugar de fallar a
medio camino. Un juego que pide más máquina que esta recibe «It may run
slowly.» y se inicia igualmente. No se oculta nada. El menú averigua lo rápida
que es esta máquina la primera vez que se reproduce su intro, cronometrando su
propio fondo, y guarda la respuesta en `machine.cfg`; nunca te pide que ejecutes
una prueba de rendimiento. Los juegos dicen lo que necesitan en su `games.dat`
(xref:Reference.adoc#gamesdat[REQUIRES y TIER]), y la herramienta Get Games
marca el catálogo del mismo modo.
[#menurenderers]
==== Los dos renderizadores
Un documento de la GUI se dibuja a través del dispositivo GPU que usa la escena
3D, así que en una máquina sin él no hay documento que construir. El menú se
encarga de eso por sí mismo: `Singe/Menu.singe` consulta
xref:Reference.adoc#singehasgpu[singeHasGpu] al arrancar y carga uno de los dos
renderizadores.
`Singe/MenuDocument.singe`::
El documento RmlUi descrito arriba, para una máquina con dispositivo GPU.
También dibuja la intro y la cuadrícula de detrás del menú como una sola escena
3D continua, así que el disco no se usa para ninguna de las dos.
`Singe/MenuOverlay.singe`::
Sprites y `fontPrint` directamente en el overlay, el aspecto que tenía Singe 2.
No necesita nada más allá del overlay en el que ya dibuja cada juego.
Los dos dibujan el mismo menú, aceptan las mismas teclas y ejecutan las mismas
herramientas de servicio; `Singe/Menu.singe` contiene todo lo que no es dibujar
-- la lista de juegos, la selección, iniciar un juego -- así que hay un solo menú
en lugar de dos. El renderizador del overlay muestra un juego cada vez en lugar
de una lista, ya que no tiene panel que desplazar, y recorta una descripción
demasiado larga para su columna en lugar de desplazarla.
Para ver el renderizador del overlay en una máquina que sí tiene GPU, pon
`MENU_OVERLAY = true` en `menu.dat` en la carpeta de datos del menú; el menú
vuelve a escribir la línea, así que se conserva. Así es como se prueba el camino
del overlay, y como lo consigue el montador de recreativas que prefiere el
aspecto antiguo.
[#onlineservice]
==== En línea: cuentas, juegos y puntuaciones
El menú incluido puede iniciar la sesión de la recreativa en un servicio maestro
(por defecto `master.singeengine.com`), que hace tres cosas: guarda la cuenta,
ofrece un catálogo de juegos para descargar y actualizar, y mantiene tablas de
récords.
Dos herramientas de servicio se encargan de ello. **Online Account** inicia
sesión, crea una cuenta, recupera una contraseña y establece la dirección del
servidor -- es donde un operador que gestiona su propio servicio apunta la
recreativa. Una cuenta nueva no se puede usar hasta que se abre el enlace
enviado por correo electrónico. **Get Games** muestra todo lo que ofrece el
servicio, marca lo que está instalado aquí y lo descarga, actualiza o quita. Una
descarga que contiene varios juegos -- una colección, o un juego en dos idiomas
-- pone cada uno de ellos en la lista con su propio nombre, indicando en qué
descarga viene, y descargar o quitar cualquiera de ellos descarga o quita todos,
ya que son un solo archivo. Lo que se ofrece depende de la cuenta: un servicio
puede reservar un juego para cuentas concretas, así que dos recreativas con la
sesión iniciada en cuentas distintas pueden ver listas distintas. El propio menú
avisa cuando existe una versión más reciente de un juego instalado: el juego
lleva una marca `update` en la lista, la línea bajo sus detalles indica la
versión, y el botón 3 en esa página la descarga, así que una recreativa no
necesita abrir una herramienta de servicio para estar al día. No se guarda en
ningún sitio nada sobre esta máquina: el menú lee la versión del propio
`games.dat` de cada juego y pregunta por su propia lista, así que un juego
copiado a mano se conoce igual que uno descargado aquí. Una recreativa sin
ningún juego abre igualmente el menú, que explica cómo conseguir algunos, y lo
que Get Games descargue o quite aparece en la lista en cuanto se cierran las
herramientas de servicio. Una lista más larga que la pantalla se desplaza con la
selección en lugar de salirse por abajo, con `...` para indicar que hay más en
un sentido u otro. Un juego que deja de ofrecerse sigue funcionando y se muestra
como «installed, no longer offered»: lo único que deja de pasar es que reciba
actualizaciones, porque un jugador que tiene un juego lo tiene. Una descarga se
comprueba con el hash que publicó el catálogo antes de que sustituya nada, así
que una transferencia que llega mal falla en lugar de instalar un juego que no
funcionará.
La cuenta pertenece a la *máquina*, no a un juego: el token se guarda en
`master.dat` en la raíz de datos, así que un juego que publica una puntuación usa
la misma sesión que inició el menú. La contraseña nunca se guarda, y el archivo
está ofuscado, así que el token y la dirección de la cuenta no se pueden sacar de
él de un vistazo; un archivo editado se lee como sin sesión. La máquina tiene que
poder volver a leerlo sin nadie delante, así que trata `master.dat` de todos
modos como una llave de la cuenta: copiado a otra máquina, inicia la sesión en
esa máquina. Publicar una puntuación necesita esa cuenta, pero leer una tabla de
récords no: una recreativa sin sesión sigue mostrando la tabla de récords en
línea de un juego, donde el juego muestre una, para cualquier juego que el
servicio ofrezca a todo el mundo. Véase
xref:Reference.adoc#onlinescores[Récords en línea] para la parte del juego, y
`Singe/Net.singe` para el cliente HTTP asíncrono que hay debajo -- nada de esto
bloquea un fotograma, porque Lua en Singe es cooperativo y una descarga grande
parecería si no un cuelgue.
Singe comprueba el certificado del servidor con dos listas a la vez: la que trae
consigo y la que guarda tu máquina. Basta con que una de las dos avale al
servidor, así que una copia antigua de Singe aún puede llegar a la actualización
que la sustituye siempre que tu sistema mantenga al día su propia lista.
¿Gestionas tu propio servicio con un certificado de tu propia autoridad? Pon el
certificado de esa autoridad en `cacerts.local.pem` en la carpeta de datos.
Singe nunca escribe ese archivo, así que sobrevive a las actualizaciones. Si se
rechaza una conexión, el mensaje dice qué listas se comprobaron, y un
certificado «not yet valid» casi siempre significa que el reloj de la máquina va
mal.
[#servicetools]
==== Las herramientas de servicio
La tecla asignada a `INPUT_SERVICE` abre una lista de herramientas sobre la
lista de juegos. Arriba y abajo eligen una y el botón 1 la abre; el botón 2 sale
de una herramienta a la lista, y la tecla de servicio otra vez sale de las
herramientas del todo. Todo está en `Singe/Tools.singe`, que el motor extrae
junto a `Menu.singe`. Ahí nada dibuja: una herramienta construye una lista de
filas y se la pasa al menú, y por eso todas las herramientas funcionan con los
dos renderizadores (véase <<menurenderers,Los dos renderizadores>>). Nada de
esto necesita que haya un juego en marcha, y nada cambia los archivos propios de
un juego.
Audio Delay::
El retardo del audio en la cadena de salida, medido con un clic y un destello.
Véase xref:Reference.adoc#menucalibration[Calibrar desde el menú] para saber qué
hace y por qué funciona.
Input Test::
Todos los mandos, ratones y pistolas que el motor ve, en directo: el último
interruptor que habría recibido el juego y cuántos han llegado, el nombre de
cada mando con sus seis ejes y los botones pulsados, y el nombre y la posición
de cada ratón. Esta es la pantalla que responde a «el botón no hace nada» -- o
el interruptor llega y el juego lo ignora, o no llega nunca.
System Information::
La versión del motor, el sistema operativo, el procesador y la memoria, el
renderizador y el dispositivo 3D, qué decodificadores de vídeo están en uso, los
formatos de audio incorporados, la SoundFont, el estado de MIDI, los tamaños de
la ventana, del lienzo y del overlay, y la carpeta de datos. Una foto de esta
página responde a la mayor parte de un informe de error.
Light Gun::
Dianas en el centro y en cada esquina del overlay, sobre lo que esté mostrando
el disco. El botón 1 marca dónde apuntó de verdad la pistola, y guarda los
últimos doce disparos; Start los borra. Una pistola bien alineada con la imagen
pone sus cruces sobre las dianas, y una que no lo está muestra hacia dónde se
desvía.
Sound Test::
El botón 1 reproduce el clic por el altavoz izquierdo, luego por el derecho y
luego por los dos, que es toda la comprobación de cables cruzados. También
muestra las pistas de audio propias del disco, e izquierda y derecha cambian
entre ellas.
Display::
El tamaño, la posición y la rotación de la imagen, cambiados en directo con las
flechas, los botones 3 y 4 y la moneda 1, sobre una carta de ajuste: una
cuadrícula de 16 por 12 para cuadrar la imagen, una cuña de grises de ocho
escalones para ajustar el brillo, y dos marcos separados un píxel en el mismo
borde -- un monitor con overscan se come primero el de fuera. El botón 1 guarda
los valores para esta máquina, en el mismo `machine.cfg` que usa el retardo de
audio, así que se aplican a todos los juegos en lugar de ajustarse una vez por
juego. Start lo deja todo como estaba.
Disc Test::
Doce saltos repartidos por todo el disco, cada uno cronometrado. Un rip cuyos
fotogramas clave están muy separados salta despacio, y el único síntoma en un
juego es que todo se nota pesado; esto lo mide directamente e informa del peor
de los doce. Un salto que no ha llegado en tres segundos cuenta como tres
segundos.
Saved Data::
Lo que ha guardado cada juego, encontrado buscando en la raíz de datos en lugar
de que se lo digan, con el tamaño de cada cosa. El botón 3 -- no el botón 1, que
es «elegir» en todas las demás partes -- tira la partida guardada del juego
seleccionado. Borrar una tabla de récords sin borrar el juego es el motivo
habitual.
Engine Update::
Un Singe más reciente, cuando el servicio tiene uno para esta máquina. Una beta
lleva la versión `3.00b2`, la segunda beta de la 3.00, y va antes que la propia
3.00, así que a una recreativa con una beta se le ofrece la versión final el
mismo día que se publica. Muestra lo que está en marcha y lo que se ofrece, y el
botón 1 lo descarga, lo comprueba con el hash que publicó el servicio, lo pone
junto al Singe en marcha con el nombre propio de la versión, aparta el antiguo
como `old-<name>` y se reinicia con el nuevo. Apartar el antiguo puede no ser
posible, por una carpeta en la que este usuario no puede escribir o por un
antivirus que tiene el archivo abierto; la herramienta lo dice y sigue adelante,
ya que el lanzador ejecuta de todos modos el Singe más reciente de la carpeta.
El nuevo Singe arranca con `--refresh`, así que la carpeta de soporte la
reescribe la versión que ahora es su dueña y la antigua se conserva como
`old-Singe-<version>`; un archivo que traía un Singe anterior y que este no trae
no puede quedarse por ahí y confundir a un juego. No pasa nada hasta pulsar ese
botón. El botón 3 vuelve a preguntar al servicio. El menú mira una vez al día
por su cuenta y lo indica en una línea bajo los detalles del juego;
`no_update_check = true` en `settings.cfg` detiene la consulta diaria, y la
herramienta sigue funcionando a mano.
Online Account::
Iniciar la sesión de esta recreativa en el servicio maestro, crear una cuenta,
recuperar una contraseña y establecer la dirección del servidor. Véase
<<onlineservice,En línea: cuentas, juegos y puntuaciones>>.
Get Games::
El catálogo: lo que ofrece el servicio, lo que está instalado aquí, y
descargarlo, actualizarlo o quitarlo.
MIDI Ports::
Los puertos de entrada y salida que tiene esta máquina, cuáles de ellos ha
abierto Singe y los últimos mensajes que han llegado. El botón 1 envía una nota,
el botón 3 vuelve a buscar puertos después de conectar algo. No se abre nada
hasta que esta herramienta lo pide, así que una recreativa que nunca toca MIDI
nunca paga por ello.
Frame Statistics::
Activa y desactiva el overlay del desarrollador. Sigue activo dentro del juego,
en la esquina superior izquierda. Véase xref:Reference.adoc#statsenable[statsEnable].
[[controls]]
== Controles
Por defecto, Singe asigna los mandos como si fueran mandos de Xbox. Si tu mando
no se reconoce o quieres cambiar las asignaciones por defecto tal y como las ve
Singe, puedes usar la herramienta gratuita SDL2 Gamepad Tool de
http://generalarcade.com/gamepadtool/.
[[controlscfg]]
=== controls.cfg
Además de configurar tu mando, puedes reasignar todas las opciones de entrada de
Singe en su conjunto o de cualquier juego concreto con archivos `controls.cfg`.
Para decidir cómo se asignan las entradas, Singe lee los ajustes de configuración
en el orden siguiente, y un archivo posterior sustituye a uno anterior entrada por
entrada (véase <<configorder,Dónde se leen los archivos de configuración>>):
. Los valores por defecto incluidos en Singe.
. `controls.cfg` de la carpeta del script principal del juego: lo que distribuyó el autor del juego.
. `controls.cfg` de la carpeta desde la que se inició Singe: el de la propia máquina (la carpeta `Singe` contiene una plantilla `controls.cfg.example` que puedes copiar).
. `controls.cfg` de la carpeta que está por encima de la carpeta de datos del juego.
. `controls.cfg` de la carpeta de datos del juego: el tuyo, para ese juego concreto.
No tienes que especificar todas las opciones en un archivo `controls.cfg`
personalizado. Basta con que pongas las entradas que quieras cambiar.
Después de instalar Singe, encontrarás un archivo de ejemplo de configuración de
entradas en `<InstallDir>/Singe/controls.cfg.example`. Para ver las opciones de
configuración que puedes usar en este archivo, repasa
`<InstallDir>/Singe/Framework.singe`.
`--keymapfile` indica un único archivo que leer en lugar de hacer esa búsqueda, lo
que resulta útil a un front-end que no quiere ninguna duda sobre qué asignaciones
recibió un juego.
Cada entrada `INPUT_` es una lista, y cualquier elemento de ella acciona el
interruptor. Una lista dentro de esa lista es una combinación: de dos a cuatro
teclas o botones pulsados a la vez, que acciona el interruptor cuando se pulsa el
último de ellos y lo suelta cuando se levanta cualquiera. Así es como una consola
portátil sin tecla Escape sale con Select y Start a la vez:
[source,lua]
----
INPUT_QUIT = { SCANCODE.ESCAPE, { GAMEPAD_0.BUTTON_BACK, GAMEPAD_0.BUTTON_START } }
----
Cada tecla o botón de una combinación conserva además su propio significado, así
que pulsar Select y Start para salir de esta forma también echa una moneda y pulsa
Start de camino a la salida.
Si quieres una forma de salir que funcione siempre, usa `--quitchord` en su lugar.
Cuando pulsas uno de sus botones, Singe espera un cuarto de segundo al resto antes
de hacer nada más, así que salir no echa una moneda ni pulsa Start. Un juego puede
desactivar su propia tecla de salida, pero no puede desactivar `--quitchord`.
[[devices]]
=== Todo dispositivo es un mando
Singe tiene una sola familia de mandos, de `GAMEPAD_0` a `GAMEPAD_3`, y todo
dispositivo que abre pertenece a ella. SDL solo llama mando a un dispositivo
cuando tiene una asignación para él, y una placa encoder de recreativa, un
spinner, un volante o un joystick de vuelo a menudo no la tiene. En lugar de
arrastrar un segundo tipo de dispositivo con sus propios nombres, Singe escribe él
mismo una asignación para ese dispositivo y luego lo abre como un mando corriente,
de modo que llega a `controls.cfg`, `controllerGetAxis`,
`controllerGetButton` y a todos los interruptores `INPUT_*` exactamente igual que
un mando reconocido.
La asignación que escribe Singe es directa: los ejes del dispositivo, en orden,
pasan a ser el stick izquierdo, el stick derecho y luego los dos gatillos; sus
botones, en orden, pasan a ser `BUTTON_A`, `BUTTON_B`, `BUTTON_X`, `BUTTON_Y`,
`BUTTON_BACK`, `BUTTON_GUIDE`, `BUTTON_START`, `BUTTON_LEFT_STICK`,
`BUTTON_RIGHT_STICK`, `BUTTON_LEFT_BUMPER` y `BUTTON_RIGHT_BUMPER`; y su primer
hat pasa a ser la cruceta. Un dispositivo sin hat dedica en su lugar sus cuatro
botones siguientes a la cruceta. **Un dispositivo con más controles de los que el
modelo de mando puede nombrar pierde los que sobran** -- más de seis ejes, más de
quince botones o un segundo hat -- y un dispositivo cuyos botones no estén
cableados en ese orden los tendrá en los sitios equivocados. Ese es el precio de
una familia en lugar de dos, y es fácil de corregir: `--program` escribe en la
traza la asignación que creó, en el formato propio de SDL, así que puedes pegarla
en un `gamecontrollerdb.txt`, reordenarla y hacer que se use esa.
`--mapjoysticks=false` desactiva esa escritura, y en ese caso un dispositivo que
SDL no reconoce no se abre en absoluto, exactamente como en versiones anteriores.
[[gamecontrollerdb]]
=== gamecontrollerdb.txt
SDL incluye una gran base de datos de asignaciones de mandos, y la comunidad
mantiene una más grande -- `gamecontrollerdb.txt`, de
https://github.com/mdqinc/SDL_GameControllerDB. Singe busca ese archivo en los
mismos cuatro sitios en los que busca `controls.cfg`, en el mismo orden (véase
<<configorder,Dónde se leen los archivos de configuración>>):
. la carpeta del script principal del juego;
. la carpeta desde la que se inició Singe;
. la carpeta que está por encima de la carpeta de datos del juego;
. la carpeta de datos del juego.
Se cargan todos los archivos encontrados, en ese orden, así que el archivo de la
máquina gana al que distribuye un juego, un archivo en la carpeta de datos del
juego gana a los dos y todos ellos ganan a la propia base de datos de SDL. Solo un dispositivo que ninguno de ellos
nombra recibe la asignación que Singe escribe para él: esa es el último recurso,
nunca una rival de tus archivos. `--program` informa de cuántas asignaciones
añadió cada archivo.
Los archivos también ganan a `SDL_GAMECONTROLLERCONFIG`, la variable de entorno de
la que SDL toma asignaciones, que algunas consolas portátiles definen para su mando
integrado. La asignación de ArkOS para la R36S, por ejemplo, deja fuera Select y
Start, así que ningún juego los ve; una línea en `gamecontrollerdb.txt` para el
mismo mando los devuelve. SDL lee la variable una sola vez, cuando arranca Singe,
así que esto vale para los archivos que encuentra el primer juego. Un juego
iniciado después desde el menú sigue leyendo los suyos, pero un mando que la
variable nombra conserva la asignación de la variable.
Una línea de ese archivo tiene este aspecto, y es exactamente lo que imprime la
traza para un dispositivo que Singe asignó por sí mismo:
----
ff00d87a475300004900000000007603,Arcade Encoder,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b4,guide:b5,start:b6,leftx:a0,lefty:a1,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,
----
[[deadzones]]
=== Zonas muertas y gatillos
`DEAD_ZONE` en `controls.cfg` es cuánto debe moverse un eje antes de contar como
un interruptor pulsado, en las unidades en bruto que da SDL: `32767` con el eje a
fondo, así que el valor por defecto de `15000` es algo menos de la mitad del
recorrido. Abarca todos los ejes de todos los mandos, incluidos los dos gatillos
analógicos, y un script lo lee como `SINGE_DEAD_ZONE`.
Dos ajustes lo afinan más.
`DEAD_ZONES` es una lista de pares `{ axis, dead zone }`, para un eje cada vez, en
esas mismas unidades en bruto, para un stick duro o un gatillo gastado sin tocar
todo lo demás:
[source,lua]
----
DEAD_ZONES = {
{ GAMEPAD_0.AXIS_LEFT_X, 8000 },
{ GAMEPAD_1.AXIS_LEFT_TRIGGER, 30000 },
}
----
El eje puede escribirse como el propio eje o como cualquiera de sus dos direcciones
(`GAMEPAD_0.AXIS_LEFT_X`, `AXIS_LEFT_X_L` y `AXIS_LEFT_X_R` nombran todos el mismo
eje). Todo lo que no esté en la lista conserva `DEAD_ZONE`.
`TRIGGER_THRESHOLD` es cuánto debe recorrer un gatillo analógico antes de contar
como un botón, expresado como *porcentaje del recorrido completo*, que es la
unidad que usa `-trigger-threshold` de Hypseus y cuyo valor por defecto allí es
`99.5`. Se aplica a los dos gatillos de los cuatro mandos. El valor por defecto de
Singe es `0`, lo que significa que los gatillos siguen con `DEAD_ZONE`, así que
nada cambia para quien no lo pida; un script lee el resultado en unidades en bruto
como `SINGE_TRIGGER_THRESHOLD`. Las dos unidades se convierten directamente: un uno
por ciento son `32767 / 100` unidades en bruto, así que el `DEAD_ZONE` de `15000`
de Singe es un `45.8` por ciento y el `99.5` por ciento de Hypseus son `32603`
unidades en bruto. `--trigger_threshold` fija el mismo número desde la línea de
comandos y gana a `controls.cfg`; `DEAD_ZONES` gana a los dos, por ser el más
específico.
[[joymouse]]
=== Mover el ratón con un stick
Un juego de pistola de luz en una recreativa con stick y sin ratón no se puede
jugar a menos que el stick pueda mover el cursor. `--joymouse` hace que lo mueva:
el **stick izquierdo del mando de la ranura 0** mueve el puntero que ve el juego, a
través del mismo `onMouseMoved` al que llega un ratón real, y el cursor se mantiene
dentro de la imagen. `--js_range` es la velocidad, de `1` a `20` con `5` por
defecto, medida en píxeles de vídeo por fotograma con el stick a fondo, así que
`5` cruza una imagen de 720 píxeles en unos dos segundos. El eje respeta su propia
zona muerta, así que un stick con deriva no hace que el cursor se vaya desplazando
solo.
Está desactivado por defecto, y en eso Singe se diferencia de Hypseus: el
`controls.cfg` que se incluye ya asigna ese stick a `INPUT_UP`, `INPUT_DOWN`,
`INPUT_LEFT` y `INPUT_RIGHT`, y que además moviera el cursor sin que nadie lo
pidiera sorprendería a todos los juegos existentes. `--joymouse=false` equivale a
`-nojoymouse` de Hypseus, y un script lo activa y desactiva con `joyMouseEnable`
y lo consulta con `joyMouseIsEnabled`. Una recarga lo deja como lo dejó la línea
de comandos.
[[mousedevices]]
=== Ratones, pistolas y quién decide
`mouseSetMode(MOUSE_MANY)` es la decisión de un juego de distinguir hasta cuatro
ratones, algo que una recreativa de dos pistolas necesita y que no se le puede dar
a un juego que nunca hace esa llamada. `--manymouse` es la decisión del usuario y
tiene prioridad sobre ella: el modo está activo desde el principio y
`mouseSetMode(MOUSE_SINGLE)` ya no lo desactiva.
`--absolutes_only` se queda solo con los dispositivos que informan de una posición
absoluta, que es lo que hace una pistola de luz de verdad y no hace un ratón
corriente, así que una recreativa con dos pistolas y un ratón de escritorio
enchufado no se confunde por culpa del ratón. Ten en cuenta cómo lo decide:
**ManyMouse, el backend que usa Singe para distinguir los ratones, no ofrece
ninguna forma de preguntar a un dispositivo de qué tipo es**, así que un
dispositivo cuenta como absoluto en cuanto ha informado de una posición absoluta,
y no antes. Una pistola lo hace con su primer movimiento; hasta entonces está en
silencio, y un dispositivo solo relativo se queda en silencio para siempre. Por
tanto, la opción es un filtro por comportamiento observado y no por clase de
dispositivo, y en una máquina donde ningún dispositivo informa nunca de una
posición absoluta silencia todos los ratones.
`SWITCH_MOUSE_DISCONNECT` es un interruptor como cualquier otro, salvo que no lo
produce ninguna tecla ni botón: el motor lo lanza cuando se desenchufa un ratón o
una pistola de luz, una vez como pulsación y otra como liberación, para que un
juego de pistolas pueda indicarlo en pantalla en lugar de parecer que se ha
colgado. Es el interruptor de Hypseus del mismo nombre. `controls.cfg` no lo
asigna a nada; asígnale también una tecla si quieres ver qué hace un juego sin
tener que tirar de un cable.
[[hotkeys]]
=== Teclas rápidas
`Alt-Enter` alterna entre pantalla completa y ventana mientras el juego está en
marcha, igual que en Hypseus. El juego nunca ve la tecla. Una ventana que empezó
en pantalla completa exclusiva (`--fullscreen`) vuelve a ella en el modo de
pantalla que se le dio; una que empezó en ventana pasa a una ventana sin bordes
que cubre el escritorio. No hace falta cambiar nada más: el renderizador presenta
un tamaño lógico en coordenadas de vídeo y lo escala a lo que mida ahora la
ventana, el rectángulo del vídeo se construye en esas mismas coordenadas y el
destino de la rotación tiene el tamaño de la imagen y no el de la ventana, así que
la imagen, el overlay, las GUI y la correspondencia del ratón se ajustan solos.
Los demás interruptores que puede pulsar un usuario -- salir, pausa, captura de
pantalla, grabación, la consola y el conmutador de captura del ratón -- son
asignaciones normales de `controls.cfg` y se describen junto a los nombres
`INPUT_*` en el archivo de ejemplo.
[[recording]]
=== Grabar vídeo
`F10` empieza a grabar el juego, imagen y sonido a la vez, y `F10` de nuevo
detiene la grabación. Cada grabación es un nuevo `singeNNN.mp4` en la carpeta de
datos del juego, junto a las capturas de pantalla, y se reproduce en cualquier
cosa que reproduzca un MP4. La imagen es la ventana entera tal como la ves, bandas
negras incluidas, y el sonido es todo lo que suena en el juego: la música, los
efectos de sonido y la propia banda sonora del vídeo.
Si la máquina tiene un codificador de vídeo por hardware, Singe lo usa, así que
grabar le cuesta muy poco al juego: H.264 mediante VA-API en Linux, VideoToolbox
en macOS, Media Foundation en Windows y V4L2 en las placas ARM que tienen uno. En
cualquier otro caso graba MPEG-4, que se reproduce en todas partes pero genera
archivos más grandes. La línea `Recording` de la traza dice cuál usó. Una máquina
demasiado lenta para seguir el ritmo descarta fotogramas de la grabación en lugar
de ralentizar el juego, y la traza dice cuántos cuando se detiene la grabación.
Para grabar en cambio una sesión entera, inicia Singe con `--record=FILENAME`.
Añade `--deterministic` y Singe grabará cada fotograma y el sonido exacto que lo
acompaña, tarde lo que tarde en generarse cada fotograma, sin reproducir nada por
los altavoces. Así es como se hace un vídeo perfecto de una demo o de un modo de
atracción: en un ordenador de sobremesa suele ir más rápido que en tiempo real.
[#_settings_and_options]
== Ajustes y opciones
Casi todo lo que puedes poner en la línea de comandos puede ir también en un
archivo de ajustes. Configúralo una vez y todos los juegos lo usan.
[[settings]]
=== El archivo de ajustes
Casi todo lo de la línea de comandos se puede escribir también una sola vez, en
un archivo `settings.cfg`, para que una recreativa no necesite un script lanzador
que lleve la misma docena de opciones para cada juego. Es Lua, como
`controls.cfg`, y Singe lo busca exactamente en los mismos cuatro sitios, en
este orden:
. `settings.cfg` de la carpeta del script principal del juego.
. `settings.cfg` de la carpeta desde la que se inició Singe (la carpeta `Singe` contiene una plantilla `settings.cfg.example` que puedes copiar).
. `settings.cfg` de la carpeta que está por encima de la carpeta de datos del juego.
. `settings.cfg` de la carpeta de datos del juego.
Cada sitio se lee una vez, y un archivo posterior gana clave por clave, así que
un archivo para toda la máquina puede fijar la pantalla y los volúmenes mientras
un archivo en la carpeta de datos de un juego desactiva el punto de mira de ese
juego. No tienes que escribir todas las claves en un archivo; escribe las que
quieras cambiar.
Cada clave es el nombre largo de una opción de línea de comandos sin los guiones
iniciales, así que no hay un segundo vocabulario que aprender:
[source,lua]
----
-- El settings.cfg de la propia recreativa
screen = 2 -- el segundo monitor
fullscreen = true
volume_vldp = 80
haptic = 0 -- esta recreativa no tiene vibración
idleexit = 900 -- devuelve la pantalla tras quince minutos sin actividad
startsilent = true
----
Una opción que no lleva valor en la línea de comandos lleva aquí `true` o
`false` (también se aceptan `yes`, `no`, `on`, `off`, `1` y `0`). Ponerla a
`false` es lo mismo que no ponerla. Una opción que lleva un valor lleva aquí el
mismo valor que en la línea de comandos, como número o como cadena.
Una opción, `--deterministic`, lleva un valor o no lo lleva, y su clave hace lo
mismo: `deterministic = true` usa el paso por defecto, `deterministic = 20`
indica uno, y `deterministic = false` deja la opción desactivada.
[[configorder]]
=== Dónde se leen los archivos de configuración
`controls.cfg`, `settings.cfg` y `gamecontrollerdb.txt` se buscan todos en los
mismos cuatro sitios, en el mismo orden, y un archivo leído después gana a uno
leído antes:
. *La carpeta del script principal del juego,* que para un juego empaquetado
está dentro de su archivo `.game`. Es lo que distribuyó el autor del juego,
así que se lee primero: fija los valores por defecto del juego y nada más.
. *La carpeta desde la que se inició Singe.* Aquí van los archivos propios de la
máquina, como la disposición de botones de una consola portátil, y ganan a lo
que distribuye un juego. Un archivo solo sustituye lo que nombra, así que para
quitar de un botón una asignación de un juego, nombra esa entrada:
`INPUT_TEST_MODE = { SCANCODE.F2 }` en el `controls.cfg` de la máquina deja el
modo de prueba solo en el teclado, sea cual sea el botón en el que lo pusiera
un juego.
. *La carpeta que está por encima de la carpeta de datos del juego,* para los
archivos que comparten todos los juegos que usan esa carpeta de datos.
. *La carpeta de datos del juego.* Tus propios archivos para un juego, que ganan
a todo lo demás.
Con `--datadir=.`, la carpeta de datos es la propia carpeta del juego, en cuyo
caso el archivo que hay ahí se lee una sola vez, como el del juego.
`--keymapfile` sustituye toda la búsqueda de `controls.cfg` por un único archivo
indicado.
[#_what_wins]
=== Qué prevalece
. El valor por defecto incorporado.
. El archivo de ajustes.
. La entrada del juego en `games.dat`, para el puñado de ajustes que lleva (véase xref:Reference.adoc#gamesdat[games.dat]).
. `machine.cfg`, para el retardo de audio y la geometría de la imagen que guardan
las herramientas de servicio (véase <<servicetools,Las herramientas de servicio>>).
. La línea de comandos, que siempre gana.
Un archivo de ajustes es, dicho de otro modo, un conjunto de valores por defecto,
no algo que hayas tecleado: si una entrada de `games.dat` da a un juego una
resolución o un borde Sinden, esa entrada sigue describiendo el juego mejor que
un archivo para toda la máquina. Lo que se teclea de verdad en la línea de
comandos gana a los dos. `machine.cfg` queda justo por debajo de la línea de
comandos porque alguien ajustó la imagen mirando este monitor, lo cual es mejor
prueba que cualquier archivo escrito en otra parte; el retardo de audio es una
excepción total a este orden, ya que se suma al retardo del juego en lugar de
sustituirlo.
Las opciones que nombran el juego (`--framefile`, `--disc`, `--entry`), nombran
una carpeta (`--gamedir`, `--datadir`), tienen que actuar antes de que se pueda
encontrar el archivo (`--help`, `--apiversion`, `--noconsole`, `--pack`,
`--patch`, `--unpack`) o son para una sola ejecución (`--record`, `--refresh`)
no se pueden fijar en un archivo de ajustes. Una clave que no es una opción, o que es una de esas, o un valor que la opción no acepta, es
un error que nombra el archivo y la clave, así que una errata nunca se ignora en
silencio:
----
settings.cfg: volume_vldpp is not an option.
settings.cfg: datadir cannot be set here; it belongs on the command line.
settings.cfg: Display scale must be between 25 and 100 percent.
----
Con `--program` o `--trace`, la cabecera al principio de `trace.txt` enumera
todos los ajustes que se aplicaron, así que nunca hay dudas sobre qué archivo
recibió un juego en marcha.
[[commandlineoptions]]
=== Opciones de línea de comandos
----
Singe [OPTIONS] gameName
----
El nombre del juego es el único argumento obligatorio. Puede ser un script
`.singe`, una carpeta que contiene un script con el mismo nombre (`MyGame`
encuentra `MyGame/MyGame.singe`) o un juego empaquetado (`MyGame.game` ejecuta
la primera entrada del `games.dat` que lleva dentro, `--entry=N` otra). Un
script o una carpeta iniciados así se ejecutan también con su entrada de
`games.dat` cuando hay una que los nombra (véase
xref:Reference.adoc#gamesdat[games.dat]), así que un juego funciona igual desde
la línea de comandos que desde el menú. Para un juego de laserdisc (`--disc`)
sin `--framefile`, Singe busca junto al script un vídeo con el mismo nombre base
y cualquier extensión que FFmpeg sepa desmultiplexar, y luego un framefile
`.txt`.
Las opciones están agrupadas según lo que hacen.
[#_the_game_and_its_files]
==== El juego y sus archivos
Qué juego se ejecuta, dónde están él y sus datos, y en qué se juega.
[cols="1,2",options="header"]
|===
| Opción | Función
| `-C`, `--canvas=WxH` | Tamaño del mundo para un juego sin disco, 720x480 por defecto. Se ignora cuando hay disco.
| `-d`, `--datadir=PATHNAME` | Carpeta para todo lo que escribe Singe: índices de vídeo, `trace.txt`, capturas de pantalla, partidas guardadas, el `menu.dat` del menú. Dentro se crea una subcarpeta con el nombre de la carpeta del juego (para un juego empaquetado, una con el nombre de la base de datos y, dentro de ella, otra con el de la carpeta del script). Por defecto, `data` en la carpeta de juegos. Singe 2.x escribía en cambio junto al juego; las carpetas de juegos pueden ser de solo lectura, así que ya no se escribe nada ahí.
| `-D`, `--disc` | Reproduce un vídeo de laserdisc: el indicado con `--framefile`, o el vídeo que se encuentre junto al script. `--framefile` la implica. Sin ella, un vídeo junto al script se notifica y se ignora.
| `-E`, `--entry=N` | Ejecuta la N-ésima entrada del `games.dat` que hay dentro de un archivo `.game` (1 por defecto). Véase xref:Reference.adoc#singlefile[Juegos de un solo archivo].
| `-v`, `--framefile=FILENAME` | Archivo de vídeo o framefile que usar en lugar del que se encuentre junto al script.
| `-G`, `--gamedir=PATHNAME` | La carpeta que contiene los juegos, los archivos `.game` empaquetados y la carpeta de soporte `Singe`, cuando el ejecutable está en otro sitio. Pasa a ser la carpeta de trabajo, así que el nombre del juego, un `--datadir` relativo y los nombres del empaquetador cuentan todos a partir de ella; las rutas absolutas funcionan tal cual. Por defecto, la carpeta actual.
| `-c`, `--showcalculated` | Muestra los rangos de fotogramas de cada segmento de un framefile, para depurar.
|===
[#_display]
==== Pantalla
La ventana y cómo la llena la imagen.
[cols="1,2",options="header"]
|===
| Opción | Función
| `-a`, `--aspect=N:D` | Fuerza la relación de aspecto que se usa para elegir el tamaño de la ventana (`4:3`, `16:9`, `16:10`).
| `-f`, `--fullscreen` | Pantalla completa exclusiva a la resolución del escritorio.
| `-w`, `--fullscreen_window` | Ventana sin bordes que cubre el escritorio.
| `--linearscale=BOOLEAN` | Suaviza el overlay cuando la ventana lo escala (`true`) o toma el píxel más cercano (`false`, que mantiene nítido el pixel art). Acepta `true`, `false`, `yes`, `no`, `on`, `off`, `1` o `0`. Un script lo cambia en marcha con `setOverlayLinearScale`. Por defecto: `true`, que es como han dibujado todas las versiones de Singe; el valor por defecto del propio Hypseus es el contrario.
| `-k`, `--nologos` | Omite las pantallas de presentación.
| `-r`, `--rotate=DEGREES` | Gira toda la presentación `0`, `90`, `180` o `270` grados en el sentido de las agujas del reloj, para una recreativa cuyo monitor está montado de lado. El vídeo, el overlay, las GUI, la escena 3D y las partículas giran juntos, un cuarto de vuelta intercambia la forma de la imagen para que se llene una ventana vertical, y las posiciones del ratón y de la pistola de luz se giran de vuelta para que un clic siga cayendo donde se dibuja. Solo se aceptan los cuatro ángulos rectos. Un script puede cambiarlo con `vldpSetRotate`.
| `--screen=N` | Abre la ventana en la pantalla `N`, contando desde `1` como las cuenta Hypseus. Un número mayor que el número de pantallas muestra las pantallas que hay y sale. Por defecto: la pantalla principal.
| `-u`, `--stretch` | Estira el vídeo para llenar la ventana en lugar de mantener su relación de aspecto.
| `-x`, `--xresolution=VALUE` | Anchura de la ventana. Si se omite la altura, se toma de la entrada correspondiente de la tabla de resoluciones incorporada. Un tamaño mayor que la pantalla -- pedido aquí o por el `games.dat` de un juego -- se reduce para que quepa, manteniendo su forma, y la traza lo indica. Al ejecutarse sin pantalla, con `SDL_VIDEODRIVER=offscreen`, no hay pantalla a la que ajustarse, y la ventana conserva el tamaño pedido.
| `-y`, `--yresolution=VALUE` | Altura de la ventana.
|===
[#_picture_placement_bezels_and_guns]
==== Colocación de la imagen, bezels y pistolas
Para una recreativa: dónde se coloca la imagen, el arte que la rodea y el borde que sigue una pistola Sinden. Véase <<cabinet,Montar una recreativa>>.
[cols="1,2",options="header"]
|===
| Opción | Función
| `-B`, `--bezel=FILENAME` | Dibuja arte de recreativa alrededor de la imagen. El archivo se busca en la carpeta `bezels` de la carpeta de juegos (un juego empaquetado puede llevar el suyo) y luego en la carpeta `bezels` de la carpeta de datos; `--bezeldir` indica otra carpeta. Sirve cualquier formato que lea SDL_image, y se conserva la transparencia. Un archivo complementario a su lado dice dónde va la imagen dentro de él; si no lo hay, la imagen conserva toda la ventana y la colocan `--shiftx`, `--shifty` y `--scalefactor`. Si el arte no se encuentra, el programa termina. Véase <<bezels,Bezels>>.
| `-I`, `--bezeldir=PATHNAME` | La carpeta que contiene el arte de `--bezel`, en lugar de `bezels`. Relativa a la carpeta de juegos, o absoluta. Solo se busca en esa carpeta. Véase <<bezels,Bezels>>.
| `-F`, `--bezelflip` | Dibuja el arte del bezel delante de la imagen en lugar de detrás, que es lo que hace Hypseus con sus propios bezels; la transparencia del arte es entonces el hueco por el que se ve el juego. Sin ella, el arte queda detrás de todo y la imagen tapa su recorte. Un script elige si el overlay y las GUI quedan por encima del arte con `setOverlayOnTop`. Véase <<bezels,Bezels>>.
| `-b`, `--scalefactor=PERCENT` | Reduce la imagen alrededor de su centro al `PERCENT` (de `25` a `100`) de la ventana, para pantallas que pierden los bordes por el overscan. Las posiciones del ratón y de la pistola de luz siguen a la imagen reducida. Un script puede cambiarlo mientras el juego se ejecuta con `vldpSetScale`. Se combina con `--shiftx`, `--shifty`, `--rotate` y `--sindengun`; véase <<videorect,El rectángulo de vídeo>>.
| `-X`, `--shiftx=PERCENT` | Mueve la imagen en horizontal dentro del espacio que le dejó `--scalefactor`, de `-100` (pegada a la izquierda) a `100` (pegada a la derecha), `0` centrada. Como en Hypseus, el desplazamiento es un porcentaje de ese espacio y nada más, así que con `--scalefactor=100` no hay espacio y el desplazamiento no hace nada: reduce antes la escala. Véase <<videorect,El rectángulo de vídeo>>.
| `-Y`, `--shifty=PERCENT` | Mueve la imagen en vertical dentro del espacio que le dejó `--scalefactor`, de `-100` (pegada arriba) a `100` (pegada abajo), `0` centrada. No hace nada a escala completa, por el mismo motivo. Véase <<videorect,El rectángulo de vídeo>>.
| `-S`, `--sindenedge=WHERE` | Dónde se coloca el borde Sinden: `video` lo dibuja alrededor de la imagen, `window` en el borde de la pantalla. Sin la opción, decide el bezel: con arte alrededor de la imagen el borde va al borde de la ventana, porque la cámara de la pistola ve toda la pantalla, y sin arte va alrededor de la imagen, como siempre. En el borde de la ventana, los dos anillos se dibujan como anillos, lo último de todo, así que el arte que queda entre ellos y la imagen sigue visible. Véase <<bezels,Bezels>>.
| `-g`, `--sindengun='PARAMS'` | Dibuja el borde que sigue una pistola de luz Sinden y traslada las posiciones del ratón y de la pistola de luz a la imagen que queda dentro: el anillo negro, si se indica, recorre el borde del vídeo, el anillo blanco va dentro de él, y el juego se dibuja en medio. `PARAMS` es una sola lista de números entre comillas: `WW` (anchura del borde blanco en píxeles de vídeo); `WW WB` (anchura del blanco y luego un borde negro por fuera); `RW GW BW WW` (un color y una anchura de borde personalizados); `RW GW BW WW WB` (lo mismo más una anchura de negro); o `RW GW BW WW RB GB BB WB` (colores y anchuras personalizados para los dos). Un borde que no deja sitio para el juego (el doble de las anchuras del blanco y del negro juntas llega al lado más corto del vídeo), o una anchura negativa, termina el programa con un mensaje. Los anillos se dibujan alrededor de lo que dejaron `--shiftx`, `--shifty` y `--scalefactor`, así que un borde sigue siendo un borde se coloque como se coloque la imagen; véase <<videorect,El rectángulo de vídeo>>.
|===
[#_sound]
==== Sonido
[cols="1,2",options="header"]
|===
| Opción | Función
| `--altaudio=SUFFIX` | Reproduce `<base><SUFFIX>.ogg` junto al vídeo del disco en lugar del audio que lleva dentro, para una edición cuyos otros idiomas vienen en archivos aparte: `--altaudio=-es` junto a `game.m2v` reproduce `game-es.ogg`. Todos los segmentos de un framefile cambian a la vez. Si el archivo no está, sigue sonando el audio propio del juego y se muestra un aviso. La clave `AUDIO_SUFFIX` de `games.dat` hace lo mismo para un juego, y un script lo cambia en marcha con `discAudioSuffix`. Por defecto: ninguno.
| `-o`, `--audio=TRACK` | Pista de audio por defecto (empezando en cero) para vídeos que tienen varias, como las ediciones en varios idiomas.
| `-A`, `--audiodelay=MS` | Compensa un audio que se oye `MS` milisegundos más tarde de lo que el motor puede medir (negativo cuando se oye antes), de `-1000` a `1000`. Véase xref:Reference.adoc#audiosync[Sincronización del audio].
| `-s`, `--nosound` | Silencia todo el audio.
| `--soundfont=FILE` | La SoundFont (`.sf2`) con la que se sintetizan los archivos MIDI. Singe no incluye ninguna, porque una buena ocupa decenas de megabytes para un formato que casi ningún juego usa. Sin esta opción busca `Singe/soundfont.sf2` -- así un juego empaquetado puede llevar la suya -- y luego en los sitios donde una distribución instala una. La línea `SoundFont:` de la cabecera de la traza dice cuál se usó, o que no se encontró ninguna. Véase xref:Reference.adoc#midi[MIDI]. Por defecto: la búsqueda.
| `--startsilent` | Arranca en silencio y sigue así hasta la primera entrada de cualquier tipo; luego suena a los volúmenes configurados. Para una recreativa en modo de atracción en una sala tranquila. `--nosound` tiene prioridad sobre ella. Por defecto: desactivada.
| `-e`, `--volume_nonvldp=PERCENT` | Volumen de los efectos de sonido y del vídeo adicional, de `0` a `100`.
| `-l`, `--volume_vldp=PERCENT` | Volumen del laserdisc, de `0` a `100`.
|===
[#_input]
==== Entrada
Véase <<controls,Controles>>.
[cols="1,2",options="header"]
|===
| Opción | Función
| `--absolutes_only` | Conserva solo los ratones que informan de una posición absoluta, que es lo que hace una pistola de luz de verdad y no hace un ratón normal. A ManyMouse no se le puede preguntar qué es un dispositivo, así que un dispositivo cuenta como absoluto en cuanto ha informado de una posición absoluta, y no antes; véase <<mousedevices,Ratones, pistolas y quién decide>>. Hypseus la escribe `-absolutes-only`; aquí el nombre lleva un guion bajo porque una clave de un archivo de ajustes tiene que ser un nombre de Lua. Por defecto: desactivada.
| `--gamepad_reorder=DIGITS` | Qué mando físico ocupa cada hueco de mando, como posiciones de enumeración contando desde `0`, una para cada hueco por orden: `--gamepad_reorder=10` hace del segundo mando encontrado el jugador uno y del primero el jugador dos. Se escribe con los dígitos seguidos (`3210`) o separados por comas o espacios, como lo escribe Hypseus; una posición repetida se rechaza. Las posiciones no nombradas ocupan los huecos que quedan, en el orden en que las encontró SDL, y una posición sin mando detrás deja su hueco vacío. Por defecto: el orden propio de SDL.
| `--haptic=STEP` | El paso de vibración más fuerte que puede usar un juego, de `0` a `4`. `0` desactiva la vibración por completo, y un número menor suaviza un juego que pide más: `controllerDoRumble` nunca vibra más fuerte que esto. Por defecto: `4`, que es cualquier paso que pida un juego.
| `--joymouse=BOOLEAN` | Deja que el stick izquierdo del hueco de mando `0` mueva el cursor del ratón, para un juego de pistola de luz en una recreativa sin ratón. `--joymouse=false` es el `-nojoymouse` de Hypseus, y un script lo fija con `joyMouseEnable()`. Véase <<joymouse,Mover el ratón con un stick>>. Por defecto: `false`, mientras que en Hypseus está activado por defecto -- el `controls.cfg` incluido ya asigna ese stick a las cuatro direcciones.
| `--js_range=SPEED` | Lo rápido que lo mueve ese stick, de `1` a `20`, en píxeles de vídeo por fotograma con el stick a tope. Por defecto: `5`, como en Hypseus.
| `--keymapfile=FILENAME` | Lee las asignaciones de controles de este archivo en lugar de buscar `controls.cfg` en los cuatro sitios, para que un front-end sepa con certeza qué asignaciones recibió un juego. Los valores por defecto incorporados siguen aplicándose por debajo, así que un archivo parcial también funciona, y un archivo que no existe termina el programa. Por defecto: la búsqueda en los cuatro sitios, descrita en <<controls,Controles>>.
| `--manymouse` | Distingue hasta cuatro ratones pida lo que pida el juego, cosa que una recreativa de dos pistolas necesita de un juego que nunca llama él mismo a `mouseSetMode(MOUSE_MANY)`. La elección del usuario prevalece sobre la del juego: `mouseSetMode(MOUSE_SINGLE)` ya no la desactiva. Por defecto: desactivada, y decide el juego.
| `--mapjoysticks=BOOLEAN` | Escribe una asignación de mando para un dispositivo que SDL no reconoce, para que un encoder de recreativa, un spinner, un volante o un joystick de vuelo se abra como `GAMEPAD_0` a `GAMEPAD_3` igual que cualquier otro. `false` deja sin abrir ese dispositivo, como hacían las versiones anteriores. Véase <<devices,Todo dispositivo es un mando>>. Por defecto: `true`.
| `-n`, `--nocrosshair` | Pide al juego que no dibuje su propio punto de mira. Los scripts lo ven como `singeWantsCrosshairs()`.
| `--nogamepad` | Ignora todos los mandos, la contrapartida de `--nomouse`. No se abre ninguno y ningún evento de mando llega al juego, así que un encoder de recreativa atascado no puede pulsar nada. Por defecto: desactivada.
| `-m`, `--nomouse` | Desactiva por completo la entrada del ratón y de la pistola de luz.
| `--quitchord=BUTTONS` | Botones del primer mando que salen al mantenerse pulsados a la vez, asigne lo que asigne el juego e incluso cuando ha desactivado su tecla de salida: la forma de salir en una consola portátil sin teclado. Un juego sale al menú desde el que se inició, y el menú cierra Singe. De dos a cuatro nombres de botón de mando de SDL unidos con `+`, como `back+start` (Select y Start); los nombres son `a`, `b`, `x`, `y`, `back`, `guide`, `start`, `leftstick`, `rightstick`, `leftshoulder`, `rightshoulder`, `dpup`, `dpdown`, `dpleft` y `dpright`, tal como los da la asignación del mando, y `--program` escribe en la traza el nombre de cada botón pulsado. Al pulsar uno de los botones de la combinación, se espera un cuarto de segundo al resto antes de hacer lo que hace normalmente, así que Start no inicia un juego desde el menú de camino a salir. Su sitio es el `settings.cfg` de la máquina. Por defecto: ninguno.
| `--trigger_threshold=PERCENT` | Cuánto tiene que recorrer un gatillo analógico antes de contar como botón, como porcentaje del recorrido completo -- la unidad de Hypseus, cuyo propio valor por defecto es `99.5`. `0` deja los gatillos con `DEAD_ZONE`, que es lo que Singe les ha dado siempre. Gana a `TRIGGER_THRESHOLD` de `controls.cfg`; `DEAD_ZONES` gana a los dos. De `0` a `100`; véase <<deadzones,Zonas muertas y gatillos>>. Por defecto: `0`.
| `--xratio=FACTOR` | La escala horizontal que un juego de pistola de luz lee con `ratioGetX()` para estirar sus propias coordenadas de pistola en una pantalla cuya forma no coincide con la del vídeo. Singe no hace nada con ella; el juego hace las cuentas, exactamente como en Hypseus. De `0` a `100`, con dos decimales, como la guarda Hypseus. Por defecto: `0`, que todo juego que la lee trata como `1`.
| `--yratio=FACTOR` | Lo mismo para `ratioGetY()`. Por defecto: `0`.
|===
[#_video_decoding_and_performance]
==== Decodificación de vídeo y rendimiento
Sobre todo para máquinas pequeñas; véase <<handhelds,Consolas portátiles y máquinas pequeñas>>.
[cols="1,2",options="header"]
|===
| Opción | Función
| `--deinterlace=MODE` | Qué se hace con una imagen entrelazada: `auto` (el valor por defecto) desentrelaza solo los fotogramas que el archivo marca como entrelazados, `on` desentrelaza todos los fotogramas, para un archivo con las marcas mal puestas, y `off` nunca toca la imagen. Un laserdisc contenía campos entrelazados, y un rip que los conservó muestra el efecto peine en una pantalla progresiva; un rip que se desentrelazó al hacerse no necesita nada aquí. Sale una imagen por cada una que entra, así que los números de fotograma nunca se mueven. Por defecto: `auto`.
| `--monochrome` | Arranca con la imagen del disco en gris. El overlay, las GUI y la escena 3D conservan su color; un script hace lo mismo con `vldpSetMonochrome`, y lo deshace. Por defecto: desactivada.
| `--scenequality=LEVEL` | Cuánto dibuja la escena 3D: `high`, todo lo que pida un juego, o `low` para una GPU pequeña -- una consola portátil o una de las primeras Raspberry Pi -- que dibuja la escena a la mitad de resolución en cada sentido y prescinde del antialiasing y del bloom pida lo que pida el juego. La imagen 3D es más suave y lo brillante no tiene resplandor, y va mucho más rápido donde el límite era la GPU; el disco, el overlay y las GUI no se tocan. Su sitio es el `settings.cfg` de la máquina más que la línea de comandos de un juego, ya que describe la máquina. Por defecto: `high`.
| `-H`, `--softwarevideo` | Decodifica el vídeo por software aunque la plataforma ofrezca un decodificador por hardware (VA-API o VDPAU en Linux, el decodificador V4L2 en la Pi, D3D11VA en Windows, VideoToolbox en macOS). Úsala para descartar o confirmar el camino por hardware cuando un vídeo se porta mal; la traza del programa dice qué decodificador se está usando.
| `--zerocopy=BOOLEAN` | Pasa los fotogramas de vídeo decodificados por hardware directamente a la GPU en lugar de copiarlos a través de la CPU: el decodificador MPP de Rockchip y VA-API en Linux, dibujados con OpenGL ES. Ahorra la mayor parte del coste del vídeo a pantalla completa en una máquina pequeña. Singe vuelve a copiar por su cuenta cuando el controlador no acepta un fotograma, o cuando un juego lee o cambia los píxeles de la imagen, y la traza del programa dice qué está haciendo; `false` hace que copie desde el principio, para descartar o confirmar este camino. Por defecto: `true`.
|===
[#_cabinets_and_front_ends]
==== Recreativas y front-ends
[cols="1,2",options="header"]
|===
| Opción | Función
| `--apiversion` | Escribe en la salida estándar una línea legible por máquina que describe esta compilación y sale, para los front-ends. Véase <<apiversion,La línea de versión>>. No se escribe nada más.
| `--fvalue=NUMBER` | Un número que el lanzador pasa al juego, que lo lee con `getFValue()`. Singe no hace nada con él. De `0` a `100000`, con tres decimales, como lo guarda Hypseus. Por defecto: `0`.
| `-h`, `--help` | Muestra el resumen de opciones y sale.
| `--idleexit=SECONDS` | Sale tras `SECONDS` sin ninguna entrada de ningún tipo -- ninguna tecla, ningún botón, ningún eje de mando, ningún ratón. Para una recreativa en modo de atracción que debe devolver la pantalla. `0` no sale nunca. De `0` a `86400`. Por defecto: `0`.
| `--no_update_check` | No pregunta nunca al servicio si existe un Singe más reciente. Si no, el menú mira una vez al día y muestra lo que ha encontrado bajo los detalles del juego; la herramienta Engine Update sigue funcionando a mano. Por defecto: desactivada, así que la consulta diaria se hace.
| `-z`, `--noconsole` | No escribe nada (y no abre ninguna ventana de consola en Windows).
| `--refresh` | Aparta la carpeta de soporte `Singe` como `old-Singe-<version>`, con el nombre de la versión que la escribió, y escribe una nueva. Para actualizar: un archivo que traía una versión anterior y que esta no trae se queda en la carpeta apartada en lugar de seguir en la que está en uso. No se borra nada, y una segunda ejecución aparta la suya como `old-Singe-<version>-1`. La herramienta Engine Update pasa esta opción al Singe con el que se reinicia.
|===
[#_making_and_testing_games]
==== Crear y probar juegos
Véase <<troubleshooting,Cuando algo sale mal>> para las trazas.
[cols="1,2",options="header"]
|===
| Opción | Función
| `--debug[=HOST:PORT]` | Conecta el juego a un depurador que escucha en `HOST:PORT`, normalmente ZeroBrane Studio, que entonces puede detenerlo en puntos de ruptura, ejecutarlo paso a paso y mostrar qué hay en sus variables; consulta xref:Reference.adoc#zerobrane[Depurar en ZeroBrane Studio]. `HOST` es `localhost` si no se indica y `PORT` es `8172`. Si nadie escucha, el juego se juega como siempre una vez que el intento se rinde, en dos segundos como mucho. Por defecto: desactivado.
| `--deterministic[=MS]` | Solo para pruebas: ignora el tiempo real y ejecuta todo el motor con un reloj virtual que avanza `MS` milisegundos cada fotograma, así que el mismo número de fotograma siempre significa el mismo momento. El disco también sigue el reloj virtual, y sus fotogramas duran el tiempo que valen, y los generadores aleatorios se inicializan con el mismo número, así que una ejecución se repite píxel a píxel. El valor es opcional y es a la vez el paso y la semilla, de `1` a `1000`. Por defecto, si se da sin valor: `15`, el tiempo de fotograma que implica la tasa propia del motor. El ritmo no tiene sentido en este modo, y tampoco el sonido salvo que se dé también `--record`, en cuyo caso se genera al paso de la imagen; véase xref:Reference.adoc#deterministic[Modo de prueba determinista]. Por defecto: desactivada.
| `-P`, `--pack=DIRECTORY` | Empaqueta el juego de `DIRECTORY` en la base de datos que se nombra tras las opciones y sale. Véase xref:Reference.adoc#singlefile[Juegos de un solo archivo].
| `-T`, `--patch=GAME.game` | Sustituye archivos del juego empaquetado a partir de la carpeta o la base de datos de parche que se nombra tras las opciones y sale.
| `--perfsync` | Con `--program`, espera a que la GPU termine cada etapa de un fotograma antes de cronometrar la siguiente, para que las líneas perf digan a qué etapa pertenece el tiempo de la GPU en lugar de dejarlo todo en `present`. Todo va más lento mientras está activada, así que es para medir, no para jugar; véase <<perflines,Leer las líneas perf>>. Por defecto: desactivada.
| `-p`, `--program` | Escribe una traza de la actividad del motor en la consola y en `trace.txt` en la carpeta de datos. El archivo empieza con una cabecera que describe la máquina; véase xref:Reference.adoc#traceheader[La cabecera de la traza]. Cada cinco segundos dice además adónde se fue el tiempo del fotograma; véase <<perflines,Leer las líneas perf>>.
| `--record=FILENAME` | Graba toda la ejecución, imagen y sonido, en un MP4 en `FILENAME`, desde el primer fotograma hasta que Singe sale. Con `--deterministic` se conservan todos los fotogramas y el sonido se genera paso a paso junto con la imagen, así que los dos coinciden exactamente y no se oye nada mientras se ejecuta. Véase <<recording,Grabar vídeo>>. Por defecto: desactivada.
| `-R`, `--reload` | Vigila los archivos de script sueltos del juego y vuelve a ejecutar el juego desde cero cuando uno cambia; `F5` hace lo mismo cuando quieras. Un script que no compila sigue vigilado, así que al guardar el arreglo se recarga. Para trabajar en un juego; véase xref:Reference.adoc#reloading[Recargar mientras trabajas].
| `-t`, `--trace` | Escribe una traza de cada llamada a la API de Lua, con la línea del script que la hizo, en la consola y en `trace.txt`. El archivo empieza con una cabecera que describe la máquina; véase xref:Reference.adoc#traceheader[La cabecera de la traza].
| `-U`, `--unpack=GAME.game` | Escribe los archivos del juego empaquetado en la carpeta que se nombra tras las opciones y sale. Se rechaza una base de datos cuyos nombres guardados acabarían fuera de esa carpeta.
|===
Las opciones se pueden dar como `-x 640`, `-x640` o `--xresolution=640`. Los
valores numéricos se validan; un valor incorrecto muestra el texto de uso y
sale. Las opciones más nuevas no tienen letra corta; el alfabeto se acabó, y una
letra elegida al azar no ayudaría a nadie.
Todo lo de aquí, salvo las opciones que nombran el juego, nombran una carpeta o
tienen que actuar antes de que se pueda encontrar un archivo, se puede fijar
también en un archivo de ajustes, así que una recreativa no necesita un script
lanzador para cada juego. Véase <<settings,El archivo de ajustes>>.
[[apiversion]]
=== La línea de versión
`--apiversion` escribe una línea y sale con el estado `0`:
----
singe version=3.00 protocol=1
----
Esto es un contrato para los front-ends y no cambiará de forma:
* La línea termina con un salto de línea y es lo único que se escribe en la
salida estándar. No se escribe nada más, haya lo que haya en la línea de
comandos.
* El primer campo es siempre `singe`.
* Cada campo posterior es `key=value`, separados por un espacio, sin espacios
dentro de un campo.
* `version` es la versión publicada, el mismo número que muestra el rótulo.
* `protocol` es la versión del formato de esta línea. Solo pasa a ser `2` si
alguna vez tienen que cambiar las reglas anteriores.
* Las versiones posteriores pueden añadir campos. Un lector debe ignorar las
claves que no conoce en lugar de tratarlas como un error.
[[cabinet]]
== Montar una recreativa
Las máquinas recreativas necesitan algunas cosas que un ordenador de sobremesa
no: apartar la imagen de los bordes que el monitor oculta, girarla para una
pantalla puesta de lado, arte a su alrededor, un borde para una pistola de luz
Sinden y un marcador. Solo necesitas este capítulo si estás montando una
recreativa. Configura esto una vez en el `settings.cfg` de la recreativa, o usa
la herramienta Display del menú (véase
<<servicetools,Las herramientas de servicio>>) para ajustar la imagen mientras
la miras.
[[videorect]]
=== El rectángulo de vídeo
Todo lo que muestra un juego -- el disco, el overlay, las GUI, la escena 3D y
las partículas -- se dibuja en un único rectángulo, y un puñado de opciones
decide dónde está ese rectángulo. Se aplican en este orden:
. *La ventana, o el recorte del bezel.* El rectángulo empieza siendo toda la
ventana. Singe trabaja en las coordenadas propias del vídeo y deja que la
ventana las encuadre con bandas negras (`--stretch`, en cambio, la llena), así
que nada de esto depende del tamaño de la ventana. Cuando `--bezel` ha cargado
un arte que declara un recorte, el rectángulo empieza siendo ese hueco y todo
lo que sigue coloca la imagen dentro de él; véase <<bezels,Bezels>>.
. *`--scalefactor`.* El rectángulo se reduce a ese porcentaje de lo que era al
empezar, alrededor de su propio centro.
. *`--shiftx` y `--shifty`.* Luego el rectángulo se mueve dentro del espacio que
dejó la escala, `-100` pegado a un lado y `100` pegado al otro, que es lo que
significan los propios `-shiftx` y `-shifty` de Hypseus. De ahí se siguen dos
consecuencias que conviene saber: la imagen nunca se puede sacar de la
pantalla, y *con `--scalefactor=100` no hay espacio y un desplazamiento no hace
nada en absoluto*. Para mover la imagen en un monitor mal montado, reduce
antes la escala: `--scalefactor=90 --shiftx=-100` pone la imagen reducida
pegada a la izquierda.
. *`--sindengun`.* El borde se aplica el último, a lo que hayan dejado el
desplazamiento y la escala. El anillo negro ocupa el borde del rectángulo, el
anillo blanco va dentro de él y el juego va dentro de los dos, así que un
borde sigue siendo un borde se haya colocado como se haya colocado la imagen.
Una escala tan pequeña que no deje sitio para el juego aprieta los dos anillos
en lugar de tragárselo. Con arte de bezel cargado, el borde va en cambio al
borde de la ventana y deja la imagen del tamaño que ya tenía; `--sindenedge`
lo decide en cualquier caso.
`--rotate` no forma parte de ese orden. El fotograma se dibuja sin girar y la
imagen terminada se gira entera en el sentido de las agujas del reloj, así que
un desplazamiento mueve la imagen a lo largo de los ejes propios del vídeo y
gira con ella. Un cuarto de vuelta también intercambia la forma de la zona
presentada, así que una ventana vertical se llena en lugar de quedarse con la
imagen metida en una franja.
Las posiciones del ratón y de la pistola de luz recorren el mismo camino al
revés: primero se quita la rotación y después la posición se traslada al
rectángulo, así que un clic cae donde lo ve el jugador con cualquier combinación
de estas opciones. `vldpGetScale`, `vldpSetScale`, `vldpGetRotate` y
`vldpSetRotate` permiten a un script mover la escala y la rotación mientras el
juego se ejecuta; el desplazamiento es un ajuste de la pantalla y no tiene
llamada de script. Ninguno de ellos es una clave de `games.dat`: igual que
`--scalefactor`, describen la pantalla del jugador, no el juego.
[[bezels]]
=== Bezels
Un bezel (marco decorativo) es el arte que rodea la pantalla de una máquina
recreativa. Singe dibuja uno a partir de un único archivo de imagen, con la
imagen del juego en un hueco recortado en él, y puede mostrar un marcador de
recreativa en el espacio que queda. Lo controlan tres opciones, y siguen la
convención propia de Hypseus, así que la línea de comandos de una recreativa se
traslada sin cambios.
`--bezel cabinet.png` nombra el arte. Se busca en este orden:
. `bezels/cabinet.png` en la carpeta de juegos -- dentro de un `.game`
empaquetado, su propia copia, así que un juego puede llevar su bezel consigo;
. `bezels/cabinet.png` en la carpeta de datos, donde puede estar el arte propio
de un usuario sin tocar una carpeta de juegos de solo lectura.
`--bezeldir art/cabinets` sustituye la carpeta `bezels` por la que nombra,
relativa a la carpeta de juegos o absoluta, y entonces solo se busca en esa
carpeta. Sirve cualquier formato que lea SDL_image (`.png` es la elección
sensata, porque la transparencia importa). Un arte que la opción nombra y que
Singe no encuentra termina el programa en lugar de ejecutarse sin él.
El arte se dibuja sobre toda la ventana, tenga la forma que tenga cualquiera de
los dos, así que se estira con la ventana exactamente igual que la imagen. Dale
la relación de aspecto con la que esperas jugar.
[#_the_cutout]
==== El recorte
Junto al archivo de imagen, y con su mismo nombre, un archivo complementario dice
dónde va la imagen del juego: `bezels/cabinet.png` lo describe
`bezels/cabinet.cfg`. Es un archivo Lua, como `controls.cfg`, y fija una tabla
en los *propios píxeles* del arte:
[source,lua]
----
-- El hueco de cabinet.png en el que se dibuja la imagen, en los propios píxeles del arte.
CUTOUT = { x = 200, y = 120, width = 800, height = 500 }
----
Los cuatro campos son obligatorios y el rectángulo debe quedar dentro del arte;
un archivo complementario que no se puede ejecutar, o que nombra un rectángulo
fuera de la imagen, termina el programa con un mensaje. Como los números son los
del propio arte, siguen siendo correctos con cualquier tamaño de ventana: la
imagen y el hueco se escalan juntos.
Con un recorte, la imagen se dibuja en ese hueco -- estirada hasta llenarlo, así
que el hueco decide la forma de la imagen -- y `--scalefactor`, `--shiftx` y
`--shifty` funcionan entonces *dentro* de él, reduciendo y empujando la imagen
en el hueco. Sin archivo complementario, la imagen conserva toda la ventana,
exactamente igual que sin bezel, y esas tres opciones la colocan como siempre.
Véase <<videorect,El rectángulo de vídeo>>.
El propio hueco debería ser transparente en la imagen. Singe dibuja el arte
detrás de la imagen por defecto, así que un centro opaco simplemente quedaría
tapado, pero `--bezelflip` pone el arte delante y entonces solo su transparencia
deja ver el juego.
[#_draw_order]
==== Orden de dibujo
Sin `--bezelflip`, el arte es lo primero del fotograma: la imagen, el overlay,
las GUI, la escena 3D y las partículas se dibujan todas encima. Con
`--bezelflip`, el arte se dibuja en cambio delante de la imagen, que es el orden
que usa Hypseus para sus propios bezels, así que un marco con bordes suaves o
con forma se superpone bien a la imagen.
Un script decide qué pasa con el overlay en ese caso:
xref:Reference.adoc#setoverlayontop[`setOverlayOnTop(true)`] dibuja el overlay y las GUI por encima
del arte, y `false` (el valor por defecto, y el de Hypseus) deja el arte encima
de ellos. Con el arte detrás de la imagen, el ajuste no cambia nada, porque todo
está ya por encima.
xref:Reference.adoc#mainbezelloaded[`mainBezelLoaded()`] le dice a un script si hay arte cargado
y le da el identificador del arte, el mismo número del que informa Hypseus, para
que un juego escrito para un bezel concreto pueda reconocerlo.
Las GUI en espacio de pantalla y el panel de puntuación siempre se dibujan por
encima del arte, ya que su razón de ser es ir sobre él.
[#_the_sinden_border]
==== El borde Sinden
Una pistola de luz Sinden vigila la pantalla buscando un borde brillante. Con
arte de bezel cargado, ese borde va en el *borde de la ventana*, no alrededor de
la imagen, porque la cámara de la pistola ve toda la pantalla, así que ahí es
donde lo pone `--sindengun` en cuanto se carga un bezel. Ahí se dibuja como dos
anillos, después de todo lo demás, así que el arte que hay entre el borde y la
imagen sigue visible y nada pinta encima del anillo blanco. Sin bezel, el borde
va alrededor de la imagen, como siempre, y la reduce.
`--sindenedge video` o `--sindenedge window` anula esa elección en cualquiera de
los dos sentidos: una recreativa de pistola cuyo arte es solo un marco fino puede
seguir queriendo el borde alrededor de la imagen, y una recreativa sin ningún
arte puede quererlo en el borde de la pantalla.
[#_the_score_panel]
==== El panel de puntuación
Dieciséis de los juegos Singe de Hypseus pueden manejar un marcador de
recreativa: los créditos, y una puntuación y un contador de vidas para cada uno
de dos jugadores. En Singe, ese marcador es el documento RmlUi
`Singe/scoreBezel.rml`, con el estilo de `Singe/scoreBezel.rcss`, ambos escritos
junto a los demás archivos de soporte. Como todo lo que hay en la carpeta
`Singe`, se escriben de nuevo en cada arranque, así que editarlos no cambia nada
por mucho tiempo: un juego que quiere otro aspecto trae sus propias copias,
`scoreBezel.rml` junto a su script enlazando una hoja de estilo propia, y Singe
usa esas en su lugar. El estilo incluido imita un display de siete segmentos:
cada indicador muestra sus dígitos débilmente iluminados detrás del valor
actual, como hace un display de verdad.
El panel está *desactivado* hasta que un juego lo pide con
xref:Reference.adoc#scorebezelenable[`scoreBezelEnable(true)`], que es también como lo distribuye
Hypseus, así que un juego que nunca lo pide se comporta exactamente como antes y
dibuja su propio marcador con sprites. xref:Reference.adoc#scorebezelgetstate[`scoreBezelGetState()`] es la
pregunta que todo juego así hace primero.
Dónde va se decide por ti: el panel ocupa la más alta de las dos franjas que la
imagen deja encima y debajo -- el espacio que suele dejar el recorte de un bezel
-- centrado respecto a la imagen, y se coloca a lo largo de la parte inferior de
la imagen cuando ninguna de las dos franjas es lo bastante alta para contenerlo.
Se dibuja como una GUI en espacio de pantalla, así que un juego puede poner sus
propias GUI sobre el arte, junto a él, con
xref:Reference.adoc#guidrawscreen[`guiDrawScreen`].
El `scoreBezelEnable` de Hypseus admite un segundo argumento que elige entre sus
cinco implementaciones de marcador. Singe tiene una, así que el argumento se
acepta y se ignora.
[[handhelds]]
== Consolas portátiles y máquinas pequeñas
Singe funciona en la Raspberry Pi y en consolas portátiles ARM baratas como la
R36S. Allí funcionan los mismos juegos que en un ordenador de sobremesa, pero una
máquina pequeña necesita un poco de ayuda para ejecutarlos bien.
[#_what_a_small_machine_needs]
=== Lo que necesita una máquina pequeña
Los sprites, el texto, el sonido y el vídeo funcionan en todas partes. La escena
3D y el aspecto vistoso del menú necesitan un chip gráfico con Vulkan u OpenGL
ES 3.1.
* Una Raspberry Pi 4 o posterior tiene las dos cosas, así que todo funciona. Una
Pi 3 solo tiene OpenGL ES 2.0, que no basta para el 3D. Aun así, ejecuta los
juegos 2D.
* La mayoría de las consolas portátiles, incluida la R36S, tienen un chip
gráfico Mali con OpenGL ES 3.1, así que el 3D también funciona en ellas.
* En una máquina sin ninguno de los dos, el menú usa un aspecto más sencillo que
no los necesita.
La primera vez que ejecutas un juego 3D, Singe compila sus shaders, lo que puede
tardar unos segundos en una máquina pequeña. Se guardan en la carpeta `Singe`
dentro de la carpeta de datos, así que esto solo pasa una vez.
[#_settings_for_a_small_machine]
=== Ajustes para una máquina pequeña
Pon esto en el `settings.cfg` que está junto al binario de Singe para que todos
los juegos lo usen:
`scenequality = "low"`::
Dibuja la escena 3D a la mitad de tamaño, sin antialiasing ni bloom. El 3D se ve
un poco más suave, pero va mucho más rápido. El vídeo, los sprites y los menús
no se ven afectados.
`zerocopy = true`::
Ya es el valor por defecto. El vídeo va del decodificador por hardware
directamente al chip gráfico sin que la CPU lo copie. Esto es lo que permite a
una consola portátil reproducir vídeo de laserdisc a toda velocidad. Desactívalo
solo si un vídeo se porta mal y quieres descartarlo.
`quitchord = "back+start"`::
Las consolas portátiles no tienen tecla Esc. Mantener pulsados Select y Start
te saca del juego al menú, y del menú a tu sistema, esté como esté configurado
el juego.
[#_the_r36s_and_arkos]
=== La R36S y ArkOS
La R36S y las consolas portátiles parecidas con ArkOS usan la compilación
`aarch64` de Linux de Singe. Pon el binario de Singe, su carpeta `Singe`,
`Menu.sh` y tus juegos en una misma carpeta, como `/roms/singe`. Ejecuta
`Menu.sh` una vez para que Singe pueda crear sus archivos de soporte.
Para iniciar Singe desde el menú Ports, añade a `/roms/ports` un script como el
de abajo. Estas consolas portátiles tardan en subir la velocidad de su
procesador y de su chip gráfico, así que el script los pone a toda velocidad
mientras Singe se ejecuta y los deja como estaban cuando sale.
[source,bash]
----
#!/bin/bash
# /roms/ports/Singe.sh: Singe en el menú Ports.
SINGE_DIR=/roms/singe
[ "$(id -u)" -eq 0 ] && ESUDO="" || ESUDO="sudo"
GOVERNORS=()
for g in /sys/devices/system/cpu/cpufreq/policy*/scaling_governor /sys/class/devfreq/*/governor; do
[ -f "$g" ] || continue
GOVERNORS+=("$g:$(cat "$g")")
echo performance | $ESUDO tee "$g" > /dev/null 2>&1
done
restore() {
for entry in "${GOVERNORS[@]}"; do
echo "${entry##*:}" | $ESUDO tee "${entry%:*}" > /dev/null 2>&1
done
}
trap restore EXIT
cd "$SINGE_DIR" || exit 1
./Menu.sh "$@"
----
ArkOS no informa a los juegos de los botones Select y Start, así que la
combinación de salida no funcionará hasta que añadas este `gamecontrollerdb.txt`
junto al binario de Singe (véase <<gamecontrollerdb,gamecontrollerdb.txt>>):
----
1900bb3e4b4800000011000000010000,GO-Super Gamepad,a:b0,b:b1,x:b2,y:b3,back:b12,start:b13,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpdown:b9,dpleft:b10,dpright:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,
----
Si un botón no hace lo que esperas, ejecuta Singe una vez con `--program` y
púlsalo. La traza muestra el nombre de cada botón que pulsas, o su número si la
asignación de arriba no lo incluye.
Por último, añade un `controls.cfg` junto al binario de Singe. Este pone la
moneda y Start en Select y Start, y mantiene los menús de prueba y de servicio
de un juego fuera de los botones frontales, donde algunos juegos los ponen.
[source,lua]
----
INPUT_1P_COIN = { SCANCODE.MAIN_5, SCANCODE.C, GAMEPAD_0.BUTTON_BACK }
INPUT_1P_START = { SCANCODE.MAIN_1, GAMEPAD_0.BUTTON_START }
INPUT_PAUSE = { SCANCODE.P }
INPUT_SCREENSHOT = { SCANCODE.F12, SCANCODE.F11 }
INPUT_SERVICE = { SCANCODE.MAIN_9 }
INPUT_TEST_MODE = { SCANCODE.F2 }
----
Este archivo gana al que incluye un juego (véase
<<configorder,Dónde se leen los archivos de configuración>>). La pausa y la
captura de pantalla pasan al teclado porque Singe normalmente las pone en Start
y Select.
[[troubleshooting]]
== Cuando algo sale mal
[#_the_trace]
=== La traza
Ejecuta Singe con `--program` (o `-p`) para ver lo que está haciendo. Todo se
escribe en la consola y se guarda en `trace.txt` en la carpeta de datos del
juego. Si informas de un problema, incluye el `trace.txt` de una ejecución con
`--program`. `--trace` (o `-t`) registra además cada llamada a Lua que hace un
juego, lo que sobre todo es útil al escribir un juego.
Si Singe se cuelga en Linux o macOS, escribe dónde se colgó en la consola y en
`trace.txt`.
`trace.txt` solo tiene los mensajes propios de Singe. Los mensajes del sistema de
sonido, del decodificador de vídeo y del controlador gráfico solo van a la
consola. Cuando el problema pueda estar ahí, guarda también la consola. En
Linux:
----
./Menu.sh --program &> singe.log
----
[[perflines]]
=== Leer las líneas perf
Con `--program`, cada cinco segundos la traza dice adónde se fue el tiempo, como
promedios por vuelta del bucle de fotogramas:
----
Perf: 58.9 frames/s shown, 353 loops; per loop 13.1 ms (worst 82.3): disc 1.1, script 0.1, scene 0.0, gui 0.4, overlay 0.0, compose 0.0, present 11.4, other 0.1
Perf script: per loop 0.1 ms of Lua and 0.0 in engine calls it made; 0.0 in engine calls altogether: overlayClear 0.01 (0.8 calls), discGetFrame 0.00 (0.8 calls)
Video 3 perf: 23.8 frames/s decoded; per frame 0.5 ms, of which read back 0.0, convert 0.0
----
* `disc` -- avanzar el vídeo del laserdisc y poner su fotograma en la GPU.
* `script` -- el `onOverlayUpdate` del juego, que la línea `Perf script` divide
entre el propio Lua y las llamadas al motor que hizo, de la más costosa a la
menos.
* `scene` -- dibujar la escena 3D.
* `gui` -- maquetar y dibujar los documentos de la GUI.
* `overlay` -- enviar a la GPU lo que cambió en el overlay.
* `compose` -- solo con `--perfsync`: la GPU dibujando juntos la imagen, el
overlay y las GUI.
* `present` -- mostrar el fotograma, lo que incluye esperar al siguiente
refresco de la pantalla.
* `other` -- todo lo demás: entrada, sonido, física y el resto.
La línea propia de un vídeo dice lo rápido que se decodifica y cuánto de cada
fotograma se fue en copiarlo de vuelta desde el decodificador por hardware y en
convertir sus colores; cero en ambos significa que sus fotogramas van a la GPU
sin copiarse.
La GPU trabaja por detrás de la CPU, así que sin `--perfsync` su tiempo cae allí
donde la CPU tenga que esperarla a continuación, que suele ser `present`. Un
`present` grande a la tasa completa de la pantalla es solo la espera del
refresco; un `present` grande por debajo de ella significa que la GPU está
ocupada. `--perfsync` hace que cada etapa espere a la GPU antes de que empiece
la siguiente, así que `scene`, `gui`, `overlay` y `compose` incluyen su tiempo de
GPU y a `present` le queda la espera del refresco. La tasa de fotogramas baja
mientras está activada, porque la CPU y la GPU ya no trabajan a la vez; compara
las etapas entre sí, no con la tasa de fotogramas.
[#_a_button_does_nothing]
=== Un botón no hace nada
Abre la herramienta Input Test del menú (véase <<servicetools,Las herramientas de servicio>>)
y pulsa el botón. Si la herramienta lo ve, el juego lo está ignorando, así que
revisa el `controls.cfg` del juego. Si la herramienta no lo ve, revisa tu propio
`controls.cfg`, o la asignación de tu mando en `gamecontrollerdb.txt`.
Ejecutar con `--program` muestra cada botón según lo pulsas.
[#_sound_and_picture_are_out_of_sync]
=== El sonido y la imagen no van sincronizados
Algunos televisores, receptores y altavoces inalámbricos retrasan el sonido. Usa
la herramienta Audio Delay del menú para medir el retardo. Singe lo recuerda para
todos los juegos. Véase xref:Reference.adoc#audiosync[Sincronización del audio]
para más detalles.
Si el sonido se entrecorta o va a trompicones, consulta las preguntas frecuentes.
[#_frequently_asked_questions]
== Preguntas frecuentes
*¿Por qué se llama Singe?*
Singe es el nombre del dragón de Dragon's Lair. Como Singe (el programa) empezó
como complemento de Daphne (la princesa de Dragon's Lair), se mantuvo el tema de
Dragon's Lair.
*¿Qué diferencia hay entre Daphne, Singe, Hypseus y Singe 3.xx?*
Daphne es un auténtico emulador de juegos de laserdisc que puede ejecutar un
puñado de juegos de láser clásicos. Daphne/Singe (Singe 1.xx) es la versión
original de Singe, que era un complemento del emulador Daphne -- distribuido al
principio como una DLL de juego para Daphne, y combinado más tarde en un solo
binario sin las funciones de emulación de Daphne. Hypseus-Singe es un fork
mejorado de Daphne con compatibilidad con Singe 1.xx y parte de Singe 2.xx.
Singe 2.xx es una actualización totalmente nueva, hecha desde cero, del Singe
original, y Singe 3.xx se basa en ella y añade 3D, física y mucho más. En
resumen, si quieres fidelidad, usa Daphne o Hypseus si pueden emular el juego
que quieres. Si es un juego de Singe, usa Singe, o prueba Hypseus.
*¿Por qué no deberíamos llamarlo «emulador»?*
Los emuladores usan el software real o las ROM del juego original y se hacen
pasar por la máquina en la que ese juego debía ejecutarse. Desde el punto de
vista del juego, todo sigue como siempre. Singe, en cambio, exige que cada juego
se reimplemente (se adapte) para funcionar en Singe. El resultado final puede
ser muy parecido, pero cómo funciona es totalmente distinto.
*¿Puedo ejecutar juegos de Singe 1.xx y 2.xx en Singe 3.xx?*
Sí, probablemente. Casi todo lo de Singe 1.xx se ha convertido y mejorado para
las versiones más nuevas de Singe, y la mayoría de los juegos de Singe 2.xx
funcionan tal cual. Los juegos que usan las funciones de sprites antiguas pueden
necesitar un pequeño cambio; véase
xref:Reference.adoc#migrating[Migración desde Singe 2.10].
*¿Necesito un juego de laserdisc para usar Singe?*
No. Los juegos no necesitan ningún disco. Pueden usar sprites, vídeo, 3D y
cualquier otra cosa que ofrezca Singe. Véase
xref:Reference.adoc#withoutadisc[Juegos sin disco].
*¿Por qué no aparece en el menú el juego que acabo de instalar?*
Quien empaquetó el juego no incluyó un archivo `games.dat` como es debido.
*¿Por qué va lento el vídeo HD?*
Ya no debería. Singe usa ahora tu tarjeta gráfica para decodificar el vídeo
cuando tu sistema lo permite, incluso en la Raspberry Pi y en muchas consolas
portátiles. Si el vídeo HD sigue yendo lento, puede que tu sistema no tenga
decodificación de vídeo por hardware, y entonces el vídeo de alta definición
necesita mucha CPU. Ejecutar con `--program` muestra qué decodificador está
usando Singe.
*¿Por qué se entrecorta el audio en Windows?*
Los usuarios han descubierto que la mayoría de los problemas de audio y de
tirones de Singe tienen que ver con el controlador de audio instalado -- sobre
todo en dispositivos basados en Realtek. Prueba a actualizar los controladores de
sonido o a cambiar al controlador genérico Windows HD Audio. Desactiva el sonido
envolvente -- usa estéreo, no 5.1 ni 7.1. Si tus controladores no te dejan usar
estéreo, puedes usar Virtual Audio Cable para arreglarlo:
. Instala VB-CABLE (https://vb-audio.com/Cable/).
. Ve a la configuración de sonido de Windows (haz clic con el botón derecho en el
icono de sonido de la barra de tareas, luego en *Sonidos* y luego en
*Reproducción*).
. Haz clic con el botón derecho en el dispositivo *Cable Input* y elige
*Establecer como dispositivo predeterminado*. (Perderás temporalmente la salida
de sonido actual.)
. Ve a la pestaña *Grabación*.
. Haz clic con el botón derecho en *Cable Output*, luego en *Propiedades*, luego
en *Escuchar* y, por último, activa *Escuchar este dispositivo*. En la lista
desplegable, elige el dispositivo con el que escuchas de verdad.
. Deberías volver a tener sonido. Abre Singe y el audio funcionará, y sin
retrasos.
*¿Funciona el 3D en una Raspberry Pi o en una consola portátil?*
En una Raspberry Pi 4 o posterior, sí. Tienen tanto un controlador Vulkan como
OpenGL ES 3.1, y Singe usa el que encuentre. La Pi 3 solo tiene OpenGL ES 2.0,
que no puede expresar el skinning ni los morph targets de la escena, así que
ejecuta los juegos 2D (física 2D incluida) exactamente como antes y rechaza la
primera llamada 3D. La Pi 4 es el mínimo para cualquier juego que use el
capítulo de escenas 3D. Lo mismo vale para las consolas portátiles baratas: una
Mali-G31 o G610 tiene el ES 3.1 que necesita la escena, tenga o no Vulkan. Véase
<<handhelds,Consolas portátiles y máquinas pequeñas>>.
*¿Por qué se entrecorta el audio en la Raspberry Pi?*
Raspberry Pi OS usa ahora Pipewire como backend de audio por defecto. Cambiar a
PulseAudio parece arreglar el problema:
. Ejecuta `sudo raspi-config` desde una ventana de terminal.
. Selecciona *Advanced Options*.
. Selecciona *Audio Config*.
. Selecciona *PulseAudio*.
. Pulsa kbd:[Tab], selecciona *Ok* y deja que se reinicie.
[#_making_games]
== Crear juegos
Este manual trata de ejecutar Singe: instalarlo, instalar juegos, montar una
recreativa y el menú. Crear juegos se trata en otros dos libros, que son una
descarga opcional desde el mismo sitio que Singe en lugar de formar parte de él,
ya que juntos ocupan más que el motor.
* La *Referencia de Singe* trata todo lo que puede hacer un juego: el modelo de
programación, la carpeta del juego, empaquetar un juego en un solo archivo y
cada función que ofrece el motor, con sus argumentos, sus valores de retorno y
un ejemplo.
* *Aprende a programar con Singe* enseña a programar desde cero, en treinta y
una lecciones, a alguien que nunca ha escrito código. Viene con los scripts y
el pequeño kit de arte que usan las lecciones.
La descarga contiene los dos libros en PDF y HTML, los archivos de las lecciones
y la licencia. Los tres libros están escritos en inglés, francés, italiano,
alemán y español, y la descarga viene en cada uno de ellos: elige la de tu
idioma. Las traducciones de este manual ya están en la carpeta `Singe`, a su
lado. Forge, la herramienta de autoría que crea un juego a partir de una
descripción en lugar de a partir de código, es un proyecto aparte con su propia
descarga y su propio libro.