home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / progrmng / stk110.lzh / STKSRC.COM / SPR_ANIM.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-25  |  15.8 KB  |  475 lines

  1. /**********************************************************************
  2. * spr_anim.c
  3. * Routines for automatic sprite animation and movement.
  4. **********************************************************************
  5.                     This file is part of
  6.  
  7.           STK -- The sprite toolkit -- version 1.1
  8.  
  9.               Copyright (C) Jari Karjala 1991
  10.  
  11. The sprite toolkit (STK) is a FreeWare toolkit for creating high
  12. resolution sprite graphics with PCompatible hardware. This toolkit 
  13. is provided as is without any warranty or such thing. See the file
  14. COPYING for further information.
  15.  
  16. **********************************************************************/
  17.  
  18. #include <alloc.h>
  19. #include <stdarg.h>
  20.  
  21. #include "gr.h"
  22. #include "spr_aniP.h"
  23. #include "spr_anim.h"
  24. #include "spr.h"
  25. #include "spr_hit.h"
  26.  
  27. #define STATE_NORMAL   0
  28. #define STATE_DELETE   1
  29. #define STATE_DESTROY  2
  30.  
  31. /**********************************************************************
  32. * The list of all animated sprites
  33. **********************************************************************/
  34. static ANIM_SPRITE anim_sprites = NULL;
  35.  
  36.  
  37. /**********************************************************************
  38. * The default fx handler. TIMEOUT & HIT_SPRITE deletes, LIMITs bounce.
  39. **********************************************************************/
  40. WORD static default_fx_handler(ANIM_SPRITE aspr, WORD fx, SPRITE spr)
  41. {
  42.     ANIM_SPR_INFO *asi;
  43.     WORD ret_code;
  44.  
  45.     asi = spr_anim_get_info(aspr);
  46.  
  47.     switch (fx) {
  48.         case SPR_ANIM_FX_TIMEOUT:
  49.             ret_code = SPR_ANIM_FX_RET_DELETE;
  50.             break;
  51.             
  52.         case SPR_ANIM_FX_HIT_X_LIMIT:
  53.             if (asi->x > asi->rig) {
  54.                 spr_anim_set_location(aspr, asi->rig, asi->y);
  55.                 spr_anim_set_vector(aspr, -asi->dx, asi->dy);
  56.             }
  57.             else {
  58.                 spr_anim_set_location(aspr, asi->lef, asi->y);
  59.                 spr_anim_set_vector(aspr, -asi->dx, asi->dy);
  60.             }
  61.             ret_code = SPR_ANIM_FX_RET_RE_PUT;
  62.                 
  63.             break;
  64.  
  65.         case SPR_ANIM_FX_HIT_Y_LIMIT:
  66.             if (asi->y > asi->bot) {
  67.                 spr_anim_set_location(aspr, asi->x, asi->bot);
  68.                 spr_anim_set_vector(aspr, asi->dx, -asi->dy);
  69.             }
  70.             else {
  71.                 spr_anim_set_location(aspr, asi->x, asi->top);
  72.                 spr_anim_set_vector(aspr, asi->dx, -asi->dy);
  73.             }
  74.             ret_code = SPR_ANIM_FX_RET_RE_PUT;
  75.  
  76.             break;
  77.  
  78.         case SPR_ANIM_FX_HIT_SPRITE:
  79.             ret_code = SPR_ANIM_FX_RET_DELETE;
  80.             break;
  81.             
  82.         default:
  83.             ret_code = SPR_ANIM_FX_RET_DELETE;
  84.     }
  85.     return ret_code;
  86. }
  87.  
  88. /**********************************************************************
  89. * Create an animated sprite from the given simple sprites.
  90. * The sprites must have the same width and height attributes.
  91. * Set the following defaults:
  92. *   x,y = 0,0
  93. *   dx,dy = 0,0
  94. *   lef,top,rig,bot = 0,0,gr_max_x,gr_max_y
  95. *   frame_delay, timeout = 0,0
  96. *   fx_mode = FX_ALL 
  97. *   fx_handler = default_fx_handler
  98. *
  99. * count The number of simple sprites
  100. * ...   The simple sprites to use for animation (objects of type SPRITE)
  101. *
  102. * Return: ANIM_SPRITE if no errors or 
  103. *          NULL if memory allocation error, count>ANIM_SPRITE_MAX 
  104. *           or ... contains NULL
  105. **********************************************************************/
  106. ANIM_SPRITE spr_anim_create(WORD count, ...)
  107. {
  108.     ANIM_SPRITE aspr;
  109.     va_list sprites;
  110.     int i, err;
  111.  
  112.     if (count==0 || count>ANIM_SPRITE_MAX)
  113.         return NULL;
  114.     
  115.     if ((aspr=(ANIM_SPRITE)calloc(1,sizeof(struct _anim_sprite)))==NULL)
  116.         return NULL;
  117.     
  118.     va_start(sprites, count);
  119.     for (i = err = 0; i < count && !err; i++) {
  120.         aspr->sprites[i] = va_arg(sprites, SPRITE);
  121.         err = (aspr->sprites[i]==NULL);
  122.     }
  123.     va_end(sprites);
  124.     
  125.     if (err) {
  126.         /** some simple sprite was NULL, free and return NULL **/
  127.         free(aspr);
  128.         return NULL;
  129.     }
  130.     
  131.     /** set defaults fx handler and limits **/
  132.     spr_anim_set_fx_handler(aspr, SPR_ANIM_FX_ALL, default_fx_handler);
  133.     spr_anim_set_limits(aspr, 0, 0, gr_max_x, gr_max_y);
  134.  
  135.     aspr->spr_count = count;
  136.         
  137.     /** add it to the chain **/
  138.     aspr->next = anim_sprites;
  139.     anim_sprites = aspr;
  140.         
  141.     return aspr;
  142. }
  143.  
  144. /**********************************************************************
  145. * Start the sprite animation. 
  146. *
  147. * aspr  The animated sprite to use
  148. **********************************************************************/
  149. void spr_anim_start(ANIM_SPRITE aspr)
  150. {
  151.     aspr->active = 1;
  152.     aspr->state = STATE_NORMAL;
  153. }
  154.  
  155. /**********************************************************************
  156. * Stop the animation of the given sprite. This means that this sprite 
  157. * will not be shown nor updated any more.
  158. *
  159. * aspr  The animated sprite to stop
  160. **********************************************************************/
  161. void spr_anim_stop(ANIM_SPRITE aspr)
  162. {
  163.     spr_hide(aspr->sprites[aspr->spr_index]);
  164.     aspr->active = 0;
  165. }
  166.  
  167. /**********************************************************************
  168. * Remove the given sprite from the anim_sprites list 
  169. **********************************************************************/
  170. static void remove_from_anim_sprites(ANIM_SPRITE aspr)
  171. {
  172.     ANIM_SPRITE as;
  173.  
  174.     as = anim_sprites;
  175.     if (as == aspr)
  176.         anim_sprites = aspr->next;
  177.     else
  178.         while (as!=NULL) {
  179.             if (as->next == aspr)
  180.                 as->next = aspr->next;
  181.             as = as->next;
  182.         }
  183. }
  184.  
  185. /**********************************************************************
  186. * Delete the given animated sprite. The simple sprites it contains are 
  187. * NOT deleted.
  188. *
  189. * aspr  The animated sprite to use
  190. **********************************************************************/
  191. void spr_anim_delete(ANIM_SPRITE aspr)
  192. {
  193.     spr_hide(aspr->sprites[aspr->spr_index]);
  194.     
  195.     aspr->active = 0;
  196.     aspr->state = STATE_DELETE;
  197. }
  198.  
  199. /**********************************************************************
  200. * Delete the given animated sprite. The simple sprites it contains are 
  201. * ALSO deleted.
  202. *
  203. * aspr  The animated sprite to destroy
  204. **********************************************************************/
  205. void spr_anim_destroy(ANIM_SPRITE aspr)
  206. {
  207.     spr_hide(aspr->sprites[aspr->spr_index]);
  208.     
  209.     aspr->active = 0;
  210.     aspr->state = STATE_DESTROY;
  211. }
  212.  
  213. /**********************************************************************
  214. * Handle the return code from fx handler
  215. **********************************************************************/
  216. void static handle_ret_code(ANIM_SPRITE as, WORD ret_code)
  217. {
  218.     switch (ret_code) {
  219.         case SPR_ANIM_FX_RET_RE_PUT:
  220.             spr_hide(as->sprites[as->spr_index]);
  221.             spr_put(as->sprites[as->spr_index], as->x, as->y);
  222.             break;
  223.         case SPR_ANIM_FX_RET_STOP:
  224.             spr_hide(as->sprites[as->spr_index]);
  225.             as->active = 0;
  226.             break;
  227.         case SPR_ANIM_FX_RET_DELETE:
  228.             spr_anim_delete(as);
  229.             break;
  230.         case SPR_ANIM_FX_RET_DESTROY:
  231.             spr_anim_destroy(as);
  232.             break;
  233.         default:
  234.             break;
  235.     }
  236. }
  237.  
  238. /**********************************************************************
  239. * Call the handler if defined, otherwise return DESTROY
  240. **********************************************************************/
  241. #define FX_HANDLER(aspr, fx, spr) ((aspr)->fx_handler==NULL  \
  242.                                     ? SPR_ANIM_FX_RET_DESTROY  \
  243.                                     : (aspr)->fx_handler(aspr, fx, spr));
  244.  
  245. /**********************************************************************
  246. * Check the special effects for all sprites, call handlers
  247. * if defined and handle return codes & actions.
  248. *
  249. * aspr  pointer to the start of sprite chain.
  250. **********************************************************************/
  251. void static do_fx(ANIM_SPRITE aspr)
  252. {
  253.     ANIM_SPRITE as, as_next;
  254.     SPRITE s;
  255.     WORD ret_code;
  256.     
  257.     as = aspr;
  258.     while (as!=NULL) {
  259.         as_next = as->next; /** save next, since action may delete as **/
  260.         
  261.         if (as->active && as->fx_mode) {
  262.             /***** Call handler for each requested effect and       *****/
  263.             /*****  interpret the return code and act as requested. *****/
  264.             ret_code = SPR_ANIM_FX_RET_NOTHING;
  265.         
  266.             if (as->fx_mode & SPR_ANIM_FX_TIMEOUT)
  267.                 if (as->timeout_count==1) {
  268.                     ret_code = FX_HANDLER(as, SPR_ANIM_FX_TIMEOUT, NULL);
  269.                     handle_ret_code(as, ret_code);
  270.                 }
  271.             
  272.             if (ret_code!=SPR_ANIM_FX_RET_DELETE
  273.                 && ret_code!=SPR_ANIM_FX_RET_DESTROY
  274.                 && (as->fx_mode & SPR_ANIM_FX_HIT_X_LIMIT))
  275.                 if (as->x < as->lef || as->x > as->rig) {
  276.                     ret_code = FX_HANDLER(as, SPR_ANIM_FX_HIT_X_LIMIT, NULL);
  277.                     handle_ret_code(as, ret_code);
  278.                 }
  279.                 
  280.             if (ret_code!=SPR_ANIM_FX_RET_DELETE
  281.                 && ret_code!=SPR_ANIM_FX_RET_DESTROY
  282.                 && (as->fx_mode & SPR_ANIM_FX_HIT_Y_LIMIT))
  283.                 if (as->y < as->top || as->y > as->bot) {
  284.                     ret_code = FX_HANDLER(as, SPR_ANIM_FX_HIT_Y_LIMIT, NULL);
  285.                     handle_ret_code(as, ret_code);
  286.                 }
  287.                 
  288.             if (ret_code!=SPR_ANIM_FX_RET_DELETE
  289.                 && ret_code!=SPR_ANIM_FX_RET_DESTROY
  290.                 && (as->fx_mode & SPR_ANIM_FX_HIT_SPRITE)) {
  291.                     s = spr_hit_first(as->sprites[as->spr_index]);
  292.                     if (s!=NULL) {
  293.                          ret_code = FX_HANDLER(as, SPR_ANIM_FX_HIT_SPRITE, s);
  294.                          handle_ret_code(as, ret_code);
  295.                     }
  296.             }
  297.         }
  298.         as = as_next;
  299.     }
  300. }
  301.  
  302. /**********************************************************************
  303. * spr_put all animated sprites then check for special effects (call
  304. * fx_handler(s) if necessary, and act according to the return values). 
  305. * Call spr_next_pass and after that update frame indices and locations 
  306. * of all animated sprites.
  307. *
  308. * Return: The current visual page
  309. **********************************************************************/
  310. WORD spr_anim_next_pass(void)
  311. {
  312.     WORD visual_page;
  313.     ANIM_SPRITE as,as1;
  314.     int i;
  315.     
  316.     /** put all sprites **/
  317.     as = anim_sprites;
  318.     while (as!=NULL) {
  319.         if (as->active)
  320.             spr_put(as->sprites[as->spr_index], as->x, as->y);
  321.         as = as->next;
  322.     }
  323.     
  324.     /** check & handle fx for all sprites **/
  325.     do_fx(anim_sprites);
  326.  
  327.     /** Now it is safe to actually delete or destroy animated sprites **/
  328.     as = anim_sprites;
  329.     while (as!=NULL) {
  330.         if (as->state!=STATE_NORMAL) {
  331.             as1 = as->next;
  332.             remove_from_anim_sprites(as);
  333.             if (as->state==STATE_DESTROY)
  334.                 for (i=0; i < as->spr_count; i++)
  335.                     spr_delete(as->sprites[i]);
  336.             free(as);
  337.             as = as1;
  338.         }
  339.         else
  340.             as = as->next;
  341.     }
  342.     
  343.     visual_page = spr_next_pass();
  344.     
  345.     /** Increment sprite index, decrement timeout and move sprite **/
  346.     as = anim_sprites;
  347.     while (as!=NULL) {
  348.         if (as->active) {
  349.             if (as->frame_delay>0)  /** animation in use **/
  350.                 if (as->delay_count==0) {
  351.                     /** delay inspired, reset it and change index **/
  352.                     as->delay_count = as->frame_delay-1;
  353.                     if (as->spr_index < as->spr_count-1)
  354.                         as->spr_index++;
  355.                     else
  356.                         as->spr_index = 0;
  357.                 }
  358.                 else
  359.                     as->delay_count--;
  360.  
  361.             if (as->timeout_count > 1)
  362.                 as->timeout_count--;
  363.             
  364.             as->x += as->dx;
  365.             as->y += as->dy;
  366.         }
  367.         as = as->next;
  368.     }
  369.     return visual_page;
  370. }
  371.  
  372.  
  373.  
  374. /**********************************************************************
  375. * Return a pointer into a static info structure of the sprite.
  376. * Note: the structure is only a copy which is overwritten by the 
  377. *       next call to this function.
  378. **********************************************************************/
  379. ANIM_SPR_INFO *spr_anim_get_info(ANIM_SPRITE aspr)
  380. {
  381.     static ANIM_SPR_INFO asi;
  382.     
  383.     asi.x = aspr->x;
  384.     asi.y = aspr->y; 
  385.     asi.dx = aspr->dx;
  386.     asi.dy = aspr->dy;
  387.     asi.lef = aspr->lef;
  388.     asi.top = aspr->top;
  389.     asi.rig = aspr->rig;
  390.     asi.bot = aspr->bot;
  391.     asi.frame = aspr->spr_index;
  392.     asi.frame_delay = aspr->frame_delay;
  393.     asi.timeout = aspr->timeout_count;
  394.     asi.id = aspr->sprites[aspr->spr_index]->id;
  395.     asi.h = aspr->sprites[aspr->spr_index]->hp;
  396.     asi.w = aspr->sprites[aspr->spr_index]->wp;
  397.     
  398.     return &asi;
  399. }
  400.  
  401. /**********************************************************************
  402. * Set the location of the animated sprite.
  403. **********************************************************************/
  404. void spr_anim_set_location(ANIM_SPRITE aspr, WORD x, WORD y)
  405. {
  406.     aspr->x = x;
  407.     aspr->y = y;
  408. }
  409.  
  410. /**********************************************************************
  411. * Set the movement vector of the animated sprite.
  412. **********************************************************************/
  413. void spr_anim_set_vector(ANIM_SPRITE aspr, int dx, int dy)
  414. {
  415.     aspr->dx = dx;
  416.     aspr->dy = dy;
  417. }
  418.  
  419. /**********************************************************************
  420. * Set the limits for the animated sprite. Note again, that all
  421. * simple sprites belonging to the animated sprite must have the
  422. * same width & heigth.
  423. **********************************************************************/
  424. void spr_anim_set_limits(ANIM_SPRITE aspr,
  425.                          WORD lef, WORD top, WORD rig, WORD bot)
  426. {
  427.     aspr->top = top;
  428.     aspr->bot = bot - aspr->sprites[0]->hp;
  429.     aspr->lef = lef;
  430.     aspr->rig = rig - aspr->sprites[0]->wp;
  431. }
  432.  
  433. /**********************************************************************
  434. * Set the frame delay and timeout values. (-1 means no change for
  435. * that value). 
  436. *
  437. * IMPORTANT NOTE: The 'frame' MUST NOT be changed from an fx_handler!!
  438. *
  439. * frame         The current animation frame number (0..nr of frames-1)
  440. * frame_delay   The number of passes for each frame change (0=no change)
  441. * timeout       The number of passes before timeout action (0=infinite)
  442. **********************************************************************/
  443. void spr_anim_set_time(ANIM_SPRITE aspr,
  444.                        int frame, int frame_delay, int timeout)
  445. {
  446.     if (frame>=0 && frame<aspr->spr_count)
  447.         aspr->spr_index = frame;
  448.     if (frame_delay>=0)
  449.         aspr->frame_delay = frame_delay;
  450.     if (timeout>=0)
  451.         aspr->timeout_count = timeout;
  452. }
  453.  
  454. /**********************************************************************
  455. * Sets the special effects handler function.
  456. * The function should have the following prototype:
  457. *   WORD func(ANIM_SPRITE aspr, WORD fx_type);
  458. * The aspr is the animated sprite and fx_type is the type of the
  459. * effect which caused this call. The function should return
  460. * one of the FX_RET values defined above.
  461. * A NULL handler means that all special effects cause spr_anim_delete.
  462. *
  463. * fx_mask     The types of effects relayed to the handler.
  464. * fx_handler  The handler function.
  465. **********************************************************************/
  466. void spr_anim_set_fx_handler(ANIM_SPRITE aspr, 
  467.                              WORD fx_mask, 
  468.                              WORD (fx_handler)(ANIM_SPRITE,WORD,SPRITE))
  469. {
  470.     aspr->fx_mode = fx_mask;
  471.     aspr->fx_handler = fx_handler;
  472. }
  473.  
  474.