ratcatcher/rc.c

1317 lines
26 KiB
C
Raw Normal View History

2006-01-27 17:27:57 +11:00
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <math.h>
#include <SDL/SDL.h>
#include <SDL/SDL_keysym.h>
#include <SDL/SDL_rotozoom.h>
#include "rc.h"
SDL_Surface *screen;
int curlevelnum = 1;
level_t *curlevel;
sprite_t *sprite = NULL; /* main sprite list */
sprite_t *player;
sprite_t *lastsprite;
SDL_Color red = {255, 0, 0, 0};
SDL_Color white = {255, 255, 255, 0};
int timer = 0;
int toggletimer = 0;
int main (int argc, char **argv) {
Uint8 *keys;
sprite_t *s,*nextsprite;
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE)==-1) {
printf("SDL_Init: %s\n", SDL_GetError());
exit(1);
}
atexit(cleanup);
screen = SDL_SetVideoMode(640,480,16,SDL_HWSURFACE|SDL_DOUBLEBUF);
if (loadimagesets()) {
return 1;
}
if (loadlevel(curlevelnum)) {
return 1;
}
drawlevel();
SDL_Flip(screen);
timer = 0;
printf("player y is %0.1f\n",player->y);
fflush(stdout);
while (1) {
/* remove player */
for (s = sprite ; s ; s = s->next) {
removesprite(s);
}
removenetting(player);
/* check for death & update movement status*/
for (s = sprite ; s ; s = nextsprite) {
s->moved = B_FALSE;
nextsprite = s->next;
if (s->dead == 4) {
killsprite(s);
}
}
/* check for keys */
SDL_PumpEvents();
keys = SDL_GetKeyState(NULL);
if (keys[SDLK_RETURN]) {
if (toggletimer == 0) {
SDL_WM_ToggleFullScreen(screen);
toggletimer = 50;
}
}
if (keys[SDLK_ESCAPE]) {
return 1;
}
if (keys[SDLK_RIGHT]) {
if (!player->jumping) {
if (!isonladder(player) || player->falling || isonground(player)) {
movex(player, player->speed);
}
}
player->dir = 1;
}
if (keys[SDLK_LEFT]) {
if (!player->jumping) {
if (!isonladder(player) || player->falling || isonground(player)) {
movex(player, -player->speed);
}
}
player->dir = -1;
}
if (keys[SDLK_UP]) {
if (isonladder(player) || isladderabove(player)) {
player->y -= player->speed;
}
}
if (keys[SDLK_x]) {
if (!player->jumping) {
if (!player->falling) {
if (isonground(player) || isonladder(player)) {
player->jumping = 1;
if (keys[SDLK_RIGHT]) {
player->jumpdir = 1;
} else if (keys[SDLK_LEFT]) {
player->jumpdir = -1;
} else {
player->jumpdir = 0;
}
player->jumpspeed = 5;
}
}
}
}
if (keys[SDLK_z]) {
if (!player->netting) {
if (keys[SDLK_DOWN]) {
/* slam */
if ((!player->slamming) && (isonground(player))) {
player->slamming = B_TRUE;
player->slamangle = 0;
player->netxstart = player->x - (player->img->w/2)*player->dir;
player->netystart = player->y;
}
} else {
/* shoot net */
player->netting = 1;
player->netspeed = NETSPEED;
player->netlen = 0;
player->netdir = player->dir;
}
}
}
for (s = sprite; s ; s = s->next) {
movesprite(s);
}
/* gravity */
for (s = sprite ; s ; s = s->next) {
dogravity(s);
}
/* tile effects */
for (s = sprite ; s ; s = s->next) {
dotileeffects(s);
}
/* check collisions */
for (s = sprite ; s ; s = s->next) {
checkcollide(s);
}
drawnetting(player);
/* draw player */
for (s = sprite ; s ; s = s->next) {
drawsprite(s);
}
SDL_Flip(screen);
if (++timer == 100) timer = 0;
if (toggletimer > 0) toggletimer--;
}
return 0;
}
void cleanup(void) {
SDL_Quit();
}
void checkcollide(sprite_t *s) {
sprite_t *s2;
int collide;
int xdiff,ydiff;
for (s2 = sprite ; s2 ; s2 = s2->next) {
collide = B_TRUE;
if (s2 == s) collide = B_FALSE;
else if (s2->dead) collide = B_FALSE;
if (collide) {
/* check for colission with our net */
if ((s->netting) && (!s2->caughtby)) {
xdiff = (s->x + s->netlen*s->netdir) - s2->x;
if (xdiff < 0) xdiff = -xdiff;
ydiff = s->netystart - s2->y;
if (ydiff < 0) ydiff = -ydiff;
if ((xdiff <= s2->img->w) && (ydiff <= s2->img->h)) {
s2->caughtby = s;
s2->caughtstate = 1;
}
} else {
/* check for collision with us */
xdiff = s->x - s2->x;
if (xdiff < 0) xdiff = -xdiff;
ydiff = s->y - s2->y;
if (ydiff < 0) ydiff = -ydiff;
if ((xdiff <= s->img->w/2 + s2->img->w/2) &&
(ydiff <= s->img->h/2 + s2->img->h/2)) {
/* COLLISION! */
if (isfruit(s2->id)) {
if (s == player) {
/* kill the fruit */
s2->dead = 4;
/* give points to the player */
}
}
if (ismonster(s2->id)) {
/* TODO: kill player */
}
}
}
}
}
}
tiletype_t *gettile(int tid) {
tiletype_t *t;
for (t = tiletype; t ; t = t->next) {
if (t->id == tid) return t;
}
return NULL;
}
void movesprite(sprite_t *s) {
int rv;
/* avoid edges of screen */
if (s->y < s->img->h) {
s->y = s->img->h;
}
if (s->jumping) {
movex(s, s->jumpdir*s->speed);
return;
} else if (s->caughtby) {
if (s->caughtby->slamming) {
/* */
s->x = s->caughtby->netxstart;
s->y = s->caughtby->netystart;
} else {
/* stay at position of net */
s->y = s->caughtby->y;
if (s->caughtstate == 1) {
s->x = s->caughtby->x + (s->caughtby->netlen*s->caughtby->netdir);
} else {
s->x = s->caughtby->x + (s->caughtby->img->w/2) * -(s->caughtby->dir);
}
}
return;
} else if (s->dead == 1) { /* just set to dead */
s->xs = ((rand() % 7)) - 3;
s->ys = ((rand() % 3) + 2) * -1;
s->dead = 2;
s->bounces = 0;
return;
} else if (s->dead == 2) { /* dying */
s->x += s->xs;
s->y += s->ys;
if (s->x >= (640-(s->img->w/2))) {
if (s->xs > 0) {
s->xs = -s->xs;
s->bounces++;
}
} else if (s->x <= s->img->w/2) {
if (s->xs < 0) {
s->xs = -s->xs;
s->bounces++;
}
}
if (s->y >= (480-(s->img->h/2))) {
if (s->ys > 0) {
s->ys = -s->ys;
s->bounces++;
}
} else if (s->y <= s->img->h) {
if (s->ys < 0) {
s->ys = -s->ys;
s->bounces++;
}
}
if ((s->bounces >= 2) && (s->ys > 0)) {
s->dead = 3;
}
return;
} else if (s->dead == 3) { /* final fall */
s->x += s->xs;
s->y += s->ys;
if (s->x >= (640-(s->img->w/2))) {
if (s->xs > 0) {
s->xs = -s->xs;
s->bounces++;
}
} else if (s->x <= s->img->w/2) {
if (s->xs < 0) {
s->xs = -s->xs;
s->bounces++;
}
}
if (s->y >= (480-(s->img->h/2))) {
if (s->ys > 0) {
s->ys = -s->ys;
s->bounces++;
}
} else if (s->y <= s->img->h) {
if (s->ys < 0) {
s->ys = -s->ys;
s->bounces++;
}
}
if ((s->ys > 0) && (s->y >= TILEH)) {
if (isonground(s)) {
int x,y,ty;
s->dead = 4;
/* change into a fruit */
x = s->x;
gettileat(s->x,s->y-1,NULL,&ty);
y = ty*TILEH + TILEH - 2;
addsprite(P_CHEESE, x, y, "Cheese");
}
}
return;
}
if (isonground(s)) {
if ((!s->falling) && (!s->jumping)) {
adjustheight(s);
}
}
if (s->id == P_RAT) {
if (!s->falling) {
tiletype_t *tt;
/* if there's not a hole in front of us, move */
tt = gettileat(s->x + s->dir+s->speed,s->y,NULL,NULL);
if (tt->solid == S_NOTSOLID) {
s->dir = -s->dir;
} else {
rv = movex(s, s->dir*s->speed);
if (rv) {
s->dir = -s->dir;
}
}
}
}
}
void dotileeffects(sprite_t *s) {
tiletype_t *tt;
if (s->jumping || s->dead || s->caughtby) {
return;
}
tt = gettileat(s->x,s->y+3,NULL,NULL);
if (tt->id == T_RIGHT) {
movex(s, 1.5);
}
if (tt->id == T_LEFT) {
movex(s, -1.5);
}
}
void drawtile(int x, int y) {
SDL_Rect area;
tiletype_t *tt;
if ((x < 0) || (y < 0) || (x >= LEVELW) || (y >= LEVELH)) {
return;
}
area.x = x * TILEW;
area.y = y * TILEH;
area.w = 0;
area.h = 0;
/* draw blank tile first */
tt = gettile(curlevel->bgtileid);
SDL_BlitSurface(tt->img, NULL, screen, &area);
tt = gettile(curlevel->map[y*LEVELW+x]);
if (tt->id != curlevel->bgtileid) {
SDL_BlitSurface(tt->img, NULL, screen, &area);
}
}
void drawlevel(void) {
int x,y;
for (x = 0; x < LEVELW; x++) {
for (y = 0; y < LEVELH; y++) {
drawtile(x,y);
}
}
}
int loadlevel(int lnum) {
FILE *f;
int x,y;
char buf[BUFLEN];
char filename[BUFLEN];
char *p;
int tileid;
int i;
level = malloc(sizeof(level_t));
level->id = 0;
sprintf(level->name, "Level %d",lnum);
level->prev = NULL;
level->next = NULL;
/* default */
level->p1x = 0;
level->p1y = 0;
sprintf(filename, "level%d.dat",lnum);
f = fopen(filename,"rt");
if (!f) {
printf("can't open level file\n");
return B_TRUE;
}
/* clear tiletype linked list */
while (tiletype != NULL) {
tiletype_t *tt;
/* kill first tile */
if (tiletype->img) {
SDL_FreeSurface(tiletype->img);
tiletype->img = NULL;
tt = tiletype->next;
free(tiletype);
tiletype = tt;
}
}
/* TODO: clear player linked list */
/* read tileset */
fgets(buf, BUFLEN, f);
if (strstr(buf, "tileset") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
/* strip newline */
p[strlen(p)-1] = '\0';
if (loadtiletypes(p)) {
printf("Cannot load tileset file: %s\n", p);
return B_TRUE;
}
} else {
printf("invalid tileset file in line: '%s'\n",buf);
return B_TRUE;
}
/* read background tile */
fgets(buf, BUFLEN, f);
if (strstr(buf, "bg") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
level->bgtileid = atoi(p);
if (!gettile(level->bgtileid)) {
printf("invalid background tile id: %d\n",level->bgtileid);
return B_TRUE;
}
printf("Background tile id is %d (%s)\n",level->bgtileid,(gettile(level->bgtileid)->name));
} else {
printf("invalid background tile id line: '%s'\n",buf);
return B_TRUE;
}
x = 0;
y = 0;
level->nummonsters = 0;
fgets(buf, BUFLEN, f);
while (!feof(f)) {
for (p = buf; *p; p++) {
if (*p == '~') {
tileid = T_LAND;
} else if (*p == '=') {
tileid = T_LADDER;
} else if (*p == '-') {
tileid = T_LADDERTOP;
} else if (*p == '>') {
tileid = T_RIGHT;
} else if (*p == '<') {
tileid = T_LEFT;
} else if (*p == '^') {
tileid = T_SPIKES;
} else if (*p == 'r') {
tileid = level->bgtileid;
level->initm[level->nummonsters].startx = x*TILEW+(TILEW/2);
level->initm[level->nummonsters].starty = y*TILEH+(TILEH-2);
level->initm[level->nummonsters].id = P_RAT;
level->nummonsters++;
} else if (*p == '*') {
tileid = T_FULL;
} else if (*p == '/') {
tileid = T_SLOPEUP;
} else if (*p == '\\') {
tileid = T_SLOPEDOWN;
} else if (*p == '1') {
tileid = level->bgtileid;
level->p1x = x;
level->p1y = y;
} else {
tileid = level->bgtileid;
}
if (!gettile(tileid)) {
printf("invalid tileid: %d\n",tileid);
fclose(f);
return B_TRUE;
}
if ((x > LEVELW) || (y > LEVELH)) {
printf("Level position out of range: %d,%d\n",x,y);
fclose(f);
return B_TRUE;
}
level->map[y*LEVELW+x] = tileid;
x++;
}
if (x < LEVELW+1) {
printf("Not enough tiles on line: y = %d\n",y);
fclose(f);
return B_TRUE;
}
y++;
x = 0;
fgets(buf, BUFLEN, f);
}
fclose(f);
if (y < LEVELH) {
printf("Incomplete level: y=%d, should be %d.\n",
y,LEVELH);
return B_TRUE;
}
if ((level->p1x == 0) || (level->p1y == 0)) {
printf("Level is missing player 1 start position.\n");
return B_TRUE;
}
/* set current level pointer */
curlevel = level;
/* add player */
addsprite(P_PLAYER, (curlevel->p1x * TILEW) + (TILEW/2),
(curlevel->p1y * TILEH) + TILEH-2 , "Player" );
player = lastsprite;
/* add monsters */
for (i = 0; i < level->nummonsters; i++) {
addsprite(level->initm[i].id,
level->initm[i].startx, level->initm[i].starty, "Monster");
}
return B_FALSE;
}
int loadtiletypes(char *filename) {
tiletype_t *t = NULL;
int i;
int state;
FILE *f;
char buf[BUFLEN];
char *p,*pp;
state = 0;
f = fopen(filename,"rt");
if (!f) {
printf("can't open tiles file\n");
return B_TRUE;
}
fgets(buf, BUFLEN, f);
while (!feof(f)) {
if (state == 0) {
if (strstr(buf, "tile") == buf) {
if (t == NULL) {
tiletype = malloc(sizeof(tiletype_t));
t = tiletype;
t->prev = NULL;
} else {
t->next = malloc(sizeof(tiletype_t));
t->next->prev = t;
t = t->next;
}
p = strtok(buf, " ");
p = strtok(NULL, " ");
/* strip newline */
p[strlen(p)-1] = '\0';
strcpy(t->name, p);
/* defaults */
t->id = 0;
t->solid = B_TRUE;
for (i = 0; i < TILEW; i++) {
t->lowness[i] = 0;
}
t->img = NULL;
t->next = NULL;
state = 1;
}
} else if (state == 1) { /* inside a definition */
if (strstr(buf, "end") == buf) {
printf("got tile %d: %s (solid=%d)\n",t->id,t->name,t->solid);
state = 0;
} else if (strstr(buf, "id") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
t->id = atoi(p);
} else if (strstr(buf, "lowness") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
pp = strtok(p, ",");
for (i = 0;i < TILEW; i++) {
t->lowness[i] = atoi(pp);
pp = strtok(NULL, ",");
}
} else if (strstr(buf, "solid") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
t->solid = atoi(p);
} else if (strstr(buf, "file") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
if (t->img) {
SDL_FreeSurface(t->img);
t->img = NULL;
}
/* strip newline */
p[strlen(p)-1] = '\0';
t->img = IMG_Load(p);
if (!t->img) {
printf("cannot load tile image file: '%s'\n",p);
fclose(f);
return B_TRUE;
}
SDL_SetColorKey(t->img, SDL_SRCCOLORKEY, SDL_MapRGB(screen->format, 0, 0, 0));
}
}
fgets(buf, BUFLEN, f);
}
fclose(f);
return B_FALSE;
}
int loadimagesets(void) {
int p,i;
imageset[P_PLAYER].img[F_WALK1] = IMG_Load("pdwarf.png");
imageset[P_PLAYER].img[F_JUMP] = IMG_Load("pdwarfjump.png");
imageset[P_PLAYER].img[F_FALL] = IMG_Load("pdwarffall.png");
imageset[P_PLAYER].img[F_CAUGHT] = IMG_Load("pdwarf.png");
imageset[P_PLAYER].img[F_DEAD] = IMG_Load("pdwarf.png");
/* next 3 are auto generated */
imageset[P_PLAYER].numimages = 8;
imageset[P_RAT].img[F_WALK1] = IMG_Load("rat.bmp");
imageset[P_RAT].img[F_JUMP] = IMG_Load("rat.bmp");
imageset[P_RAT].img[F_FALL] = IMG_Load("rat.bmp");
imageset[P_RAT].img[F_CAUGHT] = IMG_Load("ratcaught.bmp");
imageset[P_RAT].img[F_DEAD] = IMG_Load("ratdead.bmp");
/* next 3 are auto generated */
imageset[P_RAT].numimages = 8;
imageset[P_CHEESE].img[F_WALK1] = IMG_Load("cheese.bmp");
imageset[P_CHEESE].numimages = 1;
/* generate rotated/flipped images */
for (p = 0; p < MAXPTYPES; p++) {
imageset[p].img[F_DEAD2] = rotozoomSurface(imageset[p].img[F_DEAD],90,1,0);
imageset[p].img[F_DEAD3] = rotozoomSurface(imageset[p].img[F_DEAD],180,1,0);
imageset[p].img[F_DEAD4] = rotozoomSurface(imageset[p].img[F_DEAD],270,1,0);
for (i = 0; i < imageset[p].numimages; i++) {
SDL_SetColorKey(imageset[p].img[i],
SDL_SRCCOLORKEY, SDL_MapRGB(screen->format, 0, 0, 0));
imageset[p].img[MAXFRAMES+i] =
rotozoomSurfaceXY(imageset[p].img[i], 0, -1,1,0);
}
}
return B_FALSE;
}
double getspeed(int id) {
if (id == P_PLAYER) return 1;
else if (id == P_RAT) return 1.5;
else if (id == P_CHEESE) return 0;
return 1;
}
int addsprite(int id, int x, int y, char *name ) {
sprite_t *s;
if (sprite == NULL) {
sprite = malloc(sizeof(sprite_t));
s = sprite;
s->prev = NULL;
} else {
s = lastsprite;
s->next = malloc(sizeof(sprite_t));
s->next->prev = s;
s = s->next;
}
s->id = id;
s->x = x;
s->y = y;
s->img = imageset[id].img[F_WALK1];
if (s->y > (480 - TILEH-1)) {
s->y = 480 - TILEH-1;
}
strcpy(s->name, name);
if (s == sprite) {
s->netbg = SDL_CreateRGBSurface(SDL_HWSURFACE,
200, 10,
screen->format->BitsPerPixel, screen->format->Rmask,
screen->format->Gmask,screen->format->Bmask,
screen->format->Amask);
} else {
s->netbg = NULL;
}
s->speed = getspeed(id);
s->jumping = 0;
s->jumpdir = 1;
s->netting = 0;
s->falling = 0;
s->fallspeed = 0;
s->dir = 1;
s->slamming = 0;
s->dead = 0;
s->caughtby = NULL;
s->caughtstate = 0;
s->next = NULL;
lastsprite = s;
return B_FALSE;
}
int loadsprites(void) {
addsprite(P_PLAYER, 100, 400, "Player 1");
player = lastsprite;
addsprite(P_RAT, 200, 200, "Rat");
addsprite(P_RAT, 400, 200, "Rat");
return B_FALSE;
}
tiletype_t *gettileat(int pixx,int pixy, int *tilex,int *tiley) {
int tx,ty;
tx = pixx / TILEW;
ty = pixy / TILEH;
if (tilex != NULL) {
*tilex = tx;
}
if (tiley != NULL) {
*tiley = ty;
}
return gettile(curlevel->map[ty*LEVELW+tx]);
}
void drawnetting(sprite_t *s) {
int sx;
SDL_Rect area;
if (s->netting) {
sx = s->x;
s->nety = s->y - (s->img->h/2);
s->netxstart = s->x;
s->netystart = s->nety - 3;
if (s->netdir == 1) {
area.x = s->netxstart + TILEW/2;
} else {
area.x = s->netxstart - TILEW/2 - s->netlen;
}
area.y = s->netystart;
area.w = s->netlen;
area.h = 7;
SDL_BlitSurface(screen, &area,s->netbg, NULL);
drawline16(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety-3,white);
drawline16(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety,white);
drawline16(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety+3,white);
} else if (s->slamming) {
double dist;
int x,y;
dist = (s->slamangle * (180/M_PI))/2;
s->netxstart = s->x + cos(s->slamangle-(180*(M_PI/180)))*dist*s->dir;
s->netystart = s->y + sin(s->slamangle-(180*(M_PI/180)))*dist;
/* middle line */
drawline16(screen,s->x,s->y - s->img->h/2,
s->netxstart,s->netystart,white);
/* left line */
x = s->x + cos(s->slamangle-(5*(M_PI/180))-(180*(M_PI/180)))*dist*s->dir;
y = s->y + sin(s->slamangle-(5*(M_PI/180))-(180*(M_PI/180)))*dist;
drawline16(screen,s->x,s->y - s->img->h/2,x, y, white);
/* right line */
x = s->x + cos(s->slamangle+(5*(M_PI/180))-(180*(M_PI/180)))*dist*s->dir;
y = s->y + sin(s->slamangle+(5*(M_PI/180))-(180*(M_PI/180)))*dist;
drawline16(screen,s->x,s->y - s->img->h/2,x, y, white);
}
}
void drawsprite(sprite_t *s) {
SDL_Rect area;
int frame;
/* select frame */
if (isfruit(s->id)) {
frame = F_WALK1;
} else if (s->dead) {
frame = F_DEAD + ((timer/2) % 4);
} else if (s->caughtby) {
frame = F_CAUGHT;
} else if (s->jumping) {
frame = F_JUMP;
} else if (s->falling) {
frame = F_FALL;
} else {
if (s->moved) {
if ((timer/6) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_JUMP;
}
} else {
frame = F_WALK1;
}
}
/* x-flip if required */
if (s->dir == -1) {
frame += MAXFRAMES;
}
s->img = imageset[s->id].img[frame];
area.x = s->x - (s->img->w/2);
area.y = s->y - (s->img->h);
area.w = 0;
area.h = 0;
SDL_BlitSurface(s->img, NULL, screen, &area);
/* caughtby lines */
if ((s->caughtby) && (s->caughtstate == 2)){
drawline16(screen, s->x,s->y - s->img->h,
s->caughtby->x,s->caughtby->y-(s->caughtby->img->h/2), white);
drawline16(screen, s->x,s->y - (s->img->h/2),
s->caughtby->x,s->caughtby->y-(s->caughtby->img->h/2), white);
drawline16(screen, s->x,s->y,
s->caughtby->x,s->caughtby->y-(s->caughtby->img->h/2), white);
}
}
void removenetting(sprite_t *s) {
SDL_Rect area,sarea;
if (s->netting) {
sarea.x = 0;
sarea.y = 0;
sarea.w = s->netlen;
sarea.h = 7;
if (s->netdir == 1) {
area.x = s->netxstart + TILEW/2;
} else {
area.x = s->netxstart - TILEW/2 - s->netlen;
}
area.y = s->netystart;
area.w = s->netlen;
area.h = 7;
if (s->netbg != NULL) {
SDL_BlitSurface(s->netbg, &sarea, screen, &area);
}
}
}
void killsprite(sprite_t *s) {
sprite_t *nextone, *lastone;
nextone = s->next;
if (nextone != NULL) {
nextone->prev = s->prev;
} else { /*last sprite */
lastsprite = s->prev;
}
if (s->prev == NULL) {
/* first sprite */
nextone = sprite->next;
free(sprite);
sprite = nextone;
} else {
lastone = s->prev;
free (lastone->next );
lastone->next = nextone;
}
}
void removesprite(sprite_t *s) {
int startx,starty,endx,endy;
int x,y;
/* find topleft-most tile */
gettileat(s->x - s->img->w, s->y - s->img->h,&startx,&starty);
/* find bottomright-most tile */
gettileat(s->x + s->img->w, s->y + s->img->h,&endx,&endy);
if (s->slamming) {
if (s->dir == -1) {
startx -= 5;
endx += 1;
} else {
startx -= 1;
endx += 5;
}
starty -= 2;
endy += 1;
}
/* draw the tiles */
for (y = starty; y <= endy; y++) {
for (x = startx; x <= endx; x++) {
drawtile(x,y);
}
}
}
int isonladder(sprite_t *s) {
tiletype_t *tthere;
tthere = gettileat(s->x,s->y, NULL,NULL);
if ((tthere->id == T_LADDER) || (tthere->id == T_LADDERTOP)) {
return B_TRUE;
}
return B_FALSE;
}
int isladderabove(sprite_t *s) {
tiletype_t *tthere;
tthere = gettileat(s->x,s->y-TILEH, NULL,NULL);
if (tthere->id == T_LADDER) {
return B_TRUE;
}
return B_FALSE;
}
int isonground(sprite_t *s) {
/* get tile below sprite's feet */
if (isongroundpoint(s, s->x, s->y)) {
return B_TRUE;
}
if (!s->falling) {
if (isongroundpoint(s, s->x + s->img->w/2, s->y)) {
return B_TRUE;
}
if (isongroundpoint(s, s->x - s->img->w/2, s->y)) {
return B_TRUE;
}
}
return B_FALSE;
}
int isongroundpoint(sprite_t *s, int x,int y) {
tiletype_t *tt;
int tilex,tiley;
int xoff;
int groundy;
tt = gettileat(x,y, &tilex, &tiley);
/* get offset */
xoff = x - (tilex*TILEW);
/* if it's not solid... */
if (tt->solid == 0) {
return B_FALSE;
} else {
/* check height of tile at that position */
groundy = tiley*TILEH + tt->lowness[xoff];
/* above ground level */
if (y < groundy) {
return B_FALSE;
} else if (y > groundy + 3) {
/* below ground level */
return B_FALSE;
} else if (s->falling) {
tiletype_t *abovetile;
/* falling, on a tile, but with tiles above you */
abovetile = gettileat(x,y-TILEH, NULL, NULL);
if (abovetile->solid) {
return B_FALSE;
}
}
}
return B_TRUE;
}
void dogravity(sprite_t *s) {
sprite_t *s2;
if (s->dead) return;
if (isonladder(s) && !s->falling && !s->jumping) {
s->falling = B_FALSE;
return;
}
if (s->jumping) {
s->falling = B_FALSE;
s->y -= s->jumpspeed;
s->jumping++;
if (s->jumping % 5 == 0) {
if (s->jumpspeed > 0) s->jumpspeed--;
else {
s->jumping = 0;
s->falling = B_TRUE;
s->fallspeed = 0;
}
}
} else {
if (isonground(s)) {
s->falling = B_FALSE;
} else {
s->falling = B_TRUE;
s->y += s->fallspeed;
if ((timer % 10 == 0) && (s->fallspeed < FALLSPEED)) {
s->fallspeed++;
}
}
}
if (s->netting) {
s->netlen += s->netspeed;
s->netting++;
if (s->netting % 2 == 0) {
if (s->netspeed > -NETSPEED) s->netspeed--;
else {
s->netting = 0;
for (s2 = sprite ; s2 ; s2 = s2->next) {
if ((s2->caughtby == s) && (s2->caughtstate == 1)) {
s2->caughtstate = 2;
}
}
}
}
}
if (s->slamming) {
s->slamangle += (10 * (M_PI/180));
if (s->slamangle >= (190 * (M_PI/180))) {
/* if we hit the ground, kill anything we've caught */
s->slamming = 0;
for (s2 = sprite; s2 ; s2 = s2->next) {
if (s2->caughtby == s) {
if (isongroundpoint(s2,s2->x,s->y)) {
s2->dead = 1;
}
s2->caughtby = NULL;
}
}
}
}
}
int movex(sprite_t *s,double amt) {
double newx,newy;
double curx,cury;
int tilex,tiley;
tiletype_t *tt,*tt2;
int newxoff,newgroundy;
int newtilex,newtiley;
double amtdir;
tt = gettileat(s->x, s->y, &tilex,&tiley);
if (amt > 0) amtdir = 1;
else (amtdir = -1);
curx = s->x;
cury = s->y;
/* check for blockage in front of us */
newx = s->x + (amtdir*(s->img->w/2));
newy = cury-TILEH;
tt2 = gettileat(newx,newy,&newtilex,&newtiley);
if (tt2->solid == S_SOLID) {
return B_TRUE;
}
/* get new position */
newx = curx + amt;
newy = cury-2;
tt2 = gettileat(newx,newy,&newtilex,&newtiley);
newxoff = newx - (newtilex*TILEW);
newgroundy = newtiley*TILEH + tt2->lowness[newxoff];
/* new block is at least partially solid */
if (tt2->solid == S_SOLID) {
return B_TRUE;
} else if (tt2->solid == S_SLOPE) {
/* we can move, but need to adjust our height */
s->x += amt;
adjustheight(s);
} else {
/* new block is empty */
s->x += amt;
}
s->moved = B_TRUE;
return B_FALSE;
}
void adjustheight(sprite_t *s) {
tiletype_t *tt;
int xoff,groundy;
int tilex,tiley;
tt = gettileat(s->x,s->y-1,&tilex,&tiley);
if (tt->solid == S_SLOPE) {
xoff = s->x - (tilex*TILEW);
groundy = tiley*TILEH + tt->lowness[xoff];
s->y = groundy;
} else if (tt->solid == S_SOLID) {
while (tt->solid == S_SOLID) {
s->y--;
tt = gettileat(s->x,s->y-1,&tilex,&tiley);
}
}
}
int isfruit(int id) {
if (id == P_CHEESE) return B_TRUE;
return B_FALSE;
}
int ismonster(int id) {
if (id == P_RAT) return B_TRUE;
return B_FALSE;
}
inline void drawpixel16(SDL_Surface *screen, int x, int y, SDL_Color c)
{
Uint16 *bufp;
/* check x/y */
if (x >= screen->w) return;
if (y >= screen->h) return;
if (x < 0) return;
if (y < 0) return;
bufp = (Uint16 *)screen->pixels + (y*screen->pitch / 2) + x;
*bufp = SDL_MapRGB(screen->format, c.r, c.g, c.b);
}
void drawline16(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c) {
int deltax, deltay;
int numpixels;
int d;
int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2;
int i;
int x;
int y;
int maskcount = 0;
int maskindex = 0;
deltax = (x2 - x1);
if (deltax < 0) deltax = -deltax;
deltay = (y2 - y1);
if (deltay < 0) deltay = -deltay;
if (deltax >= deltay) {
numpixels = deltax + 1;
d = (deltay*2) - deltax;
dinc1 = deltay << 1;
dinc2 = (deltay-deltax) << 1;
xinc1 = 1;
xinc2 = 1;
yinc1 = 0;
yinc2 = 1;
} else {
numpixels = deltay + 1;
d = (deltax*2) - deltay;
dinc1 = deltax << 1;
dinc2 = (deltax - deltay) << 1;
xinc1 = 0;
xinc2 = 1;
yinc1 = 1;
yinc2 = 1;
}
if (x1 > x2) {
xinc1 = - xinc1;
xinc2 = - xinc2;
}
if (y1 > y2) {
yinc1 = - yinc1;
yinc2 = - yinc2;
}
x = x1; y = y1;
maskcount = 0;
maskindex = 0;
for (i = 0; i < numpixels; i++) {
drawpixel16(screen,x,y,c);
if (d < 0) {
d += dinc1;
x += xinc1;
y += yinc1;
} else {
d += dinc2;
x += xinc2;
y += yinc2;
}
}
}
void drawbox16(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color *c, SDL_Color *fc) {
if (fc != NULL) {
/* fill */
if (((x2 - x1) >= 2) && ((y2 - y1) >= 2)) {
int y;
for (y = (y1+1) ; y <= (y2-1); y++) {
drawline16(screen, x1+1, y, x2-1,y,*fc);
}
}
}
drawline16(screen,x1,y1,x2,y1,*c);
drawline16(screen,x1,y1,x1,y2,*c);
drawline16(screen,x1,y2,x2,y2,*c);
drawline16(screen,x2,y1,x2,y2,*c);
}