home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************
- * spr_anim.c
- *
- * Routines for automatic sprite animation and movement.
- **********************************************************************
- This file is part of
-
- STK -- The sprite toolkit -- version 1.1
-
- Copyright (C) Jari Karjala 1991
-
- The sprite toolkit (STK) is a FreeWare toolkit for creating high
- resolution sprite graphics with PCompatible hardware. This toolkit
- is provided as is without any warranty or such thing. See the file
- COPYING for further information.
-
- **********************************************************************/
-
- #include <alloc.h>
- #include <stdarg.h>
-
- #include "gr.h"
- #include "spr_aniP.h"
- #include "spr_anim.h"
- #include "spr.h"
- #include "spr_hit.h"
-
- #define STATE_NORMAL 0
- #define STATE_DELETE 1
- #define STATE_DESTROY 2
-
- /**********************************************************************
- * The list of all animated sprites
- **********************************************************************/
- static ANIM_SPRITE anim_sprites = NULL;
-
-
- /**********************************************************************
- * The default fx handler. TIMEOUT & HIT_SPRITE deletes, LIMITs bounce.
- **********************************************************************/
- WORD static default_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
- {
- ANIM_SPR_INFO *asi;
- WORD ret_code;
-
- asi = spr_anim_get_info(aspr);
-
- switch (fx) {
- case SPR_ANIM_FX_TIMEOUT:
- ret_code = SPR_ANIM_FX_RET_DELETE;
- break;
-
- case SPR_ANIM_FX_HIT_X_LIMIT:
- if (asi->x > asi->rig) {
- spr_anim_set_location(aspr, asi->rig, asi->y);
- spr_anim_set_vector(aspr, -asi->dx, asi->dy);
- }
- else {
- spr_anim_set_location(aspr, asi->lef, asi->y);
- spr_anim_set_vector(aspr, -asi->dx, asi->dy);
- }
- ret_code = SPR_ANIM_FX_RET_RE_PUT;
-
- break;
-
- case SPR_ANIM_FX_HIT_Y_LIMIT:
- if (asi->y > asi->bot) {
- spr_anim_set_location(aspr, asi->x, asi->bot);
- spr_anim_set_vector(aspr, asi->dx, -asi->dy);
- }
- else {
- spr_anim_set_location(aspr, asi->x, asi->top);
- spr_anim_set_vector(aspr, asi->dx, -asi->dy);
- }
- ret_code = SPR_ANIM_FX_RET_RE_PUT;
-
- break;
-
- case SPR_ANIM_FX_HIT_SPRITE:
- ret_code = SPR_ANIM_FX_RET_DELETE;
- break;
-
- default:
- ret_code = SPR_ANIM_FX_RET_DELETE;
- }
- return ret_code;
- }
-
- /**********************************************************************
- * Create an animated sprite from the given simple sprites.
- * The sprites must have the same width and height attributes.
- * Set the following defaults:
- * x,y = 0,0
- * dx,dy = 0,0
- * lef,top,rig,bot = 0,0,gr_max_x,gr_max_y
- * frame_delay, timeout = 0,0
- * fx_mode = FX_ALL
- * fx_handler = default_fx_handler
- *
- * count The number of simple sprites
- * ... The simple sprites to use for animation (objects of type SPRITE)
- *
- * Return: ANIM_SPRITE if no errors or
- * NULL if memory allocation error, count>ANIM_SPRITE_MAX
- * or ... contains NULL
- **********************************************************************/
- ANIM_SPRITE spr_anim_create(WORD count, ...)
- {
- ANIM_SPRITE aspr;
- va_list sprites;
- int i, err;
-
- if (count==0 || count>ANIM_SPRITE_MAX)
- return NULL;
-
- if ((aspr=(ANIM_SPRITE)calloc(1,sizeof(struct _anim_sprite)))==NULL)
- return NULL;
-
- va_start(sprites, count);
- for (i = err = 0; i < count && !err; i++) {
- aspr->sprites[i] = va_arg(sprites, SPRITE);
- err = (aspr->sprites[i]==NULL);
- }
- va_end(sprites);
-
- if (err) {
- /** some simple sprite was NULL, free and return NULL **/
- free(aspr);
- return NULL;
- }
-
- /** set defaults fx handler and limits **/
- spr_anim_set_fx_handler(aspr, SPR_ANIM_FX_ALL, default_fx_handler);
- spr_anim_set_limits(aspr, 0, 0, gr_max_x, gr_max_y);
-
- aspr->spr_count = count;
-
- /** add it to the chain **/
- aspr->next = anim_sprites;
- anim_sprites = aspr;
-
- return aspr;
- }
-
- /**********************************************************************
- * Start the sprite animation.
- *
- * aspr The animated sprite to use
- **********************************************************************/
- void spr_anim_start(ANIM_SPRITE aspr)
- {
- aspr->active = 1;
- aspr->state = STATE_NORMAL;
- }
-
- /**********************************************************************
- * Stop the animation of the given sprite. This means that this sprite
- * will not be shown nor updated any more.
- *
- * aspr The animated sprite to stop
- **********************************************************************/
- void spr_anim_stop(ANIM_SPRITE aspr)
- {
- spr_hide(aspr->sprites[aspr->spr_index]);
- aspr->active = 0;
- }
-
- /**********************************************************************
- * Remove the given sprite from the anim_sprites list
- **********************************************************************/
- static void remove_from_anim_sprites(ANIM_SPRITE aspr)
- {
- ANIM_SPRITE as;
-
- as = anim_sprites;
- if (as == aspr)
- anim_sprites = aspr->next;
- else
- while (as!=NULL) {
- if (as->next == aspr)
- as->next = aspr->next;
- as = as->next;
- }
- }
-
- /**********************************************************************
- * Delete the given animated sprite. The simple sprites it contains are
- * NOT deleted.
- *
- * aspr The animated sprite to use
- **********************************************************************/
- void spr_anim_delete(ANIM_SPRITE aspr)
- {
- spr_hide(aspr->sprites[aspr->spr_index]);
-
- aspr->active = 0;
- aspr->state = STATE_DELETE;
- }
-
- /**********************************************************************
- * Delete the given animated sprite. The simple sprites it contains are
- * ALSO deleted.
- *
- * aspr The animated sprite to destroy
- **********************************************************************/
- void spr_anim_destroy(ANIM_SPRITE aspr)
- {
- spr_hide(aspr->sprites[aspr->spr_index]);
-
- aspr->active = 0;
- aspr->state = STATE_DESTROY;
- }
-
- /**********************************************************************
- * Handle the return code from fx handler
- **********************************************************************/
- void static handle_ret_code(ANIM_SPRITE as, WORD ret_code)
- {
- switch (ret_code) {
- case SPR_ANIM_FX_RET_RE_PUT:
- spr_hide(as->sprites[as->spr_index]);
- spr_put(as->sprites[as->spr_index], as->x, as->y);
- break;
- case SPR_ANIM_FX_RET_STOP:
- spr_hide(as->sprites[as->spr_index]);
- as->active = 0;
- break;
- case SPR_ANIM_FX_RET_DELETE:
- spr_anim_delete(as);
- break;
- case SPR_ANIM_FX_RET_DESTROY:
- spr_anim_destroy(as);
- break;
- default:
- break;
- }
- }
-
- /**********************************************************************
- * Call the handler if defined, otherwise return DESTROY
- **********************************************************************/
- #define FX_HANDLER(aspr, fx, spr) ((aspr)->fx_handler==NULL \
- ? SPR_ANIM_FX_RET_DESTROY \
- : (aspr)->fx_handler(aspr, fx, spr));
-
- /**********************************************************************
- * Check the special effects for all sprites, call handlers
- * if defined and handle return codes & actions.
- *
- * aspr pointer to the start of sprite chain.
- **********************************************************************/
- void static do_fx(ANIM_SPRITE aspr)
- {
- ANIM_SPRITE as, as_next;
- SPRITE s;
- WORD ret_code;
-
- as = aspr;
- while (as!=NULL) {
- as_next = as->next; /** save next, since action may delete as **/
-
- if (as->active && as->fx_mode) {
- /***** Call handler for each requested effect and *****/
- /***** interpret the return code and act as requested. *****/
- ret_code = SPR_ANIM_FX_RET_NOTHING;
-
- if (as->fx_mode & SPR_ANIM_FX_TIMEOUT)
- if (as->timeout_count==1) {
- ret_code = FX_HANDLER(as, SPR_ANIM_FX_TIMEOUT, NULL);
- handle_ret_code(as, ret_code);
- }
-
- if (ret_code!=SPR_ANIM_FX_RET_DELETE
- && ret_code!=SPR_ANIM_FX_RET_DESTROY
- && (as->fx_mode & SPR_ANIM_FX_HIT_X_LIMIT))
- if (as->x < as->lef || as->x > as->rig) {
- ret_code = FX_HANDLER(as, SPR_ANIM_FX_HIT_X_LIMIT, NULL);
- handle_ret_code(as, ret_code);
- }
-
- if (ret_code!=SPR_ANIM_FX_RET_DELETE
- && ret_code!=SPR_ANIM_FX_RET_DESTROY
- && (as->fx_mode & SPR_ANIM_FX_HIT_Y_LIMIT))
- if (as->y < as->top || as->y > as->bot) {
- ret_code = FX_HANDLER(as, SPR_ANIM_FX_HIT_Y_LIMIT, NULL);
- handle_ret_code(as, ret_code);
- }
-
- if (ret_code!=SPR_ANIM_FX_RET_DELETE
- && ret_code!=SPR_ANIM_FX_RET_DESTROY
- && (as->fx_mode & SPR_ANIM_FX_HIT_SPRITE)) {
- s = spr_hit_first(as->sprites[as->spr_index]);
- if (s!=NULL) {
- ret_code = FX_HANDLER(as, SPR_ANIM_FX_HIT_SPRITE, s);
- handle_ret_code(as, ret_code);
- }
- }
- }
- as = as_next;
- }
- }
-
- /**********************************************************************
- * spr_put all animated sprites then check for special effects (call
- * fx_handler(s) if necessary, and act according to the return values).
- * Call spr_next_pass and after that update frame indices and locations
- * of all animated sprites.
- *
- * Return: The current visual page
- **********************************************************************/
- WORD spr_anim_next_pass(void)
- {
- WORD visual_page;
- ANIM_SPRITE as,as1;
- int i;
-
- /** put all sprites **/
- as = anim_sprites;
- while (as!=NULL) {
- if (as->active)
- spr_put(as->sprites[as->spr_index], as->x, as->y);
- as = as->next;
- }
-
- /** check & handle fx for all sprites **/
- do_fx(anim_sprites);
-
- /** Now it is safe to actually delete or destroy animated sprites **/
- as = anim_sprites;
- while (as!=NULL) {
- if (as->state!=STATE_NORMAL) {
- as1 = as->next;
- remove_from_anim_sprites(as);
- if (as->state==STATE_DESTROY)
- for (i=0; i < as->spr_count; i++)
- spr_delete(as->sprites[i]);
- free(as);
- as = as1;
- }
- else
- as = as->next;
- }
-
- visual_page = spr_next_pass();
-
- /** Increment sprite index, decrement timeout and move sprite **/
- as = anim_sprites;
- while (as!=NULL) {
- if (as->active) {
- if (as->frame_delay>0) /** animation in use **/
- if (as->delay_count==0) {
- /** delay inspired, reset it and change index **/
- as->delay_count = as->frame_delay-1;
- if (as->spr_index < as->spr_count-1)
- as->spr_index++;
- else
- as->spr_index = 0;
- }
- else
- as->delay_count--;
-
- if (as->timeout_count > 1)
- as->timeout_count--;
-
- as->x += as->dx;
- as->y += as->dy;
- }
- as = as->next;
- }
- return visual_page;
- }
-
-
-
- /**********************************************************************
- * Return a pointer into a static info structure of the sprite.
- * Note: the structure is only a copy which is overwritten by the
- * next call to this function.
- **********************************************************************/
- ANIM_SPR_INFO *spr_anim_get_info(ANIM_SPRITE aspr)
- {
- static ANIM_SPR_INFO asi;
-
- asi.x = aspr->x;
- asi.y = aspr->y;
- asi.dx = aspr->dx;
- asi.dy = aspr->dy;
- asi.lef = aspr->lef;
- asi.top = aspr->top;
- asi.rig = aspr->rig;
- asi.bot = aspr->bot;
- asi.frame = aspr->spr_index;
- asi.frame_delay = aspr->frame_delay;
- asi.timeout = aspr->timeout_count;
- asi.id = aspr->sprites[aspr->spr_index]->id;
- asi.h = aspr->sprites[aspr->spr_index]->hp;
- asi.w = aspr->sprites[aspr->spr_index]->wp;
-
- return &asi;
- }
-
- /**********************************************************************
- * Set the location of the animated sprite.
- **********************************************************************/
- void spr_anim_set_location(ANIM_SPRITE aspr, WORD x, WORD y)
- {
- aspr->x = x;
- aspr->y = y;
- }
-
- /**********************************************************************
- * Set the movement vector of the animated sprite.
- **********************************************************************/
- void spr_anim_set_vector(ANIM_SPRITE aspr, int dx, int dy)
- {
- aspr->dx = dx;
- aspr->dy = dy;
- }
-
- /**********************************************************************
- * Set the limits for the animated sprite. Note again, that all
- * simple sprites belonging to the animated sprite must have the
- * same width & heigth.
- **********************************************************************/
- void spr_anim_set_limits(ANIM_SPRITE aspr,
- WORD lef, WORD top, WORD rig, WORD bot)
- {
- aspr->top = top;
- aspr->bot = bot - aspr->sprites[0]->hp;
- aspr->lef = lef;
- aspr->rig = rig - aspr->sprites[0]->wp;
- }
-
- /**********************************************************************
- * Set the frame delay and timeout values. (-1 means no change for
- * that value).
- *
- * IMPORTANT NOTE: The 'frame' MUST NOT be changed from an fx_handler!!
- *
- * frame The current animation frame number (0..nr of frames-1)
- * frame_delay The number of passes for each frame change (0=no change)
- * timeout The number of passes before timeout action (0=infinite)
- **********************************************************************/
- void spr_anim_set_time(ANIM_SPRITE aspr,
- int frame, int frame_delay, int timeout)
- {
- if (frame>=0 && frame<aspr->spr_count)
- aspr->spr_index = frame;
- if (frame_delay>=0)
- aspr->frame_delay = frame_delay;
- if (timeout>=0)
- aspr->timeout_count = timeout;
- }
-
- /**********************************************************************
- * Sets the special effects handler function.
- * The function should have the following prototype:
- * WORD func(ANIM_SPRITE aspr, WORD fx_type);
- * The aspr is the animated sprite and fx_type is the type of the
- * effect which caused this call. The function should return
- * one of the FX_RET values defined above.
- * A NULL handler means that all special effects cause spr_anim_delete.
- *
- * fx_mask The types of effects relayed to the handler.
- * fx_handler The handler function.
- **********************************************************************/
- void spr_anim_set_fx_handler(ANIM_SPRITE aspr,
- WORD fx_mask,
- WORD (fx_handler)(ANIM_SPRITE,WORD,SPRITE))
- {
- aspr->fx_mode = fx_mask;
- aspr->fx_handler = fx_handler;
- }
-
-