SPRITE.C
/*========================================================================== 
 * 
 *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. 
 *  Copyright (C) 1994-1995 ATI Technologies Inc. All Rights Reserved. 
 * 
 *  File:sprite.c 
 *  Content:sprite manipulation functions 
 * 
 ***************************************************************************/ 
#include "foxbear.h" 
 
/* 
 * CreateSprite 
 */ 
HSPRITE *CreateSprite ( 
    USHORT    bitmapCount, 
    LONG      x, 
    LONG      y, 
    USHORT    width, 
    USHORT    height, 
    USHORT    xmax, 
    USHORT    ymax, 
    SHORT     as, 
    BOOL      active ) 
{ 
    HSPRITE *hSprite; 
    USHORT   i; 
 
    hSprite = MemAlloc( sizeof (HSPRITE) ); 
    if( hSprite == NULL ) 
    { 
        ErrorMessage( "hSprite in CreateSprite" ); 
    } 
 
    hSprite->hSBM = CMemAlloc( bitmapCount, sizeof (HSPRITE_BM) ); 
    if( hSprite->hSBM == NULL ) 
    { 
        MemFree( hSprite ); 
        ErrorMessage( "hSprite->hSBM in CreateSprite" ); 
    } 
     
    hSprite->active        = active; 
    hSprite->bitmapCount   = bitmapCount; 
    hSprite->x             = x; 
    hSprite->y             = y; 
    hSprite->width         = width; 
    hSprite->height        = height; 
    hSprite->xv            = 0; 
    hSprite->yv            = 0; 
    hSprite->xa            = 0; 
    hSprite->ya            = 0; 
    hSprite->xmax          = xmax; 
    hSprite->ymax          = ymax; 
    hSprite->absSwitch     = as; 
    hSprite->relSwitch     = 0; 
    hSprite->switchType    = HOR; 
    hSprite->switchForward = TRUE; 
    hSprite->switchDone    = FALSE; 
 
    for( i = 0; i < bitmapCount; ++i ) 
    { 
        hSprite->hSBM[i].hBM = NULL; 
    } 
 
    return hSprite; 
 
} /* CreateSprite */ 
 
/* 
 * BitBltSprite 
 */ 
BOOL BitBltSprite ( 
    HSPRITE   *hSprite, 
    GFX_HBM    hBM, 
    ACTION     action, 
    DIRECTION  direction, 
    SHORT      x, 
    SHORT      y, 
    USHORT     w, 
    USHORT     h ) 
{ 
    USHORT count; 
 
    if( hSprite == NULL ) 
    { 
        ErrorMessage( "hSprite in BitBltSprite" ); 
    } 
 
    if( hBM == NULL ) 
    { 
        ErrorMessage( "hBM in BitBltSprite" ); 
    } 
 
    if( (x >= hSprite->width) || (y >= hSprite->height) ) 
    { 
        ErrorMessage( "x or y in BitBltSprite" ); 
    } 
 
    count = 0; 
    while( hSprite->hSBM[count].hBM != NULL ) 
    { 
        count++; 
        if( count >= hSprite->bitmapCount ) 
    { 
            ErrorMessage( "Bitmap overflow in BitBltSprite" ); 
        } 
    } 
 
    hSprite->hSBM[count].hBM       = hBM; 
    hSprite->hSBM[count].action    = action; 
    hSprite->hSBM[count].direction = direction; 
    hSprite->hSBM[count].x         = x; 
    hSprite->hSBM[count].y         = y; 
    hSprite->hSBM[count].width     = w;  
    hSprite->hSBM[count].height    = h;  
 
    return TRUE; 
 
} /* BitBltSprite */ 
 
/* 
 * SetSpriteAction 
 */ 
BOOL SetSpriteAction ( HSPRITE *hSprite, ACTION action, DIRECTION direction ) 
{ 
    USHORT c; 
 
    c = 0; 
 
    if( direction == SAME ) 
    { 
        direction = hSprite->currentDirection; 
    } 
 
    while( (hSprite->hSBM[c].action != action) || (hSprite->hSBM[c].direction != direction) ) 
    { 
        ++c; 
    } 
 
    hSprite->currentAction    = action; 
    hSprite->currentDirection = direction; 
    hSprite->currentBitmap    = c; 
    hSprite->relSwitch        = 0; 
 
    return TRUE; 
 
} /* SetSpriteAction */ 
 
