#include #include #include #include #include #include #include #include #ifdef WINDOWS #include #else #include #include #include #endif #include #include #include #include #include #include #include #include "shared.h" #include "rc.h" FPSmanager manager; SDL_Surface *temps; SDL_Surface *screen; SDL_Surface *credittext; int lockcredits = B_FALSE; int globtimer; int autoshot = B_FALSE; int shottaken = B_FALSE; int introstate; TTF_Font *font[MAXLETTERHEIGHT]; char hiscoreserver[BUFLEN]; int hiscoreport; hiscore_t hiscore[MAXHISCORES]; int numhiscores; int wanthiscores; int gothiscore = -1; int gothiscore2 = -1; int joytest = B_FALSE; int havejoysticks; int joybuttons[2]; const char *joyname[2]; int joytype[2]; int joyanalog[2]; int joythresh[2]; SDL_Joystick *joy[2]; Uint8 *keys; int joyx[2],joyy[2],joybut[2][MAXJOYBUTTONS], joymap[MAXJOYBUTTONS]; Mix_Music *curmusic = NULL; // pointer to currently playing music char tempm[BUFLEN]; // used to remember old level if we flood it int savemap[LEVELW*LEVELH]; int watertime; double gunorigx[2]; double gunorigy[2]; int gundelay[2]; int guntime; int cameraalpha; int playedbell; int clocktime; int gameovertime; int sprayalpha; // for spray effect regrow_t regrow[MAXREGROW]; // for tile regrowth int numregrow = 0; int gameover; int firstlevel; SDL_Surface *pausedtext, *pausedshadow; int paused; int wantframerate = B_FALSE; int fps; int fpscount; int titlemode; int blinkspeed; int credits = 0; int titledone; int forcegold = B_FALSE; int forcegoldlev = -1; int skiplevels; int force1up = B_FALSE; int force2up = B_FALSE; /* the order in which fruit will appear */ int fruittypes[] = { P_CHEESE, P_ICECREAM, P_CHIPS, P_BURGER, P_PIZZA, P_SUNDAE, P_CAKE, P_CHOCOLATE, -1 }; /* the order in which powerups will appear */ int poweruptypes[] = { P_NUMNETS, P_BIGNET, P_BELL, P_NUMNETS, P_GEMBOOST, P_MASKPOWERUP, P_HONEY, P_NUMNETS, P_GEMBOOST, P_HELMET, P_UMBRELLA, P_WINGBOOTS, -1 }; int fruittime = -1; int curfruittype = 0; int curpoweruptype[2]; int gtime = 0; int fpsticks = 0; int fpsstart = 0; int skipto = -1; // which level to skip to level_t *curlevel; int levelcompletetime; int oldlevelcomplete; sprite_t *sprite = NULL; /* main sprite list */ sprite_t *lastsprite; sprite_t *lastmet; int pokereffect; int pokerpoints; SDL_Color red = {255, 0, 0, 0}; SDL_Color red2 = {150, 0, 0, 0}; SDL_Color red3 = {90, 0, 0, 0}; SDL_Color orange = {255, 167, 88, 1}; SDL_Color black = {0, 0, 0, 0}; SDL_Color blue = {0, 0, 255, 0}; SDL_Color cyan = {0, 255, 255, 0}; SDL_Color purple = {200, 0, 200, 0}; SDL_Color brown = {166, 97, 7, 0}; SDL_Color brown2 = {116, 47, 0, 0}; SDL_Color white = {255, 255, 255, 0}; SDL_Color grey = {210, 210, 210, 0}; SDL_Color grey2 = {90, 90, 90, 0}; SDL_Color green = {0, 255, 0, 0}; SDL_Color green2 = {0, 150, 0, 0}; SDL_Color yellow = {255, 255, 0, 0}; SDL_Color greenish = {82, 125, 74, 0}; int vidargs = 0; int fullscreen = B_FALSE; int timer = 0; int toggletimer = 0; int main (int argc, char **argv) { //sprite_t *s,*nextsprite; char filename[BUFLEN]; int i; int *animtile,*l3tile; levelbg = NULL; datadir = NULL; // default sprintf(hiscoreserver, "ratcatcher.nethack.net"); hiscoreport = 80; // set program name (including version string) sprintf(progname, "Rat Catcher v0.%d", REV); /* handle arguments */ if (argc >= 2) { for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-fs")) { printf("Fullscreen mode enabled.\n"); fullscreen = B_TRUE; } else if (!strcmp(argv[i], "-v")) { printf("%s\n",progname); exit(1); } else if (!strcmp(argv[i], "-d")) { if (++i >= argc) { printf("Missing data dir.\n"); usage(); exit(1); } datadir = strdup(argv[i]); } else if (!strcmp(argv[i], "-c")) { printf("Cheat mode.\n"); cheat = B_TRUE; } else if (!strcmp(argv[i], "-as")) { printf("Automatic screenshot mode activated.\n"); autoshot = B_TRUE; } else if (!strcmp(argv[i], "-l")) { if (++i >= argc) { printf("Missing level number.\n"); usage(); exit(1); } skipto = atoi(argv[i]); printf("Skipping to level %d.\n",skipto); } else if (!strcmp(argv[i], "-1")) { printf("1up added.\n"); force1up = B_TRUE; } else if (!strcmp(argv[i], "-2")) { printf("2up added.\n"); force2up = B_TRUE; } else if (!strcmp(argv[i], "-jt")) { printf("Joystick test mode enabled.\n"); joytest = B_TRUE; } else if (!strcmp(argv[i], "-hs")) { if (++i >= argc) { printf("Missing hiscore server name.\n"); usage(); exit(1); } if (strstr(argv[i], ":")) { char *p,*p2; // use port as well p2 = hiscoreserver; for (p = argv[i];p; p++) { if (*p == ':') { p++; break; } else { *p2 = *p; } p2++; } *p2 = '\0'; hiscoreport = atoi(p); printf("Hiscore server set to '%s'\n",hiscoreserver); printf("Hiscore port set to '%d'\n",hiscoreport); } else { sprintf(hiscoreserver, "%s",argv[i]); printf("Hiscore server set to '%s'\n",hiscoreserver); } } else if (!strcmp(argv[i], "-hp")) { if (++i >= argc) { printf("Missing hiscore port.\n"); usage(); exit(1); } hiscoreport = atoi(argv[i]); printf("Hiscore port set to '%d'\n",hiscoreport); } else { usage(); exit(1); } } } if (datadir == NULL) { datadir = strdup("data"); } initsdl(); if (TTF_Init()) { printf("TTF_Init: %s\n", TTF_GetError()); } atexit(cleanup); if (joytest) { if (havejoysticks) { int done = B_FALSE; SDL_Event event; printf("Joystick test mode\n"); printf("------------------\n\n"); while (!done) { /* check for key releases */ SDL_PumpEvents(); while (SDL_PollEvent(&event)) { if (event.type == SDL_KEYDOWN) { if (event.key.keysym.sym == SDLK_ESCAPE) { done = B_TRUE; } } else if (event.type == SDL_JOYBUTTONUP) { printf("Joy %d: Button %d pressed.\n",event.jbutton.which, event.jbutton.button); } else if (event.type == SDL_JOYAXISMOTION) { int j,jx,jy; j = event.jaxis.which; jx = SDL_JoystickGetAxis(joy[j],0); jy = SDL_JoystickGetAxis(joy[j],1); printf("Joy %d: Moved ",j); if (jy <= -6000) printf("UP\n"); if (jy >= 6000) printf("DOWN\n"); if (jx <= -6000) printf("LEFT\n"); if (jx >= 6000) printf("RIGHT\n"); } } } } else { printf("ERROR: no joysticks found.\n"); } return 0; } if (loadimagesets()) { printf("Error loading images.\n"); return 1; } if (loadlevellist()) { printf("Error loading level list from %s.\n",FILE_LEVELMAP); return 1; } /* fakeblock.id = T_LAND; strcpy(fakeblock.name,"Fake"); for (i = 0; i < TILEW; i++) { fakeblock.lowness[i] = 0; } fakeblock.solid = S_SOLID; fakeblock.img[0] = IMG_Load("newtiles/land.png"); fakeblock.numframes = 1; fakeblock.next = NULL; fakeblock.prev = NULL; */ /* load fonts */ sprintf(filename, "%s/gamefont.ttf",datadir); for (i = 1; i < MAXLETTERHEIGHT; i++) { SDL_Surface *surf; font[i] = TTF_OpenFont(filename,i); if (!font[i]) { printf("Error opening font: %s\n", TTF_GetError()); return 1; } surf = TTF_RenderText_Solid(font[i], "test", red); if (!surf) { printf("Error during font test, size %d\n",i); return 1; } SDL_FreeSurface(surf); } /* calculate fps delay */ SDL_initFramerate(&manager); SDL_setFramerate(&manager, WANTFPS); /* init sound */ if (initsound()) { printf("sound error.\n"); return 1; } /* init tiles */ if (loadtiletypes(FILE_TILEDEFS)) { printf("Cannot initialise tiles\n"); exit(1); } /* generate images for "PAUSED" text */ pausedtext = TTF_RenderText_Solid(font[TEXTSIZE_PAUSED], "PAUSED", yellow); pausedshadow = TTF_RenderText_Solid(font[TEXTSIZE_PAUSED], "PAUSED", black); paused = B_FALSE; gamemode = GM_NORM; // default showhelp = B_FALSE; // default // try to get hiscores printf("Attepting to download hiscores from %s:%d...\n",hiscoreserver,hiscoreport); fflush(stdout); if (gethiscores(B_FALSE)) { printf("Couldn't download hiscores. Disabling hiscore code.\n"); wanthiscores = B_FALSE; } else { printf("Hiscores successfully downloaded.\n"); wanthiscores = B_TRUE; } // outside loop while (1) { // title screen if (skipto <= 0) { dotitlescreen(); srand(time(NULL)); } else { // skipping to a level from command line if (force1up) want1up = B_TRUE; if (force2up) want2up = B_TRUE; if (!want1up && !want2up) { // must have at least 1 player!! want1up = B_TRUE; } } // shuffle cards shufflecards(); startgame(); // main loop while (!gameover) { removeall(); // check for sprite death and update moevment counters checksprites(); /********************************************** * check for end of level */ if (levelcomplete == LV_CLEAR) { sprite_t *s2, *nexts; addoutlinetext(320,240,TEXTSIZE_LEVEL,"Level Complete!",&green,&black,LEVELWINDELAY, TT_NORM); levelcomplete = LV_WAIT; playfx(FX_WINLEVEL); // turn off certain powerups if (globpowerup == PW_CLOCK) { Mix_ResumeMusic(); globpowerup = -1; } else if (globpowerup == PW_LAMP) { Mix_ResumeMusic(); globpowerup = -1; } else if ((curlevel->iced == WATER_INPROGRESS) || (curlevel->iced == WATER_COMPLETE)) { curlevel->iced = B_FALSE; undoflood(); } else if (haspowerupany(PW_GUNNER)) { disablepowerups(PW_GUNNER); } // certain things disappear at end of level for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (iscard(s2->id) || s2->id == P_MOVINGCARD) { // kill all cards, so we don't have a pokereffect during endoflevel s2->dead = D_FINAL; } else if (strstr(s2->name, "random_up")) { // also kill the random level powerup if it exists s2->dead = D_FINAL; puffin(-1, s2->x, s2->y, "end_of_lev_pw_die", 0); } else if (isflower(s2->id)) { // also kill flowers s2->dead = D_FINAL; puffin(-1, s2->x, s2->y, "end_of_lev_fl_die", 0); } } // stop teleporting if (player) { if (player->teleporting) { stopteleporting(player); } } if (player2) { if (player2->teleporting) { stopteleporting(player2); } } } else if (levelcomplete == LV_WAIT) { int mcount = 0; sprite_t *s2; /* when all monsters have become fruits */ for (s2 = sprite; s2 ; s2 = s2->next) { if (ismonster(s2->id)) { if (s2->id != P_BLACKCLOUD) { mcount++; break; } } } if (mcount == 0) { levelcompletetime = gtime; levelcomplete = LV_FINAL; } } /********************************************** * check for keypress or other input (joystick etc) */ handleinput(); if (!paused) { /********************************************** * Special effects #1 - ones which change the level by * modifiying tiles, etc, or by moving sprites. */ if (globpowerup != PW_CLOCK) { // for each animated tile on the level... for (animtile = curlevel->animtiles; animtile && *animtile != -1; animtile++) { int offset,numframes; tiletype_t *tt; offset = *animtile; // Is l2 tile animated? tt = gettile(curlevel->map2[offset]); if (tt->numframes == 1) { // if no l2, use l1 tt = gettile(curlevel->map[offset]); } numframes = tt->numframes; // is it time to change frames? if ((timer % tt->animspeed) == 0) { // change its frame curlevel->tileframe[offset]++; if (curlevel->tileframe[offset] >= numframes) { curlevel->tileframe[offset] = 0; } // redraw it drawtile(temps, offset%LEVELW,offset/LEVELW); } } // ice effect if (curlevel->iced == ICE_INPROGRESS) { doice(); } // water effect if (timer % FLOODSPEED == 0) { if (curlevel->iced == WATER_INPROGRESS) { doflood(); } } } // gunner effect - red overlay if (haspowerupany(PW_GUNNER)) { if (levelcomplete != LV_DOPOKER) { SDL_BlitSurface(redbox,NULL,screen,NULL); } if (uncaughtmonsters() <= 0) { // finish if no monsters are left alive & uncaught disablepowerups(PW_GUNNER); } } /********************************************** * Move sprites */ if (levelcomplete == LV_DOPOKER) { // only fivecards sprite can move sprite_t *this; for (this = sprite; this ; this = this->next) { if (this->id == P_FIVECARDS) { movesprite(this); } } } else { // all other states... if (levelcomplete != LV_HELPFREEZE) { // move sprites moveallsprites(); } } /********************************************** * Intro sequence */ if (inintro()) { dointroseq(); } /********************************************** * Move onscreen text */ if (levelcomplete != LV_HELPFREEZE) { movetext(); } /********************************************** * Gravity */ if (levelcomplete == LV_INIT) { // only player dogravity(player); checkwrap(player); dotileeffects(player); if (player2) { dogravity(player2); checkwrap(player2); dotileeffects(player2); } } else { sprite_t *s; switch (levelcomplete) { case LV_INPROGRESS: case LV_CLEAR: case LV_WAIT: case LV_FINAL: case LV_CLOUD: /* gravity */ for (s = sprite ; s ; s = s->next) { dogravity(s); checkwrap(s); } /* tile effects */ for (s = sprite ; s ; s = s->next) { if (levelcomplete == LV_CLOUD) { if (isplayer(s)) { if (!s->oncloud) dotileeffects(s); } else { dotileeffects(s); } } else { dotileeffects(s); } } break; case LV_GAMEOVER: // no collision detection or player movement /* gravity */ for (s = sprite; s ; s = s->next) { if (!isplayer(s)) { dogravity(s); checkwrap(s); } } break; case LV_DOPOKER: // do nothing case LV_HELPFREEZE: // do nothing break; } } /********************************************** * Special effects #2 - ones which need to happen * after sprite movement */ if ((player && player->hasbell) || (player2 && player2->hasbell)) { int dobell = B_FALSE; SDL_Color fcol; /* check for bell sound */ /* play a bell sound if the powerup will be a permenant one */ if (ispermenant(level->poweruptype)) { // flash white dobell = B_TRUE; fcol.r = 255; fcol.g = 255; ; fcol.b = 255; } else if (isabilitypowerup(level->poweruptype)) { // flash green dobell = B_TRUE; fcol.r = 0; fcol.g = 255; ; fcol.b = 0; } else if (iswinpowerup(level->poweruptype)) { // flash red dobell = B_TRUE; fcol.r = 255; fcol.g = 0; ; fcol.b = 0; } else if (isbadpowerup(level->poweruptype)) { // flash purple dobell = B_TRUE; fcol.r = 255; fcol.g = 0; ; fcol.b = 255; } if (dobell) { // play sound once if (!playedbell) { playfx(FX_BELL); playedbell = BELL_DONESOUND; } if (playedbell != BELL_DONEFLASH) { if (timer >= BELLTIME) { playedbell = BELL_DONEFLASH; } else if (timer % 10 == 0) { SDL_Rect area; area.x = 0; area.y = 0; area.w = 640; area.h = 480; SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,fcol.r,fcol.g,fcol.b)); flip(); } } } } // camera flash if ((globpowerup == PW_CAMERA) && (cameraalpha)) { SDL_Surface *whitebox; whitebox = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, 0); SDL_FillRect(whitebox, NULL, SDL_MapRGB(screen->format,255,255,255)); SDL_SetAlpha(whitebox, SDL_SRCALPHA, cameraalpha); // clear screen SDL_BlitSurface(whitebox,NULL,screen,NULL); SDL_FreeSurface(whitebox); if (timer % 10 == 0) { cameraalpha -= 35; if (cameraalpha < 0) cameraalpha = 0; } } /********************************************** * Collision detection */ if ((levelcomplete != LV_DOPOKER) && (levelcomplete != LV_HELPFREEZE)) { checkcollideall(); } } /********************************************** * Drawing routines */ // player netting if (levelcomplete != LV_DOPOKER) { drawnetting(player); drawnetting(player2); } // cannon firing if ((levelcomplete != LV_DOPOKER) && (levelcomplete != LV_HELPFREEZE)) { // cannon firing if (haspowerup(player, PW_CANNONFIRE)) { docannoneffect(player); } if (haspowerup(player2, PW_CANNONFIRE)) { docannoneffect(player2); } } // draw sprites if (levelcomplete != LV_DOPOKER) { drawallsprites(); } /// draw layer 3 tiles // for each layer 3 tile on the level... for (l3tile = curlevel->l3tiles; l3tile && *l3tile != -1; l3tile++) { int offset; tiletype_t *tt; offset = *l3tile; tt = gettile(curlevel->map3[offset]); // redraw it drawl3tile(screen, offset%LEVELW,offset/LEVELW); } // warning for cloud if (!isbosslevel(curlevelnum)) { if ((gtime >= nexthurryup + 10) && (gtime < nexthurryup+15)) { // 15 secs after hurryup if (levelcomplete == LV_INPROGRESS) { if (timer % 4 == 0) { // add puffs puffin(-1, 320 + (rand() % (TILEW*4)) - (TILEW*2), 240 + (rand() % (TILEH*2)) - TILEH, "cloudwarn", rand() % 5); } } } } // poker effect // this must come last as it clears the screen and blanks out other sprites if (levelcomplete == LV_DOPOKER) { SDL_Rect area; sprite_t *this; area.x = 0; area.y = 0; area.w = 640; area.h = 480; // clear screen SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b)); // only fivecards sprite is drawn for (this = sprite; this ; this = this->next) { if (this->id == P_FIVECARDS) { drawsprite(this); } } } else if (levelcomplete == LV_HELPFREEZE) { SDL_Rect area; SDL_Surface *blackbox; blackbox = SDL_CreateRGBSurface(SDL_SWSURFACE, screen->w, screen->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, 0); SDL_FillRect(blackbox, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b)); SDL_SetAlpha(blackbox, SDL_SRCALPHA, 175); // clear screen SDL_BlitSurface(blackbox,NULL,screen,NULL); SDL_FreeSurface(blackbox); } // draw text drawtext(); if (!inintro()) { // draw score drawscore(); } // draw boss health if (boss) { drawbosshealth(); } // draw 'PAUSED' text if (paused) { SDL_Rect area; // show that we are paused area.x = (640/2) - (pausedshadow->w/2) - 2; area.y = (480/2) - (pausedshadow->h/2) + 2; area.w = 0; area.h = 0; SDL_BlitSurface(pausedshadow, NULL, screen, &area); area.x = (640/2) - (pausedtext->w/2); area.y = (480/2) - (pausedtext->h/2); area.w = 0; area.h = 0; SDL_BlitSurface(pausedtext, NULL, screen, &area); } /********************************************** * Special effects #3 - ones which need to happen * after graphics drawing */ if (!paused) { /* is screen shaking? */ if (globpowerup == PW_BOMB) { if (timer % 5 == 0) { int amt; SDL_Rect area; amt = (rand() % 20)+1; area.x = 0; area.y = amt; area.w = 640; area.h = 480-amt; SDL_BlitSurface(screen, &area, screen, NULL); area.x = 0; area.y = 480-amt; area.w = 640; area.h = amt; SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b)); } if (--globtimer == 0) { globpowerup = -1; } } else if (globpowerup == PW_SPRAYUP) { // green overlay for fly spray if (levelcomplete != LV_DOPOKER) { SDL_SetAlpha(greenbox, SDL_SRCALPHA, sprayalpha); sprayalpha += 5; if (sprayalpha >= 100) { globpowerup = PW_SPRAYDOWN; } SDL_BlitSurface(greenbox,NULL,screen,NULL); } } else if (globpowerup == PW_SPRAYDOWN) { // green overlay for fly spray if (levelcomplete != LV_DOPOKER) { SDL_SetAlpha(greenbox, SDL_SRCALPHA, sprayalpha); sprayalpha -= 5; if (sprayalpha <= 0) { globpowerup = PW_SPRAYUP; } SDL_BlitSurface(greenbox,NULL,screen,NULL); } } else if (globpowerup == PW_RATSHAKE) { // horizontal shake due to rat // shake screen if (timer % 5 == 0) { int amt; SDL_Rect area; amt = (rand() % 20)+1; area.x = amt; area.y = 0; area.w = 640-amt; area.h = 480; SDL_BlitSurface(screen, &area, screen, NULL); area.x = 640-amt; area.y = 0; area.w = amt; area.h = 480; SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b)); } // create rat if (timer % 10 == 0) { if (countmonsters(-1) < 8) { // max 7 rats + king rat puffin(P_RAT, rand() % (640-(TILEW*8))+(TILEW*4), TILEH, "gen_rat",0); } } if (--globtimer == 0) { globpowerup = -1; } } else if (globpowerup == PW_SNAILSHAKE) { // vertical shake due to king snail // shake screen if (timer % 5 == 0) { int amt; SDL_Rect area; amt = (rand() % 20)+1; // offset screen upwards area.x = 0; area.y = amt; area.w = 640; area.h = 480-amt; SDL_BlitSurface(screen, &area, screen, NULL); // fill in empty bit area.x = 0; area.y = 480-amt; area.w = 640; area.h = amt; SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b)); } if (--globtimer == 0) { globpowerup = -1; } } } /********************************************** * Update the screen */ flip(); /********************************************** * Timers */ if (!paused) { int n; if (++timer == 100) timer = 0; for (n = 0 ; n < numregrow; n++) { regrow[n].timer--; if (regrow[n].timer <= 0) { int nn,tx,ty; // put original tile back tx = regrow[n].tx; ty = regrow[n].ty; curlevel->map[ty * LEVELW + tx] = regrow[n].origid; drawtile(temps, tx,ty); puffin(-1, tx*TILEW+(TILEW/2), ty*TILEH+TILEH, "nothing", 0); // remove from list for (nn = n ; nn < (numregrow-1); nn++) { regrow[nn].tx = regrow[nn+1].tx; regrow[nn].ty = regrow[nn+1].ty; regrow[nn].origid = regrow[nn+1].origid; regrow[nn].timer = regrow[nn+1].timer; } numregrow--; // do this number again n--; } } } if (toggletimer > 0) toggletimer--; if (haspowerupany(PW_GUNNER)) { int n; // delay between shots for (n = 0; n < 2; n++) { if (gundelay[n] > 0) { gundelay[n]--; } } } // screenshot if (autoshot && (levelcomplete == LV_INPROGRESS)) { if (shottaken) { sprite_t *s2, *nexts; // go to next level // kill all enemies and fruits for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isbullet(s2->id) || ismonster(s2->id) || isfruit(s2->id)) { s2->dead = D_FINAL; if (ismonster(s2->id)) { if (s2->caughtby) { uncatch(s2); } } } } // call in cloud immediately levelcomplete = LV_FINAL; } else { savebmp(screen); shottaken = B_TRUE; } } fpscount++; tick(); } // end main loop // TODO: fade // clear screen SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format,black.r,black.g,black.b)); if (wanthiscores) { // check for a hiscore, if so submit it if (player) checkhiscores(player); if (player2) checkhiscores(player2); // clear screen SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format,black.r,black.g,black.b)); // show high scores showhiscores(); // clear screen ready to start again... SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format,black.r,black.g,black.b)); } } // end outside loop return 0; } void tick(void) { sprite_t *s; if (!paused) { SDL_framerateDelay(&manager); } if (paused) return; if (levelcomplete == LV_HELPFREEZE) return; fpsticks = SDL_GetTicks(); if (fpsstart == 0) { fpsstart = fpsticks; } else { /* once per second */ if (fpsticks - fpsstart >= 1000) { // calculate frames per second fps = fpscount; fpscount = 0; // incremenet game time gtime++; // check for game over - 5 seocnds after game over text disappears if (gameovertime > 0) { if (gtime >= (gameovertime + GAMEOVERWAIT)) { gameover = B_TRUE; } } // handle visual countdown timers if (levelcomplete == LV_INPROGRESS) { // clock if (globpowerup == PW_CLOCK) { char tempm[SMALLBUFLEN]; // text if (clocktime > 0) { sprintf(tempm, "%d",clocktime); addoutlinetext(320,120,TEXTSIZE_LEVEL, tempm, &yellow,&black,15, TT_NORM); // sound effect playfx(FX_CLOCK); } // never reach hurryup time nexthurryup++; // decrement counter clocktime--; if (clocktime < 0) { // finished! Mix_ResumeMusic(); globpowerup = -1; } } // handle flood effect if (curlevel->iced == WATER_COMPLETE) { char tempm[SMALLBUFLEN]; // text if (watertime > 0) { sprintf(tempm, "%d",watertime); addoutlinetext(320,120,TEXTSIZE_LEVEL, tempm, &cyan,&black,15, TT_NORM); } // never reach hurryup time resethurryup(curlevel); // decrement counter watertime--; if (watertime < 0) { // finished! curlevel->iced = B_FALSE; undoflood(); } } // handle gunner effect if (haspowerupany(PW_GUNNER)) { char tempm[SMALLBUFLEN]; // text if (guntime > 0) { sprintf(tempm, "%d",guntime); addoutlinetext(320,120,TEXTSIZE_LEVEL, tempm, &red,&black,15, TT_NORM); } // never reach hurryup time resethurryup(curlevel); // decrement counter guntime--; if (guntime < 0) { // finished! disablepowerups(PW_GUNNER); } } } /* check for hurryup*/ if (!isbosslevel(curlevelnum)) { if ((gtime == nexthurryup) && (curlevel->iced != WATER_COMPLETE)) { if (!levelcomplete) { // all sprites get angry and un-iced for (s = sprite; s; s = s->next) { if (!isplayer(s) && ismonster(s->id) ) { s->angry = B_TRUE; s->iced = B_FALSE; } } // rings are disabled disablepowerups(PW_RINGWALK); disablepowerups(PW_RINGJUMP); addoutlinetext(320,240,TEXTSIZE_HURRY, "Hurry up!", &yellow,&black,HURRYDELAY, TT_NORM); stopmusic(); Mix_PlayChannel(CH_HURRYUP, sfx[FX_HURRYUP], 0); } } else if (gtime == nexthurryup + 15) { // 15 secs after hurryup if (!levelcomplete) { sprite_t *bc,*s2; int found; // does cloud already exist? (could happen if someone // picked up the whistle powerup) for (s2 = sprite; s2 ; s2 = s2->next) { if (s2->id == P_BLACKCLOUD) { found = B_TRUE; break; } } if (!found) { bc = addsprite(P_BLACKCLOUD, 320,240,"cloud"); makeinvuln(bc); } addoutlinetext(320,240,TEXTSIZE_HURRY, "Too slow!", &red,&black,HURRYDELAY, TT_NORM); playfx(FX_TOOSLOW); } } } /* check for random power up */ if ((curlevel->powerupx != -1) && (curlevel->powerupy != -1)) { if (!curlevel->gotpowerup) { if (gtime == curlevel->poweruptime) { if (!levelcomplete) { /* add a random powerup at the right position */ /* the type of powerup is randomly determined when the level is loaded */ /* IMPORTANT: the name 'random_up' is important as it tells addsprite() to give it a higher doomcount */ puffin(level->poweruptype, curlevel->powerupx*TILEW + (TILEW/2), curlevel->powerupy*TILEH + TILEH - 1, "random_up",0); curlevel->gotpowerup = B_TRUE; } } } } /* 5 seconds after level completion */ if (levelcomplete == LV_FINAL) { if (gtime - levelcompletetime >= 5) { if (playersalive()) { sprite_t *newsp; int x,y; levelcomplete = LV_CLOUD; switch (curlevel->exitdir) { case D_RIGHT: default: x = TILEW/2; y = rand() % 480; break; case D_LEFT: x = 640-(TILEW/2); y = rand() % 480; break; case D_UP: x = rand() % 640; y = 480-(TILEW/2); break; case D_DOWN: x = rand() % 640; y = TILEW/2; break; } if (player && player->lives > 0) { newsp = addsprite(P_PINKCLOUD, x, y, "pinkcloud_1"); newsp->timer1 = LV_CLOUD; newsp->owner = player; puffin(-1, x, y, "nothing", 0); } if (player2 && player2->lives > 0) { newsp = addsprite(P_PINKCLOUD, x, y, "pinkcloud_2"); newsp->timer1 = LV_CLOUD; newsp->owner = player2; puffin(-1, x, y, "nothing", 0); } } } } fpsstart = fpsticks; } } } void nextlevel(void) { char msg[SMALLBUFLEN]; sprite_t *cloudp; int x,y; // remove the players if (!firstlevel) { removesprite(player); removesprite(player2); } /* in case we skipped the level due to a powerup etc */ levelcomplete = LV_NEXTLEV; // disable "forcegold" (comes form magic lamp) unless we got // if on this level if (forcegold) { if (forcegoldlev != curlevelnum) { forcegold = B_FALSE; } } /* go to next level */ // this won't trigger on the first load of the intro // becasue curlevelnum is decremented before this function // is called. When the intro ENDs, the next line will // be true. if (curlevelnum == INTRO_LEVELNUM) { curlevelnum = 1; } else { curlevelnum++; } if (!musicplaying || (curmusic == fastmusic)) { if (curlevelnum != INTRO_LEVELNUM) { playmusic(normalmusic); } } // don't want the player flashing while scrolling if (player) player->invuln = 0; if (player2) player2->invuln = 0; // not on a trampoline! if (player) { player->ontramp = B_FALSE; player->trampx = -1; player->trampy = -1; player->oncloud = B_FALSE; } if (player2) { player2->ontramp = B_FALSE; player2->trampx = -1; player2->trampy = -1; player2->oncloud = B_FALSE; } // clear regrowth numregrow = 0; // load next level data if (haspowerupany(PW_PHONE) && !isbosslevel(curlevelnum)) { // don't add monsters loadlevel(curlevelnum, B_FALSE); } else { loadlevel(curlevelnum, B_TRUE); } // remmeber layer 2 in case we replace it with water for (y = 0 ; y < LEVELH; y++) { for (x = 0 ; x < LEVELW; x++) { savemap[y*LEVELW+x] = curlevel->map2[y*LEVELW+x]; } } watertime = -1; fruittime = -1; // do the moving to next level transition (ie. scroll the screen) drawlevel(); // now the player gets invincibility if (!inintro()) { if (!cheat) { makeinvuln(player); makeinvuln(player2); } } // phone is cancelled on boss levels if (haspowerupany(PW_PHONE)) { if (isbosslevel(curlevelnum)) { sprite_t *pp; pp = haspowerupany(PW_PHONE); losepowerup(pp); skiplevels = 0; } } /* reset game stats */ if (haspowerupany(PW_PHONE)) { levelcomplete = LV_CLOUD; } else { levelcomplete = LV_INIT; levelcompletetime = -1; } /* reset level stats */ level->gotpowerup = B_FALSE; // this is based on the max number of monsters killed // simulatneously on the previous level... forcegoodcard = nextforcegoodcard; nextforcegoodcard = B_FALSE; if (isbosslevel(curlevelnum)) { // don't play bell on boss levels playedbell = BELL_DONEFLASH; } else { if ((player && player->hasbell) || (player2 && player2->hasbell)) { playedbell = B_FALSE; } else { playedbell = BELL_DONEFLASH; } } // if this is boss level, play music if (isbosslevel(curlevelnum)) { stopmusic(); playmusic(bossmusic); } else { if (curlevelnum != INTRO_LEVELNUM) { if (curmusic != normalmusic) { stopmusic(); playmusic(normalmusic); } } } level->iced = ICE_NONE; level->icey = -1; if (!inintro()) { sprintf(msg, "Level %d-%d",getcurworld(), getcurlevel()); addoutlinetext(320,240-18,TEXTSIZE_LEVEL,msg,&white,&black,LEVELDELAY, TT_NORM); sprintf(msg, "\"%s\"", curlevel->name); addoutlinetext(320,240+18,TEXTSIZE_LEVEL2,msg,&cyan,&black,LEVELDELAY, TT_NORM); } /* reset player stats */ if (player && player->lives > 0) { player->netting = B_FALSE; player->slamming = B_FALSE; player->jumping = B_FALSE; player->netcaught = 0; // make sure player is at the right position player->x = (curlevel->p1x * TILEW) + (TILEW/2); player->y = (curlevel->p1y * TILEH) + TILEH-2; } if (player2 && player2->lives > 0) { player2->netting = B_FALSE; player2->slamming = B_FALSE; player2->jumping = B_FALSE; player2->netcaught = 0; // make sure player2 is at the right position player2->x = (curlevel->p2x * TILEW) + (TILEW/2); player2->y = (curlevel->p2y * TILEH) + TILEH-2; } // remove powerup, phone is a special case if (haspowerupany(PW_PHONE)) { skiplevels--; if (skiplevels <= 0) { disablepowerups(PW_PHONE); } } else { // lose ALL temp powerups if (player) losepowerup(player); if (player2) losepowerup(player2); } // remove level powerup effect (bomb etc) globpowerup = -1; // add initial fading cloud if (!inintro()) { if (player && player->lives > 0) { cloudp = addsprite(P_PINKCLOUD, player->x,player->y + (imageset[P_PINKCLOUD].img[F_WALK1]->h / 2),"initial_pinkcloud_1"); cloudp->timer1 = levelcomplete; cloudp->size = 1.0; cloudp->owner = player; cloudp->rotated = 0; cloudp->angle = 0; } if (player2 && player2->lives > 0) { cloudp = addsprite(P_PINKCLOUD, player2->x,player2->y + (imageset[P_PINKCLOUD].img[F_WALK1]->h / 2),"initial_pinkcloud_2"); cloudp->timer1 = levelcomplete; cloudp->size = 1.0; cloudp->owner = player2; cloudp->rotated = 0; cloudp->angle = 0; } } if (cheat) { if (player) player->speed = 2; if (player2) player2->speed = 2; } // make players face the correct way if (player) { if (player->x < (640/2)) { player->dir = D_RIGHT; } else { player->dir = D_LEFT; } } if (player2) { if (player2->x < (640/2)) { player2->dir = D_RIGHT; } else { player2->dir = D_LEFT; } } // haven't got a card yet gotcard = B_FALSE; // reset timer timer = 0; if (autoshot) { shottaken = B_FALSE; } } void jump(sprite_t *s, int dir) { // if we've ust been hit with armour, bypass all these checks) if (!s->recoiling) { // can't jump if already jumping if (s->jumping) { // unless we have the doublejump powerup if (!s->doublejump || s->useddoublejump || !s->doublejumpready) { return; } } if (s->jumptimer) return; if (s->doublejump && (s->falling || s->jumping ) && (s->useddoublejump || !s->doublejumpready)) { return; } // can only jump sideways when climbing if (s->climbing && (dir == 0)) { return; } } // check for recoiling here, because we always need to be able to // "jump" backwards, even if already jumping if (s->recoiling || isonground(s) || isinwater(s) || isonladder(s) || s->doublejump) { if (ismonster(s->id) || (s->id == P_KSSHELL)) { if (s->recoiling) { // recoiling monsters don't pause before jumping if (s->id == P_KSSHELL) { s->jumpspeed = 3; s->jumpdir = dir*3; } else { s->jumpspeed = MONJUMPSPEED; s->jumpdir = dir; } s->jumping = 1; s->dir = -s->jumpdir; // face backwards } else { //s->jumpdir = s->dir * getspeed(s); s->jumpdir = dir; if (s->jumpdir != 0) { s->dir = s->jumpdir; } // special case if ((s->id == P_KINGRAT) && (s->timer1 == KRS_CHARGEWAIT)) { // jump right away s->jumpspeed = MONJUMPSPEED; // will be changed later s->jumping = 1; } else if (s->id == P_FROG) { sprite_t *whoabove; whoabove = isplayerabove(s); if (whoabove) { double ydis; ydis = abs(s->y - whoabove->y); if (ydis <= (TILEH*5)) { s->jumpspeed = MONJUMPSPEED; // normal jump } else { s->jumpspeed = FROGJUMPSPEED2; // very high } } else { s->jumpspeed = FROGJUMPSPEED1; // ie not high enough for most platforms } s->jumping = 1; } else { // delay then jump s->jumptimer = getjumpdelay(s->id); s->willjumpspeed = getmonjumpspeed(s); } } } else if (isfruit(s->id)) { s->jumping = 1; s->jumpspeed = 2; s->jumpdir = dir; } else { // player tiletype_t *tt; s->jumpdir = dir; if (s->jumpdir != 0) { s->dir = s->jumpdir; } if (s->doublejump) { if (s->falling || s->jumping) { // we just used up the doublejump s->useddoublejump = B_TRUE; puffin(-1, s->x, s->y, "nothing", 0); } else { // we're jumping off the ground // need to let go of jump before double jumping s->doublejumpready = B_FALSE; } } if ((s->powerup == PW_JETPACK) && (!s->useddoublejump)) { // jetpack makes a blast of fire addsprite(P_SMASH, s->x, s->y, "jet_smash"); addsprite(P_SMASH, s->x+(TILEW/2), s->y, "jet_smash"); addsprite(P_SMASH, s->x-(TILEW/2), s->y, "jet_smash"); // jetpack always adds speed to sideways jumps if (s->jumpdir > 0) { s->jumpdir++; if (!haspowerup(s, P_SPEED) == 1) s->jumpdir++; // go fast even if player is slow } else if (s->jumpdir < 0) { s->jumpdir--; if (!haspowerup(s, P_SPEED) == 1) s->jumpdir--; // go fast even if player is slow } } else { tt= gettileat(s->x, s->y, NULL, NULL); // if on rollers, they add to your inertia // if you are facing their direction if ((tt->id == T_RIGHT) && (s->jumpdir > 0)) { s->jumpdir++; } else if ((tt->id == T_LEFT) && (s->jumpdir < 0)) { s->jumpdir--; } else if (isice(tt->id) && !isinwater(s)) { s->jumpdir = s->xs / getspeed(s); //if (s->jumpdir > getspeed(s)) s->jumpdir -= getspeed(s); //if (s->jumpdir < -getspeed(s)) s->jumpdir += getspeed(s); } } s->jumping = 1; if (s->climbing) { s->jumpspeed = 3; } else if (!s->useddoublejump && (s->powerup == PW_JETPACK) && (s->jumpdir == 0)) { s->jumpspeed = 7; } else if (s->ontramp) { s->jumpspeed = 7; } else { s->jumpspeed = 5; } // Special hidden cheat - jumping on the up sign on level 1 // skips you to level 3 (to avoid boring levels at the start) // Only if you haven't lost a life too! if ((levelcomplete == LV_INPROGRESS) && (!s->lostlife) && (s->jumpdir == 0)) { sprite_t *ss; int found = B_FALSE; // make sure a warp doesn't already exist for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_PHONE) && (strstr(ss->name, "warp"))) { found = B_TRUE; break; } } if (!found) { int tx,ty; tt= gettileat(s->x, s->y - (TILEH/2), &tx, &ty); if (tt->id == T_WARP) { // it disappears curlevel->map[ty*LEVELW+tx] = getuniq(T_WARP); // puff in a telephone puffin(P_PHONE, tx*TILEW + (TILEW/2), ty*TILEH+TILEH, "warpphone", -1); playfx(FX_WARP); } } } } // stop climbing s->climbing = B_FALSE; if (isplayer(s) ) { // stop recoiling if (s->recoiling) { s->recoiling = B_FALSE; } else { // play sound effect if (s->ontramp) { playfx(FX_SPRING); } else if (!s->useddoublejump && (s->powerup == PW_JETPACK)) { playfx(FX_JETPACK); } else { playfx(FX_JUMP); } } } adjustx(s, F_JUMP); } } void die(sprite_t *s) { sprite_t *s2; /* clouds can't die like this */ if (s->id == P_BLACKCLOUD) return; if (s->id == P_PINKCLOUD) return; /* if this is the player, hurryup time counter resets */ // We already do this in the cloud movement routine, but // this handles cases where the cloud hasn't appeared yet. if (isplayer(s)) { // if we have armour, we lose it instead of dying if (s->armour) { // lose armour s->armour = B_FALSE; if (s == player) { s->id = P_PLAYER; } else { s->id = P_PLAYER2; } // become invulnerable temporarily makeinvuln(s); // bounce back s->recoiling = B_TRUE; jump(s, -s->dir); // play sound playfx(FX_OW); // don't process rest of the death code return; } else { int tnum; if (globpowerup == PW_CLOCK) { Mix_ResumeMusic(); } if (globpowerup == PW_LAMP) { sprite_t *s2; Mix_ResumeMusic(); // kill all gold coins for (s2 = sprite; s2 ; s2 = s2->next) { if (s2->id == P_GOLDCOIN) { s2->dead = D_FINAL; puffin(-1, s2->x, s2->y, "gcpuff", rand() % 5); } else if ((s2->id == P_PUFF) && (s2->timer3 == P_GOLDCOIN)) { s2->dead = D_FINAL; puffin(-1, s2->x, s2->y, "gcpuff", rand() % 5); } } } // turn off some global powerups switch (globpowerup) { case PW_CLOCK: case PW_SPRAYUP: case PW_SPRAYDOWN: case PW_WHISTLE: globpowerup = -1; break; } // lose normal powerups immediately s->powerup = PW_NONE; s->umbrella = B_FALSE; resethurryup(curlevel); if (curmusic == fastmusic) { playmusic(normalmusic); } // mark sprite as dead s->lostlife = B_TRUE; // turn off attributes s->climbing = B_FALSE; s->swimming = B_FALSE; s->slamming = B_FALSE; s->netting = B_FALSE; // kill mask sprite for (s2 = sprite ; s2 ; s2 = s2->next) { if ((s2->id == P_MASK) && (s2->owner == s)) { s2->dead = D_FINAL; } } // reset powerup types curpoweruptype[0] = 0; curpoweruptype[1] = 0; /* lose a life */ s->lives--; /* play sound */ playfx(FX_DIE); // draw text tnum = rand() % MAXDEATHTEXT; addoutlinetext(s->x,s->y,TEXTSIZE_DEATH,deathtext[tnum],&red,&black,DIEDELAY, TT_NORM); /* release anything we've caught */ for (s2 = sprite; s2 ; s2 = s2->next) { if (s2->caughtby == s) { uncatch(s2); s2->angry = B_TRUE; if (s2->id == P_SPIDER) { // climb up! s2->flies = B_TRUE; s2->falling = B_FALSE; s2->ys = -getspeed(s2); } } } // un-ice everything if player dies } } else if (s == boss) { // boss effects sprite_t *ss; // stop screen shaking and rats falling if (globpowerup == PW_RATSHAKE) { globpowerup = -1; } else if (globpowerup == PW_SNAILSHAKE) { globpowerup = -1; } // reset timers s->timer1 = 0; s->timer2 = 0; // death timer s->timer3 = BOSSDIETIME; if (s->id == P_KINGRAT) { // stop rats from coming in for (ss = sprite ; ss ; ss = ss->next) { if ((s->id == P_PUFF) && (ss->timer3 == P_RAT)) { // cancel the puffin ss->timer3 = -1; } } } // give a permenant powerup! switch (s->id) { case P_KINGRAT: addsprite(P_BIGSPEED, (640/2), 0, "bigspeed"); break; case P_KINGSNAIL: addsprite(P_BIGSCUBA, (640/2), 0, "bigscuba"); break; case P_KINGFLY: addsprite(P_SUPERUMBRELLA, (640/2), 0, "bigumbrella"); break; case P_KINGANT: addsprite(P_BIGHELMET, (640/2), 0, "bighelmet"); break; } } else if ((s->id == P_SNAIL) && (s->lives > 0)) { // snails can't die but turn into slugs instead sprite_t *newsp; sprite_t *catcher; if (s->caughtby) { catcher = s->caughtby; } else { double dist1, dist2; // pick closest one if (player) dist1 = getdistance(player->x,player->y,s->x,s->y); else dist1 = 99999; if (player2) dist2 = getdistance(player2->x,player2->y,s->x,s->y); else dist2 = 99999; if (dist1 < dist2) { catcher = player; } else { catcher = player2; } } // create a slug here newsp = addsprite(P_SLUG, s->x,s->y, "slug" ); puffin(-1, s->x, s->y, "nothing", 0); // create the illusion of a puff newsp->dir = catcher->dir; // facing away from player // make sure it can't be netted right away! if (globpowerup != PW_CLOCK) { newsp->invuln = SLUGINVULNTIME; } // the shell recoils (other code will kill us off when this is done) // -become invulnerable temporarily s->invuln = INVULNTIME*2; // make sure this lasts until we die // -bounce back s->recoiling = B_TRUE; jump(s,catcher->dir); // ie. away from the player playfx(FX_CRACK); // when we hit the ground, later code will check for this. // if a snail with lives=0 hits the ground, they die (it actually // looks like a shell) s->lives = 0; // attributes s->angry = 0; s->iced = 0; // don't do rest of code return; } /* set death attribute */ s->dead = D_INITIAL; s->netcaught = B_FALSE; s->netting = 0; s->slamming = 0; s->iced = 0; s->angry = 0; // play effect if they are going to be flaming if (globpowerup == PW_CANDLE) { playfx(FX_METEOR); } // check for level clear checklevelend(); } void checklevelend(void) { sprite_t *s2; int mcount; if (inintro()) return; // can't win until monsters have appeared if (levelcomplete == LV_INIT) return; if (!levelcomplete) { if (globpowerup == PW_LAMP) { // level ends when all gold coins are gone mcount = 0; for (s2 = sprite; s2 ; s2 = s2->next) { if (s2->id == P_GOLDCOIN) { mcount++; } else if ((s2->id == P_PUFF) && (s2->timer3 == P_GOLDCOIN)) { mcount++; } } if (mcount == 0) { levelcomplete = LV_CLEAR; } } else { // level ends when all monsters are dead mcount = 0; /* any monsters left? */ for (s2 = sprite; s2 ; s2 = s2->next) { if (ismonster(s2->id) && !s2->dead) { if (s2->id != P_BLACKCLOUD) { mcount++; } } } if (mcount == 0) { levelcomplete = LV_CLEAR; } } } } // count monsters of a given type (-1 for all) on level int countmonsters(int montype) { sprite_t *s2; int mcount; mcount = 0; /* any monsters left? */ for (s2 = sprite; s2 ; s2 = s2->next) { if (ismonster(s2->id) && !s2->dead) { if (s2->id != P_BLACKCLOUD) { if ((montype == -1) || (s2->id == montype)) { mcount++; } } } } return mcount; } // count of monsters left alive and uncaught int uncaughtmonsters(void) { sprite_t *s2; int mcount; mcount = 0; /* any monsters left? */ for (s2 = sprite; s2 ; s2 = s2->next) { if (ismonster(s2->id) && !s2->dead && !s2->caughtby) { if (s2->id != P_BLACKCLOUD) { mcount++; } } } return mcount; } void cleanup(void) { int i; printf("commencing cleanup routine....\n"); SDL_FreeSurface(pausedtext); SDL_FreeSurface(pausedshadow); Mix_HaltMusic(); Mix_CloseAudio(); for (i = 1; i < MAXLETTERHEIGHT; i++) { TTF_CloseFont(font[i]); } TTF_Quit(); SDL_Quit(); printf("complete.\n"); } int isonplatform(double x, double y) { sprite_t *s2; for (s2 = sprite ; s2 ; s2 = s2->next) { if (s2->id == P_PLATFORM) { if ((x >= (s2->x - s2->img->w/2)) && (x <= (s2->x + s2->img->w/2)) && (y >= (s2->y - s2->img->h)) && (y <= s2->y)) { return B_TRUE; } } } return B_FALSE; } void checkcollideplatform(sprite_t *s) { sprite_t *s2; SDL_Surface *walkimg; for (s2 = sprite ; s2 ; s2 = s2->next) { // only monsters and players and fruits can be on platforms if (!ismonster(s2->id) && (!isplayer(s2)) && (!isfruit(s2->id))) { continue; } if (s2->onplatform == s) { // if already on us, default to not being on us in case // it's moved away s2->onplatform = NULL; } walkimg = imageset[s2->id].img[F_WALK1]; if (walkimg != NULL) { // has it hit the top half of us? if ((s2->x >= (s->x - s->img->w/2 - walkimg->w/2 ) ) && (s2->x <= (s->x + s->img->w/2 + walkimg->w/2)) && (s2->y >= (s->y - s->img->h) ) && (s2->y <= s->y - s->img->h/2)) { /* COLLISION! */ if ((!s2->jumping) && (!s2->dead)) { s2->y = s->y - s->img->h; s2->onplatform = s; } } } } } // check whether a corpse has collided with a monster void checkfruitcollide (sprite_t *s) { double xdiff,ydiff,xthresh,ythresh; sprite_t *s2; // for all other monsters for (s2 = sprite ; s2 ; s2 = s2->next) { if (s2 == s) continue; else if (!ismonster(s2->id)) continue; else if (s2->dead) continue; else if (s2->caughtby) continue; else if (s2->teleporting) continue; else if (!isnettable(s2)) continue; // did we hit it? xdiff = s->x - s2->x; if (xdiff < 0) xdiff = -xdiff; ydiff = (s->y-(s->img->h/2)) - (s2->y-(s2->img->h/2)); if (ydiff < 0) ydiff = -ydiff; // adjust for zapper xthresh = s->img->w/2 + s2->img->w/2; ythresh = s->img->h/2 + s2->img->h/2; if ((xdiff <= xthresh) && (ydiff <= ythresh)) { // Colllision! playfx(FX_KILL); // if so, it turns into a fruit too! s2->id = fruittypes[curfruittype]; // stop jumping etc and allocate score setdefaults(s2); /* increment fruit type */ curfruittype++; if (fruittypes[curfruittype] == -1) { curfruittype = 0; } // fruit time fruittime = gtime; // bounce backwards if (s->xs > 0) { jump(s2, D_RIGHT); } else { jump(s2, D_LEFT); } } } } void checkcollide(sprite_t *s) { sprite_t *s2; int keepchecking; double xdiff,ydiff; double xthresh, ythresh; int netsleft; // for all other sprites for (s2 = sprite ; s2 ; s2 = s2->next) { if (s2 == s) continue; else if (s->dead) continue; else if (s2->dead) continue; else if (s->caughtby) continue; else if (s2->caughtby) continue; else if (s2->teleporting) continue; else if (iseffect(s2->id)) continue; keepchecking = B_TRUE; /* check for colission with our net */ if ((s->netting ) && (s->powerup != PW_RAYGUN)) { if ((isnettable(s2) && !s2->invuln) || (s->netsticky && isfruit(s2->id))){ double nety; if ((s->x + s->netlen*s->netdir) > s2->x) { xdiff = (s->x + s->netlen*s->netdir) - s2->x; } else { xdiff = s2->x - (s->x + s->netlen*s->netdir); } if (xdiff < 0) xdiff = -xdiff; nety = (s->y - (s->img->h/2) - 1); if (nety > (s2->y - s2->img->h/2)) { ydiff = nety - (s2->y - s2->img->h/2); } else { ydiff = (s2->y - s2->img->h/2) - nety; } if (ydiff < 0) ydiff = -ydiff; xthresh = s2->img->w; ythresh = s2->img->h; // check... if (ythresh > TILEH*2) { printf("*DEBUG* ythresh too high: %0.0f\n",ythresh); ythresh = TILEH*2; } // take numnets into account for y check netsleft = s->netmax - s->netcaught; if (netsleft > 1) { ythresh += ((int)s->img->h / (int)(netsleft+1) ); if (ythresh > TILEH*3) { printf("*DEBUG2* ythresh too high: %0.0f\n",ythresh); ythresh = TILEH*3; } } //if ((xdiff <= s2->img->w/2) && (ydiff <= s2->img->h)) { if ((xdiff <= xthresh) && (ydiff <= ythresh)) { // we hit something! if (s->netsticky && isfruit(s2->id)) { getfruit(s, s2, 1); } else { // Otherwise, it must be a monster // if we have a boxing glove, it dies if (s->powerup == PW_BOXING) { s2->dead = D_BOUNCING;// die as soon as it hits a wall s2->bounces = 1; s2->quickdie = B_TRUE; /* go FAST in the direction player is facing */ s2->xs = s->dir * 5; s2->ys = 0; /* slightly raise the sprite to avoid isonground() being true */ s2->y -= 3; /* make sure we're not too high since we'll never get lower now */ if (s2->y <= TILEH) s2->y = TILEH+1; // become something special s2->willbecome = P_DIAMOND; playfx(FX_KILL); strncpy(tempm, bifftext[rand() % MAXBIFFTEXT], BUFLEN); addoutlinetext(s2->x,s2->y - s->img->h/2, TEXTSIZE_BIFF, tempm,&red,&yellow,POINTSDELAY, TT_NORM); keepchecking = B_FALSE; } else if (s2->iced) { // it dies s2->willbecome = P_DIAMOND; playfx(FX_ICEBREAK); if (s2->id == P_SNAIL) s2->id = P_SLUG; die(s2); } else { // otherwise we caught it if we have enough nets if (s->netcaught < s->netmax) { //printf("caught: ydiff=%0.0f,ythresh=%0.0f,s='%s',%0.0f,%0.0f s2='%s',%0.0f,%0.0f\n", //ydiff,ythresh, //s->name, s->x, s->y, s2->name,s2->x,s2->y); s2->caughtby = s; s2->jumping = B_FALSE; s2->falling = 0; s2->caughtstate = C_NETTING; s->netcaught++; // special case for whitetail if (s2->id == P_WSPIDER) { s2->timer2 = 0; } // special case for bosses if (isbosslevel(curlevelnum)) { if (s2->owner) { s2->owner = NULL; } } // special case for spider, so that it will // recover if we release it if (s2->id == P_SPIDER) { s2->flies = B_FALSE; } playfx(FX_CATCH); keepchecking = B_FALSE; } } } // end if isfruit or ismonster } } } // end if s->netting // don't keep going if this sprite has now been killed/caught if (!keepchecking) continue; /* now check for collision with us */ xdiff = s->x - s2->x; if (xdiff < 0) xdiff = -xdiff; ydiff = (s->y-(s->img->h/2)) - (s2->y-(s2->img->h/2)); if (ydiff < 0) ydiff = -ydiff; // adjust for zapper xthresh = s->img->w/2 + s2->img->w/2; ythresh = s->img->h/2 + s2->img->h/2; if (s->id == P_ZAPPER) { xthresh += (TILEW*2.5); ythresh += (TILEH*2.5); } if ((xdiff <= xthresh) && (ydiff <= ythresh)) { /* COLLISION! */ // are we the player? if (isplayer(s)) { //if (isfruit(s2->id) && (s2->teleporting == 0)) { if (isfruit(s2->id)) { getfruit(s, s2, 1); } else if (ismonster(s2->id) || isbullet(s2->id)) { if (s2->iced) { // monster dies playfx(FX_ICEBREAK); if (s2->id == P_SNAIL) s2->id = P_SLUG; s2->willbecome = P_DIAMOND; die(s2); } else if (!s->invuln) { // player dies (unless it was the initial black cloud) if (s2->id != P_BLACKCLOUD) { if ((s2->id == P_SNAIL) && (s2->invuln)) { // snail shell doesn't hurt us } else if (s->caughtby) { // can't die while being slammed if (!s->caughtby->slamming) { die(s); } } else { printf("DB: player killed by %s\n",s2->name); fflush(stdout); die(s); } } else { // initial flashing black cloud doesn't kill player; if ((s2->id == P_BLACKCLOUD) && (!s2->invuln)) { die(s); printf("DB: player killed by blackclodu\n"); fflush(stdout); // play sound playfx(FX_EVILLAUGH); } } // add puffs if this was the cloud if (s2->id == P_BLACKCLOUD) { int xx,yy; int halfwid = s2->img->w/2; for (xx = s2->x - halfwid; xx <= s2->x + halfwid; xx += TILEW) { for (yy = s2->y - s2->img->h; yy <= s2->y; yy += TILEH) { puffin(-1, xx, yy, "nothing", 0); } } } // if a bullet hit us, it dies too if (isbullet(s2->id)) { if (s2->id != P_BIGFIREBALL) { s2->dead = D_FINAL; } } } } } else if ((s->id == P_SMASH) || (s->id == P_STAR) || (s->id == P_METEOR) || (s->id == P_RAYGUNBULLET) ) { if (ismonster(s2->id)) { switch (s->id) { case P_STAR: playfx(FX_STARHIT); break; } // monster dies if (s2->id == P_SNAIL) s2->id = P_SLUG; die(s2); // become something special s2->willbecome = P_DIAMOND; } } else if ((s->id == P_BLACKCLOUD) && (globpowerup == PW_WHISTLE)) { if (ismonster(s2->id)) { // monster dies if (s2->id == P_SNAIL) s2->id = P_SLUG; die(s2); // become something special s2->willbecome = P_DIAMOND; // play sound playfx(FX_EVILLAUGH); } } else if (s->id == P_ZAPPER) { if (ismonster(s2->id)) { if (s->timer4 == 0) { // set timer for zap effect s->timer4 = ZAPPERTIME; s->zapping = s2; playfx(FX_ZAP); // monster dies if (s2->id == P_SNAIL) s2->id = P_SLUG; die(s2); // become something special s2->willbecome = P_DIAMOND; } } } else if ((s->id == P_ANT1) || (s->id == P_ANT2) || (s->id == P_ANT3)) { int isfr; int goal = 5; // eat fruits isfr = isfruit(s2->id); if (isfr) { int fruitamt; // eat the fruit s2->dead = D_FINAL; playfx(FX_CHOMP); puffin(-1, s2->x, s2->y, "nothing", 0); // increase health switch (isfr) { case FT_FRUIT: case FT_PERM: case FT_TEMP: fruitamt = 5; break; case FT_GEM: default: fruitamt = 1; break; } // override for ant egg.. if (s2->id == P_EGG) fruitamt = 5; s->timer1 += fruitamt; // huw much fruit is needed to grow? if (s->id == P_ANT3) { goal = 1; } else { goal = 5; } if (s->timer1 >= goal) { s->timer1 = 0; playfx(FX_GROWL); // grow if (s->id == P_ANT1) { s->id = P_ANT2; } else if (s->id == P_ANT2) { s->id = P_ANT3; } else if (s->id == P_ANT3) { sprite_t *newsp; // spawn a new ant newsp = addsprite(P_ANT1, s2->x, s2->y, "spawned_ant"); puffin(-1, s->x+(s->dir*TILEH), s->y, "nothing", 0); newsp->dir = -s->dir; } } } } else if (inintro() && (s->id == P_RAT)) { // collect fruits if (isfruit(s2->id)) { playfx(FX_FRUIT); s2->dead = D_FINAL; puffin(-1, s2->x, s2->y, "nothing", 0); } } } } // end for each sprite } // do death bouncing effect void bouncesprite(sprite_t *s) { s->x += s->xs; s->y += s->ys; if (s->x >= (640-TILEW-(s->img->w/2))) { // move back onto screen while (s->x >= (640-TILEW-(s->img->w/2))) { s->x--; } if (s->xs > 0) s->xs = -s->xs; // reverse direction s->bounces++; } else if (s->x <= TILEW+s->img->w/2) { // move back onto screen while (s->x <= TILEW+s->img->w/2) { s->x++; } if (s->xs < 0) s->xs = -s->xs; // reverse direction s->bounces++; } if (s->y >= (480-(s->img->h/2))) { while (s->y >= (480-(s->img->h/2))) { s->y--; } if (s->ys > 0) s->ys = -s->ys; // reverse direction s->bounces++; } else if (s->y <= s->img->h) { while (s->y <= s->img->h) { s->y++; } if (s->ys < 0) s->ys = -s->ys; // reverse direction s->bounces++; } } // returns TRUE if we finished the level int movesprite(sprite_t *s) { int rv; tiletype_t *tt; if ((isplayer(s)) && (s->powerup == PW_GUNNER)) { return B_FALSE; } if (levelcomplete == LV_INIT) { // most things can't move in this state //if ((s->id != P_PUFF) && (s != player)) { if (!iseffect(s->id) && (!isplayer(s))) { // caught or dead sprites can move, in case // the player catches something before level start time if ((!s->caughtby) && (!s->dead)) return B_FALSE; } else if (s->id == P_PLATFORM) { return B_FALSE; } } // only player can move if you have a clock if (globpowerup == PW_CLOCK) { if (!iseffect(s->id) && (!isplayer(s)) && !s->caughtby) { return B_FALSE; } } // iced monsters can't move if (ismonster(s->id) && s->iced) { return B_FALSE; } // for random powerup, pick a random image if ((timer % 5) == 0) { if (s->id == P_RANDOM) { s->timer1 = randompowerup(); while (s->timer1 == P_RANDOM) { s->timer1 = randompowerup(); } // set image s->img = imageset[s->timer1].img[F_WALK1]; } } /* timer */ if (s->doomcount) { // fruits don't time out in gunner mode if (!haspowerupany(PW_GUNNER)) { s->doomcount--; } if (s->doomcount == 0) { s->dead = D_FINAL; } } /* avoid edges of screen */ if (s->y < s->img->h) { // if (!s->flies) { if (s->dead) { s->y = s->img->h; } } if (s->x > (640 - s->img->w/2)) { s->x = 640 - s->img->w/2; } if (s->x < (s->img->w/2)) { s->x = s->img->w/2; } if (s->invuln) { s->invuln--; } // anchor weighs down flying enemies if (ismonster(s->id) && s->flies && !s->dead && (globpowerup == PW_ANCHOR)) { if (s->id != P_BLACKCLOUD) { if (!isonground(s)) { // move down s->y += 3; } } } if (s->caughtby) { if (s->caughtby->slamming) { /* */ s->x = s->caughtby->netxstart; s->y = s->caughtby->netystart; } else { /* stay at position of net */ s->y = s->caughtby->y; if (s->caughtstate == C_NETTING) { s->x = s->caughtby->x + (s->caughtby->netlen*s->caughtby->netdir); } else { s->x = s->caughtby->x + (s->caughtby->img->w/2) * -(s->caughtby->dir); } } return B_FALSE; } else if (s->dead == D_INITIAL) { /* just set to dead */ if (s == boss) { // flash s->timer3--; if (s->timer3 == 0) { s->dead = D_FINAL; } } else { // 0 through 5 s->xs = 0.5 + ((rand() % 50) / 10); // 0.5 through 5.5 if (rand() % 2) { // 50% change of going left s->xs = s->xs * -1; } s->ys = -1 * (4 + ((rand() % 30) / 10)); // -4 through -7 s->dead = D_BOUNCING; s->bounces = 0; if (isplayer(s)) { s->jumpspeed = 8; s->jumping = 1; } } return B_FALSE; } else if (s->dead == D_BOUNCING) { /* dying */ if (isplayer(s)) { /* shoot up in the air, then fall */ s->y -= s->jumpspeed; s->jumping++; if (s->jumping % 5 == 0) { s->jumpspeed--; } /* if we've fallen off the bottom... */ if (s->y >= (480+s->img->h)) { /* pause before respawning */ s->jumpspeed = 0; /* this is now a timer */ s->dead = D_LASTBOUNCE; } } else { /* bounch around the screen 3 times */ bouncesprite(s); if ((s->bounces >= 2) && (s->ys >= 0)) { // make sure we're not on the ground if (!isonground(s)) { //int tx,ty; //tiletype_t *tt; //tt = gettileat(s->x,s->y,&tx,&ty); s->dead = D_LASTBOUNCE; } } // if flaming... if (globpowerup == PW_CANDLE) { if (timer % 5 == 0) { // add explosion addsprite(P_SMASH, s->x, s->y, "candle_exp"); } } } return B_FALSE; } else if (s->dead == D_LASTBOUNCE) { /* final fall */ if (isplayer(s)) { /* just delay... */ s->jumpspeed++; if (s->jumpspeed == 50) { /* really die */ s->dead = D_FINAL; } } else { /* bounce around, stop when we hit the ground */ bouncesprite(s); if ((s->ys >= 0) && (s->y >= TILEH)) { int x,y,ty; // get position for puff/fruit x = s->x; gettileat(s->x,s->y-1,NULL,&ty); //y = ty*TILEH + TILEH - 2; y = ty*TILEH - 2; /* make sure it's within the screen */ if (x > (640-TILEW)) x = 640-TILEW; if (x < (TILEW)) x = TILEW; if (s->quickdie || (isonground(s) && !isongroundpoint(s, s->x, s->y-TILEH))) { /* change into a fruit */ s->dead = D_FINAL; if (boss) { puffin(-1, x, y, "nothing", 0); } else { puffin(s->willbecome, x, y, "fruit", 0); // check for collision with a live monster checkfruitcollide(s); } //ss = addsprite(P_PUFF, x, y, "Fruit", B_FALSE); //ss->timer3 = s->willbecome; } else if (s->bounces >= 6) { // just die s->dead = D_FINAL; puffin(-1, x, y, "nothing_sprd", 0); } // if flaming... if (globpowerup == PW_CANDLE) { if (timer % 5 == 0) { // add explosion addsprite(P_SMASH, s->x, s->y, "candle_exp"); } } } } return B_FALSE; } else if (s->teleporting > 0) { SDL_Surface *ts; if (timer % 2 == 0) { /* shrink */ if (s->teleporting == TP_SHRINKING) { ts = rotozoomSurfaceXY(s->img,0, 0.9 , 0.9 ,0); s->img = ts; } else { ts = rotozoomSurfaceXY(s->img,0, 0.9 , 0.9 ,0); SDL_FreeSurface(s->img); s->img = ts; } // mark that we've allocated the player's teleport image s->allocimg = B_TRUE; if ((s->img->w <= 2) || (s->img->h <= 2)) { /* go to tele dest */ int x,y; /* find destination */ for (y = 0; y < LEVELH; y++) { for (x = 0; x < LEVELW; x++) { tt = gettile(curlevel->map[y*LEVELW+x]); if (tt->id == T_TELEPORTDEST) { /* teleport there */ s->x = (x * TILEW) + (TILEW/2); s->y = (y * TILEH) + TILEH-2; break; } else { // search map2 tt = gettile(curlevel->map2[y*LEVELW+x]); if (tt->id == T_TELEPORTDEST) { /* teleport there */ s->x = (x * TILEW) + (TILEW/2); s->y = (y * TILEH) + TILEH-2; break; } } } } s->teleporting = -1; } else s->teleporting++; } } else if (s->teleporting < 0) { double size; if (timer % 2 == 0) { /* grow */ size = (double) -s->teleporting / 10; SDL_FreeSurface(s->img); if (size >= 1) { s->allocimg = B_FALSE; s->teleporting = 0; s->img = imageset[s->id].img[F_WALK1]; } else { s->img = rotozoomSurfaceXY(imageset[s->id].img[F_WALK1],0,size,size,0); s->teleporting--; } } } else if (s->jumping) { if (s->id != P_KINGRAT) { int rv; rv = movex(s, s->jumpdir*getspeed(s), B_TRUE); // frogs bounce off walls /* if (s->id == P_FROG) { if (rv == NM_SIDE) { if (!isongroundpoint(s,s->x,s->y - (TILEH/2))) { if (!isroofabove(s)) { s->dir = -s->dir; s->jumpdir = -s->jumpdir; } } } } */ } return B_FALSE; } // adjust height to match the ground if (!iseffect(s->id) ) { if (isonground(s) || ((s->id == P_KINGRAT) && (s->timer1 == KRS_WALK))) { if ((!s->falling) && (!s->jumping)) { if (!s->climbing && !s->dropping) { if (!isonladder(s) ) { if ((s->id == P_KINGFLY) || ((s->id == P_FLY) && (s->owner))) { // don't adjust } else { adjustheight(s); } } else if (!s->climbing) { // on ladder but not climbing adjustheight(s); } } } } } /* sprite is about to jump */ if (s->jumptimer) { s->jumptimer--; if (s->jumptimer == 0) { s->jumping = 1; if (globpowerup == PW_ANCHOR) { // jump very low s->jumpspeed = 1; } else { s->jumpspeed = s->willjumpspeed; } if (s->jumpdir != 0) s->dir = s->jumpdir; return B_FALSE; } else if (s->jumptimer % 20 == 0) { if (s->id != P_SLUG) { // slugs don't turn back and forth before jumping s->dir = -s->dir; } } } else if ((s->id == P_SMASH) || (s->id == P_FLAME)) { // still delaying if (s->timer1 < 0) { // increment "frame" s->timer1++; } else { // increment frame at a slower pace if (++s->timer2 >= 10) { s->timer2 = 0; } if (timer % PUFFSPEED == 0) { s->timer1++; // finished animating if (s->timer1 == imageset[s->id].numimages) { s->timer1 = 999; // for debugging s->dead = D_FINAL; } } } } else if (s->id == P_MOVINGCARD) { // timer1 is the actual cardid // timer2 is the target x position // timer3 is the target y position // // move towards end position moveto(s, s->timer2, s->timer3, CARDSPEED, CARDSPEED); // are we there yet? if ((s->x == s->timer2) && (s->y == s->timer3)) { gaincard(s->owner, s->timer1); s->dead = D_FINAL; } } else if ((s->id == P_PUFF) || (s->id == P_SPARKLE)) { /* SUMMARY: timer1: indicates current frame. if < 0, don't draw. if >= PUFFFRAMES, use last frame. when timer1 gets to PUFFAPPEAR, create a gem of type s-> timer2: loops from 0 to 9. at intervals of PUFFSPEED, increment timer1. */ // still delaying if (s->timer1 < 0) { // increment "frame" s->timer1++; } else { // increment frame at a slower pace if (++s->timer2 >= 10) { s->timer2 = 0; } if (timer % PUFFSPEED == 0) { s->timer1++; // finished animating if (s->timer1 == PUFFAPPEAR) { // create a gem/fruit/etc if (s->id == P_PUFF) { if (s->timer3 >= 0) { sprite_t *newsp; // if both players already have this, and no cards already on screen, // we get a card instead (and also haven't got a card yet htis // level) if (!gotcard && s->timer3 != P_SPEED) { if ((isfruit(s->timer3) == FT_PERM) && (haspowerup(player, s->timer3) && haspowerup(player2, s->timer3))) { sprite_t *search; int found; found = B_FALSE; // is there already a card here or about to appear? for (search = sprite; search ; search = search->next) { if (iscard(search->id)) { found = B_TRUE; break; } // if it's a puff that will become a card... if ((search->id == P_PUFF) && (iscard(search->timer3))) { found = B_TRUE; break; } } if (!found) { s->timer3 = P_FIRSTCARD; } } } if (s->timer3 == P_FIRSTCARD) { if (levelcomplete != LV_INPROGRESS ) { // no cards at end of level! s->timer3 = P_CHEESE; } else { s->timer3 = getrandomcard(); gotcard = B_TRUE; } } newsp = addsprite(s->timer3, s->x,s->y,s->name ); if (s->timer3 == P_FROG) { // so all frogs don't jump at once. newsp->timer3 = (rand() % FROGPAUSE); } // is it a boss? if so update boss pointer switch (s->timer3) { case P_KINGRAT: case P_KINGSNAIL: case P_KINGFLY: case P_KINGANT: boss = newsp; } // is it in the water? if (isinwater(newsp)) { newsp->swimming = B_TRUE; newsp->watertimer = rand() % BUBBLETIME; } // is it a points fruit appearing on top of us? if (isfruit(newsp->id) == FT_FRUIT) { int xdiff,ydiff; int gotit = B_FALSE; /* now check for collision with players */ if (player) { xdiff = player->x - newsp->x; if (xdiff < 0) xdiff = -xdiff; ydiff = (player->y-(player->img->h/2)) - (newsp->y-(newsp->img->h/2)); if (ydiff < 0) ydiff = -ydiff; // appeared on top of us if ((xdiff <= player->img->w/2 + newsp->img->w/2) && (ydiff <= player->img->h/2 + newsp->img->h/2)) { if ((!player->dead) && (player->powerup != PW_GUNNER)) { if (newsp->id != P_GOLDCOIN) { // bonus! getfruit(player, newsp, 4); addoutlinetext(player->x,player->y - (player->img->h*1.5), TEXTSIZE_MULTI, "Nice catch!", &green,&black,MULTIDELAY, TT_NORM); gotit = B_TRUE; } } } } if (!gotit && player2) { xdiff = player2->x - newsp->x; if (xdiff < 0) xdiff = -xdiff; ydiff = (player2->y-(player2->img->h/2)) - (newsp->y-(newsp->img->h/2)); if (ydiff < 0) ydiff = -ydiff; // appeared on top of us if ((xdiff <= player2->img->w/2 + newsp->img->w/2) && (ydiff <= player2->img->h/2 + newsp->img->h/2)) { if ((!player2->dead) && (player2->powerup != PW_GUNNER)) { // bonus! getfruit(player2, newsp, 4); addoutlinetext(player2->x,player2->y - (player2->img->h*1.5), TEXTSIZE_MULTI, "Nice catch!", &green,&black,MULTIDELAY, TT_NORM); } } } } } } } else if (s->timer1 >= PUFFFRAMES) { s->timer1 = 999; // for debugging s->dead = D_FINAL; } } } } else if (s->id == P_MOVINGCARD) { // timer1 is the actual cardid // timer2 is the target x position // timer3 is the target y position // // move towards end position moveto(s, s->timer2, s->timer3, CARDSPEED, CARDSPEED); // are we there yet? if ((s->x == s->timer2) && (s->y == s->timer3)) { gaincard(s->owner, s->timer1); s->dead = D_FINAL; } } else if (s->id == P_FIVECARDS) { // are we there yet? if ((s->x == 320) && (s->y == 240 )) { if (s->timer2 == 0) { int i; SDL_Surface *blackness, *cardimg; SDL_Rect area; int cardwidth; cardwidth = imageset[P_FIRSTCARD].img[F_WALK1]->w; s->timer2 = -1; //this means we are counting down s->timer1 = POKERWAITTIME; // hide non-used cards cardimg = imageset[P_FIRSTCARD].img[F_WALK1]; if (s->owner == player) { area.x = 0; area.y = 0; area.w = cardimg->w; area.h = cardimg->h; } else { area.x = 4*(cardwidth+2); area.y = 0; area.w = cardimg->w; area.h = cardimg->h; } // create semi-transparent black surface the size of a card blackness = SDL_CreateRGBSurface(SDL_SWSURFACE, cardimg->w, cardimg->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, screen->format->Amask); SDL_FillRect(blackness, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); SDL_SetAlpha(blackness, SDL_SRCALPHA, 200); for (i = 0; i < s->owner->numcards; i++) { if (s->owner->usedcard[i] == B_FALSE) { // hide it //SDL_FillRect(s->img, &area, SDL_MapRGB(screen->format, 0, 0, 0)); SDL_BlitSurface(blackness, NULL, s->img, &area); } if (s->owner == player) { area.x += (cardimg->w + 2); } else { area.x -= (cardimg->w + 2); } } SDL_FreeSurface(blackness); } else { s->timer1--; if (s->timer1 == 0) { sprite_t *s2, *nexts; int i; // die s->dead = D_FINAL; // restore state levelcomplete = oldlevelcomplete; Mix_ResumeMusic(); // do effect! dopokereffect(s->owner,pokereffect); // clear player cards for (i = 0; i < MAXCARDS; i++) { s->owner->card[i] = -1; } s->owner->numcards = 0; // shuffle cards shufflecards(); // kill all monsters (if not skipping levels) if (s->owner->powerup != PW_PHONE) { for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isbullet(s2->id)) { s2->dead = D_FINAL; } else if (ismonster(s2->id)) { s2->willbecome = P_DIAMOND; s2->lives = 0; // for snails if (s2->caughtby) { uncatch(s2); } die(s2); } } } } } } else { // move towards centre of the screen moveto(s, 320, 240, FIVECARDSPEED, FIVECARDSPEED); } } else if (s->id == P_MASK) { // mask effect // stay on top of player if (s->owner->slamming) { s->y = s->owner->y + MASKOFFSETSLAMY; s->x = s->owner->x + (MASKOFFSETSLAMX*s->owner->dir); } else { s->y = s->owner->y + MASKOFFSETY; s->x = s->owner->x + (MASKOFFSETX*s->owner->dir); } // die if player doesn't have a mask if (!s->owner->hasmask) { s->dead = D_FINAL; } } else if (s->id == P_STAR) { // shuriken effect // animate s->timer1++; if (s->timer1 >= STARFRAMES) { s->timer1 = 0; } // move until we hit the edge of the screen s->x = s->x + s->xs; s->y = s->y + s->ys; // if off screen if ((s->x >= 640 - s->img->w/2) || (s->x <= s->img->w/2) || (s->y <= 0) || (s->y >= 480+s->img->h)) { // die s->dead = D_FINAL; } } else if (s->id == P_METEOR) { // meteor double oldy; oldy = s->y; // fall to bottom of screen then die s->y = s->y + s->ys; // if just appeared onscreen if ((oldy < 0) && (s->y >= 0)) { playfx(FX_METEOR); } // if off screen if (s->y >= (480 + s->img->h)) { // die s->dead = D_FINAL; } } else if (s->id == P_BUBBLE) { // bubble effect tiletype_t *tt; // float up, die when we leave the water tt = gettileat(s->x,s->y, NULL,NULL); if (tt->water) { s->y -= 0.5; // move left/right s->x += (sin(s->y/5)/5); } else { // die s->dead = D_FINAL; } } else if (s->id == P_ZAPPER) { // zapper effect double degs; /* timer1 is the frame timer2 controls when to change frame doomcount ? */ // die if level finished if ((levelcomplete == LV_CLEAR) || (levelcomplete == LV_WAIT)) { s->dead = D_FINAL; } // move in figure 8 around player s->x = s->owner->x; s->y = s->owner->y; degs = (double)s->timer3 * ((double)M_PI/(double)180); s->x += (sin(degs)*(double)48); s->y += (sin(degs*2)*(double)16); // adjust position counter s->timer3 += 3; if (s->timer3 >= (360*2)) { s->timer3 = 0; } // adjust frame s->timer2--; if (s->timer2 <= 0) { s->timer1++; if (s->timer1 >= imageset[P_ZAPPER].numimages) { s->timer1 = 0; } s->timer2 = ZAPPERDELAY; } // adjust zap counter if (s->timer4 > 0) { s->timer4--; } } else if (s->id == P_CANNON) { // cannon effect // die if owner dies if (s->owner->dead) { s->dead = D_FINAL; } else if (s->owner->powerup == PW_CANNON) { int targx,targy; // try to stay behind player targx = s->owner->x - (s->owner->dir * 32); targy = s->owner->y; if (s->x < targx) { s->x += 2; if (s->x > targx) s->x = targx; } if (s->y < targy) { s->y += 2; if (s->y > targy) s->y = targy; } if (s->x > targx) { s->x -= 2; if (s->x < targx) s->x = targx; } if (s->y > targy) { s->y -= 2; if (s->y < targy) s->y = targy; } } } else if (s->id == P_GLOVE) { // boxing glove effect // dies when the player finshes netting if (!s->owner->netting) { s->dead = D_FINAL; } else { // keep it at the end of the net s->x = s->owner->x + (s->owner->netdir * s->owner->netlen); s->y = s->owner->y - (s->owner->img->h/2) + 5; s->dir = s->owner->dir; } } else if (s->id == P_MACE) { // mace slam effect // dies when the player finishes slamming if (!s->owner->slamming) { s->dead = D_FINAL; } else { double dist; // keep it at the end of the slam dist = (s->owner->slamangle * (180/M_PI))/2; s->x = s->owner->x + cos(s->owner->slamangle-(180*(M_PI/180)))*dist*s->owner->dir; s->y = s->owner->y + sin(s->owner->slamangle-(180*(M_PI/180)))*dist + imageset[P_MACEPOWERUP].img[F_WALK1]->h/2; s->dir = s->owner->dir; } } else if (s->id == P_RAT) { if (inintro()) { // move right FAST double xpoint; xpoint = (curlevel->powerupx * TILEW) + (TILEW/2); if (s->x <= xpoint) { int rv = B_FALSE; rv = movex(s, s->speed, B_TRUE); } } else { // not in intro sequence if (!s->falling) { int move = B_FALSE; int xdiff ,absxdiff; tiletype_t *tunder; /* distance to closest player */ xdiff = getxdisttoplayer(s, NULL); absxdiff = abs(xdiff); // tile in front and below tt = gettileat(s->x + s->dir*getspeed(s) + (s->dir * (s->img->w/2)),s->y + (TILEH/2),NULL,NULL); // tile below tunder = gettileat(s->x ,s->y + 1,NULL,NULL); /* if there's a hole in front of us and below*/ if (tt->solid == S_NOTSOLID) { // we're on a slope if (tunder->solid == S_SLOPE) { move = B_TRUE; } else { if (s->angry || boss) { if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) { /* if player is below, fall off */ if (xdiff <= (TILEW*8)) { move = B_TRUE; } } else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) { if (globpowerup != PW_CAMERA) { /* if player is at same level and close, jump */ if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) { jump(s,D_RIGHT); } else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) { jump(s,D_LEFT); } } } else if (level->bottomopen && (s->y >= (480 - 100)) && isplayerabove(s)) { // if near bottom of the screen and can fall through... move = B_TRUE; } } } } else { move = B_TRUE; } if (globpowerup == PW_CAMERA) { move = B_TRUE; } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } if ((s->angry) || (boss)) { if ((!s->jumping) && (!s->jumptimer)) { /* if player is above us, jump */ if ( (player && (!player->dead) && (player->y < s->y)) || (player2 && (!player2->dead) && (player2->y < s->y))) { if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { /* jump right */ jump(s, 1); } else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { /* jump left */ jump(s, -1); } else if ((player && (s->y - player->y <= (TILEH*6))) || (player2 && (s->y - player2->y <= (TILEH*6)))) { if ((xdiff >= 0) && (xdiff < (TILEW*2))) { /* jump up */ jump(s, 0); } else if ((xdiff <= 0) && (xdiff > -(TILEW*2))) { /* jump up */ jump(s, 0); } } else { /* jump whichever way we're facing */ /* s->jumpdir = s->dir; s->jumping = 1; s->jumpspeed = 5; */ } } } } } else { // falling tiletype_t *tunder, *t2under; // tile below tunder = gettileat(s->x ,s->y,NULL,NULL); t2under = gettileat(s->x ,s->y+s->img->h,NULL,NULL); if ((tunder->solid == S_SLOPE) || (t2under->solid == S_SLOPE)) { movex(s, s->dir*getspeed(s), B_TRUE); } else if (s->jumpdir) { movex(s, s->jumpdir*getspeed(s), B_TRUE); } } } // end if inintro } else if (s->id == P_ANT1) { // worker ant - moves like a rat if (!s->falling) { int move = B_FALSE; int xdiff ,absxdiff; tiletype_t *tunder; /* distance to closest player */ xdiff = getxdisttoplayer(s, NULL); absxdiff = abs(xdiff); // tile in front and below tt = gettileat(s->x + s->dir*getspeed(s) + (s->dir * (s->img->w/2)),s->y + (TILEH/2),NULL,NULL); // tile below tunder = gettileat(s->x ,s->y + 1,NULL,NULL); /* if there's a hole in front of us and below*/ if (tt->solid == S_NOTSOLID) { // we're on a slope if (tunder->solid == S_SLOPE) { move = B_TRUE; } else { if (s->angry || boss) { if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) { /* if player is below, fall off */ if (xdiff <= (TILEW*8)) { move = B_TRUE; } } else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) { if (globpowerup != PW_CAMERA) { /* if player is at same level and close, jump */ if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) { jump(s,D_RIGHT); } else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) { jump(s,D_LEFT); } } } else if (level->bottomopen && (s->y >= (480 - 100)) && isplayerabove(s)) { // if near bottom of the screen and can fall through... move = B_TRUE; } } } } else { move = B_TRUE; } if (globpowerup == PW_CAMERA) { move = B_TRUE; } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } if (s->angry) { if ((!s->jumping) && (!s->jumptimer)) { /* if player is above us, jump */ if ( (player && (!player->dead) && (player->y < s->y)) || (player2 && (!player2->dead) && (player2->y < s->y))) { if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { /* jump right */ jump(s, 1); } else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { /* jump left */ jump(s, -1); } else if ((player && (s->y - player->y <= (TILEH*6))) || (player2 && (s->y - player2->y <= (TILEH*6)))) { if ((xdiff >= 0) && (xdiff < (TILEW*2))) { /* jump up */ jump(s, 0); } else if ((xdiff <= 0) && (xdiff > -(TILEW*2))) { /* jump up */ jump(s, 0); } } else { /* jump whichever way we're facing */ /* s->jumpdir = s->dir; s->jumping = 1; s->jumpspeed = 5; */ } } } } } else { // falling tiletype_t *tunder, *t2under; // tile below tunder = gettileat(s->x ,s->y,NULL,NULL); t2under = gettileat(s->x ,s->y+s->img->h,NULL,NULL); if ((tunder->solid == S_SLOPE) || (t2under->solid == S_SLOPE)) { movex(s, s->dir*getspeed(s), B_TRUE); } else if (s->jumpdir) { movex(s, s->jumpdir*getspeed(s), B_TRUE); } } } else if (s->id == P_ANT2) { // soldier ant - moves like a tick if (!s->falling) { int move = B_FALSE; int xdiff, absxdiff; /* distance to player */ xdiff = getxdisttoplayer(s, NULL); absxdiff = abs(xdiff); tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL); /* if there's a hole in front of us */ if (tt->solid == S_NOTSOLID) { double ycutoff = s->y + (TILEH/2); if ((player && (player->y >= ycutoff)) || (player2 && (player2->y >= ycutoff ))) { /* if player is below and nearby, fall off */ if (xdiff <= (TILEW*16)) { move = B_TRUE; } } else if ((player && (player->y == s->y)) || (player2 && (player2->y == s->y ))) { if (globpowerup != PW_CAMERA) { /* if player is at same level and close, jump */ if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) { jump(s,D_RIGHT); } else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) { jump(s,D_LEFT); } } } else if (level->bottomopen && (s->y >= (480 - 100)) && isplayerabove(s)) { // if near bottom of the screen and can fall through... move = B_TRUE; } } else { move = B_TRUE; } if (globpowerup == PW_CAMERA) { move = B_TRUE; } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } /* moves like an angry rat all the time */ if (globpowerup != PW_CAMERA) { if ((playersalive()) && (!s->jumping) && (!s->jumptimer)) { sprite_t *abovep; /* if player is above us...*/ abovep = isplayerabove(s); if (abovep) { if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { // if 2-3 tiles right /* jump right */ jump(s, D_RIGHT); } else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { // if 2-3 tiles left /* jump left */ jump(s, D_LEFT); } else if (s->y - abovep->y <= (TILEH*6)) { // player less than 6 tiles above if ((xdiff >= 0) && (xdiff < (TILEW*4))) { // ... and within 4 tiles /* jump up */ jump(s, 0); } else if ((xdiff <= 0) && (xdiff > -(TILEW*4))) { // ... and within 4 tiles /* jump up */ jump(s, 0); } } } } } } else { // falling movex(s, s->jumpdir*getspeed(s), B_TRUE); } } else if (s->id == P_ANT3) { // moves like a snake /* timer1 loopsfrom 0 - 19 if timer2 is 0, we can shoot. if it is 1, we can't. */ // inc shooting timer if (s->timer1) { s->timer1--; if (s->timer1 == 0) { } } if (!s->falling) { int move = B_FALSE; int xdiff, absxdiff,ydiff; /* distance to player */ xdiff = getxdisttoplayer(s, NULL); absxdiff = abs(xdiff); tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL); /* if there's a hole in front of us */ if (tt->solid == S_NOTSOLID) { if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) { /* if player is below, fall off */ if (xdiff <= (TILEW*8)) { move = B_TRUE; } } else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) { if (s->angry) { /* if player is at same level and close, jump */ if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) { jump(s,D_RIGHT); } else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) { jump(s,D_LEFT); } } } else if (level->bottomopen && (s->y >= (480 - 100)) && isplayerabove(s)) { // if near bottom of the screen and can fall through... move = B_TRUE; } } else { move = B_TRUE; } if (globpowerup == PW_CAMERA) { move = B_TRUE; } /* shoot */ ydiff = getydisttoplayer(s); ydiff = abs(ydiff); // if there's a player close up/down... if (ydiff <= (TILEH*4)) { sprite_t *ss; sprite_t *closeplayer; int shoot = B_FALSE; if (player && (s->y - player->y <= (TILEH*12)) ) { closeplayer = player; } else if (player2 && (s->y - player2->y <= (TILEH*12))) { closeplayer = player2; } else { closeplayer = NULL; } if (closeplayer) { if (s->bullet == NULL) { // if we don't already have a bullet // if we are facing the player if ( (closeplayer->x < s->x) && (s->dir == D_LEFT) ) { shoot = B_TRUE; } else if ( (closeplayer->x > s->x) && (s->dir == D_RIGHT) ) { shoot = B_TRUE; } } if (globpowerup == PW_CAMERA) shoot = B_FALSE; if (shoot) { // if our shooting timer is okay if (s->timer1 == 0) { playfx(FX_METEOR); ss = addsprite(P_FIREBALL,s->x,s->y - s->img->h/2,"spit" ); ss->ys = 0; ss->xs = s->dir * (getspeed(s)*2); ss->dir = s->dir; ss->owner = s; s->bullet = ss; // start timer for shooting again s->timer1 = 200; } } } } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } if (globpowerup != PW_CAMERA) { if (playersalive() && (!s->jumping) && (!s->jumptimer)) { /* if player is above us, jump */ if ( (player && (!player->dead) && (player->y < s->y)) || (player2 && (!player2->dead) && (player2->y < s->y))) { if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { /* jump right */ jump(s, 1); } else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { /* jump left */ jump(s, -1); } else if ((player && (s->y - player->y <= (TILEH*6))) || (player2 && (s->y - player2->y <= (TILEH*6)))) { if ((xdiff >= 0) && (xdiff < (TILEW*2))) { /* jump up */ jump(s, 0); } else if ((xdiff <= 0) && (xdiff > -(TILEW*2))) { /* jump up */ jump(s, 0); } } else { /* jump whichever way we're facing */ /* s->jumpdir = s->dir; s->jumping = 1; s->jumpspeed = 5; */ } } } } } else { // falling movex(s, s->jumpdir*getspeed(s), B_TRUE); } } else if (s->id == P_SNAIL) { if (!s->falling) { int move = B_FALSE; int xdiff, absxdiff; /* distance to closest player */ xdiff = getxdisttoplayer(s, NULL); absxdiff = abs(xdiff); tt = gettileat(s->x + s->dir+getspeed(s) + (s->dir * (s->img->w/2)),s->y,NULL,NULL); /* if there's a hole in front of us */ if (tt->solid == S_NOTSOLID) { if (s->angry || boss) { if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) { /* if player is below, fall off */ if (xdiff <= (TILEW*8)) { move = B_TRUE; } } else if (level->bottomopen && (s->y >= (480 - 100)) && isplayerabove(s)) { // if near bottom of the screen and can fall through... move = B_TRUE; } } } else { move = B_TRUE; } if (globpowerup == PW_CAMERA) { // always move move = B_TRUE; } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } // jump? if (boss) { if ((!s->jumping) && (!s->jumptimer)) { /* if player is above us or at same level...*/ if ( (player && (!player->dead) && (player->y <= s->y-TILEH)) || (player2 && (!player2->dead) && (player2->y <= s->y-TILEH))) { int ydiff; if (player && (!player->dead) && (player->y <= s->y-TILEH)) { ydiff = s->y - player->y; } else { ydiff = s->y - player2->y; } if ((ydiff >= (TILEH*4)) && (ydiff <= (TILEH*8))) { // player between 4 and 8 tiles above if (xdiff <= (TILEW*16)) { // if closeish horizontally /* jump up */ jump(s, 0); } } else if ((xdiff >= (TILEW*1)) && (xdiff <= (TILEW*9))) { // if 1-9 tiles right if (s->dir == D_RIGHT) { /* jump right */ jump(s, D_RIGHT); } } else if ((xdiff <= -(TILEW*1)) && (xdiff >= -(TILEW*9))) { // if 1-9 tiles left if (s->dir == D_LEFT) { /* jump left */ jump(s, D_LEFT); } } } } } } else { // falling if (s->recoiling) { // fall backwards rv = movex(s, -s->dir*getspeed(s), B_TRUE); } else if (s->jumpdir) { movex(s, s->jumpdir*getspeed(s), B_TRUE); } } } else if (s->id == P_FROG) { if (isinwater(s)) { // move like a fish double absxs,absys; s->flies = B_TRUE; s->falling = B_FALSE; if ((s->xs == -99) || (s->ys == -99)) { s->xs = getspeed(s) * s->dir; s->ys = getspeed(s); } if (s->xs > 0) absxs = 1; else absxs = -1; if (s->ys > 0) absys = 1; else absys = -1; /* can we move? */ tt = gettileat(s->x + (s->dir * ((s->img->w/2)+3)) + s->xs , s->y-(s->img->h/2),NULL,NULL); if ((tt->solid) || (tt->spikes )) { /* turn */ s->xs = -s->xs; } tt = gettileat(s->x, s->y-(s->img->h/2) + s->ys,NULL,NULL); if ((tt->solid) || (tt->spikes) ) { /* turn */ s->ys = -s->ys; } else if (!tt->water) { s->flies = B_FALSE; // exit water jump(s, s->dir); // force big jump s->jumpspeed = FROGJUMPSPEED2; } /* move */ s->x += s->xs; s->y += s->ys; s->dir = absxs; s->moved = MV_WALK; } else { // for if we get back in the water s->xs = -99; s->ys = -99; s->flies = B_FALSE; // timer3 used for pause inbetween jump if ((!s->falling) && (!s->jumping)) { if (s->timer3) { s->timer3--; } else { // jump forwards jump(s, s->dir); s->timer3 = FROGPAUSE; } } else { // falling int rv; // move forwards rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv == NM_SIDE) { // bounce off walls /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } } } else if (s->id == P_SLUG) { if (!s->falling) { int move = B_FALSE; int xdiff, absxdiff; sprite_t *target = NULL; /* distance to closest player */ xdiff = getxdisttoplayer(s, &target); if (target != NULL) { absxdiff = abs(xdiff); xdiff = target->x - s->x; tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL); /* if there's a hole in front of us */ if (tt->solid == S_NOTSOLID) { if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) { /* if player is below and nearby, fall off */ if (xdiff <= (TILEW*16)) { move = B_TRUE; } } else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) { if (globpowerup != PW_CAMERA) { /* if player is at same level and close, try to jump over the gap */ if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*9))) { jump(s,D_RIGHT); } else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*9))) { jump(s,D_LEFT); } } } else if (level->bottomopen && (s->y >= (480 - 100)) && isplayerabove(s)) { // if near bottom of the screen and can fall through... move = B_TRUE; } } else { move = B_TRUE; } } if (globpowerup == PW_CAMERA) { move = B_TRUE; } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } if (globpowerup != PW_CAMERA) { /* moves like an angry rat all the time */ if ((!s->jumping) && (!s->jumptimer)) { /* if player is above us or at same level...*/ if ( (player && (!player->dead) && (player->y <= s->y)) || (player2 && (!player2->dead) && (player2->y <= s->y))) { int ydiff; if ( (player && (!player->dead) && (player->y <= s->y))) { ydiff = s->y - player->y; } else if (player2) { ydiff = s->y - player2->y; } else { ydiff = 999; } if (isplayerabove(s) && (ydiff >= (TILEH*4)) && (ydiff <= (TILEH*8))) { // player between 4 and 8 tiles above if (xdiff <= (TILEW*8)) { // if closeish horizontally /* jump up */ jump(s, 0); } } else if ((xdiff >= (TILEW*1)) && (xdiff <= (TILEW*10))) { // if 1-9 tiles right if (s->dir == D_RIGHT) { /* jump right */ jump(s, D_RIGHT); } } else if ((xdiff <= -(TILEW*1)) && (xdiff >= -(TILEW*10))) { // if 1-9 tiles left if (s->dir == D_LEFT) { /* jump left */ jump(s, D_LEFT); } } } } } } else { // falling int rv; // move forwards rv = movex(s, s->dir*getspeed(s), B_TRUE); } } else if (s->id == P_PLANT) { // don't move! s->moved = MV_WALK; } else if (s->id == P_KINGRAT) { /* timer1 is state 0 == walk back and forth timer2 counts down, at zero we change state */ if (s->timer1 == KRS_WALK) { int canseeplayer = B_TRUE; int ydis; // move rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } // if player is in front, charge! if (!playersalive()) { canseeplayer = B_FALSE; } else { if (player) { ydis = abs(s->y - player->y); if (ydis > 2) { canseeplayer = B_FALSE; } else if ((s->dir < 0) && (player->x > s->x)) { canseeplayer = B_FALSE; } else if ((s->dir > 0) && (player->x < s->x)) { canseeplayer = B_FALSE; } } if ((canseeplayer == B_TRUE) && (player2)) { ydis = abs(s->y - player2->y); if (ydis > 2) { canseeplayer = B_FALSE; } else if ((s->dir < 0) && (player2->x > s->x)) { canseeplayer = B_FALSE; } else if ((s->dir > 0) && (player2->x < s->x)) { canseeplayer = B_FALSE; } } } if (canseeplayer) { // CHARGE! playfx(FX_BOSSWINDUP); s->timer1 = KRS_CHARGEWAIT; s->timer2 = KR_NUMJUMPS; } else { // dec timer s->timer2--; if (s->timer2 == 0) { if (!playersalive()) { // reset timer s->timer2 = KR_WALKTIME; } else { // jump to player's height s->timer1 = KRS_JUMP; } } } } else if (s->timer1 == KRS_CHARGEWAIT) { // jump timer2 times. if (timer % 2 == 0) { // add puffs puffin(-1, s->x + (rand() % (s->img->w)) - (s->img->w/2), s->y, "nothing", rand() % 5); } if (!s->jumping && !s->falling) { s->timer2--; if ((s->timer2 <= 0) && (!s->jumping)){ //CHARGE s->timer1 = KRS_CHARGE; s->flies = B_TRUE; playfx(FX_BOSSCHARGE); } else { // bounce jump(s,0); s->jumpspeed = 1; } } } else if (s->timer1 == KRS_CHARGE) { int rv; // move fast forwards rv = movex(s, s->dir*KR_CHARGESPEED, B_TRUE); if (rv) { // hit a wall - get stunned s->timer1 = KRS_STUN; s->timer2 = KR_STUNTIME; s->flies = B_FALSE; playfx(FX_BOSSWALL); // shake the screen via a fake player powerup globpowerup = PW_RATSHAKE; globtimer = RATSHAKETIME; } } else if (s->timer1 == KRS_STUN) { s->timer2--; if (s->timer2 == 0) { s->timer1 = KRS_WALK; s->timer2 = KR_WALKTIME; } } else if (s->timer1 == KRS_JUMP) { // jump to closest player height if (!s->jumping) { int ydis; int try; int tot; int n; if ((!playersalive()) || isplayerbelow(s) ) { // player below or dead try = 2; } else { // get distance ydis = getydisttoplayer(s); ydis = abs(ydis); // figure out how much we need to jump for (try = 2; try < (KR_MAXJUMP-1); try++) { tot = 0; for (n = try; n >= 1; n--) { tot = tot + (5*n); } if (tot >= ydis) { break; } } } jump(s, 0); // manually adjust speed try++; // one more just to be sure s->willjumpspeed = try; // next state s->timer1 = KRS_WAITFORTOP; } } else if (s->timer1 == KRS_WAITFORTOP) { if (!s->jumping) { s->timer1 = KRS_FALL; } } else if (s->timer1 == KRS_FALL) { // fall to player height if (!s->jumping && ((player && (s->y >= player->y)) || (player2 && (s->y >= player2->y))) ) { // back to normal state but lower timer s->timer1 = KRS_WALK; s->timer2 = KR_WALKTIME; // low delay } } } else if (s->id == P_KINGSNAIL) { /* timer1 is state 0 == walk back and forth timer2 counts down, at zero we change state */ if ((s->timer1 == KSS_WALK1) || (s->timer1 == KSS_WALK2)) { // walk back and forth rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } // dec timer s->timer2--; if (s->timer2 == 0) { if (!playersalive()) { // reset timer s->timer2 = KR_WALKTIME; } else { // release snails or jump, depending on state if ((countmonsters(P_SNAIL) == 0) || (s->timer1 == KSS_WALK1)) { // next state is shooting s->timer1 = KSS_PAUSE1; s->timer2 = KS_SHOOTWAIT; playfx(FX_SNAILPREPARE); } else { // next state is jump s->timer1 = KSS_PAUSE2; s->timer2 = KS_JUMPWAIT; } } } } else if (s->timer1 == KSS_PAUSE1) { // add puffs on shell if (timer % 6 == 0) { puffin(-1, s->x + -s->dir*((s->img->w/4) + (rand() % 7)-3), s->y-(s->img->h/2) - (rand() % 7) - 3, "nothing", rand() % 5); } s->timer2--; if (s->timer2 == 0) { sprite_t *newsp; // shoot! s->timer1 = KSS_SHOOT; // shell cracks playfx(FX_CRACK); newsp = addsprite(P_KSSHELL, s->x + -s->dir*((s->img->w/4) + (rand() % 7)-3), s->y-(s->img->h/2) - (rand() % 7) - 3, "ksshell"); // the shell recoils (other code will kill us off when this is done) // -become invulnerable temporarily newsp->invuln = INVULNTIME*2; // make sure this lasts until we die // -bounce back newsp->recoiling = B_TRUE; jump(newsp,-s->dir); // ie. away from king snail } } else if (s->timer1 == KSS_SHOOT) { // shoot out snails if (timer % 20 == 0) { if (countmonsters(-1) < 6) { // max 5 snails + king snail sprite_t *newsp; newsp = addsprite(P_SNAIL, s->x + -s->dir*(s->img->w/4), s->y-(s->img->h/2),"babsnail"); // make it shoot upwards newsp->jumping = 1; newsp->jumpspeed = (rand() % 7) + 7; // 7 - 13 newsp->jumpdir = (((double)(rand() % 110) - 50) / 10); // -5 to 5 if (rand() % 2) newsp->dir = 1; else newsp->dir = -1; playfx(FX_WHOOSH); } else { // enough, regenerate shell s->timer1 = KSS_REGEN; s->timer3 = 1; // percentage of shell size } } } else if (s->timer1 == KSS_REGEN) { // shell gets bigger s->timer3++; // wait for shell to finish if (s->timer3 >= 120) { // walk again s->timer1 = KSS_WALK2; s->timer2 = KS_WALKTIME; } } else if (s->timer1 == KSS_PAUSE2) { if (!s->jumptimer) { int ydis; int try; int tot; int n; // remember our height s->timer3 = s->y; // delay then jump s->jumptimer = getjumpdelay(s->id); s->jumpdir = 0; if ((!playersalive()) || isplayerbelow(s)) { // player below or dead try = 2; } else { // get distance ydis = getydisttoplayer(s); ydis = abs(ydis); // figure out how much we need to jump for (try = 2; try < (KR_MAXJUMP-1); try++) { tot = 0; for (n = try; n >= 1; n--) { tot = tot + (5*n); } if (tot >= ydis) { break; } } } jump(s, 0); // manually adjust speed try++; // one more just to be sure s->willjumpspeed = try; // next state s->timer1 = KSS_JUMPING; } } else if (s->timer1 == KSS_JUMPING) { // wait until we land... if (!s->jumptimer && !s->jumping && !s->falling) { sprite_t *ss, *nexts; // snails turn to slugs!! for (ss = sprite ; ss ; ss = nexts) { nexts = ss->next; if ((ss->id == P_SNAIL) && !ss->caughtby && !ss->dead) { die(ss); } } // now pause a while before moving again s->timer1 = KSS_PAUSE3; s->timer2 = KS_RELOADWAIT; // shake the screen via a fake player powerup playfx(FX_BOSSWALL); globpowerup = PW_SNAILSHAKE; globtimer = SNAILSHAKETIME; } } else if (s->timer1 == KSS_PAUSE3) { s->timer2--; if (s->timer2 == 0) { // go back to start! s->timer1 = KSS_WALK1; s->timer2 = KS_WALKTIME; } } } else if (s->id == P_KINGFLY) { double absxs,absys; if ((s->timer1 == KFS_FLY1) || (s->timer1 == KFS_FLY2)) { if ((s->xs == -99) || (s->ys == -99)) { s->xs = getspeed(s); s->ys = getspeed(s); } if (s->xs > 0) absxs = 1; else absxs = -1; if (s->ys > 0) absys = 1; else absys = -1; /* this will fix the speed if ANGRY is set */ s->xs = absxs*getspeed(s); s->ys = absys*getspeed(s); /* can we move? */ if (s->x >= 640 - (s->img->w/2) - 2) { /* turn */ s->xs = -abs(s->xs); } else if (s->x <= (s->img->w/2)) { s->xs = abs(s->xs); } if (s->y <= s->img->h) { s->ys = abs(s->ys); } else if (s->y >= 480-2 ) { s->ys = -abs(s->ys); } /* move */ s->x += s->xs; s->y += s->ys; s->dir = absxs; s->moved = MV_FLY; // generate babies if (timer % 25 == 0) { int numbabies, numflies; sprite_t *ss; numflies = countmonsters(P_FLY); // count how many babies we have numbabies = 0; for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_FLY) && (ss->owner == s)) { numbabies++; } } if (numflies < 12) { if (numbabies < 6) { sprite_t *newsp; puffin(-1, s->x, s->y, "nothing", 0); newsp = addsprite(P_FLY, s->x, s->y, "gen_fly"); newsp->invuln = FLYINVULNTIME * (numbabies+1); newsp->xs = s->xs; newsp->ys = s->ys; newsp->owner = s; } } } s->timer2--; if (s->timer2 <= 0) { if ((s->y >= s->img->h*4) && (s->y <= (480-s->img->h*2))) { if ((s->x >= s->img->w) && (s->x <= 640-(s->img->w))) { if (s->timer1 == KFS_FLY1) { s->timer1 = KFS_HORZWAIT; s->timer3 = s->y; } else { s->timer1 = KFS_VERTWAIT; s->timer3 = s->x; } } } } } else if (s->timer1 == KFS_HORZWAIT) { double ymod; sprite_t *ss; int ready = B_TRUE; // hover s->ys = 2; ymod = sin(((double)timer * (double)3.6) * (M_PI/180)); if (s->ys * (ymod) > 0) absys = 1; else absys = -1; s->y += (s->ys * ymod); s->moved = MV_FLY; // if all babies attached for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_FLY) && (ss->owner == s) && (ss->timer1 != KFS_HORZWAIT)) { ready = B_FALSE; } } if (ready) { int numflies,n; s->timer1 = KFS_HORZPUSH; s->timer3 = s->y; // set position for babies numflies = countbabies(s, P_FLY); n = 1; for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_FLY) && (ss->owner == s)) { ss->timer1 = KFS_HORZPUSH; ss->timer2 = n * (640/(numflies+1)); // target x //printf("setting target to %d\n",ss->timer2); n++; } } } } else if (s->timer1 == KFS_HORZPUSH) { double ymod; int ready = B_TRUE; sprite_t *ss; // hover s->ys = 2; ymod = sin(((double)timer * (double)3.6) * (M_PI/180)); if (s->ys * (ymod) > 0) absys = 1; else absys = -1; s->y += (s->ys * ymod); s->moved = MV_FLY; // if all flies in position, release them for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_FLY) && (ss->owner == s) && (ss->x != ss->timer2)) { ready = B_FALSE; break; } } if (ready) { for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_FLY) && (ss->owner = s)) { // release it! ss->owner = NULL; } } s->timer1 = KFS_HORZ; s->timer2 = KF_HOVERTIME; } } else if (s->timer1 == KFS_HORZ) { double ymod; // hover s->ys = 2; ymod = sin(((double)timer * (double)3.6) * (M_PI/180)); if (s->ys * (ymod) > 0) absys = 1; else absys = -1; s->y += (s->ys * ymod); s->moved = MV_FLY; s->timer2--; if (s->timer2 == 0) { // fly around again s->timer1 = KFS_FLY2; s->timer2 = KF_FLYTIME; s->timer3 = 0; } } else if (s->timer1 == KFS_VERTWAIT) { double ymod; sprite_t *ss; int ready = B_TRUE; // hover s->ys = 2; ymod = sin(((double)timer * (double)3.6) * (M_PI/180)); if (s->ys * (ymod) > 0) absys = 1; else absys = -1; s->y += (s->ys * ymod); s->moved = MV_FLY; // if all babies attached for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_FLY) && (ss->owner == s) && (ss->timer1 != KFS_VERTWAIT)) { ready = B_FALSE; } } if (ready) { int numflies,n; s->timer1 = KFS_VERTPUSH; s->timer3 = s->x; // set position for babies numflies = countbabies(s, P_FLY); n = 1; for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_FLY) && (ss->owner == s)) { ss->timer1 = KFS_VERTPUSH; ss->timer2 = n * (480/(numflies+1)); // target x //printf("setting target to y = %d\n",ss->timer2); n++; } } } } else if (s->timer1 == KFS_VERTPUSH) { double ymod; int ready = B_TRUE; sprite_t *ss; // hover s->ys = 2; ymod = sin(((double)timer * (double)3.6) * (M_PI/180)); if (s->ys * (ymod) > 0) absys = 1; else absys = -1; s->y += (s->ys * ymod); s->moved = MV_FLY; // if all flies in position, release them for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_FLY) && (ss->owner == s) && (ss->y != ss->timer2)) { ready = B_FALSE; break; } } if (ready) { for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == P_FLY) && (ss->owner = s)) { // release it! ss->owner = NULL; } } s->timer1 = KFS_VERT; s->timer2 = KF_HOVERTIME; } } else if (s->timer1 == KFS_VERT) { double ymod; // hover s->ys = 2; ymod = sin(((double)timer * (double)3.6) * (M_PI/180)); if (s->ys * (ymod) > 0) absys = 1; else absys = -1; s->y += (s->ys * ymod); s->moved = MV_FLY; s->timer2--; if (s->timer2 == 0) { // fly around again s->timer1 = KFS_FLY1; s->timer2 = KF_FLYTIME; } } } else if (s->id == P_KINGANT) { /* - Move back and forth for a while - spawn out ants if not enough - Jump to top, destroying platforms - Move back and forth for a while - spawn out ant food - Jump to bottom, destroying platforms */ // add flames on it if (( timer % 2) == 0) { addsprite(P_FLAME, s->x + (rand() % s->img->w) - (s->img->w/2), s->y - (s->img->h/2) + (rand() % s->img->h/2), "antflame"); } // move back and forth if ((s->timer1 == KAS_WALK1) || (s->timer1 == KAS_WALK2)) { // move rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } // shoot out monsters s->timer3--; if (s->timer3 <= 0) { // reset shoot timer s->timer3 = KA_SHOOTTIME; if (s->timer1 == KAS_WALK1) { // shoot an ant out if (countmonsters(-1) < 7) { // max 6 ants + king ant sprite_t *newsp; puffin(-1, s->x, s->y - (s->img->h/2), "nothing", 0); newsp = addsprite(P_ANT1, s->x, s->y-(s->img->h/2),"babant"); // make it shoot upwards newsp->jumping = 1; newsp->jumpspeed = (rand() % 7) + 7; // 7 - 13 newsp->jumpdir = (((double)(rand() % 110) - 50) / 10); // -5 to 5 if (rand() % 2) newsp->dir = 1; else newsp->dir = -1; playfx(FX_WHOOSH); } else { // enough monsters, shoot food instead sprite_t *newsp; puffin(-1, s->x, s->y - (s->img->h/2), "nothing", 0); newsp = addsprite(P_EGG, s->x, s->y-(s->img->h/2),"antegg"); // make it shoot upwards newsp->jumping = 1; newsp->jumpspeed = (rand() % 7) + 7; // 7 - 13 newsp->jumpdir = (((double)(rand() % 110) - 50) / 10); // -5 to 5 if (rand() % 2) newsp->dir = 1; else newsp->dir = -1; playfx(FX_WHOOSH); } } } // dec walk timer s->timer2--; if (s->timer2 == 0) { if (playersalive()) { // jump to other side height if (s->timer1 == KAS_WALK1) s->timer1 = KAS_JUMP1; else s->timer1 = KAS_JUMP2; } else { // nobody alive - reset timer s->timer2 = KA_WALKTIME; s->timer3 = KA_SHOOTTIME; } } } else if ((s->timer1 == KAS_JUMP1) || (s->timer1 == KAS_JUMP2)) { // jump to closest player height if (!s->jumping) { if (!playersalive() ) { // player below or dead // go back to walking s->timer1 = KAS_WALK1; s->timer2 = KA_WALKTIME; s->timer3 = KA_SHOOTTIME; } else { int jumpheight, jumptarget,nextstate; jump(s, 0); if (s->timer1 == KAS_JUMP1) { jumpheight = 13; jumptarget = TILEH*3; // jump to top nextstate = KAS_WAITFORTOP1; } else { jumpheight = 3; jumptarget = 480 - (TILEH*3); // jump to bottom nextstate = KAS_WAITFORTOP2; } s->willjumpspeed = jumpheight; // next state s->timer1 = nextstate; s->timer3 = jumptarget; } } } else if (s->timer1 == KAS_WAITFORTOP1) { if (!s->jumping) { s->timer1 = KAS_FALL1; } } else if (s->timer1 == KAS_WAITFORTOP2) { if (!s->jumping) { s->timer1 = KAS_FALL2; } } else if ((s->timer1 == KAS_FALL1) || (s->timer1 == KAS_FALL2)) { // King Ant's jump is handled specially in dogravity() if (s->falling) { if (!s->bullet) { sprite_t *mytarget; // shoot fireball if player in front! mytarget = isplayerahead(s); if (mytarget) { sprite_t *ss; // shoot! playfx(FX_METEOR); ss = addsprite(P_BIGFIREBALL,s->x,mytarget->y+(TILEH/2),"horzfireball" ); ss->ys = 0; ss->xs = s->dir * 4; ss->dir = s->dir; ss->owner = s; s->bullet = ss; } } } else { // back to normal state if (s->timer1 == KAS_FALL1) { s->timer1 = KAS_WALK2; } else { s->timer1 = KAS_WALK1; } s->timer2 = KA_WALKTIME; s->timer3 = KA_SHOOTTIME; } } } else if (s->id == P_PLATFORM) { // moving platform // timer1 tells whether we are at top speed double dstx,dsty; int rv; if (s->numwaypoints > 0) { sprite_t *s2; double oldx,oldy,xdiff,ydiff; if (s->timer1 == 0) { oldx = s->x; oldy = s->y; // move torwaeds next waypoints dstx = s->wayx[s->curwaypoint]; dsty = s->wayy[s->curwaypoint]; rv = moveto(s,dstx,dsty,s->speed,s->speed); // remember how far we moved xdiff = s->x - oldx; ydiff = s->y - oldy; // got there? if (rv == 0) { // pause s->timer1 = PLATFORMPAUSE; } // move anything on top of us by the same amount for (s2 = sprite ; s2 ; s2 = s2->next) { if (s2->onplatform == s) { int ii,oldmoved; double dir,amt; amt = abs(xdiff); if (xdiff > 0) dir = 1; else dir = -1; oldmoved = s2->moved; for (ii = 0; ii < amt; ii++) { //s2->x += dir; if (movex(s2, dir, B_TRUE)) break; } s2->moved = oldmoved; // so that we don't animate s2->y += ydiff; } } } else { s->timer1--; if (s->timer1 == 0) { // go to next waypoint s->curwaypoint++; if (s->curwaypoint >= s->numwaypoints) { s->curwaypoint = 0; } } } } } else if (s->id == P_TICK) { if (!s->falling) { int move = B_FALSE; int xdiff, absxdiff; /* distance to player */ xdiff = getxdisttoplayer(s, NULL); absxdiff = abs(xdiff); tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL); /* if there's a hole in front of us */ if (tt->solid == S_NOTSOLID) { double ycutoff = s->y + (TILEH/2); if ((player && (player->y >= ycutoff)) || (player2 && (player2->y >= ycutoff ))) { /* if player is below and nearby, fall off */ if (xdiff <= (TILEW*16)) { move = B_TRUE; } } else if ((player && (player->y == s->y)) || (player2 && (player2->y == s->y ))) { if (globpowerup != PW_CAMERA) { /* if player is at same level and close, jump */ if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) { jump(s,D_RIGHT); } else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) { jump(s,D_LEFT); } } } else if (level->bottomopen && (s->y >= (480 - 100)) && isplayerabove(s)) { // if near bottom of the screen and can fall through... move = B_TRUE; } } else { move = B_TRUE; } if (globpowerup == PW_CAMERA) { move = B_TRUE; } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } /* moves like an angry rat all the time */ if (globpowerup != PW_CAMERA) { if ((playersalive()) && (!s->jumping) && (!s->jumptimer)) { sprite_t *abovep; /* if player is above us...*/ abovep = isplayerabove(s); if (abovep) { if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { // if 2-3 tiles right /* jump right */ jump(s, D_RIGHT); } else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { // if 2-3 tiles left /* jump left */ jump(s, D_LEFT); } else if (s->y - abovep->y <= (TILEH*6)) { // player less than 6 tiles above if ((xdiff >= 0) && (xdiff < (TILEW*4))) { // ... and within 4 tiles /* jump up */ jump(s, 0); } else if ((xdiff <= 0) && (xdiff > -(TILEW*4))) { // ... and within 4 tiles /* jump up */ jump(s, 0); } } } } } } else { // falling movex(s, s->jumpdir*getspeed(s), B_TRUE); } } else if (s->id == P_WSPIDER) { // white spider - very intelligent! // timer3 is climb direction // timer2 is drop countdown if (!s->falling) { int move = B_FALSE; int xdiff, absxdiff; int ladderx = isladderabove(s); if (s->timer2) { int mod,mod2; mod = (s->timer2 / (WS_DROPDELAY/2)); s->timer2--; if (s->timer2 == 0) { // drop! /* drop down */ s->dropping = B_TRUE; s->dropx = s->x / TILEW; s->dropy = s->y / TILEH; } else { mod2 = (s->timer2 / (WS_DROPDELAY/2)); if (mod2 != mod) { // change direction if (s->dir == D_RIGHT) s->dir = D_LEFT; else if (s->dir == D_LEFT) s->dir = D_RIGHT; } } } /* distance to closest player */ xdiff = getxdisttoplayer(s, NULL); absxdiff = abs(xdiff); /* already climbing */ if (s->climbing) { // TODO: replace with just climbing the current dir if (s->timer3 == D_UP) { // climb up int ladderx = isladderabove(s); // if tile above is non-solid, or a ladder if (ladderx || !isroofabove(s)) { /* // lock to ladder if (ladderx) { s->x = ladderx; // lock to ladder } */ // continue climbing s->y -= getspeed(s); s->jumping = 0; s->falling = 0; s->climbing = B_TRUE; s->moved = MV_WALK; faceplayer(s); } else { s->climbing = B_FALSE; // face a player faceplayer(s); } } else { // down if (isonladder(s)) { if (isladderbelow(s)) { // climb down s->y += getspeed(s); s->jumping = 0; s->falling = 0; s->climbing = B_TRUE; s->moved = MV_WALK; faceplayer(s); } else { s->climbing = B_FALSE; faceplayer(s); } } } } else if (ladderx && isplayerabovegt(s,TILEW)) { // if we are at the bottom of a ladder // start climbing s->x = ladderx; // lock to ladder s->y -= getspeed(s); s->jumping = 0; s->falling = 0; s->climbing = B_TRUE; s->moved = MV_WALK; s->timer3 = D_UP; } else if (isonladder(s) && isplayerbelowgt(s,TILEW)) { // are we at top of ladder int ladderx = isonladder(s); if (isladderbelow(s)) { s->y += getspeed(s); s->jumping = 0; s->falling = 0; s->climbing = B_TRUE; s->moved = MV_WALK; // lock to centre of ladder s->x = ladderx; s->timer3 = D_DOWN; } else { s->climbing = B_FALSE; } } else if (!s->dropping && (s->timer2 == 0)) { /// not climbing - walk or drop down int willdrop = B_FALSE; s->climbing = B_FALSE; // drop down? if (isonbridge(s) && !s->falling) { int dist = 9999; /* player below (get the one with closest x distance)? */ if (player && !player->dead && player->y > s->y) dist = abs(player->x - s->x); if (player2 && !player2->dead && player2->y > s->y) { int dist2; dist2 = abs(player2->x - s->x); if (dist2 < dist) dist = dist2; } if (dist <= (TILEW*3)) { willdrop = B_TRUE; } } if (willdrop) { s->timer2 = WS_DROPDELAY; } else { // walk tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL); /* if there's a hole in front of us */ if (tt->solid == S_NOTSOLID) { double ycutoff = s->y + (TILEH/2); if ((player && (player->y >= ycutoff)) || (player2 && (player2->y >= ycutoff ))) { /* if player is below and nearby, fall off */ if (xdiff <= (TILEW*16)) { move = B_TRUE; } } else if ((player && (player->y == s->y)) || (player2 && (player2->y == s->y ))) { if (globpowerup != PW_CAMERA) { /* if player is at same level and close, jump */ if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) { jump(s,D_RIGHT); } else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) { jump(s,D_LEFT); } } } else if (level->bottomopen && (s->y >= (480 - 100)) && isplayerabove(s)) { // if near bottom of the screen and can fall through... move = B_TRUE; } } else { move = B_TRUE; } if (globpowerup == PW_CAMERA) { move = B_TRUE; } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } } } /* moves like an angry rat all the time */ if (globpowerup != PW_CAMERA) { if ((playersalive()) && (!s->jumping) && (!s->jumptimer)) { sprite_t *abovep; /* if player is within 5 tiles above us...*/ abovep = isplayerabovelt(s,TILEH*5); if (abovep) { if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { // if 2-3 tiles right /* jump right */ jump(s, D_RIGHT); } else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { // if 2-3 tiles left /* jump left */ jump(s, D_LEFT); } else if (s->y - abovep->y <= (TILEH*6)) { // player less than 6 tiles above if ((xdiff >= 0) && (xdiff < (TILEW*4))) { // ... and within 4 tiles /* jump up */ jump(s, 0); } else if ((xdiff <= 0) && (xdiff > -(TILEW*4))) { // ... and within 4 tiles /* jump up */ jump(s, 0); } } } } } } else { // falling movex(s, s->jumpdir*getspeed(s), B_TRUE); faceplayer(s); } } else if (s->id == P_BAT) { /* timer1 tracks state, timer2 tracks previous direction timer3 is current direction */ if (s->timer1 == BS_FLY) { if (s->timer3 == D_NONE) { int tx,ty; int d; int maxdist = -99; int newdir = D_NONE; tiletype_t *tt; // get current pos tt = gettileat(s->x,s->y-2,&tx,&ty); // pick a direction // scan each direction... for (d = 0; d < 4; d++) { int xm,ym,dir; if (d == 0) { dir = D_UP; xm = 0; ym = -1; } else if (d == 1) { dir = D_RIGHT; xm = 1; ym = 0; } else if (d == 2) { dir = D_DOWN; xm = 0; ym = 1; } else { // ie. d == 3 dir = D_LEFT; xm = -1; ym = 0; } // are we allowed to go this dir? if ((dir != s->timer2) && (dir != oppositedir(s->timer2))) { int curx,cury,hitwall=B_FALSE; int dist = 0; curx = tx; cury = ty; // check distance until wall while (!hitwall) { curx += xm; cury += ym; tt = gettilexy(curx, cury); if (tt->solid) hitwall = 1; if (curx <= 0) hitwall = 2; if (cury <= 0) hitwall = 3; if (curx >= LEVELW) hitwall = 4; if (cury >= LEVELH) hitwall = 5; dist++; } if (dist > maxdist) { newdir = dir; maxdist = dist; } } } // update our direction s->timer2 = s->timer3; // old dir s->timer3 = newdir; // current dir } else { // we DO have a current direction tiletype_t *tt; if (s->timer3 == D_UP) { tt = gettileat(s->x, s->y - s->img->h - getspeed(s), NULL, NULL); if (tt->solid || (s->y - s->img->h) <= TILEH) { // hit a wall s->timer1 = BS_PAUSE1; s->timer2 = s->timer3; // old dir s->timer3 = BAT_PAUSE; } else { s->moved = MV_FLY; s->y -= getspeed(s); } } else if (s->timer3 == D_DOWN) { tt = gettileat(s->x, s->y + getspeed(s), NULL, NULL); if (tt->solid) { // hit a wall s->timer1 = BS_PAUSE1; s->timer2 = s->timer3; // old dir s->timer3 = BAT_PAUSE; } else { s->moved = MV_FLY; s->y += getspeed(s); } } else { // right or left s->dir = s->timer3; if (movex(s, s->dir * getspeed(s), B_TRUE)) { // hit a wall s->timer1 = BS_PAUSE1; s->timer2 = s->timer3; // old dir s->timer3 = BAT_PAUSE; } else { s->moved = MV_FLY; } } } } else if (s->timer1 == BS_PAUSE1) { s->moved = MV_FLY; // wait for countdown... s->timer3--; if ((s->timer3 == BAT_FIRESPACE*2) || (s->timer3 == BAT_FIRESPACE) || (s->timer3 == 0)) { sprite_t *ss,*target = NULL; // closest player target = getclosestplayer(s); if (target) { double ang; // get angle towards target ang = atan2(target->y - s->y, target->x - s->x); // shoot playfx(FX_SONAR); ss = addsprite(P_SONAR,s->x,s->y - s->img->h/2,"bat_sonar" ); ss->xs = cos(ang) * getspeed(ss); ss->ys = sin(ang) * getspeed(ss); ss->timer1 = 0; } } if (s->timer3 == 0) { // go to next state s->timer1 = BS_PAUSE2; s->timer3 = BAT_PAUSE; } } else if (s->timer1 == BS_PAUSE2) { s->moved = MV_FLY; s->timer3--; if (s->timer3 == 0) { // go to next state s->timer1 = BS_FLY; s->timer3 = D_NONE; } } } else if (s->id == P_SNAKE) { /* timer1 loopsfrom 0 - 19 if timer2 is 0, we can shoot. if it is 1, we can't. */ // inc shooting timer if (s->timer1) { s->timer1--; if (s->timer1 == 0) { } } if (!s->falling) { int move = B_FALSE; int xdiff, absxdiff,ydiff; /* distance to player */ xdiff = getxdisttoplayer(s, NULL); absxdiff = abs(xdiff); tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL); /* if there's a hole in front of us */ if (tt->solid == S_NOTSOLID) { if (s->angry) { if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) { /* if player is below, fall off */ if (xdiff <= (TILEW*8)) { move = B_TRUE; } } else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) { if (s->angry) { /* if player is at same level and close, jump */ if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) { jump(s,D_RIGHT); } else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) { jump(s,D_LEFT); } } } else if (level->bottomopen && (s->y >= (480 - 100)) && isplayerabove(s)) { // if near bottom of the screen and can fall through... move = B_TRUE; } } } else { move = B_TRUE; } if (globpowerup == PW_CAMERA) { move = B_TRUE; } /* shoot */ ydiff = getydisttoplayer(s); ydiff = abs(ydiff); // if there's a player close up/down... if (ydiff <= (TILEH*4)) { sprite_t *ss; sprite_t *closeplayer; int shoot = B_FALSE; if (player && (s->y - player->y <= (TILEH*4)) ) { closeplayer = player; } else if (player2 && (s->y - player2->y <= (TILEH*4))) { closeplayer = player2; } else { closeplayer = NULL; } if (closeplayer) { if (s->bullet == NULL) { // if we don't already have a bullet // if we are facing the player if ( (closeplayer->x < s->x) && (s->dir == D_LEFT) ) { shoot = B_TRUE; } else if ( (closeplayer->x > s->x) && (s->dir == D_RIGHT) ) { shoot = B_TRUE; } } if (globpowerup == PW_CAMERA) shoot = B_FALSE; if (shoot) { // if our shooting timer is okay if (s->timer1 == 0) { playfx(FX_HISS); //ss = addsprite(P_SPIT,s->x,s->y - s->img->h/2,"spit" ); ss = addsprite(P_SPIT,s->x,s->y - TILEH,"spit" ); ss->ys = 0; ss->xs = s->dir * (getspeed(s)*2); ss->dir = s->dir; ss->owner = s; s->bullet = ss; // start timer for shooting again s->timer1 = 200; } } } } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } if (s->angry && (globpowerup != PW_CAMERA)) { if (playersalive() && (!s->jumping) && (!s->jumptimer)) { /* if player is above us, jump */ if ( (player && (!player->dead) && (player->y < s->y)) || (player2 && (!player2->dead) && (player2->y < s->y))) { if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { /* jump right */ jump(s, 1); } else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { /* jump left */ jump(s, -1); } else if ((player && (s->y - player->y <= (TILEH*6))) || (player2 && (s->y - player2->y <= (TILEH*6)))) { if ((xdiff >= 0) && (xdiff < (TILEW*2))) { /* jump up */ jump(s, 0); } else if ((xdiff <= 0) && (xdiff > -(TILEW*2))) { /* jump up */ jump(s, 0); } } else { /* jump whichever way we're facing */ /* s->jumpdir = s->dir; s->jumping = 1; s->jumpspeed = 5; */ } } } } } else { // falling movex(s, s->jumpdir*getspeed(s), B_TRUE); } } else if (s->id == P_BEE) { double absxs,absys; if ((s->xs == -99) || (s->ys == -99)) { s->xs = getspeed(s); s->ys = getspeed(s); } if (s->xs > 0) absxs = 1; else absxs = -1; if (s->ys > 0) absys = 1; else absys = -1; /* this will fix the speed if ANGRY is set */ s->xs = absxs*getspeed(s); s->ys = absys*getspeed(s); /* can we move? */ tt = gettileat(s->x + absxs*((s->img->w/2)+8), s->y-(s->img->h/2),NULL,NULL); if ((tt->solid) || (tt->spikes )) { /* turn */ s->xs = -s->xs; } tt = gettileat(s->x, s->y-(s->img->h/2) + absys*((s->img->h/2)+8),NULL,NULL); if ((tt->solid) || (tt->spikes)) { /* turn */ s->ys = -s->ys; } /* move */ s->x += s->xs; s->y += s->ys; s->dir = absxs; s->moved = MV_WALK; } else if (s->id == P_FLY) { // fly - like bee but more erratic flight and can walk on ground if player far away if (s->owner) { // move like king fly if (!s->invuln) { if (s->timer1 == KFS_HORZWAIT) { // hover s->y = s->owner->y; s->moved = MV_FLY; } else if (s->timer1 == KFS_VERTWAIT) { double ymod; // hover s->ys = 2; ymod = sin(((double)timer * (double)3.6) * (M_PI/180)); s->y += (s->ys * ymod); s->x = s->owner->x; s->moved = MV_FLY; } else if (s->timer1 == KFS_HORZPUSH) { // move towards target position if (s->timer2 > s->x) { s->x += (getspeed(s)*2); if (s->x > s->timer2) s->x = s->timer2; } else if (s->timer2 < s->x) { s->x -= (getspeed(s)*2); if (s->x < s->timer2) s->x = s->timer2; } s->moved = MV_FLY; } else if (s->timer1 == KFS_VERTPUSH) { // move towards target position if (s->timer2 > s->y) { s->y += (getspeed(s)*2); if (s->y > s->timer2) s->y = s->timer2; } else if (s->timer2 < s->y) { s->y -= (getspeed(s)*2); if (s->y < s->timer2) s->y = s->timer2; } s->moved = MV_FLY; } else { double absxs,absys; if ((s->xs == -99) || (s->ys == -99)) { s->xs = getspeed(s); s->ys = getspeed(s); } if (s->xs > 0) absxs = 1; else absxs = -1; if (s->ys > 0) absys = 1; else absys = -1; /* this will fix the speed if ANGRY is set */ s->xs = absxs*getspeed(s); s->ys = absys*getspeed(s); /* can we move? */ if (s->x >= 640 - (boss->img->w/2) - 2) { /* turn */ s->xs = -abs(s->xs); } else if (s->x <= (boss->img->w/2)) { s->xs = abs(s->xs); } if (s->y <= boss->img->h) { s->ys = abs(s->ys); } else if (s->y >= 480-2 ) { s->ys = -abs(s->ys); } /* move */ s->x += s->xs; s->y += s->ys; if (s->owner->timer1 == KFS_HORZWAIT) { // fly until we're level with owner if (abs((s->y-(s->img->h/2)) - (s->owner->y - (s->owner->img->h/2))) <= (s->img->h/2)) { // lock y s->timer1 = KFS_HORZWAIT; } } else if (s->owner->timer1 == KFS_VERTWAIT) { // fly until we're level with owner if (abs(s->x - s->owner->x) <= (s->img->w/2)) { // lock x s->timer1 = KFS_VERTWAIT; } } s->dir = absxs; s->moved = MV_FLY; } } } else { double absxs,absys; double xmod,ymod; if (s->flies) { if ((s->xs == -99) || (s->ys == -99)) { s->xs = getspeed(s); s->ys = -getspeed(s); } if (s->xs > 0) absxs = 1; else absxs = -1; if (s->ys > 0) absys = 1; else absys = -1; /* this will fix the speed if ANGRY is set */ s->xs = absxs*getspeed(s); s->ys = absys*getspeed(s); if (s->flies == F_FLYVERT) { ymod = sin(((double)timer * (double)3.6) * (M_PI/180)); //ymod *= 0.8; // XXX xmod = 0; if (s->ys * (ymod) > 0) absys = 1; else absys = -1; } else if (s->flies == F_FLYHORZ) { xmod = sin(((double)timer * (double)3.6) * (M_PI/180)); // XXX ymod = 0; if (s->xs * (xmod) > 0) absxs = 1; else absxs = -1; } else { xmod = 0; ymod = 0; } /* can we move? */ tt = gettileat(s->x + absxs*((s->img->w/2)+8), s->y-(s->img->h/2),NULL,NULL); if ((tt->solid) || (tt->spikes )) { /* turn */ s->xs = -s->xs; } tt = gettileat(s->x, s->y-(s->img->h/2) + absys*((s->img->h/2)+8),NULL,NULL); if ((tt->solid) || (tt->spikes)) { /* turn */ s->ys = -s->ys; } if (tt->water && !s->swimming) { /* turn */ s->ys = -s->ys; } /* move */ if (s->flies == F_FLYVERT) { s->x += s->xs; s->y += (s->ys * ymod); } else { s->x += (s->xs * xmod); s->y += s->ys; } s->dir = absxs; s->moved = MV_FLY; // inc flying timer s->timer1++; if (s->timer1 >= FLY_FLYTIME) { if (s->flies == F_FLYHORZ) { s->flies = F_FLYVERT; } else { s->flies = F_WALK; } s->timer1 = 0; } } else { // walking - move like a rat double myspeed = getspeed(s) * 0.75; double playerdist1,playerdist2,playerdist; if (!s->falling) { int move = B_FALSE; int xdiff, absxdiff; tiletype_t *tunder; /* distance to player */ xdiff = getxdisttoplayer(s, NULL); absxdiff = abs(xdiff); // tile in front and below tt = gettileat(s->x + s->dir*myspeed + (s->dir * (s->img->w/2)),s->y + (TILEH/2),NULL,NULL); // tile below tunder = gettileat(s->x ,s->y + 1,NULL,NULL); /* if there's a hole in front of us and below*/ if (tt->solid == S_NOTSOLID) { // we're on a slope if (tunder->solid == S_SLOPE) { move = B_TRUE; } } else { move = B_TRUE; } /* either move or turn around */ if (move) { rv = movex(s, s->dir*myspeed, B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } s->moved = MV_WALK; // take off if player is close if (player) { playerdist1 = getdistance(player->x,player->y,s->x,s->y); } else { playerdist1 = 9999; } if (player2) { playerdist2 = getdistance(player2->x,player2->y,s->x,s->y); } else { playerdist2 = 9999; } if (playerdist1 < playerdist2) { playerdist = playerdist1; } else { playerdist = playerdist2; } if (globpowerup != PW_CAMERA) { if (playerdist <= (TILEW*10)) { s->timer1 = 0; s->flies = F_FLYHORZ; s->xs = -99; s->ys = -99; } } // ...and take off eventually anyway s->timer1++; if (s->timer1 >= FLY_WALKTIME) { s->timer1 = 0; s->flies = F_FLYHORZ; s->xs = -99; s->ys = -99; } } else { // falling tiletype_t *tunder, *t2under; // tile below tunder = gettileat(s->x ,s->y,NULL,NULL); t2under = gettileat(s->x ,s->y+s->img->h,NULL,NULL); if ((tunder->solid == S_SLOPE) || (t2under->solid == S_SLOPE)) { movex(s, s->dir*myspeed, B_TRUE); // reset walk timer s->timer1 = 0; } // take off eventually // ...and take off eventually anyway, or if spikes underneath s->timer1++; if ((s->timer1 >= FLY_WALKTIME) || (t2under->spikes) || tunder->spikes) { s->timer1 = 0; s->flies = F_FLYHORZ; s->xs = -99; s->ys = -99; } } } } // end if s->owner } else if (s->id == P_FISH) { // very similar to bee double absxs,absys; // dies if not in water if (!isinwater(s)) { s->dead = D_FINAL; puffin(-1, s->x, s->y, "nothing", 0); } if ((s->xs == -99) || (s->ys == -99)) { s->xs = getspeed(s)*2; s->ys = getspeed(s); } if (s->xs > 0) absxs = 1; else absxs = -1; if (s->ys > 0) absys = 1; else absys = -1; /* this will fix the speed if ANGRY is set */ s->xs = absxs*getspeed(s)*2; s->ys = absys*getspeed(s); /* can we move? */ tt = gettileat(s->x + absxs*((s->img->w/2)+8), s->y-(s->img->h/2),NULL,NULL); if ((tt->solid) || (tt->spikes )) { /* turn */ s->xs = -s->xs; } tt = gettileat(s->x, s->y-(s->img->h/2) + absys*((s->img->h/2)+8),NULL,NULL); if ((tt->solid) || (tt->spikes) || !tt->water) { /* turn */ s->ys = -s->ys; } /* move */ s->x += s->xs; s->y += s->ys; s->dir = absxs; s->moved = MV_WALK; } else if (s->id == P_SPIDER) { /* timer1 loopsfrom 0 - 45 if timer2 is 0, we can shoot. if it is 1, we can't. */ if (s->timer1) { s->timer1--; } /* if on ground, go up */ if (!s->flies && (isonground(s) || (s->y >= (480-TILEH) ) )) { s->flies = B_TRUE; s->falling = B_FALSE; s->ys = -getspeed(s); } else if (s->falling) { /* if we are about to hit spikes, go back up */ tt = gettileat(s->x,s->y + 8,NULL,NULL); if (tt->spikes) { /* go back up */ s->flies = B_TRUE; s->falling = B_FALSE; s->ys = -getspeed(s); } } else { if (s->ys != -99) { /* if roof above us */ tt = gettileat(s->x,s->y - s->img->h,NULL,NULL); if (tt->solid) { int tiley; /* start walking again */ tiley = (int) (s->y / TILEH); s->y = tiley*TILEH; s->ys = -99; s->flies = B_TRUE; } else { s->y += s->ys; s->flies = B_TRUE; } } else { int move = B_FALSE; int xdiff; sprite_t *pp = NULL; /* walk back and forwards */ /* drop if player is close */ xdiff = getxdisttoplayer(s, &pp); xdiff = abs(xdiff); if (pp) { if ((pp->y > s->y) && (xdiff <= (TILEW*2)) && (s->timer1 == 0)) { s->timer1 = 200; s->flies = B_FALSE; s->falling = B_TRUE; s->fallspeed = 8; } else { int tx,ty; s->flies = B_TRUE; /* if there's a hole in front of us */ tt = gettileat(s->x + s->dir*((s->img->w/2)+2),s->y - s->img->h - 4,&tx,&ty); if (tt->solid == S_NOTSOLID) { move = B_FALSE; } else { move = B_TRUE; } /* either move or turn around */ if (move) { rv = movex(s, s->dir*getspeed(s), B_TRUE); if (rv) { /* if we couldn't move (hit a wall), turn */ s->dir = -s->dir; } } else { s->dir = -s->dir; } } } } } } else if ((s->id == P_SPIT) || (s->id == P_FIREBALL)) { if (movex(s, s->xs, B_TRUE)) { s->dead = D_FINAL; } } else if (s->id == P_BIGFIREBALL) { tiletype_t *tt; int yyy,tx,ty; // move s->x += s->xs; // melt any ice bridges it touches for (yyy = s->y - s->img->h ; yyy < s->y ; yyy += 4) { tt = gettileat(s->x + (s->img->w/2),yyy, &tx,&ty); if (isbridge(tt->id)) { melttile(tx,ty,REGROWTIMER_SHORT); } } // die if it leaves screen if (s->x >= (640-TILEW)) { s->dead = D_FINAL; } else if (s->x <= TILEW) { s->dead = D_FINAL; } } else if (s->id == P_SONAR) { // timer1 = frame // update frame if ((timer % 5) == 0) { s->timer1++; if (s->timer1 >= imageset[P_SONAR].numimages) { s->timer1 = 0; } } // move s->x += s->xs; s->y += s->ys; // die if it leaves screen if (s->x >= (640-TILEW)) { s->dead = D_FINAL; } else if (s->x <= TILEW) { s->dead = D_FINAL; } else if (s->y >= (480+(s->img->h))) { s->dead = D_FINAL; } else if (s->y <= TILEH) { s->dead = D_FINAL; } } else if (s->id == P_RAYGUNBULLET) { s->x += s->xs; if (s->x >= (640-TILEW)) { s->dead = D_FINAL; } else if (s->x <= TILEW) { s->dead = D_FINAL; } } else if (s->id == P_PINKCLOUD) { if (s->timer1 == LV_CLOUD) { SDL_Surface *ts; double targx,targy; double amtleft; double xdis,ydis,dis; int turnsleft; if (s->owner->dead) { if (s->owner->lives <= 0) { // out of the game // no use for us anymore... s->dead = D_FINAL; } } else { /* If small, grow and move towards player's feet (at a speed which will get us there when we are fully grown. */ targx = s->owner->x; targy = s->owner->y + (imageset[P_PINKCLOUD].img[F_WALK1]->h / 2); if (s->img->w < imageset[P_PINKCLOUD].img[F_WALK1]->w) { // grow s->size += ((double)PCGROWSPEED); ts = rotozoomSurfaceXY(imageset[P_PINKCLOUD].img[F_WALK1],0, s->size, s->size,0); SDL_FreeSurface(s->img); s->img = ts; } // calculate number of turns left amtleft = 1.0 - s->size; // amount left turnsleft = (int) (amtleft / (double)PCGROWSPEED); if (turnsleft < 1) { // make sure we're in the right place s->x = targx; s->y = targy; s->rotated = 0; s->timer1 = LV_CLOUDLOOP; // stop the player teleporting if required if (s->owner->teleporting) { stopteleporting(s->owner); } // mark the player as on top of us s->owner->oncloud = B_TRUE; } else { // calculate distance to player xdis = abs(targx - s->x); ydis = abs(targy - s->y); dis = sqrt((xdis*xdis) + (ydis*ydis)); // calculate speed needed to reach player x/y in time s->speed = dis / turnsleft; // figure out angle to player s->angle = atan2(targy - s->y, targx - s->x); // keep between 0 and 360 if (s->angle > (360*(M_PI/180))) { s->angle -= (360*(M_PI/180)); } if (s->angle < 0) { s->angle += (360*(M_PI/180)); } // figure out x/y speed s->xs = (cos(s->angle) * s->speed); s->ys = (sin(s->angle) * s->speed); //printf("cloud: amtleft = %0.2f (1.0 - ssize=%0.2f)",amtleft,s->size); // printf("cloud: speed = %0.2f, xdis=%0.2f,ydis=%0.2f,dis=%0.2f, turnsleft=%d,xs=%0.2f,ys=%0.2f\n",speed,xdis,ydis,dis,turnsleft,s->xs,s->ys); // move s->x += s->xs; s->y += s->ys; // keep on screen!! keeponscreen(s); } } } else if (s->timer1 == LV_CLOUDLOOP) { // make sure we are on the screen!! // should never happen, but... if (s->x < 0) s->x = 320; if (s->y < 0) s->y = 240; if (s->x >= 640) s->x = 320; if (s->y >= 480) s->y = 240; // stick player to us s->owner->x = s->x; s->owner->y = s->y - (imageset[P_PINKCLOUD].img[F_WALK1]->h / 2); // turn off player attributes s->owner->climbing = B_FALSE; s->owner->netting = B_FALSE; s->owner->slamming = B_FALSE; s->owner->jumping = B_FALSE; // keep turning towards exit (2 degrees at a time) s->angle += (PCTURN * (M_PI/180)); // keep between 0 and 360 if (s->angle > (360*(M_PI/180))) { s->angle -= (360*(M_PI/180)); } if (s->angle < 0) { s->angle += (360*(M_PI/180)); } // track total rotation s->rotated += (PCTURN * (M_PI/180)); if (s->angle < (270 * (M_PI/180))) { // decellerate if (s->speed > 5) { s->speed -= 1; } } else { // accellerate if (s->speed < 10) { s->speed += 0.5; } } // figure out x/y speed s->xs = (cos(s->angle) * s->speed); s->ys = (sin(s->angle) * s->speed); // move s->x += s->xs; s->y += s->ys; // keep on screen (but use player height if (s->x > 640-(s->img->w/2)) { s->x = 640 - (s->img->w/2); } if (s->y > 480-(s->img->h/2)) { s->y = 480 - (s->img->h/2); } if (s->x < s->img->w/2) { s->x = s->img->w/2; } if (s->y < s->owner->img->h/2) { s->y = s->owner->img->h/2; } // if we've done at least one revolution if (s->rotated >= 360 * (M_PI/180)) { // done one revolution sprite_t *c; int ready = B_TRUE; // and other cloud is finished or dead... for (c = sprite ; c ; c = c->next) { if ((c->id == P_PINKCLOUD) && (c->timer1 != LV_CLOUDLOOP) && (c->owner->lives > 0)) { ready = B_FALSE; } } if (ready) { // level clear! levelcomplete = LV_NEXTLEV; } return B_TRUE; } } else if ((levelcomplete == LV_INIT) || (levelcomplete == LV_INPROGRESS)) { SDL_Surface *ts; // shrink s->size -= ((double)PCSHRINKSPEED); if (s->size <= 0.1) { s->dead = D_FINAL; } else { ts = rotozoomSurfaceXY(imageset[P_PINKCLOUD].img[F_WALK1],0, s->size, s->size,0); SDL_FreeSurface(s->img); s->img = ts; } // move up slightly s->y -= PCSHRINKSPEED; } } else if (s->id == P_BLACKCLOUD) { if ((player && player->dead) || (player2 && player2->dead) || (levelcomplete)) { if (s->size <= 0.2) { s->dead = D_FINAL; /* reset hurryup timer */ resethurryup(curlevel); } else { SDL_Surface *ts, *cloudim; //printf("shrink\n"); if (s->angry) { cloudim = imageset[P_BLACKCLOUD].img[MAXFRAMES*2]; } else { cloudim = imageset[P_BLACKCLOUD].img[0]; } /* get smaller */ s->size -= 0.1; ts = rotozoomSurfaceXY(cloudim,0,s->size, s->size, 0); //ts = rotozoomSurfaceXY(s->img,0, 0.9 , 0.9 ,0); SDL_FreeSurface(s->img); // free old image s->img = ts; s->y--; } } else { if (!s->invuln) { if ((s->xs == -99) || (s->ys == -99)) { if (isplayerabove(s)) { s->ys = -0.5; } else { s->ys = 0.5; } if (isplayerright(s)) { s->xs = 1; } else { s->xs = -1; } } s->x += s->xs; s->y += s->ys; if (s->x >= (640 - s->img->w/2)) { s->xs = -s->xs; s->x = 640 - s->img->w/2; } if (s->x <= (s->img->w/2)) { s->xs = -s->xs; s->x = s->img->w/2; } //if (s->y >= (480 - s->img->h)) { if (s->y >= 480-1) { s->ys = -s->ys; //s->y = 480 - s->img->h; s->y = 480-1; } if (s->y <= (s->img->h)) { s->ys = -s->ys; s->y = s->img->h; } //if (timer % CLOUDGROWSPEED == 0) { if (1) { double growamt; //int w,h; SDL_Surface *ts, *cloudim; if (s->angry) { cloudim = imageset[P_BLACKCLOUD].img[MAXFRAMES*2]; } else { cloudim = imageset[P_BLACKCLOUD].img[0]; } //w = s->img->w; //h = s->img->h; //ts = rotozoomSurfaceXY(s->img,0, 1.1 , 1.1 ,0); growamt = ((double)CLOUDGROWAMT / (double)CLOUDGROWSPEED); s->size += growamt; //printf("grow, now %0.2f\n",s->size); // TODO: free old first? depends if we ever use a preset one ts = rotozoomSurfaceXY(cloudim,0,s->size, s->size, 0); SDL_FreeSurface(s->img); s->img = ts; s->y += growamt; } } // end if !s->invuln } } else if (haspowerupany(PW_MAGNET) && isfruit(s->id)) { sprite_t *who; who = haspowerupany(PW_MAGNET); if (abs(who->y - s->y) <= (TILEH)) { double dis; double spd; dis = abs(who->x - s->x); // ie. 0 - 640 if (dis <= 320) { spd = dis / 45; // ie. 0 - 10 // now reverse it (so the closer it is, the faster it goes) spd = 7 - spd; if (spd > 7) spd = 7; if (who->x > s->x) { movex(s, spd, B_FALSE); } else if (who->x < s->x) { movex(s, -spd, B_FALSE); } } } } else if (haspowerupany(PW_BADMAGNET) && isfruit(s->id)) { sprite_t *who; who = haspowerupany(PW_BADMAGNET); if (abs(who->y - s->y) <= (TILEH)) { double dis; double spd; dis = abs(who->x - s->x); // ie. 0 - 640 if (dis <= 320) { spd = dis / 45; // ie. 0 - 10 // now reverse it (so the closer it is, the faster it goes) spd = 7 - spd; if (spd > 7) spd = 7; if (who->x > s->x) { movex(s, -spd, B_TRUE); } else if (who->x < s->x) { movex(s, spd, B_TRUE); } } } } return B_FALSE; } void dotileeffects(sprite_t *s) { tiletype_t *tt; int finished = B_FALSE; int state = 0; int tilex,tiley; if (!s) return; if (iseffect(s->id) || isbullet(s->id)) { return; } if (s->jumping || s->dead || s->caughtby) { return; } // no tile effects for machine gun if (haspowerupany(PW_GUNNER)) { if (isplayer(s)) { return; } } /* check where we are */ tt = gettileat(s->x,s->y-2,&tilex,&tiley); // teleporters if ((tt->id == T_TELEPORT) || (tt->id == T_TELEPORT2)) { //if (!isendoflev()) { // can't enter teleporters after level end to avoid cloud moving too far if (isplayer(s) || ismonster(s->id)) { if (s->id != P_BLACKCLOUD) { if (!s->teleporting) { playfx(FX_TELEPORT); s->teleporting = 1; } } } // } } /* check on top of us */ tt = gettileat(s->x,s->y-(s->img->h/2),&tilex,&tiley); switch (tt->id) { case T_WATERRIGHT: if (!ismonster(s->id) && !isfruit(s->id)) { movex(s, 1.5, B_TRUE); } else if (s->id == P_PLANT) { movex(s, 1.5, B_TRUE); } break; case T_WATERLEFT: if (!ismonster(s->id) && !isfruit(s->id)) { movex(s, -1.5, B_TRUE); } else if (s->id == P_PLANT) { movex(s, -1.5, B_TRUE); } break; case T_WATERDOWN: if (!ismonster(s->id) && !isfruit(s->id)) { s->y += 1.5; } else if (s->id == P_PLANT) { s->y += 1.5; } break; } /* check under us */ tt = gettileat(s->x,s->y+3,&tilex,&tiley); // CHECKS WHICH COULD APPLY TO TILES UNDER AND SLIGHTLY LEFT/RIGHT OF US while (!finished) { if (tt->id == T_RIGHT) { if (globpowerup != PW_CLOCK) { if (!ismonster(s->id) && !isfruit(s->id)) { movex(s, 1.5, B_FALSE); } else if (s->id == P_PLANT) { movex(s, 1.5, B_FALSE); } } finished = B_TRUE; } else if (tt->id == T_LEFT) { if (globpowerup != PW_CLOCK) { if (!ismonster(s->id) && !isfruit(s->id)) { movex(s, -1.5, B_FALSE); } else if (s->id == P_PLANT) { movex(s, -1.5, B_FALSE); } } finished = B_TRUE; } else if (isice(tt->id)) { if (isplayer(s) && !isinwater(s)) { if (globpowerup != PW_CLOCK) { if (!s->moved) { if (s->xs != 0) { // slide along the ground movex(s, s->xs, B_FALSE); // slow down if (s->xs > 0) { s->xs -= ICEDECCEL; if (s->xs < 0) s->xs = 0; } else if (s->xs < 0) { s->xs += ICEDECCEL; if (s->xs > 0) s->xs = 0; } } } } } finished = B_TRUE; } else if (tt->spikes) { if (!isfruit(s->id) ) { if (!s->invuln) { if ((s->id != P_BLACKCLOUD) && (s->id != P_KINGSNAIL)) { die(s); printf("DB: killed by spikes\n"); fflush(stdout); } } } finished = B_TRUE; } else if (tt->id == T_TRAMPUP) { /* tile changes to trampoline down */ //if (!isfruit(s->id) && !iseffect(s->id) && !isbullet(s->id)) { if (isplayer(s)) { // are we on a trampoline already? if (s->ontramp) { // a different one? if ((s->trampx != tilex) || (s->trampy != tiley)) { // if a different one, release it if (s->tramplayer == 1) { curlevel->map[s->trampy * LEVELW + s->trampx] = getuniq(T_TRAMPUP); } else { curlevel->map2[s->trampy * LEVELW + s->trampx] = getuniq(T_TRAMPUP); } drawtile(temps, s->trampx, s->trampy); } } else { tiletype_t *temptile; // remember we were on it so it can release s->ontramp = B_TRUE; s->trampx = tilex; s->trampy = tiley; // which layer was it on? temptile = gettile(curlevel->map2[s->trampy*LEVELW+s->trampx]); if (temptile->id == T_TRAMPUP) { s->tramplayer = 2; } else { s->tramplayer = 1; } // move it down then draw it if (s->tramplayer == 1) { curlevel->map[tiley*LEVELW+tilex] = getuniq(T_TRAMPDOWN); } else { curlevel->map2[tiley*LEVELW+tilex] = getuniq(T_TRAMPDOWN); } drawtile(temps, tilex, tiley); } } finished = B_TRUE; } else if (tt->id == T_TRAMPDOWN) { // don't keep checking tiles left/right finished = B_TRUE; } else { if (state == 0) { /* check tile to our right */ tt = gettileat(s->x + s->img->w/2,s->y+3,&tilex,&tiley); state = 1; } else if (state == 1) { /* check tile to our left */ tt = gettileat(s->x - s->img->w/2,s->y+3,&tilex,&tiley); state = 2; } else { finished = B_TRUE; } } } } // initial transition to a new level void drawlevel(void) { int x,y,i; int dstx[2],dsty[2],xdis[2],ydis[2]; double turns; double pspeed[2]; double dist[2]; SDL_Rect area,dst; int speed = 16; SDL_Surface *playerbg = NULL, *playerbg2 = NULL; SDL_Surface *cloudbg = NULL,*cloudbg2 = NULL; int got1p = B_FALSE,got2p = B_FALSE; sprite_t tempcloud, tempcloud2; sprite_t *cloud = NULL, *cloud2 = NULL; if (temps) { SDL_FreeSurface(temps); temps = NULL; } temps = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, screen->format->Amask); SDL_DisplayFormat(temps); if (player && player->lives > 0) got1p = B_TRUE; if (player2 && player2->lives > 0) got2p = B_TRUE; if (!got1p && !got2p) { // ERROR!! printf("trying to transition level with no players!!\n "); return; } // init clouds if (got1p) { cloud = &tempcloud; cloud->id = P_PINKCLOUD; cloud->iceimg = NULL; setdefaults(cloud); // redo image cloud->img =rotozoomSurfaceXY(imageset[P_PINKCLOUD].img[F_WALK1],0,1,1,0); // set player image player->img = imageset[player->id].img[F_SHOOT]; // create buffer for player background playerbg = SDL_CreateRGBSurface(SDL_SWSURFACE, player->img->w+1, player->img->h+1, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, screen->format->Amask); SDL_DisplayFormat(playerbg); // create buffer for cloud background cloudbg = SDL_CreateRGBSurface(SDL_SWSURFACE, cloud->img->w+1, cloud->img->h+1, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, screen->format->Amask); SDL_DisplayFormat(cloudbg); } if (got2p) { cloud2 = &tempcloud2; cloud2->id = P_PINKCLOUD; cloud2->iceimg = NULL; setdefaults(cloud2); // redo image cloud2->img =rotozoomSurfaceXY(imageset[P_PINKCLOUD].img[F_WALK1],0,1,1,0); // set player image player2->img = imageset[player2->id].img[F_SHOOT]; // create buffer for player background playerbg2 = SDL_CreateRGBSurface(SDL_SWSURFACE, player2->img->w+1, player2->img->h+1, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, screen->format->Amask); SDL_DisplayFormat(playerbg2); // create buffer for cloud background cloudbg2 = SDL_CreateRGBSurface(SDL_SWSURFACE, cloud2->img->w+1, cloud2->img->h+1, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, screen->format->Amask); SDL_DisplayFormat(cloudbg2); } // draw the full level onto the temporary surface for (x = 0; x < LEVELW; x++) { for (y = 0; y < LEVELH; y++) { drawtile(temps,x,y); } } // initialise values so we don't accidentally use them // uninitialied... for (i = 0; i < 2; i++) { dstx[i] = 0; dsty[i] = 0; xdis[i] = 0; ydis[i] = 0; pspeed[i] = 1; } // figure out where the players' new start positions are if (player) { dstx[0] = (curlevel->p1x * TILEW) + (TILEW/2); dsty[0] = (curlevel->p1y * TILEH) + TILEH-2; } if (player2) { dstx[1] = (curlevel->p2x * TILEW) + (TILEW/2); dsty[1] = (curlevel->p2y * TILEH) + TILEH-2; } // figure out distance to newposition if (player) { xdis[0] = player->x - dstx[0]; if (xdis[0] < 0) xdis[0] = -xdis[0]; ydis[0] = player->y - dsty[0]; if (ydis[0] < 0) ydis[0] = -ydis[0]; } if (player2) { xdis[1] = player2->x - dstx[1]; if (xdis[1] < 0) xdis[1] = -xdis[1]; ydis[1] = player2->y - dsty[1]; if (ydis[1] < 0) ydis[1] = -ydis[1]; } // figure out how many loops it will take to scroll to the next level switch (oldexitdir) { case D_LEFT: case D_RIGHT: speed = 16; turns = 640 / speed; break; case D_UP: case D_DOWN: default: speed = 12; turns = 480 / speed; break; } //turns -= 2; // just to be safe if (turns < 1) turns = 1; // figure out how fast player needs to move to get there in time if (player) { dist[0] = sqrt((xdis[0]*xdis[0]) + (ydis[0]*ydis[0])); pspeed[0] = dist[0] / turns; } if (player2) { dist[1] = sqrt((xdis[1]*xdis[1]) + (ydis[1]*ydis[1])); pspeed[1] = dist[1] / turns; } // just to be sure //pspeed += 1; if (oldexitdir == D_LEFT) { // blit a column at a time to the real screen, shuffling // the real one along. for (x = 0; x < 640; x += speed) { // move player if (player && player->lives > 0) moveto(player,dstx[0],dsty[0],pspeed[0],pspeed[0]); if (player2 && player2->lives > 0) moveto(player2,dstx[1],dsty[1],pspeed[1],pspeed[1]); // set cloud location if (player && player->lives > 0) { cloud->x = player->x; cloud->y = player->y + (cloud->img->h / 2); } if (player2 && player2->lives > 0) { cloud2->x = player2->x; cloud2->y = player2->y + (cloud2->img->h / 2); } // shuffle real screen area.x = 0; area.y = 0; area.w = 640-speed; area.h = 480; dst.x = speed; dst.y = 0; dst.w = 0; dst.h = 0; SDL_BlitSurface(screen, &area, screen, &dst); // blit next column from temp surface (take last column first) area.x = 640-x; area.y = 0; area.w = speed; area.h = 480; dst.x = 0; dst.y = 0; dst.w = 0; dst.h = 0; SDL_BlitSurface(temps, &area, screen, &dst); // remember area behind players if (player && player->lives > 0) { player->img = imageset[player->id].img[F_SHOOT]; grabbehind(player, playerbg); grabbehind(cloud, cloudbg); } if (player2 && player2->lives > 0) { player2->img = imageset[player2->id].img[F_SHOOT]; grabbehind(player2, playerbg2); grabbehind(cloud2, cloudbg2); } // draw player if (curlevelnum != INTRO_LEVELNUM) { if (player && player->lives > 0) { drawsprite(player); drawsprite(cloud); } if (player2 && player2->lives > 0) { drawsprite(player2); drawsprite(cloud2); } } // update screen //SDL_GL_SwapBuffers(); SDL_UpdateRect(screen, 0,0,640,480); if (!paused) { SDL_framerateDelay(&manager); } // remove players if (curlevelnum != INTRO_LEVELNUM) { if (player && player->lives > 0) { area.x = player->x - player->img->w/2; area.y = player->y - player->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(playerbg, NULL, screen, &area ); area.x = cloud->x - cloud->img->w/2; area.y = cloud->y - cloud->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(cloudbg, NULL, screen, &area ); } if (player2 && player2->lives > 0) { area.x = player2->x - player2->img->w/2; area.y = player2->y - player2->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(playerbg2, NULL, screen, &area ); area.x = cloud2->x - cloud2->img->w/2; area.y = cloud2->y - cloud2->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(cloudbg2, NULL, screen, &area ); } } } } else if (oldexitdir == D_UP) { // blit a row at a time to the real screen, shuffling // the real one along. for (y = 0; y < 480; y += speed) { // move player if (player && player->lives > 0) moveto(player,dstx[0],dsty[0],pspeed[0],pspeed[0]); if (player2 && player2->lives > 0) moveto(player2,dstx[1],dsty[1],pspeed[1],pspeed[1]); // set cloud location if (player && player->lives > 0) { cloud->x = player->x; cloud->y = player->y + (cloud->img->h / 2); } if (player2 && player2->lives > 0) { cloud2->x = player2->x; cloud2->y = player2->y + (cloud2->img->h / 2); } // shuffle real screen area.x = 0; area.y = 0; area.w = 640; area.h = 480-speed; dst.x = 0; dst.y = speed; dst.w = 0; dst.h = 0; SDL_BlitSurface(screen, &area, screen, &dst); // blit next row from temp surface (take last column first) area.x = 0; area.y = 480-y; area.w = 640; area.h = speed; dst.x = 0; dst.y = 0; dst.w = 0; dst.h = 0; SDL_BlitSurface(temps, &area, screen, &dst); // remember area behind player if (player && player->lives > 0) { player->img = imageset[player->id].img[F_SHOOT]; grabbehind(player, playerbg); grabbehind(cloud, cloudbg); } if (player2 && player2->lives > 0) { player2->img = imageset[player2->id].img[F_SHOOT]; grabbehind(player2, playerbg2); grabbehind(cloud2, cloudbg2); } // draw player if (curlevelnum != INTRO_LEVELNUM) { if (player && player->lives > 0) { drawsprite(player); drawsprite(cloud); } if (player2 && player2->lives > 0) { drawsprite(player2); drawsprite(cloud2); } } // update screen //SDL_GL_SwapBuffers(); SDL_UpdateRect(screen, 0,0,640,480); if (!paused) SDL_framerateDelay(&manager); // remove players if (curlevelnum != INTRO_LEVELNUM) { if (player && player->lives > 0) { area.x = player->x - player->img->w/2; area.y = player->y - player->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(playerbg, NULL, screen, &area ); area.x = cloud->x - cloud->img->w/2; area.y = cloud->y - cloud->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(cloudbg, NULL, screen, &area ); } if (player2 && player2->lives > 0) { area.x = player2->x - player2->img->w/2; area.y = player2->y - player2->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(playerbg2, NULL, screen, &area ); area.x = cloud2->x - cloud2->img->w/2; area.y = cloud2->y - cloud2->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(cloudbg2, NULL, screen, &area ); } } } } else if (oldexitdir == D_DOWN) { // blit a row at a time to the real screen, shuffling // the real one along. for (y = 0; y < 480; y += speed) { // move player if (player && player->lives > 0) moveto(player,dstx[0],dsty[0],pspeed[0],pspeed[0]); if (player2 && player2->lives > 0) moveto(player2,dstx[1],dsty[1],pspeed[1],pspeed[1]); // set cloud location if (player && player->lives > 0) { cloud->x = player->x; cloud->y = player->y + (cloud->img->h / 2); } if (player2 && player2->lives > 0) { cloud2->x = player2->x; cloud2->y = player2->y + (cloud2->img->h / 2); } // shuffle real screen area.x = 0; area.y = speed; area.w = 640; area.h = 480-speed; dst.x = 0; dst.y = 0; dst.w = 0; dst.h = 0; SDL_BlitSurface(screen, &area, screen, &dst); // blit next row from temp surface (take last column first) area.x = 0; area.y = y; area.w = 640; area.h = speed; dst.x = 0; dst.y = 480-speed; dst.w = 0; dst.h = 0; SDL_BlitSurface(temps, &area, screen, &dst); // remember area behind players if (player && player->lives > 0) { player->img = imageset[player->id].img[F_SHOOT]; grabbehind(player, playerbg); grabbehind(cloud, cloudbg); } if (player2 && player2->lives > 0) { player2->img = imageset[player2->id].img[F_SHOOT]; grabbehind(player2, playerbg2); grabbehind(cloud2, cloudbg2); } // draw player if (curlevelnum != INTRO_LEVELNUM) { if (player && player->lives > 0) { drawsprite(player); drawsprite(cloud); } if (player2 && player2->lives > 0) { drawsprite(player2); drawsprite(cloud2); } } // update screen //SDL_GL_SwapBuffers(); SDL_UpdateRect(screen, 0,0,640,480); if (!paused) SDL_framerateDelay(&manager); // remove players if (curlevelnum != INTRO_LEVELNUM) { if (player && player->lives > 0) { area.x = player->x - player->img->w/2; area.y = player->y - player->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(playerbg, NULL, screen, &area ); area.x = cloud->x - cloud->img->w/2; area.y = cloud->y - cloud->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(cloudbg, NULL, screen, &area ); } if (player2 && player2->lives > 0) { area.x = player2->x - player2->img->w/2; area.y = player2->y - player2->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(playerbg2, NULL, screen, &area ); area.x = cloud2->x - cloud2->img->w/2; area.y = cloud2->y - cloud2->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(cloudbg2, NULL, screen, &area ); } } } } else { // RIGHT right, or default // blit a column at a time to the real screen, shuffling // the real one along. for (x = 0; x < 640; x += speed) { // move player if (player && player->lives > 0) moveto(player,dstx[0],dsty[0],pspeed[0],pspeed[0]); if (player2 && player2->lives > 0) moveto(player2,dstx[1],dsty[1],pspeed[1],pspeed[1]); // set cloud location if (player && player->lives > 0) { cloud->x = player->x; cloud->y = player->y + (cloud->img->h / 2); } if (player2 && player2->lives > 0) { cloud2->x = player2->x; cloud2->y = player2->y + (cloud2->img->h / 2); } // shuffle real screen area.x = speed; area.y = 0; area.w = 640-speed; area.h = 480; dst.x = 0; dst.y = 0; dst.w = 0; dst.h = 0; SDL_BlitSurface(screen, &area, screen, &dst); // blit next column from temp surface (take last column first) area.x = x; area.y = 0; area.w = speed; area.h = 480; dst.x = 640-speed; dst.y = 0; dst.w = 0; dst.h = 0; SDL_BlitSurface(temps, &area, screen, &dst); // remember area behind players if (player && player->lives > 0) { player->img = imageset[player->id].img[F_SHOOT]; grabbehind(player, playerbg); grabbehind(cloud, cloudbg); } if (player2 && player2->lives > 0) { player2->img = imageset[player2->id].img[F_SHOOT]; grabbehind(player2, playerbg2); grabbehind(cloud2, cloudbg2); } // draw player if (curlevelnum != INTRO_LEVELNUM) { if (player && player->lives > 0) { drawsprite(player); drawsprite(cloud); } if (player2 && player2->lives > 0) { drawsprite(player2); drawsprite(cloud2); } } // update screen //SDL_GL_SwapBuffers(); SDL_UpdateRect(screen, 0,0,640,480); if (!paused) SDL_framerateDelay(&manager); // remove players if (curlevelnum != INTRO_LEVELNUM) { if (player && player->lives > 0) { area.x = player->x - player->img->w/2; area.y = player->y - player->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(playerbg, NULL, screen, &area ); area.x = cloud->x - cloud->img->w/2; area.y = cloud->y - cloud->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(cloudbg, NULL, screen, &area ); } if (player2 && player2->lives > 0) { area.x = player2->x - player2->img->w/2; area.y = player2->y - player2->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(playerbg2, NULL, screen, &area ); area.x = cloud2->x - cloud2->img->w/2; area.y = cloud2->y - cloud2->img->h; area.w = 0; area.h = 0; SDL_BlitSurface(cloudbg2, NULL, screen, &area ); } } } } if (player && player->lives > 0) { SDL_FreeSurface(playerbg); SDL_FreeSurface(cloudbg); SDL_FreeSurface(cloud->img); } if (player2 && player2->lives > 0) { SDL_FreeSurface(playerbg2); SDL_FreeSurface(cloudbg2); SDL_FreeSurface(cloud2->img); } levelcomplete = B_FALSE; } double getspeed(sprite_t *s ) { int id = s->id; double speed = 1; if (s == player) { if (haspowerup(s, PW_PILL)) { speed = PLAYERPILL; } else { speed = s->speed; } } else if (s == player2) { speed = s->speed; } else if (id == P_SNAIL) { if (s->recoiling) { speed = 2; } else { if (s->angry) speed = 1; else speed = 0.5; } } else if (id == P_SLUG) { if (s->angry) speed = 1; else speed = 0.5; if (s->jumping) { speed = 8; // very fast jumping } } else if (id == P_FROG) { if (s->angry) speed = 1.5; else speed = 1; } else if (id == P_RAT) { if (s->angry) speed = 1.5; else speed = 1; } else if (id == P_WSPIDER) { if (s->angry) speed = 1.5; else speed = 1; } else if (id == P_ANT1) { if (s->angry) speed = 1.5; else speed = 1; } else if (id == P_ANT2) { if (s->angry) speed = 2.5; else speed = 2; } else if (id == P_ANT3) { if (s->angry) speed = 2.5; else speed = 2; } else if (id == P_SNAKE) { if (s->angry) speed = 1.5; else speed = 1; } else if (id == P_BEE) { if (s->angry) speed = 2; else speed = 1; } else if (id == P_FLY) { if (s->owner) { speed = 2; } else { if (s->angry) speed = 2.5; else speed = 1.5; } } else if (id == P_SPIDER) { if (s->angry) speed = 2; else speed = 1.5; } else if (id == P_BAT) { if (s->angry) speed = 3; else speed = 2.5; } else if (id == P_SONAR) { speed = 2.5; } else if (id == P_KINGRAT) { speed = 1.5; } else if (id == P_KINGANT) { speed = 1.5; } else if (id == P_KINGFLY) { speed = 2; } else if (id == P_PLATFORM) { speed = PLATFORM_MAXSPEED; } if (isinwater(s) && (s->id != P_FISH) && (s->id != P_FROG)) { if (!s->hasmask) { speed /= 2; } } if ((globpowerup == PW_SPRAYUP) || (globpowerup == PW_SPRAYDOWN)) { if (!isplayer(s)) { speed /= 2; } } return speed; } int addtext(int x, int y, int size, char *string, SDL_Color *c, int delay, int ttype) { text_t *t; if (text == NULL) { text = malloc(sizeof(text_t)); t = text; t->prev = NULL; } else { t = lasttext; t->next = malloc(sizeof(text_t)); t->next->prev = t; t = t->next; } t->bg = SDL_CreateRGBSurface(SDL_SWSURFACE, 300, 110, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, screen->format->Amask); t->type = ttype; t->c = c; t->x = x; t->y = y; t->maxsize = size; t->size = 3; strcpy(t->txt, string); t->state = 0; t->delay = delay; t->img = TTF_RenderText_Solid(font[t->size], t->txt, *t->c); if (t->img == NULL) { printf("rendertext failed for '%s'\n", t->txt); fflush(stdout); } t->next = NULL; lasttext = t; return B_FALSE; } void movetext(void) { text_t *t,*nextt; int newhelpfreeze = B_FALSE; for (t = text ; t ; t = nextt) { nextt = t->next; if (t->state == 0) { t->size += TEXTSPEED; if (t->size >= t->maxsize) { if (t->type == TT_HELP) { // freeze oldlevelcomplete = levelcomplete; levelcomplete = LV_HELPFREEZE; t->state = t->delay; newhelpfreeze = B_TRUE; } else { t->state = 1; } } } else if (t->state == t->delay) { t->size -= TEXTSPEED; if (t->size <= 3) { if ((t->type == TT_GAMEOVER) && (levelcomplete == LV_GAMEOVER)) { // start game over timer gameovertime = gtime; } if (t->type == TT_INTROTEXT) { introstate = IS_JUMP; } killtext(t); } } else { t->state++; } } if (newhelpfreeze) { // expire delay on all help text for (t = text ; t ; t = t->next) { if (t->type == TT_HELPSHADOW) { t->state = t->delay; } } } } void drawbosshealth(void) { int i; SDL_Rect area; int healthframe; int maxhealth; maxhealth = getbosshealth(boss->id); area.x = (640/2) - maxhealth*(healthbar[0]->w+HEALTHBARGAP); area.y = HEALTHBARY; area.w = 0; area.h = 0; // for each health point, draw two bars for (i = 0; i < boss->lives; i++) { if (i < (maxhealth/8)) { healthframe = HF_RED; } else if (i <= (maxhealth/3)) { healthframe = HF_YELLOW; } else { healthframe = HF_GREEN; } SDL_BlitSurface(healthbar[healthframe], NULL, screen, &area); area.x += (healthbar[healthframe]->w + HEALTHBARGAP); SDL_BlitSurface(healthbar[healthframe], NULL, screen, &area); area.x += (healthbar[healthframe]->w + HEALTHBARGAP); } } void drawscore(void) { SDL_Surface *score; SDL_Rect area; SDL_Color scorecol; int i; int numtoshow; int numtoshow2; int scoreval; if (player) { if (forcegoodcard) { if ((timer / LUCKYFLASH) % 2 == 0) { scorecol = green; } else { scorecol = red; } } else { scorecol = red; } if (wantframerate) { scoreval = fps; sprintf(tempm, "%d fps",scoreval); } else { scoreval = player->score; addcommas(tempm, scoreval); } /* shadow */ score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, black); area.x = P1SCOREX-2; area.y = SCOREY; area.w = 0; area.h = 0; SDL_BlitSurface(score, NULL, screen, &area); SDL_FreeSurface(score); /* score */ score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, scorecol); area.x = P1SCOREX; area.y = SCOREY-2; area.w = 0; area.h = 0; SDL_BlitSurface(score, NULL, screen, &area); SDL_FreeSurface(score); // lives if (player->lives > 0) { // show 1 less than lives numtoshow = player->lives-1; area.x = P1LIVESX; area.y = LIVESY; area.w = 0; area.h = 0; // show "x5" for lots of lives while (numtoshow >= 5) { SDL_BlitSurface(head5, NULL, screen, &area); area.x += (head->w + 3); numtoshow -= 5; } for (i = 0; i < numtoshow; i++) { SDL_BlitSurface(head, NULL, screen, &area); area.x += (head->w + 3); } } else { area.x = P1LIVESX; area.y = LIVESY; area.w = 0; area.h = 0; SDL_BlitSurface(grave, NULL, screen, &area); } // cards if (levelcomplete != LV_DOPOKER) { area.x = CARDX; area.y = CARDY; area.w = 0; area.h = 0; for (i = 0; i < player->numcards; i++) { SDL_Surface *cardimg; cardimg = imageset[player->card[i]].img[F_WALK1]; SDL_BlitSurface(cardimg, NULL, screen, &area); area.x += (cardimg->w + 2); } } } if (player2) { if (forcegoodcard) { if ((timer / LUCKYFLASH) % 2 == 0) { scorecol = green; } else { scorecol = purple; } } else { scorecol = purple; } if (wantframerate) { scoreval = fps; sprintf(tempm, "%d fps",scoreval); } else { scoreval = player2->score; addcommas(tempm, scoreval); } /* shadow */ score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, black); area.x = 640 - score->w - P1SCOREX - 2; area.y = SCOREY-2; area.w = 0; area.h = 0; SDL_BlitSurface(score, NULL, screen, &area); SDL_FreeSurface(score); /* score */ score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, scorecol); area.x = 640 - score->w - P1SCOREX; area.y = SCOREY; area.w = 0; area.h = 0; SDL_BlitSurface(score, NULL, screen, &area); SDL_FreeSurface(score); // lives if (player2->lives > 0) { // show 1 less than lives numtoshow = player2->lives-1; area.x = 640 - P1LIVESX; area.y = LIVESY; area.w = 0; area.h = 0; // go left correct amount numtoshow2 = numtoshow; while (numtoshow2 >= 5) { area.x -= (head2->w + 3); numtoshow2 -= 5; } for (i = 0; i < numtoshow2; i++) { area.x -= (head2->w + 3); } // now start displaying // show "x5" for lots of lives while (numtoshow >= 5) { SDL_BlitSurface(head52, NULL, screen, &area); area.x += (head2->w + 3); numtoshow -= 5; } for (i = 0; i < numtoshow; i++) { SDL_BlitSurface(head2, NULL, screen, &area); area.x += (head2->w + 3); } } else { area.x = 640 - P1LIVESX - (head2->w); area.y = LIVESY; area.w = 0; area.h = 0; SDL_BlitSurface(grave, NULL, screen, &area); } // cards if (levelcomplete != LV_DOPOKER) { //area.x = 640 - CARDX - (5*(imageset[P_FIRSTCARD].img[F_WALK1]->w + 2)); area.x = 640 - CARDX - (imageset[P_FIRSTCARD].img[F_WALK1]->w ); area.y = CARDY; area.w = 0; area.h = 0; for (i = 0; i < player2->numcards; i++) { SDL_Surface *cardimg; cardimg = imageset[player2->card[i]].img[F_WALK1]; SDL_BlitSurface(cardimg, NULL, screen, &area); area.x -= (cardimg->w + 2); } } } // level # sprintf(tempm, "Level %d-%d",getcurworld(), getcurlevel()); /* shadow */ score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, black); area.x = 320-(score->w/2)-2; area.y = 7; area.w = 0; area.h = 0; SDL_BlitSurface(score, NULL, screen, &area); SDL_FreeSurface(score); /* text */ score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, white); area.x = 320-(score->w/2); area.y = 5; area.w = 0; area.h = 0; SDL_BlitSurface(score, NULL, screen, &area); SDL_FreeSurface(score); drawcredits(); } void drawtext(void) { text_t *t; SDL_Rect area; for (t = text ; t ; t = t->next) { if ((levelcomplete != LV_HELPFREEZE) || (t->type == TT_HELP)) { /* create text */ if (t->img) { SDL_FreeSurface(t->img); t->img = NULL; } t->img = TTF_RenderText_Solid(font[t->size], t->txt, *t->c); // make sure it's on the screen (leave space for border) if (t->x - (t->img->w / 2) < 2) { // left t->x = 2 + (t->img->w/2); } if (t->x + (t->img->w / 2) > 640-2) { // right t->x = 640-2 - (t->img->w/2); } if (t->y - (t->img->h / 2) < 2) { // top t->y = 2 + (t->img->h/2); } if (t->y + (t->img->h / 2) > 480-2) { // bottom t->y = 480-2 - (t->img->h/2); } /* get bg */ /* t->bgarea.x = t->x - t->img->w/2; t->bgarea.y = t->y - t->img->h/2; t->bgarea.w = t->img->w; t->bgarea.h = t->img->h; SDL_BlitSurface(screen, &t->bgarea, t->bg, NULL); */ /* draw text */ area.x = t->x - t->img->w/2; area.y = t->y - t->img->h/2; area.w = t->img->w; area.h = t->img->h; SDL_BlitSurface(t->img,NULL, screen, &area); } } } /* copy background buffer (ie. tiles) to screen, erasing sprites */ void removeall(void) { sprite_t *s; text_t *t; SDL_Rect area; int clearfull = B_FALSE; int *animtile; /* switch (player->powerup) { case PW_CANNONFIRE: case PW_SPRAYUP: case PW_SPRAYDOWN: case PW_BOMB: case PW_RATSHAKE: clearfull = B_TRUE; break; } switch (levelcomplete) { case LV_DOPOKER: case LV_HELPFREEZE: case LV_CLOUDLOOP: case LV_CLOUD: case LV_NEXTLEV: clearfull = B_TRUE; break; } if (curlevel->iced) clearfull = B_TRUE; if (paused) clearfull = B_TRUE; if (playedbell == BELL_DONESOUND) { if (timer < BELLTIME) { clearfull = B_TRUE; } } if (isbosslevel(curlevelnum)) { clearfull = B_TRUE; } */ clearfull = B_TRUE; if (clearfull) { // clear the entire screen SDL_BlitSurface(temps, NULL, screen, NULL); } else { for (s = sprite; s ; s = s->next) { /* // blit every tile coverting this sprite startx = s->x - (s->img->w/2); starty = s->y - s->img->h; endx = s->x + (s->img->w/2); endy = s->y; for (y = starty ; y <= endy; y++) { for (x = startx ; x <= endx; x++) { drawtile(screen,x,y); } }*/ removesprite(s); } // animated tiles for (animtile = curlevel->animtiles; animtile && *animtile != -1; animtile++) { int offset,tx,ty; offset = *animtile; tx = offset%LEVELW; ty = offset / LEVELW; area.x = tx*TILEW; area.y = ty*TILEH; area.w = TILEW; area.h = TILEH; SDL_BlitSurface(temps, &area, screen, &area); } // remove all text for (t = text ; t ; t = t->next) { /* draw text */ area.x = t->x - t->img->w/2; area.y = t->y - t->img->h/2; area.w = t->img->w; area.h = t->img->h; SDL_BlitSurface(temps, &area, screen, &area); } // clear top left (with score +cards) area.x = 0; area.y = 0; area.w = 200; area.h = 80; SDL_BlitSurface(temps, &area, screen, &area); // clear top middle (level) area.x = 250; area.y = 0; area.w = 100; area.h = 25; SDL_BlitSurface(temps, &area, screen, &area); // clear bottom middle (credits) area.x = 270; area.y = 455; area.w = 130; area.h = 24; SDL_BlitSurface(temps, &area, screen, &area); } } void drawnetting(sprite_t *s) { int sx; int xx; SDL_Rect area; if (!s) return; if (s->powerup == PW_RAYGUN) return; if (s->netting) { int y,yy; int dis; int netsleft; sx = s->x; s->nety = s->y - (s->img->h/2) + 2; s->netxstart = s->x; s->netystart = s->nety - 3; if (s->netdir == 1) { area.x = s->netxstart + TILEW/2; } else { area.x = s->netxstart - TILEW/2 - s->netlen; } //area.y = s->netystart; area.y = s->y - s->img->h-2 + 2; area.w = s->netlen; area.h = s->img->h+2; SDL_BlitSurface(screen, &area,s->netbg, NULL); netsleft = s->netmax - s->netcaught; if (netsleft < 1) netsleft = 1; dis = (int)s->img->h / (int)(netsleft+1) + 1; for (y = dis; y < s->img->h; y += dis) { yy = s->y - s->img->h; yy += y; xx = s->x + s->netdir*s->netlen; if (s->netsticky) { drawdotline16(screen,sx,s->nety,xx,yy,orange,yellow); } else { drawline(screen,sx,s->nety,xx,yy,white); } // add sparkle xx = s->x + s->netdir*s->netlen; if (levelcomplete != LV_HELPFREEZE) { addsprite(P_SPARKLE, xx + (rand() % 14) - 7, yy + (rand() % 8) - 4, "sparkle"); } } //drawline(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety-3,white); //drawline(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety,white); //drawline(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety+3,white); } else if (s->slamming) { double dist; int x,y; int ii; SDL_Color *col1,*col2; dist = (s->slamangle * (180/M_PI))/2; if (s->powerup == PW_SMALLNET) { dist /= 2; } s->netxstart = s->x + cos(s->slamangle-(180*(M_PI/180)))*dist*s->dir; s->netystart = s->y + sin(s->slamangle-(180*(M_PI/180)))*dist; // select colours if (s->netsticky) { col1 = &orange; col2 = &yellow; } else { col1 = &white; col2 = &white; } /* middle dotline */ drawdotline16(screen,s->x,s->y - s->img->h/2, s->netxstart,s->netystart,*col1,*col2); /* left dotline */ x = s->x + cos(s->slamangle-(5*(M_PI/180))-(180*(M_PI/180)))*dist*s->dir; y = s->y + sin(s->slamangle-(5*(M_PI/180))-(180*(M_PI/180)))*dist; drawdotline16(screen,s->x,s->y - s->img->h/2,x, y, *col1,*col2); /* right dotline */ x = s->x + cos(s->slamangle+(5*(M_PI/180))-(180*(M_PI/180)))*dist*s->dir; y = s->y + sin(s->slamangle+(5*(M_PI/180))-(180*(M_PI/180)))*dist; drawdotline16(screen,s->x,s->y - s->img->h/2,x, y, *col1,*col2); // add sparkles for (ii = 0 ; ii < s->netmax; ii++) { addsprite(P_SPARKLE, s->netxstart + (rand() % 8) - 4, s->netystart + (rand() % 8) - 4, "sparkle"); } } } void removenetting(sprite_t *s) { SDL_Rect area,sarea; if (s->netting) { sarea.x = 0; sarea.y = 0; sarea.w = s->netlen; sarea.h = s->img->h+2; if (s->netdir == 1) { area.x = s->netxstart + TILEW/2; } else { area.x = s->netxstart - TILEW/2 - s->netlen; } //area.y = s->netystart; area.y = s->y - s->img->h-2; area.w = s->netlen; area.h = s->img->h+2; if (s->netbg != NULL) { SDL_BlitSurface(s->netbg, &sarea, screen, &area); } } } void removesprite(sprite_t *s) { int startx,starty,endx,endy; int x,y; if (s == NULL) return; // find topleft-most tile gettileat(s->x - s->img->w, s->y - s->img->h,&startx,&starty); // find bottomright-most tile gettileat(s->x + s->img->w, s->y + s->img->h,&endx,&endy); if (s->slamming) { if (s->dir == D_LEFT) { startx -= 5; endx += 1; } else { startx -= 1; endx += 5; } starty -= 2; endy += 1; } if (s->netting) { if (s->dir == D_LEFT) { if (s->powerup == PW_ACCORDION) { startx = 0; } else { startx -= 5; } } else { if (s->powerup == PW_ACCORDION) { endx = LEVELW-1; } else { endx += 5; } } starty -= 1; endy += 1; } if (s->doublejump) { if (s->dir == D_LEFT) { endx += 2; } else { startx -= 2; } } // handle spider's web if ((s->id == P_SPIDER) && ((s->ys != -99) || s->falling) && !s->dead && !s->caughtby && !s->iced) { // do entire column starty = 0; } // draw the tiles for (y = starty; y <= endy; y++) { for (x = startx; x <= endx; x++) { drawtile(screen,x,y); } } } int isonbridge(sprite_t *s) { tiletype_t *tthere; tthere = gettileat(s->x,s->y, NULL,NULL); if (isbridge(tthere->id)) { return B_TRUE; } return B_FALSE; } int isladder(int tid) { switch (tid) { case T_LADDER: case T_LADDERTOP: return B_TRUE; } return B_FALSE; } // return the x position of the middle of the ladder if so int isonladder(sprite_t *s) { int tx; tiletype_t *tthere; tthere = gettileat(s->x,s->y, &tx,NULL); if (isladder(tthere->id)) { return (tx*TILEW)+(TILEW/2); } // if ladder above and climbing if (isladderabove(s) && s->climbing) { return isladderabove(s); } return B_FALSE; } // return the x position of the middle of the ladder if so int isladderabove(sprite_t *s) { tiletype_t *tthere; int tx; //tthere = gettileat(s->x,s->y-TILEH, NULL,NULL); tthere = gettileat(s->x,s->y-s->img->h, &tx,NULL); if (isladder(tthere->id)) { return (tx*TILEW)+(TILEW/2); } return B_FALSE; } // return the x position of the middle of the ladder if so int isladderbelow(sprite_t *s) { tiletype_t *tthere; int tx; //tthere = gettileat(s->x,s->y-TILEH, NULL,NULL); tthere = gettileat(s->x,s->y, &tx,NULL); if (isladder(tthere->id)) { return (tx*TILEW)+(TILEW/2); } return B_FALSE; } int isinwater(sprite_t *s) { return isinwaterpoint(s->x, s->y - s->img->h/2); } int isinwaterpoint(int x, int y) { tiletype_t *tt; tt = gettileat(x, y, NULL, NULL); if (tt->water) { return B_TRUE; } return B_FALSE; } int isroofabove(sprite_t *s) { tiletype_t *tt; /* get tile above sprite's head */ tt = gettileat(s->x, s->y - s->img->h,NULL,NULL); if (tt->solid) return B_TRUE; tt = gettileat(s->x + s->img->w/3, s->y - s->img->h,NULL,NULL); if (tt->solid) return B_TRUE; tt = gettileat(s->x - s->img->w/3, s->y - s->img->h,NULL,NULL); if (tt->solid) return B_TRUE; return B_FALSE; } /* is there a roof n tiles above us. If howfar is 1, this is the same as the regular isroofabove() */ int isroofnabove(sprite_t *s, int howfar) { tiletype_t *tt; int ypos; ypos = s->y - s->img->h - TILEH*(howfar-1); /* get tile above sprite's head */ tt = gettileat(s->x, ypos,NULL,NULL); if (tt->solid) return B_TRUE; tt = gettileat(s->x + (s->img->w/2 - 2), ypos,NULL,NULL); if (tt->solid) return B_TRUE; tt = gettileat(s->x - (s->img->w/2 - 2), ypos,NULL,NULL); if (tt->solid) return B_TRUE; return B_FALSE; } int isonground(sprite_t *s) { // are we on a platform? if (s->onplatform) { return B_TRUE; } // antigrav? if (s->antigrav ) { return B_TRUE; } /* get tile below sprite's feet */ if (isongroundpoint(s, s->x, s->y)) { return B_TRUE; } if ((s->dead) || (!s->falling && !s->dropping)) { if (!s->swimming) { if (isongroundpoint(s, s->x + s->img->w/2, s->y)) { return B_TRUE; } if (isongroundpoint(s, s->x - s->img->w/2, s->y)) { return B_TRUE; } } } //if (s->falling && s->id == P_KINGRAT) { if (s->id == P_KINGRAT) { if (isongroundpoint(s, s->x + s->img->w/2, s->y)) { return B_TRUE; } if (isongroundpoint(s, s->x - s->img->w/2, s->y)) { return B_TRUE; } } return B_FALSE; } int isongroundpoint(sprite_t *s, int x,int y) { tiletype_t *tt; int tilex,tiley; int xoff; int groundy; if (s->onplatform) { return B_TRUE; } tt = gettileat(x,y, &tilex, &tiley); // slope etc doesn't matter if you're dead if (s->dead && tt->solid) { return B_TRUE; } // when dropping, the tile you dropped from doesn't count // as "ground". //if (s->dropping && (tilex == s->dropx) && (tiley == s->dropy)) { if (s->dropping && (tiley == s->dropy)) { return B_FALSE; } /* get offset */ xoff = x - (tilex*TILEW); /* if it's not solid... */ if (tt->solid == 0) { return B_FALSE; } else { /* check height of tile at that position */ groundy = tiley*TILEH + tt->lowness[xoff]; /* above ground level */ if (y < groundy) { return B_FALSE; } else if (y > groundy + 3) { /* below ground level */ if (s->jumping) { return B_FALSE; } } else if (s->falling) { tiletype_t *abovetile; /* falling, on a tile, but with tiles above you */ // ie. you've jumped up through a single tile (can't // jump through two or more tiles abovetile = gettileat(x,y-TILEH, NULL, NULL); if (abovetile->solid) { return B_FALSE; } // } else if (s->dropping) { // tiletype_t *abovetile; /* if the tile we're on is solid but not the one above, then we've "dropped" and are still travelling through the tile we dropped from. */ // abovetile = gettileat(x,y-TILEH, NULL, NULL); // if (!abovetile->solid) { // return B_FALSE; // } } } return B_TRUE; } void dogravity(sprite_t *s) { sprite_t *s2; tiletype_t *tt; int tilex,tiley; if (!s) return; if (s->id == P_PINKCLOUD) return; // only player can move if you have a clock if (globpowerup == PW_CLOCK) { if (!iseffect(s->id) && (!isplayer(s)) && !s->caughtby && !s->dead) { return; } } // no gravity for players if you have the machine gun if (haspowerupany(PW_GUNNER)) { if (isplayer(s)) { return; } } // if we were on a trampoline and are now not, it releases */ tt = gettileat(s->x,s->y,&tilex,&tiley); if (s->ontramp) { if (s->trampy == tiley) { // you jump automatically! jump(s, s->xs / getspeed(s)); } else { //if (s->trampy != tiley) { // change tile type if (s->tramplayer == 1) { curlevel->map[s->trampy * LEVELW + s->trampx] = getuniq(T_TRAMPUP); } else { curlevel->map2[s->trampy * LEVELW + s->trampx] = getuniq(T_TRAMPUP); } drawtile(temps, s->trampx, s->trampy); // update sprite settings s->ontramp = B_FALSE; s->trampx = -1; s->trampy = -1; } } if (s->dead) return; // update flashing bosses if ((s == boss) && (s->angry)) { s->angry--; } if (s->flies && !s->iced) return; // no gravity if you fly, but ice cancels flying if (s->id != P_KSSHELL) { if (iseffect(s->id)) return; } if (isbullet(s->id)) return; //if (isonladder(s) && !s->falling && !s->jumping) { /* if (isonladder(s) ) { s->falling = B_FALSE; return; } */ // iced sprites can't jump if (s->iced) { s->jumping = B_FALSE; } // update water stats if ((isplayer(s) || ismonster(s->id)) && !s->oncloud) { if (isinwater(s)) { if (!s->swimming) { // we just entered the water s->swimming = B_TRUE; s->watertimer = rand() % BUBBLETIME; // play a splash sound if (curlevel->iced != WATER_INPROGRESS) { if (!s->caughtby && !s->dead) { playfx(FX_SPLASH); } } // give player a mask if they don't have one if (isplayer(s) && (s->hasmask)) { sprite_t *ms; int found = B_FALSE; // is there one already? for (ms = sprite; ms ; ms = ms->next) { if ((ms->id == P_MASK) && (ms->owner == s)) { found = B_TRUE; break; } } if (!found) { ms = addsprite(P_MASK, s->x + MASKOFFSETX*s->dir, s->y + MASKOFFSETY, "mask"); ms->owner = s; } } // adjust x pos so we don't get stuck in a wall if (isplayer(s)) adjustx(s, F_SWIM1); else adjustx(s, F_WALK1); if (isplayer(s)) { // dim the music Mix_VolumeMusic(MIX_MAX_VOLUME/3); } } // generate bubbles // just use s->x and s->y to add randomness, so that // all sprites don't make bubbles at the same time s->watertimer++; if (s->watertimer >= BUBBLETIME) { addsprite(P_BUBBLE,s->x + (s->dir*((s->img->w/4)+(rand() % 12 - 6))),s->y-(s->img->h/2),"bubble" ); s->watertimer = 0; } } else { if (s->swimming) { sprite_t *ms; // exitted the water s->swimming = B_FALSE; if (isplayer(s)) { Mix_VolumeMusic(MIX_MAX_VOLUME); } // get rid of the mask for (ms = sprite; ms ; ms = ms->next) { if ((ms->id == P_MASK) && (ms->owner == s)) { ms->dead = D_FINAL; break; } } } } } if (s->climbing) { int attop = B_FALSE; // check if we are at the top of our ladder //tt = gettileat(s->x, s->y - s->img->h-1,NULL,NULL); if (!isonladder(s)) { attop = B_TRUE; } //if (isonground(s)) { if (isongroundpoint(s, s->x, s->y)) { if (!isongroundpoint(s, s->x, s->y-1)) { attop = B_TRUE; } } if (attop) { s->climbing = B_FALSE; } else { // don't do any more checking return; } } // handle jumps if (s->jumping) { s->falling = B_FALSE; s->y -= s->jumpspeed; s->jumping++; if (s->jumping % 5 == 0) { if (s->jumpspeed > 0) { s->jumpspeed--; } else { s->jumping = B_FALSE; s->falling = B_TRUE; s->fallspeed = 0; } if (s->powerup == PW_JETPACK) { puffin(-1, s->x, s->y, "jet_puff", 0); } } // handle ring if (isplayer(s)) { if (s->powerup == PW_RINGJUMP) { if (timer % 2 == 0) { int xx,yy; // add sparkle xx = s->x + (rand() % s->img->w) - (s->img->w/2); yy = s->y - (rand() % (s->img->h/2)); addsprite(P_SPARKLE, xx, yy, "sparkle"); // gain points addscore(s, 65); } } } // king ant makes flames if (s->id == P_KINGANT) { // add flames on it if (( timer % 2) == 0) { addsprite(P_FLAME, s->x + (rand() % s->img->w) - (s->img->w/2), s->y - (s->img->h/2) + (rand() % s->img->h/2), "antflame"); } } /* have we hit a roof ? */ if (isroofabove(s)) { // king ANT destroys tiles when jumping, and shoots at players if (s->id == P_KINGANT) { int xxx; int tx,ty; // melt roof for (xxx = s->x - (s->img->w/2) ; xxx < s->x + (s->img->w/2) ; xxx += TILEW) { tt = gettileat(xxx, s->y - s->img->h,&tx,&ty); if (isbridge(tt->id)) { // melt it! melttile(tx,ty,REGROWTIMER_LONG); } } // shoot at players if (!s->bullet) { sprite_t *mytarget; // shoot fireball if player in front! mytarget = isplayerahead(s); if (mytarget) { sprite_t *ss; // shoot! playfx(FX_METEOR); ss = addsprite(P_BIGFIREBALL,s->x,mytarget->y+(TILEH/2),"horzfireball" ); ss->ys = 0; ss->xs = s->dir * 4; ss->dir = s->dir; ss->owner = s; s->bullet = ss; } } } /* can jump through one tile, but not two or more */ if (isroofnabove(s,2)) { if ((s->id != P_KINGRAT) && (s->id != P_KINGANT)) { // king rat can't hit roof /* stop jumping */ s->jumping = B_FALSE; s->falling = B_TRUE; s->fallspeed = 0; } } } } else { // not jumping int ontheground; if ((isfruit(s->id) == FT_SUPER) && (s->y < 480/2)) { ontheground = B_FALSE; } else { ontheground = isonground(s); } if (ontheground) { // reset doublejump if (s->doublejump) { s->useddoublejump = B_FALSE; } // reset jumpdir if (!s->jumptimer) { s->jumpdir = 0; } if (s->falling && s->iced) { // when an iced monster hits the ground, it smashes s->willbecome = P_DIAMOND; if (s->id == P_SNAIL) s->id = P_SLUG; playfx(FX_ICEBREAK); die(s); } if ((s->id == P_KINGRAT) && (s->timer1 == KRS_FALL)) { // special case // king rat drops until he is at player height if (!playersalive() || isplayerbelow(s)) { // above player ontheground = B_FALSE; } else { // above player s->dropping = B_FALSE; s->falling = B_FALSE; s->climbing = B_FALSE; } } else if ((s->id == P_KINGANT) && ((s->timer1 == KAS_FALL1) || (s->timer1 == KAS_FALL2))) { // special case int xxx,tx,ty; // add extra flames on it if (( timer % 2) == 0) { addsprite(P_FLAME, s->x + (rand() % s->img->w) - (s->img->w/2), s->y - (s->img->h/2) + (rand() % s->img->h/2), "antflame"); } // king ant drops until he is at the wanted height if (s->y >= s->timer3) { s->dropping = B_FALSE; s->falling = B_FALSE; s->climbing = B_FALSE; } else { // keep falling through ontheground = B_FALSE; } // king ant melts ground for (xxx = s->x - (s->img->w/2) ; xxx < s->x + (s->img->w/2) ; xxx += TILEW) { tt = gettileat(xxx, s->y + 2 ,&tx,&ty); if (isbridge(tt->id)) { melttile(tx,ty,REGROWTIMER_LONG); } } } else if ((s->id == P_KINGSNAIL) && (s->timer1 == KSS_JUMPING)) { // special case // king snail drops until he is at original height if (s->y < s->timer3) { // above orig height ontheground = B_FALSE; } else { s->dropping = B_FALSE; s->falling = B_FALSE; s->climbing = B_FALSE; } } else if ((s->id == P_SNAIL) && (s->lives == 0) && s->falling) { // snail dies - this is actuall the snail's shell s->dead = D_FINAL; } else if ((s->id == P_KSSHELL) && s->falling) { // king snail's shell dies when it hits the ground s->dead = D_FINAL; } else { // everyone else s->dropping = B_FALSE; s->falling = B_FALSE; s->climbing = B_FALSE; } } // snail also dies if it's been alive too long if ((s->id == P_SNAIL) && (s->lives == 0) && (!s->invuln)) { s->dead = D_FINAL; } // don't use an ELSE here because king rat needs to fall through if (!ontheground) { //if ((s->id == P_KINGRAT) && ((s->timer1 == KRS_CHARGE) || (s->timer1 == KRS_WALK))) { // do nothing //} else { //if (!s->climbing) { if (s->falling == B_FALSE) { s->fallspeed = 1; } s->falling = B_TRUE; if (isplayer(s)) { // stop ice inertia if (!s->moved) { s->xs = 0; } } if (s->id == P_FLY) { // constant speed - we are flying down, not falling s->y += getspeed(s); } else { double termvel; if (isinwater(s) && !s->iced) { if (s->hasmask) { // bob around s->y += (sin(timer/5)/3); } else { // sink s->y += (s->fallspeed/2); } } else { s->y += s->fallspeed; } if (s->umbrella && s->umbrellaup) { termvel = UMBFALLSPEED; } else { termvel = FALLSPEED; } if ((timer % 10 == 0) && (s->fallspeed < FALLSPEED)) { s->fallspeed++; } if (s->fallspeed > termvel) s->fallspeed = termvel; } //} //} } } if (s->netting) { if (s->powerup == PW_ACCORDION) { if (s->netspeed > 0) { s->netlen += s->netspeed; } else { s->netlen += (s->netspeed*2); } } else { s->netlen += s->netspeed; } s->netting++; if ((s->powerup == PW_ACCORDION) || (s->netting % 2 == 0)) { if ((s->netlen > 0) && (s->netspeed > -NETSPEED)) { s->netspeed--; } else { if (s->netlen <= 0) { // finished netting if ((s->powerup == PW_RAYGUN) && (s->timer1 <= 0)) { // finished using ray gun s->powerup = PW_NONE; } s->netting = 0; adjustx(s, F_WALK1); for (s2 = sprite ; s2 ; s2 = s2->next) { if ((s2->caughtby == s) && (s2->caughtstate == C_NETTING)) { s2->caughtstate = C_NETTED; } } } } } } else if (s->slamming) { int netx,nety; double dist; int hitwall = B_FALSE; s->slamangle += (10 * (M_PI/180)); dist = (s->slamangle * (180/M_PI))/2; if (s->powerup == PW_SMALLNET) { dist /= 2; } netx = s->x + cos(s->slamangle-(180*(M_PI/180)))*dist*s->dir; nety = s->y + sin(s->slamangle-(180*(M_PI/180)))*dist; if ((netx >= (640-TILEW)) || (netx <= TILEW)) { hitwall = B_TRUE; } // hit a boss? if (boss) { if ( (netx >= boss->x-(boss->img->w/2)) && (netx <= boss->x+(boss->img->w/2))) { if ((nety >= boss->y - boss->img->h) && (nety <= boss->y)) { hitwall = B_TRUE; } } } if (s->slamangle >= (180 * (M_PI/180)) || (hitwall && (s->slamangle >= (90 * (M_PI/180))))) { /* finished slamming */ int xdiff,ydiff,xnet = 0,ynet = 0; int pointsinc = 250; int psize = 6; int gotsomething = B_FALSE; int gotclover = B_FALSE; int hitboss = B_FALSE; int macex,macey; int numcaught = 0; // initialise just in case macex = s->x ; macey = s->y; s->slamming = 0; // if we have a mace, add an explosion and play a thump sound if (s->powerup == PW_MACE) { // play sound playfx(FX_MACE); // find location of mace for (s2 = sprite; s2 ; s2 = s2->next) { if (s2->id == P_MACE) { if (s2->owner == s) { break; } } } if (!s2) { // should never happen macex = s->x ; macey = s->y; } else { int xx,yy; macex = s2->x; macey = s2->y - s2->img->h/2; // add explosion addsprite(P_SMASH, macex, macey, "smash"); addsprite(P_SMASH, macex+TILEW, macey, "smash"); addsprite(P_SMASH, macex-TILEW, macey, "smash"); addsprite(P_SMASH, macex, macey+TILEH, "smash"); addsprite(P_SMASH, macex, macey-TILEH, "smash"); for (yy = 1; yy <= MACEEXPY; yy++) { for (xx = 1; xx <= MACEEXPX; xx++) { addsprite(P_SMASH, macex+xx*TILEW, macey-yy*TILEH, "smash"); addsprite(P_SMASH, macex-xx*TILEW, macey-yy*TILEH, "smash"); addsprite(P_SMASH, macex+xx*TILEW, macey+yy*TILEH, "smash"); addsprite(P_SMASH, macex-xx*TILEW, macey+yy*TILEH, "smash"); } } } } /* kill anything we've caught */ for (s2 = sprite; s2 ; s2 = s2->next) { /* kill anything we have caught */ if (s2->caughtby == s) { tiletype_t *tt; int onplatform; if (!isplayer(s2)) { numcaught++; // used later in slam code } tt = gettileat(s2->x,s2->y+2,NULL,NULL); // check for platform onplatform = isonplatform(s2->x,s2->y+2); /* if on ground or hitting a wall, monster dies */ if ((hitwall) || (onplatform) || (tt == NULL) || (tt->solid)) { if (isplayer(s2)) { tiletype_t *tt2; // release player playfx(FX_KILL); uncatch(s2); tt2 = gettileat(s2->x, s2->y-(TILEH), NULL, NULL); // if they were slammed into solid wall, they die if (tt2->solid) { die(s2); } else { // otherwise they recoil s2->recoiling = B_TRUE; jump(s2, s->dir); // away from the one who caught them s2->jumpspeed = 3; } // still counts as a monster for hitting others gotsomething++; xnet = s2->x; ynet = s2->y - s2->img->h/2; } else { /* will become a fruit when it finishes dying */ if (boss) { s2->willbecome = -1; } else if (s->powerup == PW_TOPHAT) { /* all fruits are powerups! */ s2->willbecome = poweruptypes[curpoweruptype[getpnum(s)]]; if (poweruptypes[++(curpoweruptype[getpnum(s)])] == -1) { curpoweruptype[getpnum(s)] = 0; } } else { if (forcegold) { s2->willbecome = P_GOLDBAR; } else { s2->willbecome = fruittypes[curfruittype]; /* increment fruit type */ curfruittype++; if (fruittypes[curfruittype] == -1) { curfruittype = 0; } // fruit time fruittime = gtime; } } if ((s->powerup == PW_MACE) && (s2->id == P_SNAIL)) { // turn into a slug so that it really dies s2->id = P_SLUG; } die(s2); if ((s->powerup == PW_MACE) || (s2->id != P_SNAIL)) { pointsinc *= 2; psize += 10; gotsomething++; // killing 5 at a time gives us a clover for good luck if ((!gotclover) && (gotsomething >= 5)) { puffin(P_CLOVER, s2->x, s2->y, "clover", 0); gotclover = B_TRUE; } } xnet = s2->x; ynet = s2->y - s2->img->h/2; } // end if isplayer() } else { /* otherwise it gets angry */ if (!isplayer(s2)) { s2->angry = B_TRUE; } } } } // if we have a powerup, centre of net is the mace position if (s->powerup == PW_MACE) { xnet = macex; ynet = macey; } // only check for hitting something if we already had a monster caught, // or we have a mace if (gotsomething || (s->powerup == PW_MACE)) { /* kill anything we hit */ for (s2 = sprite; s2 ; s2 = s2->next) { if ((s2->caughtby != s) && !s2->dead && !s2->invuln && (ismonster(s2->id))) { int xthresh,ythresh; xdiff = s2->x - xnet; if (xdiff < 0) xdiff =-xdiff; ydiff = (s2->y - s2->img->h/2) - ynet; if (ydiff < 0) ydiff =-ydiff; /* if (player->powerup == PW_MACE) { xthresh = TILEW*MACEEXPX*2; ythresh = TILEW*MACEEXPY*2; } else { */ xthresh = s2->img->w; ythresh = s2->img->h; //} if ((xdiff <= xthresh) && (ydiff <= ythresh)) { if (s2 == boss) { int n; // flash white, longer for each monster we were // holding s2->angry = BOSSFLASHTIME*numcaught; // lose health s2->lives -= numcaught; // if no health left < 0, it dies if (s2->lives <= 0) { sprite_t *s3; // todo: change to big fruit! s2->willbecome = P_DIAMOND; // add puffs for (n = 0; n < 30; n++) { puffin(-1, s2->x - (s2->img->w/2) + (rand() % s2->img->w), s2->y - (rand() % s2->img->h), "nothing", rand() % 80); } playfx(FX_BOSSDIE); die(s2); pointsinc *= 2; pointsinc = 64000; // hardcode for a boss psize += 10; gotsomething++; // kill everything else too for (s3 = sprite; s3 ; s3=s3->next) { if (ismonster(s3->id) && !s3->dead) { s3->willbecome = P_DIAMOND; if (s3->caughtby) { uncatch(s3); } die(s3); } } hitboss = B_TRUE; } else { // remaining health playfx(FX_BOSSHIT); hitboss = B_TRUE; } } else if (s2->id != P_BLACKCLOUD) { // non bosses /* dies and becomes a powerup */ // if we were holding something, we can get a powerup. // if we used a mace, it becomes a diamond. if (gotsomething) { if (boss) { // no fruits on boss levels s2->willbecome = -1; } else { int forcespeed = B_FALSE; if (!haspowerup(s, P_SPEED)) forcespeed = B_TRUE; // if anyone is alive and not fast isn't fast, give a speed. if (forcespeed) { s2->willbecome = P_SPEED; } else if (!gotcard & (gotsomething >= 4)) { // card for killing 5 at once s2->willbecome = getrandomcard(); gotcard = B_TRUE; } else if (!gotcard && (rand() % 5 == 0)) { // random chance of a card s2->willbecome = getrandomcard(); gotcard = B_TRUE; } else { // otherwise use normal powerup counter s2->willbecome = poweruptypes[curpoweruptype[getpnum(s)]]; if (poweruptypes[++(curpoweruptype[getpnum(s)])] == -1) { curpoweruptype[getpnum(s)] = 0; } } } } else if (s->powerup == PW_MACE) { s2->willbecome = P_DIAMOND; } else { // should never happen if (s->powerup == PW_TOPHAT) { s2->willbecome = poweruptypes[curpoweruptype[getpnum(s)]]; if (poweruptypes[++(curpoweruptype[getpnum(s)])] == -1) { curpoweruptype[getpnum(s)] = 0; } } else { if (forcegold) { s2->willbecome = P_GOLDBAR; } else { /* will become a fruit when it finishes dying */ s2->willbecome = fruittypes[curfruittype]; /* increment fruit type */ if (fruittypes[++curfruittype] == -1) { curfruittype = 0; } fruittime = gtime; } } } if (s2->id == P_SNAIL) { // turn into a slug so that it really dies s2->id = P_SLUG; } /* if (s2->id == P_SNAIL) { // avoid triggering death code twice for caught snails // since for them s->dead won't be set after we // slam them. if (s2->lives != 0) { // ie if we didn't just catch+slam it die(s2); } } else { */ die(s2); pointsinc *= 2; psize += 10; gotsomething++; // killing 5 at a time gives us a clover for good luck if ((!gotclover) && (gotsomething >= 5)) { puffin(P_CLOVER, s2->x, s2->y, "clover", 0); gotclover = B_TRUE; } //} } } } } } // end if gotsomething || PW_MACE // play sound effect if (!hitboss) { if (gotsomething >= 1) { playfx(FX_KILL); } if (gotsomething > 1) { playfx(FX_MULTIKILL); } } gotsomething = B_FALSE; /* release anything we've caught */ for (s2 = sprite; s2 ; s2 = s2->next) { if (s2->caughtby == s) { /* release it */ uncatch(s2); } } s->netcaught = 0; /* show points */ if (psize >= MAXLETTERHEIGHT) { psize = MAXLETTERHEIGHT-1; } if (pointsinc > 250) { /* give points to player */ //s->score += pointsinc; sprintf(tempm, "%d",addscore(s, pointsinc)); addoutlinetext(xnet,ynet-TILEH, psize, tempm, &white,&black,POINTSDELAY, TT_NORM); } } // end if slamangle > 180degrees } // end if slamming } int movex(sprite_t *s,double amt,int onpurpose) { double newx,newy; double curx,cury; int tilex,tiley; tiletype_t *tt,*tt2; int newxoff,newgroundy; int newtilex,newtiley; int domove = B_FALSE; double amtdir; tt = gettileat(s->x, s->y, &tilex,&tiley); if (amt > 0) amtdir = 1; else (amtdir = -1); curx = s->x; cury = s->y; /* check for blockage to E/W */ if ((s->id == P_SNAIL) && (s->jumping) && (boss)) { // unless we're a snail on kingsnail level } else { newx = s->x + (amtdir*(s->img->w/2)) ; //newx = s->x + (amtdir*TILEW/2); newy = cury-TILEH; tt2 = gettileat(newx,newy,&newtilex,&newtiley); if (tt2->solid == S_SOLID) { s->xs = 0; return NM_SIDE; } if ((tt2->solid == S_SLOPE) && (!candoslopes(s->id))) { s->xs = 0; return NM_SIDE; } } // if falling, check the tile directly to our SW/SEtoo */ if ((s->falling) && (s->id != P_KINGSNAIL)) { newx = s->x + (amtdir*TILEW/2); newy = cury; tt2 = gettileat(newx,newy,&newtilex,&newtiley); if (tt2->solid == S_SOLID) { //s->xs = 0; return NM_BELOW; } if (tt2->solid == S_SLOPE && (!candoslopes(s->id))) { //s->xs = 0; return NM_BELOW; } } /* get new position */ if (isplayer(s) && isice(tt->id) && !isinwater(s) && onpurpose ) { double newxs; // change speed newxs = s->xs + (s->dir*ICEACCEL); s->xs += (s->dir*ICEACCEL); // don't get too fast! if (newxs > getspeed(s)) newxs = getspeed(s); if (newxs < -getspeed(s)) newxs = -getspeed(s); newx = curx + newxs; amt = newx - curx; } else { newx = curx + amt; } newy = cury-2; tt2 = gettileat(newx,newy,&newtilex,&newtiley); newxoff = newx - (newtilex*TILEW); newgroundy = newtiley*TILEH + tt2->lowness[newxoff]; /* new block is at least partially solid */ domove = B_FALSE; if (tt2->solid == S_SOLID) { // s->xs = 0; return NM_SIDE; } else if ((tt2->solid == S_SLOPE) && candoslopes(s->id)) { /* we can move, but need to adjust our height */ domove = B_TRUE; } else { /* new block is empty */ domove = B_TRUE; } if (domove) { if (isplayer(s) && isice(tt->id) && !isinwater(s) && onpurpose) { // change speed s->xs += (s->dir*ICEACCEL); // don't get too fast! if (s->xs > getspeed(s)) s->xs = getspeed(s); if (s->xs < -getspeed(s)) s->xs = -getspeed(s); s->x += s->xs; s->moved = MV_WALK; } else { s->x += amt; s->xs = amt; if (!onpurpose) { if (isice(tt->id) && !isinwater(s)) { s->moved = MV_ICE; } else if (!isconveyor(tt->id)) { s->moved = MV_WALK; } } else { s->moved = MV_WALK; } } } else { s->xs = 0; } // rings if (isplayer(s)) { if (s->powerup == PW_RINGWALK) { if (isonground(s) && !s->swimming) { int xx,yy; // add sparkle xx = s->x + (rand() % s->img->w) - (s->img->w/2); yy = s->y - (rand() % (s->img->h/2)); addsprite(P_SPARKLE, xx, yy, "sparkle"); // gain points addscore(s, 15); } } } return B_FALSE; } void adjustheight(sprite_t *s) { tiletype_t *tt; int xoff,groundy; int tilex,tiley; double origy; int totmoved; if ((s->flies) || isbullet(s->id) ) { return; } tt = gettileat(s->x,s->y-1,&tilex,&tiley); if (!tt) return; if (tt->solid == S_SLOPE) { xoff = s->x - (tilex*TILEW); groundy = tiley*TILEH + tt->lowness[xoff]; s->y = groundy; } else if (tt->solid == S_SOLID) { origy = s->y; totmoved = 0; // keep moving up while (tt->solid == S_SOLID) { s->y--; totmoved++; // don't move more than 1 tile worth! // don't go off top of screen if ((totmoved >= TILEH) || (s->y <= TILEH)) { break; } tt = gettileat(s->x,s->y-1,&tilex,&tiley); } } } int dofruiteffect(sprite_t *pp, sprite_t *s) { if (s->id == P_SPEED) { playfx(FX_POWERUP); pp->speed = PLAYERFAST; addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, "Speed up!", &white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_BIGSPEED) { // both players playfx(FX_POWERUP); if (player) { player->permspeed = B_TRUE; player->speed = PLAYERFAST; addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_LIFE, "SUPER SPEED UP!", &cyan,&black,POINTSDELAY, TT_NORM); } if (player2) { player2->permspeed = B_TRUE; player2->speed = PLAYERFAST; addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_LIFE, "SUPER SPEED UP!", &cyan,&black,POINTSDELAY, TT_NORM); } return B_TRUE; } else if (s->id == P_BIGSCUBA) { // both players playfx(FX_POWERUP); if (player) { player->permmask = B_TRUE; player->hasmask = B_TRUE; if ((player->lives > 0) && !player->dead) { addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_LIFE, "SUPER MASK!", &cyan,&black,POINTSDELAY, TT_NORM); } } if (player2) { player2->permmask = B_TRUE; player2->hasmask = B_TRUE; if ((player2->lives > 0) && !player2->dead) { addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_LIFE, "SUPER MASK!", &cyan,&black,POINTSDELAY, TT_NORM); } } return B_TRUE; } else if (s->id == P_SUPERUMBRELLA) { // both players playfx(FX_POWERUP); if (player) { player->permumbrella = B_TRUE; player->umbrella = B_TRUE; if ((player->lives > 0) && !player->dead) { addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_LIFE, "SUPER UMBRELLA!", &cyan,&black,POINTSDELAY, TT_NORM); } } if (player2) { player2->permumbrella = B_TRUE; player2->umbrella = B_TRUE; if ((player2->lives > 0) && !player2->dead) { addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_LIFE, "SUPER UMBRELLA!", &cyan,&black,POINTSDELAY, TT_NORM); } } return B_TRUE; } else if (s->id == P_BIGHELMET) { // both players playfx(FX_POWERUP); if (player) { player->permarmour = B_TRUE; player->armour = B_TRUE; if ((player->lives > 0) && !player->dead) { int xx,yy; addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_LIFE, "SUPER ARMOUR!", &cyan,&black,POINTSDELAY, TT_NORM); for (xx = player->x - TILEW; xx <= player->x + TILEW; xx += TILEW) { for (yy = player->y - TILEW*2; yy <= player->y; yy += TILEH) { puffin(-1, xx, yy, "nothing", 0); } } } player->id = P_ARMOUR; // change how the player looks } if (player2) { player2->permarmour = B_TRUE; player2->armour = B_TRUE; if ((player2->lives > 0) && !player2->dead) { int xx,yy; addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_LIFE, "SUPER ARMOUR!", &cyan,&black,POINTSDELAY, TT_NORM); // add puffs for (xx = player2->x - TILEW; xx <= player2->x + TILEW; xx += TILEW) { for (yy = player2->y - TILEW*2; yy <= player2->y; yy += TILEH) { puffin(-1, xx, yy, "nothing", 0); } } } player2->id = P_ARMOUR; // change how the player looks } return B_TRUE; } else if (s->id == P_NUMNETS) { playfx(FX_POWERUP); if (pp->netmax < 4) { pp->netmax++; } sprintf(tempm, "%d nets!",pp->netmax); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_BIGNET) { playfx(FX_POWERUP); pp->netbig = B_TRUE; sprintf(tempm, "Big net!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_TROPHY) { // all powerups playfx(FX_POWERUP); pp->netmax = 4; // all nets pp->netbig = B_TRUE; // big net pp->speed = 2; // fast sprintf(tempm, "Full power!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_MASKPOWERUP) { playfx(FX_POWERUP); pp->hasmask = B_TRUE; sprintf(tempm, "Scuba Mask!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_BELL) { // powerup detector - makes the level flash depending on what power up will appear. // white = permenant // green = temporary ability // red = instawin // purple = bad playfx(FX_BELL); // different sound effect pp->hasbell = B_TRUE; sprintf(tempm, "Powerup Detector!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_RINGGOLD) { // points for walking playfx(FX_POWERUP); pp->powerup = PW_RINGWALK; sprintf(tempm, "Walk Ring!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_RINGSILVER) { // points for walking playfx(FX_POWERUP); pp->powerup = PW_RINGJUMP; sprintf(tempm, "Jump Ring!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_MACEPOWERUP) { playfx(FX_POWERUP); pp->powerup = PW_MACE; sprintf(tempm, "Mace Slam!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_BOXING) { playfx(FX_POWERUP); pp->powerup = PW_BOXING; sprintf(tempm, "Boxing Glove!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_HELMET) { int xx,yy; playfx(FX_ARMOR); if (pp == player) { pp->id = P_ARMOUR; // change how the player looks } else { pp->id = P_ARMOUR2; // change how the player looks } pp->armour = B_TRUE; sprintf(tempm, "Armour!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); // add puffs for (xx = pp->x - TILEW; xx <= pp->x + TILEW; xx += TILEW) { for (yy = pp->y - TILEW*2; yy <= pp->y; yy += TILEH) { puffin(-1, xx, yy, "nothing", 0); } } return B_TRUE; } else if (s->id == P_GEMBOOST) { playfx(FX_POWERUP); if (pp->gemboost <= 1) { pp->gemboost = 2; } else { pp->gemboost = 3; } sprintf(tempm, "Bonus x%d!",pp->gemboost); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_FTODIAMOND) { sprite_t *s2, *nexts; // convert all flowers to diamonds playfx(FX_MORPH); sprintf(tempm, "Make diamonds!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isflower(s2->id)) { puffin(-1, s2->x, s2->y, "nothing", 0); // replace with a diamond s2->id = P_DIAMOND; s2->score = getpoints(P_DIAMOND); sprintf(s2->name, "made_diamond"); } } playfx(FX_MORPH); return B_TRUE; } else if (s->id == P_FTOGEM) { sprite_t *s2, *nexts; int howmany; int puffdelay; int gemtype = P_GEMYELLOW; int xx; tiletype_t *tt; // convert all flowers to gems playfx(FX_MORPH); sprintf(tempm, "Make gems!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isflower(s2->id)) { puffin(-1, s2->x, s2->y, "nothing", 0); // replace with a diamond s2->id = flowertogem(s2->id); s2->score = getpoints(s2->id); sprintf(s2->name, "made_gem"); } } // and also make a stream of gems underneath us howmany = (STREAMWID+1)*3; // RIGHT puffdelay = 0; for (xx = s->x+TILEW; xx < s->x + (TILEW*howmany); xx += TILEW) { // if on a wall, exit tt = gettileat(xx,s->y-TILEH,NULL,NULL); if (tt->solid) { break; } switch (puffdelay % 3) { case 0: gemtype = P_GEMYELLOW; break; case 1: gemtype = P_GEMRED; break; case 2: gemtype = P_GEMPURPLE; break; } /* create a gem */ puffin(gemtype, xx, s->y, "gem", puffdelay); puffdelay += 1; } // LEFT puffdelay = 0; for (xx = s->x+TILEW; xx > s->x - (TILEW*howmany); xx -= TILEW) { // if on a wall, exit tt = gettileat(xx,s->y-TILEH,NULL,NULL); if (tt->solid) { break; } switch (puffdelay % 3) { case 0: gemtype = P_GEMYELLOW; break; case 1: gemtype = P_GEMRED; break; case 2: gemtype = P_GEMPURPLE; break; } /* create a gem */ puffin(gemtype, xx, s->y, "gem", puffdelay); puffdelay += 1; } return B_TRUE; } else if (s->id == P_CLOCK) { // Freeze monsters playfx(FX_POWERUP); globpowerup = PW_CLOCK; clocktime = CLOCKTIME; sprintf(tempm, "Freeze time!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); // pause music Mix_PauseMusic(); return B_TRUE; } else if (s->id == P_TAP) { // flood level playfx(FX_FLOOD); sprintf(tempm, "Flood!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&blue,&black,POINTSDELAY, TT_NORM); if (!curlevel->iced) { curlevel->iced = WATER_INPROGRESS; curlevel->icey = LEVELH-1; // water for 20 seconds watertime = 20; } return B_TRUE; } else if (s->id == P_SNOWMAN) { // ice playfx(FX_FREEZE); sprintf(tempm, "Blizzard!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&cyan,&black,POINTSDELAY, TT_NORM); if (!curlevel->iced) { curlevel->iced = ICE_INPROGRESS; curlevel->icey = 0; } // postpone hurryup nexthurryup += 10; return B_TRUE; } else if (s->id == P_SPRAY) { // flyspray playfx(FX_SPRAY); sprintf(tempm, "Fly Spray!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); globpowerup = PW_SPRAYUP; sprayalpha = 0; return B_TRUE; } else if (s->id == P_RAYGUN) { // ray gun playfx(FX_POWERUP); sprintf(tempm, "Ray Gun!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); pp->powerup = PW_RAYGUN; pp->timer1 = 5; // # of shots return B_TRUE; } else if (s->id == P_TOPHAT) { // Top Hat playfx(FX_POWERUP); sprintf(tempm, "Top Hat!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); pp->powerup = PW_TOPHAT; return B_TRUE; } else if (s->id == P_LAMP) { int xx,yy,delay; sprite_t *s2; tiletype_t *tt; // Magic Lamp Mix_PauseMusic(); // pause music playfx(FX_LAMP); sprintf(tempm, "Magic Lamp!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); globpowerup = PW_LAMP; // create gold coins delay = 0; for (xx = 0; xx < LEVELW; xx++) { for (yy = 0; yy < (LEVELH-1); yy++) { tt = gettileat(xx*TILEW,yy*TILEH, NULL,NULL); if (!tt->solid) { // check tile below tt = gettileat(xx*TILEW,(yy+1)*TILEH, NULL,NULL); if (tt->id == T_LAND) { // add a coin ! (NAME is important as it gives a higher doom // count when being placed in addsprite()!) puffin(P_GOLDCOIN, xx*TILEW+(TILEW/2), yy*TILEH+(TILEH),"goldcoin", delay); } } } //inc delay delay += 1; } // remove all monsters for (s2 = sprite; s2 ; s2 = s2->next) { if (ismonster(s2->id) && !s2->dead ) { s2->dead = D_FINAL; //puffs puffin(-1, s2->x - (s2->img->w/2), s2->y, "wandpuff", rand() % 5); puffin(-1, s2->x + (s2->img->w/2), s2->y, "wandpuff", rand() % 5); puffin(-1, s2->x, s2->y - (s2->img->h/2), "wandpuff", rand() % 5); puffin(-1, s2->x, s2->y + (s2->img->h/2), "wandpuff", rand() % 5); } } return B_TRUE; } else if (s->id == P_CANNONPOWERUP) { sprite_t *newsp; // cannon playfx(FX_POWERUP); sprintf(tempm, "Fusion Cannon"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); pp->powerup = PW_CANNON; puffin(-1, pp->x, pp->y,"nothign", 0); newsp = addsprite(P_CANNON, pp->x, pp->y, "cannon"); newsp->owner = pp; return B_TRUE; } else if (s->id == P_HONEY) { playfx(FX_POWERUP); pp->netsticky = B_TRUE; sprintf(tempm, "Sticky net!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_LIFE) { extralife(pp); return B_TRUE; } else if (s->id == P_PHONE) { sprite_t *s2, *nexts; // can't skip levels if the nxet one is a boss level if (isbosslevel(curlevelnum + 1)) { playfx(FX_ENGAGED); sprintf(tempm, "Engaged"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); } else { if (!strstr(s->name, "warp")) { playfx(FX_PHONE); sprintf(tempm, "Telephone!"); } else { sprintf(tempm, "Warp!"); } addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); // set powerup pp->powerup = PW_PHONE; skiplevels = 1; // kill all enemies and fruits for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isbullet(s2->id) || ismonster(s2->id) || isfruit(s2->id)) { s2->dead = D_FINAL; if (ismonster(s2->id)) { if (s2->caughtby) { uncatch(s2); } } } } // call in cloud immediately levelcomplete = LV_FINAL; } return B_TRUE; } else if (s->id == P_UFO) { int n; int wid,hei; sprite_t *sp; playfx(FX_POWERUP); sprintf(tempm, "Meteor Shower!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); wid = imageset[P_METEOR].img[0]->w; hei = imageset[P_METEOR].img[0]->h; for (n = 0; n < 7; n++) { sp = addsprite(P_METEOR, rand() % (640 - (wid*2)) + (wid/2), - (rand() % (hei*7)), "meteor"); sp->ys = (rand() % METEORMAXSPEED)+2; } lastmet = sp; return B_TRUE; } else if (s->id == P_STARPOWERUP) { int n; double ang; sprite_t *sp; // add a starburst ang = (rand() % 360) * (M_PI/180); for (n = 0; n < 8; n++) { sp = addsprite(P_STAR, pp->x, pp->y, "star"); /* switch (n) { case 0: sp->xs = 0; sp->ys = -STARSPEED; break; case 1: sp->xs = STARSPEED; sp->ys = -STARSPEED; break; case 2: sp->xs = STARSPEED; sp->ys = 0; break; case 3: sp->xs = STARSPEED; sp->ys = STARSPEED; break; case 4: sp->xs = 0; sp->ys = STARSPEED; break; case 5: sp->xs = -STARSPEED; sp->ys = STARSPEED; break; case 6: sp->xs = -STARSPEED; sp->ys = 0; break; case 7: sp->xs = -STARSPEED; sp->ys = -STARSPEED; break; } */ sp->xs = cos(ang)*STARSPEED; sp->ys = sin(ang)*STARSPEED; ang = ang + (45 * (M_PI/180)); // use timer1 as the frame counter sp->timer1 = rand() % STARFRAMES; } playfx(FX_STAR); sprintf(tempm, "Shuriken!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); return B_TRUE; } else if (s->id == P_BOMB) { sprite_t *s2, *nexts; // make the screen shake globpowerup = PW_BOMB; globtimer = BOMBSHAKETIME; // kill all monsters playfx(FX_BOOM); sprintf(tempm, "KABOOM!!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_BOMB, tempm,&red,&yellow,POINTSDELAY, TT_NORM); for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isbullet(s2->id)) { s2->dead = D_FINAL; } else if (ismonster(s2->id)) { addsprite(P_SMASH, s2->x, s2->y, "kaboom"); s2->willbecome = P_DIAMOND; s2->lives = 0; // for snails uncatch(s2); die(s2); } } return B_TRUE; } else if (s->id == P_SHIELD) { playfx(FX_POWERUP); sprintf(tempm, "Shield!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); // temp invincibility pp->invuln = SHIELDTIME; return B_TRUE; } else if (s->id == P_CLOVER) { playfx(FX_POWERUP); sprintf(tempm, "Lucky!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_CLOVER, tempm,&green2,&black,CLOVERDELAY, TT_NORM); nextforcegoodcard = B_TRUE; forcegoodcard = B_TRUE; return B_TRUE; } else if (s->id == P_ACCORDION) { playfx(FX_POWERUP); sprintf(tempm, "Extra Long Net!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); pp->powerup = PW_ACCORDION; return B_TRUE; } else if (s->id == P_WINGBOOTS) { playfx(FX_POWERUP); sprintf(tempm, "Double jump!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); pp->doublejump = B_TRUE; return B_TRUE; } else if (s->id == P_PILL) { playfx(FX_POWERUP); sprintf(tempm, "Hyper speed!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); pp->powerup = PW_PILL; return B_TRUE; } else if (s->id == P_GUN) { playfx(FX_ALARM); sprintf(tempm, "Machine gunner!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); guntime = 10; gundelay[0] = 0; // used to control shooting speed gundelay[1] = 0; // used to control shooting speed // gunner works on BOTH players if (player) { player->netting = B_FALSE; player->slamming = B_FALSE; player->powerup = PW_GUNNER; gunorigx[0] = player->x; gunorigy[0] = player->y; } if (player2) { player2->netting = B_FALSE; player2->slamming = B_FALSE; player2->powerup = PW_GUNNER; gunorigx[1] = player2->x; gunorigy[1] = player2->y; } return B_TRUE; } else if (s->id == P_GNOME) { sprite_t *s2; playfx(FX_BOOM2); sprintf(tempm, "Exploding Flowers!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); puffin(-1, s->x, s->y, "gnomepuff", 0); // turn all flowers into explosions for (s2 = sprite; s2 ; s2 = s2->next) { if (isflower(s2->id)) { // replace with an explosion s2->dead = D_FINAL; addsprite(P_SMASH, s2->x, s2->y, "gnom_exp"); } } return B_TRUE; } else if (s->id == P_WHISTLE) { sprite_t *bc; sprite_t *s2; int found = B_FALSE; playfx(FX_WHISTLE); // if black cloud exists, it gets angry for (s2 = sprite; s2 ; s2 = s2->next) { if (s2->id == P_BLACKCLOUD) { found = B_TRUE; break; } } if (found) { s2->angry = B_TRUE; addoutlinetext(320,240,TEXTSIZE_HURRY, "Angry cloud!", &red,&black,HURRYDELAY, TT_NORM); } else { bc = addsprite(P_BLACKCLOUD, 320,240,"cloud"); makeinvuln(bc); bc->angry = B_TRUE; addoutlinetext(320,240,TEXTSIZE_HURRY, "Angry cloud!", &red,&black,HURRYDELAY, TT_NORM); playfx(FX_TOOSLOW); } globpowerup = PW_WHISTLE; return B_TRUE; } else if (s->id == P_CANDLE) { playfx(FX_POWERUP); sprintf(tempm, "Flaming Corpses!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); globpowerup = PW_CANDLE; return B_TRUE; } else if (s->id == P_MAGNET) { playfx(FX_POWERUP); sprintf(tempm, "Attract fruits!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); pp->powerup = PW_MAGNET; return B_TRUE; } else if (s->id == P_JETPACK) { playfx(FX_POWERUP); sprintf(tempm, "Jet pack!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); pp->powerup = PW_JETPACK; return B_TRUE; } else if (s->id == P_UMBRELLA) { playfx(FX_POWERUP); sprintf(tempm, "Umbrella!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); pp->umbrella = B_TRUE; return B_TRUE; } else if (s->id == P_BADMAGNET) { playfx(FX_SKULL); sprintf(tempm, "Repel fruits!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&black,&grey,POINTSDELAY, TT_NORM); pp->powerup = PW_BADMAGNET; return B_TRUE; } else if (s->id == P_ANCHOR) { playfx(FX_MORPH); sprintf(tempm, "Anchor!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); globpowerup = PW_ANCHOR; return B_TRUE; } else if (s->id == P_CAMERA) { playfx(FX_CAMERA); sprintf(tempm, "Blind enemies!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); globpowerup = PW_CAMERA; cameraalpha = 255; return B_TRUE; } else if (s->id == P_WAND) { sprite_t *s2; playfx(FX_WAND); sprintf(tempm, "Weaken monsters!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); // turn all live monsters into weaker versions for (s2 = sprite; s2 ; s2 = s2->next) { if (ismonster(s2->id) && !s2->dead && !s2->caughtby) { // don't get ones which we just created! if (!strstr(s2->name, "created")) { int newtype = -1; // make it non-angry if (s2->angry) s2->angry = B_FALSE; // change to a weaker version switch (s2->id) { case P_SNAKE: case P_TICK: case P_SNAIL: case P_SLUG: newtype = P_RAT; break; case P_FISH: case P_FLY: newtype = P_BEE; break; } s2->dead = D_FINAL; if (newtype != -1) { // morph into something else... addsprite(newtype, s2->x, s2->y, "created_mon"); } //puffs anyway puffin(-1, s2->x - (s2->img->w/2), s2->y, "wandpuff", rand() % 5); puffin(-1, s2->x + (s2->img->w/2), s2->y, "wandpuff", rand() % 5); puffin(-1, s2->x, s2->y - (s2->img->h/2), "wandpuff", rand() % 5); puffin(-1, s2->x, s2->y + (s2->img->h/2), "wandpuff", rand() % 5); } } } return B_TRUE; } else if (s->id == P_ZAPPOWERUP) { sprite_t *newsp; playfx(FX_POWERUP); sprintf(tempm, "Bug Zapper!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM); puffin(-1, pp->x, pp->y, "bzpuff", 0); newsp = addsprite(P_ZAPPER, pp->x,pp->y, "bugzapper" ); newsp->timer1 = 0; newsp->timer2 = ZAPPERDELAY; newsp->timer3 = 0; newsp->doomcount = 800; newsp->owner = pp; return B_TRUE; } else if (s->id == P_SKULL) { playfx(FX_SKULL); sprintf(tempm, "Power Down!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&black,&grey,POINTSDELAY, TT_NORM); pp->powerup = PW_SMALLNET; return B_TRUE; } else if (s->id == P_HELP) { playfx(FX_POWERUP); addoutlinetext(320,240,TEXTSIZE_HELP, s->name, &white,&black,HELPDELAY,TT_HELP); return B_TRUE; } else if (iscard(s->id)) { if (pp->numcards < MAXCARDS) { sprite_t *newc; int cardwidth,cardheight; playfx(FX_CARD); // show text sprintf(tempm, getcardname(s->id), BUFLEN); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY,TT_NORM); // add a "card" effect. it will move slowly towards the corner. newc = addsprite(P_MOVINGCARD,s->x, s->y, "moving_card"); newc->owner = pp; // timer1 is the actual cardid // timer2 is the target x position // timer3 is the target y position cardwidth = imageset[P_FIRSTCARD].img[F_WALK1]->w; cardheight = imageset[P_FIRSTCARD].img[F_WALK1]->h; newc->timer1 = s->id; if (pp == player) { newc->timer2 = CARDX + (pp->numcards * (cardwidth+2)) + (cardwidth/2); } else if (pp == player2) { int cardx2 = 640 - CARDX - (imageset[P_FIRSTCARD].img[F_WALK1]->w + 2); newc->timer2 = cardx2 - (pp->numcards * (cardwidth+2)) + (cardwidth/2); } newc->timer3 = CARDY + cardheight; // set image newc->img = imageset[s->timer1].img[F_WALK1]; } else { // is this possible?! addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, "Full cards!",&red,&black,POINTSDELAY,TT_NORM); } return B_TRUE; } else if (isflower(s->id)) { int xx; sprite_t *ss; tiletype_t *tt; int found = B_FALSE; /* was this the last fruit of its kind on the level? */ for (ss = sprite; ss; ss = ss->next) { if ((ss != s) && (ss->id == s->id)) { found = B_TRUE; } } /* if so, create a left/right stream of flowers */ if (!found) { int howmany = (STREAMWID + 1) * pp->gemboost; int puffdelay; // RIGHT puffdelay = 0; for (xx = s->x+TILEW; xx < s->x + (TILEW*howmany); xx += TILEW) { // if on a wall, exit tt = gettileat(xx,s->y-TILEH,NULL,NULL); if (tt->solid) { break; } /* create a flower */ puffin(flowertogem(s->id), xx, s->y, "flower", puffdelay); puffdelay += 1; } // LEFT puffdelay = 0; for (xx = s->x+TILEW; xx > s->x - (TILEW*howmany); xx -= TILEW) { // if on a wall, exit tt = gettileat(xx,s->y-TILEH,NULL,NULL); if (tt->solid) { break; } puffin(flowertogem(s->id), xx, s->y, "flower", puffdelay); puffdelay += 1; } playfx(FX_BONUS); sprintf(tempm, "BONUS!"); addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_BONUS, tempm,&white,&black,BONUSDELAY,TT_NORM); return B_TRUE; } } return B_FALSE; } void usage(void) { printf("usage: rc [-fs] [-l xx]\n"); printf(" -fs Start in full-screen mode.\n"); printf(" -l xx Skip to level xx.\n"); printf(" -hs xx Set hiscore_server to http://xx.\n"); printf(" -hp xx Connect to hiscore_server on port xx.\n"); printf(" -js Joystick test mode.\n"); printf(" -as Auto screenshot mode (dumps to /tmp/levelxx.bmp).\n"); printf("\n"); } // returns B_TRUE if the given player is able to walk/fall left/right int canmove(sprite_t *pl) { if (!pl->jumping && !pl->slamming ) { if (!pl->netting) { if ( pl->climbing || pl->falling || isonground(pl)) { return B_TRUE; } } else if (pl->netting && pl->falling) { // netting and falling return B_TRUE; } } return B_FALSE; } // returns B_TRUE if the given player is able to change which direction they're facing int canturn(sprite_t *pl) { if (!pl->slamming && !pl->netting) { return B_TRUE; } return B_FALSE; } int loadfx(int sid , char *filename) { char tempname[BUFLEN]; sprintf(tempname, "%s/sounds/",datadir); strncat(tempname, filename, BUFLEN); sfx[sid] = Mix_LoadWAV(tempname); if (!sfx[sid]) { printf("error loading %s\n",tempname); return B_TRUE; } return B_FALSE; } int initsound(void) { int i; char filename[BUFLEN]; /* init */ //if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 1024) < 0) { //if (Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 512) < 0) { if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 512) < 0) { printf("Error initialising sound: %s.\n",Mix_GetError()); return B_TRUE; } Mix_AllocateChannels(CH_LASTCHANNEL); loadfx(FX_SHOOT, "shoot.wav"); loadfx(FX_SLAM, "slam.wav"); loadfx(FX_KILL, "kill.wav"); loadfx(FX_MULTIKILL, "multikill.wav"); loadfx(FX_JUMP, "jump.wav"); loadfx(FX_FRUIT, "fruit.wav"); loadfx(FX_POWERUP, "powerup.wav"); loadfx(FX_DIE, "die.wav"); loadfx(FX_WINLEVEL, "winlevel.wav"); loadfx(FX_HURRYUP, "hurryup.wav"); loadfx(FX_TOOSLOW, "tooslow.wav"); loadfx(FX_BONUS, "bonus.wav"); loadfx(FX_MORPH, "morph.wav"); loadfx(FX_BOOM, "boom.wav"); loadfx(FX_SPRING, "spring.wav"); loadfx(FX_TELEPORT, "teleport.wav"); loadfx(FX_SPLASH, "splash.wav"); loadfx(FX_MACE, "mace.wav"); loadfx(FX_COIN, "coin.wav"); loadfx(FX_GAMEOVER, "gameover.wav"); loadfx(FX_OW, "ow.wav"); loadfx(FX_BELL, "bell.wav"); loadfx(FX_CLOCK, "clock.wav"); loadfx(FX_ARMOR, "armor.wav"); loadfx(FX_FREEZE, "freeze.wav"); loadfx(FX_ICEBREAK, "icebreak.wav"); loadfx(FX_BOSSWINDUP, "chargewait.wav"); loadfx(FX_BOSSCHARGE, "bosscharge.wav"); loadfx(FX_BOSSDIE, "bossdie.wav"); loadfx(FX_BOSSHIT, "bosshit.wav"); loadfx(FX_BOSSWALL, "bosswall.wav"); loadfx(FX_SPRAY, "spray.wav"); loadfx(FX_CANNON, "fusion.wav"); loadfx(FX_CRACK, "crack.wav"); loadfx(FX_PHONE, "phone.wav"); loadfx(FX_STAR, "star.wav"); loadfx(FX_STARHIT, "starhit.wav"); loadfx(FX_METEOR, "meteor.wav"); loadfx(FX_ENGAGED, "engaged.wav"); loadfx(FX_FLOOD, "flood.wav"); loadfx(FX_CARD, "card.wav"); loadfx(FX_POKER, "poker.wav"); loadfx(FX_SKULL, "skull.wav"); loadfx(FX_KEYPRESS, "1up.wav"); loadfx(FX_CATCH, "catch.wav"); loadfx(FX_GUN, "gun.wav"); loadfx(FX_ALARM, "alarm.wav"); loadfx(FX_ZAP, "zap.wav"); loadfx(FX_SNAILPREPARE, "longdrum.wav"); loadfx(FX_WHOOSH, "whoosh.wav"); loadfx(FX_BOOM2, "boom2.wav"); loadfx(FX_WAND, "wand.wav"); loadfx(FX_WHISTLE, "whistle.wav"); loadfx(FX_EVILLAUGH, "evillaugh.wav"); loadfx(FX_BIRDS, "birds.wav"); loadfx(FX_EXTRALIFE, "extralife.wav"); loadfx(FX_WARP, "warp.wav"); loadfx(FX_JETPACK, "jetpack.wav"); loadfx(FX_CAMERA, "camera.wav"); loadfx(FX_LASER, "laser.wav"); loadfx(FX_HISS, "hiss.wav"); loadfx(FX_CHOMP, "chomp.wav"); loadfx(FX_GROWL, "growl.wav"); loadfx(FX_LAMP, "lamp.wav"); loadfx(FX_SONAR, "pea.wav"); // load sound effects for (i = 0; i < MAXFX; i++) { if (!sfx[i]) { return B_TRUE; } } // set up callback Mix_ChannelFinished(channeldone); // load music sprintf(filename, "%s/music/main.mod",datadir); normalmusic = Mix_LoadMUS(filename); if (!normalmusic) { printf("can't load music\n"); return B_TRUE; } sprintf(filename, "%s/music/mainfast.mod",datadir); fastmusic = Mix_LoadMUS(filename); if (!fastmusic) { printf("can't load fast music\n"); return B_TRUE; } sprintf(filename, "%s/music/boss.mod",datadir); bossmusic = Mix_LoadMUS(filename); if (!bossmusic) { printf("can't load music\n"); return B_TRUE; } sprintf(filename, "%s/music/hiscore.mod",datadir); hiscoremusic = Mix_LoadMUS(filename); if (!hiscoremusic) { printf("can't load music\n"); return B_TRUE; } return B_FALSE; } void playfx(int num) { Mix_PlayChannel(-1, sfx[num], 0); } void playmusic(Mix_Music *toplay) { // is this one already playing? if ((curmusic == toplay) && (musicplaying)) { return; } /* stop music */ if (musicplaying) { Mix_HaltMusic(); } /* start music */ //music = toplay; Mix_PlayMusic(toplay, -1); if ((player && player->swimming) || (player2 && player2->swimming)) { Mix_VolumeMusic(MIX_MAX_VOLUME/3); } else { Mix_VolumeMusic(MIX_MAX_VOLUME); } curmusic = toplay; musicplaying = B_TRUE; } void stopmusic(void) { /* stop music */ if (musicplaying) { Mix_HaltMusic(); } musicplaying = B_FALSE; curmusic = NULL; } // callback for sound effects finishing void channeldone(int channel) { if (channel == CH_HURRYUP) { // start fast music playmusic(fastmusic); } } // move player towards new position // return distance left int moveto(sprite_t *p, int dstx, int dsty, double xspeed, double yspeed) { double ang,xs,ys; int distanceleft; int therex = B_FALSE,therey = B_FALSE; // figure out angle to player ang = atan2(dsty - p->y, dstx - p->x); xs = (cos(ang) * xspeed); ys = (sin(ang) * yspeed); if (p->x < dstx) { p->x += xs; if (p->x >= dstx) { p->x = dstx; } } if (p->x > dstx) { p->x += xs; if (p->x <= dstx) { p->x = dstx; } } if (p->x == dstx) { therex = B_TRUE; } if (p->y < dsty) { p->y += ys; if (p->y >= dsty) { p->y = dsty; } } if (p->y > dsty) { p->y += ys; if (p->y <= dsty) { p->y = dsty; } } if (p->y == dsty) { therey = B_TRUE; } // figure out distance to target distanceleft = getdistance(p->x,p->y,dstx,dsty); if (therex && therey) return 0; return distanceleft; } // grabs area behind a sprite into a temp buffer SDL_Surface *grabbehind(sprite_t *s, SDL_Surface *surf) { SDL_Rect area; // create buffer for player background /* if (surf) { SDL_FreeSurface(surf); surf = NULL; } surf = SDL_CreateRGBSurface(SDL_SWSURFACE, s->img->w, s->img->h, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, screen->format->Amask); SDL_DisplayFormat(surf); */ // remember area behind player area.x = s->x - s->img->w/2; area.y = s->y - s->img->h; area.w = surf->w; area.h = surf->h; SDL_BlitSurface(screen, &area, surf, NULL); return surf; } void dumpsprites(void) { sprite_t *s; int i = 0; int mcount = 0; for (s = sprite; s ; s = s->next) { printf("Sprite #%d: %s at %1.0f,%1.0f id=%d (",i,s->name,s->x,s->y, s->id); if (ismonster(s->id)) { printf("MONSTER, "); mcount++; } if (isfruit(s->id)) printf("FRUIT, "); if (isflower(s->id)) printf("FLOWER, "); if (isbullet(s->id)) printf("BULLET, "); if (iseffect(s->id)) printf("EFFECT, "); printf(")\n"); i++; } printf("--------\n"); printf("Total monsters: %d\n",mcount); printf("\n\n"); } // returns width int drawoutlinetext(SDL_Surface *where,int x, int y, int size, char *msg, SDL_Color *col, SDL_Color *bgcol) { SDL_Surface *surf; SDL_Rect area; int wid; area.w=0;area.h=0; //shadow surf = TTF_RenderText_Solid(font[size], msg, *bgcol); area.x = x-1; area.y = y; SDL_BlitSurface(surf, NULL, where, &area); area.x = x-1; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x+1; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x+1; area.y = y; SDL_BlitSurface(surf, NULL, where, &area); area.x = x+1; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x-1; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area); // text SDL_SetColors(surf, col, 1, 1); area.x = x; area.y = y; SDL_BlitSurface(surf, NULL, where, &area); wid = surf->w; SDL_FreeSurface(surf); return wid; } void drawoutlinecentretext(SDL_Surface *where, int y, int size, char *msg, SDL_Color *col, SDL_Color *bgcol) { SDL_Surface *surf; SDL_Rect area; int x; area.w=0;area.h=0; //shadow surf = TTF_RenderText_Solid(font[size], msg, *bgcol); x = 320 - (surf->w/2); area.x = x-1; area.y = y; SDL_BlitSurface(surf, NULL, where, &area); area.x = x-1; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x+1; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x+1; area.y = y; SDL_BlitSurface(surf, NULL, where, &area); area.x = x+1; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area); area.x = x-1; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area); // text SDL_SetColors(surf, col, 1, 1); area.x = x; area.y = y; SDL_BlitSurface(surf, NULL, where, &area); SDL_FreeSurface(surf); } void addoutlinetext(int x, int y, int size, char *msg, SDL_Color *col, SDL_Color *bgcol, int delay, int ttype) { int shadowtype; if (ttype == TT_HELP) { shadowtype = TT_HELPSHADOW; } else { shadowtype = TT_NORM; } addtext(x-1,y,size,msg,bgcol,delay,shadowtype); // outline addtext(x-1,y-1,size,msg,bgcol,delay,shadowtype); // outline addtext(x,y-1,size,msg,bgcol,delay,shadowtype); // outline addtext(x+1,y-1,size,msg,bgcol,delay,shadowtype); // outline addtext(x+1,y,size,msg,bgcol,delay,shadowtype); // outline addtext(x+1,y+1,size,msg,bgcol,delay,shadowtype); // outline addtext(x,y+1,size,msg,bgcol,delay,shadowtype); // outline addtext(x-1,y+1,size,msg,bgcol,delay,shadowtype); // outline addtext(x,y,size,msg,col,delay,ttype); // main text } char *addcommas(char *buffer, long num) { char tempbuf[MIDBUFLEN]; char *p; char *p2; int count; sprintf(tempbuf, "%ld",num); p2 = buffer; p = tempbuf; if (strlen(tempbuf) <= 3) { strcpy(buffer,tempbuf); return buffer; } else { count = ((strlen(tempbuf)-1) % 3)+1; } for (p = tempbuf; *p; p++) { if (count == 0) { count = 3; *p2 = ','; p2++; } *p2 = *p; p2++; count--; } *p2 = '\0'; return buffer; } int addscore(sprite_t *s, long amt) { int oldscore; oldscore = s->score; /* // less points in easy mode if (gamemode == GM_EASY) { amt /= 2; } */ s->score += amt; // each multiple of 100,000 if (isplayer(s)) { if ((s->score / 100000) > (oldscore / 100000)) { extralife(s); } } return amt; } void extralife(sprite_t *which) { playfx(FX_EXTRALIFE); which->lives += 1; addoutlinetext(which->x,which->y - which->img->h/2, TEXTSIZE_LIFE, "Extra life!",&green,&black,LIFEDELAY,TT_NORM); } // slowly change level to ice void doice(void) { int yy,xx,changed; sprite_t *s; int l2id; // just in case if (!curlevel->iced) { curlevel->iced = ICE_INPROGRESS; } // slowly change a level to ice //if (timer % ICESPEED == 0) { xx = 0; for (yy = curlevel->icey; yy >= 0; yy--) { // make sure tile is valid if ((yy >= 0) && (yy < LEVELH) && (xx >= 0) && (xx < LEVELW)) { tiletype_t *tt; changed = B_FALSE; // if not already a second layer here... //l2id = curlevel->map2[yy*LEVELW+xx]; tt = gettile(curlevel->map2[yy*LEVELW+xx]); l2id = tt->id; if (l2id == T_BLANK) { // add ice layer tt = gettile(curlevel->map[yy*LEVELW+xx]); switch (tt->id) { case T_FULL: curlevel->map2[yy*LEVELW+xx] = getuniq(T_ICE); changed = B_TRUE; break; case T_LAND: curlevel->map2[yy*LEVELW+xx] = getuniq(T_ICETOP); changed = B_TRUE; break; } } else { // certain l2 ids can still be replaced switch (l2id) { case T_FULL: curlevel->map2[yy*LEVELW+xx] = getuniq(T_ICE); changed = B_TRUE; break; case T_LAND: curlevel->map2[yy*LEVELW+xx] = getuniq(T_ICETOP); changed = B_TRUE; break; } } if (changed) { drawtile(temps, xx, yy); } } // finished? if ((xx == LEVELW-1) && (yy == LEVELH-1)) { curlevel->iced = ICE_COMPLETE; break; } xx++; if (xx >= LEVELW) break; } // ice any monsters for (s = sprite; s ; s = s->next) { if (ismonster(s->id)) { if ((s->x <= (xx*TILEW)) && (s->y <= (curlevel->icey*TILEH))) { if (!s->iced && !s->dead && !s->caughtby) { // ice it! s->iced = B_TRUE; s->jumping = B_FALSE; } } } } // increase icey for next time curlevel->icey++; } void adjustx(sprite_t *s,int framenum) { int newx,newy,diff; tiletype_t *tt; if (imageset[s->id].img[framenum] == NULL) { return; } if ((levelcomplete == LV_CLOUD) || (levelcomplete == LV_CLOUDLOOP)) { return; } if (imageset[s->id].img[framenum]->w > s->img->w) { diff = (imageset[s->id].img[framenum]->w - s->img->w) +1 ; } else { diff = (s->img->w - imageset[s->id].img[framenum]->w) +1 ; } newy = s->y-TILEH; // check RIGHT newx = s->x + (s->img->w/2); tt = gettileat(newx,newy,NULL,NULL); if (tt->solid == S_SOLID) { s->x -= diff; } // check LEFT newx = s->x - (s->img->w/2); tt = gettileat(newx,newy,NULL,NULL); if (tt->solid == S_SOLID) { s->x += diff; } } /* check for death & update movement status*/ void checksprites(void) { sprite_t *s, *nextsprite; int inair = 0; for (s = sprite ; s ; s = nextsprite) { s->moved = MV_NONE; nextsprite = s->next; if (ismonster(s->id)) { if ((s->dead && (s->dead != D_FINAL))) { inair++; } } if (s->dead == D_FINAL) { if (isplayer(s)) { int alldead; if (s->lives > 0) { /* if we have lives left, go back to start position */ setdefaults(s); if (s == player) { s->x = (curlevel->p1x * TILEW) + (TILEW/2); s->y = (curlevel->p1y * TILEH) + (TILEH/2); } else { s->x = (curlevel->p2x * TILEW) + (TILEW/2); s->y = (curlevel->p2y * TILEH) + (TILEH/2); } makeinvuln(s); } else { // permenantly dead - mark for later s->lives = -1; } // is everyone dead? alldead = B_TRUE; if (player) { if ((player->dead != D_FINAL) || (player->lives > 0)) alldead = B_FALSE; } if (player2) { if ((player2->dead != D_FINAL) || (player2->lives > 0)) alldead = B_FALSE; } if (alldead) { if (levelcomplete != LV_GAMEOVER) { // special type - when it expires, gameover timer will start addoutlinetext(320,240,TEXTSIZE_GAMEOVER,"Game Over",&red,&black,GAMEOVERDELAY,TT_GAMEOVER); levelcomplete = LV_GAMEOVER; stopmusic(); playfx(FX_GAMEOVER); } } } else { if ((s->id == P_PUFF) && (s->timer1 != 999)) { printf("puff deid without changing!!!\n"); } killsprite(s); // check for level completion checklevelend(); } } } if ((inair == 0) && (fruittime != -1)) { // reset fruit counter fruittime = -1; curfruittype = 0; } // check if we've hit the cloud if (levelcomplete == LV_NEXTLEV) { nextlevel(); } } void moveallsprites(void) { sprite_t *s; for (s = sprite; s ; s = s->next) { movesprite(s); } } void checkcollideall(void) { sprite_t *s; /* check collisions for player and effects */ for (s = sprite ; s ; s = s->next) { if (isplayer(s)) { if (!inintro()) { if (s->powerup != PW_GUNNER) { checkcollide(s); } } } else if (needscollisions(s->id)) { if (isplatform(s->id)) { checkcollideplatform(s); } else { checkcollide(s); } } else if ((s->id == P_BLACKCLOUD) && (globpowerup == PW_WHISTLE)) { checkcollide(s); } else if (inintro() && s->id == P_RAT) { checkcollide(s); } else if ((s->id == P_ANT1) || (s->id == P_ANT2) || (s->id == P_ANT3)) { checkcollide(s); } } } void drawallsprites(void) { sprite_t *s; int lastframe; /* draw non-puff sprites */ for (s = sprite ; s ; s = s->next) { if (s->id != P_PUFF) { lastframe = s->frame; drawsprite(s); if (s->frame != lastframe) { if ((s->id == P_KINGFLY) || ((s->id == P_FLY) && (s->owner))) { // don't adjust } else { adjustx(s, s->frame); } } } } /* draw puff sprites */ for (s = sprite ; s ; s = s->next) { if (s->id == P_PUFF) drawsprite(s); } } // check if sprite has passed off bottom/top of screen void checkwrap(sprite_t *s) { if (!s) return; if (!s->dead) { if (!iseffect(s->id)) { /* if we've fallen off the bottom... */ if (s->y > (480+s->img->h)) { if (inintro()) { // die s->dead = D_FINAL; } else { // move to top s->y = -s->img->h; } } /* if we've gone off the top */ if (s->y < -s->img->h) { // move to bottom s->y = (480+s->img->h); } } } } int getcurworld(void) { return getworld(curlevelnum); } int getcurlevel(void) { return getlevel(curlevelnum); } // returns how high a given monster will jump int getmonjumpspeed(sprite_t *s ) { switch (s->id) { case P_SLUG: if (s->jumpdir == 0) { // jumping straight up return MONJUMPSPEED; } else { // jumping horizontally return 3; } case P_KINGSNAIL: return 3; default: return MONJUMPSPEED; } } // returns how long to pause before jumping int getjumpdelay(int mid) { switch (mid) { case P_SLUG: return 30; case P_KINGSNAIL: return 60; default: return 60; } } void togglepause(void) { if (paused) { Mix_ResumeMusic(); paused = B_FALSE; } else { Mix_PauseMusic(); paused = B_TRUE; } } void togglefullscreen(void) { // close window //SDL_Quit(); // set fullscreen variable if (fullscreen) { fullscreen = B_FALSE; } else { fullscreen = B_TRUE; } screen=SDL_SetVideoMode(screen->w,screen->h,screen->format->BitsPerPixel,SDL_SWSURFACE|(screen->flags&SDL_FULLSCREEN?0:SDL_FULLSCREEN)); // set title bar if required if (!fullscreen) { SDL_WM_SetCaption(progname, progname); } // redraw background SDL_BlitSurface(temps, NULL, screen, NULL); if (!paused) { /* redo framerate manager */ SDL_setFramerate(&manager, WANTFPS); } } void initsdl(void) { int i; if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE)==-1) { printf("SDL_Init: %s\n", SDL_GetError()); exit(1); } vidargs = 0; if (fullscreen) { vidargs |= SDL_FULLSCREEN; } #ifdef OPENGL SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); //SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); screen = SDL_SetVideoMode(640,480,16,SDL_OPENGLBLIT|vidargs); #else //screen = SDL_SetVideoMode(640,480,16,SDL_SWSURFACE|SDL_DOUBLEBUF|vidargs); // Try for 16 bit mode, but SDL_ANYFORMAT means that 32 bit is acceptable. screen = SDL_SetVideoMode(640,480,16,SDL_SWSURFACE|SDL_ANYFORMAT|vidargs); #endif // set drawpixel function based on what depth we ended up with if (screen->format->BitsPerPixel == 32) { drawpixel = drawpixel32; printf("32 bit mode in use.\n"); } else { drawpixel = drawpixel16; printf("16 bit mode in use.\n"); } // set title bar SDL_WM_SetCaption(progname, progname); if (!screen) { printf("Failed to open window: %s\n", SDL_GetError()); exit(1); } SDL_ShowCursor(SDL_DISABLE); // find joysticks havejoysticks = 0; SDL_InitSubSystem(SDL_INIT_JOYSTICK); for (i = 0; i < 2; i++) { joy[i] = SDL_JoystickOpen(i); if (joy[i]) { joyname[i] = SDL_JoystickName(i); printf("Joystick #%d found: %s",i, joyname[i]); if (strstr(joyname[i], "aystati")) { joytype[i] = J_PLAYSTATION; printf(" (PS3 controller)\n"); } else if (strstr(joyname[i], "Wii")) { joytype[i] = J_WII; printf(" (Wiimote)\n"); } else { joytype[i] = J_OTHER; printf(" (Generic joystick)\n"); } havejoysticks++; joybuttons[i] = SDL_JoystickNumButtons(joy[i]); printf("Joy %d has %d buttons\n",i,joybuttons[i]); if (joytype[i] == J_PLAYSTATION) { joyanalog[i] = B_TRUE; } else { joyanalog[i] = B_FALSE; } if (joyanalog[i]) { joythresh[i] = JOYTHRESH_ANA; } else { joythresh[i] = JOYTHRESH_DIG; } } } if (havejoysticks) { setjoymappings(); SDL_JoystickEventState(SDL_ENABLE); } else { printf("No joysticks found.\n"); } SDL_EnableUNICODE(1); } // player collects the given fruit void getfruit(sprite_t *giveto, sprite_t *fruit, int multiplier) { char tempm[MIDBUFLEN]; char tempm2[BUFLEN]; int gotscore = fruit->score; int modscore = gotscore; // default int i; SDL_Color *col, *bgcol; /* kill the fruit */ fruit->dead = D_FINAL; /* give points to the player */ for (i = 0; i < multiplier; i++) { modscore = addscore(giveto, gotscore); } if (fruit->id == P_RANDOM) { // change id to whatever it currently looks like fruit->id = fruit->timer1; } /* handle fruit effects */ if (!dofruiteffect(giveto, fruit)) { playfx(FX_FRUIT); col = getcolour(fruit->id); bgcol = getbgcolour(fruit->id); if (multiplier <= 1) { addcommas(tempm, modscore); //sprintf(tempm, "%d", modscore); addoutlinetext(fruit->x,fruit->y - fruit->img->h/2, TEXTSIZE_POINTS, tempm, col,bgcol,POINTSDELAY,TT_NORM); } else { addcommas(tempm, modscore); sprintf(tempm2, "%s x %d" , tempm,multiplier); addoutlinetext(fruit->x,fruit->y - fruit->img->h/2, TEXTSIZE_POINTS + 2*multiplier, tempm2, col,bgcol,POINTSDELAY,TT_NORM); } // last goin coin is special... if (fruit->id == P_GOLDCOIN) { int ccount; sprite_t *s2; ccount = 0; for (s2 = sprite; s2 ; s2 = s2->next) { if (s2 != fruit) { if (s2->id == P_GOLDCOIN) { ccount++; } else if ((s2->id == P_PUFF) && (s2->timer3 == P_GOLDCOIN)) { ccount++; } } } if (ccount == 0) { addoutlinetext(fruit->x,fruit->y - fruit->img->h/2, TEXTSIZE_BOMB, "Perfect!", &green,&black,CLOVERDELAY,TT_NORM); forcegold = B_TRUE; forcegoldlev = curlevelnum; } } } } // slowly change level to water void doflood(void) { int yy,xx,changed; int l2id; // just in case if (!curlevel->iced) { curlevel->iced = WATER_INPROGRESS; } // slowly change a level to water //if (timer % ICESPEED == 0) { for (yy = curlevel->icey ; (yy <= curlevel->icey+1) && (yy < LEVELH); yy++) { for (xx = 0; xx < LEVELW; xx++) { tiletype_t *tt; changed = B_FALSE; // if not already a second layer here... //l2id = curlevel->map2[yy*LEVELW+xx]; tt = gettile(curlevel->map2[yy*LEVELW+xx]); l2id = tt->id; if (l2id == T_BLANK) { // maybe change to water ice layer tt = gettile(curlevel->map[yy*LEVELW+xx]); switch (tt->id) { case T_BLANK: case T_SKY: case T_SPIKES: case T_WATER: case T_WATERTOP: if (yy == curlevel->icey) { curlevel->map2[yy*LEVELW+xx] = getuniq(T_WATERTOP); } else { curlevel->map2[yy*LEVELW+xx] = getuniq(T_WATER); } changed = B_TRUE; break; } } else { // certain l2 ids can still be replaced switch (l2id) { case T_SKY: case T_WATER: case T_WATERTOP: if (yy == curlevel->icey) { curlevel->map2[yy*LEVELW+xx] = getuniq(T_WATERTOP); } else { curlevel->map2[yy*LEVELW+xx] = getuniq(T_WATER); } changed = B_TRUE; break; } } if (changed) { drawtile(temps, xx, yy); } } } // decrease icey for next time curlevel->icey--; if (curlevel->icey < 0) { curlevel->iced = WATER_COMPLETE; } } // put flood effect back to normal void undoflood(void) { int x,y; for (y = 0 ; y < LEVELH; y++) { for (x = 0 ; x < LEVELW; x++) { curlevel->map2[y*LEVELW+x] = savemap[y*LEVELW+x]; drawtile(temps, x, y); } } SDL_BlitSurface(temps, NULL, screen, NULL); } sprite_t *haspowerupany(int pid) { if (player && haspowerup(player,pid)) return player; if (player2 && haspowerup(player2,pid)) return player2; return NULL; } int haspowerup(sprite_t *s, int pid) { if (!s) return B_FALSE; switch (pid) { case P_SPEED: if (s->speed != 1) { return B_TRUE; } break; case P_NUMNETS: if (s->netmax >= 4 ) { return B_TRUE; } break; case P_BIGNET: if (s->netbig) { return B_TRUE; } break; case P_MASKPOWERUP: if (s->hasmask) { return B_TRUE; } break; case P_TROPHY: if ((s->netmax >= 4) && (s->netbig) && (s->speed != 1)) { return B_TRUE; } break; case P_HELMET: if (s->armour) { return B_TRUE; } break; case P_BELL: if (s->hasbell) { return B_TRUE; } break; case P_GEMBOOST: if (s->gemboost >= 3) { return B_TRUE; } break; case P_HONEY: if (s->netsticky) { return B_TRUE; } break; case P_WINGBOOTS: if (s->doublejump) { return B_TRUE; } break; default: if (s->powerup == pid) return B_TRUE; } return B_FALSE; } void gaincard(sprite_t *s, int cardid) { int i; char msg[BUFLEN]; // just in case if (s->numcards >= MAXCARDS) return; // gain the card s->card[s->numcards] = cardid; s->numcards++; // check for a full hand of cards if (s->numcards == MAXCARDS) { int cardwidth,cardheight; SDL_Rect area; sprite_t *newsp; cardwidth = imageset[P_FIRSTCARD].img[F_WALK1]->w; cardheight = imageset[P_FIRSTCARD].img[F_WALK1]->h; // remember old level state oldlevelcomplete = levelcomplete; // change state to LV_CARDCOMPLETE // (in this state, everything is frozen ) levelcomplete = LV_DOPOKER; // generate FIVECARDS sprite if (s == player) { newsp = addsprite(P_FIVECARDS, CARDX, CARDY, "fivecards"); } else { int cardx2 = 640 - CARDX - (5*(imageset[P_FIRSTCARD].img[F_WALK1]->w + 2)); newsp = addsprite(P_FIVECARDS, cardx2, CARDY, "fivecards"); } newsp->owner = s; // create blank image newsp->img = SDL_CreateRGBSurface(SDL_SWSURFACE, (cardwidth+2)*MAXCARDS, cardheight, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask,screen->format->Bmask, screen->format->Amask); SDL_FillRect(newsp->img, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); // fill in the cards if (s == player) { // left to right area.x = 0; area.y = 0; area.w = 0; area.h = 0; for (i = 0; i < s->numcards; i++) { SDL_Surface *cardimg; cardimg = imageset[s->card[i]].img[F_WALK1]; if (cardimg == NULL){ printf("ERROR! Card image is null!!\n"); fflush(stdout); } SDL_BlitSurface(cardimg, NULL, newsp->img, &area); area.x += (cardimg->w + 2); } } else { // right to left area.x = 4*(cardwidth+2); area.y = 0; area.w = 0; area.h = 0; for (i = 0; i < s->numcards; i++) { SDL_Surface *cardimg; cardimg = imageset[s->card[i]].img[F_WALK1]; if (cardimg == NULL){ printf("ERROR! Card image is null!!\n"); fflush(stdout); } SDL_BlitSurface(cardimg, NULL, newsp->img, &area); area.x -= (cardimg->w + 2); } } // adjust x value so we can use drawsprite() newsp->x += (newsp->img->w / 2); newsp->y += (newsp->img->h); // figure out what happened pokereffect = getpokereffect(s); getpokermsg2(pokereffect, msg); // display BIG message addoutlinetext(320,180,TEXTSIZE_POKER,getpokermsg(pokereffect),&green, &black, POKERDELAY,TT_NORM); addoutlinetext(320,290,TEXTSIZE_POKER,msg,&green, &black, POKERDELAY,TT_NORM); // pause music Mix_PauseMusic(); // sound effect playfx(FX_POKER); } } // figure out what poker effect to apply and set variables // also record which cards were used in pl->usedcards int getpokereffect(sprite_t *pl) { int i, c, count, curval, val, suit, found; // default pokerpoints = 0; /// mark all player cards as unused for (c = 0; c < MAXCARDS; c++) { pl->usedcard[c] = B_FALSE; } // * check for royal straight flush (perm trophy) // for each card, count up from here for (i = 0; i < MAXCARDS; i++) { count = 1; val = getcardvalue(pl->card[i]); suit = getcardsuit(pl->card[i]); curval = val; found = B_TRUE; // start at this card while (found && count < 5) { found = B_FALSE; for (c = 0; c < MAXCARDS; c++) { if (c != i) { if (getcardsuit(pl->card[c]) == suit) { // same suit? if (getcardvalue(pl->card[c]) == curval + 1) { curval++; count++; found = B_TRUE; } } } } } // got it? if (count >= 5) { if (curval == 13) { // last card was a king // GOT IT! /// mark all player cards as USED for (c = 0; c < MAXCARDS; c++) { pl->usedcard[c] = B_TRUE; } return PE_ROYALFLUSH; } } } // * check for straight flush (skip 7 levels) for (i = 0; i < MAXCARDS; i++) { count = 1; val = getcardvalue(pl->card[i]); suit = getcardsuit(pl->card[i]); curval = val; found = B_TRUE; // start at this card while (found && count < 5) { found = B_FALSE; for (c = 0; c < MAXCARDS; c++) { if (c != i) { if (getcardsuit(pl->card[c]) == suit) { // same suit? if (getcardvalue(pl->card[c]) == curval + 1) { curval++; count++; found = B_TRUE; } } } } } // got it? if (count >= 5) { // GOT IT! /// mark all player cards as USED for (c = 0; c < MAXCARDS; c++) { pl->usedcard[c] = B_TRUE; } return PE_STRAIGHTFLUSH; } } // * check for four of a kind (perm 4 nets ) for (i = 0; i < MAXCARDS; i++) { val = getcardvalue(pl->card[i]); count = 1; for (c = 0; c < MAXCARDS; c++) { if (c != i) { if (getcardvalue(pl->card[c]) == val ) { count++; } } } // got it? if (count >= 4) { // GOT IT! /// mark all player cards with correct value as USED for (c = 0; c < MAXCARDS; c++) { if (getcardvalue(pl->card[c]) == val) { pl->usedcard[c] = B_TRUE; } } return PE_FOUR; } } // * check for full house (perm bignet ) for (i = 0; i < MAXCARDS; i++) { val = getcardvalue(pl->card[i]); count = 1; for (c = 0; c < MAXCARDS; c++) { if (c != i) { if (getcardvalue(pl->card[c]) == val ) { count++; } } } // got it? if (count >= 3) { int ii, val2,cc,count2; // got a triple with this card - now look for doubles for (ii = 0; ii < MAXCARDS; ii++) { val2 = getcardvalue(pl->card[ii]); if (val2 != val) { // must be a DIFFERENT value! count2 = 1; for (cc = 0; cc < MAXCARDS; cc++) { if (cc != ii) { if (getcardvalue(pl->card[cc]) == val2 ) { count2++; } } } // got it? if (count2 >= 2) { // GOT IT! - double with this one /// mark all player cards as USED for (c = 0; c < MAXCARDS; c++) { pl->usedcard[c] = B_TRUE; } return PE_FULLHOUSE; } } } } } // * check for flush (skip 5 levels ) for (i = 0; i < MAXCARDS; i++) { suit = getcardsuit(pl->card[i]); count = 1; for (c = 0; c < MAXCARDS; c++) { if (c != i) { if (getcardsuit(pl->card[c]) == suit ) { count++; } } } // got it? if (count >= 5) { // GOT IT! /// mark all player cards as USED for (c = 0; c < MAXCARDS; c++) { pl->usedcard[c] = B_TRUE; } return PE_FLUSH; } } // * check for straight (perm honey) for (i = 0; i < MAXCARDS; i++) { count = 1; val = getcardvalue(pl->card[i]); suit = getcardsuit(pl->card[i]); curval = val; found = B_TRUE; // start at this card while (found && count < 5) { found = B_FALSE; for (c = 0; c < MAXCARDS; c++) { if (c != i) { if (getcardvalue(pl->card[c]) == curval + 1) { curval++; count++; found = B_TRUE; } } } } // got it? if (count >= 5) { // GOT IT! /// mark all player cards as USED for (c = 0; c < MAXCARDS; c++) { pl->usedcard[c] = B_TRUE; } return PE_STRAIGHT; } } // * check for triple (skip 3 levels ) for (i = 0; i < MAXCARDS; i++) { val = getcardvalue(pl->card[i]); count = 1; for (c = 0; c < MAXCARDS; c++) { if (c != i) { if (getcardvalue(pl->card[c]) == val ) { count++; } } } // got it? if (count >= 3) { // GOT IT! /// mark all player cards with correct value as USED for (c = 0; c < MAXCARDS; c++) { if (getcardvalue(pl->card[c]) == val) { pl->usedcard[c] = B_TRUE; } } return PE_TRIPLE; } } // * check for two pair (value * 2000 for each card in pair ) for (i = 0; i < MAXCARDS; i++) { val = getcardvalue(pl->card[i]); count = 1; for (c = 0; c < MAXCARDS; c++) { if (c != i) { if (getcardvalue(pl->card[c]) == val ) { count++; } } } // got it? if (count >= 2) { int ii, val2,cc,count2; // got a pair with this card - now look for another one for (ii = 0; ii < MAXCARDS; ii++) { val2 = getcardvalue(pl->card[ii]); if (val2 != val) { // must be a DIFFERENT value! count2 = 1; for (cc = 0; cc < MAXCARDS; cc++) { if (cc != ii) { if (getcardvalue(pl->card[cc]) == val2 ) { count2++; } } } // got it? if (count2 >= 2) { // GOT IT! - double with this one /// mark all player cards as USED and assign points pokerpoints = 0; for (c = 0; c < MAXCARDS; c++) { int thisval; thisval = getcardvalue(pl->card[c]); if ((thisval == val) || (thisval == val2)) { pokerpoints += (thisval * 4000); pl->usedcard[c] = B_TRUE; } } return PE_TWOPAIR; } } } } } // * check for pair (value * 2000 for each card in pair ) for (i = 0; i < MAXCARDS; i++) { val = getcardvalue(pl->card[i]); count = 1; for (c = 0; c < MAXCARDS; c++) { if (c != i) { if (getcardvalue(pl->card[c]) == val ) { count++; } } } // got it? if (count >= 2) { // GOT IT! // assign points and // mark all player cards with correct value as USED pokerpoints = 0; for (c = 0; c < MAXCARDS; c++) { int thisval; thisval = getcardvalue(pl->card[c]); if (thisval == val) { pokerpoints += (thisval * 4000); pl->usedcard[c] = B_TRUE; } } return PE_PAIR; } } // * default is high card (value * 1000) // find highest card count = -1;// use this to track highest card index curval = -1; for (i = 0; i < MAXCARDS; i++) { val = getcardvalue(pl->card[i]); if (val > curval) { curval = val; count = i; } } // assign points pokerpoints = curval * 1000; // mark used card for (c = 0; c < MAXCARDS; c++) { if (c == count) { pl->usedcard[c] = B_TRUE; } else { pl->usedcard[c] = B_FALSE; } } return PE_HIGHCARD; } // actually apply the current poker effect (in global "pokereffect") void dopokereffect(sprite_t *pl, int effect) { char tempmsg[BUFLEN]; sprite_t *s2, *nexts; switch (effect) { case PE_HIGHCARD: case PE_TWOPAIR: case PE_PAIR: // points sprintf(tempmsg, "%d",addscore(pl, pokerpoints)); addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM); break; case PE_TRIPLE: // skip 3 levels sprintf(tempmsg, "Skip 3 levels!"); addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM); // set powerup pl->powerup = PW_PHONE; skiplevels = 2; // kill all enemies for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isbullet(s2->id) || ismonster(s2->id)) { s2->dead = D_FINAL; if (s2->caughtby) { uncatch(s2); } } } // call in cloud immediately levelcomplete = LV_FINAL; break; case PE_STRAIGHT: // permenant big net pl->permbignet = B_TRUE; pl->netbig = B_TRUE; sprintf(tempmsg, "Permenant Big Nets!"); addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM); break; case PE_FLUSH: // skip 5 levels sprintf(tempmsg, "Skip 5 levels!"); addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM); // set powerup pl->powerup = PW_PHONE; skiplevels = 4; // kill all enemies for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isbullet(s2->id) || ismonster(s2->id)) { s2->dead = D_FINAL; if (s2->caughtby) { uncatch(s2); } } } // call in cloud immediately levelcomplete = LV_FINAL; break; case PE_FULLHOUSE: // permenant double jump pl->permdoublejump = B_TRUE; pl->doublejump = B_TRUE; sprintf(tempmsg, "Permenant Double Jump!"); addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM); break; case PE_FOUR: // permenant max nets pl->permnumnets = 4; pl->netmax = 4; sprintf(tempmsg, "Permenant Max Nets!"); addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM); break; case PE_STRAIGHTFLUSH: // skip 7 levels sprintf(tempmsg, "Skip 7 levels!"); addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM); // set powerup pl->powerup = PW_PHONE; skiplevels = 6; // kill all enemies for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isbullet(s2->id) || ismonster(s2->id)) { s2->dead = D_FINAL; if (s2->caughtby) { uncatch(s2); } } } // call in cloud immediately levelcomplete = LV_FINAL; break; case PE_ROYALFLUSH: // permenant trophy pl->permspeed = B_TRUE; pl->permbignet = B_TRUE; pl->permnumnets = 4; pl->speed = 2; pl->netbig = B_TRUE; pl->netmax = 4; sprintf(tempmsg, "Permenant full power!"); addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM); break; } } char *getpokermsg(int effect) { switch (effect) { case PE_HIGHCARD: return "High Card"; case PE_PAIR: return "Pair!"; case PE_TWOPAIR: return "Two Pairs!"; case PE_TRIPLE: return "Triple!"; case PE_STRAIGHT: return "Straight!"; case PE_FLUSH: return "Flush!"; case PE_FULLHOUSE: return "Full House!"; case PE_FOUR: return "Four of a Kind!"; case PE_STRAIGHTFLUSH: return "Straight Flush!"; case PE_ROYALFLUSH: return "ROYAL FLUSH!"; } return "unknown"; } char *getpokermsg2(int effect, char *buf) { sprintf(buf, "Unknown"); switch (effect) { case PE_HIGHCARD: sprintf(buf, "%d points",pokerpoints); break; case PE_PAIR: sprintf(buf, "%d points",pokerpoints); break; case PE_TWOPAIR: sprintf(buf, "%d points",pokerpoints); break; case PE_TRIPLE: sprintf(buf, "Skip 3 levels"); break; case PE_STRAIGHT: sprintf(buf, "Permenant Big Nets"); break; case PE_FLUSH: sprintf(buf, "Skip 5 levels"); break; case PE_FULLHOUSE: sprintf(buf, "Permenant Double Jump"); break; case PE_FOUR: sprintf(buf, "Permenant 4x Nets"); break; case PE_STRAIGHTFLUSH: sprintf(buf, "Skip 7 levels"); break; case PE_ROYALFLUSH: sprintf(buf, "Permenant Full Power"); break; } return buf; } void handleinput(void) { SDL_Event event; /* check for key releases */ SDL_PumpEvents(); while (SDL_PollEvent(&event)) { if (event.type == SDL_KEYUP) { // TODO: can only add credits in title screen ? if ((event.key.keysym.sym == SDLK_5) || (event.key.keysym.sym == SDLK_6)) { addcredit(); } if (levelcomplete == LV_HELPFREEZE) { if ((event.key.keysym.sym == KEY_SHOOT) || (event.key.keysym.sym == KEY_SLAM) || (event.key.keysym.sym == SDLK_s) || (event.key.keysym.sym == SDLK_f)) { levelcomplete = oldlevelcomplete; } } } else if (havejoysticks && (event.type == SDL_JOYBUTTONUP)) { if (levelcomplete == LV_HELPFREEZE) { if ((joybuttontokey(event.jbutton.button) == KEY_SHOOT) || (joybuttontokey(event.jbutton.button) == KEY_SLAM)) { levelcomplete = oldlevelcomplete; } } } } // don't accept other input in helpfreeze state if (levelcomplete == LV_HELPFREEZE) return; // now handle key preses /joystick getinput(); /* ************************************************************ These keys can always be pressed ************************************************************/ // toggle fullscreen if (keydown(0, SDLK_F3)) { if (toggletimer == 0) { // always pause first paused = B_TRUE; togglefullscreen(); toggletimer = 40; } } // pause if (keydown(0, SDLK_p)) { if (toggletimer == 0) { togglepause(); toggletimer = 80; } } // quit if (keydown(0, SDLK_ESCAPE)) { exit(1); } if (keydown(0, SDLK_F2)) { // show framerate if (toggletimer == 0) { if (wantframerate) { wantframerate = B_FALSE; } else { wantframerate = B_TRUE; } toggletimer = 80; } } // 1up/2up if ( (player && keydown(0, SDLK_1)) || (player2 && keydown(0, SDLK_2))) { if (inintro()) { // skip intro nextlevel(); } } if (cheat) { if (keydown(0, SDLK_q)) { gtime = nexthurryup-1; //gtime = nexthurryup+14; } if (keydown(0, SDLK_b)) { //gtime = nexthurryup-1; if (player && !player->dead) { player->lives = 1; } if (player2 && !player2->dead) { player2->lives = 1; } } if (keydown(0, SDLK_t)) { if (player->numcards == 0) { //gaincard(player, getrandomcard()); //gaincard(player, getrandomcard()); //gaincard(player, getrandomcard()); //gaincard(player, getrandomcard()); gaincard(player, P_CARDD4); gaincard(player, P_CARDD5); gaincard(player, P_CARDD1); gaincard(player, P_CARDDJ); gaincard(player, P_CARDD10); } } if (keydown(0, SDLK_u)) { if (player2->numcards == 0) { //gaincard(player, getrandomcard()); //gaincard(player, getrandomcard()); //gaincard(player, getrandomcard()); //gaincard(player, getrandomcard()); gaincard(player2, P_CARDD4); gaincard(player2, P_CARDC5); gaincard(player2, P_CARDD5); gaincard(player2, P_CARDSJ); gaincard(player2, P_CARDD10); } } if (keydown(0, SDLK_e)) { if (toggletimer == 0) { addscore(player, 100001); toggletimer = 30; } } if (keydown(0, SDLK_v)) { // cheat if (toggletimer == 0) { // all powerups playfx(FX_POWERUP); sprintf(tempm, "Cheat!"); if (player) { player->netmax = 4; // all nets player->netbig = B_TRUE; // big net player->speed = 2; // fast player->netsticky = B_TRUE; player->doublejump = B_TRUE; player->hasbell = B_TRUE; player->umbrella = B_TRUE; player->armour = B_TRUE; player->id = P_ARMOUR; // change how the player looks player->hasmask = B_TRUE; addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY,TT_NORM); } if (player2) { player2->netmax = 4; // all nets player2->netbig = B_TRUE; // big net player2->speed = 2; // fast player2->netsticky = B_TRUE; player2->doublejump = B_TRUE; player2->hasbell = B_TRUE; player2->hasmask = B_TRUE; player2->umbrella = B_TRUE; addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY,TT_NORM); } toggletimer = 80; } } if (keydown(0, SDLK_n)) { if (toggletimer == 0) { // nextlevel(); sprite_t *s2, *nexts; // kill all enemies and fruits for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isbullet(s2->id) || ismonster(s2->id) || isfruit(s2->id)) { s2->dead = D_FINAL; if (ismonster(s2->id)) { if (s2->caughtby) { uncatch(s2); } } } } // call in cloud immediately levelcomplete = LV_FINAL; toggletimer = 50; } } /* if (keydown(0, SDLK_d)) { if (toggletimer == 0) { // dump sprites dumpsprites(); toggletimer = 50; } } */ /* if (keydown(SDLK_d)) { sprite_t *s2,*nexts; // set powerup player->powerup = PW_PHONE; // kill all enemies for (s2 = sprite; s2 ; s2 = nexts) { nexts = s2->next; if (isbullet(s2->id) || ismonster(s2->id)) { s2->dead = D_FINAL; if (s2->caughtby) { uncatch(s2); player->netcaught--; } } } } */ } // revive from dead or join in? if (levelcomplete == LV_INPROGRESS) { if (keydown(0, SDLK_1)) { if (player) { if ((player->dead == D_FINAL) && (player->lives == -1)) { if (credits >= 1) { double px,py; // lose credit and come back to life credits--; setdefaults(player); player->lives = INITPLAYERLIVES; player->score = 0; playfx(FX_EXTRALIFE); px = (curlevel->p1x * TILEW) + (TILEW/2); py = (curlevel->p1y * TILEH) + TILEH-2; puffin(-1, px, py-TILEH, "nothing", 0); puffin(-1, px, py, "nothing", 0); if (!lockcredits) { lockcredits = B_TRUE; addoutlinetext(px,py - TILEH, TEXTSIZE_SCORE, "Credits locked",&yellow,&red2,DIEDELAY, TT_NORM); } } } } else { // !player if (credits >= 1) { double px,py; // join the game credits--; px = (curlevel->p1x * TILEW) + (TILEW/2); py = (curlevel->p1y * TILEH) + TILEH-2; want1up = B_TRUE; player = addsprite(P_PLAYER, px, py, "Player 1" ); setdefaults(player); puffin(-1, px, py-TILEH, "nothing", 0); puffin(-1, px, py, "nothing", 0); makeinvuln(player); player->score = 0; if (gamemode == GM_EASY) { player->permarmour = B_TRUE; player->armour = B_TRUE; player->id = P_ARMOUR; } else { player->permarmour = B_FALSE; player->armour = B_FALSE; player->id = P_PLAYER; } player->lives = INITPLAYERLIVES; playfx(FX_EXTRALIFE); } } } if (keydown(0, SDLK_2)) { if (player2) { if ((player2->dead == D_FINAL) && (player2->lives == -1)) { if (credits >= 1) { double px,py; // lose credit and come back to life credits--; setdefaults(player2); player2->lives = INITPLAYERLIVES; player2->score = 0; playfx(FX_EXTRALIFE); px = (curlevel->p2x * TILEW) + (TILEW/2); py = (curlevel->p2y * TILEH) + TILEH-2; puffin(-1, px, py-TILEH, "nothing", 0); puffin(-1, px, py, "nothing", 0); if (!lockcredits) { lockcredits = B_TRUE; addoutlinetext(px,py - TILEH, TEXTSIZE_SCORE, "Credits locked",&yellow,&red2,DIEDELAY, TT_NORM); } } } } else { // !player2 if (credits >= 1) { double px,py; // join the game credits--; px = (curlevel->p2x * TILEW) + (TILEW/2); py = (curlevel->p2y * TILEH) + TILEH-2; want1up = B_TRUE; player2 = addsprite(P_PLAYER2, px, py, "Player 2" ); setdefaults(player2); puffin(-1, px, py-TILEH, "nothing", 0); puffin(-1, px, py, "nothing", 0); makeinvuln(player2); player2->score = 0; if (gamemode == GM_EASY) { player2->permarmour = B_TRUE; player2->armour = B_TRUE; player2->id = P_ARMOUR2; } else { player2->permarmour = B_FALSE; player2->armour = B_FALSE; player2->id = P_PLAYER2; } player2->lives = INITPLAYERLIVES; playfx(FX_EXTRALIFE); } } } } /* ************************************************************ Player movement ************************************************************/ if ((!inintro()) && !paused && (!levelcomplete != LV_DOPOKER) ) { // is cloud touching the player? if (levelcomplete == LV_CLOUD) { sprite_t *c; int hitplayer1 = B_FALSE,hitplayer2 = B_FALSE; for (c = sprite ; c ; c = c->next) { if (player) { if ((c->owner == player) && (c->timer1 == LV_CLOUDLOOP)) { // can't move hitplayer1 = B_TRUE; } } if (player2) { if ((c->owner == player2) && (c->timer1 == LV_CLOUDLOOP)) { // can't move hitplayer2 = B_TRUE; } } } if (!hitplayer1) doplayermovement(player); if (!hitplayer2) doplayermovement(player2); } else { doplayermovement(player); doplayermovement(player2); } } // ignore other events while (SDL_PollEvent(&event)) { } } void swimup(sprite_t *pl) { int pnum; if (pl == player) { pnum = 0; } else if (pl == player2) { pnum = 1; } else return; // only valid for players if (pl->moved & MV_SWIM) { return; } pl->falling = B_FALSE; if (!isroofabove(pl)) { // is there water above us too? if (isinwaterpoint(pl->x, pl->y-TILEH)) { double swimspeed; swimspeed = getspeed(pl); if (pl->hasmask) { swimspeed *= 1.5; } else { swimspeed *= 2; } // if so, swim up pl->y -= swimspeed; pl->moved |= MV_SWIM; } else { int whichway; // if not, jump up pl->climbing = B_FALSE; if (keydown(pnum, KEY_RIGHT)) { whichway = 1; } else if (keydown(pnum, KEY_LEFT)) { whichway = -1; } else { whichway = 0; } playfx(FX_SPLASH); jump(pl, whichway); } } } void swimdown(sprite_t *pl) { if (pl->moved & MV_SWIM) { return; } pl->falling = B_FALSE; if (!isonground(pl)) { double swimspeed; // swim down swimspeed = getspeed(pl); if (pl->hasmask) { swimspeed *= 1.5; } else { swimspeed *= 2; } pl->y += swimspeed; pl->moved |= MV_SWIM; } } void trytojump(sprite_t *pl) { int pnum; if (pl == player) { pnum = 0; } else if (pl == player2) { pnum = 1; } else return; // only valid for players if (pl->caughtby) return; // can't jump while slamming if (pl->slamming) return; if (isinwater(pl)) { // in water? // swim up if (!pl->jumping) { swimup(pl); } } else { // not in water // jump if (!pl->jumping || (pl->doublejump && pl->doublejumpready && !pl->useddoublejump)) { if (!pl->falling || (pl->doublejump && pl->doublejumpready && !pl->useddoublejump)) { if (isonground(pl) || isonladder(pl) || pl->doublejump ) { /* dropping through a bridge */ if (keydown(pnum,KEY_DOWN)) { if (isonbridge(pl) && !pl->falling) { /* drop down */ pl->dropping = B_TRUE; pl->dropx = pl->x / TILEW; pl->dropy = pl->y / TILEH; } } else { // jumping int whichway; if (keydown(pnum,KEY_RIGHT)) { whichway = 1; } else if (keydown(pnum,KEY_LEFT)) { whichway = -1; } else { whichway = 0; } jump(pl, whichway); } } } } } } void trytoslam(sprite_t *pl) { if (pl->caughtby) return; if ((!pl->netting) && (!pl->slamming)) { /* slam */ if ((!pl->slamming) && (isonground(pl) && !pl->climbing)) { playfx(FX_SLAM); pl->slamming = B_TRUE; pl->slamangle = 0; pl->netxstart = pl->x - (pl->img->w/2)*pl->dir; adjustx(pl, F_SLAM1); pl->netystart = pl->y; /* handle mace */ if (pl->powerup == PW_MACE) { sprite_t *s; int found; // use existing mace if it is there found = B_FALSE; for (s = sprite; s ; s = s->next) { if ((s->id == P_MACE) && (s->owner == pl)) { s->x = pl->x; s->y = pl->y - (imageset[pl->id].img[F_SHOOT]->h / 2) + 5; found = B_TRUE; } } if (!found) { sprite_t *newsp; newsp = addsprite(P_MACE, pl->x, pl->y - (imageset[pl->id].img[F_SHOOT]->h / 2) + 5, "mace"); newsp->owner = pl; } } } } } void trytoshoot(sprite_t *pl) { if (pl->caughtby) return; if ((!pl->netting) && (!pl->slamming)) { if ((pl->netcaught < pl->netmax) && (pl->climbing == B_FALSE)) { // handle cannon if (pl->powerup == PW_CANNON) { playfx(FX_CANNON); pl->powerup = PW_CANNONFIRE; pl->timer3 = CANNONSIZE+5; // use this for size } else { if (pl->powerup == PW_RAYGUN) { // fire a ray gun bullet sprite_t *ss; playfx(FX_LASER); ss = addsprite(P_RAYGUNBULLET, pl->x, pl->y - (pl->img->h/2) + 4, "raygunbullet"); ss->xs = pl->dir * RAYGUNSPEED; ss->dir = pl->dir; pl->timer1--; // reduce # of shots if (pl->timer1 > 0) { sprintf(tempm, "%d shots left",pl->timer1); addoutlinetext(pl->x,pl->y - pl->img->h, TEXTSIZE_POINTS, tempm,&cyan,&black,POINTSDELAY, TT_NORM); } else { sprintf(tempm, "Out of ammo"); addoutlinetext(pl->x,pl->y - pl->img->h, TEXTSIZE_POINTS, tempm,&grey2,&black,POINTSDELAY, TT_NORM); } } else { // net sound effect playfx(FX_SHOOT); } /* shoot net */ pl->netting = 1; adjustx(pl, F_SHOOT); if (pl->powerup == PW_ACCORDION) { pl->netspeed = ACCNETSPEED; } else if (pl->powerup == PW_SMALLNET) { pl->netspeed = SMALLNETSPEED; } else if (pl->netbig) { pl->netspeed = BIGNETSPEED; } else { pl->netspeed = NETSPEED; } pl->netlen = 0; pl->netdir = pl->dir; // set up initial... pl->nety = pl->y - (pl->img->h/2) + 2; } /* handle boxing glove */ if (pl->powerup == PW_BOXING) { sprite_t *s; int found; // use existing glove if it is there found = B_FALSE; for (s = sprite; s ; s = s->next) { if ((s->id == P_GLOVE) && (s->owner == pl)) { s->x = pl->x; s->y = pl->y - (imageset[pl->id].img[F_SHOOT]->h / 2) + 5; found = B_TRUE; } } if (!found) { sprite_t *newsp; newsp = addsprite(P_GLOVE, pl->x, pl->y - (imageset[pl->id].img[F_SHOOT]->h / 2) + 5, "glove"); newsp->owner = pl; } } } } } int keydown(int whichplayer, int checkfor) { int checkkey; checkkey = checkfor; // adjust checkkey based on player if (whichplayer == 1) { if (checkfor == KEY_RIGHT) checkkey = KEY2_RIGHT; if (checkfor == KEY_LEFT) checkkey = KEY2_LEFT; if (checkfor == KEY_UP) checkkey = KEY2_UP; if (checkfor == KEY_DOWN) checkkey = KEY2_DOWN; if (checkfor == KEY_SHOOT) checkkey = KEY2_SHOOT; if (checkfor == KEY_JUMP) checkkey = KEY2_JUMP; if (checkfor == KEY_SLAM) checkkey = KEY2_SLAM; } // check for keypress if (keys[checkkey]) { return B_TRUE; } // check for joystick if (havejoysticks) { //if (joybut[keytojoybutton(checkfor)]) return B_TRUE; if (joybuttondown(whichplayer, checkfor)) return B_TRUE; if ((checkfor == KEY_UP) && (joyy[whichplayer] <= -joythresh[whichplayer])) return B_TRUE; if ((checkfor == KEY_DOWN) && (joyy[whichplayer] >= joythresh[whichplayer])) return B_TRUE; if ((checkfor == KEY_LEFT) && (joyx[whichplayer] <= -joythresh[whichplayer])) return B_TRUE; if ((checkfor == KEY_RIGHT) && (joyx[whichplayer] >= joythresh[whichplayer])) return B_TRUE; } return B_FALSE; } // draw cannon lasers and check for collision from them void docannoneffect(sprite_t *pp) { if (timer % 2 == 0) { int found; sprite_t *s; // find cannon found = B_FALSE; for (s = sprite; s ; s = s->next) { if (s->id == P_CANNON) { if (s->owner == pp) { found = B_TRUE; } break; } } if (!found) { printf("weird error - no cannon!!\n"); losepowerup(pp); } else { int initx,inity; int i; int initsize; int xx,yy; sprite_t *s3; initsize = pp->timer3; if (initsize > CANNONSIZE) initsize = CANNONSIZE; // calc init positions inity = s->y - (s->img->h/2) - (initsize/2); initx = s->x - (initsize/2); yy = inity; xx = initx; // horiz lines for (i = 0; i < initsize ; i++) { drawline(screen,0,yy,640,yy,white); for (s3 = sprite; s3 ; s3 = s3->next) { if (ismonster(s3->id) && !s3->dead) { if (!s3->caughtby) { if ((yy >= s3->y - s3->img->h) && (yy <= s3->y)) { s3->willbecome = P_DIAMOND; if (s3->id == P_SNAIL) s3->id = P_SLUG; die(s3); } } } } yy++; } // vert lines for (i = 0; i < initsize ; i++) { drawline(screen,xx,0,xx,480,white); for (s3 = sprite; s3 ; s3 = s3->next) { if (ismonster(s3->id) && !s3->dead) { if (!s3->caughtby) { if ((xx >= s3->x - (s3->img->w/2)) && (xx <= s3->x + (s3->img->w/2))) { s3->willbecome = P_DIAMOND; if (s3->id == P_SNAIL) s3->id = P_SLUG; die(s3); } } } } xx++; } // dec size if (timer % 8 == 0) { pp->timer3--; if (pp->timer3 <= 0) { losepowerup(pp); s->dead = D_FINAL; SDL_BlitSurface(temps, NULL, screen, NULL); } } } } } void dotitlescreen(void) { char tempst[BUFLEN]; char svnver[MIDBUFLEN]; SDL_Surface *titlebg; SDL_Surface *cointext, *text, *text2, *easy, *norm, *ver; SDL_Surface *help, *helpon, *helpoff; SDL_Surface *p1ready,*p2ready; SDL_Surface *ts; SDL_Event event; SDL_Rect area; int timer = 0; double bouncetimer = 0; //int i; int texton = B_TRUE; int htstart = 0, htime = 0,hticks; // allow credits lockcredits = B_FALSE; // clear all sprites!! want1up = B_FALSE; want2up = B_FALSE; while (sprite) { killsprite(sprite); } sprite = NULL; player = NULL; player2 = NULL; // reset gothiscore setting gothiscore = -1; gothiscore2 = -1; // load title screen sprintf(tempst, "%s/backgrounds/title.png",datadir); ts = IMG_Load(tempst); SDL_SetColorKey(ts, SDL_RLEACCEL, 0); titlebg = SDL_DisplayFormat(ts); SDL_FreeSurface(ts); if (!titlebg) { printf("cannot load title screen (%s)\n",tempst); exit(1); } // load ready text sprintf(tempst, "%s/sprites/p1ready.png",datadir); ts = IMG_Load(tempst); SDL_SetColorKey(ts, SDL_RLEACCEL, 0); p1ready = SDL_DisplayFormat(ts); SDL_FreeSurface(ts); if (!p1ready) { printf("cannot load p1 ready img (%s)\n",tempst); exit(1); } sprintf(tempst, "%s/sprites/p2ready.png",datadir); ts = IMG_Load(tempst); SDL_SetColorKey(ts, SDL_RLEACCEL, 0); p2ready = SDL_DisplayFormat(ts); SDL_FreeSurface(ts); if (!p2ready) { printf("cannot load p2 ready img (%s)\n",tempst); exit(1); } // set up text cointext = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Insert Coin", white); text = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Press 1UP or 2UP to start", red); text2 = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Select game mode:", red); easy = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Easy Mode", red2); norm = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Normal Mode", red2); help = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Hints:", green); helpoff = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Off", green2); helpon = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "On", green2); sprintf(svnver, "v0.%d",REV); ver = TTF_RenderText_Solid(font[TEXTSIZE_VER], svnver, greenish); if (credits > 0) { titlemode = TS_WAIT1UP; } else { titlemode = TS_INSERTCOIN; } gamemode = GM_NORM; // default blinkspeed = 20; // wait for keypress titledone = B_FALSE; while (!titledone) { if (SDL_PollEvent(&event)) { int j; switch (event.type) { case SDL_JOYAXISMOTION: j = event.jaxis.which; joyx[j] = SDL_JoystickGetAxis(joy[j],0); joyy[j] = SDL_JoystickGetAxis(joy[j],1); //printf("got joy motion: joy %d, x=%d,y=%d\n",j,joyx[j],joyy[j]); if (joyy[j] <= -6000) handletitleinput(j, KEY_UP); if (joyy[j] >= 6000) handletitleinput(j, KEY_DOWN); if (joyx[j] <= -6000) handletitleinput(j, KEY_LEFT); if (joyx[j] >= 6000) handletitleinput(j, KEY_RIGHT); break; case SDL_KEYUP: handletitleinput(0, event.key.keysym.sym); break; case SDL_JOYBUTTONUP: //printf("got joy button: joy %d, button=%d\n",j,event.jbutton.button); handletitleinput(event.jbutton.which, joybuttontokey(event.jbutton.button)); break; } } if (++timer >= blinkspeed) { // reset timer timer = 0; // blink text if (texton) { // disappear texton = B_FALSE; } else { // appear texton = B_TRUE; } } // draw screen if (titlemode != TS_HISCORES) { SDL_BlitSurface(titlebg, NULL, screen, NULL); } else { SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); } if (titlemode != TS_HISCORES) { // version number area.x = 640 - (ver->w) - 10; area.y = 150; SDL_SetColors(ver, &black, 1, 1); SDL_BlitSurface(ver, NULL, screen, &area); area.x -= 2; area.y -= 2; SDL_SetColors(ver, &greenish, 1, 1); SDL_BlitSurface(ver, NULL, screen, &area); } // mode-specific text if ((titlemode == TS_INSERTCOIN) || (titlemode == TS_HISCORES)) { if (texton) { area.x = 320 - (cointext->w/2)+2; area.y = 10; SDL_SetColors(cointext, &black, 1, 1); SDL_BlitSurface(cointext, NULL, screen, &area); area.x -= 2; area.y -= 2; SDL_SetColors(cointext, &white, 1, 1); SDL_BlitSurface(cointext, NULL, screen, &area); } } if (titlemode == TS_WAIT1UP) { //if (texton) { area.x = 320 - (text->w/2)+2; area.y = 240 - (text->h/2)+2; SDL_SetColors(text, &black, 1, 1); SDL_BlitSurface(text, NULL, screen, &area); area.x -= 2; area.y -= 2; SDL_SetColors(text, &red, 1, 1); SDL_BlitSurface(text, NULL, screen, &area); //} } else if (titlemode == TS_SELECTMODE) { SDL_Surface *desc; // who is in? if (want1up) { area.x = 10; area.y = (480/2) - (p1ready->h/2); area.y += (sin(bouncetimer * (M_PI/180)) * 20); SDL_BlitSurface(p1ready, NULL, screen, &area); } if (want2up) { area.x = 640 - p2ready->w - 10; area.y = (480/2) - (p2ready->h/2); area.y -= (sin(bouncetimer * (M_PI/180)) * 20); SDL_BlitSurface(p2ready, NULL, screen, &area); } // "select mode" area.x = 320 - (text2->w/2)+2; area.y = 240 - (text2->h*3)+2; SDL_SetColors(text2, &black, 1, 1); SDL_BlitSurface(text2, NULL, screen, &area); area.x -=2 ; area.y -= 2; SDL_SetColors(text2, &red, 1, 1); SDL_BlitSurface(text2, NULL, screen, &area); // "easy" area.x = 320 - (easy->w/2)+2; area.y = 240 - (easy->h)+2; SDL_SetColors(easy, &black, 1, 1); SDL_BlitSurface(easy, NULL, screen, &area); area.x -= 2; area.y -= 2; if ((gamemode == GM_NORM) || (texton)) { // easy not blinking // normal SDL_SetColors(easy, &red2, 1, 1); } else { // white SDL_SetColors(easy, &white, 1, 1); } SDL_BlitSurface(easy, NULL, screen, &area); // "normal" area.x = 320 - (norm->w/2)+2; area.y = 240 +2; SDL_SetColors(norm, &black, 1, 1); SDL_BlitSurface(norm, NULL, screen, &area); area.x -= 2; area.y -= 2; if ((gamemode == GM_EASY) || (texton)) { // easy not blinking // normal SDL_SetColors(norm, &red2, 1, 1); } else { // white SDL_SetColors(norm, &white, 1, 1); } SDL_BlitSurface(norm, NULL, screen, &area); // help on/off area.x = 320 - 100 +2; area.y = 480 - 50 +2; SDL_SetColors(help, &black, 1, 1); SDL_BlitSurface(help, NULL, screen, &area); area.x -= 2; area.y -= 2; SDL_SetColors(help, &red, 1, 1); SDL_BlitSurface(help, NULL, screen, &area); // "on" area.x += (help->w+10)+2; area.y = 480 - 50 +2; SDL_SetColors(helpon, &black, 1, 1); SDL_BlitSurface(helpon, NULL, screen, &area); area.x -= 2; area.y -= 2; if ((showhelp == B_FALSE) || (texton)) { // on not blinking // normal SDL_SetColors(helpon, &red2, 1, 1); } else { // white SDL_SetColors(helpon, &white, 1, 1); } SDL_BlitSurface(helpon, NULL, screen, &area); // "off" area.x += (helpon->w+10)+2; area.y = 480 - 50 +2; SDL_SetColors(helpoff, &black, 1, 1); SDL_BlitSurface(helpoff, NULL, screen, &area); area.x -= 2; area.y -= 2; if ((showhelp == B_TRUE) || (texton)) { // off not blinking // normal SDL_SetColors(helpoff, &red2, 1, 1); } else { // white SDL_SetColors(helpoff, &white, 1, 1); } SDL_BlitSurface(helpoff, NULL, screen, &area); // level description if (gamemode == GM_EASY) { int x,y; int startx,starty; desc = TTF_RenderText_Solid(font[TEXTSIZE_TITLE2], "Permenant armour and extra time", black); startx = 320 - (desc->w/2); starty = 240 + (desc->h)*2; for (x = startx-1 ; x <= startx+1; x++) { for (y = starty-1 ; y <= starty+1; y++) { area.x = x; area.y = y; SDL_BlitSurface(desc, NULL, screen, &area); } } area.x = startx; area.y = starty; SDL_SetColors(desc, &green, 1, 1); SDL_BlitSurface(desc, NULL, screen, &area); SDL_FreeSurface(desc); } } else if (titlemode == TS_HISCORES) { drawhiscores(); } bouncetimer += 7; if (bouncetimer >= 360) { bouncetimer = 0; } // draw text drawcredits(); SDL_framerateDelay(&manager); SDL_UpdateRect(screen, 0,0,640,480); hticks = SDL_GetTicks(); if (htstart == 0) { htstart = hticks; } else { /* once per second */ if (hticks - htstart >= 1000) { htime++; htstart = hticks; if ((htime > 0) && (htime % TTIME == 0)) { if (titlemode == TS_INSERTCOIN) { // INSERTCOIN -> NORMAL HISCORES if (wanthiscores) gethiscores(easymode()); titlemode = TS_HISCORES; } else if (titlemode == TS_HISCORES) { // next time, get other hiscores if (gamemode == GM_EASY) gamemode = GM_NORM; else gamemode = GM_EASY; // NORMAL HISCORES -> INSERTCOIN titlemode = TS_INSERTCOIN; } } } } } // clear screen to black //SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0)); // free temp surfaces SDL_FreeSurface(cointext ); SDL_FreeSurface(ver ); SDL_FreeSurface(text ); SDL_FreeSurface(text2 ); SDL_FreeSurface(easy ); SDL_FreeSurface(norm ); SDL_FreeSurface(help ); SDL_FreeSurface(helpon ); SDL_FreeSurface(helpoff ); SDL_FreeSurface(titlebg ); SDL_FreeSurface(p1ready); SDL_FreeSurface(p2ready); } void startgame(void) { int i; // initial variables curlevelnum = 1; musicplaying = B_FALSE; levelcompletetime = -1; oldlevelcomplete = -1; pokereffect = -1; pokerpoints = 0; skiplevels = 0; gothiscore = -1; gothiscore2 = -1; forcegold = B_FALSE; forcegoldlev = -1; curfruittype = 0; curpoweruptype[0] = 0; curpoweruptype[1] = 0; fpsticks = 0; fpsstart = 0; numregrow = 0; // init player variables - if player // hasn't been allocated yet then this will // be done so in loadlevel(), and the below // settings done in addsprite() if (player) { int c; player->permspeed = B_FALSE; player->permbignet = B_FALSE; player->permnumnets = B_FALSE; player->permmask = B_FALSE; player->permarmour = B_FALSE; player->permsticky = B_FALSE; setdefaults(player); player->numcards = 0; for (c = 0; c < MAXCARDS; c++) { player->card[c] = -1; player->usedcard[c] = 0; } } if (player2) { int c; player2->permspeed = B_FALSE; player2->permbignet = B_FALSE; player2->permnumnets = B_FALSE; player2->permmask = B_FALSE; player2->permarmour = B_FALSE; player2->permsticky = B_FALSE; setdefaults(player2); player2->numcards = 0; for (c = 0; c < MAXCARDS; c++) { player2->card[c] = -1; player2->usedcard[c] = 0; } } // is we're skipping to a level, do so now if (skipto >= 0) { for (i = 0; i < numlevels; i++) { if (levelentry[i].id == skipto) { curlevelnum = i; } } } else { // special intro level curlevelnum = INTRO_LEVELNUM; } // allocate player if (want1up) { if (player == NULL) { player = addsprite(P_PLAYER, 32, 450, "Player 1" ); setdefaults(player); } } if (want2up) { if (player2 == NULL) { player2 = addsprite(P_PLAYER2, 32, 450, "Player 2" ); setdefaults(player2); } } // more initial variables if (player) { makeinvuln(player); player->score = 0; if (gamemode == GM_EASY) { player->permarmour = B_TRUE; player->armour = B_TRUE; player->id = P_ARMOUR; } else { player->permarmour = B_FALSE; player->armour = B_FALSE; player->id = P_PLAYER; } player->lives = INITPLAYERLIVES; } if (player2) { makeinvuln(player2); player2->score = 0; if (gamemode == GM_EASY) { player2->permarmour = B_TRUE; player2->armour = B_TRUE; player2->id = P_ARMOUR2; } else { player2->permarmour = B_FALSE; player2->armour = B_FALSE; player2->id = P_PLAYER2; } player2->lives = INITPLAYERLIVES; } forcegoodcard = B_FALSE; nextforcegoodcard = B_FALSE; gameover = B_FALSE; gameovertime = -1; gtime = 0; curlevelnum-- ; // since nextlevel() will increment it // start intro introstate = IS_START; firstlevel = B_TRUE; nextlevel(); firstlevel = B_FALSE; flip(); if (skipto == -1) { playfx(FX_BIRDS); } // start timer timer = 0; } void uncatch(sprite_t *s) { if (s->caughtby) { s->caughtby->netcaught--; } s->caughtby = NULL; s->caughtstate = B_FALSE; } void makeinvuln(sprite_t *s) { if (!s) return; if (s->id == P_BLACKCLOUD) { s->invuln = INVULNTIME/2; } else { s->invuln = INVULNTIME; } } void setjoymappings(void) { // ps3 joymap[4] = KEY_UP; joymap[5] = KEY_RIGHT; joymap[6] = KEY_DOWN; joymap[7] = KEY_LEFT; joymap[14] = KEY_JUMP; //x == jump joymap[13] = KEY_SLAM; //circle = slam joymap[12] = KEY_SHOOT; // square/triangle = shoot joymap[15] = KEY_SHOOT; // mame (directions are joystick) joymap[0] = KEY_SHOOT; joymap[1] = KEY_JUMP; joymap[2] = KEY_SLAM; joymap[3] = KEY_SLAM; } int joybuttontokey(int buttonnum) { return joymap[buttonnum]; } int joybuttondown(int whichplayer, int key) { int i; for (i = 0; i < joybuttons[whichplayer]; i++) { if ((joymap[i] == key) && (joybut[whichplayer][i])) return B_TRUE; } return B_FALSE; } /* int keytojoybutton(int key) { int i; for (i = 0; i < joybuttons; i++) { if (joymap[i] == key) return i; } return -1; } */ void handletitleinput(int whichplayer, int key) { if (key == SDLK_ESCAPE) { // quit exit(0); } if ((titlemode == TS_INSERTCOIN) || (titlemode == TS_HISCORES)) { if ((key == SDLK_5) || (key == SDLK_6) || (key == SDLK_RETURN)) { addcredit(); titlemode = TS_WAIT1UP; } } else if (titlemode == TS_WAIT1UP) { if ((key == SDLK_5) || (key == SDLK_6)) { addcredit(); // if this was the first credit, default to normal mode if (credits == 1) { gamemode = GM_NORM; } } else if ((key == SDLK_1) || (key == SDLK_2) || (key == SDLK_RETURN)) { if (credits > 0) { int donesomething = B_FALSE; if ((key == SDLK_1) || (key == SDLK_RETURN)) { if (!want1up) { want1up = B_TRUE; donesomething = B_TRUE; } } else if (key == SDLK_2) { if (!want2up) { want2up = B_TRUE; donesomething = B_TRUE; } } if (donesomething) { playfx(FX_EXTRALIFE); credits--; titlemode = TS_SELECTMODE; blinkspeed = 5; } } } } else if (titlemode == TS_SELECTMODE) { // pick current mode if (key == KEY_UP) { gamemode = GM_EASY; } else if (key == KEY_DOWN) { gamemode = GM_NORM; } else if (key == KEY_LEFT) { showhelp = B_TRUE; } else if (key == KEY_RIGHT) { showhelp = B_FALSE; } else if ((key == KEY_SHOOT) || (key == SDLK_RETURN)) { playfx(FX_KEYPRESS); titledone = B_TRUE; } else if ((key == SDLK_1) || (key == SDLK_2) || (key == SDLK_RETURN)) { // another player joining if (credits > 0) { int donesomething = B_FALSE; if ((key == SDLK_1) || (key == SDLK_RETURN)) { if (!want1up) { want1up = B_TRUE; donesomething = B_TRUE; } } else if (key == SDLK_2) { if (!want2up) { want2up = B_TRUE; donesomething = B_TRUE; } } if (donesomething) { playfx(FX_EXTRALIFE); credits--; } } } else if ((key == SDLK_5) || (key == SDLK_6)) { addcredit(); } } } void drawcredits(void) { char tempst[BUFLEN]; SDL_Rect area; // credits if (credits == MAXCREDITS) { sprintf(tempst, "Credits: MAX"); } else { sprintf(tempst, "Credits: %d",credits); } credittext = TTF_RenderText_Solid(font[TEXTSIZE_CREDIT], tempst, black); area.x = 320 - (credittext->w / 2) + 2; area.y = 480 - 2 - (credittext->h)+2; if (lockcredits) { SDL_SetColors(credittext, &red2, 1, 1); } else { SDL_SetColors(credittext, &black, 1, 1); } SDL_BlitSurface(credittext, NULL, screen, &area); area.x -= 2; area.y -= 2; SDL_SetColors(credittext, &white, 1, 1); SDL_BlitSurface(credittext, NULL, screen, &area); SDL_FreeSurface(credittext); } int submithiscore(int score,int level, char *name) { struct sockaddr_in serveraddress; struct hostent *server; int rv; int sock; char buf[1500]; char newtext[BUFLEN]; char buf2[512]; char *p,*p2; server = gethostbyname(hiscoreserver); sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { printf("Error getting socket.\n"); return B_TRUE; } //bzero((char *) &serveraddress, sizeof(serveraddress)); memset(&serveraddress, 0, sizeof(serveraddress)); serveraddress.sin_family = AF_INET; memcpy(&serveraddress.sin_addr.s_addr, server->h_addr, server->h_length); serveraddress.sin_port = htons(hiscoreport); // replace spaces in name with %20s p2 = newtext; for (p = name ; *p != '\0'; p++) { if (*p == ' ') { *p2 = '%'; p2++; *p2 = '2'; p2++; *p2 = '0'; } else { *p2 = *p; } p2++; } *p2 = '\0'; // connect if (connect(sock,(struct sockaddr *)&serveraddress,sizeof(serveraddress)) < 0) { printf("Error connecting to hiscore server.\n"); return B_TRUE; } // send request sprintf(buf2, "GET HTTP://ratcatcher.nethack.net/hiscores/submitscore.php?score=%d&name=%s&level=%d&easymode=%d HTTP/1.0\n\n", score,newtext,level,easymode()); write(sock,buf2,strlen(buf2)); // wait for data rv = read(sock, buf, 1500); while (rv > 0) { rv = read(sock, buf, 1500); } close(sock); return B_FALSE; } int gethiscores(int easyscores) { struct sockaddr_in serveraddress; struct hostent *server; int rv; int sock; char buf[BUFLEN]; char buf2[512]; int state = 0; int pos; int finished; server = gethostbyname(hiscoreserver); if (!server) { printf("can't resolve hiscore server name\n"); return B_TRUE; } sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { printf("Error getting socket.\n"); return B_TRUE; } //bzero((char *) &serveraddress, sizeof(serveraddress)); memset(&serveraddress, 0, sizeof(serveraddress)); serveraddress.sin_family = AF_INET; memcpy(&serveraddress.sin_addr.s_addr, server->h_addr, server->h_length); serveraddress.sin_port = htons(hiscoreport); // connect if (connect(sock,(struct sockaddr *)&serveraddress,sizeof(serveraddress)) < 0) { perror("connect"); printf("Error connecting to hiscore server.\n"); return B_TRUE; } // send request if (easyscores) { sprintf(buf2, "GET HTTP://ratcatcher.nethack.net/hiscores/hiscores_plain.php?easymode=1 HTTP/1.0\n\n"); } else { sprintf(buf2, "GET HTTP://ratcatcher.nethack.net/hiscores/hiscores_plain.php HTTP/1.0\n\n"); } write(sock,buf2,strlen(buf2)); pos = 0; finished = B_FALSE; // wait for data //rv = read(sock, buf, 1500); rv = socket_readline(sock, buf); while ((rv > 0) && !finished) { buf[rv] = '\0'; if (state == 0) { // header char *p; p = strstr(buf, "text/plain"); if (p) { state = 1; } } else if (state == 1) { // waiting for start of data if (strstr(buf, "start")) { state = 2; } } else { char *p; // validate line if (strstr(buf, "endofscores")) { finished = B_TRUE; } else if (strstr(buf, "^")) { // process line p = strtok(buf, "^"); hiscore[pos].score = atoi(p); p = strtok(NULL, "^"); hiscore[pos].level = atoi(p); p = strtok(NULL, "^"); sprintf(hiscore[pos].name,"%s", p); pos++; if (pos >= MAXHISCORES) { // too many - cut it off here finished = B_TRUE; } } } //rv = read(sock, buf, 1500); rv = socket_readline(sock, buf); } numhiscores = pos; close(sock); return B_FALSE; } void checkhiscores(sprite_t *who){ int finished = B_FALSE; int i; char srank[BUFLEN],sscore[BUFLEN],slevel[BUFLEN],sname[BUFLEN]; //char line[BUFLEN]; char commascore[BUFLEN]; int x,y,sx,sy; char thisname[BUFLEN]; int timer = 0,keytimer = 0; int capital = B_TRUE; int curlet; int pnum; // player number (for key input) if (who == player) { pnum = 0; } else { pnum = 1; } // no hiscores if we are cheating! if (cheat) { return; } // contact server and read appropriate list if (gethiscores(easymode())) { printf("Cannot contact hiscore server!\n"); return; } // check if we are higher than any if (who == player) { gothiscore = -1; for (i = 0; i < numhiscores; i++) { if (who->score > hiscore[i].score) { // we got a hi score gothiscore = i; break; } } } else { gothiscore2 = -1; for (i = 0; i < numhiscores; i++) { if (who->score > hiscore[i].score) { // we got a hi score gothiscore2 = i; break; } } } if ((who == player) && (gothiscore == -1)) return; // didn't get a hiscore if ((who == player2) && (gothiscore2 == -1)) return; // didn't get a hiscore // play hiscore music //stopmusic(); playmusic(hiscoremusic); // prompt user for a name curlet = 'a'; strcpy(thisname, ""); while (!finished) { SDL_Color *fg, *bg; SDL_Event event; char let[2]; // clear SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format,black.r,black.g,black.b)); //draw hiscore heading sx = 110; sy = 100; x = sx; y = sy; // headings if (who == player) { drawoutlinecentretext(screen, 50, TEXTSIZE_HISCORE, "1UP - New high score!", &white, &grey2); } else { drawoutlinecentretext(screen, 50, TEXTSIZE_HISCORE, "2UP - New high score!", &white, &grey2); } // print rank drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Rank", &cyan, &blue); x += 70; // print score drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Score", &cyan, &blue); x += 150; // print level drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Level", &cyan, &blue); x += 90; // print name drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Name", &cyan, &blue); y += (TEXTSIZE_HISCORE*2); x = sx; // player's score... // generate hiscore lines sprintf(srank, "%-2d.",((who == player) ? gothiscore : gothiscore2)+1); addcommas(commascore, who->score ); sprintf(sscore, "%-14s",commascore); sprintf(slevel, "%1d-%-2d",getworld(curlevelnum),getlevel(curlevelnum)); if (strlen(thisname) > 0) { sprintf(sname, "%-32s",thisname); } fg = &white; bg = &grey2; // print rank drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, srank, fg, bg); x += 70; // print score drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, sscore, fg, bg); x += 150; // print level drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, slevel, fg, bg); x += 90; // print name if (strlen(thisname) > 0) { int wid; wid = drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, thisname, fg, bg); x += (wid + 2); } // print cursor if (curlet == '*') { if (((timer / 5) % 2) == 0) { drawoutlinetext(screen, x, y+3, TEXTSIZE_HISCORE/2, "END", &white, &grey2); } else { drawoutlinetext(screen, x, y+3, TEXTSIZE_HISCORE/2, "END", &red, &red2); } } else { sprintf(let, "%c",capital ? toupper(curlet) : curlet ); if (((timer / 5) % 2) == 0) { drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, let, &white, &grey2); } else { drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, let, &red, &red2); } } if (++timer == 100) { timer = 0; } getinput(); if (keytimer == 0) { // check for scrolling if (keydown(pnum, KEY_UP)) { // scroll through letters if (curlet == 'a') curlet = '*'; else if (curlet == '*') curlet = ' '; else if (curlet == ' ') curlet = 'z'; else curlet--; keytimer = 5; } else if (keydown(pnum, KEY_DOWN)) { // scroll through letters if (curlet == 'z') curlet = ' '; else if (curlet == ' ') curlet = '*'; else if (curlet == '*') curlet = 'a'; else curlet++; keytimer = 5; } } else { keytimer--; } if (strlen(thisname) >= MAXHISCORENAME) { // have to END now curlet='*'; } // wait for a key... if (SDL_PollEvent(&event)) { int key = -1; switch (event.type) { case SDL_KEYUP: key = event.key.keysym.sym; // make sure it's the correct player if (who == player ){ switch (key) { case SDLK_s: case SDLK_d: case SDLK_f: case SDLK_6: case SDLK_2: key = -1; } } else { switch (key) { case KEY_SHOOT: case KEY_JUMP: case KEY_SLAM: case SDLK_5: case SDLK_1: key = -1; } } break; case SDL_JOYBUTTONUP: if (event.jbutton.which == pnum) { key = joybuttontokey(event.jbutton.button); } else { key = -1; } break; } if ((event.type == SDL_KEYUP) || (event.type == SDL_JOYBUTTONUP)) { if (key != -1) { if (key == SDLK_ESCAPE) { // quit exit(0); } else if ((key == SDLK_RETURN) || (key == SDLK_5) || (key == SDLK_6)) { if (strlen(thisname) > 0) { playfx(FX_KEYPRESS); finished = B_TRUE; } } else if ((key == SDLK_BACKSPACE) || (key == KEY_JUMP) || (key == SDLK_d)) { thisname[strlen(thisname)-1] = '\0'; if (strlen(thisname) == 0) { capital = B_TRUE; } else if (thisname[strlen(thisname)-1] == ' ') { capital = B_TRUE; } } else if ((key == KEY_SHOOT) || (key == SDLK_s)) { // add current letter or finish if it is on "end" if (curlet == '*') { if (strlen(thisname) > 0) { playfx(FX_KEYPRESS); finished = B_TRUE; } } else { // capital let[0] = capital ? toupper(curlet) : curlet; let[1] = '\0'; strcat(thisname, let); // don't let name get too long playfx(FX_POWERUP); if (curlet == ' ') { // next letter is a capital capital = B_TRUE; } else { capital = B_FALSE; } } } } } } if (!paused) SDL_framerateDelay(&manager); SDL_UpdateRect(screen, 0,0,640,480); } // submit the hiscore if (submithiscore(who->score, curlevelnum, thisname)) { printf("failed to submit hiscore.\n"); } else { // downlaod the hiscores again gethiscores(easymode()); } } void showhiscores(void){ int finished = B_FALSE; //char line[BUFLEN]; int htstart = 0, htime = 0,hticks; // contact server and read list /* if (gethiscores()) { printf("Cannot contact hiscore server!\n"); return; } */ /* hiscore[0].score = 55000; hiscore[0].level = 24; sprintf(hiscore[0].name, "King Rat"); hiscore[1].score = 1000; hiscore[1].level = 5; sprintf(hiscore[1].name, "Queen Rat"); numscores = 2; */ // display list on screen and wait for key while (!finished) { SDL_Event event; drawhiscores(); // check for a key... if (SDL_PollEvent(&event)) { int key = -1; switch (event.type) { case SDL_KEYUP: key = event.key.keysym.sym; break; case SDL_JOYBUTTONUP: key = joybuttontokey(event.jbutton.button); break; } if (key != -1) { if (key == SDLK_ESCAPE) { // quit exit(0); } else if ((key == SDLK_1) || (key == SDLK_2)) { // 1up buttons finished = B_TRUE; } } } SDL_UpdateRect(screen, 0,0,640,480); hticks = SDL_GetTicks(); if (htstart == 0) { htstart = hticks; } else { /* once per second */ if (hticks - htstart >= 1000) { htime++; htstart = hticks; } if (htime >= HISCORE_DISPLAYTIME) { finished = B_TRUE; } } } // stop music ready for title screen again (it will only be playing if // we got a hiscore) stopmusic(); } int socket_readline(int sock, char* out) { /* current location in buffer */ int i = 0; /* whether the previous char was a \r */ int cr = 0; char ch; /* result, grows as we need it to */ //out = malloc(sizeof(char) * size); for ( ; ; ) { if (recv(sock, &ch, 1, 0) == -1) { return -1; } /* if (i >= size) { // grow buffer size *= 2; out = realloc(out, size); } */ if (ch == '\n') { /* if preceded by a \r, we overwrite it */ if (cr) { i--; } out[i] = '\0'; break; } else { cr = (ch == '\r' ? 1 : 0); out[i] = ch; } i++; } return i + 1; } void drawhiscores(void) { char srank[BUFLEN],sscore[BUFLEN],slevel[BUFLEN],sname[BUFLEN]; char commascore[BUFLEN]; int x,y,sx,sy; int i; //draw hiscore list sx = 110; sy = 100; x = sx; y = sy; // headings if (easymode()) { drawoutlinecentretext(screen, 50, TEXTSIZE_HISCORE, "High Scores - Easy", &cyan, &blue); } else { drawoutlinecentretext(screen, 50, TEXTSIZE_HISCORE, "High Scores - Normal", &cyan, &blue); } if (numhiscores <= 0) { // print rank y += (TEXTSIZE_HISCORE*4); drawoutlinecentretext(screen, y, TEXTSIZE_HISCORE, "High score server unavailable", &red, &red3); } else { // print rank drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Rank", &cyan, &blue); x += 70; // print score drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Score", &cyan, &blue); x += 150; // print level drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Level", &cyan, &blue); x += 90; // print name drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Name", &cyan, &blue); y += (TEXTSIZE_HISCORE*2); x = sx; for (i = 0; i < numhiscores; i++) { SDL_Color *fg, *bg; // generate hiscore lines sprintf(srank, "%-2d.",i+1); addcommas(commascore, hiscore[i].score); sprintf(sscore, "%-14s",commascore); sprintf(slevel, "%1d-%-2d",getworld(hiscore[i].level),getlevel(hiscore[i].level)); sprintf(sname, "%-32s",hiscore[i].name); if ((gothiscore != -1) && (i == gothiscore)) { fg = &white; bg = &grey2; } else if ((gothiscore2 != -1) && (i == gothiscore2)) { fg = &white; bg = &grey2; } else { fg = &red; bg = &red3; } // print rank drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, srank, fg, bg); x += 70; // print score drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, sscore, fg, bg); x += 150; // print level drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, slevel, fg, bg); x += 90; // print name drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, sname, fg, bg); // go to next line x = sx; y += (TEXTSIZE_HISCORE+2); } } } // read keyboard info void getinput(void) { int i,j; keys = SDL_GetKeyState(NULL); if (havejoysticks) { for (j = 0; j < 2; j++) { joyx[j] = SDL_JoystickGetAxis(joy[j],0); joyy[j] = SDL_JoystickGetAxis(joy[j],1); for (i = 0; i < joybuttons[j]; i++) { joybut[j][i] = SDL_JoystickGetButton(joy[j],i); } } } } int isendoflev(void) { if (levelcomplete == LV_CLEAR) return B_TRUE; if (levelcomplete == LV_WAIT) return B_TRUE; if (levelcomplete == LV_FINAL) return B_TRUE; if (levelcomplete == LV_CLOUD) return B_TRUE; if (levelcomplete == LV_CLOUDLOOP) return B_TRUE; if (levelcomplete == LV_NEXTLEV) return B_TRUE; return B_FALSE; } void keeponscreen(sprite_t *s) { if (s->x >= (640-(s->img->w/2))) { s->x = 640 - (s->img->w/2)-1; } if (s->x <= s->img->w/2) { s->x = (s->img->w/2)+1; } if (s->y <= s->img->h) { s->y = s->img->h+1; } if (s->y >= 480) { s->y = 480 - 1; } } void stopteleporting(sprite_t *s) { if (s->teleporting) { if (s->allocimg) { SDL_FreeSurface(s->img); s->img = NULL; } s->allocimg = B_FALSE; s->teleporting = 0; s->img = imageset[s->id].img[F_WALK1]; } } void disablepowerups(int pid) { if (haspowerup(player, pid)) { losepowerup(player); } if (haspowerup(player2, pid)) { losepowerup(player2); } } void losepowerup(sprite_t *s) { if (s->powerup == PW_GUNNER) { // go back to original position if (s == player) { s->x = gunorigx[0]; s->y = gunorigy[0]; } else if (s == player2) { s->x = gunorigx[1]; s->y = gunorigy[1]; } // invulnerable for a little while s->invuln = INVULNTIME/2; } s->powerup = B_FALSE; } int easymode(void) { if (gamemode == GM_EASY) return B_TRUE; return B_FALSE; } double getdistance(double x1, double y1, double x2, double y2) { double xdis,ydis; xdis = abs(x1 - x2); ydis = abs(y1 - y2); if ((xdis == 0) && (ydis == 0)) { return 0; } else return sqrt((xdis*xdis) + (ydis*ydis)); } void doplayermovement(sprite_t *pl) { int pnum; if (pl == player) { pnum = 0; } else if (pl == player2) { pnum = 1; } else return; // only valid for players if (!pl) return; if (pl->caughtby) return; if (pl->powerup == PW_GUNNER) { // move crosshairs if (keydown(pnum,KEY_RIGHT)) { if (pl->x < 640-(TILEW/2)) { pl->x += GUNNERSPEED; } } if (keydown(pnum,KEY_LEFT)) { if (pl->x > (TILEW/2)) { pl->x -= GUNNERSPEED; } } if (keydown(pnum,KEY_DOWN)) { if (pl->y < 480-(TILEH/2)) { pl->y += GUNNERSPEED; } } if (keydown(pnum,KEY_UP)) { if (pl->y > (TILEH/2)) { pl->y -= GUNNERSPEED; } } if (keydown(pnum,KEY_SHOOT)) { // shoot - add explosion if (gundelay[pnum] == 0) { playfx(FX_GUN); addsprite(P_SMASH, pl->x, pl->y+(TILEH/2), "gunexplosion"); gundelay[pnum] = GUNNERDELAY; } } } else { if ((!pl->dead) && (!pl->teleporting)) { int moveok = B_FALSE; if (pl->climbing) { tiletype_t *tt; // can only move left/right if we're at the bottom of a ladder tt = gettileat(pl->x,pl->y, NULL,NULL); if (tt->solid) { moveok = B_TRUE; } tt = gettileat(pl->x,pl->y+TILEH, NULL,NULL); if (tt->solid ) { moveok = B_TRUE; } } else moveok = B_TRUE; if (moveok) { if (keydown(pnum,KEY_RIGHT)) { if (canmove(pl)) { movex(pl, getspeed(pl), B_TRUE); } if (canturn(pl)) { pl->dir = D_RIGHT; } } else if (keydown(pnum,KEY_LEFT)) { if (canmove(pl)) { movex(pl, -getspeed(pl), B_TRUE); } if (canturn(pl)) { pl->dir = D_LEFT; } } } if (keydown(pnum,KEY_UP)) { if ((pl->swimming) && (pl->hasmask)) { // swimming swimup(pl); } else if (!pl->netting && !pl->slamming && !pl->jumping) { // climbing if (pl->climbing) { int ladderx = isladderabove(pl); // if tile above is non-solid, or a ladder if (ladderx || !isroofabove(pl)) { // lock to ladder if (ladderx) { pl->x = ladderx; // lock to ladder } // continue climbing pl->y -= getspeed(pl); pl->jumping = 0; pl->falling = 0; pl->climbing = B_TRUE; pl->moved = MV_WALK; } } else {// not climbing int ladderx = isladderabove(pl); if (ladderx) { pl->x = ladderx; // lock to ladder // start climbing pl->y -= getspeed(pl); pl->jumping = 0; pl->falling = 0; pl->climbing = B_TRUE; pl->moved = MV_WALK; } } } if (pl->umbrella) pl->umbrellaup = B_TRUE; } else { if (pl->umbrella) pl->umbrellaup = B_FALSE; } if (keydown(pnum,KEY_DOWN)) { if ((pl->swimming) && (pl->hasmask)) { // swimming swimdown(pl); } else if (!pl->netting && !pl->slamming && !pl->jumping) { int ladderx = isonladder(pl); if (ladderx) { pl->y += getspeed(pl); pl->jumping = 0; pl->falling = 0; pl->climbing = B_TRUE; pl->moved = MV_WALK; // lock player to centre of ladder pl->x = ladderx; } } } // Jump if (keydown(pnum,KEY_JUMP)) { trytojump(pl); } else { if (pl->jumping && pl->doublejump) { // have to let go of jump button to double jump if (!pl->doublejumpready) { pl->doublejumpready = B_TRUE; } } } // Shoot if (keydown(pnum,KEY_SHOOT)) { if (!havejoysticks && keydown(pnum,KEY_DOWN)) { trytoslam(pl); } else if (havejoysticks && (joytype[pnum] == J_WII) && keydown(pnum, KEY_DOWN)) { trytoslam(pl); } else { trytoshoot(pl); } } // Slam if (keydown(pnum,KEY_SLAM)) { trytoslam(pl); } } } } sprite_t *getclosestplayer(sprite_t *s) { double xdiff1,xdiff2,ydiff1,ydiff2,diff1,diff2; sprite_t *closest = NULL; // closest player if (player && !player->dead) { xdiff1 = abs(player->x - s->x); ydiff1 = abs(player->y - s->y); diff1 = xdiff1 + ydiff1; closest = player; } else { diff1 = 9999; } if (player2 && !player2->dead) { xdiff2 = abs(player2->x - s->x); ydiff2 = abs(player2->y - s->y); diff2 = xdiff2 + ydiff2; if (closest == NULL) closest = player2; else if (closest == player) { if (diff2 > diff1) closest = player2; } } return closest; } double getxdisttoplayer(sprite_t *s, sprite_t **pl) { double xdiff1,xdiff2,xdiff = 9999; if (globpowerup == PW_CAMERA) return 9999; /* distance to closest player */ if (player) { xdiff1 = abs(player->x - s->x); } else { xdiff1 = 9999; } if (player2) { xdiff2 = abs(player2->x - s->x); } else { xdiff2 = 9999; } if (pl != NULL) *pl = NULL; // default if (xdiff1 < xdiff2) { // p1 closer if (xdiff1 != 9999) { xdiff = player->x - s->x; } if (pl != NULL) *pl = player; } else { // p2 closer if (xdiff2 != 9999) { xdiff = player2->x - s->x; } if (pl != NULL) *pl = player2; } return xdiff; } double getydisttoplayer(sprite_t *s) { double ydiff1,ydiff2,ydiff; /* distance to closest player */ if (globpowerup == PW_CAMERA) return 9999; if (player) { ydiff1 = player->y - s->y; } else { ydiff1 = 9999; } if (player2) { ydiff2 = player2->y - s->y; } else { ydiff2 = 9999; } if (ydiff1 < ydiff2) { ydiff = ydiff1; } else { ydiff = ydiff2; } return ydiff; } sprite_t *isplayerbelow(sprite_t *s) { if (globpowerup == PW_CAMERA) return NULL; if (player && !player->dead && player->y > s->y) return player; if (player2 && !player2->dead && player2->y > s->y) return player2; return NULL; } // is there a player more than "dis" pixels below? sprite_t *isplayerbelowgt(sprite_t *s,int dis) { if (globpowerup == PW_CAMERA) return NULL; if (player && !player->dead && (player->y - s->y) >= dis ) return player; if (player2 && !player2->dead && (player2->y - s->y) >= dis) return player2; return NULL; } sprite_t *isplayerabove(sprite_t *s) { if (globpowerup == PW_CAMERA) return NULL; if (player && !player->dead && player->y < s->y) return player; if (player2 && !player2->dead && player2->y < s->y) return player2; return NULL; } // // is there a player within "dis" pixels above? sprite_t *isplayerabovelt(sprite_t *s,int dis) { if (globpowerup == PW_CAMERA) return NULL; if (player && !player->dead && (player->y < s->y) && ((s->y - player->y) <= dis )) return player; if (player2 && !player2->dead && (player->y < s->y) && ((s->y - player2->y) <= dis)) return player2; return NULL; } // is there a player more than "dis" pixels above? sprite_t *isplayerabovegt(sprite_t *s,int dis) { if (globpowerup == PW_CAMERA) return NULL; if (player && !player->dead && ((s->y - player->y) >= dis )) return player; if (player2 && !player2->dead && ((s->y - player2->y) >= dis)) return player2; return NULL; } sprite_t *isplayerright(sprite_t *s) { if (globpowerup == PW_CAMERA) return NULL; if (player && !player->dead && player->x > s->x) return player; if (player2 && !player2->dead && player2->x > s->x) return player2; return NULL; } sprite_t *isplayerleft(sprite_t *s) { if (globpowerup == PW_CAMERA) return NULL; if (player && !player->dead && player->x < s->x) return player; if (player2 && !player2->dead && player2->x < s->x) return player2; return NULL; } sprite_t *isplayerahead(sprite_t *s) { sprite_t *seen = NULL; int ydis; if (!playersalive()) { seen = NULL; } else { if (player) { ydis = abs((s->y - s->img->h/2) - (player->y - player->img->h/2)); if (ydis > TILEH*2) { seen = NULL; } else if ((s->dir < 0) && (player->x > s->x)) { seen = NULL; } else if ((s->dir > 0) && (player->x < s->x)) { seen = NULL; } else seen = player; } if (!seen && (player2)) { ydis = abs((s->y - s->img->h/2) - (player2->y - player2->img->h/2)); if (ydis > TILEH*2) { seen = NULL; } else if ((s->dir < 0) && (player2->x > s->x)) { seen = NULL; } else if ((s->dir > 0) && (player2->x < s->x)) { seen = NULL; } else seen = player2; } } return seen; } // turn to face a player void faceplayer(sprite_t *s) { // face a player if ((s->dir == D_RIGHT) && !isplayerright(s) && isplayerleft(s)) { s->dir = D_LEFT; } else if ((s->dir == D_LEFT) && !isplayerleft(s) && isplayerright(s)) { s->dir = D_RIGHT; } } SDL_Color *getcolour(int id) { switch (id) { case P_FLOWERYELLOW: case P_GEMYELLOW: case P_CHEESE: case P_PIZZA: case P_GOLDCOIN: case P_GOLDBAR: return &yellow; case P_FLOWERRED: case P_GEMRED: case P_CHIPS: return &red; case P_FLOWERPURPLE: case P_GEMPURPLE: return &purple; case P_BURGER: case P_SUNDAE: case P_CHOCOLATE: return &brown; case P_DIAMOND: return &cyan; case P_CAKE: return &blue; case P_ICECREAM: return &white; } return &white; } SDL_Color *getbgcolour (int id) { switch (id) { case P_PIZZA: return &red2; case P_CHIPS: return &brown2; } return &black; } int inintro(void) { if (curlevelnum == INTRO_LEVELNUM) return B_TRUE; return B_FALSE; } void dointroseq(void) { if (introstate == IS_START) { if (gtime >= 2) { playfx(FX_POWERUP); introstate = IS_YUM; } } else if (introstate == IS_YUM) { if (player) { addoutlinetext(player->x,player->y - (player->img->h*1.5),TEXTSIZE_YUM,"Yum!",&red,&black,YUMDELAY, TT_INTROTEXT); } if (player2) { addoutlinetext(player2->x,player2->y - (player2->img->h*1.5),TEXTSIZE_YUM,"Yum!",&purple,&black,YUMDELAY, TT_INTROTEXT); } introstate = IS_YUMWAIT; // exits when yum text is gone } else if (introstate == IS_JUMP) { if (player) { if (!player->jumping && !player->falling) { jump(player, D_RIGHT); player->jumpspeed = 7; } else if (player->falling) { movex(player, getspeed(player)/2, B_TRUE); } } if (player2) { if (player) { if (player->jumping && player->jumpspeed <= 5) { if (!player2->jumping && !player2->falling) { jump(player2, D_LEFT); player2->jumpspeed = 7; } else if (player2->falling) { movex(player2, -getspeed(player2)/2, B_TRUE); } } } else { if (!player2->jumping && !player2->falling) { jump(player2, D_LEFT); player2->jumpspeed = 7; } else if (player2->falling) { movex(player2, -getspeed(player2)/2, B_TRUE); } } } if ((player && player->falling) || (player2 && player2->falling)) { sprite_t *newsp; double startx,starty; // add rats startx = TILEW; starty = (curlevel->p1y * TILEH) + TILEH-2; puffin(-1, startx, starty, "nothing", 0); newsp = addsprite(P_RAT, startx, starty, "intro_rat"); newsp->speed = INTRO_RATSPEED; newsp->antigrav = B_TRUE; introstate = IS_RATS; playfx(FX_BOSSCHARGE); } } else if ((introstate == IS_RATS) || (introstate == IS_RATS2)) { sprite_t *s; double xpoint; // keep moving until we hit the ground if (player) { if (player->falling) { movex(player, getspeed(player), B_TRUE); } if (introstate == IS_RATS2) { // look around if (timer % 20 == 0) { player->dir = -player->dir; } } } if (player2) { if (player2->falling) { movex(player2, -getspeed(player2), B_TRUE); } if (introstate == IS_RATS2) { // look around if ((timer+5) % 20 == 0) { player2->dir = -player2->dir; } } } // add more rats if (introstate != IS_RATS2) { if (countmonsters(P_RAT) <= 6) { if (timer % 5 == 0) { sprite_t *newsp; double startx,starty; // add rats startx = TILEW; starty = (curlevel->p1y * TILEH) + TILEH-2; puffin(-1, startx, starty, "nothing", 0); newsp = addsprite(P_RAT, startx, starty, "intro_rat"); newsp->speed = INTRO_RATSPEED; newsp->antigrav = B_TRUE; } } } // if rats are past p2 start point, they fall xpoint = (curlevel->p2x * TILEW) + (TILEW/2); for (s = sprite ; s ; s = s->next) { if (ismonster(s->id)) { if (s->x >= xpoint) { s->antigrav = B_FALSE; s->speed = (INTRO_RATSPEED / 2); introstate = IS_RATS2; } } } // next state if (countmonsters(-1) <= 0) { introstate = IS_FINISH; if (player) { player->timer1 = 0; player->timer2 = 0; } if (player2) { player2->timer1 = 0; player2->timer2 = 0; } } } else if (introstate == IS_FINISH) { int finished = B_TRUE; // players jump up and down 3 times if (player) { if (isonground(player)) { if (player->timer1 < 3) { playfx(FX_JUMP); player->jumping = 1; player->jumpdir = 0; player->jumpspeed = 2; player->timer1++; finished = B_FALSE; } } } if (player2) { if (isonground(player2)) { if (player2->timer1 < 3) { playfx(FX_JUMP); player2->jumping = 1; player2->jumpdir = 0; player2->jumpspeed = 2; player2->timer1++; finished = B_FALSE; } } } if (finished) { if (levelcomplete == LV_INPROGRESS) { // clouds come in levelcomplete = LV_FINAL; // don't delay levelcompletetime = gtime; gtime += 10; } } } } int addcredit(void) { // can't add credits during game if (credits < MAXCREDITS) { if (lockcredits) { playfx(FX_SKULL); } else { credits++; playfx(FX_COIN); } return B_FALSE; } return B_TRUE; } int getpnum(sprite_t *s) { if (s == player) return 0; else return 1; } int countbabies(sprite_t *s, int babytype) { sprite_t *ss; int numbabies; numbabies = 0; for (ss = sprite ; ss ; ss = ss->next) { if ((ss->id == babytype) && (ss->owner == s)) { numbabies++; } } return numbabies; } int isbridge(int id) { switch (id) { case T_BRIDGE: case T_ICEBRIDGE: return B_TRUE; } return B_FALSE; } int isice(int id) { switch (id) { case T_ICE: case T_ICEBRIDGE: case T_ICETOP: return B_TRUE; } return B_FALSE; } int isconveyor(int id) { switch (id) { case T_RIGHT: case T_LEFT: return B_TRUE; } return B_FALSE; } int savebmp(SDL_Surface *which) { int rv; char filename[BUFLEN]; sprintf(filename, "/tmp/level_%d_%d.bmp",getcurworld(), getcurlevel()); rv = SDL_SaveBMP(which, filename); printf("Screenshot saved in %s\n",filename); return rv; } void melttile(int tx, int ty,int howlong) { if (numregrow >= (MAXREGROW-1)) { return; } regrow[numregrow].tx = tx; regrow[numregrow].ty = ty; regrow[numregrow].origid = curlevel->map[ty * LEVELW + tx ]; regrow[numregrow].timer = howlong; numregrow++; curlevel->map[ty * LEVELW + tx ] = getuniq(T_BLANK); drawtile(temps, tx,ty); puffin(-1, tx*TILEW+(TILEW/2), ty*TILEH+TILEH, "nothing", 0); }