#include <windows.h>
#include "main.h"
#include "game.h"
int get_action( RECT col, RECT bounds, POINT oldpos );
int get_action( RECT col, RECT bounds, POINT oldpos )
{
int val = 0;
RECT sub;
if ( &col == NULL || &bounds == NULL )
return ERROR;
if ( IntersectRect( &sub, &col, &bounds ) == 0 )
return ERROR;
return val;
}
void link_by_zorder( SPRITE *sprite )
{
SPRITE *loop;
if ( sprite == NULL )
return;
if ( lvl->first_sprite != NULL )
for (loop = lvl->first_sprite; loop != NULL; loop = loop->next)
if (sprite->z <= loop->z)
{
INSERT( sprite, loop, lvl->first_sprite, next, prev );
return;
}
LINK( sprite, lvl->first_sprite, lvl->last_sprite, next, prev );
}
SPRITE *sprite_from_bitmap( BMP *bitmap, int frames, int delay, char *name )
{
SPRITE *sprite;
CREATE( sprite, SPRITE, 1 );
if ( sprite == NULL )
return NULL;
sprite->bitmap = bitmap;
sprite->position.x = sprite->position.y = 0;
sprite->velocity.x = sprite->velocity.y = 0;
sprite->z = 0;
sprite->name = (char *)strdup( name );
SetRect(&sprite->bounds, 0, 0, PRG_WIDTH, PRG_HEIGHT );
sprite->action = STOP;
sprite->hidden = FALSE;
sprite->drag = TRUE; sprite->gravity = TRUE; sprite->proto = FALSE;
sprite->type = NONE; sprite->frames = UMAX(1,frames);
sprite->delay = UMAX(2,delay);
sprite->current_frame = sprite->trigger = 0;
sprite->width = sprite->bitmap->width/sprite->frames;
sprite->height = sprite->bitmap->height;
sprite->direction = RIGHT;
CalcCollisionRect( sprite );
link_by_zorder( sprite );
lvl->num_sprites++;
sprite->bitmask = bitmask_create(sprite->width,sprite->height);
return sprite;
}
SPRITE *sprite_from_initial( BMP *bitmap, POINT position, POINT velocity,
int z, RECT bounds, int action, int width, int height, char *name, int type )
{
SPRITE *sprite;
CREATE( sprite, SPRITE, 1 );
if ( sprite == NULL )
return NULL;
sprite->bitmap = bitmap;
sprite->position.x = position.x;
sprite->position.y = position.y;
sprite->velocity = velocity;
sprite->z = z;
sprite->name = (char *)strdup(name);
CopyRect(&sprite->bounds, &bounds );
sprite->action = action;
sprite->hidden = FALSE;
sprite->proto = FALSE;
sprite->gravity = TRUE; sprite->frames = 1;
sprite->current_frame = sprite->delay = sprite->trigger = 0;
sprite->direction = RIGHT;
sprite->width = width;
sprite->height = height;
sprite->type = type;
CalcCollisionRect( sprite );
link_by_zorder( sprite );
lvl->num_sprites++;
sprite->bitmask = bitmask_create(sprite->width,sprite->height);
return sprite;
}
int update_sprite( SPRITE *sprite )
{
POINT newpos, size, pos = sprite->position;
RECT bounds;
POINT velo = sprite->velocity;
CopyRect(&bounds, &sprite->bounds );
newpos.x = pos.x + velo.x;
newpos.y = pos.y + velo.y;
size.x = sprite->width;
size.y = sprite->height;
update_frame( sprite );
if (sprite->action == WRAP)
{
if ((newpos.x + size.x) < bounds.left)
newpos.x = bounds.right - size.x/2;
else if (newpos.x > bounds.right)
newpos.x = bounds.left - size.x/2;
if ( sprite->bitmap != NULL )
{
if ((newpos.y + size.y) < bounds.top)
newpos.y = bounds.bottom;
else if (newpos.y > bounds.bottom)
newpos.y = bounds.top - size.y;
}
else
newpos.y = UMIN(320, UMAX(0, (int)newpos.y));
}
else if (sprite->action == BOUNCE)
{
bool bounce = FALSE;
POINT ptNewVelocity = sprite->velocity;
if (newpos.x < bounds.left)
{
bounce = TRUE;
newpos.x = bounds.left;
ptNewVelocity.x = -ptNewVelocity.x;
}
else if ((newpos.x + size.x) > bounds.right)
{
bounce = TRUE;
newpos.x = bounds.right - size.x;
ptNewVelocity.x = -ptNewVelocity.x;
}
if (newpos.y < bounds.top)
{
bounce = TRUE;
newpos.y = bounds.top;
ptNewVelocity.y = -ptNewVelocity.y;
}
else if ((newpos.y + size.y) > bounds.bottom)
{
bounce = TRUE;
newpos.y = bounds.bottom - size.y;
ptNewVelocity.y = -ptNewVelocity.y;
}
if (bounce)
SetVelocity(sprite, ptNewVelocity.x, ptNewVelocity.y);
}
else if (sprite->action == DIE)
{
if (newpos.x < bounds.left ||
newpos.x > (bounds.right - size.x) ||
newpos.y < bounds.top ||
newpos.y > (bounds.bottom - size.y))
return rKILL;
}
else
{
if (newpos.x < bounds.left || newpos.x > (bounds.right - size.x))
{
newpos.x = UMAX(bounds.left, UMIN(newpos.x, bounds.right - size.x));
SetVelocity(sprite, 0, sprite->velocity.y);
}
if (newpos.y < bounds.top ||
newpos.y > (bounds.bottom - size.y))
{
newpos.y = UMAX(bounds.top, UMIN(newpos.y, bounds.bottom - size.y));
SetVelocity(sprite, 0, 0);
}
}
SetPosition(sprite, newpos);
return rNONE;
}
void draw_sprite(SPRITE *sprite, HDC hDC)
{
if (sprite->bitmap != NULL && sprite->hidden == FALSE)
{
if ( sprite->frames == 1 )
{
int x = sprite->position.x - lvl->pos.x;
int y = sprite->position.y - lvl->pos.y;
Draw(sprite->bitmap, hDC, x, y, TRUE, FALSE);
}
else
DrawFrame( sprite, hDC );
}
}
void DrawFrame( SPRITE *sprite, HDC hDC )
{
if ( sprite == NULL || sprite->bitmap == NULL )
return;
int x = sprite->position.x - lvl->pos.x;
int y = sprite->position.y - lvl->pos.y;
DrawTransparentBitmap(hDC, sprite->bitmap->bitmap, x, y,
(sprite->current_frame+sprite->direction)*sprite->width, 0, sprite->width, sprite->height, RGB(255, 0, 255));
}
void DrawSprites( SPRITE *sprite, HDC hDC )
{
if ( sprite == NULL )
return;
for ( ; sprite != NULL; sprite = sprite->next )
draw_sprite(sprite, hDC );
}
void UpdateSprites( void )
{
POINT oldpos;
int action;
SPRITE *loop = NULL;
SPRITE *next = NULL;
if ( lvl->first_sprite == NULL )
return;
for ( loop = lvl->first_sprite; loop != NULL; loop = next)
{
next = loop->next;
loop->oldpos = loop->position;
action = update_sprite( loop );
if (action == rKILL)
{
lvl->num_sprites--; loop->bitmap = NULL;
UNLINK( loop, lvl->first_sprite, lvl->last_sprite, next, prev ); loop->next = loop->prev = NULL;
subtract_from_population( loop->name, lvl );
bitmask_free(loop->bitmask);
DISPOSE( loop->name );
DISPOSE( loop ); continue;
}
CheckSpriteCollision(loop);
}
}
void CleanSprites( void )
{
SPRITE *sprite;
SPRITE *loop_sprite;
for ( sprite = lvl->first_sprite; sprite != NULL; sprite = loop_sprite)
{
loop_sprite = sprite->next;
if ( sprite != NULL )
{
lvl->num_sprites--; sprite->bitmap = NULL;
UNLINK( sprite, lvl->first_sprite, lvl->last_sprite, next, prev );
sprite->next = sprite->prev = NULL;
subtract_from_population( sprite->name, lvl );
bitmask_free(sprite->bitmask);
DISPOSE( sprite->name );
DISPOSE( sprite ); }
}
}
SPRITE *is_point_in_sprite(int x, int y)
{
SPRITE *sprite;
for ( sprite = lvl->first_sprite; sprite != NULL; sprite = sprite->next )
if ( sprite->hidden == FALSE )
{
POINT size;
size.x = sprite->position.x + sprite->width;
size.y = sprite->position.y + sprite->height;
if( x >= sprite->position.x && x <= size.x && y >= sprite->position.y && y <= size.y)
return sprite;
}
return NULL;
}
void update_frame( SPRITE *sprite )
{
if ( sprite->velocity.x != 0 && sprite->velocity.y == 0 )
if ( (sprite->delay >= 0 ) && (--sprite->trigger <= 0) )
{
sprite->trigger = sprite->delay;
if ( ++sprite->current_frame >= sprite->frames )
sprite->current_frame = 0;
}
}
bool SpriteCollision(SPRITE *hitter, SPRITE *hittee)
{
#ifdef COLLISION_LOG
glog( "Collision between %s and %s", hitter->name, hittee->name );
#endif
int x,y;
x = hittee->velocity.x;
y = hittee->velocity.y;
hittee->velocity.x = hitter->velocity.x;
hittee->velocity.y = hitter->velocity.y;
hitter->velocity.x = x;
hitter->velocity.y = y;
POINT pos1, pos2;
pos1 = hittee->position;
pos2 = hitter->position;
hittee->position = hittee->oldpos;
hitter->position = hitter->oldpos;
hittee->oldpos = pos1;
hitter->oldpos = pos2;
return TRUE;
}
bool CheckSpriteCollision(SPRITE *sprite)
{
SPRITE *loop;
for ( loop = lvl->first_sprite; loop != NULL; loop = loop->next)
{
if (sprite == loop) continue;
if ((loop == drag) || (sprite == drag)) continue;
if (TestCollision(sprite,loop) != FALSE) return SpriteCollision(loop, sprite);
}
return FALSE;
}
bool CheckSpriteCollisionObj(SPRITE *sprite)
{
OBJ *loop;
if ( sprite == NULL )
return FALSE;
for ( loop = lvl->first_obj; loop != NULL; loop = loop->next)
{
if (loop->state == NONE || loop->state == CLICK)
continue;
if (TestCollisionObj(sprite,loop) == TRUE) return SpriteCollisionObj(loop, sprite);
}
return FALSE;
}
bool SpriteCollisionObj(OBJ *obj, SPRITE *sprite)
{
return TRUE;
}
bool TestCollisionObj( SPRITE *sprite, OBJ *obj )
{
RECT test1, test2;
POINT pos = sprite->position;
POINT lpos = lvl->pos;
CopyRect( &test1, &sprite->collision );
CopyRect( &test2, &obj->bounds );
if ( test1.left <= test2.right &&
test2.left <= test1.right &&
test1.top <= test2.bottom &&
test2.top <= test1.bottom )
return TRUE;
return FALSE;
}
bool TestCollision( SPRITE *sprite1, SPRITE *sprite2 )
{
int xoffset, yoffset;
if ( sprite1 == NULL || sprite2 == NULL )
return FALSE;
xoffset = (sprite2->position.x-sprite1->position.x);
yoffset = (sprite2->position.y-sprite1->position.y);
return bitmask_overlap(sprite1->bitmask, sprite2->bitmask, xoffset, yoffset);
}
void CalcCollisionRect( SPRITE *sprite )
{
POINT pos = sprite->position;
RECT rect = { pos.x, pos.y, pos.x+sprite->width, pos.y+sprite->height };
CopyRect(&sprite->collision, &rect);
InflateRect(&sprite->collision, -1, -1);
}
SPRITE *get_proto( char *name, LEVEL *level )
{
SPRITE *loop;
if ( (!name || name[0] == '\0') || level == NULL )
return NULL;
for ( loop = level->first_proto; loop != NULL; loop = loop->next )
{
if ( !stricmp( loop->name, name ) )
return loop;
}
return NULL;
}
SPRITE *get_sprite( char *name, LEVEL *level )
{
SPRITE *loop;
if ( (!name || name[0] == '\0') || level == NULL )
return NULL;
for ( loop = level->first_sprite; loop != NULL; loop = loop->next )
{
if ( !stricmp( loop->name, name ) )
return loop;
}
return NULL;
}
void SetVelocity( SPRITE *sprite, int x, int y )
{
sprite->velocity.x = URANGE( -MAXSPEED, x, MAXSPEED);
sprite->velocity.y = URANGE( -MAXSPEED, y, MAXSPEED);
if ( sprite->velocity.x < 0 )
sprite->direction = LEFT;
else if ( sprite->velocity.x > 0 )
sprite->direction = RIGHT;
}
void SetPosition( SPRITE *sprite, POINT position )
{
sprite->oldpos.x = sprite->position.x;
sprite->oldpos.y = sprite->position.y;
sprite->position.x = position.x;
sprite->position.y = position.y;
CalcCollisionRect( sprite );
}