/* 
 * ChangeSpriteDirection 
 */ 
BOOL ChangeSpriteDirection( HSPRITE *hSprite ) 
{ 
    DIRECTION direction; 
 
    if( hSprite->currentDirection == RIGHT ) 
    { 
        direction = LEFT; 
    } 
    else 
    { 
        direction = RIGHT; 
    } 
 
    SetSpriteAction( hSprite, hSprite->currentAction, direction ); 
 
    return TRUE; 
 
} /* ChangeSpriteDirection */ 
 
/* 
 * GetSpriteAction 
 */ 
ACTION GetSpriteAction( HSPRITE *hSprite ) 
{ 
    return hSprite->currentAction; 
 
} /* GetSpriteAction */ 
 
 
/* 
 * GetSpriteDirection 
 */ 
DIRECTION GetSpriteDirection( HSPRITE *hSprite )          
{ 
    return hSprite->currentDirection; 
 
} /* GetSpriteDirection */ 
 
/* 
 * SetSpriteActive 
 */ 
BOOL SetSpriteActive( HSPRITE *hSprite, BOOL active ) 
{ 
    hSprite->active = active; 
     
    if( active == FALSE ) 
    { 
        hSprite->xv = 0; 
        hSprite->yv = 0; 
        hSprite->xa = 0; 
        hSprite->ya = 0; 
    } 
 
    return TRUE; 
 
} /* SetSpriteActive */ 
 
/* 
 * GetSpriteActive 
 */ 
BOOL GetSpriteActive( HSPRITE *hSprite ) 
{ 
    return hSprite->active; 
 
} /* GetSpriteActive */ 
 
/* 
 * SetSpriteVelX 
 */ 
BOOL SetSpriteVelX( HSPRITE *hSprite, LONG xv, POSITION position ) 
{ 
    if( hSprite->active == FALSE ) 
    { 
        return FALSE; 
    } 
 
    if( position == P_ABSOLUTE ) 
    { 
        hSprite->xv = xv; 
    } 
    else if( position == P_RELATIVE ) 
    { 
        hSprite->xv += xv; 
    } 
 
    return TRUE; 
 
} /* SetSpriteVelX */ 
 
/* 
 * GetSpriteVelX 
 */ 
LONG GetSpriteVelX( HSPRITE *hSprite ) 
{ 
    return hSprite->xv; 
 
} /* GetSpriteVelX */ 
 
/* 
 * SetSpriteVelY 
 */ 
BOOL SetSpriteVelY( HSPRITE *hSprite, LONG  yv, POSITION position ) 
{ 
    if( hSprite->active == FALSE ) 
    { 
        return FALSE; 
    } 
 
    if( position == P_ABSOLUTE ) 
    { 
        hSprite->yv = yv; 
    } 
    else if( position == P_RELATIVE ) 
    { 
        hSprite->yv += yv; 
    } 
 
    return TRUE; 
 
} /* SetSpriteVelY */ 
 
/* 
 * GetSpriteVelY 
 */ 
LONG GetSpriteVelY( HSPRITE *hSprite ) 
{ 
    return hSprite->yv; 
 
} /* GetSpriteVelY */ 
 
/* 
 * SetSpriteAccX 
 */ 
BOOL SetSpriteAccX ( HSPRITE *hSprite, LONG xa, POSITION position ) 
{ 
    if( position == P_ABSOLUTE ) 
    { 
        hSprite->xa = xa; 
    } 
    else if( position == P_RELATIVE ) 
    { 
        hSprite->xa += xa; 
    } 
    return TRUE; 
 
} /* SetSpriteAccX */ 
 
/* 
 * GetSpriteAccX 
 */ 
LONG GetSpriteAccX( HSPRITE *hSprite ) 
{ 
    return hSprite->xa; 
 
} /* GetSpriteAccX */ 
 
/* 
 * SetSpriteAccY 
 */ 
BOOL SetSpriteAccY ( HSPRITE *hSprite, LONG ya, POSITION position ) 
{ 
    if( position == P_ABSOLUTE ) 
    { 
        hSprite->ya = ya; 
    } 
    else if( position == P_RELATIVE ) 
    { 
        hSprite->ya += ya; 
    } 
    return TRUE; 
 
} /* SetSpriteAccY */ 
 
