# 11. Characters

**A character is the reusable template. An actor is the instance.**

Everything that is the same for every goblin on the map — top speed, acceleration,
how long an animation frame is held, and which sprite to draw for which combination
of state bits — lives in one `akgl_Character` and is shared by pointer. A hundred
goblins cost one character. Everything that is unique to a particular goblin — where
it is, which way it is going, which frame it is on — lives in its `akgl_Actor`. See
[Chapter 12](12-actors.md).

Characters are pool objects (`akgl_heap_next_character`, 256 slots) published in
`AKGL_REGISTRY_CHARACTER` under their name, which is how `akgl_actor_set_character`
finds them. `akgl_registry_init` has to have run first.

```text
    akgl_Character "hero"                       akgl_Actor "player"
    +--------------------------------+          +---------------------+
    | sx, sy, sz    top speeds       |<---------| basechar            |
    | ax, ay, az    accelerations    |  borrowed| x, y, z             |
    | speedtime     frame dwell (ns) |          | state  (bitmask)    |
    | state_sprites -----------------+---+      | curSpriteFrameId    |
    +--------------------------------+   |      +---------------------+
                                         |
             SDL_PropertiesID keyed by the DECIMAL state bitmask
             "18"  -> akgl_Sprite *hero standing left
             "146" -> akgl_Sprite *hero walking left
```

## The state-to-sprite map is an exact-match lookup

`state_sprites` is an `SDL_PropertiesID`. The key is **the decimal spelling of the
whole state value** — `SDL_itoa(state, buf, 10)` — and the value is an
`akgl_Sprite *`.

Two things follow, and both of them shape how you build a character:

**1. The key is the entire state word, not a set of bits to match against.** A
sprite added for `FACE_LEFT | MOVING_LEFT` is *not* found by a lookup for
`FACE_LEFT`. There is no subset fallback, no wildcard, no priority order, and no
default sprite. **You need a mapping for every state combination the character can
actually be in.**

**2. A missing mapping is an error, not a quiet miss.** `akgl_character_sprite_get`
raises `AKERR_KEY` — this is the one lookup in the library that treats absence as a
failure rather than as a successful answer of "nothing here", on the grounds that an
actor with no sprite for its current state cannot be drawn. `*dest` is set to `NULL`
alongside the error.

```c
#include <akgl/actor.h>
#include <akgl/character.h>

/*
 * sprite_get treats "no mapping" as AKERR_KEY. Handle the status; do not test
 * the return value for NULL and hope.
 */
akerr_ErrorContext *sprite_or_none(akgl_Character *basechar, int state, akgl_Sprite **dest)
{
    PREPARE_ERROR(errctx);

    FAIL_ZERO_RETURN(errctx, basechar, AKERR_NULLPOINTER, "basechar");
    FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "dest");
    *dest = NULL;

    ATTEMPT {
	CATCH(errctx, basechar->sprite_get(basechar, state, dest));
    } CLEANUP {
    } PROCESS(errctx) {
    } HANDLE(errctx, AKERR_KEY) {
	/* No sprite for this exact combination. *dest is already NULL. */
    } FINISH(errctx, true);
    SUCCEED_RETURN(errctx);
}
```

`akgl_actor_update` and `akgl_actor_render` both swallow that `AKERR_KEY` themselves
— states change faster than art gets drawn, and a missing sprite should not stop the
frame — so an under-mapped character shows up as an actor that silently does not
draw. That is the symptom to recognize.

### The combinations you will actually need

Four facings, moving and standing, alive: eight mappings for the simplest walking
character. Written out, with the decimal key each one lands on:

| Combination | Decimal key | What it draws |
|---|---|---|
| `ALIVE` | 16 | standing still, **no facing** — see below |
| `ALIVE\|FACE_DOWN` | 17 | standing, facing the camera |
| `ALIVE\|FACE_LEFT` | 18 | standing, facing left |
| `ALIVE\|FACE_RIGHT` | 20 | standing, facing right |
| `ALIVE\|FACE_UP` | 24 | standing, facing away |
| `ALIVE\|FACE_DOWN\|MOVING_DOWN` | 1041 | walking towards the camera |
| `ALIVE\|FACE_LEFT\|MOVING_LEFT` | 146 | walking left |
| `ALIVE\|FACE_RIGHT\|MOVING_RIGHT` | 276 | walking right |
| `ALIVE\|FACE_UP\|MOVING_UP` | 536 | walking away |

**Do not skip the first row.** The default `facefunc`
(`akgl_actor_automatic_face`) clears every facing bit and then sets one only if a
movement bit is set — so an actor that stops moving is left with *no* facing bit at
all, and its state drops to bare `ALIVE`. Without a mapping for 16 it vanishes the
moment it stops. This is a known rough edge; the implementation carries a `TODO`
saying as much, and [Chapter 12](12-actors.md) covers the workaround.

The decimals are shown to make the mechanism concrete. **Write the constants**, or
the state-name strings in JSON — never the numbers.

## Adding a mapping

`akgl_character_sprite_add` takes a reference on the sprite, so the character keeps
it alive. The reference is taken *before* the property write, so a failed write
cannot leave the sprite bound with no reference behind it.

