/*========================================================================== * * 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 ) { SHORT c; SHORT n; ACTION curAct; ACTION act; DIRECTION curDir; DIRECTION dir; 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 ) { USHORT count; SHORT left; SHORT right; SHORT shortx; SHORT shorty; SHORT planex; 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 == TIMESWITCH ) { 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 */