/* 
 * GetSpriteAccY 
 */ 
LONG GetSpriteAccY( HSPRITE *hSprite ) 
{ 
    return hSprite->ya; 
 
} /* GetSpriteAccY */ 
 
/* 
 * SetSpriteX 
 */ 
BOOL SetSpriteX( HSPRITE *hSprite, LONG x, POSITION position ) 
{ 
    if( hSprite->active == FALSE ) 
    { 
        return FALSE; 
    } 
 
    if( position == P_AUTOMATIC ) 
    { 
        hSprite->xv += hSprite->xa; 
        hSprite->x  += hSprite->xv; 
    } 
    else if( position == P_ABSOLUTE ) 
    { 
        hSprite->x = x; 
    } 
    else if( position == P_RELATIVE ) 
    { 
        hSprite->x += x; 
    } 
 
    if( hSprite->x < 0 ) 
    { 
        hSprite->x += hSprite->xmax << 16; 
    } 
    else if( hSprite->x >= hSprite->xmax << 16 ) 
    { 
        hSprite->x -= hSprite->xmax << 16; 
    } 
    return TRUE; 
 
} /* SetSpriteX */ 
 
/* 
 * GetSpriteX 
 */ 
LONG GetSpriteX( HSPRITE *hSprite ) 
{ 
    return hSprite->x; 
 
} /* GetSpriteX */ 
 
/* 
 * SetSpriteY 
 */ 
BOOL SetSpriteY ( HSPRITE *hSprite, LONG y, POSITION position ) 
{ 
    if( hSprite->active == FALSE ) 
    { 
        return FALSE; 
    } 
 
    if( position == P_AUTOMATIC ) 
    { 
        hSprite->yv += hSprite->ya; 
        hSprite->y  += hSprite->yv; 
    } 
    else if( position == P_ABSOLUTE ) 
    { 
        hSprite->y = y; 
    } 
    else if( position == P_RELATIVE ) 
    { 
        hSprite->y += y; 
    } 
 
    if( hSprite->y < 0 ) 
    { 
        hSprite->y += hSprite->ymax << 16; 
    } 
    else if( hSprite->y >= hSprite->ymax << 16 ) 
    { 
        hSprite->y -= hSprite->ymax << 16; 
    } 
 
    return TRUE; 
 
} /* SetSpriteY */ 
 
/* 
 * GetSpriteY 
 */ 
LONG GetSpriteY( HSPRITE *hSprite ) 
{ 
    return hSprite->y; 
 
} /* GetSpriteY */ 
 
/* 
 * SetSpriteSwitch 
 */ 
BOOL SetSpriteSwitch ( HSPRITE *hSprite, LONG absSwitch, POSITION position )                
{ 
    if( position == P_ABSOLUTE ) 
    { 
        hSprite->absSwitch = absSwitch; 
    } 
    else if( position == P_RELATIVE ) 
    { 
        hSprite->absSwitch += absSwitch; 
    } 
    return TRUE; 
 
} /* SetSpriteSwitch */ 
 
 
/* 
 * IncrementSpriteSwitch 
 */ 
BOOL IncrementSpriteSwitch ( HSPRITE *hSprite, LONG n ) 
{ 
    hSprite->relSwitch += n; 
    return TRUE; 
 
} /* IncrementSpriteSwitch */ 
 
/* 
 * SetSpriteSwitchType 
 */ 
BOOL SetSpriteSwitchType( HSPRITE *hSprite, SWITCHING switchType ) 
{ 
    hSprite->switchType = switchType; 
    hSprite->relSwitch  = 0; 
    return TRUE; 
 
} /* SetSpriteSwitchType */ 
 
 
/* 
 * GetSpriteSwitchType 
 */ 
SWITCHING GetSpriteSwitchType ( HSPRITE *hSprite ) 
{ 
    return hSprite->switchType; 
 
} /* GetSpriteSwitchType */ 
 
/* 
 * SetSpriteSwitchForward 
 */ 
BOOL SetSpriteSwitchForward( HSPRITE *hSprite, BOOL switchForward ) 
{ 
    hSprite->switchForward = switchForward; 
 
    return TRUE; 
 
} /* SetSpriteSwitchForward */ 
 
/* 
 * GetSpriteSwitchForward 
 */ 
