1317 lines
26 KiB
C
1317 lines
26 KiB
C
#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);
|
|
}
|
|
|