ratcatcher/shared.c

4426 lines
114 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.h>
#include <SDL_keysym.h>
#include <SDL_rotozoom.h>
#include <SDL_ttf.h>
#include <SDL_framerate.h>
#include "defs.h"
#include "globals.h"
#include "shared.h"
int loadlevel(int lnum, int wantmonsters) {
FILE *f;
int x,y;
int xx,yy;
char buf[BUFLEN];
char buf2[BUFLEN];
char filename[BUFLEN];
char tempfile[BUFLEN];
char *help[MAXHELP];
int numhelp = 0;
int curhelp = 0;
char *p;
int tileid;
int i;
//int *ii;
//mapping_t mapping[MAXMAPPINGS];
//int nmappings = 0;
//tiletype_t *lasttile;
int newversion;
int numanim = 0;
int leveldone;
int tempanim[LEVELW*LEVELH];
sprite_t *ss, *nextss;
int numenemies = 0;
printf("Loading level %d-%d (seq %d) %s...",getworld(lnum), getlevel(lnum), lnum,levelentry[lnum].filename);
if (lnum == 101) {
// special case for intro
sprintf(filename,"%s/%s/intro.dat",datadir,DIR_LEVELS);
} else {
sprintf(filename,"%s/%s/%s",datadir,DIR_LEVELS,levelentry[lnum].filename);
}
//filename = levelentry[lnum].filename;
f = fopen(filename,"rt");
if (!f) {
printf("can't open level file %s\n",filename);
return B_TRUE;
}
// remember exit direction for current level
// before loading the new one.
if (level) {
oldexitdir = level->exitdir;
} else {
oldexitdir = D_RIGHT;
}
if (!level) {
level = malloc(sizeof(level_t));
level->animtiles = NULL;
}
sprintf(level->filename, levelentry[lnum].filename);
/* set current level pointer */
curlevel = level;
if (level->animtiles) free(level->animtiles);
level->id = levelentry[lnum].id;
sprintf(level->name, "%s",levelentry[lnum].desc);
level->prev = NULL;
level->next = NULL;
/* default */
level->hurryuptime = 30;
if (cheat) {
level->poweruptime = 5;
} else if (getnumplayers() >= 2) {
level->poweruptime = POWERUPTIME2;
} else {
level->poweruptime = POWERUPTIME;
}
level->p1x = 0;
level->p1y = 0;
level->powerupx = -1;
level->powerupy = -1;
/* remove all onscreen text */
while (text) {
killtext(text);
}
/* clear sprite linked list (leave players) */
for (ss = sprite ; ss ; ss = nextss) {
nextss = ss->next;
if (!isplayer(ss)) {
killsprite(ss);
}
}
/* 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 ( level->tileset) free(level->tileset);
level->tileset = strdup(p);
strcat(p, ".tiles");
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;
}
*/
/* load background image */
fgets(buf, BUFLEN, f);
if (strstr(buf, "bgfile") == buf) {
SDL_Surface *ts;
p = strtok(buf, " ");
p = strtok(NULL, " ");
// strip newline
p[strlen(p)-1] = '\0';
if (levelbg) SDL_FreeSurface(levelbg);
sprintf(level->bgfile, "%s",p);
sprintf(tempfile, "%s/backgrounds/%s",datadir,level->bgfile);
ts = IMG_Load(tempfile);
if (!ts) {
printf("Cannot load background file: %s\n", tempfile);
// default to forest
sprintf(tempfile, "%s/backgrounds/forest.png",datadir);
ts = IMG_Load(tempfile);
SDL_SetColorKey(ts, SDL_RLEACCEL, 0);
levelbg = SDL_DisplayFormat(ts);
SDL_FreeSurface(ts);
} else {
SDL_SetColorKey(ts, SDL_RLEACCEL, 0);
levelbg = SDL_DisplayFormat(ts);
SDL_FreeSurface(ts);
}
} else {
SDL_Surface *ts;
// default to forest
if (levelbg) SDL_FreeSurface(levelbg);
sprintf(tempfile, "%s/backgrounds/forest.png",datadir);
ts = IMG_Load(tempfile);
SDL_SetColorKey(ts, SDL_RLEACCEL, 0);
levelbg = SDL_DisplayFormat(ts);
SDL_FreeSurface(ts);
}
//if (levelbg) SDL_FreeSurface(levelbg);
//levelbg = IMG_Load("backgrounds/forest.png");
/* 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;
}
/* read hurryup time tile */
fgets(buf, BUFLEN, f);
if (strstr(buf, "hurryup") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
level->hurryuptime = atoi(p);
//printf("Hurryup time is %d\n",level->hurryuptime);
} else {
printf("invalid hurryup time line: '%s'\n",buf);
return B_TRUE;
}
level->nummonsters = 0;
fgets(buf, BUFLEN, f);
/* read help messages if present */
if (strstr(buf, "help")) {
curhelp = 0; // used later
numhelp = 0;
fgets(buf, BUFLEN, f);
while (!strstr(buf, "endhelp")) {
// strip newline
buf[strlen(buf)-1] = '\0';
help[numhelp] = strdup(buf);
numhelp++;
fgets(buf, BUFLEN, f);
}
/* this reads the first line of the level */
fgets(buf, BUFLEN, f);
}
/* read monster definitions if present */
if (strstr(buf, "monsters")) {
fgets(buf, BUFLEN, f);
while (!strstr(buf, "endmonsters")) {
//char ch;
int monid;
int x,y;
// strip newline
buf[strlen(buf)-1] = '\0';
strncpy(buf2,buf,BUFLEN);
p = strtok(buf2, " ");
if (p == NULL) {
printf("invalid monster definition (missing type): '%s'\n",buf);
return B_TRUE;
}
//ch = p[0]; // type of monster
//monid = chartomonster(ch);
// type of monster
monid = atoi(p);
if (monid < 0) {
printf("invalid monster definition (invalid type): '%s'\n",buf);
return B_TRUE;
}
p = strtok(NULL, " ");
if (p == NULL) {
printf("invalid monster definition (missing x): '%s'\n",buf);
return B_TRUE;
}
x = atoi(p); // monster x pos
p = strtok(NULL, " ");
if (p == NULL) {
printf("invalid monster definition (missing y): '%s'\n",buf);
return B_TRUE;
}
y = atoi(p); // monster y pos
// waypoints
if (isplatform(monid)) {
// initial waypoint is start position
level->initm[level->nummonsters].wayx[0] = x*TILEW+(TILEW/2);
level->initm[level->nummonsters].wayy[0] = y*TILEH+(TILEH-2)+2;
level->initm[level->nummonsters].numwaypoints = 1;
// read waypoints
p = strtok(NULL, " ");
while (p) {
level->initm[level->nummonsters].wayx[level->initm[level->nummonsters].numwaypoints] = atoi(p);
p = strtok(NULL, " ");
level->initm[level->nummonsters].wayy[level->initm[level->nummonsters].numwaypoints] = atoi(p);
level->initm[level->nummonsters].numwaypoints++;
// go to next one
p = strtok(NULL, " ");
}
if ( level->initm[level->nummonsters].numwaypoints <= 0 ){
printf("missing waypoint data for platform!\n");
}
}
if (monid == P_PLAYER) {
level->p1x = x;
level->p1y = y;
} else if (monid == P_PLAYER2) {
level->p2x = x;
level->p2y = y;
} else if (monid == P_POWERUPPOS) {
level->powerupx = x;
level->powerupy = y;
level->poweruptype = randompowerup();
} else {
/* place the monster */
level->initm[level->nummonsters].startx = x*TILEW+(TILEW/2);
level->initm[level->nummonsters].starty = y*TILEH+(TILEH-2)+2;
level->initm[level->nummonsters].id = monid;
if (ismonster(monid)) numenemies++;
if (monid == P_HELP) {
if (curhelp >= numhelp) {
printf("Error in level - more help icons than help texts.\n");
exit(1);
} else {
level->initm[level->nummonsters].help = strdup(help[curhelp]);
curhelp++;
}
}
level->nummonsters++;
if (level->nummonsters >= MAXMONSTERSPERLEVEL) {
printf("ERROR: too many sprites !\n");
fclose(f);
return B_TRUE;
}
}
fgets(buf, BUFLEN, f);
}
/* this reads the next line after monster defs */
fgets(buf, BUFLEN, f);
}
/* exitdir ? */
if (strstr(buf, "exitdir")) {
p = strtok(buf, " "); // "exitdir"
p = strtok(NULL, " ");
level->exitdir = atoi(p);
/*
printf("Exit direction is ");
switch (level->exitdir) {
case D_RIGHT:
printf("RIGHT"); break;
case D_LEFT:
printf("lEFT"); break;
case D_UP:
printf("UP"); break;
case D_DOWN:
printf("DOWN"); break;
default:
level->exitdir = D_RIGHT;
printf("*INVALID*");
break;
}
*/
printf("\n");
fgets(buf, BUFLEN, f);
} else {
level->exitdir = D_RIGHT;
printf("Defaulting to exitdir of RIGHT.\n");
}
/* check whether we've got a new or old level version */
if (strstr(buf, ",")) {
/* new version */
newversion = B_TRUE;
printf("Level data is new version.\n");
} else {
/* old version */
newversion = B_FALSE;
printf("Level data is old version.\n");
}
x = 0;
y = 0;
leveldone = B_FALSE;
level->bottomopen = B_FALSE; // default, could get chnaged in the next block of code
while (!leveldone) {
/* process a line of level data */
if (newversion) {
strncpy(buf2, buf, BUFLEN);
p = strtok(buf2, ",");
while (p) {
int numframes;
tileid = atoi(p);
/* validate it */
if (!gettile(tileid)) {
printf("invalid tileid: %d\n",tileid);
fclose(f);
return B_TRUE;
}
if (x > LEVELW) {
printf("Too many tiles on line %d: %d,%d\n",y,x,y);
fclose(f);
return B_TRUE;
}
if (y >= LEVELH) {
printf("Too many lines at line %d: %d,%d\n",y,x,y);
fclose(f);
return B_TRUE;
}
/* all okay */
level->map[y*LEVELW+x] = tileid;
numframes = gettileframecount(tileid);
if (numframes == 1) {
// not animated
level->tileframe[y*LEVELW+x] = 0;
} else {
tiletype_t *thistile;
// animated
thistile = gettile(tileid);
if (thistile->animsync) {
level->tileframe[y*LEVELW+x] = 0;
} else {
level->tileframe[y*LEVELW+x] = rand() % numframes;
}
tempanim[numanim] = y*LEVELW+x;
numanim++;
}
// if this is the last line, update level->bottomopen
if (y == LEVELH-1) {
tiletype_t *thistile;
thistile = gettile(tileid);
if (!thistile->solid) {
level->bottomopen = B_TRUE;
}
}
x++;
p = strtok(NULL, ",");
}
} else { // old level data version
printf("ERROR: old level data!\n");
fclose(f);
return B_TRUE;
}
/* make sure enough data was found */
if (x < LEVELW+1) {
printf("Not enough tiles on line: y = %d\n",y);
fclose(f);
return B_TRUE;
}
/* go to next line */
y++;
x = 0;
fgets(buf, BUFLEN, f);
if (feof(f)) {
leveldone = B_TRUE;
} else if (strstr(buf, "layer2")) {
leveldone = B_TRUE;
}
}
// clear out layer2 by default
for (xx = 0; xx < LEVELW; xx++) {
for (yy = 0; yy < LEVELH; yy++) {
level->map2[yy*LEVELW+xx] = T_BLANK;
}
}
if (!feof(f)) {
int tid,xx,yy;
//printf("found second layer\n");
// second layer exists - read it
fgets(buf, BUFLEN, f);
while (!feof(f)) {
// format is x,y,tileid
p = strtok(buf, ","); xx = atoi(p);
p = strtok(NULL, ","); yy = atoi(p);
p = strtok(NULL, ","); tid = atoi(p);
level->map2[yy*LEVELW+xx] = tid;
fgets(buf, BUFLEN, f);
}
}
fclose(f);
// copy from our temp buffer into the real one
level->animtiles = malloc(sizeof(int) * (numanim+1));
memcpy(level->animtiles,tempanim,numanim*sizeof(int));
level->animtiles[numanim] = -1;
//level->animtiles = realloc(level->animtiles, (numanim+2) * sizeof(int)); // leave space for terminator
if ((numhelp > 0) && (curhelp != numhelp)) {
printf("WARNING: Unused help text. First unused is '%s'\n",help[curhelp]);
}
if (y < LEVELH) {
printf("Not enough lines in level: last y=%d, should be %d.\n",
y,LEVELH);
return B_TRUE;
}
#ifndef __EDITOR
if ((level->p1x == 0) || (level->p1y == 0)) {
printf("Level is missing player 1 start position.\n");
return B_TRUE;
}
if ((level->p2x == 0) || (level->p2y == 0)) {
printf("Level is missing player 2 start position.\n");
return B_TRUE;
}
#endif
/* free help texts */
for (i = 0; i < numhelp; i++) {
free(help[i]);
}
/* add player if required */
if (want1up) {
if (player == NULL) {
player = addsprite(P_PLAYER, (curlevel->p1x * TILEW) + (TILEW/2),
(curlevel->p1y * TILEH) + TILEH-2 , "Player 1" );
}
}
if (want2up) {
if (player2 == NULL) {
player2 = addsprite(P_PLAYER2, (curlevel->p2x * TILEW) + (TILEW/2),
(curlevel->p2y * TILEH) + TILEH-2 , "Player 2" );
}
}
// don't move player to start of the level if they already exist, becuase they're
// currently on a cloud - we move them after the level transition animation.
#ifdef __EDITOR
/* add powerup and player pos if they exists */
if ((level->powerupx != -1) && (level->powerupy != -1)) {
addsprite(P_POWERUPPOS, (curlevel->powerupx * TILEW) + (TILEW/2),
(curlevel->powerupy * TILEH) + TILEH-2 , "poweruppos" );
}
player->x = (curlevel->p1x * TILEW) + (TILEW/2);
player->y = (curlevel->p1y * TILEH) + TILEH-2 ;
player2->x = (curlevel->p2x * TILEW) + (TILEW/2);
player2->y = (curlevel->p2y * TILEH) + TILEH-2 ;
#endif
/*else {
player->x = (curlevel->p1x * TILEW) + (TILEW/2);
player->y = (curlevel->p1y * TILEH) + TILEH-2;
}
*/
/* add monsters */
if (wantmonsters) {
for (i = 0; i < level->nummonsters; i++) {
char name[MIDBUFLEN];
int delay;
if (level->initm[i].id == P_HELP) {
// is help disabled?
#ifndef __EDITOR
if (showhelp == B_FALSE ) continue;
#endif
strncpy(name, level->initm[i].help, MIDBUFLEN);
} else {
sprintf(name, "Monster-%d",i);
}
if (ismonster(level->initm[i].id)) {
delay = 20;
} else {
delay = 0;
}
if (isplatform(level->initm[i].id)) {
sprite_t *newsp;
int w;
newsp = addsprite(level->initm[i].id, level->initm[i].startx, level->initm[i].starty, name );
newsp->numwaypoints = level->initm[i].numwaypoints;
for (w = 0; w < newsp->numwaypoints; w++) {
newsp->wayx[w] = level->initm[i].wayx[w];
newsp->wayy[w] = level->initm[i].wayy[w];
}
newsp->curwaypoint = 1;
} else {
#ifdef __EDITOR
addsprite(level->initm[i].id, level->initm[i].startx, level->initm[i].starty, name );
#else
puffin(level->initm[i].id, level->initm[i].startx, level->initm[i].starty, name, delay );
#endif
}
}
}
gtime = 0;
resethurryup(level);
boss = NULL;
printf("Done.\n");
/*
for (ii = level->animtiles ; ii && *ii != -1; ii++) {
printf("%d ",*ii);
}
printf(".\n");
*/
return B_FALSE;
}
void setdefaults(sprite_t *s) {
if (isplayer(s)) {
// set permenant powerups based on level
if (curlevelnum > 20) {
s->permspeed = B_TRUE;
} else {
s->permspeed = B_FALSE;
}
if (curlevelnum > 40) {
s->permmask = B_TRUE;
} else {
s->permmask = B_FALSE;
}
if (curlevelnum > 60) {
s->permumbrella = B_TRUE;
} else {
s->permumbrella = B_FALSE;
}
// player powerup stats
if (s->permspeed) {
s->speed = 2;
} else {
s->speed = 1;
}
if (s->permbignet) {
s->netbig = B_TRUE;
} else {
s->netbig = B_FALSE;
}
if (s->permmask) {
s->hasmask = B_TRUE;
} else {
s->hasmask = B_FALSE;
}
if (s->permnumnets) {
s->netmax = s->permnumnets;
} else {
s->netmax = 1;
}
if (s->permsticky) {
s->netsticky = B_TRUE;
} else {
s->netsticky = B_FALSE;
}
if (s->permdoublejump) {
s->doublejump = B_TRUE;
} else {
s->doublejump = B_FALSE;
}
if (s->permarmour) {
s->armour = B_TRUE;
if (s == player) {
s->id = P_ARMOUR;
} else {
s->id = P_ARMOUR2;
}
} else {
s->armour = B_FALSE;
}
if (s->permumbrella) {
s->umbrella = B_TRUE;
} else {
s->umbrella = B_FALSE;
}
} else {
if (s->id == P_PLATFORM) {
s->speed = PLATFORM_MAXSPEED;
} else {
s->speed = 1;
}
s->hasmask = B_FALSE;
s->armour = B_FALSE;
s->netsticky = B_FALSE;
s->doublejump = B_FALSE;
s->umbrella = B_FALSE;
s->netbig = B_FALSE;
s->netmax = 1;
}
s->doublejumpready = B_FALSE;
s->allocimg = B_FALSE;
s->frame = 0;
s->onplatform = NULL;
s->antigrav = B_FALSE;
s->hasbell = B_FALSE;
s->gemboost = 1;
s->powerup = PW_NONE;
// player-only states
s->netting = 0;
s->netcaught = 0;
s->slamming = 0;
s->invuln = 0;
// states
s->recoiling = B_FALSE;
s->teleporting = 0;
s->climbing = 0;
s->swimming = 0;
s->jumping = 0;
s->jumpspeed = 0;
s->jumpdir = 1;
s->useddoublejump = B_FALSE;
s->umbrellaup = B_FALSE;
if (s->id != P_RANDOM) {
// random gets timer1 set during addsprite()
s->timer1 = 0;
}
s->timer2 = 0;
s->timer3 = 0;
s->timer4 = 0;
s->dbltimer = -1;
s->dropping = 0;
s->dropx = -1;
s->dropy = -1;
s->ontramp = B_FALSE;
s->trampx = -1;
s->trampy = -1;
s->quickdie = B_FALSE;
s->falling = 0;
s->fallspeed = 0;
s->dir = 1;
s->dead = 0;
s->angry = 0;
s->jumptimer = 0;
s->willjumpspeed = 0;
s->iced = B_FALSE;
if (s->iceimg) {
SDL_FreeSurface(s->iceimg);
s->iceimg = NULL;
}
s->watertimer = 0;
s->bullet = NULL;
s->owner = NULL;
s->willbecome = P_CHEESE;
// special
if (s->id == P_PINKCLOUD) {
s->size = 0.1;
} else if (s->id == P_BLACKCLOUD) {
s->size = 0.1;
} else {
// not used
s->size = -1;
}
// special
if (s->id == P_SNAIL) {
s->lives = 1;
}
// special for bosses
if (s->id == P_KINGRAT) {
s->timer1 = 0;
s->timer2 = KR_WALKTIME;
s->timer3 = 0;
} else if (s->id == P_KINGSNAIL) {
s->timer1 = KSS_WALK1;
s->timer2 = KS_WALKTIME;
s->timer3 = 0;
} else if (s->id == P_KINGFLY) {
s->timer1 = KFS_FLY1;
s->timer2 = KF_FLYTIME;
s->timer3 = 0;
s->xs = -99;
s->ys = -99;
}
if (isboss(s->id)) {
s->lives = getbosshealth(s->id); // health
}
// flying
switch (s->id) {
case P_BEE:
case P_FISH:
case P_BLACKCLOUD:
case P_SPIDER:
case P_KINGFLY:
s->flies = B_TRUE;
break;
case P_FLY:
s->flies = F_FLYVERT;
break;
default:
s->flies = B_FALSE;
break;
}
if (!isplayer(s)) {
s->score = getpoints(s->id);
}
s->caughtby = NULL;
s->caughtstate = B_FALSE;
s->zapping = NULL;
s->xs = -99;
s->ys = -99;
s->doomcount = 0;
}
/* initial is TRUE if we are populating the level for the first time */
sprite_t *addsprite(int id, int x, int y, char *name ) {
sprite_t *s;
int c;
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;
// special case for random powerup
if (s->id == P_RANDOM) {
s->timer1 = randompowerup();
while (s->timer1 == P_RANDOM) {
// pick again
s->timer1 = randompowerup();
}
}
if (s->id == P_BLACKCLOUD) {
s->img = rotozoomSurfaceXY(imageset[id].img[F_WALK1],0,0.1,0.1,0);
} else if (s->id == P_PINKCLOUD) {
s->img = rotozoomSurfaceXY(imageset[id].img[F_WALK1],0,(double)PCGROWSPEED,(double)PCGROWSPEED,0);
} else if (s->id == P_RANDOM) {
s->img = imageset[s->timer1].img[F_WALK1];
} else {
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_SWSURFACE,
200, 64,
screen->format->BitsPerPixel, screen->format->Rmask,
screen->format->Gmask,screen->format->Bmask,
screen->format->Amask);
} else {
s->netbg = NULL;
}
s->iceimg = NULL;
// waypoints for moving platforms
s->numwaypoints = 0;
s->curwaypoint = 0;
// don't set these in setdefaults() as setdefaults() is called after each player death
s->permspeed = B_FALSE;
s->permmask = B_FALSE;
s->permumbrella = B_FALSE;
s->permbignet = B_FALSE;
s->permnumnets = B_FALSE;
s->permsticky = B_FALSE;
s->permdoublejump = B_FALSE;
s->permarmour = B_FALSE;
s->lostlife = B_FALSE;
// don't set this in setdefaults() as setdefaults() is called after each player death
s->numcards = 0;
for (c = 0; c < MAXCARDS; c++) {
s->card[c] = -1;
s->usedcard[c] = 0;
}
setdefaults(s);
// initial fruits don't time out
#ifndef __EDITOR
if ((levelcomplete != LV_NEXTLEV) && (levelcomplete != LV_INIT)) {
if (isfruit(s->id)) {
// random powerups stay for longer
if (!strcmp(s->name, "random_up")) {
s->doomcount = 900;
} else {
s->doomcount = 500;
}
}
}
#endif
s->next = NULL;
lastsprite = s;
return s;
}
tiletype_t *gettileat(int pixx,int pixy, int *tilex,int *tiley) {
int tx,ty;
int tid;
tx = pixx / TILEW;
ty = pixy / TILEH;
if (tilex != NULL) {
*tilex = tx;
}
if (tiley != NULL) {
*tiley = ty;
}
if (ty >= LEVELH) {
// if tile is off the bottom of the screen,
// return one from the top row
ty = 0;
}
if (pixy < 0) {
// if tile is off the top of the screen,
// return one from the bottom row
ty = LEVELH-1;
}
// return layer2 if it exists
tid = curlevel->map2[ty*LEVELW+tx];
if (tid == T_BLANK) {
tid = curlevel->map[ty*LEVELW+tx];
}
return gettile(tid);
}
int loadtiletypes(char *filename) {
char fullfile[BUFLEN];
tiletype_t *t = NULL;
int i;
int state;
FILE *f;
char buf[BUFLEN];
char dirname[BUFLEN];
char imagefile[BUFLEN];
char *p,*pp;
int uniq = 0 ;
/* clear tiletype linked list */
while (tiletype != NULL) {
int i;
tiletype_t *tt;
/* kill first tile */
for (i = 0; i < tiletype->numframes; i++) {
if (tiletype->img[i]) {
SDL_FreeSurface(tiletype->img[i]);
tiletype->img[i] = NULL;
}
}
tt = tiletype->next;
free(tiletype);
tiletype = tt;
}
sprintf(fullfile, "%s/%s",datadir,filename);
state = 0;
f = fopen(fullfile,"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 */
strcpy(dirname, ".");
t->id = 0;
t->animspeed = 0; // not animated
t->numframes = 1; // not animated
t->animsync = B_FALSE;
t->water = B_FALSE;
t->spikes = B_FALSE;
t->solid = B_TRUE;
for (i = 0; i < TILEW; i++) {
t->lowness[i] = 0;
}
for (i = 0; i < MAXTILEFRAMES; i++) {
t->img[i] = NULL;
}
t->next = NULL;
state = 1;
/* unique id */
t->uniqid = uniq;
uniq++;
}
} 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);
/* check */
state = 0;
} else if (strstr(buf, "id") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
t->id = atoi(p);
} else if (strstr(buf, "dir") == buf) { // tile directory
/* strip newline */
buf[strlen(buf)-1] = '\0';
p = strtok(buf, " ");
p = strtok(NULL, " ");
strcpy(dirname, p);
} else if (strstr(buf, "animspeed") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
t->animspeed = atoi(p);
} else if (strstr(buf, "animsync") == buf) {
t->animsync = B_TRUE;
} 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, "spikes") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
t->spikes = atoi(p);
} else if (strstr(buf, "water") == buf) {
p = strtok(buf, " ");
p = strtok(NULL, " ");
t->water = atoi(p);
} else if (strstr(buf, "file") == buf) {
int frame;
/* strip newline */
buf[strlen(buf)-1] = '\0';
p = strtok(buf, " ");
// read all images
frame = 0;
p = strtok(NULL, " ");
while (p) {
if (t->img[frame]) {
SDL_FreeSurface(t->img[frame]);
t->img[frame] = NULL;
}
sprintf(imagefile, "%s/%s/%s",datadir,dirname,p);
//strcpy(imagefile, dirname);
//strcat(imagefile, "/");
//strcat(imagefile, p);
//t->img[frame] = IMG_Load(imagefile);
t->img[frame] = IMG_Load(imagefile);
if (!t->img[frame]) {
printf("cannot load tile image file: '%s'\n",imagefile);
fclose(f);
return B_TRUE;
}
// black is transparent
SDL_SetColorKey(t->img[frame], SDL_SRCCOLORKEY, SDL_MapRGB(screen->format, 0, 0, 0));
// get next one
frame++;
p = strtok(NULL, " ");
}
t->numframes = frame;
// default animation speed
t->animspeed = 20;
}
}
fgets(buf, BUFLEN, f);
}
fclose(f);
return B_FALSE;
}
int loadimagesets(void) {
int p,i;
SDL_Surface *tempimg;
SDL_Surface *reds;
SDL_Surface *origi;
char tempfile[BUFLEN];
sprintf(tempfile, "%s/sprites/gravestone.png",datadir);
grave = IMG_Load(tempfile);
sprintf(tempfile, "%s/sprites/dwarfhead.png",datadir);
head = IMG_Load(tempfile);
sprintf(tempfile, "%s/sprites/dwarfhead5.png",datadir);
head5 = IMG_Load(tempfile);
sprintf(tempfile, "%s/sprites/dwarf2head.png",datadir);
head2 = IMG_Load(tempfile);
sprintf(tempfile, "%s/sprites/dwarf2head5.png",datadir);
head52 = IMG_Load(tempfile);
sprintf(tempfile, "%s/sprites/icecube.png",datadir);
icecube = IMG_Load(tempfile);
sprintf(tempfile, "%s/sprites/health.png",datadir);
healthbar[HF_GREEN] = IMG_Load(tempfile);
sprintf(tempfile, "%s/sprites/healthyellow.png",datadir);
healthbar[HF_YELLOW] = IMG_Load(tempfile);
sprintf(tempfile, "%s/sprites/healthred.png",datadir);
healthbar[HF_RED] = IMG_Load(tempfile);
// green square for flyspray effect
greenbox = SDL_CreateRGBSurface(SDL_SWSURFACE,
screen->w,
screen->h,
screen->format->BitsPerPixel, screen->format->Rmask,
screen->format->Gmask,screen->format->Bmask, 0);
SDL_FillRect(greenbox, NULL, SDL_MapRGB(greenbox->format, 0, 150, 0));
SDL_SetAlpha(greenbox, SDL_SRCALPHA,80);
// red square for gunner effect
redbox = SDL_CreateRGBSurface(SDL_SWSURFACE,
screen->w,
screen->h,
screen->format->BitsPerPixel, screen->format->Rmask,
screen->format->Gmask,screen->format->Bmask, 0);
SDL_FillRect(redbox, NULL, SDL_MapRGB(greenbox->format, 150, 0, 0));
SDL_SetAlpha(redbox, SDL_SRCALPHA,80);
loadspriteimage(P_PLAYER,F_WALK1, "sprites/pdwarf.png");
loadspriteimage(P_PLAYER,F_JUMP, "sprites/pdwarfjump.png");
loadspriteimage(P_PLAYER,F_FALL, "sprites/pdwarffall.png");
loadspriteimage(P_PLAYER,F_CAUGHT, "sprites/dwarfdie.png");
loadspriteimage(P_PLAYER,F_DEAD, "sprites/dwarfdie.png");
/* next 3 are auto generated */
loadspriteimage(P_PLAYER,F_CLIMB1, "sprites/dclimb1.png");
loadspriteimage(P_PLAYER,F_CLIMB2, "sprites/dclimb2.png");
loadspriteimage(P_PLAYER,F_SHOOT, "sprites/dwarfshoot.png");
loadspriteimage(P_PLAYER,F_SLAM1, "sprites/dslam1.png");
loadspriteimage(P_PLAYER,F_SLAM2, "sprites/dslam2.png");
loadspriteimage(P_PLAYER,F_SLAM3, "sprites/dslam3.png");
loadspriteimage(P_PLAYER,F_SLAM4, "sprites/dslam4.png");
loadspriteimage(P_PLAYER,F_SLAM5, "sprites/dslam5.png");
loadspriteimage(P_PLAYER,F_SWIM1, "sprites/dswim1.png");
loadspriteimage(P_PLAYER,F_SWIM2, "sprites/dswim2.png");
imageset[P_PLAYER].numimages = 18;
loadspriteimage(P_PLAYER2,F_WALK1, "sprites/p2dwarf.png");
loadspriteimage(P_PLAYER2,F_JUMP, "sprites/p2dwarfjump.png");
loadspriteimage(P_PLAYER2,F_FALL, "sprites/p2dwarffall.png");
loadspriteimage(P_PLAYER2,F_CAUGHT, "sprites/dwarf2die.png");
loadspriteimage(P_PLAYER2,F_DEAD, "sprites/dwarf2die.png");
/* next 3 are auto generated */
loadspriteimage(P_PLAYER2,F_CLIMB1, "sprites/d2climb1.png");
loadspriteimage(P_PLAYER2,F_CLIMB2, "sprites/d2climb2.png");
loadspriteimage(P_PLAYER2,F_SHOOT, "sprites/dwarf2shoot.png");
loadspriteimage(P_PLAYER2,F_SLAM1, "sprites/d2slam1.png");
loadspriteimage(P_PLAYER2,F_SLAM2, "sprites/d2slam2.png");
loadspriteimage(P_PLAYER2,F_SLAM3, "sprites/d2slam3.png");
loadspriteimage(P_PLAYER2,F_SLAM4, "sprites/d2slam4.png");
loadspriteimage(P_PLAYER2,F_SLAM5, "sprites/d2slam5.png");
loadspriteimage(P_PLAYER2,F_SWIM1, "sprites/d2swim1.png");
loadspriteimage(P_PLAYER2,F_SWIM2, "sprites/d2swim2.png");
imageset[P_PLAYER2].numimages = 18;
loadspriteimage(P_ARMOUR,F_WALK1, "sprites/armor.png");
loadspriteimage(P_ARMOUR,F_JUMP, "sprites/armorjump.png");
loadspriteimage(P_ARMOUR,F_FALL, "sprites/armorfall.png");
loadspriteimage(P_ARMOUR,F_CAUGHT, "sprites/armorcaught.png");
loadspriteimage(P_ARMOUR,F_DEAD, "sprites/dwarfdie.png");
/* next 3 are auto generated */
loadspriteimage(P_ARMOUR,F_CLIMB1, "sprites/armorclimb1.png");
loadspriteimage(P_ARMOUR,F_CLIMB2, "sprites/armorclimb2.png");
loadspriteimage(P_ARMOUR,F_SHOOT, "sprites/armorshoot.png");
loadspriteimage(P_ARMOUR,F_SLAM1, "sprites/armorslam1.png");
loadspriteimage(P_ARMOUR,F_SLAM2, "sprites/armorslam2.png");
loadspriteimage(P_ARMOUR,F_SLAM3, "sprites/armorslam3.png");
loadspriteimage(P_ARMOUR,F_SLAM4, "sprites/armorslam4.png");
loadspriteimage(P_ARMOUR,F_SLAM5, "sprites/armorslam5.png");
loadspriteimage(P_ARMOUR,F_SWIM1, "sprites/armorswim1.png");
loadspriteimage(P_ARMOUR,F_SWIM2, "sprites/armorswim2.png");
imageset[P_ARMOUR].numimages = 18;
loadspriteimage(P_ARMOUR2,F_WALK1, "sprites/armor2.png");
loadspriteimage(P_ARMOUR2,F_JUMP, "sprites/armor2jump.png");
loadspriteimage(P_ARMOUR2,F_FALL, "sprites/armor2fall.png");
loadspriteimage(P_ARMOUR2,F_CAUGHT, "sprites/armor2caught.png");
loadspriteimage(P_ARMOUR2,F_DEAD, "sprites/dwarfdie.png"); // not used
/* next 3 are auto generated */
loadspriteimage(P_ARMOUR2,F_CLIMB1, "sprites/armor2climb1.png");
loadspriteimage(P_ARMOUR2,F_CLIMB2, "sprites/armor2climb2.png");
loadspriteimage(P_ARMOUR2,F_SHOOT, "sprites/armor2shoot.png");
loadspriteimage(P_ARMOUR2,F_SLAM1, "sprites/armor2slam1.png");
loadspriteimage(P_ARMOUR2,F_SLAM2, "sprites/armor2slam2.png");
loadspriteimage(P_ARMOUR2,F_SLAM3, "sprites/armor2slam3.png");
loadspriteimage(P_ARMOUR2,F_SLAM4, "sprites/armor2slam4.png");
loadspriteimage(P_ARMOUR2,F_SLAM5, "sprites/armor2slam5.png");
loadspriteimage(P_ARMOUR2,F_SWIM1, "sprites/armor2swim1.png");
loadspriteimage(P_ARMOUR2,F_SWIM2, "sprites/armor2swim2.png");
imageset[P_ARMOUR2].numimages = 18;
loadspriteimage(P_SNAKE,F_WALK1, "sprites/snake.png");
loadspriteimage(P_SNAKE,F_JUMP, "sprites/snakejump.png");
loadspriteimage(P_SNAKE,F_FALL, "sprites/snakejump.png");
loadspriteimage(P_SNAKE,F_CAUGHT, "sprites/snakecaught.png");
loadspriteimage(P_SNAKE,F_DEAD, "sprites/snakedead.png");
/* next 3 are auto generated */
imageset[P_SNAKE].numimages = 8;
loadspriteimage(P_RAT,F_WALK1, "sprites/rat.png");
loadspriteimage(P_RAT,F_JUMP, "sprites/ratjump.png");
loadspriteimage(P_RAT,F_FALL, "sprites/ratjump.png");
loadspriteimage(P_RAT,F_CAUGHT, "sprites/ratcaught.png");
loadspriteimage(P_RAT,F_DEAD, "sprites/ratdead.png");
/* next 3 are auto generated */
imageset[P_RAT].numimages = 8;
loadspriteimage(P_BEE,F_WALK1, "sprites/newbee.png");
loadspriteimage(P_BEE,F_JUMP, "sprites/newbeejump.png");
loadspriteimage(P_BEE,F_FALL, "sprites/newbeejump.png");
loadspriteimage(P_BEE,F_CAUGHT, "sprites/newbeecaught.png");
loadspriteimage(P_BEE,F_DEAD, "sprites/newbeedead.png");
/* next 3 are auto generated */
imageset[P_BEE].numimages = 8;
loadspriteimage(P_FLY,F_WALK1, "sprites/fly.png");
loadspriteimage(P_FLY,F_JUMP, "sprites/flywalk2.png");
loadspriteimage(P_FLY,F_FALL, "sprites/flyjump.png");
loadspriteimage(P_FLY,F_CAUGHT, "sprites/flycaught.png");
loadspriteimage(P_FLY,F_DEAD, "sprites/flydead.png");
/* next 3 are auto generated */
imageset[P_FLY].numimages = 8;
loadspriteimage(P_FROG,F_WALK1, "sprites/frog.png");
loadspriteimage(P_FROG,F_JUMP, "sprites/frogjump.png");
loadspriteimage(P_FROG,F_FALL, "sprites/frogfall.png");
loadspriteimage(P_FROG,F_CAUGHT, "sprites/frogcaught.png");
loadspriteimage(P_FROG,F_DEAD, "sprites/frogdead.png");
/* next 3 are auto generated */
imageset[P_FROG].numimages = 8;
loadspriteimage(P_ANT1,F_WALK1, "sprites/ant1.png");
loadspriteimage(P_ANT1,F_JUMP, "sprites/ant1jump.png");
loadspriteimage(P_ANT1,F_FALL, "sprites/ant1jump.png");
loadspriteimage(P_ANT1,F_CAUGHT, "sprites/ant1caught.png");
loadspriteimage(P_ANT1,F_DEAD, "sprites/ant1dead.png");
/* next 3 are auto generated */
imageset[P_ANT1].numimages = 8;
loadspriteimage(P_ANT2,F_WALK1, "sprites/ant2.png");
loadspriteimage(P_ANT2,F_JUMP, "sprites/ant2jump.png");
loadspriteimage(P_ANT2,F_FALL, "sprites/ant2jump.png");
loadspriteimage(P_ANT2,F_CAUGHT, "sprites/ant2caught.png");
loadspriteimage(P_ANT2,F_DEAD, "sprites/ant2dead.png");
/* next 3 are auto generated */
imageset[P_ANT2].numimages = 8;
loadspriteimage(P_ANT3,F_WALK1, "sprites/ant3.png");
loadspriteimage(P_ANT3,F_JUMP, "sprites/ant3jump.png");
loadspriteimage(P_ANT3,F_FALL, "sprites/ant3jump.png");
loadspriteimage(P_ANT3,F_CAUGHT, "sprites/ant3caught.png");
loadspriteimage(P_ANT3,F_DEAD, "sprites/ant3dead.png");
/* next 3 are auto generated */
imageset[P_ANT3].numimages = 8;
loadspriteimage(P_SPIDER,F_WALK1, "sprites/newspider.png");
loadspriteimage(P_SPIDER,F_JUMP, "sprites/newspiderjump.png");
loadspriteimage(P_SPIDER,F_FALL, "sprites/newspiderfall.png");
loadspriteimage(P_SPIDER,F_CAUGHT, "sprites/newspidercaught.png");
loadspriteimage(P_SPIDER,F_DEAD, "sprites/newspiderdead.png");
/* next 3 are auto generated */
imageset[P_SPIDER].numimages = 8;
loadspriteimage(P_FISH,F_WALK1, "sprites/fish.png");
loadspriteimage(P_FISH,F_JUMP, "sprites/fishjump.png");
loadspriteimage(P_FISH,F_FALL, "sprites/fishjump.png");
loadspriteimage(P_FISH,F_CAUGHT, "sprites/fishcaught.png");
loadspriteimage(P_FISH,F_DEAD, "sprites/fishdead.png");
/* next 3 are auto generated */
imageset[P_FISH].numimages = 8;
loadspriteimage(P_BLACKCLOUD,F_WALK1, "sprites/blackcloud.png");
imageset[P_BLACKCLOUD].numimages = 1;
loadspriteimage(P_PINKCLOUD,F_WALK1, "sprites/pinkcloud.png");
imageset[P_PINKCLOUD].numimages = 1;
loadspriteimage(P_TICK,F_WALK1, "sprites/tick.png");
loadspriteimage(P_TICK,F_JUMP, "sprites/tickjump.png");
loadspriteimage(P_TICK,F_FALL, "sprites/tickjump.png");
loadspriteimage(P_TICK,F_CAUGHT, "sprites/tickcaught.png");
loadspriteimage(P_TICK,F_DEAD, "sprites/tickdead.png");
imageset[P_TICK].numimages = 8;
loadspriteimage(P_PLANT,F_WALK1, "sprites/plant.png");
loadspriteimage(P_PLANT,F_JUMP, "sprites/plantjump.png");
loadspriteimage(P_PLANT,F_FALL, "sprites/plantjump.png");
loadspriteimage(P_PLANT,F_CAUGHT, "sprites/plant.png");
loadspriteimage(P_PLANT,F_DEAD, "sprites/plantdead.png");
imageset[P_PLANT].numimages = 8;
loadspriteimage(P_KINGRAT,F_WALK1, "sprites/kingrat.png");
loadspriteimage(P_KINGRAT,F_JUMP, "sprites/kingratjump.png");
loadspriteimage(P_KINGRAT,F_FALL, "sprites/kingratjump.png");
loadspriteimage(P_KINGRAT,F_CAUGHT, "sprites/kingratcaught.png");
loadspriteimage(P_KINGRAT,F_DEAD, "sprites/kingratdead.png");
/* next 3 are auto generated */
imageset[P_KINGRAT].numimages = 8;
loadspriteimage(P_KINGSNAIL,F_WALK1, "sprites/kingsnail.png");
loadspriteimage(P_KINGSNAIL,F_JUMP, "sprites/kingsnailjump.png");
loadspriteimage(P_KINGSNAIL,F_FALL, "sprites/kingsnailjump.png");
loadspriteimage(P_KINGSNAIL,F_CAUGHT, "sprites/kingsnail_broken.png");
loadspriteimage(P_KINGSNAIL,F_DEAD, "sprites/kingsnaildead.png");
/* next 3 are auto genesnailed */
imageset[P_KINGSNAIL].numimages = 8;
loadspriteimage(P_KINGFLY,F_WALK1, "sprites/kingfly.png");
loadspriteimage(P_KINGFLY,F_JUMP, "sprites/kingflyjump.png");
loadspriteimage(P_KINGFLY,F_FALL, "sprites/kingflyjump.png");
loadspriteimage(P_KINGFLY,F_CAUGHT, "sprites/kingfly.png");
loadspriteimage(P_KINGFLY,F_DEAD, "sprites/kingflydead.png");
/* next 3 are auto geneflyed */
imageset[P_KINGFLY].numimages = 8;
loadspriteimage(P_KSSHELL,F_WALK1, "sprites/kingsnail_shell.png");
imageset[P_KSSHELL].numimages = 1;
// manually do flipped one
imageset[P_KSSHELL].img[MAXFRAMES] = rotozoomSurfaceXY(imageset[P_KSSHELL].img[0], 0, -1,1,0);
loadspriteimage(P_SNAIL,F_WALK1, "sprites/snail.png");
loadspriteimage(P_SNAIL,F_JUMP, "sprites/snailwalk2.png");
loadspriteimage(P_SNAIL,F_FALL, "sprites/snailwalk2.png");
loadspriteimage(P_SNAIL,F_CAUGHT, "sprites/snailcaught.png");
loadspriteimage(P_SNAIL,F_DEAD, "sprites/snaildead.png");
/* next 3 are auto generated */
imageset[P_SNAIL].numimages = 8;
loadspriteimage(P_SLUG,F_WALK1, "sprites/slug.png");
loadspriteimage(P_SLUG,F_JUMP, "sprites/slugwalk.png");
loadspriteimage(P_SLUG,F_FALL, "sprites/slugjump.png");
loadspriteimage(P_SLUG,F_CAUGHT, "sprites/slugcaught.png");
loadspriteimage(P_SLUG,F_DEAD, "sprites/slugdead.png");
/* next 3 are auto generated */
imageset[P_SLUG].numimages = 8;
/* fruits / powerups */
loadspriteimage(P_CHEESE,F_WALK1, "sprites/cheese.png");
imageset[P_CHEESE].numimages = 1;
loadspriteimage(P_ICECREAM,F_WALK1, "sprites/icecream.png");
imageset[P_ICECREAM].numimages = 1;
loadspriteimage(P_CHIPS,F_WALK1, "sprites/chips.png");
imageset[P_CHIPS].numimages = 1;
loadspriteimage(P_BURGER,F_WALK1, "sprites/burger.png");
imageset[P_BURGER].numimages = 1;
loadspriteimage(P_SPEED,F_WALK1, "sprites/speed.png");
imageset[P_SPEED].numimages = 1;
loadspriteimage(P_PIZZA,F_WALK1, "sprites/pizza.png");
imageset[P_PIZZA].numimages = 1;
loadspriteimage(P_SUNDAE,F_WALK1, "sprites/sundae.png");
imageset[P_SUNDAE].numimages = 1;
loadspriteimage(P_CAKE,F_WALK1, "sprites/cake.png");
imageset[P_CAKE].numimages = 1;
loadspriteimage(P_CHOCOLATE,F_WALK1, "sprites/chocolate.png");
imageset[P_CHOCOLATE].numimages = 1;
// we never use it, but load an image for P_RANDOM
// just in case... otehrwise we'll get crashes due to
// NULL images.
loadspriteimage(P_RANDOM,F_WALK1, "sprites/random.png");
imageset[P_RANDOM].numimages = 1;
loadspriteimage(P_NUMNETS,F_WALK1, "sprites/numnets.png");
imageset[P_NUMNETS].numimages = 1;
loadspriteimage(P_BIGNET,F_WALK1, "sprites/bignet.png");
imageset[P_BIGNET].numimages = 1;
loadspriteimage(P_GEMBOOST,F_WALK1, "sprites/gemboost.png");
imageset[P_GEMBOOST].numimages = 1;
loadspriteimage(P_MASK,0, "sprites/mask.png");
loadspriteimage(P_MASK,1, "sprites/maskleft.png");
imageset[P_MASK].numimages = 2;
loadspriteimage(P_MASKPOWERUP,F_WALK1, "sprites/maskpowerup.png");
imageset[P_MASKPOWERUP].numimages = 1;
loadspriteimage(P_HELP,F_WALK1, "sprites/help.png");
imageset[P_HELP].numimages = 1;
loadspriteimage(P_HELMET,F_WALK1, "sprites/helmet.png");
imageset[P_HELMET].numimages = 1;
loadspriteimage(P_FLOWERYELLOW,F_WALK1, "sprites/flower-yellow.png");
imageset[P_FLOWERRED].numimages = 1;
loadspriteimage(P_FLOWERRED,F_WALK1, "sprites/flower-red.png");
imageset[P_FLOWERRED].numimages = 1;
loadspriteimage(P_FLOWERPURPLE,F_WALK1, "sprites/flower-purple.png");
imageset[P_FLOWERPURPLE].numimages = 1;
loadspriteimage(P_GEMYELLOW,F_WALK1, "sprites/gem-yellow.png");
imageset[P_GEMYELLOW].numimages = 1;
loadspriteimage(P_GEMRED,F_WALK1, "sprites/gem-red.png");
imageset[P_GEMRED].numimages = 1;
loadspriteimage(P_GEMPURPLE,F_WALK1, "sprites/gem-purple.png");
imageset[P_GEMPURPLE].numimages = 1;
loadspriteimage(P_POWERUPPOS,F_WALK1, "sprites/poweruppos.png");
imageset[P_POWERUPPOS].numimages = 1;
loadspriteimage(P_BOXING,F_WALK1, "sprites/boxing.png");
imageset[P_BOXING].numimages = 1;
loadspriteimage(P_GLOVE,F_WALK1, "sprites/glove.png");
imageset[P_GLOVE].numimages = 1;
// manually do flipped images
imageset[P_GLOVE].img[MAXFRAMES] = rotozoomSurfaceXY(imageset[P_GLOVE].img[0], 0, -1,1,0);
loadspriteimage(P_DIAMOND,F_WALK1, "sprites/diamond.png");
imageset[P_DIAMOND].numimages = 1;
loadspriteimage(P_FTODIAMOND,F_WALK1, "sprites/flowertodiamond.png");
imageset[P_FTODIAMOND].numimages = 1;
loadspriteimage(P_FTOGEM,F_WALK1, "sprites/flowertogem.png");
imageset[P_FTOGEM].numimages = 1;
loadspriteimage(P_BOMB,F_WALK1, "sprites/bomb.png");
imageset[P_BOMB].numimages = 1;
loadspriteimage(P_STARPOWERUP,F_WALK1, "sprites/star.png");
imageset[P_STARPOWERUP].numimages = 1;
// Don't load image for P_MOVINGCARD or P_FIVECARDS
for (i = 0; i < STARFRAMES; i++) {
char name[SMALLBUFLEN];
sprintf(name, "sprites/star%d.png",i);
loadspriteimage(P_STAR,i, name);
}
imageset[P_STAR].numimages = STARFRAMES;
loadspriteimage(P_UFO,F_WALK1, "sprites/ufo.png");
imageset[P_UFO].numimages = 1;
loadspriteimage(P_METEOR,F_WALK1, "sprites/meteor.png");
imageset[P_METEOR].numimages = 1;
loadspriteimage(P_LIFE,F_WALK1, "sprites/extralife.png");
imageset[P_LIFE].numimages = 1;
loadspriteimage(P_PHONE,F_WALK1, "sprites/phone.png");
imageset[P_PHONE].numimages = 1;
loadspriteimage(P_HONEY,F_WALK1, "sprites/honey.png");
imageset[P_HONEY].numimages = 1;
loadspriteimage(P_SHIELD,F_WALK1, "sprites/shield.png");
imageset[P_SHIELD].numimages = 1;
loadspriteimage(P_MACEPOWERUP,F_WALK1, "sprites/macepowerup.png");
imageset[P_MACEPOWERUP].numimages = 1;
loadspriteimage(P_MACE,F_WALK1, "sprites/mace.png");
imageset[P_MACE].numimages = 1;
loadspriteimage(P_TROPHY,F_WALK1, "sprites/trophy.png");
imageset[P_TROPHY].numimages = 1;
loadspriteimage(P_RINGSILVER,F_WALK1, "sprites/ring-silver.png");
imageset[P_RINGSILVER].numimages = 1;
loadspriteimage(P_RINGGOLD,F_WALK1, "sprites/ring-gold.png");
imageset[P_RINGGOLD].numimages = 1;
loadspriteimage(P_BELL,F_WALK1, "sprites/bell.png");
imageset[P_BELL].numimages = 1;
loadspriteimage(P_CLOCK,F_WALK1, "sprites/clock.png");
imageset[P_CLOCK].numimages = 1;
loadspriteimage(P_SNOWMAN,F_WALK1, "sprites/snowman.png");
imageset[P_SNOWMAN].numimages = 1;
loadspriteimage(P_TAP,F_WALK1, "sprites/tap.png");
imageset[P_TAP].numimages = 1;
loadspriteimage(P_SPRAY,F_WALK1, "sprites/spray.png");
imageset[P_SPRAY].numimages = 1;
loadspriteimage(P_CANNONPOWERUP,F_WALK1, "sprites/cannonpowerup.png");
imageset[P_CANNONPOWERUP].numimages = 1;
loadspriteimage(P_CANNON,F_WALK1, "sprites/cannon.png");
imageset[P_CANNON].numimages = 1;
loadspriteimage(P_CLOVER,F_WALK1, "sprites/clover.png");
imageset[P_CLOVER].numimages = 1;
loadspriteimage(P_ACCORDION,F_WALK1, "sprites/accordion.png");
imageset[P_ACCORDION].numimages = 1;
loadspriteimage(P_WINGBOOTS,F_WALK1, "sprites/wingboots.png");
imageset[P_WINGBOOTS].numimages = 1;
loadspriteimage(P_PILL,F_WALK1, "sprites/pill.png");
imageset[P_PILL].numimages = 1;
loadspriteimage(P_RAYGUN,F_WALK1, "sprites/raygun.png");
imageset[P_RAYGUN].numimages = 1;
loadspriteimage(P_GUN,F_WALK1, "sprites/gunner.png");
imageset[P_GUN].numimages = 1;
loadspriteimage(P_GNOME,F_WALK1, "sprites/gnome.png");
imageset[P_GNOME].numimages = 1;
loadspriteimage(P_WAND,F_WALK1, "sprites/wand.png");
imageset[P_WAND].numimages = 1;
loadspriteimage(P_CANDLE,F_WALK1, "sprites/candle.png");
imageset[P_CANDLE].numimages = 1;
loadspriteimage(P_WHISTLE,F_WALK1, "sprites/whistle.png");
imageset[P_WHISTLE].numimages = 1;
loadspriteimage(P_ANCHOR,F_WALK1, "sprites/anchor.png");
imageset[P_ANCHOR].numimages = 1;
loadspriteimage(P_SMALLANCHOR,F_WALK1, "sprites/smallanchor.png");
imageset[P_SMALLANCHOR].numimages = 1;
loadspriteimage(P_MAGNET,F_WALK1, "sprites/magnet.png");
imageset[P_MAGNET].numimages = 1;
loadspriteimage(P_BADMAGNET,F_WALK1, "sprites/badmagnet.png");
imageset[P_BADMAGNET].numimages = 1;
loadspriteimage(P_JETPACK,F_WALK1, "sprites/jetpack.png");
imageset[P_JETPACK].numimages = 1;
loadspriteimage(P_UMBRELLA,F_WALK1, "sprites/umbrella.png");
imageset[P_UMBRELLA].numimages = 1;
loadspriteimage(P_BIGUMBRELLA,F_WALK1, "sprites/bigumbrella.png");
imageset[P_BIGUMBRELLA].numimages = 1;
loadspriteimage(P_SUPERUMBRELLA,F_WALK1, "sprites/superumbrella.png");
imageset[P_SUPERUMBRELLA].numimages = 1;
loadspriteimage(P_CAMERA,F_WALK1, "sprites/camera.png");
imageset[P_CAMERA].numimages = 1;
loadspriteimage(P_ZAPPOWERUP,F_WALK1, "sprites/zapper.png");
imageset[P_ZAPPOWERUP].numimages = 1;
// moving platforms
loadspriteimage(P_PLATFORM,F_WALK1, "sprites/platform.png");
imageset[P_PLATFORM].numimages = 1;
loadspriteimage(P_ZAPPER,0, "sprites/zap1.png");
loadspriteimage(P_ZAPPER,1, "sprites/zap2.png");
loadspriteimage(P_ZAPPER,2, "sprites/zap3.png");
loadspriteimage(P_ZAPPER,3, "sprites/zap2.png");
loadspriteimage(P_ZAPPER,4, "sprites/zap1.png");
imageset[P_ZAPPER].numimages = 5;
// wings
loadspriteimage(P_WINGLEFT,0, "sprites/wingleft0.png"); // standing
loadspriteimage(P_WINGLEFT,1, "sprites/wingleft1.png"); // jumping
loadspriteimage(P_WINGLEFT,2, "sprites/wingleft2.png"); // jumping
loadspriteimage(P_WINGLEFT,3, "sprites/wingleft3.png"); // swimming
imageset[P_WINGLEFT].numimages = 4;
loadspriteimage(P_WINGRIGHT,0, "sprites/wingright0.png"); // standing
loadspriteimage(P_WINGRIGHT,1, "sprites/wingright1.png"); // jumping
loadspriteimage(P_WINGRIGHT,2, "sprites/wingright2.png"); // jumping
imageset[P_WINGRIGHT].numimages = 3;
// manually do flipped images
for (i = 0; i < 3; i++) {
imageset[P_WINGLEFT].img[MAXFRAMES+i] = rotozoomSurfaceXY(imageset[P_WINGLEFT].img[i], 0, -1,1,0);
imageset[P_WINGRIGHT].img[MAXFRAMES+i] = rotozoomSurfaceXY(imageset[P_WINGRIGHT].img[i], 0, -1,1,0);
}
// and one more for WINGLEFT...
imageset[P_WINGLEFT].img[MAXFRAMES+3] = rotozoomSurfaceXY(imageset[P_WINGLEFT].img[3], 0, -1,1,0);
loadspriteimage(P_SKULL,F_WALK1, "sprites/skull.png");
imageset[P_SKULL].numimages = 1;
loadspriteimage(P_BIGSPEED,F_WALK1, "sprites/bigspeed.png");
imageset[P_BIGSPEED].numimages = 1;
loadspriteimage(P_BIGSCUBA,F_WALK1, "sprites/bigscuba.png");
imageset[P_BIGSCUBA].numimages = 1;
// puffs and mace smashes
for (i = 0; i < PUFFFRAMES; i++) {
char name[SMALLBUFLEN];
sprintf(name, "sprites/puff%d.png",i);
loadspriteimage(P_PUFF,i, name);
}
imageset[P_PUFF].numimages = PUFFFRAMES;
for (i = 0; i < EXPFRAMES; i++) {
char name[SMALLBUFLEN];
sprintf(name, "sprites/exp%d.png",i);
loadspriteimage(P_SMASH,i, name);
}
imageset[P_SMASH].numimages = EXPFRAMES;
// playing card bonuses
//loadspriteimage(P_CARDHK,F_WALK1, "sprites/cardhk.png");
// load card font
sprintf(tempfile, "%s/cardfont.ttf", datadir);
cardfont = TTF_OpenFont(tempfile, CARDFONTSIZE);
if (!cardfont) {
printf("Error opening font '%s': %s\n", tempfile, TTF_GetError());
exit(1);
}
for (i = 1; i <= 13; i++) {
SDL_Surface *letter;
SDL_Rect area;
char str[2];
// HEARTS
loadspriteimage(P_FIRSTHEART+i-1, F_WALK1, "sprites/cardh.png");
sprintf(str, "%s",getcardletter(i));
letter = TTF_RenderText_Blended(cardfont, str, red );
area.x = CARDFONTX; area.y = CARDFONTY; area.w = 0; area.h = 0;
if (i == 10) area.x -= 3;
SDL_BlitSurface(letter, NULL, imageset[P_FIRSTHEART + i-1].img[F_WALK1], &area);
imageset[P_FIRSTHEART + i-1].numimages = 1;
SDL_FreeSurface(letter);
// DIAMONDS
loadspriteimage(P_FIRSTDIAMOND+i-1, F_WALK1, "sprites/cardd.png");
sprintf(str, "%s",getcardletter(i));
letter = TTF_RenderText_Blended(cardfont, str, red );
area.x = CARDFONTX; area.y = CARDFONTY; area.w = 0; area.h = 0;
if (i == 10) area.x -= 3;
SDL_BlitSurface(letter, NULL, imageset[P_FIRSTDIAMOND + i-1].img[F_WALK1], &area);
imageset[P_FIRSTDIAMOND + i-1].numimages = 1;
SDL_FreeSurface(letter);
// SPADES
loadspriteimage(P_FIRSTSPADE+i-1, F_WALK1, "sprites/cards.png");
sprintf(str, "%s",getcardletter(i));
letter = TTF_RenderText_Blended(cardfont, str, black );
area.x = CARDFONTX; area.y = CARDFONTY; area.w = 0; area.h = 0;
if (i == 10) area.x -= 3;
SDL_BlitSurface(letter, NULL, imageset[P_FIRSTSPADE + i-1].img[F_WALK1], &area);
imageset[P_FIRSTSPADE + i-1].numimages = 1;
SDL_FreeSurface(letter);
// CLUBS
loadspriteimage(P_FIRSTCLUB+i-1, F_WALK1, "sprites/cardc.png");
sprintf(str, "%s",getcardletter(i));
letter = TTF_RenderText_Blended(cardfont, str, black );
area.x = CARDFONTX; area.y = CARDFONTY; area.w = 0; area.h = 0;
if (i == 10) area.x -= 3;
SDL_BlitSurface(letter, NULL, imageset[P_FIRSTCLUB + i-1].img[F_WALK1], &area);
imageset[P_FIRSTCLUB + i-1].numimages = 1;
SDL_FreeSurface(letter);
}
// sparkles
for (i = 0; i < SPARKLEFRAMES; i++) {
char name[SMALLBUFLEN];
sprintf(name, "sprites/sparkle%d.png",i);
loadspriteimage(P_SPARKLE,i, name);
}
imageset[P_SPARKLE].numimages = SPARKLEFRAMES;
loadspriteimage(P_BUBBLE,F_WALK1, "sprites/bubble.png");
imageset[P_BUBBLE].numimages = 1;
/* ray gun bullet */
loadspriteimage(P_RAYGUNBULLET,F_WALK1, "sprites/raygunbullet.png");
imageset[P_RAYGUNBULLET].numimages = 1;
/* bullets */
loadspriteimage(P_SPIT,0, "sprites/spit.png");
loadspriteimage(P_SPIT,1, "sprites/spit2.png");
imageset[P_SPIT].numimages = 2;
loadspriteimage(P_FIREBALL,0, "sprites/fire1.png");
loadspriteimage(P_FIREBALL,1, "sprites/fire2.png");
imageset[P_FIREBALL].numimages = 2;
// manual angry image for black cloud
origi = imageset[P_BLACKCLOUD].img[0];
reds = SDL_CreateRGBSurface(SDL_SWSURFACE,
origi->w,
origi->h,
origi->format->BitsPerPixel, origi->format->Rmask,
origi->format->Gmask,origi->format->Bmask, 0);
SDL_FillRect(reds, NULL, SDL_MapRGB(reds->format, 255, 0, 0));
SDL_SetAlpha(reds, SDL_SRCALPHA,100);
// take a copy of the original image
imageset[P_BLACKCLOUD].img[MAXFRAMES*2] = rotozoomSurfaceXY(origi, 0, 1,1,0);
// paste the transparent one on top of it
SDL_BlitSurface(reds, NULL, imageset[P_BLACKCLOUD].img[MAXFRAMES*2], NULL);
SDL_FreeSurface(reds);
// Convert the reddened image to the screen format
temps = SDL_DisplayFormat(imageset[P_BLACKCLOUD].img[MAXFRAMES*2]);
SDL_FreeSurface(imageset[P_BLACKCLOUD].img[MAXFRAMES*2]);
imageset[P_BLACKCLOUD].img[MAXFRAMES*2] = temps;
// Make the background red bits completely transparent
SDL_SetColorKey(imageset[P_BLACKCLOUD].img[MAXFRAMES*2],
SDL_SRCCOLORKEY, SDL_MapRGB(imageset[P_BLACKCLOUD].img[MAXFRAMES*2]->format, 99, 0, 0));
/* generate rotated/flipped images */
for (p = 0; p < MAXPTYPES; p++) {
int fr;
int angle = 90;
/* rotated death images */
if (!isfruit(p) && !isbullet(p) && !iseffect(p) && p != P_BLACKCLOUD) {
for (fr = F_DEAD2; fr <= F_DEAD4; fr++) {
if (!imageset[p].img[fr]) {
tempimg = rotozoomSurface(imageset[p].img[F_DEAD],angle,1,0);
if (tempimg == NULL) {
printf("error rotozooming sprite %d, deadimage %d\n",p,fr);
exit(1);
}
SDL_SetColorKey(tempimg, SDL_RLEACCEL, 0);
imageset[p].img[fr] = SDL_DisplayFormat(tempimg);
SDL_FreeSurface(tempimg);
}
angle += 90;
}
}
for (i = 0; i < imageset[p].numimages; i++) {
if (!isfruit(p) && !iseffect(p) && p != P_BLACKCLOUD) {
SDL_SetColorKey(imageset[p].img[i],
SDL_SRCCOLORKEY, SDL_MapRGB(screen->format, 0, 0, 0));
origi = imageset[p].img[i];
/* flipped image */
imageset[p].img[MAXFRAMES+i] =
rotozoomSurfaceXY(imageset[p].img[i], 0, -1,1,0);
SDL_SetColorKey(imageset[p].img[MAXFRAMES+i],
SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(screen->format, 0, 0, 0));
/* angry image */
// create semi-transparent red square (white for bosses)
if (isboss(p)) {
reds = SDL_CreateRGBSurface(SDL_SWSURFACE,
origi->w,
origi->h,
origi->format->BitsPerPixel, origi->format->Rmask,
origi->format->Gmask,origi->format->Bmask, 0);
SDL_FillRect(reds, NULL, SDL_MapRGB(reds->format, 255, 255, 255));
SDL_SetAlpha(reds, SDL_SRCALPHA,100);
} else {
reds = SDL_CreateRGBSurface(SDL_SWSURFACE,
origi->w,
origi->h,
origi->format->BitsPerPixel, origi->format->Rmask,
origi->format->Gmask,origi->format->Bmask, 0);
SDL_FillRect(reds, NULL, SDL_MapRGB(reds->format, 255, 0, 0));
SDL_SetAlpha(reds, SDL_SRCALPHA,100);
}
// take a copy of the original image
imageset[p].img[MAXFRAMES*2+i] = rotozoomSurfaceXY(origi, 0, 1,1,0);
// paste the transparent one on top of it
SDL_BlitSurface(reds, NULL, imageset[p].img[MAXFRAMES*2+i], NULL);
SDL_FreeSurface(reds);
// Convert the reddened image to the screen format
temps = SDL_DisplayFormat(imageset[p].img[MAXFRAMES*2+i]);
SDL_FreeSurface(imageset[p].img[MAXFRAMES*2+i]);
imageset[p].img[MAXFRAMES*2+i] = temps;
// Make the background red bits completely transparent
if (isboss(p)) {
SDL_SetColorKey(imageset[p].img[MAXFRAMES*2+i],
SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(imageset[p].img[MAXFRAMES*2+i]->format, 99, 97, 99));
} else {
///SDL_Color tempcol;
///getpixelrgb(imageset[p].img[MAXFRAMES*2+i], 0, 0, &tempcol);
//printf("for spriteid %d, rgb is %d,%d,%d\n",p,tempcol.r,tempcol.g,tempcol.b);
SDL_SetColorKey(imageset[p].img[MAXFRAMES*2+i],
SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(imageset[p].img[MAXFRAMES*2+i]->format, 99, 0, 0));
}
/* flipped angry image */
imageset[p].img[MAXFRAMES*3+i] = rotozoomSurfaceXY(imageset[p].img[MAXFRAMES*2+i], 0, -1,1,0);
SDL_SetColorKey(imageset[p].img[MAXFRAMES*3+i],SDL_RLEACCEL, 0);
/* flipped angry image */
/*
reds = SDL_CreateRGBSurface(SDL_SWSURFACE,
origi->w,
origi->h,
origi->format->BitsPerPixel, origi->format->Rmask,
origi->format->Gmask,origi->format->Bmask, 0);
SDL_FillRect(reds, NULL, SDL_MapRGB(reds->format, 255, 0, 0));
SDL_SetAlpha(reds, SDL_SRCALPHA,100);
imageset[p].img[MAXFRAMES*3+i] = rotozoomSurfaceXY(origi, 0, -1,1,0);
SDL_BlitSurface(reds, NULL, imageset[p].img[MAXFRAMES*3+i], NULL);
SDL_FreeSurface(reds);
temps = SDL_DisplayFormat(imageset[p].img[MAXFRAMES*3+i]);
SDL_FreeSurface(imageset[p].img[MAXFRAMES*3+i]);
imageset[p].img[MAXFRAMES*3+i] = temps;
SDL_SetColorKey(imageset[p].img[MAXFRAMES*3+i],
SDL_SRCCOLORKEY, SDL_MapRGB(imageset[p].img[MAXFRAMES*3+i]->format, 101, 0, 0));
*/
}
}
}
return B_FALSE;
}
void drawsprite(sprite_t *s) {
SDL_Rect area;
int frame = 0;
#ifndef __EDITOR
if (isplayer(s) && s->lives < 0) {
// permenantly dead - don't draw
return;
}
#endif
// don't show caught mosnters in gunner mode
if (!isplayer(s) && (s->caughtby) ) {
if ((player) && (player->powerup == PW_GUNNER)) {
return;
}
if ((player2) && (player2->powerup == PW_GUNNER)) {
return;
}
}
if (isplayer(s) && (levelcomplete == LV_NEXTLEV)) {
frame = F_SHOOT;
if (curlevel->exitdir == D_RIGHT) {
s->dir = 1;
} else if (curlevel->exitdir == D_LEFT) {
s->dir = -1;
}
} else {
/* select frame */
if (isfruit(s->id)) {
frame = F_WALK1;
} else if (isbullet(s->id)) {
if ((timer/6) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_JUMP;
}
} else if (iseffect(s->id)) {
if ((s->id == P_PUFF) || (s->id == P_SMASH) || (s->id == P_SPARKLE)) {
if (s->timer1 >= imageset[s->id].numimages) {
frame = imageset[s->id].numimages - 1;
} else if (s->timer1 < 0) {
// don't draw
return;
} else {
frame = s->timer1;
}
} else if (s->id == P_GLOVE) {
frame = F_WALK1;
} else if (s->id == P_KSSHELL) {
frame = F_WALK1;
} else if (s->id == P_MACE) {
frame = F_WALK1;
} else if (s->id == P_CANNON) {
frame = F_WALK1;
} else if (s->id == P_ZAPPER) {
if (s->timer1 >= imageset[s->id].numimages) {
// just in case
frame = 0;
} else {
frame = s->timer1;
}
} else if (s->id == P_BUBBLE) {
frame = F_WALK1;
} else if (s->id == P_METEOR) {
frame = F_WALK1;
} else if (s->id == P_STAR) {
frame = s->timer1;
} else if (s->id == P_MASK) {
// only draw this if the player is swimming
if (s->owner->swimming) {
if (s->owner->dir > 0) {
frame = 0;
} else {
frame = 1;
}
} else {
return;
}
} else if (s->id == P_MOVINGCARD) {
// not really needed but included here for neatness
frame = F_WALK1;
} else if (s->id == P_FIVECARDS) {
// not really needed but included here for neatness
frame = F_WALK1;
}
} else if (s->dead) {
if (isplayer(s)) {
frame = F_DEAD;
} else if (s == boss) {
frame = F_DEAD;
} else if (s->id == P_SNAIL) {
frame = F_DEAD;
} else {
frame = F_DEAD + ((timer/2) % 4);
}
} else if (s->id == P_KINGSNAIL) {
// frame based on state
switch (s->timer1) {
case KSS_WALK1:
case KSS_WALK2:
default:
if ((timer/12) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_JUMP;
}
break;
case KSS_PAUSE1:
case KSS_PAUSE2:
case KSS_PAUSE3:
frame = F_WALK1;
break;
case KSS_SHOOT:
case KSS_REGEN:
if (s->timer3 < 100) {
frame = F_CAUGHT; // ie. broken shell
} else {
frame = F_WALK1;
}
break;
case KSS_JUMPING:
frame = F_JUMP;
break;
}
} else if (s->caughtby) {
frame = F_CAUGHT;
} else if (s->climbing) {
//frame = F_CLIMB1 + ((timer/12) % 2);
if (s->moved) {
if ((timer/12) % 2 == 0) {
frame = F_CLIMB1;
} else {
frame = F_CLIMB2;
}
} else {
frame = F_CLIMB1;
}
} else if ((s->swimming) && isplayer(s) && !s->slamming) {
if ((timer/12) % 2 == 0) {
frame = F_SWIM1;
} else {
frame = F_SWIM2;
}
} else if (s->netting) {
frame = F_SHOOT;
} else if (s->iced) {
frame = F_WALK1;
} else if (s->jumping) {
if ((s->id == P_SNAIL) && (s->recoiling)) {
// when a snail is "jumping" it is actually recoiling
// and should look like a shell
frame = F_DEAD;
} else if (s->id == P_SLUG) {
frame = F_FALL;
} else if (s->powerup == PW_PILL) {
// toggle between walking frames FAST
if ((timer/3) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_JUMP;
}
} else {
frame = F_JUMP;
}
} else if (s->falling) {
if ((s->id == P_SNAIL) && (s->recoiling)) {
frame = F_DEAD;
} else if (s->id == P_FLY) {
// same as flying
// toggle between flying frames
if ((timer/3) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_FALL;
}
} else if (s->powerup == PW_PILL) {
// toggle between walking frames FAST
if ((timer/3) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_JUMP;
}
} else {
frame = F_FALL;
}
} else if (s->slamming) {
double slamdegs = s->slamangle / (M_PI/180);
if (slamdegs < 36) {
frame = F_SLAM1;
} else if (slamdegs < 72) {
frame = F_SLAM2;
} else if (slamdegs < 108) {
frame = F_SLAM3;
} else if (slamdegs < 144) {
frame = F_SLAM4;
} else {
frame = F_SLAM5;
}
} else if (!s->teleporting) {
if ((s->id == P_SPIDER) && (s->ys != -99)) {
frame = F_FALL;
} else {
// DEFAULT FOR EVERYTHING
// walking / sliding
if (s->moved == MV_WALK) {
if (s->powerup == PW_PILL) {
// toggle between walking frames FAST
if ((timer/3) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_JUMP;
}
} else {
// toggle between walking frames
if ((timer/12) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_JUMP;
}
}
} else if (s->moved == MV_FLY) {
int animspeed;
// fly animates faster
if ((s->id == P_FLY) && (s->flies)) {
animspeed = 3;
} else if (s->id == P_KINGFLY){
animspeed = 3;
} else {
animspeed = 12;
}
// toggle between flying frames
if ((timer/animspeed) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_FALL;
}
} else if (s->moved == MV_ICE) { // sliding
frame = F_FALL;
} else { // standing still
if (s->powerup == PW_PILL) {
// toggle between walking frames FAST
if ((timer/3) % 2 == 0) {
frame = F_WALK1;
} else {
frame = F_JUMP;
}
} else {
frame = F_WALK1;
}
}
}
}
}
/* x-flip if required */
if (!isfruit(s->id) && !iseffect(s->id) && (s->id != P_BLACKCLOUD)) {
if (s->dir == -1) {
frame += MAXFRAMES;
}
} else if ((s->id == P_GLOVE) || (s->id == P_KSSHELL)) {
if (s->dir == -1) {
frame += MAXFRAMES;
}
} else if ((s->id == P_WINGLEFT) || (s->id == P_WINGRIGHT)) {
if (s->owner->dir == -1) {
frame += MAXFRAMES;
}
}
/* make red if required */
if (s->angry && s->id != P_BLACKCLOUD) {
if (!isplayer(s) && !isfruit(s->id)) {
frame += (MAXFRAMES*2);
}
}
if (s->id == P_MOVINGCARD) {
// image comes from timer1
s->img = imageset[s->timer1].img[F_WALK1];
} else if (s->id == P_FIVECARDS) {
// do nothing - img already there!
} else if (s->id == P_RANDOM) {
// image based on timer1
s->img = imageset[s->timer1].img[F_WALK1];
} else if ((s->id != P_BLACKCLOUD) && (s->id != P_PINKCLOUD) && (!s->teleporting)) {
// ALL OTHERS:
// select image based on sprite id
s->img = imageset[s->id].img[frame];
}
// zapper lightning bolt
if ((s->id == P_ZAPPER) && (s->timer4 > 0)) {
if (s->zapping) {
SDL_Color col;
double zapx,zapy;
// initialise
col.r = 0;
col.g = 0;
col.b = 0;
col.unused = 0;
switch (timer % 4) {
case 0: col.r = 255; col.g = 255; col.b = 255; break;
case 1: col.r = 0; col.g = 0; col.b = 0; break;
case 2: col.r = 0; col.g = 255; col.b = 255; break;
default:
case 3: col.r = 0; col.g = 0; col.b = 0; break;
}
// draw lines to zap position
zapx = s->zapping->x;
zapy = s->zapping->y;
drawline(screen, s->x, s->y - (s->img->h/2),zapx, zapy, col);
drawline(screen, s->x+1, s->y - (s->img->h/2),zapx, zapy, col);
drawline(screen, s->x-1, s->y - (s->img->h/2),zapx, zapy, col);
drawline(screen, s->x, s->y+1 - (s->img->h/2),zapx, zapy, col);
drawline(screen, s->x, s->y-1 - (s->img->h/2),zapx, zapy, col);
} else { // the thing we were zapping died!
s->timer4 = 0;
}
}
/* spider's climbing web */
if ((s->id == P_SPIDER) && ((s->ys != -99) || s->falling) && !s->dead && !s->caughtby && !s->iced) {
tiletype_t *tt;
int x = s->x;
int y = s->y - s->img->h/2;
int tx=0,ty = 0;
int done = B_FALSE;
for (y = s->y ; !done ; y-= TILEH) {
tt = gettileat(x,y,&tx,&ty);
if ((tt == NULL) || (tt->solid)) {
done = B_TRUE;
}
if (y < 0) { // nothing above us!
// die!
s->dead = D_FINAL;
puffin(-1, s->x, s->y, "spiderdeath",0);
return;
}
}
drawline(screen,s->x,s->y - (s->img->h/2),s->x,ty*TILEH+TILEH-1,white);
}
// override
if ((s->id == P_SNAIL) && (s->recoiling)) {
frame = F_DEAD;
}
s->frame = frame;
// TODO: return if s->img is NULL - but try to bugfix everything
// before resorting to this.
area.x = s->x - (s->img->w/2);
area.y = s->y - (s->img->h);
area.w = 0;
area.h = 0;
// don't blink invuln things while showing help text
if ((s->invuln) && (levelcomplete != LV_HELPFREEZE)) {
if (timer % 2 == 0) {
//SDL_BlitSurface(s->img, NULL, screen, &area);
if (isplayer(s)) {
drawplayer(s, &area);
} else {
doblit(s->img, screen, &area);
}
}
} else if ((s->doomcount > 0) && (s->doomcount <= 150) && (levelcomplete != LV_HELPFREEZE)) {
if ((timer/2) % 2 == 0) {
if (isplayer(s)) {
drawplayer(s, &area);
} else {
doblit(s->img, screen, &area);
}
}
} else if (s == boss && s->dead) {
if ((timer / 10) % 2 == 0) {
//SDL_BlitSurface(s->img, NULL, screen, &area);
doblit(s->img, screen, &area);
}
} else {
if (isplayer(s)) {
drawplayer(s, &area);
} else {
doblit(s->img, screen, &area);
// king snail regenerating shell...
if ((s->id == P_KINGSNAIL) && (s->timer1 == KSS_REGEN)) {
SDL_Surface *shellimg, *srcimg;
SDL_Rect newarea;
double pct;
// shell image -left or right?
if (s->dir == 1) {
srcimg = imageset[P_KSSHELL].img[0];
} else {
srcimg = imageset[P_KSSHELL].img[MAXFRAMES];
}
// generate new shell at correct size ...
pct = ((double)s->timer3 / 100);
if (pct > 1) pct = 1;
shellimg = rotozoomSurfaceXY(srcimg,0, pct, pct ,0);
// blit it
if (s->dir == 1) {
newarea.x = s->x - (shellimg->w/2) - 21;
} else {
newarea.x = s->x - (shellimg->w/2) + 21;
}
newarea.y = s->y - (shellimg->h/2) - 28;
newarea.w = 0;
newarea.h = 0;
SDL_BlitSurface(shellimg, NULL, screen, &newarea);
// free it
SDL_FreeSurface(shellimg);
}
}
}
// ice cube
if (s->iced) {
if (!s->iceimg) {
double xmod,ymod;
xmod = (double)s->img->w / (double)icecube->w;
ymod = (double)s->img->h / (double)icecube->h;
// create image
s->iceimg = rotozoomSurfaceXY(icecube,0, xmod, ymod ,0);
}
// draw it
doblit(s->iceimg, screen, &area);
//SDL_BlitSurface(s->iceimg, NULL, screen, &area);
}
// anchor
if (globpowerup == PW_ANCHOR) {
if (ismonster(s->id) && !s->caughtby && !s->dead) {
SDL_Rect newarea;
newarea = area;
newarea.y += (s->img->h / 3);
SDL_BlitSurface(imageset[P_SMALLANCHOR].img[0], NULL, screen, &newarea);
}
}
/* caughtby lines */
if ((s->caughtby) && (s->caughtstate == 2)){
// only if we're on the screen
if ((s->y >= 0) && (s->y <= 480)) {
drawline(screen, s->x,s->y - s->img->h,
s->caughtby->x,s->caughtby->y-(s->caughtby->img->h/2), white);
drawline(screen, s->x,s->y - (s->img->h/2),
s->caughtby->x,s->caughtby->y-(s->caughtby->img->h/2), white);
drawline(screen, s->x,s->y,
s->caughtby->x,s->caughtby->y-(s->caughtby->img->h/2), white);
}
}
}
void killsprite(sprite_t *s) {
sprite_t *nextone, *lastone;
#ifndef __EDITOR
sprite_t *s2;
// remove boss pointer
if (boss == s) {
boss = NULL;
}
// remove mask pointer
/*
if (mask == s) {
mask = NULL;
}
*/
if (s->caughtby) {
s->caughtby->netcaught--;
s->caughtby = NULL;
s->caughtstate = B_FALSE;
}
s->zapping = NULL;
/* remove references to this sprite before removing it */
for (s2 = sprite ; s2 ; s2 = s2->next) {
if (s2->owner == s) {
s2->owner = NULL;
}
if (s2->bullet == s) {
s2->bullet = NULL;
}
if (s2->zapping == s) {
s2->zapping = NULL;
}
}
// free ice image
if (s->iceimg) {
SDL_FreeSurface(s->iceimg);
}
// free image for certain types
switch (s->id) {
case P_FIVECARDS:
case P_PINKCLOUD:
case P_BLACKCLOUD:
if (s->img) {
SDL_FreeSurface(s->img);
}
break;
}
#endif
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 flip(void) {
#ifdef OPENGL
SDL_UpdateRect(screen,0,0,screen->w,screen->h);
SDL_GL_SwapBuffers();
#else
SDL_Flip(screen);
#endif
}
// returns 0 if tile isn't animated, else the number of frames
int gettileframecount(int tid) {
tiletype_t *tt;
tt = gettile(tid);
return tt->numframes;
}
// returns gem type for a given flower
int flowertogem(int id) {
switch (id) {
case P_FLOWERRED:
return P_GEMRED;
case P_FLOWERYELLOW:
return P_GEMYELLOW;
case P_FLOWERPURPLE:
return P_GEMPURPLE;
}
return P_GEMRED;
}
int iscard(int id) {
if ((id >= P_FIRSTCARD) && (id <= P_FIRSTCARD+51)) {
return B_TRUE;
}
return B_FALSE;
}
int isflower(int id) {
switch (id) {
case P_FLOWERRED:
case P_FLOWERYELLOW:
case P_FLOWERPURPLE:
return B_TRUE;
}
return B_FALSE;
}
/* returns B_TRUE if the given powerup is one which
gives the player a special ability */
int isabilitypowerup(int id) {
switch (id) {
case P_BOXING:
case P_MACEPOWERUP:
case P_SHIELD:
case P_RINGSILVER:
case P_RINGGOLD:
case P_CLOVER:
case P_ACCORDION:
case P_ZAPPOWERUP:
case P_GUN:
case P_CANNONPOWERUP:
case P_MAGNET:
case P_JETPACK:
case P_PILL:
case P_RAYGUN:
return B_TRUE;
}
return B_FALSE;
}
int isbadpowerup(int id) {
switch (id) {
case P_SKULL:
case P_BADMAGNET:
return B_TRUE;
}
return B_FALSE;
}
/* returns B_TRUE if the given powerup is one which
will or could effectively win the level */
int iswinpowerup(int id) {
switch (id) {
case P_BOMB:
case P_PHONE:
case P_WAND:
return B_TRUE;
}
return B_FALSE;
}
int isfruit(int id) {
switch (id) {
/* fruits */
case P_CHEESE:
case P_ICECREAM:
case P_CHIPS:
case P_BURGER:
case P_PIZZA:
case P_SUNDAE:
case P_CAKE:
case P_CHOCOLATE:
case P_DIAMOND:
return FT_FRUIT;
/* super powerups */
case P_BIGSPEED:
case P_BIGSCUBA:
case P_SUPERUMBRELLA:
return FT_SUPER;
/* permenant powerups */
case P_SPEED:
case P_NUMNETS:
case P_BIGNET:
case P_HELP:
case P_GEMBOOST:
case P_BELL:
case P_TROPHY:
case P_HONEY:
case P_HELMET:
case P_MASKPOWERUP:
case P_WINGBOOTS:
case P_UMBRELLA:
return FT_PERM;
/* one-off level only powerups */
case P_BOXING:
case P_MACEPOWERUP:
case P_FTODIAMOND:
case P_FTOGEM:
case P_BOMB:
case P_STARPOWERUP:
case P_UFO:
case P_LIFE:
case P_PHONE:
case P_SHIELD:
case P_RINGSILVER:
case P_RINGGOLD:
case P_CLOCK:
case P_SNOWMAN:
case P_TAP:
case P_SPRAY:
case P_CANNONPOWERUP:
case P_CLOVER:
case P_ACCORDION:
case P_GUN:
case P_ZAPPOWERUP:
case P_SKULL:
case P_GNOME:
case P_WAND:
case P_ANCHOR:
case P_CANDLE:
case P_WHISTLE:
case P_RANDOM:
case P_MAGNET:
case P_BADMAGNET:
case P_JETPACK:
case P_CAMERA:
case P_PILL:
case P_RAYGUN:
return FT_TEMP;
/* flowers */
case P_FLOWERYELLOW:
case P_FLOWERRED:
case P_FLOWERPURPLE:
/* gems */
case P_GEMYELLOW:
case P_GEMRED:
case P_GEMPURPLE:
return FT_GEM;
/* misc */
case P_POWERUPPOS:
return FT_OTHER;
}
if (iscard(id)) return FT_CARD;
return B_FALSE;
}
int isbullet(int id) {
if (id == P_SPIT) return B_TRUE;
if (id == P_FIREBALL) return B_TRUE;
return B_FALSE;
}
int isplatform(int id) {
switch (id) {
case P_PLATFORM:
return B_TRUE;
}
return B_FALSE;
}
int iseffect(int id) {
switch (id) {
case P_PUFF:
case P_SPARKLE:
case P_SMASH:
case P_KSSHELL:
case P_POWERUPPOS:
case P_GLOVE:
case P_MACE:
case P_PINKCLOUD:
case P_CANNON:
case P_ZAPPER:
case P_BUBBLE:
case P_STAR:
case P_METEOR:
case P_MASK:
case P_MOVINGCARD:
case P_FIVECARDS:
case P_PLATFORM:
case P_RAYGUNBULLET:
// these last ones aren't REALLY effects since they never have a sprite allocated
case P_WINGLEFT:
case P_WINGRIGHT:
case P_BIGUMBRELLA:
case P_SMALLANCHOR:
return B_TRUE;
}
return B_FALSE;
}
int needscollisions(int id) {
if (id == P_SMASH) return B_TRUE;
if (id == P_STAR) return B_TRUE;
if (id == P_METEOR) return B_TRUE;
if (id == P_ZAPPER) return B_TRUE;
if (id == P_RAYGUNBULLET) return B_TRUE;
if (isplatform(id)) return B_TRUE;
return B_FALSE;
}
#ifdef OPENGL
inline void drawpixel16(SDL_Surface *screen, int x, int y, SDL_Color c)
{
Uint8 *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 = (Uint8 *)screen->pixels + y * screen->pitch + x * 4;
// *bufp = SDL_MapRGB(screen->format, c.r, c.g, c.b);
*(Uint32 *)bufp = SDL_MapRGB(screen->format, c.r, c.g, c.b);
}
#else
inline void drawpixel16(SDL_Surface *s, int x, int y, SDL_Color c)
{
Uint16 *bufp;
// check x/y
if (x >= s->w) return;
if (y >= s->h) return;
if (x < 0) return;
if (y < 0) return;
bufp = (Uint16 *)s->pixels + (y*s->pitch / 2) + x;
*bufp = SDL_MapRGB(s->format, c.r, c.g, c.b);
}
#endif
inline void drawpixel32(SDL_Surface *s, int x, int y, SDL_Color c)
{
Uint32 *bufp;
/* check x/y */
if (x >= s->w) return;
if (y >= s->h) return;
if (x < 0) return;
if (y < 0) return;
bufp = (Uint32 *)s->pixels + (y*s->pitch / 4) + x;
*bufp = SDL_MapRGB(s->format, c.r, c.g, c.b);
}
void drawline(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++) {
drawpixel(screen,x,y,c);
if (d < 0) {
d += dinc1;
x += xinc1;
y += yinc1;
} else {
d += dinc2;
x += xinc2;
y += yinc2;
}
}
}
// draw line with alternating colours
void drawdotline16(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c, SDL_Color c2) {
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++) {
if (i % 2 == 0) {
drawpixel(screen,x,y,c);
} else {
drawpixel(screen,x,y,c2);
}
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++) {
drawline(screen, x1+1, y, x2-1,y,*fc);
}
}
}
drawline(screen,x1,y1,x2,y1,*c);
drawline(screen,x1,y1,x1,y2,*c);
drawline(screen,x1,y2,x2,y2,*c);
drawline(screen,x2,y1,x2,y2,*c);
}
int getcolor(SDL_Surface *dest, int x, int y, SDL_Color *col) {
Uint32 pixel;
int bpp = dest->format->BytesPerPixel;
char *ppos;
unsigned char r,g,b,a;
ppos = (char *) dest->pixels;
/* offset y */
ppos += (dest->pitch * y);
/* offset x */
ppos += (bpp * x);
memcpy(&pixel, ppos, bpp);
if (dest->format->BitsPerPixel == 32) {
SDL_GetRGBA(pixel, dest->format, &r,&g,&b, &a);
col->r = r;
col->g = g;
col->b = b;
col->unused = a;
} else if (dest->format->BitsPerPixel == 16) {
SDL_GetRGB(pixel, dest->format, &r,&g,&b);
col->r = r;
col->g = g;
col->b = b;
} else if (dest->format->BitsPerPixel == 8) {
*col = dest->format->palette->colors[(Uint8)pixel];
}
return 0;
}
tiletype_t *gettile(int uniqid) {
tiletype_t *t;
for (t = tiletype; t ; t = t->next) {
if (t->uniqid == uniqid) return t;
}
return &fakeblock;
}
int getuniq(int tileid) {
tiletype_t *t;
for (t = tiletype; t ; t = t->next) {
if (t->id == tileid) return t->uniqid;
}
return 0;
}
void drawtile(SDL_Surface *where, int x, int y) {
SDL_Rect area;
tiletype_t *tt;
int frame;
int offset;
if ((x < 0) || (y < 0) || (x >= LEVELW) || (y >= LEVELH)) {
return;
}
area.x = x * TILEW;
area.y = y * TILEH;
area.w = TILEW;
area.h = TILEH;
/* draw blank tile first */
tt = gettile(curlevel->bgtileid);
SDL_BlitSurface(levelbg, &area, where, &area);
/* now draw real one */
offset = y*LEVELW+x;
tt = gettile(curlevel->map[offset]);
frame = curlevel->tileframe[offset];
if (tt->id != curlevel->bgtileid) {
SDL_BlitSurface(tt->img[frame], NULL, where, &area);
}
/* now draw layer2 if it exists */
if (curlevel->map2[offset] != T_BLANK) {
tt = gettile(curlevel->map2[offset]);
if (tt->id != curlevel->bgtileid) {
SDL_BlitSurface(tt->img[frame], NULL, where, &area);
}
}
}
void initglobals(void) {
sprite = NULL;
level = NULL;
vidargs = 0;
/* timers */
gtime = 0;
timer = 0;
toggletimer = 0;
/* colours */
red.r = 255; red.g = 0; red.b = 0;
black.r = 0; black.g = 0; black.b = 0;
blue.r = 0; blue.g = 0; blue.b = 255;
white.r = 255; white.g = 255; white.b = 255;
green.r = 0; green.g = 255; green.b = 0;
yellow.r = 255; yellow.g = 255; yellow.b = 0;
purple.r = 255; purple.g = 0; purple.b = 255;
}
SDL_Surface *loadspriteimage(int spriteid, int frame, char *filename) {
char fullfile[BUFLEN];
SDL_Surface *temps;
sprintf(fullfile,"%s/%s",datadir,filename);
//imageset[spriteid].img[frame] = IMG_Load(fullfile);
temps = IMG_Load(fullfile);
imageset[spriteid].img[frame] = SDL_DisplayFormatAlpha(temps);
if (imageset[spriteid].img[frame] == NULL) {
printf("Error loading image file: %s\n",fullfile);
exit(1);
}
SDL_FreeSurface(temps);
SDL_SetColorKey(imageset[spriteid].img[frame], SDL_RLEACCEL, 0);
return imageset[spriteid].img[frame];
}
int candoslopes(int sid) {
switch(sid) {
case P_SNAKE:
case P_SNAIL:
case P_SLUG:
return B_FALSE;
}
return B_TRUE;
}
int ismonster(int id) {
switch (id) {
case P_RAT:
case P_BEE:
case P_FLY:
case P_SPIDER:
case P_SNAKE:
case P_TICK:
case P_PLANT:
case P_SNAIL:
case P_SLUG:
case P_FISH:
case P_FROG:
case P_ANT1:
case P_ANT2:
case P_ANT3:
return MT_MONSTER;
case P_BLACKCLOUD:
case P_KINGRAT:
case P_KINGSNAIL:
case P_KINGFLY:
return MT_BOSS;
}
return B_FALSE;
}
void puffin(int willbecome, int x, int y, char *name, int delay) {
sprite_t *ss;
ss = addsprite(P_PUFF, x, y, "puff" );
ss->timer3 = willbecome;
ss->timer1 = -delay;
strncpy(ss->name, name, MIDBUFLEN);
}
/*
void removetext(void) {
SDL_Rect sarea;
text_t *t;
for (t = text ; t ; t = t->next) {
sarea.x = 0;
sarea.y = 0;
sarea.w = t->bgarea.w;
sarea.h = t->bgarea.h;
SDL_BlitSurface(t->bg, &sarea, screen, &t->bgarea);
}
}
*/
void killtext(text_t *t) {
text_t *nextone, *lastone;
if (t->bg) {
SDL_FreeSurface(t->bg);
t->bg = NULL;
}
if (t->img) {
SDL_FreeSurface(t->img);
t->img = NULL;
}
nextone = t->next;
if (nextone != NULL) {
nextone->prev = t->prev;
} else { /*last text */
lasttext = t->prev;
}
if (t->prev == NULL) {
/* first text */
nextone = text->next;
free(text);
text = nextone;
} else {
lastone = t->prev;
free (lastone->next );
lastone->next = nextone;
}
/* if we're killing text during LV_INIT, it must have been
the level announcement. That means that we can start
moving.
*/
if (levelcomplete == LV_INIT) {
levelcomplete = LV_INPROGRESS;
}
}
// returns score of given fruit type
int getpoints(int id) {
int points;
switch (id) {
case P_CHEESE:
points = 500;
break;
case P_ICECREAM:
points = 1000;
break;
case P_CHIPS:
points = 1500;
break;
case P_BURGER:
points = 2000;
break;
case P_PIZZA:
points = 2500;
break;
case P_SUNDAE:
points = 3000;
break;
case P_CAKE:
points = 3500;
break;
case P_CHOCOLATE: // LOTS
points = 8000;
break;
case P_DIAMOND:
points = 2500;
break;
case P_FLOWERYELLOW:
points = 5;
break;
case P_FLOWERRED:
points = 10;
break;
case P_FLOWERPURPLE:
points = 30;
break;
case P_GEMYELLOW:
points = 50;
break;
case P_GEMRED:
points = 75;
break;
case P_GEMPURPLE:
points = 100;
break;
default:
points = 0;
break;
}
return points;
}
int savelevellist(void) {
char filename[BUFLEN];
FILE *f;
int i;
sprintf(filename, "%s/%s",datadir,FILE_LEVELMAP);
f = fopen(filename,"w");
if (!f) {
printf("error writing to %s\n",FILE_LEVELMAP);
return B_FALSE;
}
for (i = 1; i < numlevels; i++) {
fprintf(f, "%d,%s,%s\n",levelentry[i].id, levelentry[i].filename, levelentry[i].desc);
}
fclose(f);
return B_FALSE;
}
int loadlevellist(void) {
int lev;
char filename[BUFLEN];
FILE *f;
char buf[BUFLEN];
char *p;
sprintf(filename, "%s/%s",datadir, FILE_LEVELMAP);
f = fopen(filename,"r");
if (!f) {
printf("Error opening %s\n",FILE_LEVELMAP);
exit(1);
}
// format is:
//
// id,filename,description,
lev = 1;
maxlevid = -99;
fgets(buf, BUFLEN, f);
while (!feof(f)) {
p = strtok(buf, ",");
if (!p) {
printf("invalid level id - line %d\n",lev);
return B_TRUE;
}
levelentry[lev].id = atoi(p);
// track max levelid
if (levelentry[lev].id > maxlevid) {
maxlevid = levelentry[lev].id;
}
p = strtok(NULL, ",");
if (!p) {
printf("invalid level filename - line %d\n",lev);
return B_TRUE;
}
strncpy(levelentry[lev].filename, p, MIDBUFLEN);
p = strtok(NULL, ",");
if (!p) {
printf("invalid level description - line %d\n",lev);
return B_TRUE;
}
p[strlen(p)-1] = '\0'; // strip newline
//LEVELENTry[lev].desc = strdup(p);
strncpy(levelentry[lev].desc, p, MIDBUFLEN);
lev++;
fgets(buf, BUFLEN, f);
}
fclose(f);
numlevels = lev;
printf("Read %d levels.\n",numlevels);
return B_FALSE;
}
int randompowerup(void) {
int num;
num = rand() % 46;
switch (num) {
case 0:
default:
return P_SPEED;
case 1:
return P_BIGNET;
case 2:
return P_NUMNETS;
case 3:
return P_BOXING;
case 4:
return P_FTODIAMOND;
case 5:
return P_FTOGEM;
case 6:
return P_BOMB;
case 7:
return P_SHIELD;
case 8:
return P_MACEPOWERUP;
case 9:
return P_HELMET;
case 10:
return P_GEMBOOST;
case 11:
return P_TROPHY;
case 12:
return P_RINGSILVER;
case 13:
return P_RINGGOLD;
case 14:
return P_BELL;
case 15:
return P_CLOCK;
case 16:
return P_SNOWMAN;
case 17:
return P_SPRAY;
case 18:
return P_CANNONPOWERUP;
case 19:
return P_PHONE;
case 20:
return P_HONEY;
case 21:
return P_LIFE;
case 22:
return P_STARPOWERUP;
case 23:
return P_UFO;
case 24:
return P_TAP;
case 25:
return P_MASKPOWERUP;
case 26:
if (!gotcard) {
gotcard = B_TRUE;
return getrandomcard();
} else {
return P_DIAMOND;
}
case 27:
return P_CLOVER;
case 28:
return P_ACCORDION;
case 29:
return P_WINGBOOTS;
case 30:
return P_SKULL;
case 31:
return P_GUN;
case 32:
return P_ZAPPOWERUP;
case 33:
return P_RANDOM;
case 34:
return P_GNOME;
case 35:
return P_WAND;
case 36:
return P_WHISTLE;
case 37:
return P_CANDLE;
case 38:
return P_ANCHOR;
case 39:
return P_MAGNET;
case 40:
return P_BADMAGNET;
case 41:
return P_JETPACK;
case 42:
return P_CAMERA;
case 43:
return P_UMBRELLA;
case 44:
return P_PILL;
case 45:
return P_RAYGUN;
}
}
// returns true if the given powerup id is a permenant one
int ispermenant(int pid) {
switch (pid) {
case P_SPEED:
case P_NUMNETS:
case P_BIGNET:
case P_MASKPOWERUP:
case P_HELP:
case P_TROPHY:
case P_HELMET:
case P_BELL:
case P_GEMBOOST:
return B_TRUE;
}
return B_FALSE;
}
int isbosslevel(int lev) {
if (lev % 20 == 0) {
return B_TRUE;
}
return B_FALSE;
}
int isboss(int monid) {
switch (monid) {
case P_KINGRAT:
case P_KINGSNAIL:
case P_KINGFLY:
return B_TRUE;
default:
return B_FALSE;
}
}
int isnettable(sprite_t *s) {
if (ismonster(s->id)) {
if (ismonster(s->id)) {
switch (s->id) {
case P_BLACKCLOUD:
case P_KINGRAT:
case P_KINGSNAIL:
case P_KINGFLY:
return B_FALSE;
default:
return B_TRUE;
}
}
}
if (isplayer(s)) return B_TRUE;
return B_FALSE;
}
// return starting health for a given boss type
int getbosshealth(int mid) {
switch (mid) {
case P_KINGRAT:
return 8;
case P_KINGSNAIL:
return 8;
case P_KINGFLY:
return 8;
}
return 0;
}
void getpixelrgb(SDL_Surface *where, int x, int y, SDL_Color *clr) {
Uint32 col;
//determine position
char* pPosition = ( char* ) where->pixels ;
//offset by y
pPosition += ( where->pitch * y ) ;
//offset by x
pPosition += ( where->format->BytesPerPixel * x ) ;
//copy pixel data
memcpy ( &col , pPosition , where->format->BytesPerPixel ) ;
//convert color
SDL_GetRGB ( col , where->format , &clr->r , &clr->g , &clr->b ) ;
//*r = color.r;
//*g = color.g;
//*b = color.b;
}
void setfruitinfo(void) {
setinfo(P_CHEESE, "Cheese", "", "cheese.png");
setinfo(P_ICECREAM, "Ice Cream","", "icecream.png");
setinfo(P_CHIPS, "Chips", "", "chips.png");
setinfo(P_BURGER, "Burger", "", "burger.png");
setinfo(P_DIAMOND, "Diamond", "", "diamond.png");
setinfo(P_PIZZA, "Pizza", "", "pizza.png");
setinfo(P_SUNDAE, "Sundae", "", "sundae.png");
setinfo(P_CAKE, "Cake", "", "cake.png");
setinfo(P_CHOCOLATE, "Chocolate", "", "chocolate.png");
setinfo(P_FLOWERYELLOW, "Sunflower", "", "flower-yellow.png");
setinfo(P_FLOWERRED, "Tulip", "", "flower-red.png");
setinfo(P_FLOWERPURPLE, "Orchid", "", "flower-purple.png");
setinfo(P_GEMYELLOW, "Topaz", "", "gem-yellow.png");
setinfo(P_GEMRED, "Ruby", "", "gem-red.png");
setinfo(P_GEMPURPLE, "Amethyst", "", "gem-purple.png");
setinfo(P_FIRSTCARD, "Card", "Keep a look out for these useful items. Collect a full poker hand for a secret bonus!", "cardh.png");
setinfo(P_SPEED, "Speed Up", "Makes you walk faster.", "speed.png");
setinfo(P_NUMNETS, "More Nets", "Increases the number of monsters you can catch simultaneously.", "numnets.png");
setinfo(P_BIGNET, "Big Net", "Makes your nets reach further.", "bignet.png");
setinfo(P_HELP, "Help", "Gives useful game information or hints.", "help.png");
setinfo(P_GEMBOOST, "Gem Boost", "Increases the length of gem streams.", "gemboost.png");
setinfo(P_BELL, "Powerup Bell", "Rings if certain types of powerup are going to appear on the level.", "bell.png");
setinfo(P_TROPHY, "Trophy", "Gives the player all powerups", "trophy.png");
setinfo(P_HELMET, "Helmet","Gives you a suit of armour which will protect you from death.", "helmet.png");
setinfo(P_BIGSPEED, "Big Speed Up", "Makes you walk faster, permenantly!", "bigspeed.png");
setinfo(P_BIGSCUBA, "Big Scuba Mask", "Permenantly gives you fast underwater movement.", "bigscuba.png");
setinfo(P_SUPERUMBRELLA, "Big Umbrella", "Bestows you with an umbrella which can survive death!", "superumbrella.png");
setinfo(P_MASKPOWERUP, "Scuba Mask", "Allows you to move fast underwater.", "maskpowerup.png");
setinfo(P_WINGBOOTS, "Winged Boots", "These magical boots cause you to grow wings, allowing to you jump again while in mid-air!", "wingboots.png");
setinfo(P_PILL, "Pill", "Eating this pill will cause you to enter a hyperactive state, moving at four times your standard speed!", "pill.png");
setinfo(P_RAYGUN, "Ray Gun", "Alien in origin, the ray gun contains enough charge for five shots of burning plasma.", "raygun.png");
setinfo(P_BOXING, "Boxing Glove", "Your net will punch monsters, killing them instantly.", "boxing.png");
setinfo(P_MACEPOWERUP, "Mace", "Slamming your net will cause a lethal explosion!", "macepowerup.png");
setinfo(P_FTODIAMOND, "Diamond Flower","Transforms all flowers on the level into diamonds.", "flowertodiamond.png");
setinfo(P_FTOGEM, "Rainbow Flower", "Transforms all flowers on the level into gems, and turns itself into an extra-long stream of gems.", "flowertogem.png");
setinfo(P_BOMB, "Bomb", "Explodes and kills all monsters on the level.", "bomb.png");
setinfo(P_SHIELD, "Shield", "Temporary invulnerability", "shield.png");
setinfo(P_RINGSILVER, "Silver Ring", "Until the end of the level, you gain points for jumping.", "ring-silver.png");
setinfo(P_RINGGOLD, "Gold Ring", "Until the end of the level, you gain points for walking.", "ring-gold.png");
setinfo(P_CLOCK, "Stopwatch", "Stops time for 10 seconds", "clock.png");
setinfo(P_SNOWMAN, "Snowman", "Freezes the level, turning everything to ice - touch a monster to shatter it!", "snowman.png");
setinfo(P_SPRAY, "Fly Spray", "Sickens all monsters, causing them to slow down to half speed.","spray.png");
setinfo(P_CANNONPOWERUP, "Fusion Cannon", "A powerful weapon which will shoot out laser beams in all directions!", "cannonpowerup.png");
setinfo(P_PHONE, "Phone", "Calls in your helper cloud and immediately skips two levels (but note that this cannot skip a boss level).", "phone.png");
setinfo(P_HONEY, "Honey", "Coats your net in a layer of sticky honey, allowing it to pick up fruits from afar.", "honey.png");
setinfo(P_STARPOWERUP, "Shuriken", "Shoots deadly razor blades in all directions.", "star.png");
setinfo(P_LIFE, "Life", "Awards the player an extra life.", "extralife.png");
setinfo(P_UFO, "UFO", "Calls in a powerful meteor strike!", "ufo.png");
setinfo(P_TAP, "Tap", "The leaky tap will flood the level with water for 20 seconds, allowing you to access hard to reach areas.", "tap.png");
setinfo(P_ACCORDION, "Accordion", "Makes your nets enormous", "accordion.png");
setinfo(P_GUN, "Gunner", "Temporarily equips you with a super powerful machine gun!", "gunner.png");
setinfo(P_GNOME, "Garden Gnome", "This tricky little gnome has rigged explosive devices to all flowers on the level - when collected he will detonate them!", "gnome.png");
setinfo(P_WAND, "Magic Wand", "A wave of the magic wand will magically polymorph all monsters into weaker ones. Anything which can't become weaker will be instantly destroyed!", "wand.png");
setinfo(P_WHISTLE, "Whistle", "Produces an extremely loud, shrill whistling noise which wakes the black cloud of doom! In its angered state, the black cloud will slaughter both friend and foe alike.", "whistle.png");
setinfo(P_CANDLE, "Candle", "Once collected, the candle will cause all enemy corpses to burst into flames, igniting any other enemy which they touch.", "candle.png");
setinfo(P_ANCHOR, "Anchor", "The extremely heavy anchor will weigh down enemies, preventing them from jumping or flying.", "anchor.png");
setinfo(P_MAGNET, "Magnet", "Collecting this powerup will align the magnetic forces of the earth in your favour, attracting all nearby fruits towards you.", "magnet.png");
setinfo(P_BADMAGNET, "Red Skull", "This skull curses you and will repel fruits away from you, denying you access to them!", "badmagnet.png");
setinfo(P_JETPACK, "Jetpack", "For the remainder of the current level, the jetpack's thrust will add to your jumping ability!", "jetpack.png");
setinfo(P_UMBRELLA, "Umbrella", "Slows your descent, giving you more time to contemplate your rat eradication quest. Activate this useful item by holding UP while falling.", "umbrella.png");
setinfo(P_CAMERA, "Camera", "Creates a bright flash of light, blinding all enemies.", "camera.png");
setinfo(P_ZAPPOWERUP, "Bug Zapper", "Zaps nearby enemies with miniature bolts of lightning", "zapper.png");
setinfo(P_SKULL, "Green Skull", "Avoid these at all costs! The green skull will shrink your net to miniscule proportions for the remainder of the level.", "skull.png");
setinfo(P_CLOVER, "4-Leaf Clover", "Increases your luck...", "clover.png");
setinfo(P_RANDOM, "Random", "Gives you a random effect...", "random.png");
setinfo(P_PLAYER, "Mr. Dwarf", "Mr. Dwarf is currently highly disgruntled due to repeated burglaries of his hard-earned dinner. After one theft too many, he is now out for revenge! When encased in his shining suit of golden armour, Mr. Dwarf is bestowed with incredible powers of endurance, and is able to withstand any earthly threat. Once once, though.", "pdwarf.png");
setinfo(P_PLAYER2, "Mrs. Dwarf", "Mrs. Dwarf, being the loyal partner that she is, has become equally aggrieved by the constant re-appropriation of culinary treats and has joined Mr. Dwarf on his quest to end the rat menace forever. Her more feminine armour no less effective, just slightly more visually appealing with its convenient openings for lipstick and hair!", "p2dwarf.png");
setinfo(P_ARMOUR, "Armoured Mr. Dwarf", "", "armor.png");
setinfo(P_ARMOUR2, "Armoured Mrs. Dwarf", "", "armor2.png");
setinfo(P_RAT, "Rat", "The weakest of the monsters, the rat will simply walk back and forth waiting to be caught. Beware an angry rat though, as it will try to fall or jump in order to catch you!", "rat.png");
setinfo(P_BEE, "Bee", "Bees, while still relatively weak, gain an advantage over rats in that they are able to fly. They move in a simple diagonal pattern, changing direction when they get near a wall or spikes. Bees will speed up when angry.", "newbee.png");
setinfo(P_FISH, "Pirahna", "These fish at at home in the water and unhampered by slowness while swimming.", "fish.png");
setinfo(P_SPIDER, "Spider", "Spiders will lurk quietly on the ceiling, crawling back and forth. If they notice a player nearby however they will swiftly pounce down onto their prey!", "spider.png");
setinfo(P_FROG, "Frog", "Green frogs will continually bounce around, making them more difficult to catch. They are also excellent swimmers.", "frog.png");
setinfo(P_ANT1, "Worker Ant", "Worker ants are relatively easy to avoid, but when fed will quickly grow into more dangerous soldier ants.", "ant1.png");
setinfo(P_ANT2, "Soldier Ant", "Soldiers move faster and are more intelligent than their worker siblings. In addition, with just a little food they will become queens.", "ant2.png");
setinfo(P_ANT3, "Queen Ant", "After an ant has eaten enough, they become a Queen. Queens are just as fast as soldiers and can also breath fire. Furthermore, they are only one meal away from spawning additional ants!", "ant3.png");
setinfo(P_SNAKE, "Snake", "The snake moves in a similar fashion to the rat with one important exception - upon seeing a player they will spit a glob of deadly venom at them!", "snake.png");
setinfo(P_FLY, "Fly", "Annoying pests at the best of times, flies pose additional danger to dwarves. They fly around more erratically than bees and after landing can scurry quickly back and forth.", "fly.png");
setinfo(P_TICK, "Tick", "The tick is small but intelligent. Even in its regular placid state it will move in the same manner as an angry rat. Because of their small size, they are also difficult to target with a slam!", "tick.png");
setinfo(P_PLANT, "Plant", "Evil venus fly trap plants will lie in wait and devour any player foolish enough to wander into their clutches.", "plant.png");
setinfo(P_BLACKCLOUD, "Cloud of Doom", "This unkillable cloud will appear if you spend too much time on one level. Beware, as the only way to defeat the cloud of doom is to complete the level before it grows too large to handle!", "cloud.png");
setinfo(P_KINGRAT, "King Rat", "This mighty creature is the ruler of the rats, and impervious to the player's net. It can only be harmed by slamming another monster into it! King Rat will roam the level searching for a player, and upon spotting them will charge at high speed.", "kingrat.png");
setinfo(P_KINGSNAIL, "King Snail", "The absolute ruler of the snail kingdom is far too large and heavy to catch in a net. In addition, its shell provides protection against all attacks, leaving only its head vulnerable. While King Snail is too proud to chase down enemies itself, it can use its snail army to destroy its foes.", "kingsnail.png");
setinfo(P_KINGFLY, "King Fly", "King Fly is quite literally the lord of the flies. Far from the timid garden-variety fly, King Fly will roam around with its entourage of underlings in tow, running down anything in its path!", "kingfly.png");
setinfo(P_SNAIL, "Snail", "Snails are slow moving but tough. When attacked normally they will not die, but simply lose their shell and become a slug. The safest way to take them out is to slam another monster into them, thus killing them instantly.", "snail.png");
setinfo(P_SLUG, "Slug", "Slugs are faster moving than snails and capable of launching themselves through the air at their prey!", "slug.png");
}
void setinfo(int id, char *name, char *desc, char *file) {
spriteinfo[id].name = strdup(name);
spriteinfo[id].desc = strdup(desc);
spriteinfo[id].file = strdup(file);
}
// dump html doco
void dumpinfo(void) {
int i;
int count;
// header
//printf("<html>\n");
//printf("<body bgcolor=\"#AAAAAA\">\n");
printf("<center><h2>Creatures</h2></center>\n");
printf("<table border=1>\n");
// players
printf("<tr bgcolor=\"#ffff00\"><th colspan=4>Players</th></tr>\n");
for (i = 0; i < MAXPTYPES; i++) {
switch (i) {
case P_PLAYER:
printf("<tr><td align=center><img src=\"img/%s\"><img src=\"img/%s\"><br>%s</td><td colspan=3>%s</td></tr>\n",
spriteinfo[i].file, spriteinfo[P_ARMOUR].file, spriteinfo[i].name,spriteinfo[i].desc);
break;
case P_PLAYER2:
printf("<tr><td align=center><img src=\"img/%s\"><img src=\"img/%s\"><br>%s</td><td colspan=3>%s</td></tr>\n",
spriteinfo[i].file, spriteinfo[P_ARMOUR2].file, spriteinfo[i].name,spriteinfo[i].desc);
break;
}
}
// monsters
printf("<tr bgcolor=\"#ffff00\"><th colspan=4>Monsters</th></tr>\n");
/*
for (i = 0; i < MAXPTYPES; i++) {
if (ismonster(i) == MT_MONSTER) {
printf("<tr><td align=center><img src=\"img/%s\"><br>%s</td><td>%s</td></tr>\n",
spriteinfo[i].file, spriteinfo[i].name,spriteinfo[i].desc);
}
}
*/
count = 0;
for (i = 0; i < MAXPTYPES; i++) {
if (ismonster(i) == MT_MONSTER) {
if (count % 2 == 0) {
printf("<tr>");
}
printf("<td width=10%% align=center><img src=\"img/%s\">\n",
spriteinfo[i].file);
if (i == P_SNAKE) {
printf("<img src=\"img/spit.png\">");
} else if (i == P_ANT3) {
printf("<img src=\"img/fire1.png\">");
} else if (i == P_SPIDER) {
printf("<img src=\"img/newspiderfall.png\">");
}
printf("<br>%s</td><td>%s</td>\n",
spriteinfo[i].name,spriteinfo[i].desc);
if (count % 2 == 1) {
printf("</tr>");
}
count++;
}
}
if (count % 2 == 0) {
printf("</tr>");
} else {
printf("<td colspan=2>&nbsp;</td></tr>");
}
// bosses
printf("<tr bgcolor=\"#ffff00\"><th colspan=4>Bosses</th></tr>\n");
/*
for (i = 0; i < MAXPTYPES; i++) {
if (ismonster(i) == MT_BOSS) {
printf("<tr><td align=center><img src=\"img/%s\"><br>%s</td><td colspan=3>%s</td></tr>\n",
spriteinfo[i].file, spriteinfo[i].name,spriteinfo[i].desc);
}
}
*/
count = 0;
for (i = 0; i < MAXPTYPES; i++) {
if (ismonster(i) == MT_BOSS) {
if (count % 2 == 0) {
printf("<tr>");
}
printf("<td align=center><img src=\"img/%s\"><br>%s</td><td>%s</td>\n",
spriteinfo[i].file, spriteinfo[i].name,spriteinfo[i].desc);
if (count % 2 == 1) {
printf("</tr>");
}
count++;
}
}
if (count % 2 == 0) {
printf("</tr>");
} else {
printf("<td colspan=2>&nbsp;</td></tr>");
}
printf("</table>\n");
printf("<center><h2>Power-Ups</h2>\n");
printf("<table border=1>\n");
// fruits
printf("<tr bgcolor=\"#ffff00\"><th colspan=4>Fruits</th></tr>\n");
count = 0;
for (i = 0; i < MAXPTYPES; i++) {
if ((isfruit(i) == FT_FRUIT) && (i != P_DIAMOND)) {
if (count % 2 == 0) {
printf("<tr>");
}
printf("<td width=10%% align=center><img src=\"img/%s\"><br>%s</td><td width=40%%>Worth %d points.</td>\n",
spriteinfo[i].file, spriteinfo[i].name,getpoints(i));
if (count % 2 == 1) {
printf("</tr>");
}
count++;
}
}
for (i = 0; i < MAXPTYPES; i++) {
if ((isfruit(i) == FT_GEM)) {
if (count % 2 == 0) {
printf("<tr>");
}
printf("<td width=10%% align=center><img src=\"img/%s\"><br>%s</td><td width=40%%>Worth %d points.</td>\n",
spriteinfo[i].file, spriteinfo[i].name,getpoints(i));
if (count % 2 == 1) {
printf("</tr>");
}
count++;
}
}
printf("<td width=10%% align=center><img src=\"img/%s\"><br>%s</td><td width=40%%>Worth %d points.</td>\n",
spriteinfo[P_DIAMOND].file, spriteinfo[P_DIAMOND].name,getpoints(P_DIAMOND));
if (count % 2 == 1) {
printf("</tr>");
} else {
printf("<td colspan=2>&nbsp;</td></tr>");
}
// perm powerup
printf("<tr bgcolor=\"#ffff00\"><th colspan=4>Permenant Powerups</th></tr>\n");
count = 0;
for (i = 0; i < MAXPTYPES; i++) {
if (isfruit(i) == FT_PERM) {
if (count % 2 == 0) {
printf("<tr>");
}
printf("<td align=center><img src=\"img/%s\"><br>%s</td><td>%s</td>\n",
spriteinfo[i].file, spriteinfo[i].name,spriteinfo[i].desc);
if (count % 2 == 1) {
printf("</tr>");
}
count++;
}
}
if (count % 2 == 0) {
printf("<tr>");
}
// card
printf("<td align=center><img src=\"img/%s\"><br>%s</td><td>%s</td>\n",
spriteinfo[P_FIRSTCARD].file, spriteinfo[P_FIRSTCARD].name,spriteinfo[P_FIRSTCARD].desc);
if (count % 2 == 1) {
printf("</tr>");
} else {
printf("<td colspan=2>&nbsp;</td></tr>");
}
// temp powerup
printf("<tr bgcolor=\"#ffff00\"><th colspan=4>Temporary Powerups</th></tr>\n");
count = 0;
for (i = 0; i < MAXPTYPES; i++) {
if ((isfruit(i) == FT_TEMP) && (i != P_RANDOM)) {
if (count % 2 == 0) {
printf("<tr>");
}
printf("<td align=center><img src=\"img/%s\"><br>%s</td><td>%s</td>\n",
spriteinfo[i].file, spriteinfo[i].name,spriteinfo[i].desc);
if (count % 2 == 1) {
printf("</tr>");
}
count++;
}
}
if (count % 2 == 0) {
printf("<tr>");
}
// random comes last
printf("<td align=center><font color=\"ff00ff\"><b><big>?</big></b></font><br>%s</td><td>%s</td>\n", spriteinfo[P_RANDOM].name,spriteinfo[P_RANDOM].desc);
if (count % 2 == 1) {
printf("</tr>");
} else {
printf("<td colspan=2>&nbsp;</td></tr>");
}
// super powerup
printf("<tr bgcolor=\"#ffff00\"><th colspan=4>Super Powerups</th></tr>\n");
count = 0;
for (i = 0; i < MAXPTYPES; i++) {
if (isfruit(i) == FT_SUPER) {
if (count % 2 == 0) {
printf("<tr>");
}
printf("<td align=center><img src=\"img/%s\"><br>%s</td><td>%s</td>\n",
spriteinfo[i].file, spriteinfo[i].name,spriteinfo[i].desc);
if (count % 2 == 1) {
printf("</tr>");
}
count++;
}
}
if (count % 2 == 1) {
printf("<td colspan=2>&nbsp;</td></tr>");
}
printf("</table>\n");
printf("</center>\n");
//printf("</body></html>\n");
}
void doblit(SDL_Surface *src, SDL_Surface *dst, SDL_Rect *dstarea) {
SDL_Rect srcarea;
if ((dstarea->y > 0) && (dstarea->y <= (480-src->h))) {
// completely onscreen
SDL_BlitSurface(src, NULL, dst, dstarea);
} else if (dstarea->y > (480-src->h)) {
// off the bottom
srcarea.x = 0;
srcarea.y = 0;
srcarea.w = src->w;
srcarea.h = 480 - dstarea->y;
if (srcarea.h > 0) {
SDL_BlitSurface(src, &srcarea, dst, dstarea);
}
} else if (dstarea->y < 0) {
// off the top
srcarea.x = 0;
srcarea.w = src->w;
srcarea.y = - dstarea->y;
srcarea.h = src->h - srcarea.y;
if (srcarea.y > 0) {
dstarea->y = 0;
dstarea->h = srcarea.h;
dstarea->w = srcarea.w;
SDL_BlitSurface(src, &srcarea, dst, dstarea);
}
}
}
char *getcardletter(int num) {
switch (num) {
case 0:
return "X";
case 1:
return "A";
case 2:
return "2";
case 3:
return "3";
case 4:
return "4";
case 5:
return "5";
case 6:
return "6";
case 7:
return "7";
case 8:
return "8";
case 9:
return "9";
case 10:
return "10";
case 11:
return "J";
case 12:
return "Q";
case 13:
return "K";
}
return "?";
}
// returns a random card sprite id
int getrandomcard(void) {
int i;
int cardid;
int gotit;
//cardid = P_FIRSTCARD + (rand() % 52);
// TODO: possible infinite loop?
gotit = B_TRUE;
while (gotit) {
// give current card
cardid = deck[curcard];
// move to next card
curcard++;
if (curcard >= DECKSIZE) {
shufflecards();
curcard = 0;
}
// make sure the player doesn't have it!
gotit = B_FALSE;
if (player) {
for (i = 0; i < player->numcards; i++) {
if (player->card[i] == cardid) {
gotit = B_TRUE;
}
}
}
if (player2) {
for (i = 0; i < player2->numcards; i++) {
if (player2->card[i] == cardid) {
gotit = B_TRUE;
}
}
}
// are we forcing it to be good?
if (forcegoodcard) {
if ((player && player->numcards > 0) || (player2 && player2->numcards > 0)) {
int okay = B_FALSE;
int csuit,cval;
if (player) {
for (i = 0; i < player->numcards; i++) {
cval = getcardvalue(player->card[i]);
csuit = getcardsuit(player->card[i]);
if (csuit == getcardsuit(cardid)) okay = B_TRUE;
if (cval == (getcardvalue(cardid))) okay = B_TRUE;
if (cval == (getcardvalue(cardid)+1)) okay = B_TRUE;
if (cval == (getcardvalue(cardid)-1)) okay = B_TRUE;
}
}
if (player2 && !okay) {
for (i = 0; i < player2->numcards; i++) {
cval = getcardvalue(player2->card[i]);
csuit = getcardsuit(player2->card[i]);
if (csuit == getcardsuit(cardid)) okay = B_TRUE;
if (cval == (getcardvalue(cardid))) okay = B_TRUE;
if (cval == (getcardvalue(cardid)+1)) okay = B_TRUE;
if (cval == (getcardvalue(cardid)-1)) okay = B_TRUE;
}
}
// if not a good card, go to next one
if (!okay) {
gotit = B_TRUE;
}
}
}
}
return cardid;
}
char *getcardname(int id) {
switch (id) {
case P_CARDH1:
return "Ace of Hearts";
case P_CARDH2:
return "Two of Hearts";
case P_CARDH3:
return "Three of Hearts";
case P_CARDH4:
return "Four of Hearts";
case P_CARDH5:
return "Five of Hearts";
case P_CARDH6:
return "Six of Hearts";
case P_CARDH7:
return "Seven of Hearts";
case P_CARDH8:
return "Eight of Hearts";
case P_CARDH9:
return "Nine of Hearts";
case P_CARDH10:
return "Ten of Hearts";
case P_CARDHJ:
return "Jack of Hearts";
case P_CARDHQ:
return "Queen of Hearts";
case P_CARDHK:
return "King of Hearts";
case P_CARDD1:
return "Ace of Diamonds";
case P_CARDD2:
return "Two of Diamonds";
case P_CARDD3:
return "Three of Diamonds";
case P_CARDD4:
return "Four of Diamonds";
case P_CARDD5:
return "Five of Diamonds";
case P_CARDD6:
return "Six of Diamonds";
case P_CARDD7:
return "Seven of Diamonds";
case P_CARDD8:
return "Eight of Diamonds";
case P_CARDD9:
return "Nine of Diamonds";
case P_CARDD10:
return "Ten of Diamonds";
case P_CARDDJ:
return "Jack of Diamonds";
case P_CARDDQ:
return "Queen of Diamonds";
case P_CARDDK:
return "King of Diamonds";
case P_CARDS1:
return "Ace of Spades";
case P_CARDS2:
return "Two of Spades";
case P_CARDS3:
return "Three of Spades";
case P_CARDS4:
return "Four of Spades";
case P_CARDS5:
return "Five of Spades";
case P_CARDS6:
return "Six of Spades";
case P_CARDS7:
return "Seven of Spades";
case P_CARDS8:
return "Eight of Spades";
case P_CARDS9:
return "Nine of Spades";
case P_CARDS10:
return "Ten of Spades";
case P_CARDSJ:
return "Jack of Spades";
case P_CARDSQ:
return "Queen of Spades";
case P_CARDSK:
return "King of Spades";
case P_CARDC1:
return "Ace of Clubs";
case P_CARDC2:
return "Two of Clubs";
case P_CARDC3:
return "Three of Clubs";
case P_CARDC4:
return "Four of Clubs";
case P_CARDC5:
return "Five of Clubs";
case P_CARDC6:
return "Six of Clubs";
case P_CARDC7:
return "Seven of Clubs";
case P_CARDC8:
return "Eight of Clubs";
case P_CARDC9:
return "Nine of Clubs";
case P_CARDC10:
return "Ten of Clubs";
case P_CARDCJ:
return "Jack of Clubs";
case P_CARDCQ:
return "Queen of Clubs";
case P_CARDCK:
return "King of Clubs";
}
return "Unknown Card";
}
void shufflecards(void) {
int ii,i,n,thiscard;
// generate initial list of cards
for (i = 0; i < DECKSIZE; i++) {
deck[i] = P_FIRSTCARD + i;
}
// shuffle them
for (ii = 0; ii < SHUFFLEQUALITY; ii++) {
for (i = 0; i < DECKSIZE; i++) {
// 50% chance of moving to the end
if (rand() % 2) {
thiscard = deck[i];
for (n = i; n < (DECKSIZE-1); n++) {
deck[n] = deck[n+1];
}
deck[DECKSIZE-1] = thiscard;
}
}
}
curcard = 0;
}
int getworld(int lev) {
int wnum;
wnum = ((lev-1)/20)+1;
return wnum;
}
int getlevel(int lev) {
int wnum;
wnum = (lev%20);
if (wnum == 0) return 20;
return wnum;
}
int getcardsuit(int cardid) {
if ((cardid >= P_FIRSTHEART) && (cardid <= (P_FIRSTHEART + 12))) {
return CS_HEART;
} else if ((cardid >= P_FIRSTDIAMOND) && (cardid <= (P_FIRSTDIAMOND + 12))) {
return CS_DIAMOND;
} else if ((cardid >= P_FIRSTSPADE) && (cardid <= (P_FIRSTSPADE + 12))) {
return CS_SPADE;
} else {
return CS_CLUB;
}
}
int getcardvalue(int cardid) {
int points;
points = cardid;
switch (getcardsuit(cardid)) {
case CS_HEART:
points -= P_FIRSTHEART;
break;
case CS_DIAMOND:
points -= P_FIRSTDIAMOND;
break;
case CS_SPADE:
points -= P_FIRSTSPADE;
break;
case CS_CLUB:
default:
points -= P_FIRSTCLUB;
break;
}
return (points+1);
}
// draw player, and wings if required
void drawplayer(sprite_t *s, SDL_Rect *where) {
#ifndef __EDITOR
SDL_Rect wingarea;
int wingframe;
int drawwings;
#endif
#ifndef __EDITOR
if (s->powerup == PW_GUNNER) {
SDL_Color *ccol;
SDL_Color purple;
purple.r = 255;
purple.g = 0;
purple.b = 255;
// just draw crosshairs
if (s == player) {
ccol = &red;
} else {
ccol = &purple;
}
// box
drawbox16(screen, s->x-(TILEW/2),s->y-(TILEH/2),s->x+(TILEW/2),s->y+(TILEH/2), ccol, NULL);
// littlebox
drawbox16(screen, s->x-1,s->y-1,s->x+1,s->y+1, ccol, NULL);
// lines
drawline(screen, s->x, 0, s->x, s->y-(TILEH/2), *ccol); // top
drawline(screen, s->x, s->y+(TILEH/2), s->x, 480-1, *ccol); // bottom
drawline(screen, 0, s->y, s->x-(TILEW/2), s->y, *ccol); // left
drawline(screen, s->x+(TILEW/2), s->y, 640-1, s->y, *ccol); // right
return;
}
// only draw wings in certain states
switch (levelcomplete) {
case LV_NEXTLEV:
case LV_CLOUDLOOP:
drawwings = B_FALSE;
break;
default:
drawwings = B_TRUE;
break;
}
if ((s->doublejump) && (levelcomplete != LV_NEXTLEV)) {
// draw wings behind the sprite
if (s->jumping || s->falling) {
// flapping wings - freeze while showing help text
if (((timer/12) % 2 == 0) || (levelcomplete == LV_HELPFREEZE)) {
wingframe = 1;
} else {
wingframe = 2;
}
} else {
// still wings
wingframe = 0;
}
wingarea.x = s->x - (imageset[P_WINGRIGHT].img[wingframe]->w/2);
wingarea.y = s->y - (imageset[P_WINGRIGHT].img[wingframe]->h);
if (wingframe == 0) { // still
wingarea.x += (4*s->dir);
wingarea.y += 2;
} else if ((wingframe >= 1) && (wingframe <= 2)) { // flapping
wingarea.x += (11*s->dir);
wingarea.y -= 9;
}
if (s == player2) {
wingarea.x -= (4 * s->dir);
}
// when climbing, show "left" wing twice instead
// when swimming, only show left wing
if (!s->climbing && !s->swimming) {
if (s->dir == -1) wingframe += MAXFRAMES;
doblit(imageset[P_WINGRIGHT].img[wingframe], screen, &wingarea);
}
}
#endif
if ((levelcomplete == LV_CLOUDLOOP) || (levelcomplete == LV_NEXTLEV)) {
s->img = imageset[s->id].img[F_SHOOT];
}
// draw the sprite
doblit(s->img, screen, where);
#ifndef __EDITOR
if ((s->doublejump) && (levelcomplete != LV_NEXTLEV)) {
// draw wings in front of the sprite
if (s->swimming) {
wingframe = 3;
} else if (s->jumping || s->falling) {
// flapping wings
if ((timer/12) % 2 == 0) {
wingframe = 1;
} else {
wingframe = 2;
}
} else {
// still wings
wingframe = 0;
}
wingarea.x = s->x - (imageset[P_WINGLEFT].img[wingframe]->w/2);
wingarea.y = s->y - (imageset[P_WINGLEFT].img[wingframe]->h);
if (wingframe == 0) { // still
if (s->climbing) {
wingarea.x -= 4;
wingarea.y += 2;
} else {
wingarea.x -= (6*s->dir);
wingarea.y += 2;
}
} else if ((wingframe >= 1) && (wingframe <= 2)) { // flapping
wingarea.x -= (11*s->dir);
wingarea.y -= 9;
} else if (wingframe == 3) {
wingarea.y -= 9;
wingarea.x -= (6*s->dir);
}
if (s->dir == -1) wingframe += MAXFRAMES;
doblit(imageset[P_WINGLEFT].img[wingframe], screen, &wingarea);
if (s->climbing) {
// draw the other wing
wingarea.x += 8;
// reverse it
if (s->dir == -1) wingframe -= MAXFRAMES;
else wingframe += MAXFRAMES;
doblit(imageset[P_WINGLEFT].img[wingframe], screen, &wingarea);
}
}
// draw umbrella
if (s->umbrella && s->umbrellaup) {
if ((levelcomplete != LV_CLOUD) && (levelcomplete != LV_CLOUDLOOP)) {
if (!s->swimming && !s->climbing) {
SDL_Rect umarea;
if (s->netting) {
if (s->dir == D_RIGHT) {
umarea.x = s->x - 11 - 10;
} else {
umarea.x = s->x - 11 + 10;
}
umarea.y = s->y - s->img->h - 2;
} else if (s->falling) {
if (s->dir == D_RIGHT) {
umarea.x = s->x - 11 - 8;
} else {
umarea.x = s->x - 11 + 8;
}
umarea.y = s->y - s->img->h - 9;
} else {
umarea.x = s->x - 11;
umarea.y = s->y - s->img->h - 2;
}
doblit(imageset[P_BIGUMBRELLA].img[F_WALK1], screen, &umarea);
}
}
}
#endif
}
void resethurryup(level_t *lev) {
nexthurryup = gtime + lev->hurryuptime;
if (gamemode == GM_EASY) {
nexthurryup += 15;
}
}
int isplayer(sprite_t *s) {
if (player && (s == player)) return B_TRUE;
if (player2 && (s == player2)) return B_TRUE;
return B_FALSE;
}
int playersalive(void) {
// you don't count as a "player" if you are out of lives
if (player && player->dead && player->lives > 0) return B_FALSE;
if (player2 && player2->dead && player2->lives > 0) return B_FALSE;
return B_TRUE;
}
int getnumplayers(void) {
int num = 0;
if (player) num++;
if (player2) num++;
return num;
}