BOOL GetSpriteSwitchForward( HSPRITE *hSprite ) 
{ 
    return hSprite->switchForward; 
 
} /* GetSpriteSwitchForward */ 
 
/* 
 * SetSpriteSwitchDone 
 */ 
BOOL SetSpriteSwitchDone( HSPRITE *hSprite, BOOL switchDone ) 
{ 
    hSprite->switchDone = switchDone; 
    return TRUE; 
 
} /* SetSpriteSwitchDone */ 
 
 
/* 
 * GetSpriteSwitchDone 
 */ 
BOOL GetSpriteSwitchDone( HSPRITE *hSprite ) 
{ 
    return hSprite->switchDone; 
 
} /* GetSpriteSwitchDone */ 
 
/* 
 * SetSpriteBitmap 
 */ 
BOOL SetSpriteBitmap ( HSPRITE *hSprite, USHORT currentBitmap ) 
{ 
    USHORT c; 
 
    c = 0; 
    while( (hSprite->currentAction != hSprite->hSBM[c].action) || 
           (hSprite->currentDirection != hSprite->hSBM[c].direction) ) 
    { 
        ++c; 
    } 
    hSprite->currentBitmap = c + currentBitmap; 
    return TRUE; 
 
} /* SetSpriteBitmap */ 
 
/* 
 * GetSpriteBitmap 
 */ 
USHORT GetSpriteBitmap( HSPRITE *hSprite ) 
{ 
    USHORT count; 
 
    count = 0; 
    while( (hSprite->currentAction != hSprite->hSBM[count].action) || 
       (hSprite->currentDirection != hSprite->hSBM[count].direction) ) 
    { 
        ++count; 
    } 
    return hSprite->currentBitmap - count; 
 
} /* GetSpriteBitmap */ 
 
/* 
 * advanceSpriteBitmap 
 */ 
static BOOL advanceSpriteBitmap( HSPRITE *hSprite ) 
{ 
    SHORTc; 
    SHORTn; 
    ACTIONcurAct; 
    ACTIONact; 
    DIRECTIONcurDir; 
    DIRECTIONdir; 
 
    curAct = hSprite->currentAction; 
    curDir = hSprite->currentDirection; 
 
// 
// See if we're cycling forward or backward though the images. 
// 
    if( hSprite->switchForward ) // Are we cycling forward? 
    { 
        c   = hSprite->currentBitmap + 1; 
 
// Does the next image exceed the number of images we have? 
        if( c >= hSprite->bitmapCount ) 
{ 
// if the next image is past the end of the list, 
// we need to set it to the start of the series. 
            SetSpriteBitmap( hSprite, 0 ); 
c   = hSprite->currentBitmap; 
        } 
else 
{ 
act = hSprite->hSBM[c].action; 
dir = hSprite->hSBM[c].direction; 
 
// By examining the action and direction fields we can tell 
// if we've past the current series of images and entered  
// another series. 
if( (curAct != act) || (curDir != dir) ) 
{ 
SetSpriteBitmap( hSprite, 0 ); 
}  
else // We're still in the series, use the next image. 
{ 
hSprite->currentBitmap = c; 
} 
} 
    } 
else //cycling backwards 
{ 
        c   = hSprite->currentBitmap - 1; 
 
        if( c < 0 ) // Is the next image past the beginning of the list? 
{ 
            n = 0; 
 
// Find the last bitmap in the series 
            while( (n <= hSprite->bitmapCount) && 
       (curAct == hSprite->hSBM[n].action) && 
           (curDir == hSprite->hSBM[n].direction) ) 
{ 
++n; 
} 
 
            hSprite->currentBitmap = n - 1; 
        } 
 
else 
{ 
act = hSprite->hSBM[c].action; 
dir = hSprite->hSBM[c].direction; 
// Is the next image past the of the series 
if( (curAct != act) || (curDir != dir) )  
{ 
n = c + 1; 
while( (n <= hSprite->bitmapCount) && 
   (curAct == hSprite->hSBM[n].action) && 
       (curDir == hSprite->hSBM[n].direction) ) 
{ 
++n; 
} 
 
hSprite->currentBitmap = n - 1; 
} 
else  // The next image is fine, use it. 
{ 
hSprite->currentBitmap = c; 
} 
} 
    } 
    return TRUE; 
 
} /* advanceSpriteBitmap */ 
 