Rebinding a state that is already mapped releases the sprite it displaced. **The
header says otherwise** — `character.h`'s `@note` on `akgl_character_sprite_add`
claims the displaced sprite's reference "is never given back". That was true and is
not; `src/character.c` reads the old binding out first and releases it, with a
comment explaining that without it a character rebinding a state while alive leaks
one sprite slot per rebind.

> **A defect the release path does have.** The release is guarded by
> `(displaced != NULL) && (displaced != ref)`. Re-adding the *same* sprite for the
> *same* state therefore increments its reference count and releases nothing — one
> leaked reference per redundant call. It is idempotent-looking and is not.
> Harmless in a loader that runs once; not harmless in a loop.

State `0` is accepted and is a usable key.

## Building a character in code

```c
#include <akgl/actor.h>
#include <akgl/character.h>
#include <akgl/game.h>
#include <akgl/heap.h>

akerr_ErrorContext *build_hero(akgl_Sprite *idle_left, akgl_Sprite *walk_left)
{
    akgl_Character *hero = NULL;
    PREPARE_ERROR(errctx);

    FAIL_ZERO_RETURN(errctx, idle_left, AKERR_NULLPOINTER, "idle_left");
    FAIL_ZERO_RETURN(errctx, walk_left, AKERR_NULLPOINTER, "walk_left");

    ATTEMPT {
	CATCH(errctx, akgl_heap_next_character(&hero));
	/* Zeroes the struct, creates the map, binds the two hooks, registers. */
	CATCH(errctx, akgl_character_initialize(hero, "hero"));

	/* Everything numeric is left at zero for us. */
	hero->speedtime = 100 * AKGL_TIME_ONEMS_NS;  /* 100 ms, in nanoseconds */
	hero->sx = 0.20f;
	hero->sy = 0.20f;
	hero->ax = 0.20f;
	hero->ay = 0.20f;

	/* One mapping per exact combination we intend to draw. */
	CATCH(errctx,
	      hero->sprite_add(
		  hero,
		  idle_left,
		  AKGL_ACTOR_STATE_ALIVE | AKGL_ACTOR_STATE_FACE_LEFT)
	    );
	CATCH(errctx,
	      hero->sprite_add(
		  hero,
		  walk_left,
		  AKGL_ACTOR_STATE_ALIVE
		  | AKGL_ACTOR_STATE_FACE_LEFT
		  | AKGL_ACTOR_STATE_MOVING_LEFT)
	    );
    } CLEANUP {
    } PROCESS(errctx) {
    } FINISH(errctx, true);
    SUCCEED_RETURN(errctx);
}
```

`sprite_add` and `sprite_get` are function pointers on the struct, bound to
`akgl_character_sprite_add` and `akgl_character_sprite_get` by
`akgl_character_initialize`. Call through the pointers, as with the render backend
in [Chapter 08](08-rendering.md) — that is what lets a game substitute its own
lookup, a state machine with fallbacks for instance, on one character.

`az` and `sz` are **not** read from JSON. They stay 0 unless you set them by hand.

## The character JSON format

```json kind=character setup=character
{
    "name": "hero",
    "speedtime": 100,
    "speed_x": 0.20,
    "speed_y": 0.20,
    "acceleration_x": 0.20,
    "acceleration_y": 0.20,
    "sprite_mappings": [
	{
	    "state": [
		"AKGL_ACTOR_STATE_ALIVE",
		"AKGL_ACTOR_STATE_FACE_LEFT"
	    ],
	    "sprite": "hero standing left"
	},
	{
	    "state": [
		"AKGL_ACTOR_STATE_ALIVE",
		"AKGL_ACTOR_STATE_FACE_LEFT",
		"AKGL_ACTOR_STATE_MOVING_LEFT"
	    ],
	    "sprite": "hero walking left"
	}
    ]
}
```

| Key | Type | Meaning |
|---|---|---|
| `name` | string | Registry key in `AKGL_REGISTRY_CHARACTER`. |
| `speedtime` | integer | **Milliseconds** a frame is held, scaled to nanoseconds by `AKGL_TIME_ONEMS_NS`. |
| `speed_x`, `speed_y` | number | Top speed per axis. Copied onto an actor as `sx`/`sy`. |
| `acceleration_x`, `acceleration_y` | number | Acceleration per axis, signed by direction each step. |
| `sprite_mappings` | array of objects | One entry per state combination. |
| `…[].sprite` | string | A name already in `AKGL_REGISTRY_SPRITE`. |
| `…[].state` | array of strings | State names, **OR-ed together** into one key. |

All of them are required. An absent key is `AKERR_KEY` naming it; a wrong type is
`AKERR_TYPE`.

`character.h`'s `@brief` describes `speedtime` as "in seconds". It is milliseconds
— the struct field's own documentation says so and `src/character.c` multiplies by
`AKGL_TIME_ONEMS_NS`.

