#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "defs.h" #include "globals.h" #include "shared.h" int loadlevel(int wnum, int lnum) { FILE *f; int x,y; char buf[BUFLEN]; char buf2[BUFLEN]; char filename[BUFLEN]; char *help[MAXHELP]; int numhelp = 0; int curhelp; char *p; int tileid; int i; //int *ii; mapping_t mapping[MAXMAPPINGS]; int nmappings = 0; tiletype_t *lasttile; int newversion; int numanim = 0; int tempanim[LEVELW*LEVELH]; int numenemies = 0; printf("Loading level %d-%d...",wnum,lnum); // 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)); if (level->animtiles) free(level->animtiles); level->id = 0; sprintf(level->name, "Level %d-%d",wnum,lnum); level->prev = NULL; level->next = NULL; /* default */ level->hurryuptime = 30; level->poweruptime = 5; level->p1x = 0; level->p1y = 0; level->powerupx = -1; level->powerupy = -1; sprintf(filename, "world%d/level%d.dat",wnum,lnum); f = fopen(filename,"rt"); if (!f) { printf("can't open level file\n"); return B_TRUE; } /* 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; } /* remove all onscreen text */ while (text) { killtext(text); } /* clear sprite linked list (leave player) */ if (sprite != NULL) { while (sprite->next) { killsprite(sprite->next); } } /* 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; } /* 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; /* read tile defs */ nmappings = 0; fgets(buf, BUFLEN, f); while (!strstr(buf, "endmaps")) { strncpy(buf2,buf,BUFLEN); p = strtok(buf2, ","); if (p == NULL) { printf("invalid char->tile mapping: '%s'\n",buf); return B_TRUE; } mapping[nmappings].ch = p[0]; p = strtok(NULL, ","); if (p == NULL) { printf("invalid char->tile mapping: '%s'\n",buf); return B_TRUE; } mapping[nmappings].tnum = atoi(p); printf("got mapping: '%c' to %d\n",mapping[nmappings].ch,mapping[nmappings].tnum); nmappings++; fgets(buf, BUFLEN, f); } 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); 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 if (monid == P_PLAYER) { level->p1x = x; level->p1y = y; } else if (monid == P_POWERUPPOS) { level->powerupx = x; level->powerupy = y; } 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++; } fgets(buf, BUFLEN, f); } /* this reads the next line after monster defs */ fgets(buf, BUFLEN, f); } printf("got %d monsters\n", numenemies); /* 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; while (!feof(f)) { /* 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 { // animated level->tileframe[y*LEVELW+x] = rand() % numframes; tempanim[numanim] = y*LEVELW+x; numanim++; } x++; p = strtok(NULL, ","); } } else { /* old level data version */ for (p = buf; *p; p++) { int n,found = 0; /* search mappings */ for (n = 0; n < nmappings; n++) { if (mapping[n].ch == *p) { tileid = mapping[n].tnum; found = B_TRUE; break; } } if (!found) { if (*p == '~') { tileid = T_LAND; } else if (*p == '=') { tileid = T_LADDER; } else if (*p == '-') { tileid = T_LADDERTOP; } else if (*p == '{') { tileid = T_WATERTOP; } else if (*p == '}') { tileid = T_WATER; } else if (*p == '>') { tileid = T_RIGHT; } else if (*p == '<') { tileid = T_LEFT; } else if (*p == '^') { tileid = T_SPIKES; } else if (*p == '|') { tileid = T_WATERSPIKES; } else if (*p == 'c') { tileid = level->bgtileid; level->initm[level->nummonsters].startx = x*TILEW+(TILEW/2); level->initm[level->nummonsters].starty = y*TILEH+(TILEH-2); level->initm[level->nummonsters].id = P_CLOUD; level->nummonsters++; } else if (*p == 'r') { /* figure out background type */ if (lasttile->solid) { tileid = level->map[(y-1)*LEVELW+x]; } else { tileid = lasttile->id; } // tileid = level->bgtileid; level->initm[level->nummonsters].startx = x*TILEW+(TILEW/2); level->initm[level->nummonsters].starty = y*TILEH+(TILEH-2); level->initm[level->nummonsters].id = P_RAT; level->nummonsters++; } else if (*p == 'S') { /* figure out background type */ if (lasttile->solid) { tileid = level->map[(y-1)*LEVELW+x]; } else { tileid = lasttile->id; } // tileid = level->bgtileid; level->initm[level->nummonsters].startx = x*TILEW+(TILEW/2); level->initm[level->nummonsters].starty = y*TILEH+(TILEH-2); level->initm[level->nummonsters].id = P_SNAKE; level->nummonsters++; } else if (*p == 'a') { /* figure out background type */ if (lasttile->solid) { tileid = level->map[(y-1)*LEVELW+x]; } else { tileid = lasttile->id; } level->initm[level->nummonsters].startx = x*TILEW+(TILEW/2); level->initm[level->nummonsters].starty = y*TILEH+(TILEH-2); level->initm[level->nummonsters].id = P_BEE; level->nummonsters++; } else if (*p == 's') { /* figure out background type */ if (lasttile->solid) { tileid = level->map[(y-1)*LEVELW+x]; } else { tileid = lasttile->id; } level->initm[level->nummonsters].startx = x*TILEW+(TILEW/2); level->initm[level->nummonsters].starty = y*TILEH+TILEH; level->initm[level->nummonsters].id = P_SPIDER; level->nummonsters++; } else if (*p == '?') { /* figure out background type */ if (lasttile->solid) { tileid = level->map[(y-1)*LEVELW+x]; } else { tileid = lasttile->id; } // tileid = level->bgtileid; level->initm[level->nummonsters].startx = x*TILEW+(TILEW/2); level->initm[level->nummonsters].starty = y*TILEH+(TILEH-2); level->initm[level->nummonsters].id = P_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++; } else if (*p == '*') { tileid = T_FULL; } else if (*p == ';') { tileid = T_TELEPORT; } else if (*p == ':') { tileid = T_TELEPORT2; } else if (*p == '.') { tileid = T_TELEPORTDEST; } else if (*p == '/') { tileid = T_SLOPEUP; } else if (*p == '\\') { tileid = T_SLOPEDOWN; } else if (*p == '1') { /* figure out background type */ if (lasttile->solid) { tileid = level->map[(y-1)*LEVELW+x]; } else { tileid = lasttile->id; } level->p1x = x; level->p1y = y; } else { tileid = level->bgtileid; } } if (!gettile(tileid)) { printf("invalid tileid: %d\n",tileid); fclose(f); return B_TRUE; } if (x > LEVELW) { 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; } level->map[y*LEVELW+x] = tileid; lasttile = gettile(tileid); x++; } } /* if newversion */ /* 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); } 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; } #endif /* free help texts */ for (i = 0; i < numhelp; i++) { free(help[i]); } /* set current level pointer */ curlevel = level; /* add player if required */ if (player == NULL) { addsprite(P_PLAYER, (curlevel->p1x * TILEW) + (TILEW/2), (curlevel->p1y * TILEH) + TILEH-2 , "Player" ); player = lastsprite; } #ifdef __EDITOR /* add powerup pos if it exists */ if ((level->powerupx != -1) && (level->powerupy != -1)) { addsprite(P_POWERUPPOS, (curlevel->powerupx * TILEW) + (TILEW/2), (curlevel->powerupy * TILEH) + TILEH-2 , "poweruppos" ); } #endif /*else { player->x = (curlevel->p1x * TILEW) + (TILEW/2); player->y = (curlevel->p1y * TILEH) + TILEH-2; } */ /* add monsters */ for (i = 0; i < level->nummonsters; i++) { char name[MIDBUFLEN]; int delay; if (level->initm[i].id == P_HELP) { strncpy(name, level->initm[i].help, MIDBUFLEN); } else { strcpy(name, "Monster"); } if (ismonster(level->initm[i].id)) { delay = 20; } else { delay = 0; } #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; printf("Done.\n"); /* for (ii = level->animtiles ; ii && *ii != -1; ii++) { printf("%d ",*ii); } printf(".\n"); */ return B_FALSE; } void setdefaults(sprite_t *s) { s->speed = 1; s->teleporting = 0; s->climbing = 0; s->jumping = 0; s->jumpspeed = 0; s->jumpdir = 1; s->timer1 = 0; s->timer2 = 0; s->timer3 = 0; s->netting = 0; s->netmax = 1; s->netcaught = 0; s->netbig = 0; s->dropping = 0; s->dropx = -1; s->quickdie = B_FALSE; s->dropy = -1; s->falling = 0; s->fallspeed = 0; s->dir = 1; s->slamming = 0; s->dead = 0; s->angry = 0; s->invuln = 0; s->jumptimer = 0; s->bullet = NULL; s->owner = NULL; s->willbecome = P_CHEESE; switch (s->id) { case P_BEE: case P_CLOUD: s->flies = B_TRUE; break; default: s->flies = B_FALSE; break; } s->score = getpoints(s->id); s->caughtby = NULL; s->caughtstate = 0; 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; 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; if (s->id == P_CLOUD) { s->img = rotozoomSurfaceXY(imageset[id].img[F_WALK1],0,1,1,0); } 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; } 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; tx = pixx / TILEW; ty = pixy / TILEH; if (tilex != NULL) { *tilex = tx; } if (tiley != NULL) { *tiley = ty; } return gettile(curlevel->map[ty*LEVELW+tx]); } int loadtiletypes(char *filename) { 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 ; state = 0; f = fopen(filename,"rt"); if (!f) { printf("can't open tiles file\n"); return B_TRUE; } fgets(buf, BUFLEN, f); while (!feof(f)) { if (state == 0) { if (strstr(buf, "tile") == buf) { if (t == NULL) { tiletype = malloc(sizeof(tiletype_t)); t = tiletype; t->prev = NULL; } else { t->next = malloc(sizeof(tiletype_t)); t->next->prev = t; t = t->next; } p = strtok(buf, " "); p = strtok(NULL, " "); /* strip newline */ p[strlen(p)-1] = '\0'; strcpy(t->name, p); /* defaults */ strcpy(dirname, "."); t->id = 0; t->animspeed = 0; // not animated t->numframes = 1; // not animated 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, "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; } strcpy(imagefile, dirname); strcat(imagefile, "/"); strcat(imagefile, p); 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; 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/pdwarf.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"); imageset[P_PLAYER].numimages = 16; loadspriteimage(P_SNAKE,F_WALK1, "sprites/snake.bmp"); loadspriteimage(P_SNAKE,F_JUMP, "sprites/snakejump.bmp"); loadspriteimage(P_SNAKE,F_FALL, "sprites/snakejump.bmp"); loadspriteimage(P_SNAKE,F_CAUGHT, "sprites/snakecaught.bmp"); loadspriteimage(P_SNAKE,F_DEAD, "sprites/snakedead.bmp"); /* next 3 are auto generated */ imageset[P_SNAKE].numimages = 8; loadspriteimage(P_RAT,F_WALK1, "sprites/rat.bmp"); loadspriteimage(P_RAT,F_JUMP, "sprites/ratjump.bmp"); loadspriteimage(P_RAT,F_FALL, "sprites/ratjump.bmp"); loadspriteimage(P_RAT,F_CAUGHT, "sprites/ratcaught.bmp"); loadspriteimage(P_RAT,F_DEAD, "sprites/ratdead.bmp"); /* next 3 are auto generated */ imageset[P_RAT].numimages = 8; loadspriteimage(P_BEE,F_WALK1, "sprites/bee.bmp"); loadspriteimage(P_BEE,F_JUMP, "sprites/beejump.bmp"); loadspriteimage(P_BEE,F_FALL, "sprites/beejump.bmp"); loadspriteimage(P_BEE,F_CAUGHT, "sprites/beecaught.bmp"); loadspriteimage(P_BEE,F_DEAD, "sprites/beedead.bmp"); /* next 3 are auto generated */ imageset[P_BEE].numimages = 8; loadspriteimage(P_SPIDER,F_WALK1, "sprites/spider.bmp"); loadspriteimage(P_SPIDER,F_JUMP, "sprites/spiderjump.bmp"); loadspriteimage(P_SPIDER,F_FALL, "sprites/spiderfall.bmp"); loadspriteimage(P_SPIDER,F_CAUGHT, "sprites/spidercaught.bmp"); loadspriteimage(P_SPIDER,F_DEAD, "sprites/spiderdead.bmp"); /* next 3 are auto generated */ imageset[P_SPIDER].numimages = 8; loadspriteimage(P_CLOUD,F_WALK1, "sprites/cloud.bmp"); loadspriteimage(P_CLOUD,F_JUMP, "sprites/cloud.bmp"); loadspriteimage(P_CLOUD,F_FALL, "sprites/cloud.bmp"); loadspriteimage(P_CLOUD,F_CAUGHT, "sprites/cloud.bmp"); loadspriteimage(P_CLOUD,F_DEAD, "sprites/cloud.bmp"); imageset[P_CLOUD].numimages = 2; loadspriteimage(P_COKE,F_WALK1, "sprites/coke.png"); loadspriteimage(P_COKE,F_JUMP, "sprites/cokejump.png"); loadspriteimage(P_COKE,F_FALL, "sprites/cokejump.png"); loadspriteimage(P_COKE,F_CAUGHT, "sprites/cokecaught.png"); loadspriteimage(P_COKE,F_DEAD, "sprites/cokedead.png"); imageset[P_COKE].numimages = 8; /* fruits / powerups */ loadspriteimage(P_CHEESE,F_WALK1, "sprites/cheese.bmp"); imageset[P_CHEESE].numimages = 1; loadspriteimage(P_ICECREAM,F_WALK1, "sprites/icecream.bmp"); imageset[P_ICECREAM].numimages = 1; loadspriteimage(P_CHIPS,F_WALK1, "sprites/chips.bmp"); imageset[P_CHIPS].numimages = 1; loadspriteimage(P_BURGER,F_WALK1, "sprites/burger.bmp"); imageset[P_BURGER].numimages = 1; loadspriteimage(P_SPEED,F_WALK1, "sprites/speed.bmp"); imageset[P_SPEED].numimages = 1; loadspriteimage(P_NUMNETS,F_WALK1, "sprites/numnets.bmp"); imageset[P_NUMNETS].numimages = 1; loadspriteimage(P_BIGNET,F_WALK1, "sprites/bignet.bmp"); imageset[P_BIGNET].numimages = 1; loadspriteimage(P_HELP,F_WALK1, "sprites/help.bmp"); imageset[P_HELP].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; 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; 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; /* bullets */ loadspriteimage(P_SPIT,F_WALK1, "sprites/spit.bmp"); imageset[P_SPIT].numimages = 1; /* generate rotated/flipped images */ for (p = 0; p < MAXPTYPES; p++) { /* rotated */ // TODO: need to free tempimg ? */ if (!isfruit(p) && !isbullet(p) && !iseffect(p)) { tempimg = rotozoomSurface(imageset[p].img[F_DEAD],90,1,0); imageset[p].img[F_DEAD2] = SDL_DisplayFormat(tempimg); tempimg = rotozoomSurface(imageset[p].img[F_DEAD],180,1,0); imageset[p].img[F_DEAD3] = SDL_DisplayFormat(tempimg); tempimg = rotozoomSurface(imageset[p].img[F_DEAD],270,1,0); imageset[p].img[F_DEAD4] = SDL_DisplayFormat(tempimg); } for (i = 0; i < imageset[p].numimages; i++) { SDL_Surface *origi; 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_MapRGB(screen->format, 0, 0, 0)); /* 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*2+i] = rotozoomSurfaceXY(origi, 0, 1,1,0); SDL_BlitSurface(reds, NULL, imageset[p].img[MAXFRAMES*2+i], NULL); SDL_FreeSurface(reds); temps = SDL_DisplayFormat(imageset[p].img[MAXFRAMES*2+i]); SDL_FreeSurface(imageset[p].img[MAXFRAMES*2+i]); imageset[p].img[MAXFRAMES*2+i] = temps; SDL_SetColorKey(imageset[p].img[MAXFRAMES*2+i], SDL_SRCCOLORKEY, SDL_MapRGB(imageset[p].img[MAXFRAMES*2+i]->format, 101, 0, 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; if ((s == player) && (levelcomplete == LV_NEXTLEV)) { frame = F_SHOOT; } else { /* select frame */ if (isfruit(s->id)) { frame = F_WALK1; } else if (isbullet(s->id)) { frame = F_WALK1; } else if (iseffect(s->id)) { if (s->id == P_PUFF) { if (s->timer1 >= PUFFFRAMES) { frame = PUFFFRAMES-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->dead) { if (s == player) { frame = F_DEAD; } else { frame = F_DEAD + ((timer/2) % 4); } } else if (s->caughtby) { frame = F_CAUGHT; } else if (s->climbing) { frame = F_CLIMB1 + ((timer/12) % 2); } else if (s->netting) { frame = F_SHOOT; } else if (s->jumping) { frame = F_JUMP; } else if (s->falling) { 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 { if (s->moved) { if ((timer/12) % 2 == 0) { frame = F_WALK1; } else { frame = F_JUMP; } } else { frame = F_WALK1; } } } } /* x-flip if required */ if (s->dir == -1) { frame += MAXFRAMES; } /* make red if required */ if (s->angry) { frame += (MAXFRAMES*2); } if ((s->id != P_CLOUD) && (!s->teleporting)) { s->img = imageset[s->id].img[frame]; } /* spider's climbing web */ if ((s->id == P_SPIDER) && ((s->ys != -99) || s->falling) && (!s->dead) && (!s->caughtby)) { 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; } } drawline16(screen,s->x,s->y - (s->img->h/2),s->x,ty*TILEH+TILEH-1,white); } area.x = s->x - (s->img->w/2); area.y = s->y - (s->img->h); area.w = 0; area.h = 0; if (area.y < (480-s->img->h)) { if (s->invuln) { if (timer % 2 == 0) { SDL_BlitSurface(s->img, NULL, screen, &area); } } else { SDL_BlitSurface(s->img, NULL, screen, &area); /* for opengl */ //SDL_UpdateRect(screen, area.x, area.y, area.w, area.h); } } /* caughtby lines */ if ((s->caughtby) && (s->caughtstate == 2)){ drawline16(screen, s->x,s->y - s->img->h, s->caughtby->x,s->caughtby->y-(s->caughtby->img->h/2), white); drawline16(screen, s->x,s->y - (s->img->h/2), s->caughtby->x,s->caughtby->y-(s->caughtby->img->h/2), white); drawline16(screen, s->x,s->y, s->caughtby->x,s->caughtby->y-(s->caughtby->img->h/2), white); } } void killsprite(sprite_t *s) { sprite_t *nextone, *lastone; sprite_t *s2; /* 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; } } 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_GL_SwapBuffers(); SDL_UpdateRect(screen,0,0,screen->w,screen->h); #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 isflower(int id) { switch (id) { case P_FLOWERRED: case P_FLOWERYELLOW: case P_FLOWERPURPLE: 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_DIAMOND: /* normal powerups */ case P_SPEED: case P_NUMNETS: case P_BIGNET: case P_HELP: /* random powerups */ case P_BOXING: case P_FTODIAMOND: case P_FTOGEM: /* flowers */ case P_FLOWERYELLOW: case P_FLOWERRED: case P_FLOWERPURPLE: /* gems */ case P_GEMYELLOW: case P_GEMRED: case P_GEMPURPLE: return B_TRUE; } return B_FALSE; } int isbullet(int id) { if (id == P_SPIT) return B_TRUE; return B_FALSE; } int iseffect(int id) { if (id == P_PUFF) return B_TRUE; if (id == P_POWERUPPOS) return B_TRUE; if (id == P_GLOVE) return B_TRUE; return B_FALSE; } inline void drawpixel16(SDL_Surface *screen, int x, int y, SDL_Color c) { Uint16 *bufp; /* check x/y */ if (x >= screen->w) return; if (y >= screen->h) return; if (x < 0) return; if (y < 0) return; bufp = (Uint16 *)screen->pixels + (y*screen->pitch / 2) + x; *bufp = SDL_MapRGB(screen->format, c.r, c.g, c.b); } void drawline16(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color c) { int deltax, deltay; int numpixels; int d; int dinc1,dinc2,xinc1,xinc2,yinc1,yinc2; int i; int x; int y; int maskcount = 0; int maskindex = 0; deltax = (x2 - x1); if (deltax < 0) deltax = -deltax; deltay = (y2 - y1); if (deltay < 0) deltay = -deltay; if (deltax >= deltay) { numpixels = deltax + 1; d = (deltay*2) - deltax; dinc1 = deltay << 1; dinc2 = (deltay-deltax) << 1; xinc1 = 1; xinc2 = 1; yinc1 = 0; yinc2 = 1; } else { numpixels = deltay + 1; d = (deltax*2) - deltay; dinc1 = deltax << 1; dinc2 = (deltax - deltay) << 1; xinc1 = 0; xinc2 = 1; yinc1 = 1; yinc2 = 1; } if (x1 > x2) { xinc1 = - xinc1; xinc2 = - xinc2; } if (y1 > y2) { yinc1 = - yinc1; yinc2 = - yinc2; } x = x1; y = y1; maskcount = 0; maskindex = 0; for (i = 0; i < numpixels; i++) { drawpixel16(screen,x,y,c); if (d < 0) { d += dinc1; x += xinc1; y += yinc1; } else { d += dinc2; x += xinc2; y += yinc2; } } } void drawbox16(SDL_Surface *screen, int x1, int y1, int x2, int y2, SDL_Color *c, SDL_Color *fc) { if (fc != NULL) { /* fill */ if (((x2 - x1) >= 2) && ((y2 - y1) >= 2)) { int y; for (y = (y1+1) ; y <= (y2-1); y++) { drawline16(screen, x1+1, y, x2-1,y,*fc); } } } drawline16(screen,x1,y1,x2,y1,*c); drawline16(screen,x1,y1,x1,y2,*c); drawline16(screen,x1,y2,x2,y2,*c); drawline16(screen,x2,y1,x2,y2,*c); } 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; } int chartomonster(char ch) { switch (ch) { case 'c': return P_CLOUD; case 'r': return P_RAT; case 'S': return P_SNAKE; case 'a': return P_BEE; case 's': return P_SPIDER; case '?': return P_HELP; case '1': return P_PLAYER; case '@': return P_FLOWERRED; case 'Y': return P_FLOWERYELLOW; case 'P': return P_FLOWERPURPLE; case 'C': return P_COKE; case '*': return P_GEMRED; case '!': return P_POWERUPPOS; } return -1; } char monstertochar(int id ) { switch (id) { case P_CLOUD: return 'c'; case P_RAT: return 'r'; case P_SNAKE: return 'S'; case P_BEE: return 'a'; case P_SPIDER: return 's'; case P_HELP: return '?'; case P_PLAYER: return '1'; case P_FLOWERRED: return '@'; case P_FLOWERYELLOW: return 'Y'; case P_FLOWERPURPLE: return 'P'; case P_COKE: return 'C'; case P_GEMRED: return '*'; case P_POWERUPPOS: return '!'; } return '\0'; } tiletype_t *gettile(int tid) { tiletype_t *t; for (t = tiletype; t ; t = t->next) { if (t->uniqid == tid) return t; } return &fakeblock; } 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 = 0; area.h = 0; /* draw blank tile first */ tt = gettile(curlevel->bgtileid); SDL_BlitSurface(tt->img[0], NULL, 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); } } 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; 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; } SDL_Surface *loadspriteimage(int spriteid, int frame, char *filename) { imageset[spriteid].img[frame] = IMG_Load(filename); if (imageset[spriteid].img[frame] == NULL) { printf("Error loading image file: %s\n",filename); exit(1); } return imageset[spriteid].img[frame]; } int candoslopes(int sid) { switch(sid) { case P_SNAKE: return B_FALSE; } return B_TRUE; } int ismonster(int id) { if (id == P_RAT) return B_TRUE; if (id == P_BEE) return B_TRUE; if (id == P_SPIDER) return B_TRUE; if (id == P_SNAKE) return B_TRUE; if (id == P_CLOUD) return B_TRUE; if (id == P_COKE) return B_TRUE; 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 = 100; break; case P_ICECREAM: points = 200; break; case P_CHIPS: points = 300; break; case P_BURGER: points = 400; break; case P_DIAMOND: points = 500; 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; }