/* 
 * DisplaySprite 
 */ 
BOOL DisplaySprite ( GFX_HBM hBuffer, HSPRITE *hSprite, LONG xPlane ) 
{ 
    USHORTcount; 
    SHORTleft; 
    SHORTright; 
    SHORTshortx; 
    SHORTshorty; 
    SHORTplanex; 
    POINT       src; 
    RECT        dst; 
 
    if( hSprite->active == FALSE ) 
    { 
        return FALSE; 
    } 
 
    count = hSprite->currentBitmap; 
    shortx = (SHORT) (hSprite->x >> 16); 
    shorty = (SHORT) (hSprite->y >> 16); 
    planex = (SHORT) (xPlane >> 16); 
    src.x = 0; 
    src.y = 0; 
 
    if( shortx < planex - C_SCREEN_W ) 
    { 
        shortx += hSprite->xmax; 
    } 
    else if( shortx >= planex + C_SCREEN_W ) 
    { 
        shortx -= hSprite->xmax; 
    } 
 
    left = shortx - planex; 
     
    if( hSprite->currentDirection == RIGHT ) 
    { 
        left += hSprite->hSBM[count].x; 
    } 
    else 
    { 
        left += hSprite->width - hSprite->hSBM[count].x - hSprite->hSBM[count].width; 
    } 
 
    right = left + hSprite->hSBM[count].width; 
 
    if( left > C_SCREEN_W ) 
    { 
        left = C_SCREEN_W; 
    } 
    else if( left < 0 ) 
    { 
        src.x = -left; 
        left = 0; 
    } 
 
    if( right > C_SCREEN_W ) 
    { 
        right = C_SCREEN_W; 
    } 
    else if( right < 0 ) 
    { 
        right = 0; 
    } 
 
    dst.left   = left; 
    dst.right  = right; 
    dst.top    = shorty + hSprite->hSBM[count].y; 
    dst.bottom = dst.top + hSprite->hSBM[count].height; 
 
    gfxBlt(&dst,hSprite->hSBM[count].hBM,&src); 
 
    if( hSprite->switchType == HOR ) 
    { 
        hSprite->relSwitch += abs(hSprite->xv); 
 
        if( hSprite->relSwitch >= hSprite->absSwitch ) 
{ 
            hSprite->relSwitch = 0; 
            advanceSpriteBitmap( hSprite ); 
        } 
    } 
    else if( hSprite->switchType == VER ) 
    { 
        hSprite->relSwitch += abs(hSprite->yv); 
 
        if( hSprite->relSwitch >= hSprite->absSwitch ) 
    { 
            hSprite->relSwitch = 0; 
            advanceSpriteBitmap( hSprite ); 
 
            if( GetSpriteBitmap( hSprite ) == 0 ) 
        { 
                SetSpriteSwitchDone( hSprite, TRUE ); 
            } 
        } 
    } 
    else if( hSprite->switchType == TIME ) 
    { 
        hSprite->relSwitch += C_UNIT; 
 
        if( hSprite->relSwitch >= hSprite->absSwitch ) 
    { 
            hSprite->relSwitch = 0; 
            advanceSpriteBitmap( hSprite ); 
             
            if( GetSpriteBitmap( hSprite ) == 0 ) 
        { 
                SetSpriteSwitchDone( hSprite, TRUE ); 
            } 
        } 
    } 
 
    return TRUE; 
 
} /* DisplaySprite */ 
 
/* 
 * DestroySprite 
 */ 
BOOL DestroySprite ( HSPRITE *hSprite ) 
{ 
    USHORT i; 
 
    if( hSprite == NULL ) 
    { 
        ErrorMessage( "hSprite in DestroySprite" ); 
    } 
 
    if( hSprite->hSBM == NULL ) 
    { 
        ErrorMessage( "hSprite->hSBM in DestroySprite" ); 
    } 
 
    for( i = 0; i < hSprite->bitmapCount; ++i ) 
    { 
        if( !gfxDestroyBitmap( hSprite->hSBM[i].hBM ) ) 
    { 
            ErrorMessage( "gfxDestroyBitmap (hBM) in DestroySprite" ); 
        } 
    } 
 
    MemFree( hSprite->hSBM ); 
    MemFree( hSprite ); 
 
    return TRUE; 
 
} /* DestroySprite */