[0.2.2]
Added
Cauldron2D.Drafter.Client.Picture: how a game's picture reaches a terminal that keeps images (native,native:N,size:WxH,png,swap,none), read from the client's:picturemount prop, the application envconfig :cauldron_2d_drafter, picture:, theCAULDRON_PICTUREenvironment variable or the game's look, withparse/1for a mix task's--picture. Defaultnative:2,swap.- A look's
:nativeand:picturekeys: a picture's own size, and the game's default picture options. - The client's
:mutemount prop,config :cauldron_2d_drafter, mute: trueandCAULDRON_MUTE=1: no sound, whatever sink the game or session would have had.
Breaking changes
- A scene's
:native_scale,:picture_formatand:swapkeys are no longer read; the client's picture options decide them. A scene's:nativestill declares the picture's own size.
[0.2.0]
Breaking changes
- The
:startmount prop names a flow, not a first screen.:lobbynow opens on the title, then the lobby; pass{:lobby, title: false}for the lobby first (whatstart: :lobbydid before, and what an embedding game passes).:titleis read as:lobby. - A game embedding the client under its own
Drafter.Appmust addcontroller: trueandmouse_hover: trueto itsuse Drafter.Appline. - The client binds keys of its own by default:
vcycles the projection,[/]turn,'/;tilt or pitch, and the controller'sStartand bumpers. A game using any of them for its own actions rebinds or drops them throughclient_keys/0andclient_pad/0. arenas/1inCauldron2D.Drafter.Clientis nowworlds/1, calling the game'sworlds/1.next_arena/1inCauldron2D.Drafter.Clientis nownext_world/1, reading:next_worldand:same_worldfrom the outcome.- The screen a world is played on is
:play(was:arena), and the geometry event is:play_geometry(was:arena_geometry). The client's state holds the joined world as:joined(was:arena) and the summary's as:summary_world(was:summary_arena). Chat inside a world arrives as{:chat, {:world, id}, message}. arena/1inCauldron2D.Drafter.Client.Screensis nowplay/1, andarena_at/3is nowworld_at/3.
Added
- Three options for a surface's
:pictureon a kitty terminal, each independent and off by default::native{width, height}asks the picture at its own size times a whole number (:native_scale,:fitor a number) for the terminal to scale to the pane;picture_format: :pngsends it as a PNG;swap: truereplaces it without a blank pane between frames. A game's scene gives them by the same names. Cauldron2D.Drafter.Server.start/1takesport: 0for any free port, and returns the port it serves on as:port.- A world can ask the client to open the game's menu with an argument (
{:menu, arg}), which a game answers withopen_menu/2; one without it getsopen_menu/1. - Game controllers are tracked by name (
Cauldron2D.Drafter.Client.Controllers): each plays a player of the client — the player itself, then its seats — by the settings'pads(a controller's name to a player number or:none), else the lowest free one in the order they connected; a controller with no player is ignored during play. A disconnect frees its player. The settings'controllerslist the connected ones for the game's menus, and any controller works the game's menu while it is open. - A game's
ask/1can ask{:enter, props}: the client leaves its world, mergespropsinto its mount props and joins the first worldworlds/1then lists. When that world goes down, the client takes its earlier props back and joins the first of their worlds again. local_seats/1is given the client's props with:settings, and the seats take new keymaps when the game's menu changes the settings.- The client acts on the game's
ask/1::menuopens the game's menu as themenukey does,:quitends the client. - A local seat joins with the prop
:seat_of, the player's own username. - Local seats: a game's
local_seats/1keymaps each play a further player in the same world from the same terminal, joined as"<username> 2"and on without frames; keys reach every seat and count where they are mapped, and controllers go to the seats, the player's own first, in the order they first report (Cauldron2D.Drafter.Client.Seats). - The client starts its audio with the game's
audio/0settings (:voices,:earshot). - The terminal client opens a game's own menu on its
menukey (unbound until the game binds it): the player's held actions are let go, a world of their own is paused, and keys, mouse buttons, the wheel and the controller's d-pad,A,BandStartgo to the game'smenu_event/3; settings it changes are saved and take effect at once, and the scene is drawn again ten times a second for the menu's animations (:menu_frameon the look). Settings keep the game's own:options, which reachscene/2on the look and the world with every input, with the menu's requests. - A game that binds the wheel gets it during play instead of the zoom, and a right stick the game's padmap binds holds the game's actions instead of nudging the aim. A notch of the wheel can be bound in the settings.
- Saved settings naming a preset the game no longer has start from the game's first preset, and the saved bindings go with the old preset.
Cauldron2D.Drafter.Surfacetakes:picture—fn {width, height}, aspect -> raster end— and draws the game's own picture through the same pixel protocols and block glyphs as the atlas projections. The client passes a scene's:picturethrough.- Five projections on
Cauldron2D.Drafter.Surfacethrough:projection—:top,:oblique,:iso,:mode7,:first_person— with:facing,:facings(a number, or a map per projection),:tilt,:heading,:pitch,:eyeand:density(a number, or a map per projection).Surface.projections/0. Surface:modetakes the block-character glyph sets:half,:quad,:sextantand:octantbeside:braille; every projection draws in them, and the plain glyph mode draws the isometric and oblique views.Surfaceoptions:volumesand:layers(Cauldron2D.Parallaxlayers, top-down); movers may be{art, {x, y}, heading}and are posed by their heading.Surface.world_at/3andcell_at/3map between a pane cell and a world point in every projection and drawing mode;picture/2,drawn_mode/1,fitted/1,fitting_zoom/2,image_active?/1, andzoom_levels/3for a projection.- The isometric and oblique panes are stored once and shown through a moving source
rectangle on a terminal with kitty placements; what moves is sent as patches
(
Cauldron2D.Drafter.Surface.Patch.plan/4). Cauldron2D.Drafter.Clientflows:enter/3,to_lobby/1,to_title/1,to_guide/1andhome/1for a game's ownstart/0function.- Controllers:
{:controller, event}goes through the game'spadmap/1into the input sent to the world. The right stick nudges the aim or looks around, the triggers tilt or pitch, the d-pad andAchoose and join in the lobby. A stick bound to:aimaims eight tiles from the focus and follows the focus while held. - View keys and look:
client_keys/0gainsprojection,turn_left,turn_right,tilt_up,tilt_down, and the unbounddisplay,glyphsandmouse_look; the game'slook/0sets the view a world opens in andscene/2is called when defined. A note under the world names the projection, its facing, tilt or heading and pitch, and how it is drawn. - A drag turns and pitches the first-person and mode 7 eye, and turns an isometric view
of more than four facings; a click still reaches the game.
turns_with_pointer?/1. Cauldron2D.Drafter.Client.steered/2: direction actions turned with the isometric or oblique facing; in first person and mode 7 the input carries the eye's:heading.Cauldron2D.Drafter.Client.scene/1,look/1andeye_height/2; a scene's:eye, a height in tiles or an art, sets how high the first-person camera sits.Cauldron2D.Drafter.Client.Settingsdisplay choices:half,:quad,:sextantand:octant;frame_rate/3takes whether the terminal places images.
Changed
gamepadis a dependency, so the client's game controllers work in every game without the game listing it; a game that listed it only for the client can drop it.- The client asks its world for frames at the rate it draws (20 a second over ssh, 30 locally, or the frame rate chosen in settings) instead of every tick, so the world builds and sends no views that would not be drawn.
Cauldron2D.Drafter.Server.stop/2takes a notice shown to each player it disconnects, whose terminal is restored. It returns once the port is closed, and disconnects the players and stops the accounts afterwards from a process of its own, so it can be called from a world those players' games call as they leave.- A session served over ssh draws at 20 frames a second when its frame rate is
:auto; local sessions keep 30. Cauldron2D.Drafter.Servergives each connection a 64 KiB send buffer (:send_buffer), so a session drawing faster than its connection carries skips frames instead of falling seconds behind, and players 10 minutes to log in (:login_timeout), ssh's host key question included, where they had two.- A client whose name is already playing in a world joins it as
"<name> (2)", up to"<name> (9)", instead of taking the other's player. Cauldron2D.Drafter.Surface.world_at/3on a:picturesurface gives the point of the picture under the pointer as fractions of its width and height, and games playing a picture receive it as their input'saim. A scene with a:frame(the shape its screen is shown at) gets the point of that frame asCauldron2D.Fit.letterbox/3places it, andnilon the bars around it. With the terminal reporting the pointer in pixels (drafter'spixel_mouse), a picture game's pointer is that pixel, not its cell.:autoframe rate is 12 on inline images (iTerm2's own, sixel), 20 on kitty without placements, 30 otherwise (was 15 and 30).Surface.protocol/1takes a forced mode, thenCauldron2D.Renderer.resolved/1, thenDrafter.Widget.Chart.Pixel.terminal/0. Whether a terminal places stored images isFrenchCurve.Capability.placements?/1of the session's environment, which is false for every iTerm2.- The client is
mouse_hover: true, so a pointer aim previews without a click. - Zoom levels follow the projection; zooming the isometric view out draws its world smaller in the same picture.
Fixed
- A session served over ssh plays its sound to its account's tunnel port
(
TuningFork.Sink.Tcpto127.0.0.1:<pulse_port>), or nowhere without one. - A player whose world stops — it crashed, or was stopped — is taken to the lobby and told "<world> stopped".