2026-07-30 01:10:31 -04:00
|
|
|
/**
|
|
|
|
|
* @file character.c
|
|
|
|
|
* @brief Implements the character subsystem.
|
|
|
|
|
*/
|
|
|
|
|
|
2025-08-03 10:07:35 -04:00
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
|
#include <SDL3_image/SDL_image.h>
|
2026-01-05 08:58:06 -05:00
|
|
|
#include <akerror.h>
|
2025-08-03 10:07:35 -04:00
|
|
|
#include <string.h>
|
|
|
|
|
#include <jansson.h>
|
|
|
|
|
|
2026-05-07 22:20:10 -04:00
|
|
|
#include <akgl/game.h>
|
|
|
|
|
#include <akgl/sprite.h>
|
|
|
|
|
#include <akgl/json_helpers.h>
|
|
|
|
|
#include <akgl/heap.h>
|
|
|
|
|
#include <akgl/registry.h>
|
|
|
|
|
#include <akgl/staticstring.h>
|
|
|
|
|
#include <akgl/iterator.h>
|
|
|
|
|
#include <akgl/util.h>
|
2025-08-03 10:07:35 -04:00
|
|
|
|
2026-05-06 23:18:42 -04:00
|
|
|
akerr_ErrorContext *akgl_character_initialize(akgl_Character *obj, char *name)
|
2025-08-03 10:07:35 -04:00
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
2026-05-06 23:18:42 -04:00
|
|
|
FAIL_ZERO_RETURN(errctx, obj, AKERR_NULLPOINTER, "NULL akgl_Character reference");
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_RETURN(errctx, name, AKERR_NULLPOINTER, "NULL name string pointer");
|
2026-05-06 23:18:42 -04:00
|
|
|
memset(obj, 0x00, sizeof(akgl_Character));
|
|
|
|
|
strncpy(obj->name, name, AKGL_SPRITE_MAX_CHARACTER_NAME_LENGTH);
|
2025-08-03 10:07:35 -04:00
|
|
|
obj->state_sprites = SDL_CreateProperties();
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_RETURN(errctx, obj->state_sprites, AKERR_NULLPOINTER, "Unable to initialize SDL_PropertiesID for character state map");
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
|
2026-05-06 23:18:42 -04:00
|
|
|
obj->sprite_add = &akgl_character_sprite_add;
|
|
|
|
|
obj->sprite_get = &akgl_character_sprite_get;
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
|
2025-08-03 10:07:35 -04:00
|
|
|
FAIL_ZERO_RETURN(
|
|
|
|
|
errctx,
|
2026-05-06 23:18:42 -04:00
|
|
|
SDL_SetPointerProperty(AKGL_REGISTRY_CHARACTER, name, (void *)obj),
|
2026-05-03 23:57:55 -04:00
|
|
|
AKERR_KEY,
|
2025-08-03 10:07:35 -04:00
|
|
|
"Unable to add character to registry");
|
|
|
|
|
obj->refcount += 1;
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-06 23:18:42 -04:00
|
|
|
akerr_ErrorContext *akgl_character_sprite_add(akgl_Character *basechar, akgl_Sprite *ref, int state)
|
2025-08-03 10:07:35 -04:00
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
char stateval[32];
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_RETURN(errctx, basechar, AKERR_NULLPOINTER, "NULL character reference");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, ref, AKERR_NULLPOINTER, "NULL sprite reference");
|
2025-08-03 10:07:35 -04:00
|
|
|
memset(&stateval, 0x00, 32);
|
|
|
|
|
SDL_itoa(state, (char *)&stateval, 10);
|
|
|
|
|
SDL_SetPointerProperty(basechar->state_sprites, (char *)&stateval, ref);
|
2025-08-08 22:39:48 -04:00
|
|
|
SDL_Log("Added sprite %s to character %s for state %b", (char *)&ref->name, (char *)&basechar->name, state);
|
2025-08-03 10:07:35 -04:00
|
|
|
ref->refcount += 1;
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-06 23:18:42 -04:00
|
|
|
akerr_ErrorContext *akgl_character_sprite_get(akgl_Character *basechar, int state, akgl_Sprite **dest)
|
2025-08-03 10:07:35 -04:00
|
|
|
{
|
2026-05-06 23:18:42 -04:00
|
|
|
akgl_Sprite *target = NULL;
|
2025-08-03 10:07:35 -04:00
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
char stateval[32];
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_RETURN(errctx, dest, AKERR_NULLPOINTER, "NULL pointer to sprite pointer (**dest)");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, basechar, AKERR_NULLPOINTER, "NULL character reference");
|
2025-08-03 10:07:35 -04:00
|
|
|
memset(&stateval, 0x00, 32);
|
|
|
|
|
SDL_itoa(state, (char *)&stateval, 10);
|
2026-05-06 23:18:42 -04:00
|
|
|
*dest = (akgl_Sprite *)SDL_GetPointerProperty(basechar->state_sprites, (char *)&stateval, NULL);
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_RETURN(errctx, *dest, AKERR_KEY, "Sprite for state %d (%b) not found in the character's registry", state, state);
|
2025-08-04 21:37:36 -04:00
|
|
|
target = *dest;
|
2025-08-08 22:39:48 -04:00
|
|
|
//SDL_Log("Sprite state %d (%s) has character %s", state, (char *)&stateval, target->name);
|
2025-08-03 10:07:35 -04:00
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SDL iterator so we can't return error information here, void only
|
|
|
|
|
// this means we don't have anywhere to send exceptions up to, so if we hit an error, we log and exit(1) here
|
2026-05-06 23:18:42 -04:00
|
|
|
void akgl_character_state_sprites_iterate(void *userdata, SDL_PropertiesID registry, const char *name)
|
2025-08-03 10:07:35 -04:00
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
2026-05-06 23:18:42 -04:00
|
|
|
akgl_Sprite *spriteptr;
|
|
|
|
|
akgl_Iterator *opflags = (akgl_Iterator *)userdata;
|
2025-08-03 10:07:35 -04:00
|
|
|
ATTEMPT {
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_BREAK(errctx, opflags, AKERR_NULLPOINTER, "Character state sprite iterator received null iterator op pointer");
|
|
|
|
|
FAIL_ZERO_BREAK(errctx, name, AKERR_NULLPOINTER, "Character state sprite iterator received null sprite name");
|
2026-05-06 23:18:42 -04:00
|
|
|
spriteptr = (akgl_Sprite *)SDL_GetPointerProperty(registry, name, NULL);
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_BREAK(errctx, spriteptr, AKERR_NULLPOINTER, "Character state sprite for %s not found", name);
|
2026-05-06 23:18:42 -04:00
|
|
|
if ( AKGL_BITMASK_HAS(opflags->flags, AKGL_ITERATOR_OP_RELEASE) ) {
|
|
|
|
|
CATCH(errctx, akgl_heap_release_sprite(spriteptr));
|
2025-08-03 10:07:35 -04:00
|
|
|
}
|
|
|
|
|
} CLEANUP {
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} FINISH_NORETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
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 OR a JSON array of actor-state names together into one bitmask.
|
|
|
|
|
*
|
|
|
|
|
* This is what lets a character JSON say `["FACE_LEFT", "MOVING_LEFT"]` rather
|
|
|
|
|
* than a number: each name is looked up in #AKGL_REGISTRY_ACTOR_STATE_STRINGS
|
|
|
|
|
* and OR-ed in. A name that is not a known state is an error rather than being
|
|
|
|
|
* skipped -- a typo in a state name would otherwise bind a sprite to the wrong
|
|
|
|
|
* combination and show up as art that never appears.
|
|
|
|
|
*
|
|
|
|
|
* @param states JSON array of state-name strings. Required. An empty array is
|
|
|
|
|
* legal and leaves @p dest as it was.
|
|
|
|
|
* @param dest Receives the OR of every named bit. Required in practice, and
|
|
|
|
|
* **not** checked -- the guard that should test it tests @p states
|
|
|
|
|
* a second time instead, so a `NULL` here is a crash. It is OR-ed
|
|
|
|
|
* into rather than assigned, so the caller must zero it first.
|
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 states is `NULL`.
|
|
|
|
|
* @throws AKERR_KEY If a name is not in the actor-state registry. The message
|
|
|
|
|
* quotes it. Note that bits 11 and 12 are unreachable by name; see
|
|
|
|
|
* akgl_registry_init_actor_state_strings.
|
|
|
|
|
* @throws AKERR_TYPE If an array element is not a string.
|
|
|
|
|
* @throws AKERR_OUTOFBOUNDS If the array is indexed past its end.
|
|
|
|
|
* @throws AKGL_ERR_HEAP If the string pool is exhausted.
|
2026-07-30 01:10:31 -04:00
|
|
|
*/
|
2026-05-06 23:18:42 -04:00
|
|
|
static akerr_ErrorContext *akgl_character_load_json_state_int_from_strings(json_t *states, int *dest)
|
2025-08-03 10:07:35 -04:00
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
long newstate = 0;
|
2026-05-06 23:18:42 -04:00
|
|
|
akgl_String *tmpstring = NULL;
|
2025-08-03 10:07:35 -04:00
|
|
|
PREPARE_ERROR(errctx);
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_RETURN(errctx, states, AKERR_NULLPOINTER, "NULL states array");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, states, AKERR_NULLPOINTER, "NULL destination integer");
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
|
2025-08-03 10:07:35 -04:00
|
|
|
ATTEMPT {
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_heap_next_string(&tmpstring));
|
2025-08-03 10:07:35 -04:00
|
|
|
for ( i = 0; i < json_array_size((json_t *)states) ; i++ ) {
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_get_json_array_index_string(states, i, &tmpstring));
|
2026-05-09 14:45:37 -04:00
|
|
|
newstate = (long)SDL_GetNumberProperty(AKGL_REGISTRY_ACTOR_STATE_STRINGS, (char *)&tmpstring->data, 0);
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_BREAK(errctx, newstate, AKERR_KEY, "Unknown actor state %s", (char *)&tmpstring->data);
|
2025-08-03 10:07:35 -04:00
|
|
|
*dest = (*dest | (int)(newstate));
|
|
|
|
|
}
|
|
|
|
|
} CLEANUP {
|
2026-05-06 23:18:42 -04:00
|
|
|
IGNORE(akgl_heap_release_string(tmpstring));
|
2025-08-03 10:07:35 -04:00
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} FINISH(errctx, true);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
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 Name a character and build its state-to-sprite map from a JSON document.
|
|
|
|
|
*
|
|
|
|
|
* The half of akgl_character_load_json that deals with identity and sprites; the
|
|
|
|
|
* caller handles the numeric fields afterwards. Reads `name`, initializes the
|
|
|
|
|
* character with it, then walks `sprite_mappings` binding each named sprite to
|
|
|
|
|
* the bitmask its `state` array adds up to.
|
|
|
|
|
*
|
|
|
|
|
* Every sprite named must already be in #AKGL_REGISTRY_SPRITE.
|
|
|
|
|
*
|
|
|
|
|
* @param json The parsed character document. Required in practice; not checked,
|
|
|
|
|
* and passed straight to accessors that report it.
|
|
|
|
|
* @param obj The pooled character to fill in. Required, unchecked -- it is
|
|
|
|
|
* handed to akgl_character_initialize, which does check it.
|
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 a mapping names a sprite that is not registered.
|
|
|
|
|
* The message names the character, the state, and the sprite.
|
|
|
|
|
* @throws AKERR_KEY If `name`, `sprite_mappings`, or a mapping's `sprite` or
|
|
|
|
|
* `state` is absent, or if a state name is unknown.
|
|
|
|
|
* @throws AKERR_TYPE If one of those keys has the wrong JSON type.
|
|
|
|
|
* @throws AKERR_OUTOFBOUNDS If an array is indexed past its end.
|
|
|
|
|
* @throws AKGL_ERR_HEAP If the string pool is exhausted.
|
2026-07-30 01:10:31 -04:00
|
|
|
*/
|
2026-05-06 23:18:42 -04:00
|
|
|
static akerr_ErrorContext *akgl_character_load_json_inner(json_t *json, akgl_Character *obj)
|
2025-08-03 10:07:35 -04:00
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
json_t *mappings = NULL;
|
|
|
|
|
json_t *curmapping = NULL;
|
|
|
|
|
json_t *statearray = NULL;
|
2026-05-06 23:18:42 -04:00
|
|
|
akgl_Sprite *spriteptr = NULL;
|
2025-08-03 10:07:35 -04:00
|
|
|
int i = 0;
|
2026-05-06 23:18:42 -04:00
|
|
|
akgl_String *tmpstr = NULL;
|
|
|
|
|
akgl_String *tmpstr2 = NULL;
|
2025-08-03 10:07:35 -04:00
|
|
|
int stateval = 0;
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
|
2025-08-03 10:07:35 -04:00
|
|
|
ATTEMPT {
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_get_json_string_value((json_t *)json, "name", &tmpstr));
|
|
|
|
|
CATCH(errctx, akgl_character_initialize((akgl_Character *)obj, tmpstr->data));
|
|
|
|
|
CATCH(errctx, akgl_get_json_array_value((json_t *)json, "sprite_mappings", &mappings));
|
2025-08-03 10:07:35 -04:00
|
|
|
for ( i = 0; i < json_array_size((json_t *)mappings) ; i++ ) {
|
|
|
|
|
stateval = 0;
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_get_json_array_index_object((json_t *)mappings, i, &curmapping));
|
|
|
|
|
CATCH(errctx, akgl_get_json_string_value((json_t *)curmapping, "sprite", &tmpstr));
|
|
|
|
|
spriteptr = (akgl_Sprite *)SDL_GetPointerProperty(
|
|
|
|
|
AKGL_REGISTRY_SPRITE,
|
2025-08-03 10:07:35 -04:00
|
|
|
tmpstr->data,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_get_json_string_value((json_t *)json, "name", &tmpstr2));
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_get_json_array_value((json_t *)curmapping, "state", &statearray));
|
|
|
|
|
CATCH(errctx, akgl_character_load_json_state_int_from_strings(statearray, &stateval));
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_get_json_string_value((json_t *)curmapping, "sprite", &tmpstr));
|
2025-08-03 10:07:35 -04:00
|
|
|
FAIL_ZERO_BREAK(
|
|
|
|
|
errctx,
|
|
|
|
|
spriteptr,
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
AKERR_NULLPOINTER,
|
2025-08-08 22:39:48 -04:00
|
|
|
"Character %s for state %b references sprite %s but not found in the registry",
|
2025-08-03 10:07:35 -04:00
|
|
|
tmpstr2->data,
|
|
|
|
|
stateval,
|
|
|
|
|
tmpstr->data
|
|
|
|
|
);
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_character_sprite_add((akgl_Character *)obj, (akgl_Sprite *)spriteptr, stateval));
|
2025-08-03 10:07:35 -04:00
|
|
|
}
|
|
|
|
|
} CLEANUP {
|
|
|
|
|
if ( tmpstr != NULL ) {
|
2026-05-06 23:18:42 -04:00
|
|
|
IGNORE(akgl_heap_release_string(tmpstr));
|
2025-08-03 10:07:35 -04:00
|
|
|
}
|
|
|
|
|
if ( tmpstr2 != NULL ) {
|
2026-05-06 23:18:42 -04:00
|
|
|
IGNORE(akgl_heap_release_string(tmpstr2));
|
2025-08-03 10:07:35 -04:00
|
|
|
}
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} FINISH(errctx, true);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-06 23:18:42 -04:00
|
|
|
akerr_ErrorContext *akgl_character_load_json(char *filename)
|
2025-08-03 10:07:35 -04:00
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
json_t *json;
|
|
|
|
|
json_error_t error;
|
2026-05-06 23:18:42 -04:00
|
|
|
akgl_Character *obj = NULL;
|
|
|
|
|
//akgl_String *tmpstr = NULL;
|
Reindent all C sources to the canonical stroustrup style
Mechanical whitespace-only change across src/, include/, tests/, and
util/, applied with scripts/reindent.sh. No behavioral change.
Most files already conformed. The genuine outliers indented at 2 columns
(json_helpers.c, util.c from akgl_rectangle_points onward, assets.c,
staticstring.c, akgl_actor_add_child, util.h, staticstring.h) or used
spaces where the canonical form is a tab (draw.c). cc-mode also re-aligns
line-continuation backslashes in multi-line macros to its default
c-backslash-column, which is required for the tree to be a fixed point of
the indenter.
Verified whitespace-only: `git diff -w` over this change is empty apart
from three trailing blank lines removed at EOF in src/heap.c,
src/registry.c, and tests/tilemap.c. The build produces no new errors and
ctest is unchanged at 13/14, with `character` still the one intentional
failure.
The tree is now a fixed point of `scripts/reindent.sh --check`.
include/akgl/SDL_GameControllerDB.h is generated and excluded.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 18:17:37 -04:00
|
|
|
|
2026-05-03 23:57:55 -04:00
|
|
|
FAIL_ZERO_RETURN(errctx, filename, AKERR_NULLPOINTER, "Received null filename");
|
2025-08-03 10:07:35 -04:00
|
|
|
ATTEMPT {
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_heap_next_character(&obj));
|
|
|
|
|
//CATCH(errctx, akgl_heap_next_string(&tmpstr));
|
|
|
|
|
//CATCH(errctx, akgl_string_initialize(tmpstr, NULL));
|
|
|
|
|
//SDL_snprintf((char *)&tmpstr->data, AKGL_MAX_STRING_LENGTH, "%s%s", SDL_GetBasePath(), filename);
|
2025-08-04 22:34:25 -04:00
|
|
|
json = (json_t *)json_load_file(filename, 0, &error);
|
2025-08-03 10:07:35 -04:00
|
|
|
FAIL_ZERO_BREAK(
|
|
|
|
|
errctx,
|
|
|
|
|
json,
|
2026-05-03 23:57:55 -04:00
|
|
|
AKERR_NULLPOINTER,
|
2025-08-03 15:14:36 -04:00
|
|
|
"Error while loading character from %s on line %d: %s", filename, error.line, error.text
|
2025-08-03 10:07:35 -04:00
|
|
|
);
|
2026-05-06 23:18:42 -04:00
|
|
|
CATCH(errctx, akgl_character_load_json_inner(json, obj));
|
2026-05-26 10:36:31 -04:00
|
|
|
CATCH(errctx, akgl_get_json_integer_value(json, "speedtime", (int *)&obj->speedtime));
|
|
|
|
|
obj->speedtime = obj->speedtime * AKGL_TIME_ONESEC_MS;
|
|
|
|
|
CATCH(errctx, akgl_get_json_number_value(json, "speed_x", &obj->sx));
|
|
|
|
|
CATCH(errctx, akgl_get_json_number_value(json, "speed_y", &obj->sy));
|
|
|
|
|
CATCH(errctx, akgl_get_json_number_value(json, "acceleration_x", &obj->ax));
|
|
|
|
|
CATCH(errctx, akgl_get_json_number_value(json, "acceleration_y", &obj->ay));
|
2025-08-03 10:07:35 -04:00
|
|
|
} CLEANUP {
|
2026-05-06 23:18:42 -04:00
|
|
|
//IGNORE(akgl_heap_release_string(tmpstr));
|
2025-08-03 10:07:35 -04:00
|
|
|
if ( errctx != NULL ) {
|
|
|
|
|
if ( errctx->status != 0 ) {
|
2026-05-06 23:18:42 -04:00
|
|
|
IGNORE(akgl_heap_release_character(obj));
|
2025-08-03 10:07:35 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} FINISH(errctx, true);
|
2026-05-13 16:56:24 -04:00
|
|
|
SDL_Log("Character %s loaded from %s", obj->name, filename);
|
2025-08-03 10:07:35 -04:00
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|