123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- #include "eruta.h"
- #include "mem.h"
- #include "sprite.h"
- #include "spritestate.h"
- #include "bad.h"
- #include "monolog.h"
- #include "callrb.h"
- /* Sprite state layer functions. */
- SpriteStateLayer * spritestatelayer_init_empty(SpriteStateLayer * me) {
- if (!me) return NULL;
- me->flags = 0;
- me->tint = al_map_rgba(1.0, 1.0, 1.0, 0.0);
- return me;
- }
- /* Sprite state action functions. */
- SpriteStateAction * spritestateaction_init_empty(SpriteStateAction * me) {
- if (!me) return NULL;
- me->done = FALSE;
- me->loop = SPRITESTATE_ACTION_LOOP;
- me->next_action = -1;
- return me;
- }
- /* Sprite state functions. */
- SpriteState * spritestate_alloc() {
- return STRUCT_ALLOC(SpriteState);
- }
- Sprite * spritestate_sprite_(SpriteState * self, Sprite * sprite) {
- int index;
- if(!self) return NULL;
- self->sprite = sprite;
- self->action_index = -1;
- self->action_now = NULL;
- self->frame_now = NULL;
- self->frame_index = -1;
- self->time = 0.0;
- self->pose_now = SPRITE_STAND;
- self->direction_now = SPRITE_ALL;
- /* No cleanup of sprite as it is not owned by the sprite state. */
- return self->sprite;
- }
- /* Clean up the sprite state.
- * No cleanup of the sprite itself since the Sprite * is owned by the sprite
- * list.
- */
- SpriteState * spritestate_done(SpriteState * self) {
- int index;
- return self;
- }
- SpriteState * spritestate_free(SpriteState * self) {
- spritestate_done(self);
- return mem_free(self);
- }
- Sprite * spritestate_sprite(SpriteState * self) {
- if(!self) return NULL;
- return self->sprite;
- }
- /** Thing is passed as a void data pointer to avoid dependencies. */
- SpriteState * spritestate_init(SpriteState * self, Sprite * sprite, void * data) {
- int index;
-
- if(!self) return NULL;
- spritestate_sprite_(self, sprite);
- self->speedup = 1.0;
-
- for (index = 0 ; index < SPRITESTATE_LAYER_MAX; index ++) {
- spritestatelayer_init_empty(self->layers + index);
- }
-
- for (index = 0 ; index < SPRITESTATE_ACTION_MAX; index ++) {
- spritestateaction_init_empty(self->actions + index);
- }
-
- self->data = data;
-
- return self;
- }
- void * spritestate_data(SpriteState * self) {
- if (!self) return NULL;
- return self->data;
- }
- double spritestate_speedup(SpriteState * self) {
- if (!self) return 0.0;
- return self->speedup;
- }
- double spritestate_speedup_(SpriteState * self, double speedup) {
- if (!self) return 0.0;
- return self->speedup = speedup;
- }
- SpriteState * spritestate_new(Sprite * sprite, void * data) {
- return spritestate_init(spritestate_alloc(), sprite, data);
- }
- /** Returns whether or not the sprite state can be drawn or not. */
- int spritestate_can_draw_p(SpriteState * self) {
- if (!self) return FALSE;
- if (!(self->frame_now)) return FALSE;
- return TRUE;
- }
- /* Draws the given layer of the sprite using the sprite state.
- */
- void spritestate_draw_frame(SpriteState * me, SpriteFrame * frame, Point * at)
- {
- int index, stop;
- SpriteCell * cell;
- Color * tint;
- if (!me) return;
- if (!frame) {
- /* Draw a red box to show the missing frame */
- al_draw_filled_rectangle(at->x, at->y, at->x+16, at->y+16, al_map_rgb(255, 64, 64));
- return;
- };
-
- al_hold_bitmap_drawing(true);
- stop = spriteframe_maxlayers(frame);
- for (index = 0; index < stop ; index++) {
- if ((BIT_ISFLAG(me->layers[index].flags, SPRITESTATE_LAYER_HIDDEN))) {
- continue; /* Skip invisible layers. */
- }
- cell = spriteframe_cell(frame, index);
- tint = spritestate_get_layer_tint(me, index);
- if (tint) {
- spritecell_draw_tinted(cell, at, (*tint));
- } else {
- spritecell_draw(cell, at);
- }
- }
- al_hold_bitmap_drawing(false);
- }
- /* Draw the SpriteState at the given location. This takes
- the current action, frame, layers and offsets into consideration. */
- void spritestate_draw(SpriteState * self, Point * at) {
- if (!self) return;
- if (!self->sprite) return;
- spritestate_draw_frame(self, self->frame_now, at);
- }
- /* Sets the spritestate's current action and current frame. Returns
- self if ok, NULL if out of bounds. */
- SpriteState *
- spritestate_now_(SpriteState * self, int actionnow, int framenow) {
- SpriteAction * action;
- SpriteFrame * frame;
- Sprite * sprite;
- if (!self) return NULL;
- sprite = self->sprite;
- if (!sprite) return NULL;
- if (bad_outofboundsi(actionnow, 0, sprite_maxactions(sprite))) return NULL;
- frame = sprite_frame(sprite, actionnow, framenow);
- if (!frame) { return NULL; }
- self->frame_index = framenow;
- self->action_index = actionnow;
- self->frame_now = frame;
- self->time = 0.0;
- return self;
- }
- /* Advances the frame of the sprite state if needed, depending on the
- * looping and stop mode.
- */
- void spritestate_next_frame(SpriteState * self) {
- int next = self->frame_index + 1;
- int action;
- int action_loop;
-
- /* Loop if needed. */
- if (next >= sprite_framesused(self->sprite, self->action_index)) {
- action_loop = spritestate_get_action_loop(self, self->action_index);
- /* It's a one-shot action. Do NOT cycle. */
- if (action_loop & SPRITESTATE_ACTION_ONESHOT) {
- /* If it's a stop action, leave it there, otherwise go back to standing pose. */
- if (action_loop & SPRITESTATE_ACTION_STOP) {
- /* First time at end of a one shot stop action... */
- if (!self->actions[self->action_index].done) {
- /* Notify scripting of end of this loop. */
- callrb_sprite_event(self, action_loop, NULL);
- /* Set action to done to prevent double emitting the event above. */
- self->actions[self->action_index].done = TRUE;
- }
- } else {
- /* Notify script side. */
- callrb_sprite_event(self, action_loop, NULL);
- /* Go to back to first frame of standing pose with current direction. */
- action = sprite_action_index_for
- (self->sprite, SPRITE_WALK, self->direction_now);
- spritestate_pose_(self, SPRITE_WALK);
- spritestate_now_(self, action, 0);
- /* Action to done. */
- self->actions[self->action_index].done = TRUE;
- }
- } else {
- /* Loop back to first frame.*/
- spritestate_now_(self, self->action_index, 0);
- /* Set action to not done. */
- self->actions[self->action_index].done = FALSE;
- }
- } else {
- /* Advance to next frame. */
- spritestate_now_(self, self->action_index, next);
- /* Set action to not done. */
- self->actions[self->action_index].done = FALSE;
- }
- }
- /* Updates the spritestate.
- * dt is the time passed since the last update in seconds (usuallu around 0.02). */
- void spritestate_update(SpriteState * self, double dt) {
- Sprite * sprite;
- if (!self) return;
- sprite = self->sprite;
- if (!sprite) return;
- if(!self->frame_now) {
- int x, y, w, h;
- LOG_LEVEL(__FILE__, "NULL current sprite frame!: %d\n", self->action_index);
- // try to restore back to first frame if out of whack somehow.
- spritestate_now_(self, self->action_index, 0);
- return;
- }
- self->time += (self->speedup * dt);
- if(self->time > spriteframe_duration(self->frame_now)) {
- spritestate_next_frame(self);
- }
- }
- /* Sets the spritestate's current pose and direction. Will reset the frame to 0.
- * Returns negative if the pose could not be found in this sprite;
- * Otherwise returns the index of the used sprite action.
- * Returns -2 without effect if the pose and direction are identical to the ones
- * currently set.
- */
- int spritestate_posedirection_(SpriteState * self, int pose, int direction) {
- int max, index;
- SpriteAction * action;
- Sprite * sprite;
- if (!self) return -1;
- sprite = self->sprite;
- if (!sprite) return -1;
- if ((self->pose_now == pose) && (self->direction_now == direction)) {
- /* Do nothing if the pose and ditr are not actually changed. */
- return -2;
- }
-
- self->pose_now = pose;
- self->direction_now = direction;
- max = sprite_maxactions(sprite);
- for (index = 0; index < max; index ++) {
- action = sprite_action(sprite, index);
- if (spriteaction_matches_pose(action, pose, direction)) {
- spritestate_now_(self, index, 0);
- return index;
- }
- }
- return -1;
- }
- /* Changes the direction but keeps the pose.
- * No effect if direction is the current active one.*/
- int spritestate_direction_(SpriteState * self, int direction) {
- if (!self) return -1;
- return spritestate_posedirection_(self, self->pose_now, direction);
- }
- /* Changes the pose but keeps the direction.
- * No effect if pose is the current active one.
- */
- int spritestate_pose_(SpriteState * self, int pose) {
- if (!self) return -1;
- return spritestate_posedirection_(self, pose, self->direction_now);
- }
- /* Returns true if the layer or self are out of bounds, false if not. */
- int spritestate_is_bad_layer(SpriteState * self, int layer) {
- if (!self) return TRUE;
- if (layer < 0) return TRUE;
- if (layer > SPRITESTATE_LAYER_MAX) return TRUE;
- return FALSE;
- }
- /* Returns the current active pose of the sprite state.*/
- int spritestate_pose(SpriteState * self) {
- if (!self) return SPRITE_STAND;
- return self->pose_now;
- }
- /* Returns the current active direction of the sprite state.*/
- int spritestate_direction(SpriteState * self) {
- if (!self) return SPRITE_NO_DIRECTION;
- return self->direction_now;
- }
- /* Sets the tint color for a layer of the sprite. */
- int spritestate_tint_layer(SpriteState * self, int layer, Color color) {
- if (spritestate_is_bad_layer(self, layer)) return -1;
- self->layers[layer].tint = color;
- self->layers[layer].flags = BIT_SETFLAG(self->layers[layer].flags, SPRITESTATE_LAYER_TINTED);
- return layer;
- }
- /** Unsets the tint color for a layer of the sprite. */
- int spritestate_remove_tint_layer(SpriteState * self, int layer) {
- if (!spritestate_is_layer_tinted(self, layer)) return -1;
- self->layers[layer].flags = BIT_UNFLAG(self->layers[layer].flags, SPRITESTATE_LAYER_TINTED);
- return layer;
- }
- /** Returns TRUE if the layer of the sprite is tinted, FALSE if not. */
- int spritestate_is_layer_tinted(SpriteState * self, int layer) {
- if (spritestate_is_bad_layer(self, layer)) return FALSE;
- if (!(BIT_ISFLAG(self->layers[layer].flags, SPRITESTATE_LAYER_TINTED)))
- return FALSE;
- return TRUE;
- }
- /** Returns apointer to the tint of the layer or NULL if not tinted or
- * if the layer is out of bounds. */
- Color * spritestate_get_layer_tint(SpriteState * self, int layer) {
- if (!spritestate_is_layer_tinted(self, layer)) return NULL;
- return &(self->layers[layer].tint);
- }
- /** Hides or unhides the given layer of the sprite. */
- int spritestate_set_layer_hidden(SpriteState * self, int layer, int hidden) {
- if (hidden) {
- self->layers[layer].flags = BIT_SETFLAG(self->layers[layer].flags, SPRITESTATE_LAYER_HIDDEN);
- } else {
- self->layers[layer].flags = BIT_UNFLAG(self->layers[layer].flags, SPRITESTATE_LAYER_HIDDEN);
- }
- return spritestate_get_layer_hidden(self, layer);
- }
- /** Returns true if the sprite's layer is hidden false if not. */
- int spritestate_get_layer_hidden(SpriteState * self, int layer) {
- if (spritestate_is_bad_layer(self, layer)) return TRUE;
- return ((BIT_ISFLAG(self->layers[layer].flags, SPRITESTATE_LAYER_HIDDEN)));
- }
- /* Returns true if the action or self are out of bounds, false if not. */
- int spritestate_is_bad_action(SpriteState * self, int action) {
- if (!self) return TRUE;
- if (action < 0) return TRUE;
- if (action > SPRITESTATE_ACTION_MAX) return TRUE;
- return FALSE;
- }
- /** Sets the loop mode for the given action of the sprite. */
- int spritestate_set_action_loop(SpriteState * self, int action, int loopmode) {
- if (spritestate_is_bad_action(self, action)) return -1;
- self->actions[action].loop = loopmode;
- return self->actions[action].loop;
- }
- /** Gets the loop mode for the given action of the sprite. */
- int spritestate_get_action_loop(SpriteState * self, int action) {
- if (spritestate_is_bad_action(self, action)) return -1;
- return self->actions[action].loop;
- }
- /** Returns true if the last set action is done, false if not. */
- int spritestate_is_action_done(SpriteState * self, int action) {
- if (spritestate_is_bad_action(self, action)) return -1;
- return self->actions[action].done;
- }
- /** Sets the loop mode for the given pose and direction of the sprite. */
- int spritestate_set_pose_direction_loop
- (SpriteState * self, int pose, int direction, int loopmode) {
- int action = sprite_action_index_for(self->sprite, pose, direction);
- return spritestate_set_action_loop(self, action, loopmode);
- }
- /** Sets the loop mode for the given pose and direction of the sprite. */
- int spritestate_get_pose_direction_loop
- (SpriteState * self, int pose, int direction) {
- int action = sprite_action_index_for(self->sprite, pose, direction);
- return spritestate_get_action_loop(self, action);
- }
|