**Sprites must be loaded first.** This loads characters, not sprites: every name in
a `sprite` field has to already be in `AKGL_REGISTRY_SPRITE`, so
`akgl_sprite_load_json` runs before `akgl_character_load_json`. A mapping naming an
unregistered sprite fails with `AKERR_NULLPOINTER` (not `AKERR_KEY` — it is a
lookup miss reported with a pointer status), and the message names the character,
the state and the sprite.

Two keys you may see in existing files and should not copy: `movementspeed` and
`velocity_x`. **Neither is read by anything.** They are ignored, silently.

### State names are prefixed

The strings come from `AKGL_ACTOR_STATE_STRING_NAMES` in
`src/actor_state_string_names.c`, which `akgl_registry_init_actor_state_strings`
turns into a registry. Entry `i` names the bit `1 << i`, and **every name carries
the `AKGL_ACTOR_STATE_` prefix**:

```text
    AKGL_ACTOR_STATE_FACE_DOWN      AKGL_ACTOR_STATE_MOVING_LEFT
    AKGL_ACTOR_STATE_FACE_LEFT      AKGL_ACTOR_STATE_MOVING_RIGHT
    AKGL_ACTOR_STATE_FACE_RIGHT     AKGL_ACTOR_STATE_MOVING_UP
    AKGL_ACTOR_STATE_FACE_UP        AKGL_ACTOR_STATE_MOVING_DOWN
    AKGL_ACTOR_STATE_ALIVE          AKGL_ACTOR_STATE_MOVING_IN
    AKGL_ACTOR_STATE_DYING          AKGL_ACTOR_STATE_MOVING_OUT
    AKGL_ACTOR_STATE_DEAD           AKGL_ACTOR_STATE_UNDEFINED_13 .. _31
```

A name that is not in that list is `AKERR_KEY`, "Unknown actor state", quoting it —
a typo is refused rather than skipped, because a skipped typo would bind a sprite to
the wrong combination and show up as art that never appears. An empty `state` array
is legal and gives you the key `0`.

Adding a new state means adding a bit in `include/akgl/actor.h` **and** its name at
the matching index in `src/actor_state_string_names.c`. A bit whose name is missing
cannot be referred to from JSON at all — which is exactly what happened to
`MOVING_IN` and `MOVING_OUT` until 0.5.0.

> ### `util/assets/littleguy.json` is invalid against the current loader
>
> The sample data for the one shipped demo does not load, and it is worth naming
> the three separate reasons because each is a different class of drift:
>
> 1. **The state names are unprefixed** — `"ACTOR_STATE_ALIVE"` rather than
>    `"AKGL_ACTOR_STATE_ALIVE"`. Every one fails with `AKERR_KEY`, "Unknown actor
>    state".
> 2. **It has `velocity_x` and `velocity_y`**, which nothing reads, and lacks
>    `speed_x` and `speed_y`, which are required.
> 3. **It has no `speedtime`, `acceleration_x` or `acceleration_y`** either — all
>    three required, all three `AKERR_KEY`.
>
> `tests/assets/testcharacter.json` is the file to copy from. Fixing the sample is
> out of scope here (`plan.md`, "Out of scope, deliberately"); the finding is
> recorded so nobody quotes it forward.

## Teardown

`akgl_heap_release_character` decrements the reference count, and at zero it walks
`state_sprites` with `akgl_character_state_sprites_iterate`, releasing every sprite
reference `sprite_add` took, destroys the property set, clears the registry entry
and zeroes the slot.

That walk is an `SDL_EnumerateProperties` callback, so it returns `void` and ends in
`FINISH_NORETURN`. **An error inside it exits the process** via libakerror's default
unhandled-error handler. The same hazard, in its more common form, is in
[Chapter 12](12-actors.md) under `akgl_registry_iterate_actor`; install your own
`akerr_handler_unhandled_error` if a game should survive it.

An actor **borrows** its character and takes no reference on it. Releasing a
character out from under a live actor leaves a dangling `basechar`.

## Known defects worth knowing here

- **Re-adding the same sprite for the same state leaks a reference.** See above.
- **Long names register and unregister under different keys.**
  `akgl_character_initialize` writes the registry entry under the *caller's* `name`
  pointer, while `akgl_heap_release_character` clears it under the character's own
  truncated 128-byte copy. For a name over 127 bytes those differ, and the registry
  entry survives the release — pointing at a zeroed slot. Latent for ordinary names;
  related to `TODO.md`, "Truncated registry keys can collide", which covers the
  collision half.
- **`speedtime` is written through an `int *` cast of a `uint64_t` field.**
  `src/character.c` passes `(int *)&obj->speedtime` to
  `akgl_get_json_integer_value`. It works because the struct was zeroed and the
  platform is little-endian; it is the same class of cast-over-a-signature-mismatch
  that `AGENTS.md` argues against under "Never silence a warning with a cast".
- **`akgl_character_initialize` silently replaces a same-named character**, and the
  one it displaced becomes unreachable rather than being released.

## Where to look next

- [Chapter 10](10-spritesheets-and-sprites.md) — the sprites these map to.
- [Chapter 12](12-actors.md) — the state bitmask itself, and what sets it.
- [Chapter 14](14-physics.md) — what `sx`/`sy` and `ax`/`ay` mean once an actor is
  simulated.
