2026-07-30 01:10:31 -04:00
/**
* @ file character . h
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief The reusable half of an actor : movement constants and a state - to - sprite map .
*
* A character is the template ; an akgl_Actor is the instance . Everything that is
* the same for every goblin on the map - - top speed , acceleration , frame dwell
* time , and which sprite to draw for which combination of actor - state bits - -
* lives here and is shared by pointer , so a hundred actors cost one character .
*
* Characters are pool objects ( akgl_heap_next_character ) and are published in
* the # AKGL_REGISTRY_CHARACTER property registry under their name , which is how
* akgl_actor_set_character finds them . akgl_registry_init must have run first .
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
# ifndef _AKGL_CHARACTER_H_
# define _AKGL_CHARACTER_H_
2025-08-03 10:07:35 -04:00
# include <SDL3/SDL_properties.h>
2026-05-08 22:01:56 -04:00
# include "types.h"
2025-08-03 10:07:35 -04:00
# include "sprite.h"
2026-05-06 23:18:42 -04:00
# define AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH 128
# define AKGL_MAX_HEAP_CHARACTER 256
2025-08-03 10:07:35 -04:00
2026-07-30 01:10:31 -04:00
/** @brief Defines reusable movement parameters and actor-state sprite bindings. */
2026-05-06 23:18:42 -04:00
typedef struct akgl_Character {
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
uint8_t refcount ; /**< Pool bookkeeping; 0 means the slot is free. */
char name [ AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH ] ; /**< Registry key. Truncated, not rejected, if the source name is longer. */
SDL_PropertiesID state_sprites ; /**< State bitmask (decimal, as a string) -> akgl_Sprite *. */
uint64_t speedtime ; /**< Nanoseconds one sprite frame is held before advancing. Read from JSON in milliseconds and scaled by #AKGL_TIME_ONESEC_MS, which despite its name is nanoseconds-per-millisecond. TODO.md item 6. */
float32_t ax ; /**< Acceleration along x, world units per second squared. Copied into an actor by akgl_actor_set_character. */
float32_t ay ; /**< Acceleration along y. */
float32_t az ; /**< Acceleration along z. Not read from JSON; stays 0 unless set by hand. */
float32_t sx ; /**< Maximum speed along x, world units per second. */
float32_t sy ; /**< Maximum speed along y. */
float32_t sz ; /**< Maximum speed along z. Not read from JSON; stays 0 unless set by hand. */
akerr_ErrorContext AKERR_NOIGNORE * ( * sprite_add ) ( struct akgl_Character * , akgl_Sprite * , int ) ; /**< Bound to akgl_character_sprite_add by akgl_character_initialize. */
akerr_ErrorContext AKERR_NOIGNORE * ( * sprite_get ) ( struct akgl_Character * , int , akgl_Sprite * * ) ; /**< Bound to akgl_character_sprite_get by akgl_character_initialize. */
2026-05-06 23:18:42 -04:00
} akgl_Character ;
2025-08-03 10:07:35 -04:00
2026-07-30 01:10:31 -04:00
/**
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief Zero a pooled character , name it , and publish it in the character registry .
*
* Wipes the struct , copies @ p name into it , creates the empty state - to - sprite
* property set , binds the ` sprite_add ` / ` sprite_get ` function pointers , inserts
* the character into # AKGL_REGISTRY_CHARACTER under @ p name , and takes the first
* reference . Everything numeric ( speeds , accelerations , ` speedtime ` ) is left at
* zero for the caller - - or akgl_character_load_json - - to fill in .
*
* @ param basechar Pooled character to initialize , normally straight from
* akgl_heap_next_character . Required . Any previous contents are
* discarded without releasing the sprites they referenced .
* @ param name Registry key , NUL - terminated . Required . Truncated at
* # AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH . A name already in the
* registry is silently replaced , and the character it displaced
* becomes unreachable rather than being released .
2026-07-30 01:10:31 -04:00
* @ return ` NULL ` on success , otherwise an error context owned by the caller .
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ throws AKERR_NULLPOINTER If @ p basechar or @ p name is ` NULL ` , or if SDL
* cannot create the state - to - sprite property set ( out of memory ) .
* @ throws AKERR_KEY If the character cannot be written into
* # AKGL_REGISTRY_CHARACTER - - in practice , because akgl_registry_init
* has not run and the registry id is still 0.
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
akerr_ErrorContext AKERR_NOIGNORE * akgl_character_initialize ( akgl_Character * basechar , char * name ) ;
2026-07-30 01:10:31 -04:00
/**
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief Bind a sprite to one exact combination of actor - state bits .
*
* The map key is the decimal spelling of @ p state , so lookups match the * whole *
* value : a sprite added for ` FACE_LEFT | MOVING_LEFT ` is not found by a lookup for
* ` FACE_LEFT ` alone . Callers are expected to register every combination they
* intend to draw . Adding a sprite takes a reference on it .
*
* @ param basechar Character to add the mapping to . Required . Must already have
* been through akgl_character_initialize .
* @ param ref Sprite to draw for @ p state . Required . Its ` refcount ` is
* incremented , so the character keeps it alive .
* @ param state The exact actor - state bitmask ( ` AKGL_ACTOR_STATE_ * ` ) this
* sprite is for . 0 is accepted and is a usable key .
2026-07-30 01:10:31 -04:00
* @ return ` NULL ` on success , otherwise an error context owned by the caller .
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ throws AKERR_NULLPOINTER If @ p basechar or @ p ref is ` NULL ` .
*
* @ note Re - adding a different sprite for a @ p state that is already mapped
* replaces the entry without releasing the sprite it displaced , so the
* displaced sprite ' s reference is never given back .
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
akerr_ErrorContext AKERR_NOIGNORE * akgl_character_sprite_add ( akgl_Character * basechar , akgl_Sprite * ref , int state ) ;
2026-07-30 01:10:31 -04:00
/**
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief Look up the sprite bound to one exact combination of actor - state bits .
*
* The counterpart to akgl_character_sprite_add , and matched the same way : an
* exact match on the whole @ p state value , with no fallback to a subset of the
* bits and no default sprite . Unlike most lookups in this codebase , * not finding
* one is an error * rather than a successful " nothing here " - - an actor with no
* sprite for its current state cannot be drawn .
*
* @ param basechar Character to search . Required .
* @ param state The exact actor - state bitmask to look up .
* @ param dest Receives the mapped sprite . Required - - the return value is
* spoken for by the error context . Set to ` NULL ` when there is
* no mapping , alongside the AKERR_KEY error .
2026-07-30 01:10:31 -04:00
* @ return ` NULL ` on success , otherwise an error context owned by the caller .
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ throws AKERR_NULLPOINTER If @ p basechar or @ p dest is ` NULL ` .
* @ throws AKERR_KEY If no sprite is bound to exactly that @ p state . The message
* carries the state both as a decimal and as a bit pattern .
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
akerr_ErrorContext AKERR_NOIGNORE * akgl_character_sprite_get ( akgl_Character * basechar , int state , akgl_Sprite * * dest ) ;
2025-08-03 10:07:35 -04:00
// This is an SDL iterator so we can't return our error state from it.
2026-07-30 01:10:31 -04:00
/**
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief ` SDL_EnumerateProperties ` callback that applies an akgl_Iterator to one state - to - sprite entry .
*
* Currently implements exactly one operation : with # AKGL_ITERATOR_OP_RELEASE
* set , it hands the mapped sprite back to its heap layer . Every other flag is
* ignored here . Used to tear a character ' s sprite map down entry by entry .
*
* @ param userdata The akgl_Iterator carrying the operation flags , passed through
* by ` SDL_EnumerateProperties ` . Required despite the ` void * ` - -
* a ` NULL ` here is an error , not " no operations " .
* @ param props The character ' s ` state_sprites ` set , supplied by SDL .
* @ param name The property key : one state bitmask in decimal . Required .
*
* @ warning This is an SDL callback , so it returns ` void ` and has nowhere to
* propagate an error to . It ends in ` FINISH_NORETURN ` , which logs the
* stack trace and then calls libakerror ' s unhandled - error handler - -
* whose default implementation * * exits the process * * with the error
* status . A missing sprite or a ` NULL ` @ p userdata therefore terminates
* the game rather than skipping an entry . Install your own
* ` akerr_handler_unhandled_error ` if that is not what you want .
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
void akgl_character_state_sprites_iterate ( void * userdata , SDL_PropertiesID props , const char * name ) ;
2025-08-03 10:07:35 -04:00
2026-07-30 01:10:31 -04:00
/**
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ brief Build a character from a JSON definition file and register it .
*
* Claims a character from the pool , then reads : ` name ` ( the registry key ) ,
* ` sprite_mappings ` ( an array of ` { " sprite " : < name > , " state " : [ < state names > ] } `
* objects ) , ` speedtime ` in seconds , ` speed_x ` , ` speed_y ` , ` acceleration_x ` , and
* ` acceleration_y ` . Each mapping ' s ` state ` array is OR - ed together into one
* bitmask by looking every name up in # AKGL_REGISTRY_ACTOR_STATE_STRINGS , so
* ` [ " FACE_LEFT " , " MOVING_LEFT " ] ` becomes a single key .
*
* Every referenced sprite must already be in # AKGL_REGISTRY_SPRITE : this loads
* characters , not sprites , so akgl_sprite_load_json runs first . On any failure
* the pooled character is released again .
*
* @ param filename Path to the JSON document . Required . Used verbatim - - it is
* not resolved against ` SDL_GetBasePath ( ) ` .
2026-07-30 01:10:31 -04:00
* @ return ` NULL ` on success , otherwise an error context owned by the caller .
Document what the functions actually do instead of that they can fail
The Doxygen comments were generated from the declarations, so 217 @throws
lines across 21 headers read "When the corresponding validation or operation
fails" and told a caller nothing beyond the status name. The @param lines were
the same shape: every output was "Output destination populated by the
function", every instance "Object to initialize, inspect, or modify".
Rewritten against the implementations, following the pattern libakstdlib
already uses:
- @throws names the condition. akgl_sprite_load_json separated AKERR_KEY
(absent) from AKERR_TYPE (present, wrong type) from AKERR_OUTOFBOUNDS
(filename too long, or array indexed past its end), and gained AKGL_ERR_SDL
and AKGL_ERR_HEAP, which it raises and never declared.
- Parameters say whether they are required, what a NULL means, and what is
written on a failure path. Where an argument is not checked, the doc says so:
akgl_heap_next_actor's dest is a crash on NULL, not an error, and
akgl_render_2d_frame_start dereferences self before testing it.
- The conventions move up to the file blocks so the per-function docs stay
short. json_helpers.h states once that absence is an error here and that
json_t * results are borrowed; heap.h explains the pool model and the
acquire asymmetry; physics.h carries the thrust/environmental/velocity table.
- Struct fields, enum values, macros and exported globals are documented,
including the dead ones - sprite_w/sprite_h, movetimer, p_scale and
timer_gravity are read by nothing, and say so.
Also fixes ten comments in error.h and audio.h that opened with /** rather
than /**<, so Doxygen attached them to the following entity and rendered the
text as part of the macro's value. Verified against the generated HTML.
Comments only - no declaration changed. Doxygen builds clean under
WARN_AS_ERROR, scripts/reindent.sh --check passes, 19/19 suites pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 11:02:20 -04:00
* @ throws AKERR_NULLPOINTER If @ p filename is ` NULL ` ; if the file cannot be
* opened or does not parse ( the message carries jansson ' s line number
* and text ) ; or if a mapping names a sprite that is not in the sprite
* registry .
* @ throws AKERR_KEY If a ` state ` array contains a name that is not a known
* actor state , if a required top - level key is absent , or if the
* character cannot be added to the registry .
* @ throws AKERR_TYPE If a key is present but holds the wrong JSON type - - for
* example ` speedtime ` as a string . The message names the key .
* @ throws AKERR_OUTOFBOUNDS If a ` state ` array is indexed past its end .
* @ throws AKGL_ERR_HEAP If the character pool or the string pool is exhausted .
2026-07-30 01:10:31 -04:00
*/
2026-05-06 23:18:42 -04:00
akerr_ErrorContext AKERR_NOIGNORE * akgl_character_load_json ( char * filename ) ;
2025-08-03 10:07:35 -04:00
2026-05-06 23:18:42 -04:00
# endif // _AKGL_CHARACTER_H_