2025-08-03 10:07:35 -04:00
|
|
|
#include <SDL3/SDL.h>
|
|
|
|
|
#include <SDL3_image/SDL_image.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <sdlerror.h>
|
|
|
|
|
|
2025-08-03 10:41:09 -04:00
|
|
|
#include <sdl3game/game.h>
|
|
|
|
|
#include <sdl3game/sprite.h>
|
|
|
|
|
#include <sdl3game/actor.h>
|
|
|
|
|
#include <sdl3game/heap.h>
|
|
|
|
|
#include <sdl3game/registry.h>
|
|
|
|
|
#include <sdl3game/staticstring.h>
|
|
|
|
|
#include <sdl3game/iterator.h>
|
2025-08-03 10:07:35 -04:00
|
|
|
|
|
|
|
|
ErrorContext *actor_initialize(actor *obj, char *name)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "actor_initialize received null actor pointer");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, name, ERR_NULLPOINTER, "actor_initialize received null name string pointer");
|
|
|
|
|
|
|
|
|
|
memset(obj, 0x00, sizeof(actor));
|
|
|
|
|
strncpy((char *)obj->name, name, ACTOR_MAX_NAME_LENGTH);
|
|
|
|
|
obj->curSpriteReversing = false;
|
|
|
|
|
obj->movement_controls_face = true;
|
|
|
|
|
|
|
|
|
|
obj->updatefunc = &actor_update;
|
|
|
|
|
obj->renderfunc = &actor_render;
|
|
|
|
|
obj->facefunc = &actor_automatic_face;
|
|
|
|
|
obj->movementlogicfunc = &actor_logic_movement;
|
|
|
|
|
obj->changeframefunc = &actor_logic_changeframe;
|
|
|
|
|
obj->addchild = &actor_add_child;
|
|
|
|
|
|
|
|
|
|
FAIL_ZERO_RETURN(
|
|
|
|
|
errctx,
|
|
|
|
|
SDL_SetPointerProperty(REGISTRY_ACTOR, name, (void *)obj),
|
|
|
|
|
ERR_KEY,
|
|
|
|
|
"Unable to add actor to registry"
|
|
|
|
|
);
|
|
|
|
|
obj->refcount += 1;
|
|
|
|
|
SDL_Log("Actor %s initialized and added to the registry", (char *)obj->name);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext *actor_set_character(actor *obj, char *basecharname)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "Null actor reference");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, basecharname, ERR_NULLPOINTER, "Null character reference");
|
|
|
|
|
|
|
|
|
|
obj->basechar = SDL_GetPointerProperty(REGISTRY_CHARACTER, basecharname, NULL);
|
|
|
|
|
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj->basechar, ERR_NULLPOINTER, "Character not found in the registry");
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext *actor_automatic_face(actor *obj)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "Null actor reference");
|
|
|
|
|
ATTEMPT {
|
|
|
|
|
if ( obj->movement_controls_face == true ) {
|
|
|
|
|
// TODO : This doesn't really work properly
|
|
|
|
|
BITMASK_DEL(obj->state, ACTOR_STATE_FACE_ALL);
|
|
|
|
|
if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_LEFT) ) {
|
|
|
|
|
BITMASK_ADD(obj->state, ACTOR_STATE_FACE_LEFT);
|
|
|
|
|
} else if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_RIGHT) ) {
|
|
|
|
|
BITMASK_ADD(obj->state, ACTOR_STATE_FACE_RIGHT);
|
|
|
|
|
} else if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_UP) ) {
|
|
|
|
|
BITMASK_ADD(obj->state, ACTOR_STATE_FACE_UP);
|
|
|
|
|
} else if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_DOWN) ) {
|
|
|
|
|
BITMASK_ADD(obj->state, ACTOR_STATE_FACE_DOWN);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} CLEANUP {
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} FINISH(errctx, true);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext *actor_logic_changeframe(actor *obj, sprite *curSprite, SDL_Time curtimems)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "Null actor reference");
|
|
|
|
|
ATTEMPT {
|
|
|
|
|
// are we currently looping in reverse?
|
|
|
|
|
if ( curSprite->loop == true && obj->curSpriteReversing == true ) {
|
|
|
|
|
// are we at the beginning of the loop?
|
|
|
|
|
if ( obj->curSpriteFrameId == 0 ) {
|
|
|
|
|
obj->curSpriteReversing = false;
|
|
|
|
|
obj->curSpriteFrameId += 1;
|
|
|
|
|
} else {
|
|
|
|
|
obj->curSpriteFrameId -= 1;
|
|
|
|
|
}
|
|
|
|
|
// are we at the end of the animation?
|
2025-08-09 08:54:12 -04:00
|
|
|
} else if ( obj->curSpriteFrameId >= (curSprite->frames-1) ) {
|
2025-08-03 10:07:35 -04:00
|
|
|
// are we set to loop in reverse?
|
|
|
|
|
if ( curSprite->loop == true && curSprite->loopReverse == true ) {
|
|
|
|
|
obj->curSpriteReversing = true;
|
|
|
|
|
obj->curSpriteFrameId -= 1;
|
|
|
|
|
// are we set to loop forward?
|
2025-08-09 08:54:12 -04:00
|
|
|
} else {
|
|
|
|
|
// we are at the end of the animation and we either loop forward or do not loop
|
2025-08-03 10:07:35 -04:00
|
|
|
obj->curSpriteFrameId = 0;
|
2025-08-09 08:54:12 -04:00
|
|
|
}
|
2025-08-03 10:07:35 -04:00
|
|
|
// we are not looping in reverse and we are not at the end of the animation
|
|
|
|
|
} else {
|
|
|
|
|
obj->curSpriteFrameId += 1;
|
|
|
|
|
}
|
|
|
|
|
} CLEANUP {
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} FINISH(errctx, true);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext *actor_logic_movement(actor *obj, SDL_Time curtimems)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "Null actor reference");
|
|
|
|
|
if ( obj->parent != NULL ) {
|
|
|
|
|
// Children don't move independently of their parents, they just have an offset
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
} else {
|
|
|
|
|
if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_LEFT) ) {
|
|
|
|
|
obj->x -= obj->basechar->vx;
|
|
|
|
|
}
|
|
|
|
|
if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_RIGHT) ) {
|
|
|
|
|
obj->x += obj->basechar->vx;
|
|
|
|
|
}
|
|
|
|
|
if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_UP) ) {
|
|
|
|
|
obj->y -= obj->basechar->vy;
|
|
|
|
|
}
|
|
|
|
|
if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_DOWN) ) {
|
|
|
|
|
obj->y += obj->basechar->vy;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext *actor_update(actor *obj)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
SDL_Time curtime = 0;
|
|
|
|
|
SDL_Time curtimems = 0;
|
|
|
|
|
sprite *curSprite = NULL;
|
|
|
|
|
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor reference");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj->basechar, ERR_NULLPOINTER, "Actor has NULL base character reference");
|
|
|
|
|
|
|
|
|
|
ATTEMPT {
|
|
|
|
|
SDL_GetCurrentTime(&curtime);
|
|
|
|
|
curtimems = curtime / 1000000;
|
|
|
|
|
CATCH(errctx, obj->facefunc(obj));
|
|
|
|
|
// is it time to apply movement logic?
|
|
|
|
|
if ( (curtimems - obj->logictimer) >= obj->basechar->movementspeed ) {
|
|
|
|
|
CATCH(errctx, obj->movementlogicfunc(obj, curtimems));
|
|
|
|
|
obj->logictimer = curtimems;
|
|
|
|
|
}
|
|
|
|
|
} CLEANUP {
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} FINISH(errctx, false);
|
|
|
|
|
|
|
|
|
|
ATTEMPT {
|
|
|
|
|
CATCH(errctx, character_sprite_get(obj->basechar, obj->state, &curSprite));
|
|
|
|
|
// is it time to change frames?
|
|
|
|
|
if ( (curtimems - obj->curSpriteFrameTimer) >= curSprite->speed ) {
|
|
|
|
|
CATCH(errctx, obj->changeframefunc(obj, curSprite, curtimems));
|
|
|
|
|
obj->curSpriteFrameTimer = curtimems;
|
|
|
|
|
}
|
|
|
|
|
} CLEANUP {
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} HANDLE(errctx, ERR_KEY) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
} FINISH(errctx, true);
|
|
|
|
|
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ErrorContext *actor_visible(actor *obj, SDL_FRect *camera, bool *visible)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
sprite *curSprite = NULL;
|
|
|
|
|
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, renderer, ERR_NULLPOINTER, "NULL renderer");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj->basechar, ERR_NULLPOINTER, "Actor has NULL base character reference");
|
|
|
|
|
|
|
|
|
|
ATTEMPT {
|
|
|
|
|
CATCH(errctx, character_sprite_get(obj->basechar, obj->state, &curSprite));
|
|
|
|
|
} CLEANUP {
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} HANDLE(errctx, ERR_KEY) {
|
|
|
|
|
// TODO: Actor has no sprite matching the current state. Should we treat this as an error and throw?
|
|
|
|
|
*visible = false;
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
} FINISH(errctx, true);
|
|
|
|
|
|
|
|
|
|
if ( (obj->x < (camera->x - curSprite->width)) ||
|
|
|
|
|
(obj->x > (camera->x + camera->w)) ||
|
|
|
|
|
(obj->y < (camera->y - curSprite->height)) ||
|
|
|
|
|
(obj->y > (camera->y + camera->h)) ) {
|
|
|
|
|
*visible = false;
|
|
|
|
|
} else {
|
|
|
|
|
*visible = obj->visible;
|
|
|
|
|
}
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext *actor_render(actor *obj, SDL_Renderer *renderer)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
sprite *curSprite = NULL;
|
|
|
|
|
bool visible = false;
|
|
|
|
|
SDL_FRect src;
|
|
|
|
|
SDL_FRect dest;
|
|
|
|
|
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, renderer, ERR_NULLPOINTER, "NULL renderer");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj->basechar, ERR_NULLPOINTER, "Actor has NULL base character reference");
|
|
|
|
|
|
|
|
|
|
ATTEMPT {
|
|
|
|
|
CATCH(errctx, character_sprite_get(obj->basechar, obj->state, &curSprite));
|
|
|
|
|
CATCH(errctx, actor_visible(obj, &camera, &visible));
|
|
|
|
|
} CLEANUP {
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} HANDLE(errctx, ERR_KEY) {
|
2025-08-09 08:54:12 -04:00
|
|
|
} HANDLE_GROUP(errctx, ERR_OUTOFBOUNDS) {
|
2025-08-03 10:07:35 -04:00
|
|
|
// If an actor doesn't have a sprite for a state, just log it and move on
|
|
|
|
|
LOG_ERROR(errctx);
|
|
|
|
|
} FINISH(errctx, true);
|
|
|
|
|
|
|
|
|
|
if ( ! visible ) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
2025-08-09 08:54:12 -04:00
|
|
|
if ( (obj->curSpriteFrameId > curSprite->frames) ) {
|
|
|
|
|
// This isn't necessarily an error - this actor's frame index is outside the range of
|
|
|
|
|
// their current sprite. There are a number of reasons this could happen, and it will
|
|
|
|
|
// get cleaned up on the next logic update. Just pass on rendering them this frame.
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
2025-08-03 10:07:35 -04:00
|
|
|
|
|
|
|
|
src.x = curSprite->width * curSprite->frameids[obj->curSpriteFrameId];
|
|
|
|
|
if ( src.x >= curSprite->sheet->texture->w ) {
|
|
|
|
|
src.y = ((int)src.x / curSprite->sheet->texture->w) * curSprite->height;
|
|
|
|
|
src.x = ((int)src.x % curSprite->sheet->texture->w);
|
|
|
|
|
} else {
|
|
|
|
|
src.y = 0;
|
|
|
|
|
}
|
|
|
|
|
src.w = curSprite->width;
|
|
|
|
|
src.h = curSprite->height;
|
|
|
|
|
if ( obj->parent != NULL ) {
|
|
|
|
|
dest.x = (obj->parent->x + obj->x - camera.x);
|
|
|
|
|
dest.y = (obj->parent->y + obj->y - camera.y);
|
|
|
|
|
} else {
|
|
|
|
|
dest.x = (obj->x - camera.x);
|
|
|
|
|
dest.y = (obj->y - camera.y);
|
|
|
|
|
}
|
|
|
|
|
dest.w = curSprite->width;
|
|
|
|
|
dest.h = curSprite->width;
|
|
|
|
|
|
|
|
|
|
SDL_RenderTexture(renderer, curSprite->sheet->texture, &src, &dest);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext *actor_add_child(actor *obj, actor *child)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL parent pointer");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, child, ERR_NULLPOINTER, "NULL child pointer");
|
|
|
|
|
|
|
|
|
|
FAIL_NONZERO_RETURN(errctx, child->parent, ERR_RELATIONSHIP, "Child object already has a parent");
|
|
|
|
|
for ( i = 0; i < ACTOR_MAX_CHILDREN ; i++ ) {
|
|
|
|
|
if ( obj->children[i] == NULL ) {
|
|
|
|
|
obj->children[i] = child;
|
|
|
|
|
child->parent = obj;
|
|
|
|
|
child->refcount += 1;
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
FAIL_RETURN(errctx, ERR_OUTOFBOUNDS, "Parent object has no remaining child slots left");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
void registry_iterate_actor(void *userdata, SDL_PropertiesID registry, const char *name)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
iterator *opflags = (iterator *)userdata;
|
|
|
|
|
|
|
|
|
|
ATTEMPT {
|
|
|
|
|
FAIL_ZERO_BREAK(errctx, name, ERR_NULLPOINTER, "registry_iterate_actor received NULL property name");
|
|
|
|
|
FAIL_ZERO_BREAK(errctx, opflags, ERR_NULLPOINTER, "received NULL iterator flags");
|
|
|
|
|
actor *obj = (actor *)SDL_GetPointerProperty(registry, name, NULL);
|
|
|
|
|
FAIL_ZERO_BREAK(errctx, obj, ERR_KEY, "registry_iterate_actor received property name that was not in the registry");
|
|
|
|
|
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_LAYERMASK) ) {
|
|
|
|
|
if ( obj->layer != opflags->layerid ) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_UPDATE) ) {
|
|
|
|
|
CATCH(errctx, obj->updatefunc(obj));
|
|
|
|
|
}
|
|
|
|
|
if ( BITMASK_HAS(opflags->flags, ITERATOR_OP_RENDER) ) {
|
|
|
|
|
CATCH(errctx, obj->renderfunc(obj, renderer));
|
|
|
|
|
}
|
|
|
|
|
} CLEANUP {
|
|
|
|
|
} PROCESS(errctx) {
|
|
|
|
|
} FINISH_NORETURN(errctx);
|
|
|
|
|
}
|
2025-08-08 22:39:48 -04:00
|
|
|
|
|
|
|
|
ErrorContext ERROR_NOIGNORE *SDL3GActor_cmhf_left_on(actor *obj, SDL_Event *event)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, event, ERR_NULLPOINTER, "NULL event");
|
|
|
|
|
if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_LEFT) ) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
SDL_Log("event %d (button %d / key %d) moves actor left", event->type, event->gbutton.which, event->key.key);
|
|
|
|
|
BITMASK_DEL(obj->state, (ACTOR_STATE_FACE_ALL | ACTOR_STATE_MOVING_ALL));
|
|
|
|
|
BITMASK_ADD(obj->state, (ACTOR_STATE_MOVING_LEFT | ACTOR_STATE_FACE_LEFT));
|
|
|
|
|
SDL_Log("new target actor state: %b", obj->state);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext ERROR_NOIGNORE *SDL3GActor_cmhf_left_off(actor *obj, SDL_Event *event)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, event, ERR_NULLPOINTER, "NULL event");
|
|
|
|
|
if ( !BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_LEFT) ) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
SDL_Log("event %d (button %d / key %d) stops moving actor left", event->type, event->gbutton.which, event->key.key);
|
|
|
|
|
BITMASK_DEL(obj->state, (ACTOR_STATE_FACE_ALL | ACTOR_STATE_MOVING_ALL));
|
|
|
|
|
BITMASK_ADD(obj->state, ACTOR_STATE_FACE_LEFT);
|
|
|
|
|
SDL_Log("new target actor state: %b", obj->state);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext ERROR_NOIGNORE *SDL3GActor_cmhf_right_on(actor *obj, SDL_Event *event)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, event, ERR_NULLPOINTER, "NULL event");
|
|
|
|
|
if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_RIGHT) ) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
SDL_Log("event %d (button %d / key %d) moves actor right", event->type, event->gbutton.which, event->key.key);
|
|
|
|
|
BITMASK_DEL(obj->state, (ACTOR_STATE_FACE_ALL | ACTOR_STATE_MOVING_ALL));
|
|
|
|
|
BITMASK_ADD(obj->state, (ACTOR_STATE_MOVING_RIGHT | ACTOR_STATE_FACE_RIGHT));
|
|
|
|
|
SDL_Log("new target actor state: %b", obj->state);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext ERROR_NOIGNORE *SDL3GActor_cmhf_right_off(actor *obj, SDL_Event *event)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, event, ERR_NULLPOINTER, "NULL event");
|
|
|
|
|
if ( !BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_RIGHT) ) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
SDL_Log("event %d (button %d / key %d) stops moving actor right", event->type, event->gbutton.which, event->key.key);
|
|
|
|
|
BITMASK_DEL(obj->state, (ACTOR_STATE_FACE_ALL | ACTOR_STATE_MOVING_ALL));
|
|
|
|
|
BITMASK_ADD(obj->state, ACTOR_STATE_FACE_RIGHT);
|
|
|
|
|
SDL_Log("new target actor state: %b", obj->state);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext ERROR_NOIGNORE *SDL3GActor_cmhf_up_on(actor *obj, SDL_Event *event)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, event, ERR_NULLPOINTER, "NULL event");
|
|
|
|
|
if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_UP) ) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
SDL_Log("event %d (button %d / key %d) moves actor up", event->type, event->gbutton.which, event->key.key);
|
|
|
|
|
BITMASK_DEL(obj->state, (ACTOR_STATE_FACE_ALL | ACTOR_STATE_MOVING_ALL));
|
|
|
|
|
BITMASK_ADD(obj->state, (ACTOR_STATE_FACE_UP | ACTOR_STATE_MOVING_UP));
|
|
|
|
|
SDL_Log("new target actor state: %b", obj->state);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext ERROR_NOIGNORE *SDL3GActor_cmhf_up_off(actor *obj, SDL_Event *event)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, event, ERR_NULLPOINTER, "NULL event");
|
|
|
|
|
if ( !BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_UP) ) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
SDL_Log("event %d (button %d / key %d) stops moving actor up", event->type, event->gbutton.which, event->key.key);
|
|
|
|
|
BITMASK_DEL(obj->state, (ACTOR_STATE_FACE_ALL | ACTOR_STATE_MOVING_ALL));
|
|
|
|
|
BITMASK_ADD(obj->state, ACTOR_STATE_FACE_UP);
|
|
|
|
|
SDL_Log("new target actor state: %b", obj->state);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext ERROR_NOIGNORE *SDL3GActor_cmhf_down_on(actor *obj, SDL_Event *event)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, event, ERR_NULLPOINTER, "NULL event");
|
|
|
|
|
if ( BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_DOWN) ) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
SDL_Log("event %d (button %d / key %d) moves actor down", event->type, event->gbutton.which, event->key.key);
|
|
|
|
|
BITMASK_DEL(obj->state, (ACTOR_STATE_FACE_ALL | ACTOR_STATE_MOVING_ALL));
|
|
|
|
|
BITMASK_ADD(obj->state, (ACTOR_STATE_MOVING_DOWN | ACTOR_STATE_FACE_DOWN));
|
|
|
|
|
SDL_Log("new target actor state: %b", obj->state);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErrorContext ERROR_NOIGNORE *SDL3GActor_cmhf_down_off(actor *obj, SDL_Event *event)
|
|
|
|
|
{
|
|
|
|
|
PREPARE_ERROR(errctx);
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, obj, ERR_NULLPOINTER, "NULL actor");
|
|
|
|
|
FAIL_ZERO_RETURN(errctx, event, ERR_NULLPOINTER, "NULL event");
|
|
|
|
|
if ( !BITMASK_HAS(obj->state, ACTOR_STATE_MOVING_DOWN) ) {
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|
|
|
|
|
SDL_Log("event %d (button %d / key %d) stops moving actor down", event->type, event->gbutton.which, event->key.key);
|
|
|
|
|
BITMASK_DEL(obj->state, (ACTOR_STATE_FACE_ALL | ACTOR_STATE_MOVING_ALL));
|
|
|
|
|
BITMASK_ADD(obj->state, ACTOR_STATE_FACE_DOWN);
|
|
|
|
|
SDL_Log("new target actor state: %b", obj->state);
|
|
|
|
|
SUCCEED_RETURN(errctx);
|
|
|
|
|
}
|