3906 lines
88 KiB
C
3906 lines
88 KiB
C
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <unistd.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <SDL.h>
|
|
#include <SDL_keysym.h>
|
|
#include <SDL_rotozoom.h>
|
|
#include <SDL_ttf.h>
|
|
#include <SDL_framerate.h>
|
|
#include <SDL_mixer.h>
|
|
|
|
#include "shared.h"
|
|
#include "rc.h"
|
|
|
|
FPSmanager manager;
|
|
SDL_Surface *temps;
|
|
SDL_Surface *screen;
|
|
|
|
TTF_Font *font[MAXLETTERHEIGHT];
|
|
|
|
Mix_Music *curmusic = NULL; // pointer to currently playing music
|
|
|
|
char tempm[BUFLEN];
|
|
|
|
int playedbell;
|
|
int clocktime;
|
|
|
|
SDL_Surface *pausedtext, *pausedshadow;
|
|
int paused;
|
|
|
|
tiletype_t fakeblock;
|
|
|
|
|
|
/* the order in which fruit will appear */
|
|
int fruittypes[] = {
|
|
P_CHEESE,
|
|
P_ICECREAM,
|
|
P_CHIPS,
|
|
P_BURGER,
|
|
-1
|
|
};
|
|
|
|
|
|
/* the order in which powerups will appear */
|
|
int poweruptypes[] = {
|
|
P_SPEED,
|
|
P_NUMNETS,
|
|
P_BELL,
|
|
P_BIGNET,
|
|
P_GEMBOOST,
|
|
P_NUMNETS,
|
|
P_GEMBOOST,
|
|
P_NUMNETS,
|
|
P_HELMET,
|
|
-1
|
|
};
|
|
|
|
int curfruittype = 0;
|
|
int curpoweruptype = 0;
|
|
|
|
int gtime = 0;
|
|
int fpsticks = 0;
|
|
int fpsstart = 0;
|
|
|
|
int curworld = 1;
|
|
int curlevelnum;
|
|
int skipto = -1; // which level to skip to
|
|
level_t *curlevel;
|
|
int levelcompletetime = -1;
|
|
|
|
sprite_t *sprite = NULL; /* main sprite list */
|
|
sprite_t *player;
|
|
sprite_t *lastsprite;
|
|
|
|
|
|
|
|
SDL_Color red = {255, 0, 0, 0};
|
|
SDL_Color black = {0, 0, 0, 0};
|
|
SDL_Color blue = {0, 0, 255, 0};
|
|
SDL_Color cyan = {0, 255, 255, 0};
|
|
SDL_Color white = {255, 255, 255, 0};
|
|
SDL_Color grey = {210, 210, 210, 0};
|
|
SDL_Color green = {0, 255, 0, 0};
|
|
SDL_Color yellow = {255, 255, 0, 0};
|
|
|
|
int vidargs = 0;
|
|
|
|
int timer = 0;
|
|
int toggletimer = 0;
|
|
|
|
int main (int argc, char **argv) {
|
|
Uint8 *keys;
|
|
sprite_t *s,*nextsprite;
|
|
char filename[BUFLEN];
|
|
int i;
|
|
int *animtile;
|
|
|
|
curlevelnum = 1;
|
|
musicplaying = B_FALSE;
|
|
cheat = B_FALSE;
|
|
levelbg = NULL;
|
|
|
|
|
|
/* handle arguments */
|
|
if (argc >= 2) {
|
|
for (i = 1; i < argc; i++) {
|
|
if (!strcmp(argv[i], "-fs")) {
|
|
printf("Fullscreen mode enabled.\n");
|
|
vidargs |= SDL_FULLSCREEN;
|
|
} else if (!strcmp(argv[i], "-c")) {
|
|
printf("Cheat mode.\n");
|
|
cheat = 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 {
|
|
usage();
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE)==-1) {
|
|
printf("SDL_Init: %s\n", SDL_GetError());
|
|
exit(1);
|
|
}
|
|
|
|
atexit(cleanup);
|
|
|
|
#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);
|
|
screen = SDL_SetVideoMode(640,480,16,SDL_SWSURFACE|vidargs);
|
|
#endif
|
|
|
|
|
|
if (!screen) {
|
|
printf("Failed to open window: %s\n", SDL_GetError());
|
|
exit(1);
|
|
}
|
|
|
|
srand(time(NULL));
|
|
|
|
if (loadimagesets()) {
|
|
printf("Error loading images.\n");
|
|
return 1;
|
|
}
|
|
|
|
if (loadlevellist()) {
|
|
printf("Error loading level list from levels.dat.\n");
|
|
return 1;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 */
|
|
TTF_Init();
|
|
sprintf(filename, "gamefont.ttf");
|
|
for (i = 1; i < MAXLETTERHEIGHT; i++) {
|
|
font[i] = TTF_OpenFont(filename,i);
|
|
if (!font[i]) {
|
|
printf("Error opening font: %s\n", TTF_GetError());
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* calculate fps delay */
|
|
SDL_initFramerate(&manager);
|
|
SDL_setFramerate(&manager, WANTFPS);
|
|
|
|
|
|
|
|
/* init sound */
|
|
if (initsound()) {
|
|
printf("sound error.\n");
|
|
return 1;
|
|
}
|
|
|
|
/* init tiles */
|
|
if (loadtiletypes("green.tiles")) {
|
|
printf("Cannot initialise tiles\n");
|
|
exit(1);
|
|
}
|
|
|
|
playmusic(normalmusic);
|
|
if (loadlevel(curworld,curlevelnum)) {
|
|
return 1;
|
|
}
|
|
|
|
|
|
//levelcomplete = LV_FINAL;
|
|
curlevelnum-- ; // since nexlevel() will increment it
|
|
nextlevel();
|
|
//drawlevel();
|
|
flip();
|
|
|
|
timer = 0;
|
|
|
|
player->invuln = INVULNTIME;
|
|
player->score = 0;
|
|
player->lives = 3;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
// main loop
|
|
while (1) {
|
|
removeall();
|
|
|
|
/* check for death & update movement status*/
|
|
for (s = sprite ; s ; s = nextsprite) {
|
|
s->moved = MV_NONE;
|
|
nextsprite = s->next;
|
|
if (s->dead == D_FINAL) {
|
|
if (s == player) {
|
|
if (player->lives > 0) {
|
|
/* if we have lives left, go back to start position */
|
|
setdefaults(s);
|
|
s->x = (curlevel->p1x * TILEW) + (TILEW/2);
|
|
s->y = (curlevel->p1y * TILEH) + (TILEH/2);
|
|
s->invuln = INVULNTIME;
|
|
} else {
|
|
if (levelcomplete == LV_GAMEOVER) {
|
|
// TODO: Wait until "game over" text is gone, then slowly fade out the screen
|
|
// then show hiscores
|
|
// then back to title screen
|
|
} else {
|
|
addoutlinetext(320,240,TEXTSIZE_GAMEOVER,"Game Over",&red,&black,GAMEOVERDELAY);
|
|
levelcomplete = LV_GAMEOVER;
|
|
stopmusic();
|
|
playfx(FX_GAMEOVER);
|
|
}
|
|
}
|
|
} else {
|
|
killsprite(s);
|
|
// check for level completion
|
|
countmonsters();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* check for end of level */
|
|
if (levelcomplete == LV_CLEAR) {
|
|
addoutlinetext(320,240,TEXTSIZE_LEVEL,"Level Complete!",&green,&black,LEVELWINDELAY);
|
|
levelcomplete = LV_WAIT;
|
|
playfx(FX_WINLEVEL);
|
|
// turn off clock powerup
|
|
if (player->powerup == PW_CLOCK) {
|
|
Mix_ResumeMusic();
|
|
player->powerup = B_FALSE;
|
|
}
|
|
} else if (levelcomplete == LV_WAIT) {
|
|
int mcount = 0;
|
|
sprite_t *s2;
|
|
|
|
/* when all monsters have become fruits */
|
|
for (s2 = sprite->next ; s2 ; s2 = s2->next) {
|
|
if (ismonster(s2->id)) {
|
|
if (s2->id != P_CLOUD) {
|
|
mcount++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (mcount == 0) {
|
|
levelcompletetime = gtime;
|
|
levelcomplete = LV_FINAL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* check for keys */
|
|
SDL_PumpEvents();
|
|
keys = SDL_GetKeyState(NULL);
|
|
|
|
|
|
if (keys[SDLK_p]) {
|
|
if (toggletimer == 0) {
|
|
if (paused) {
|
|
paused = B_FALSE;
|
|
} else {
|
|
paused = B_TRUE;
|
|
}
|
|
toggletimer = 80;
|
|
}
|
|
}
|
|
if (keys[SDLK_ESCAPE]) {
|
|
return 1;
|
|
}
|
|
|
|
|
|
if (!paused) {
|
|
if (keys[SDLK_q]) {
|
|
gtime = nexthurryup-1;
|
|
}
|
|
if (keys[SDLK_l]) {
|
|
if (toggletimer == 0) {
|
|
addscore(player, 100001);
|
|
toggletimer = 80;
|
|
}
|
|
}
|
|
if (keys[SDLK_n]) {
|
|
if (toggletimer == 0) {
|
|
nextlevel();
|
|
toggletimer = 50;
|
|
}
|
|
}
|
|
if (keys[SDLK_d]) {
|
|
if (toggletimer == 0) {
|
|
// dump sprites
|
|
dumpsprites();
|
|
toggletimer = 50;
|
|
}
|
|
}
|
|
if (keys[SDLK_RETURN]) {
|
|
if (toggletimer == 0) {
|
|
SDL_WM_ToggleFullScreen(screen);
|
|
toggletimer = 50;
|
|
}
|
|
}
|
|
|
|
if ((!player->dead) && (!player->teleporting)) {
|
|
if (keys[SDLK_RIGHT]) {
|
|
if (canmove(player)) {
|
|
movex(player, getspeed(player));
|
|
}
|
|
if (canturn(player)) {
|
|
player->dir = D_RIGHT;
|
|
}
|
|
}
|
|
if (keys[SDLK_LEFT]) {
|
|
if (canmove(player)) {
|
|
movex(player, -getspeed(player));
|
|
}
|
|
if (canturn(player)) {
|
|
player->dir = D_LEFT;
|
|
}
|
|
}
|
|
if (keys[SDLK_UP]) {
|
|
//if (isonladder(player) || isladderabove(player)) {
|
|
if (player->climbing || isladderabove(player)) {
|
|
if (!player->netting && !player->slamming) {
|
|
player->y -= getspeed(player);
|
|
player->jumping = 0;
|
|
player->falling = 0;
|
|
player->climbing = B_TRUE;
|
|
player->moved = MV_WALK;
|
|
}
|
|
}
|
|
}
|
|
if (keys[SDLK_DOWN]) {
|
|
if (isonladder(player)) {
|
|
if (!player->netting && !player->slamming) {
|
|
player->y += getspeed(player);
|
|
player->jumping = 0;
|
|
player->falling = 0;
|
|
player->climbing = B_TRUE;
|
|
player->moved = MV_WALK;
|
|
}
|
|
}
|
|
}
|
|
if (keys[SDLK_x]) {
|
|
if (isinwater(player)) {
|
|
if (!player->jumping) {
|
|
//player->jumping = B_FALSE;
|
|
player->falling = B_FALSE;
|
|
if (!isroofabove(player)) {
|
|
// is there water above us too?
|
|
if (isinwaterpoint(player->x, player->y-TILEH)) {
|
|
// if so, swim up
|
|
player->y -= (getspeed(player)*3);
|
|
} else {
|
|
int whichway;
|
|
// if not, jump up
|
|
player->climbing = B_FALSE;
|
|
if (keys[SDLK_RIGHT]) {
|
|
whichway = 1;
|
|
} else if (keys[SDLK_LEFT]) {
|
|
whichway = -1;
|
|
} else {
|
|
whichway = 0;
|
|
}
|
|
playfx(FX_SPLASH);
|
|
jump(player, whichway);
|
|
}
|
|
|
|
}
|
|
}
|
|
} else { // not in water
|
|
if (!player->jumping) {
|
|
if (!player->falling) {
|
|
if (isonground(player) || isonladder(player)) {
|
|
/* dropping through a bridge */
|
|
if (keys[SDLK_DOWN]) {
|
|
if (isonbridge(player) && !player->falling) {
|
|
/* drop down */
|
|
player->dropping = B_TRUE;
|
|
player->dropx = player->x / TILEW;
|
|
player->dropy = player->y / TILEH;
|
|
}
|
|
} else { // jumping
|
|
int whichway;
|
|
if (keys[SDLK_RIGHT]) {
|
|
whichway = 1;
|
|
} else if (keys[SDLK_LEFT]) {
|
|
whichway = -1;
|
|
} else {
|
|
whichway = 0;
|
|
}
|
|
|
|
jump(player, whichway);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (keys[SDLK_z]) {
|
|
if ((!player->netting) && (!player->slamming)) {
|
|
if (keys[SDLK_DOWN]) {
|
|
/* slam */
|
|
if ((!player->slamming) && (isonground(player))) {
|
|
playfx(FX_SLAM);
|
|
player->slamming = B_TRUE;
|
|
player->slamangle = 0;
|
|
player->netxstart = player->x - (player->img->w/2)*player->dir;
|
|
player->netystart = player->y;
|
|
|
|
/* handle mace */
|
|
if (player->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->x = player->x;
|
|
s->y = player->y - (imageset[player->id].img[F_SHOOT]->h / 2) + 5;
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
addsprite(P_MACE, player->x,
|
|
player->y - (imageset[player->id].img[F_SHOOT]->h / 2) + 5,
|
|
"mace");
|
|
}
|
|
}
|
|
|
|
}
|
|
} else {
|
|
if ((player->netcaught < player->netmax) && (player->climbing == B_FALSE)) {
|
|
/* shoot net */
|
|
playfx(FX_SHOOT);
|
|
player->netting = 1;
|
|
if (player->netbig) {
|
|
player->netspeed = NETSPEED+3;
|
|
} else {
|
|
player->netspeed = NETSPEED;
|
|
}
|
|
player->netlen = 0;
|
|
player->netdir = player->dir;
|
|
|
|
/* handle boxing glove */
|
|
if (player->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->x = player->x;
|
|
s->y = player->y - (imageset[player->id].img[F_SHOOT]->h / 2) + 5;
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
addsprite(P_GLOVE, player->x,
|
|
player->y - (imageset[player->id].img[F_SHOOT]->h / 2) + 5,
|
|
"glove");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (!paused) {
|
|
if (player->powerup != 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;
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
// move sprites
|
|
for (s = sprite; s ; s = s->next) {
|
|
movesprite(s);
|
|
}
|
|
movetext();
|
|
|
|
|
|
if (levelcomplete == LV_INIT) {
|
|
// only player
|
|
dogravity(player);
|
|
dotileeffects(player);
|
|
} else {
|
|
if (levelcomplete != LV_NEXTLEV) {
|
|
/* gravity */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
dogravity(s);
|
|
}
|
|
|
|
/* tile effects */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
dotileeffects(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
// bell flash effect
|
|
if (player->hasbell) {
|
|
/* check for bell sound */
|
|
|
|
/* play a bell sound if the powerup will be a permenant one */
|
|
if (ispermenant(level->poweruptype)) {
|
|
// 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,white.r,white.g,white.b));
|
|
flip();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* check collisions for player and effects */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if ((s == player) || needscollisions(s->id)) {
|
|
checkcollide(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
drawscore();
|
|
|
|
drawnetting(player);
|
|
|
|
/* draw non-puff sprites */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if (s->id != P_PUFF) drawsprite(s);
|
|
}
|
|
/* draw puff sprites */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if (s->id == P_PUFF) drawsprite(s);
|
|
}
|
|
/* draw text */
|
|
drawtext();
|
|
|
|
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);
|
|
}
|
|
|
|
if (!paused) {
|
|
/* is screen shaking? */
|
|
if (player->powerup == 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 (--player->timer1 == 0) {
|
|
player->powerup = B_FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Update screen
|
|
flip();
|
|
|
|
if (!paused) {
|
|
if (++timer == 100) timer = 0;
|
|
}
|
|
|
|
if (toggletimer > 0) toggletimer--;
|
|
|
|
if (!paused) {
|
|
tick();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
void tick(void) {
|
|
sprite_t *s;
|
|
|
|
SDL_framerateDelay(&manager);
|
|
|
|
fpsticks = SDL_GetTicks();
|
|
if (fpsstart == 0) {
|
|
fpsstart = fpsticks;
|
|
} else {
|
|
/* once per second */
|
|
if (fpsticks - fpsstart >= 1000) {
|
|
gtime++;
|
|
|
|
// handle clock effect
|
|
if (player->powerup == PW_CLOCK) {
|
|
char tempm[SMALLBUFLEN];
|
|
// text
|
|
if (clocktime > 0) {
|
|
sprintf(tempm, "%d",clocktime);
|
|
addoutlinetext(320,120,TEXTSIZE_LEVEL, tempm, &yellow,&black,15);
|
|
// sound effect
|
|
playfx(FX_CLOCK);
|
|
}
|
|
// never reach hurryup time
|
|
nexthurryup++;
|
|
// decrement counter
|
|
clocktime--;
|
|
if (clocktime < 0) {
|
|
// finished!
|
|
Mix_ResumeMusic();
|
|
player->powerup = B_FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
/* check for hurryup*/
|
|
if (gtime == nexthurryup) {
|
|
if (!levelcomplete) {
|
|
for (s = sprite; s; s = s->next) {
|
|
if ((s != player) && (ismonster(s->id))) {
|
|
s->angry = B_TRUE;
|
|
s->iced = B_FALSE;
|
|
}
|
|
}
|
|
addoutlinetext(320,240,TEXTSIZE_HURRY, "Hurry up!", &yellow,&black,HURRYDELAY);
|
|
|
|
stopmusic();
|
|
Mix_PlayChannel(CH_HURRYUP, sfx[FX_HURRYUP], 0);
|
|
}
|
|
} else if (gtime == nexthurryup + 15) { // 15 secs after hurryup
|
|
if (!levelcomplete) {
|
|
addsprite(P_CLOUD, 320,240,"cloud");
|
|
addoutlinetext(320,240,TEXTSIZE_HURRY, "Too slow!", &red,&black,HURRYDELAY);
|
|
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 (!player->dead) {
|
|
levelcomplete = LV_NEXTLEV;
|
|
nextlevel();
|
|
}
|
|
}
|
|
}
|
|
fpsstart = fpsticks;
|
|
}
|
|
}
|
|
}
|
|
|
|
void nextlevel(void) {
|
|
char msg[SMALLBUFLEN];
|
|
|
|
// remove the player
|
|
removesprite(player);
|
|
|
|
/* in case we skipped the level due to a powerup etc */
|
|
levelcomplete = LV_NEXTLEV;
|
|
|
|
/* go to next level */
|
|
curlevelnum++;
|
|
if (!musicplaying || (curmusic == fastmusic)) {
|
|
playmusic(normalmusic);
|
|
}
|
|
|
|
// don't want the player flashing while scrolling
|
|
player->invuln = 0;
|
|
|
|
// these two handle the scroll effect to the next level
|
|
loadlevel(curworld,curlevelnum);
|
|
drawlevel();
|
|
|
|
// now the player gets invincibility
|
|
player->invuln = INVULNTIME;
|
|
|
|
/* reset game stats */
|
|
levelcomplete = LV_INIT;
|
|
levelcompletetime = -1;
|
|
|
|
/* reset level stats */
|
|
level->gotpowerup = B_FALSE;
|
|
|
|
if (player->hasbell) {
|
|
playedbell = B_FALSE;
|
|
} else {
|
|
playedbell = BELL_DONEFLASH;
|
|
}
|
|
|
|
level->iced = ICE_NONE;
|
|
level->icey = -1;
|
|
|
|
sprintf(msg, "Level %d-%d",curworld, curlevelnum);
|
|
addoutlinetext(320,240-18,TEXTSIZE_LEVEL,msg,&white,&black,LEVELDELAY);
|
|
|
|
|
|
sprintf(msg, "%s", curlevel->name);
|
|
addoutlinetext(320,240+18,TEXTSIZE_LEVEL2,msg,&cyan,&black,LEVELDELAY);
|
|
|
|
/* reset player stats */
|
|
player->netting = B_FALSE;
|
|
player->slamming = B_FALSE;
|
|
player->jumping = B_FALSE;
|
|
player->powerup = B_FALSE;
|
|
|
|
|
|
|
|
if (cheat) {
|
|
player->speed = 2;
|
|
}
|
|
|
|
// reset timer
|
|
timer = 0;
|
|
}
|
|
|
|
void jump(sprite_t *s, int dir) {
|
|
// if we've just been hit with armour, bypass all these checks)
|
|
if (!s->recoiling) {
|
|
// can't jump if already jumping
|
|
if (s->jumping) return;
|
|
if (s->jumptimer) return;
|
|
|
|
// can only jump up when climbing
|
|
if (s->climbing && (dir == 0)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (s->recoiling || isonground(s) || isinwater(s) || isonladder(s)) {
|
|
if (ismonster(s->id)) {
|
|
s->jumpdir = dir;
|
|
if (s->jumpdir != 0) {
|
|
s->dir = s->jumpdir;
|
|
}
|
|
s->jumptimer = 60;
|
|
} else {
|
|
s->jumpdir = dir;
|
|
if (s->jumpdir != 0) {
|
|
s->dir = s->jumpdir;
|
|
}
|
|
s->jumping = 1;
|
|
if (s->climbing) {
|
|
s->jumpspeed = 3;
|
|
} else if (s->ontramp) {
|
|
s->jumpspeed = 7;
|
|
} else {
|
|
s->jumpspeed = 5;
|
|
}
|
|
}
|
|
// stop climbing
|
|
s->climbing = B_FALSE;
|
|
// stop recoiling
|
|
s->recoiling = B_FALSE;
|
|
// play a sound effect if this is the player
|
|
if (s == player) {
|
|
if (player->ontramp) {
|
|
playfx(FX_SPRING);
|
|
} 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_CLOUD) 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 (s == player) {
|
|
// if we have armour, we lose it instead of dying
|
|
if (player->armour) {
|
|
// lose armour
|
|
player->armour = B_FALSE;
|
|
player->id = P_PLAYER;
|
|
// become invulnerable temporarily
|
|
player->invuln = INVULNTIME;
|
|
// bounce back
|
|
player->recoiling = B_TRUE;
|
|
jump(player, -player->dir);
|
|
// play sound
|
|
playfx(FX_OW);
|
|
// don't process rest of the death code
|
|
return;
|
|
} else {
|
|
int tnum;
|
|
|
|
if (player->powerup == PW_CLOCK) {
|
|
Mix_ResumeMusic();
|
|
}
|
|
player->powerup = B_FALSE;
|
|
|
|
nexthurryup = gtime + level->hurryuptime;
|
|
if (curmusic == fastmusic) {
|
|
playmusic(normalmusic);
|
|
}
|
|
// reset powerup types
|
|
curpoweruptype = 0;
|
|
|
|
/* lose a life */
|
|
player->lives--;
|
|
|
|
/* play sound */
|
|
playfx(FX_DIE);
|
|
|
|
// draw text
|
|
tnum = rand() % MAXDEATHTEXT;
|
|
addoutlinetext(player->x,player->y,TEXTSIZE_DEATH,deathtext[tnum],&red,&black,DIEDELAY);
|
|
}
|
|
}
|
|
|
|
/* release anything we've caught */
|
|
for (s2 = sprite->next ; s2 ; s2 = s2->next) {
|
|
if (s2->caughtby == s) {
|
|
s2->caughtby = NULL;
|
|
s2->angry = B_TRUE;
|
|
}
|
|
}
|
|
|
|
// un-ice everything
|
|
if (s == player) {
|
|
for (s2 = sprite->next ; s2 ; s2 = s2->next) {
|
|
if (s2->iced) {
|
|
s2->iced = B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* set death attribute */
|
|
s->dead = D_INITIAL;
|
|
s->netting = 0;
|
|
s->slamming = 0;
|
|
s->iced = 0;
|
|
|
|
// check for level clear
|
|
countmonsters();
|
|
|
|
}
|
|
|
|
// check whether the level has been won
|
|
void countmonsters(void) {
|
|
sprite_t *s2;
|
|
int mcount;
|
|
mcount = 0;
|
|
/* any monsters left? */
|
|
if (!levelcomplete) {
|
|
for (s2 = sprite->next ; s2 ; s2 = s2->next) {
|
|
if (ismonster(s2->id) && !s2->dead) {
|
|
if (s2->id != P_CLOUD) {
|
|
mcount++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mcount == 0) {
|
|
levelcomplete = LV_CLEAR;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cleanup(void) {
|
|
int i;
|
|
SDL_FreeSurface(pausedtext);
|
|
SDL_FreeSurface(pausedshadow);
|
|
Mix_HaltMusic();
|
|
Mix_CloseAudio();
|
|
for (i = 1; i < MAXLETTERHEIGHT; i++) {
|
|
TTF_CloseFont(font[i]);
|
|
}
|
|
TTF_Quit();
|
|
SDL_Quit();
|
|
}
|
|
|
|
void checkcollide(sprite_t *s) {
|
|
sprite_t *s2;
|
|
int keepchecking;
|
|
int xdiff,ydiff;
|
|
int 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;
|
|
|
|
keepchecking = B_TRUE;
|
|
|
|
/* check for colission with our net */
|
|
if (s->netting ) {
|
|
if (ismonster(s2->id) && s2->id != P_CLOUD) {
|
|
xdiff = (s->x + s->netlen*s->netdir) - s2->x;
|
|
if (xdiff < 0) xdiff = -xdiff;
|
|
ydiff = s->netystart - (s2->y - s2->img->h/2);
|
|
if (ydiff < 0) ydiff = -ydiff;
|
|
|
|
// take numnets into account for y check
|
|
ythresh = s2->img->h;
|
|
netsleft = s->netmax - s->netcaught;
|
|
if (netsleft > 1) {
|
|
ythresh += ((int)s->img->h / (int)(netsleft+1) );
|
|
}
|
|
|
|
//if ((xdiff <= s2->img->w/2) && (ydiff <= s2->img->h)) {
|
|
if ((xdiff <= s2->img->w/2) && (ydiff <= ythresh)) {
|
|
// we hit something!
|
|
|
|
// 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);
|
|
sprintf(tempm, bifftext[rand() % MAXBIFFTEXT]);
|
|
addoutlinetext(s2->x,s2->y - s->img->h/2, TEXTSIZE_BIFF, tempm,&red,&yellow,POINTSDELAY);
|
|
|
|
keepchecking = B_FALSE;
|
|
} else if (s2->iced) {
|
|
// it dies
|
|
playfx(FX_ICEBREAK);
|
|
die(s2);
|
|
} else {
|
|
// otherwise we caught it if we have enough nets
|
|
|
|
if (s->netcaught < s->netmax) {
|
|
s2->caughtby = s;
|
|
s2->jumping = B_FALSE;
|
|
s2->falling = 0;
|
|
s2->caughtstate = C_NETTING;
|
|
s->netcaught++;
|
|
|
|
keepchecking = B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // 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;
|
|
|
|
if ((xdiff <= s->img->w/2 + s2->img->w/2) &&
|
|
(ydiff <= s->img->h/2 + s2->img->h/2)) {
|
|
/* COLLISION! */
|
|
|
|
// are we the player?
|
|
if (s == player) {
|
|
//if (isfruit(s2->id) && (s2->teleporting == 0)) {
|
|
if (isfruit(s2->id)) {
|
|
int gotscore = s2->score;
|
|
|
|
/* kill the fruit */
|
|
s2->dead = D_FINAL;
|
|
/* give points to the player */
|
|
addscore(player, gotscore);
|
|
/* handle fruit effects */
|
|
if (!dofruiteffect(s2)) {
|
|
playfx(FX_FRUIT);
|
|
sprintf(tempm, "%d", gotscore);
|
|
addoutlinetext(s2->x,s2->y - s2->img->h/2, TEXTSIZE_POINTS, tempm, &white,&black,POINTSDELAY);
|
|
}
|
|
} else if (ismonster(s2->id) || isbullet(s2->id)) {
|
|
if (s2->iced) {
|
|
// monster dies
|
|
playfx(FX_ICEBREAK);
|
|
die(s2);
|
|
} else if (!s->invuln) {
|
|
// player dies
|
|
die(s);
|
|
}
|
|
}
|
|
} else if (s->id == P_SMASH) { // smash from mace slam
|
|
if (ismonster(s2->id)) {
|
|
// monster dies
|
|
die(s2);
|
|
// become something special
|
|
s2->willbecome = P_DIAMOND;
|
|
}
|
|
}
|
|
}
|
|
} // 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++;
|
|
}
|
|
}
|
|
|
|
|
|
void movesprite(sprite_t *s) {
|
|
int rv;
|
|
tiletype_t *tt;
|
|
|
|
if (levelcomplete == LV_INIT) {
|
|
// most things can't move in this state
|
|
//if ((s->id != P_PUFF) && (s != player)) {
|
|
if (!iseffect(s->id) && (s != player)) {
|
|
// caught or dead sprites can move, in case
|
|
// the player catches something before level start time
|
|
if ((!s->caughtby) && (!s->dead)) return;
|
|
}
|
|
}
|
|
|
|
// only player can move if you have a clock
|
|
if (player->powerup == PW_CLOCK) {
|
|
if (!iseffect(s->id) && (s != player) && !s->caughtby && !s->dead) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// iced monsters can't move
|
|
if (ismonster(s->id) && s->iced) {
|
|
return;
|
|
}
|
|
|
|
/* timer */
|
|
if (s->doomcount) {
|
|
s->doomcount--;
|
|
if (s->doomcount == 0) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
}
|
|
|
|
/* avoid edges of screen */
|
|
if (s->y < s->img->h) {
|
|
if (!s->flies) {
|
|
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--;
|
|
}
|
|
|
|
|
|
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;
|
|
} else if (s->dead == D_INITIAL) { /* just set to dead */
|
|
|
|
// 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 (s == player) {
|
|
s->jumpspeed = 8;
|
|
s->jumping = 1;
|
|
}
|
|
return;
|
|
} else if (s->dead == D_BOUNCING) { /* dying */
|
|
if (s == player) {
|
|
/* 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) {
|
|
/* 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;
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
} else if (s->dead == D_LASTBOUNCE) { /* final fall */
|
|
if (s == player) {
|
|
/* 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)) {
|
|
if (s->quickdie || isonground(s)) {
|
|
int x,y,ty;
|
|
s->dead = D_FINAL;
|
|
/* change into a 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;
|
|
|
|
//addsprite(s->willbecome, x, y, "Fruit", B_FALSE);
|
|
puffin(s->willbecome, x, y, "fruit", 0);
|
|
//ss = addsprite(P_PUFF, x, y, "Fruit", B_FALSE);
|
|
//ss->timer3 = s->willbecome;
|
|
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
} 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
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->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) {
|
|
movex(s, s->jumpdir*getspeed(s));
|
|
return;
|
|
}
|
|
|
|
if (!iseffect(s->id)) {
|
|
if (isonground(s)) {
|
|
if ((!s->falling) && (!s->jumping)) {
|
|
if (!s->climbing && !s->dropping) {
|
|
if (!isonladder(s)) {
|
|
adjustheight(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* sprite is about to jump */
|
|
if (s->jumptimer) {
|
|
s->jumptimer--;
|
|
if (s->jumptimer == 0) {
|
|
s->jumping = 1;
|
|
s->jumpspeed = 5;
|
|
if (s->jumpdir != 0) s->dir = s->jumpdir;
|
|
return;
|
|
} else if (s->jumptimer % 20 == 0) {
|
|
s->dir = -s->dir;
|
|
}
|
|
} else if ((s->id == P_PUFF) || (s->id == P_SMASH) || (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) {
|
|
addsprite(s->timer3, s->x,s->y,s->name );
|
|
}
|
|
}
|
|
} else if (s->timer1 >= PUFFFRAMES) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if (s->id == P_GLOVE) { // boxing glove effect
|
|
// dies when the player finshes netting
|
|
if (!player->netting) {
|
|
s->dead = D_FINAL;
|
|
} else {
|
|
// keep it at the end of the net
|
|
s->x = player->x + (player->netdir * player->netlen);
|
|
s->y = player->y - (player->img->h/2) + 5;
|
|
s->dir = player->dir;
|
|
}
|
|
} else if (s->id == P_MACE) { // mace slam effect
|
|
// dies when the player finishes slamming
|
|
if (!player->slamming) {
|
|
s->dead = D_FINAL;
|
|
} else {
|
|
double dist;
|
|
// keep it at the end of the slam
|
|
dist = (player->slamangle * (180/M_PI))/2;
|
|
|
|
s->x = player->x + cos(player->slamangle-(180*(M_PI/180)))*dist*player->dir;
|
|
s->y = player->y + sin(player->slamangle-(180*(M_PI/180)))*dist + imageset[P_MACEPOWERUP].img[F_WALK1]->h/2;
|
|
s->dir = player->dir;
|
|
}
|
|
} else if (s->id == P_RAT) {
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff;
|
|
|
|
|
|
/* distance to player */
|
|
xdiff = player->x - s->x;
|
|
if (xdiff < 0) absxdiff = -xdiff;
|
|
else absxdiff = 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->y > s->y) && (s->angry)) {
|
|
/* if player is below, fall off */
|
|
if (xdiff <= (TILEW*8)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if (player->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 {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s));
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
if (s->angry) {
|
|
if ((player->dead == 0) && (!s->jumping) && (!s->jumptimer)) {
|
|
/* if player is above us, jump */
|
|
if (player->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 (s->y - player->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 if (s->id == P_COKE) {
|
|
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff;
|
|
|
|
|
|
/* distance to player */
|
|
xdiff = player->x - s->x;
|
|
if (xdiff < 0) absxdiff = -xdiff;
|
|
else absxdiff = 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->y > s->y ) {
|
|
/* if player is below and nearby, fall off */
|
|
if (xdiff <= (TILEW*16)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if (player->y == s->y) {
|
|
/* 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 {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s));
|
|
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 ((player->dead == 0) && (!s->jumping) && (!s->jumptimer)) {
|
|
/* if player is above us...*/
|
|
if (player->y < s->y) {
|
|
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 - player->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 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 = player->x - s->x;
|
|
if (xdiff < 0) absxdiff = -xdiff;
|
|
else absxdiff = 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->y > s->y) && (s->angry)) {
|
|
/* if player is below, fall off */
|
|
if (xdiff <= (TILEW*8)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if (player->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 {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* shoot */
|
|
ydiff = player->y - s->y;
|
|
if (ydiff < 0) ydiff =-ydiff;
|
|
|
|
if (ydiff <= (TILEH*4)) {
|
|
sprite_t *ss;
|
|
int shoot = B_FALSE;
|
|
if (s->bullet == NULL) { // if we don't already have a bullet
|
|
// if we are facing the player
|
|
if ( (player->x < s->x) && (s->dir == D_LEFT) ) {
|
|
shoot = B_TRUE;
|
|
} else if ( (player->x > s->x) && (s->dir == D_RIGHT) ) {
|
|
shoot = B_TRUE;
|
|
}
|
|
}
|
|
if (shoot) {
|
|
// if our shooting timer is okay
|
|
if (s->timer1 == 0) {
|
|
ss = addsprite(P_SPIT,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));
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
|
|
if (s->angry) {
|
|
if ((player->dead == 0) && (!s->jumping) && (!s->jumptimer)) {
|
|
/* if player is above us, jump */
|
|
if (player->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 (s->y - player->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 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;
|
|
}
|
|
|
|
/* check for top of screen */
|
|
// TODO: later, remove this when we can wrap around
|
|
if ((s->y <= s->img->h) && (s->ys < 0)) {
|
|
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 (isonground(s) && !s->flies) {
|
|
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;
|
|
/* walk back and forwards */
|
|
|
|
/* drop if player is close */
|
|
xdiff = player->x - s->x;
|
|
if (xdiff < 0) xdiff =-xdiff;
|
|
|
|
if ((player->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));
|
|
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) {
|
|
if (movex(s, s->xs)) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_CLOUD) {
|
|
if ((player->dead) || (levelcomplete)) {
|
|
if ((s->img->h <= 3) || (s->img->w <= 3)) {
|
|
s->dead = D_FINAL;
|
|
/* reset hurryup timer */
|
|
nexthurryup = gtime + level->hurryuptime;
|
|
} else {
|
|
SDL_Surface *ts;
|
|
/* get smaller */
|
|
ts = rotozoomSurfaceXY(s->img,0, 0.9 , 0.9 ,0);
|
|
SDL_FreeSurface(s->img);
|
|
s->img = ts;
|
|
s->y--;
|
|
}
|
|
} else {
|
|
if ((s->xs == -99) || (s->ys == -99)) {
|
|
s->ys = 0.5;
|
|
s->xs = 1;
|
|
}
|
|
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
|
|
if (s->x >= (640 - s->img->w/2 - 5)) {
|
|
s->xs = -s->xs;
|
|
s->x = 640 - s->img->w/2 - 6;
|
|
}
|
|
if (s->x <= (s->img->w/2 + 5)) {
|
|
s->xs = -s->xs;
|
|
s->x = s->img->w/2 + 6;
|
|
}
|
|
if (s->y >= (480 - s->img->h/2 - 5)) {
|
|
s->ys = -s->ys;
|
|
s->y = 480 - s->img->h/2 - 6;
|
|
}
|
|
if (s->y <= (s->img->h/2 + 5)) {
|
|
s->ys = -s->ys;
|
|
s->y = s->img->h/2 + 6;
|
|
}
|
|
|
|
|
|
if (timer % 50 == 0) {
|
|
int w,h;
|
|
SDL_Surface *ts;
|
|
/* get bigger */
|
|
w = s->img->w;
|
|
h = s->img->h;
|
|
ts = rotozoomSurfaceXY(s->img,0, 1.1 , 1.1 ,0);
|
|
SDL_FreeSurface(s->img);
|
|
s->img = ts;
|
|
|
|
s->y += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void dotileeffects(sprite_t *s) {
|
|
tiletype_t *tt;
|
|
int finished = B_FALSE;
|
|
int state = 0;
|
|
int tilex,tiley;
|
|
|
|
if (s->jumping || s->dead || s->caughtby) {
|
|
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 (s == player || ismonster(s->id)) {
|
|
if (s->id != P_CLOUD) {
|
|
if (!s->teleporting) {
|
|
playfx(FX_TELEPORT);
|
|
s->teleporting = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* 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 (!ismonster(s->id) && !isfruit(s->id)) {
|
|
if (player->powerup != PW_CLOCK) {
|
|
movex(s, 1.5);
|
|
}
|
|
}
|
|
finished = B_TRUE;
|
|
} else if (tt->id == T_LEFT) {
|
|
if (!ismonster(s->id) && !isfruit(s->id)) {
|
|
if (player->powerup != PW_CLOCK) {
|
|
movex(s, -1.5);
|
|
}
|
|
}
|
|
finished = B_TRUE;
|
|
} else if ((tt->id == T_ICE) || (tt->id == T_ICETOP)) {
|
|
if (s == player) {
|
|
if (player->powerup != PW_CLOCK) {
|
|
if (!s->moved) {
|
|
movex(s, s->dir*s->speed);
|
|
s->moved = MV_ICE;
|
|
}
|
|
}
|
|
}
|
|
finished = B_TRUE;
|
|
} else if (tt->spikes) {
|
|
if (!isfruit(s->id) && !iseffect(s->id) && !isbullet(s->id)) {
|
|
if (!s->invuln) {
|
|
if (s->id != P_CLOUD) {
|
|
die(s);
|
|
}
|
|
}
|
|
}
|
|
finished = B_TRUE;
|
|
} else if (tt->id == T_TRAMPUP) {
|
|
/* tile changes to trampoline down */
|
|
if (!isfruit(s->id) && !iseffect(s->id) && !isbullet(s->id)) {
|
|
// 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
|
|
curlevel->map[s->trampy * LEVELW + s->trampx] = getuniq(T_TRAMPUP);
|
|
drawtile(temps, s->trampx, s->trampy);
|
|
}
|
|
} else {
|
|
// remember we were on it so it can release
|
|
s->ontramp = B_TRUE;
|
|
s->trampx = tilex;
|
|
s->trampy = tiley;
|
|
|
|
// move it down then draw it
|
|
curlevel->map[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;
|
|
int dstx,dsty,xdis,ydis;
|
|
int turns;
|
|
double pxspeed,pyspeed;
|
|
SDL_Rect area,dst;
|
|
int speed = 16;
|
|
SDL_Surface *playerbg;
|
|
|
|
/* TODO: chekc for memory leak here with temps -
|
|
need to free it at the end? */
|
|
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);
|
|
|
|
// change player to floating image
|
|
player->img = imageset[player->id].img[F_SHOOT];
|
|
|
|
// create buffer for player background
|
|
playerbg = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
player->img->w, player->img->h,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask,
|
|
screen->format->Amask);
|
|
SDL_DisplayFormat(playerbg);
|
|
|
|
|
|
// draw the full level onto the temporary surface
|
|
for (x = 0; x < LEVELW; x++) {
|
|
for (y = 0; y < LEVELH; y++) {
|
|
drawtile(temps,x,y);
|
|
}
|
|
}
|
|
|
|
|
|
// figure out where the player's new start position is
|
|
dstx = (curlevel->p1x * TILEW) + (TILEW/2);
|
|
dsty = (curlevel->p1y * TILEH) + TILEH-2;
|
|
|
|
// figure out distance to newposition
|
|
xdis = player->x - dstx; if (xdis < 0) xdis = -xdis;
|
|
ydis = player->y - dsty; if (ydis < 0) ydis = -ydis;
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// figure out how fast player needs to move to get there in time
|
|
pxspeed = ceil((double)xdis / (double)turns); if (pxspeed < 1) pxspeed = 1;
|
|
pyspeed = ceil((double)ydis / (double)turns); if (pyspeed < 1) pyspeed = 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
|
|
movetostart(player,dstx,dsty,pxspeed,pyspeed);
|
|
|
|
// 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 player
|
|
grabbehind(player, playerbg);
|
|
|
|
// draw player
|
|
drawsprite(player);
|
|
|
|
// update screen
|
|
SDL_GL_SwapBuffers();
|
|
SDL_UpdateRect(screen, 0,0,640,480);
|
|
SDL_framerateDelay(&manager);
|
|
|
|
// remove player
|
|
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 );
|
|
}
|
|
} 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
|
|
movetostart(player,dstx,dsty,pxspeed,pyspeed);
|
|
|
|
// 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
|
|
grabbehind(player, playerbg);
|
|
|
|
// draw player
|
|
drawsprite(player);
|
|
|
|
// update screen
|
|
SDL_GL_SwapBuffers();
|
|
SDL_UpdateRect(screen, 0,0,640,480);
|
|
SDL_framerateDelay(&manager);
|
|
|
|
// remove player
|
|
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 );
|
|
}
|
|
} 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
|
|
movetostart(player,dstx,dsty,pxspeed,pyspeed);
|
|
|
|
// 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 player
|
|
grabbehind(player, playerbg);
|
|
|
|
// draw player
|
|
drawsprite(player);
|
|
|
|
// update screen
|
|
SDL_GL_SwapBuffers();
|
|
SDL_UpdateRect(screen, 0,0,640,480);
|
|
SDL_framerateDelay(&manager);
|
|
|
|
// remove player
|
|
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 );
|
|
}
|
|
} 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
|
|
movetostart(player,dstx,dsty,pxspeed,pyspeed);
|
|
|
|
// 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 player
|
|
grabbehind(player, playerbg);
|
|
|
|
// draw player
|
|
drawsprite(player);
|
|
|
|
// update screen
|
|
SDL_GL_SwapBuffers();
|
|
SDL_UpdateRect(screen, 0,0,640,480);
|
|
SDL_framerateDelay(&manager);
|
|
|
|
// remove player
|
|
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 );
|
|
}
|
|
}
|
|
|
|
SDL_FreeSurface(playerbg);
|
|
|
|
levelcomplete = B_FALSE;
|
|
}
|
|
|
|
|
|
double getspeed(sprite_t *s ) {
|
|
int id = s->id;
|
|
double speed = 1;
|
|
|
|
if (s == player) {
|
|
speed = s->speed;
|
|
} else if (id == P_RAT) {
|
|
if (s->angry) speed = 1.5;
|
|
else speed = 1;
|
|
} 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_SPIDER) {
|
|
if (s->angry) speed = 2;
|
|
else speed = 1.5;
|
|
} else if (id == P_CHEESE) {
|
|
speed = 0;
|
|
}
|
|
|
|
if (isinwater(s)) speed /= 2;
|
|
|
|
return speed;
|
|
}
|
|
|
|
|
|
int addtext(int x, int y, int size, char *string, SDL_Color *c, int delay) {
|
|
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->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);
|
|
|
|
|
|
t->next = NULL;
|
|
lasttext = t;
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
/* copy background buffer (ie. tiles) to screen, erasing sprites */
|
|
void fruit(void) {
|
|
SDL_BlitSurface(temps, NULL, screen, NULL);
|
|
}
|
|
|
|
|
|
void movetext(void) {
|
|
text_t *t,*nextt;
|
|
for (t = text ; t ; t = nextt) {
|
|
nextt = t->next;
|
|
if (t->state == 0) {
|
|
t->size += TEXTSPEED;
|
|
if (t->size >= t->maxsize) {
|
|
t->state = 1;
|
|
}
|
|
} else if (t->state == t->delay) {
|
|
t->size -= TEXTSPEED;
|
|
if (t->size <= 3) {
|
|
killtext(t);
|
|
}
|
|
|
|
} else {
|
|
t->state++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void drawscore(void) {
|
|
SDL_Surface *score;
|
|
SDL_Rect area;
|
|
int i;
|
|
|
|
addcommas(tempm, player->score);
|
|
|
|
/* shadow */
|
|
score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, black);
|
|
area.x = 18;
|
|
area.y = 7;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(score, NULL, screen, &area);
|
|
SDL_FreeSurface(score);
|
|
/* score */
|
|
score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, red);
|
|
area.x = 20;
|
|
area.y = 5;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(score, NULL, screen, &area);
|
|
SDL_FreeSurface(score);
|
|
|
|
// lives
|
|
|
|
// lives - show 1 less than lives
|
|
area.x = 20;
|
|
area.y = 25;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
for (i = 1; i < player->lives; i++) {
|
|
SDL_BlitSurface(head, NULL, screen, &area);
|
|
area.x += (head->w + 3);
|
|
}
|
|
|
|
// level #
|
|
sprintf(tempm, "Level %d-%d",curworld, curlevelnum);
|
|
/* 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);
|
|
/* score */
|
|
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);
|
|
}
|
|
|
|
void drawtext(void) {
|
|
text_t *t;
|
|
SDL_Rect area;
|
|
|
|
for (t = text ; t ; t = t->next) {
|
|
|
|
/* 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) {
|
|
SDL_BlitSurface(temps, NULL, screen, NULL);
|
|
}
|
|
|
|
void drawnetting(sprite_t *s) {
|
|
int sx;
|
|
int xx;
|
|
SDL_Rect area;
|
|
|
|
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;
|
|
drawline16(screen,sx,s->nety,xx,yy,white);
|
|
// add sparkle
|
|
xx = s->x + s->netdir*s->netlen;
|
|
addsprite(P_SPARKLE, xx + (rand() % 14) - 7, yy + (rand() % 8) - 4, "sparkle");
|
|
}
|
|
|
|
//drawline16(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety-3,white);
|
|
//drawline16(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety,white);
|
|
//drawline16(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety+3,white);
|
|
} else if (s->slamming) {
|
|
double dist;
|
|
int x,y;
|
|
int ii;
|
|
dist = (s->slamangle * (180/M_PI))/2;
|
|
|
|
s->netxstart = s->x + cos(s->slamangle-(180*(M_PI/180)))*dist*s->dir;
|
|
s->netystart = s->y + sin(s->slamangle-(180*(M_PI/180)))*dist;
|
|
|
|
/* middle line */
|
|
drawline16(screen,s->x,s->y - s->img->h/2,
|
|
s->netxstart,s->netystart,white);
|
|
/* left line */
|
|
x = s->x + cos(s->slamangle-(5*(M_PI/180))-(180*(M_PI/180)))*dist*s->dir;
|
|
y = s->y + sin(s->slamangle-(5*(M_PI/180))-(180*(M_PI/180)))*dist;
|
|
drawline16(screen,s->x,s->y - s->img->h/2,x, y, white);
|
|
|
|
/* right line */
|
|
x = s->x + cos(s->slamangle+(5*(M_PI/180))-(180*(M_PI/180)))*dist*s->dir;
|
|
y = s->y + sin(s->slamangle+(5*(M_PI/180))-(180*(M_PI/180)))*dist;
|
|
drawline16(screen,s->x,s->y - s->img->h/2,x, y, white);
|
|
|
|
// add sparkles
|
|
for (ii = 0 ; ii < player->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;
|
|
|
|
|
|
/* 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;
|
|
}
|
|
|
|
/* 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 (tthere->id == T_BRIDGE) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isladder(int tid) {
|
|
switch (tid) {
|
|
case T_LADDER:
|
|
case T_LADDERTOP:
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
int isonladder(sprite_t *s) {
|
|
tiletype_t *tthere;
|
|
tthere = gettileat(s->x,s->y, NULL,NULL);
|
|
if (isladder(tthere->id)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isladderabove(sprite_t *s) {
|
|
tiletype_t *tthere;
|
|
tthere = gettileat(s->x,s->y-TILEH, NULL,NULL);
|
|
if (tthere->id == T_LADDER) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int 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) {
|
|
/* 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isongroundpoint(sprite_t *s, int x,int y) {
|
|
tiletype_t *tt;
|
|
int tilex,tiley;
|
|
int xoff;
|
|
int groundy;
|
|
|
|
tt = gettileat(x,y, &tilex, &tiley);
|
|
|
|
|
|
// 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;
|
|
|
|
// only player can move if you have a clock
|
|
if (player->powerup == PW_CLOCK) {
|
|
if (!iseffect(s->id) && (s != player) && !s->caughtby && !s->dead) {
|
|
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) {
|
|
// change tile type
|
|
curlevel->map[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;
|
|
if (s->flies && !s->iced) return; // ice cancels flying
|
|
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 (s == player || ismonster(s)) {
|
|
if (isinwater(s)) {
|
|
if (!s->swimming) {
|
|
s->swimming = B_TRUE;
|
|
playfx(FX_SPLASH);
|
|
adjustx(s, F_SWIM1);
|
|
}
|
|
} else {
|
|
if (s->swimming) {
|
|
s->swimming = B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
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;
|
|
}
|
|
}
|
|
|
|
// handle ring
|
|
if (s == player) {
|
|
if (player->powerup == PW_RINGJUMP) {
|
|
if (timer % 2 == 0) {
|
|
int xx,yy;
|
|
// add sparkle
|
|
xx = player->x + (rand() % player->img->w) - (player->img->w/2);
|
|
yy = player->y - (rand() % (player->img->h/2));
|
|
addsprite(P_SPARKLE, xx, yy, "sparkle");
|
|
|
|
// gain points
|
|
addscore(player, 20);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* have we hit a roof ? */
|
|
/* can jump through one tile, but not two or more */
|
|
if (isroofabove(s) && isroofnabove(s,2)) {
|
|
/* stop jumping */
|
|
s->jumping = B_FALSE;
|
|
s->falling = B_TRUE;
|
|
s->fallspeed = 0;
|
|
}
|
|
|
|
} else { // not jumping
|
|
if (isonground(s) ) {
|
|
if (s->falling && s->iced) {
|
|
// when an iced monster hits the ground, it smashes
|
|
s->willbecome = P_DIAMOND;
|
|
playfx(FX_ICEBREAK);
|
|
die(s);
|
|
}
|
|
s->dropping = B_FALSE;
|
|
s->falling = B_FALSE;
|
|
s->climbing = B_FALSE;
|
|
} else {
|
|
if (s->falling == B_FALSE) {
|
|
s->fallspeed = 1;
|
|
}
|
|
s->falling = B_TRUE;
|
|
if (isinwater(s) && !s->iced) {
|
|
s->y += (s->fallspeed/2);
|
|
} else {
|
|
s->y += s->fallspeed;
|
|
}
|
|
if ((timer % 10 == 0) && (s->fallspeed < FALLSPEED)) {
|
|
s->fallspeed++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s->netting) {
|
|
s->netlen += s->netspeed;
|
|
s->netting++;
|
|
if (s->netting % 2 == 0) {
|
|
if (s->netspeed > -NETSPEED) s->netspeed--;
|
|
else {
|
|
if (s->netlen <= 0) {
|
|
s->netting = 0;
|
|
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;
|
|
double dist;
|
|
int hitwall = B_FALSE;
|
|
|
|
s->slamangle += (10 * (M_PI/180));
|
|
|
|
|
|
dist = (s->slamangle * (180/M_PI))/2;
|
|
netx = s->x + cos(s->slamangle-(180*(M_PI/180)))*dist*s->dir;
|
|
if ((netx >= (640-TILEW)) || (netx <= TILEW)) {
|
|
hitwall = B_TRUE;
|
|
}
|
|
|
|
if (s->slamangle >= (180 * (M_PI/180)) || hitwall) {
|
|
/* finished slamming */
|
|
int xdiff,ydiff,xnet = 0,ynet = 0;
|
|
int pointsinc = 250;
|
|
int psize = 6;
|
|
int gotsomething = B_FALSE;
|
|
int macex,macey;
|
|
|
|
s->slamming = 0;
|
|
|
|
/* reset fruit type counter */
|
|
curfruittype = 0;
|
|
|
|
// if we have a mace, add an explosion and play a thump sound
|
|
if (player->powerup == PW_MACE) {
|
|
// play sound
|
|
playfx(FX_MACE);
|
|
|
|
// find location of mace
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (s2->id == P_MACE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!s2) {
|
|
// should never happen
|
|
macex = 0;
|
|
macey = 0;
|
|
} else {
|
|
int xx,yy;
|
|
macex = s2->x;
|
|
macey = s2->y - s2->img->h/2;
|
|
|
|
// add explosion
|
|
//puffin(-1, macex, macey, "nothing", 0);
|
|
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");
|
|
//puffin(-1, macex+xx*TILEW, macey-yy*TILEH, "nothing", 0);
|
|
//puffin(-1, macex-xx*TILEW, macey-yy*TILEH, "nothing", 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* kill anything we've caught */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
/* kill anything we have caught */
|
|
if (s2->caughtby == s) {
|
|
tiletype_t *tt;
|
|
tt = gettileat(s2->x,s2->y+2,NULL,NULL);
|
|
/* if on ground or hitting a wall, monster dies */
|
|
if ((hitwall) || (tt == NULL) || (tt->solid)) {
|
|
/* will become a fruit when it finishes dying */
|
|
s2->willbecome = fruittypes[curfruittype];
|
|
/* increment fruit type */
|
|
if (fruittypes[++curfruittype] == -1) {
|
|
curfruittype = 0;
|
|
}
|
|
die(s2);
|
|
pointsinc *= 2;
|
|
psize += 10;
|
|
xnet = s2->x;
|
|
ynet = s2->y - s2->img->h/2;
|
|
|
|
gotsomething++;
|
|
} else {
|
|
/* otherwise it gets angry */
|
|
s2->angry = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we have a powerup, centre of net is the mace position
|
|
if (player->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 || (player->powerup == PW_MACE)) {
|
|
/* kill anything we hit */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if ((s2->caughtby != s) && (!s2->dead) && (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->id != P_CLOUD) {
|
|
/* dies and becomes a powerup */
|
|
// if we were holding something, we can get a powerup
|
|
// if we used a mace, it becomes a diamon.
|
|
if (gotsomething) {
|
|
s2->willbecome = poweruptypes[curpoweruptype];
|
|
if (poweruptypes[++curpoweruptype] == -1) {
|
|
curpoweruptype = 0;
|
|
}
|
|
} else if (player->powerup == PW_MACE) {
|
|
s2->willbecome = P_DIAMOND;
|
|
} else { // should never happen
|
|
/* will become a fruit when it finishes dying */
|
|
s2->willbecome = fruittypes[curfruittype];
|
|
/* increment fruit type */
|
|
if (fruittypes[++curfruittype] == -1) {
|
|
curfruittype = 0;
|
|
}
|
|
}
|
|
die(s2);
|
|
pointsinc *= 2;
|
|
psize += 10;
|
|
|
|
gotsomething++;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
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 */
|
|
s2->caughtby = NULL;
|
|
}
|
|
}
|
|
|
|
s->netcaught = 0;
|
|
|
|
/* show points */
|
|
if (psize >= MAXLETTERHEIGHT) {
|
|
psize = MAXLETTERHEIGHT-1;
|
|
}
|
|
if (pointsinc > 250) {
|
|
sprintf(tempm, "%d",pointsinc);
|
|
addoutlinetext(xnet,ynet-TILEH, psize, tempm, &white,&black,POINTSDELAY);
|
|
/* give points to player */
|
|
//s->score += pointsinc;
|
|
addscore(s, pointsinc);
|
|
}
|
|
|
|
} // end if slamangle > 180degrees
|
|
} // end if slamming
|
|
}
|
|
|
|
|
|
int movex(sprite_t *s,double amt) {
|
|
double newx,newy;
|
|
double curx,cury;
|
|
int tilex,tiley;
|
|
tiletype_t *tt,*tt2;
|
|
int newxoff,newgroundy;
|
|
int newtilex,newtiley;
|
|
|
|
double amtdir;
|
|
|
|
tt = gettileat(s->x, s->y, &tilex,&tiley);
|
|
|
|
|
|
if (amt > 0) amtdir = 1;
|
|
else (amtdir = -1);
|
|
|
|
|
|
curx = s->x;
|
|
cury = s->y;
|
|
|
|
/* check for blockage to E/W */
|
|
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) {
|
|
return B_TRUE;
|
|
}
|
|
if (tt2->solid == S_SLOPE && (!candoslopes(s->id))) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
// if falling, check the tile directly to our SW/SEtoo */
|
|
if (s->falling) {
|
|
newx = s->x + (amtdir*TILEW/2);
|
|
newy = cury;
|
|
tt2 = gettileat(newx,newy,&newtilex,&newtiley);
|
|
if (tt2->solid == S_SOLID) {
|
|
return B_TRUE;
|
|
}
|
|
if (tt2->solid == S_SLOPE && (!candoslopes(s->id))) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
/* get new position */
|
|
newx = curx + amt;
|
|
newy = cury-2;
|
|
tt2 = gettileat(newx,newy,&newtilex,&newtiley);
|
|
newxoff = newx - (newtilex*TILEW);
|
|
newgroundy = newtiley*TILEH + tt2->lowness[newxoff];
|
|
|
|
/* new block is at least partially solid */
|
|
if (tt2->solid == S_SOLID) {
|
|
return B_TRUE;
|
|
} else if ((tt2->solid == S_SLOPE) && candoslopes(s->id)) {
|
|
/* we can move, but need to adjust our height */
|
|
s->x += amt;
|
|
} else {
|
|
/* new block is empty */
|
|
s->x += amt;
|
|
}
|
|
|
|
s->moved = MV_WALK;
|
|
|
|
// rings
|
|
if (s == player) {
|
|
if (player->powerup == PW_RINGWALK) {
|
|
if (isonground(player)) {
|
|
int xx,yy;
|
|
// add sparkle
|
|
xx = player->x + (rand() % player->img->w) - (player->img->w/2);
|
|
yy = player->y - (rand() % (player->img->h/2));
|
|
addsprite(P_SPARKLE, xx, yy, "sparkle");
|
|
|
|
// gain points
|
|
addscore(player, 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void adjustheight(sprite_t *s) {
|
|
tiletype_t *tt;
|
|
int xoff,groundy;
|
|
int tilex,tiley;
|
|
|
|
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) {
|
|
while (tt->solid == S_SOLID) {
|
|
s->y--;
|
|
tt = gettileat(s->x,s->y-1,&tilex,&tiley);
|
|
}
|
|
}
|
|
}
|
|
|
|
int dofruiteffect(sprite_t *s) {
|
|
if (s->id == P_SPEED) {
|
|
playfx(FX_POWERUP);
|
|
player->speed = 2;
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, "Speed up!", &white,&black,POINTSDELAY);
|
|
return B_TRUE;
|
|
} else if (s->id == P_NUMNETS) {
|
|
playfx(FX_POWERUP);
|
|
if (player->netmax < 4) {
|
|
player->netmax++;
|
|
}
|
|
sprintf(tempm, "%d nets!",player->netmax);
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
return B_TRUE;
|
|
} else if (s->id == P_BIGNET) {
|
|
playfx(FX_POWERUP);
|
|
player->netbig = B_TRUE;
|
|
sprintf(tempm, "Big net!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
return B_TRUE;
|
|
} else if (s->id == P_TROPHY) {
|
|
// all powerups
|
|
playfx(FX_POWERUP);
|
|
player->netmax = 4; // all nets
|
|
player->netbig = B_TRUE; // big net
|
|
player->speed = 2; // fast
|
|
sprintf(tempm, "Full power!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
return B_TRUE;
|
|
} else if (s->id == P_BELL) {
|
|
// all powerups
|
|
playfx(FX_BELL); // different sound effect
|
|
player->hasbell = B_TRUE;
|
|
sprintf(tempm, "Powerup Detector!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
return B_TRUE;
|
|
} else if (s->id == P_RINGGOLD) {
|
|
// points for walking
|
|
playfx(FX_POWERUP);
|
|
player->powerup = PW_RINGWALK;
|
|
sprintf(tempm, "Walk Ring!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
return B_TRUE;
|
|
} else if (s->id == P_RINGSILVER) {
|
|
// points for walking
|
|
playfx(FX_POWERUP);
|
|
player->powerup = PW_RINGJUMP;
|
|
sprintf(tempm, "Jump Ring!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
return B_TRUE;
|
|
} else if (s->id == P_MACEPOWERUP) {
|
|
playfx(FX_POWERUP);
|
|
player->powerup = PW_MACE;
|
|
sprintf(tempm, "Mace Slam!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
return B_TRUE;
|
|
} else if (s->id == P_BOXING) {
|
|
playfx(FX_POWERUP);
|
|
player->powerup = PW_BOXING;
|
|
sprintf(tempm, "Boxing Glove!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
return B_TRUE;
|
|
} else if (s->id == P_HELMET) {
|
|
int xx,yy;
|
|
playfx(FX_ARMOR);
|
|
player->id = P_ARMOUR; // change how the player looks
|
|
player->armour = B_TRUE;
|
|
sprintf(tempm, "Armour!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
// add puffs
|
|
for (xx = s->x - TILEW; xx <= s->x + TILEW; xx += TILEW) {
|
|
for (yy = s->y - TILEW*2; yy <= s->y; yy += TILEH) {
|
|
puffin(-1, xx, yy, "nothing", 0);
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_GEMBOOST) {
|
|
playfx(FX_POWERUP);
|
|
if (player->gemboost <= 1) {
|
|
player->gemboost = 2;
|
|
} else {
|
|
player->gemboost = 3;
|
|
}
|
|
sprintf(tempm, "Bonus x%d!",player->gemboost);
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
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);
|
|
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);
|
|
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);
|
|
player->powerup = PW_CLOCK;
|
|
clocktime = CLOCKTIME;
|
|
sprintf(tempm, "Freeze time!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY);
|
|
// pause music
|
|
Mix_PauseMusic();
|
|
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,&white,&black,POINTSDELAY);
|
|
if (!curlevel->iced) {
|
|
curlevel->iced = ICE_INPROGRESS;
|
|
curlevel->icey = 0;
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_BOMB) {
|
|
sprite_t *s2, *nexts;
|
|
|
|
// make the screen shake
|
|
player->powerup = PW_BOMB;
|
|
player->timer1 = 100;
|
|
|
|
// kill all monsters
|
|
playfx(FX_BOOM);
|
|
sprintf(tempm, "KABOOM!!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_BOMB, tempm,&red,&yellow,POINTSDELAY);
|
|
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->caughtby = NULL;
|
|
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);
|
|
|
|
// temp invincibility
|
|
player->invuln = SHIELDTIME;
|
|
|
|
return B_TRUE;
|
|
} else if (s->id == P_HELP) {
|
|
playfx(FX_POWERUP);
|
|
// TODO: move other HELP text around if need be!
|
|
addoutlinetext(320,240,TEXTSIZE_HELP, s->name, &white,&black,HELPDELAY);
|
|
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) * player->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);
|
|
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("\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 (!isonladder(pl) || pl->falling || isonground(pl)) {
|
|
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, "sounds/");
|
|
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;
|
|
|
|
/* init */
|
|
if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 1024) < 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_LIFE, "life.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");
|
|
|
|
|
|
// load sound effects
|
|
for (i = 0; i < MAXFX; i++) {
|
|
if (!sfx[i]) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
// set up callback
|
|
Mix_ChannelFinished(channeldone);
|
|
|
|
// load music
|
|
normalmusic = Mix_LoadMUS("music/main.mod");
|
|
if (!normalmusic) {
|
|
printf("can't load music\n");
|
|
return B_TRUE;
|
|
}
|
|
|
|
fastmusic = Mix_LoadMUS("music/mainfast.mod");
|
|
if (!fastmusic) {
|
|
printf("can't load fast music\n");
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void playfx(int num) {
|
|
Mix_PlayChannel(-1, sfx[num], 0);
|
|
}
|
|
|
|
void playmusic(Mix_Music *toplay) {
|
|
/* stop music */
|
|
if (musicplaying) {
|
|
Mix_HaltMusic();
|
|
}
|
|
|
|
/* start music */
|
|
//music = toplay;
|
|
Mix_PlayMusic(toplay, -1);
|
|
|
|
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
|
|
void movetostart(sprite_t *p, int dstx, int dsty, double xspeed, double yspeed) {
|
|
if (p->x < dstx) {
|
|
p->x += xspeed;
|
|
if (p->x > dstx) p->x = dstx;
|
|
}
|
|
if (p->x > dstx) {
|
|
p->x -= xspeed;
|
|
if (p->x < dstx) p->x = dstx;
|
|
}
|
|
if (p->y < dsty) {
|
|
p->y += yspeed;
|
|
if (p->y > dsty) p->y = dsty;
|
|
}
|
|
if (p->y > dsty) {
|
|
p->y -= yspeed;
|
|
if (p->y < dsty) p->y = dsty;
|
|
}
|
|
}
|
|
|
|
// grabs area behind a sprite into a temp buffer
|
|
SDL_Surface *grabbehind(sprite_t *s, SDL_Surface *surf) {
|
|
SDL_Rect area;
|
|
|
|
// remember area behind player
|
|
area.x = s->x - s->img->w/2;
|
|
area.y = s->y - s->img->h;
|
|
area.w = s->img->w;
|
|
area.h = s->img->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");
|
|
}
|
|
|
|
printf("--------\n");
|
|
printf("Total monsters: %d\n",mcount);
|
|
printf("\n\n");
|
|
}
|
|
|
|
void addoutlinetext(int x, int y, int size, char *msg, SDL_Color *col, SDL_Color *bgcol, int delay) {
|
|
addtext(x-1,y,size,msg,bgcol,delay); // outline
|
|
addtext(x-1,y-1,size,msg,bgcol,delay); // outline
|
|
addtext(x,y-1,size,msg,bgcol,delay); // outline
|
|
addtext(x+1,y-1,size,msg,bgcol,delay); // outline
|
|
addtext(x+1,y,size,msg,bgcol,delay); // outline
|
|
addtext(x+1,y+1,size,msg,bgcol,delay); // outline
|
|
addtext(x,y+1,size,msg,bgcol,delay); // outline
|
|
addtext(x-1,y+1,size,msg,bgcol,delay); // outline
|
|
addtext(x,y,size,msg,col,delay); // main text
|
|
}
|
|
|
|
char *addcommas(char *buffer, int num) {
|
|
char tempbuf[MIDBUFLEN];
|
|
char *p;
|
|
char *p2;
|
|
int count;
|
|
|
|
sprintf(tempbuf, "%d",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;
|
|
}
|
|
|
|
void addscore(sprite_t *s, int amt) {
|
|
int oldscore;
|
|
oldscore = s->score;
|
|
|
|
s->score += amt;
|
|
|
|
// each multiple of 100,000
|
|
if (s == player) {
|
|
if ((s->score / 100000) > (oldscore / 100000)) {
|
|
playfx(FX_LIFE);
|
|
s->lives++;
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_LIFE, "Extra life!",&green,&black,LIFEDELAY);
|
|
}
|
|
}
|
|
}
|
|
|
|
void doice(void) {
|
|
int yy,xx,changed;
|
|
sprite_t *s;
|
|
|
|
// 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--) {
|
|
// finished?
|
|
if ((xx == LEVELW-1) && (yy == LEVELH-1)) {
|
|
curlevel->iced = ICE_COMPLETE;
|
|
break;
|
|
}
|
|
// make sure tile is valid
|
|
if ((yy >= 0) && (yy < LEVELH) && (xx >= 0) && (xx < LEVELW)) {
|
|
changed = B_FALSE;
|
|
// if not already a second layer here...
|
|
if (curlevel->map2[yy*LEVELW+xx] == T_BLANK) {
|
|
// add ice layer
|
|
switch (curlevel->map[yy*LEVELW+xx] ) {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
|
|
diff = (imageset[s->id].img[framenum]->w - s->img->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;
|
|
}
|
|
}
|