15305 lines
369 KiB
C
15305 lines
369 KiB
C
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <sys/types.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef WINDOWS
|
|
#include <winsock.h>
|
|
#else
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netdb.h>
|
|
#endif
|
|
|
|
#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>
|
|
#ifdef OPENGL
|
|
#include <SDL_opengl.h>
|
|
#endif
|
|
#include <sqlite3.h>
|
|
|
|
#include "shared.h"
|
|
#include "rc.h"
|
|
|
|
FPSmanager manager;
|
|
SDL_Surface *temps;
|
|
SDL_Surface *screen;
|
|
|
|
SDL_Surface *credittext;
|
|
SDL_Surface *endgamebox;
|
|
|
|
SDL_Surface *temptilesurf;
|
|
|
|
int lockcredits = B_FALSE;
|
|
|
|
int globtimer;
|
|
|
|
int endgame = B_FALSE;
|
|
int autoshot = B_FALSE;
|
|
int shottaken = B_FALSE;
|
|
|
|
int introstate;
|
|
|
|
TTF_Font *font[MAXLETTERHEIGHT];
|
|
|
|
char hiscoreserver[BUFLEN];
|
|
int hiscoreport;
|
|
hiscore_t hiscore[MAXHISCORES];
|
|
int numhiscores;
|
|
int wanthiscores;
|
|
int gothiscore = -1;
|
|
int gothiscore2 = -1;
|
|
|
|
|
|
int joytest = B_FALSE;
|
|
int havejoysticks;
|
|
int joybuttons[2];
|
|
const char *joyname[2];
|
|
int joytype[2];
|
|
int joyanalog[2];
|
|
int joythresh[2];
|
|
SDL_Joystick *joy[2];
|
|
Uint8 *keys;
|
|
int joyx[2],joyy[2],joybut[2][MAXJOYBUTTONS], joymap[MAXJOYBUTTONS];
|
|
|
|
Mix_Music *curmusic = NULL; // pointer to currently playing music
|
|
|
|
char tempm[BUFLEN];
|
|
|
|
// used to remember old level if we flood it
|
|
int savemap[LEVELW*LEVELH];
|
|
int watertime;
|
|
|
|
double gunorigx[2];
|
|
double gunorigy[2];
|
|
int gundelay[2];
|
|
int guntime;
|
|
|
|
int cameraalpha;
|
|
|
|
int playedbell;
|
|
int clocktime;
|
|
int lamptime = -1;
|
|
|
|
int gameovertime;
|
|
|
|
int sprayalpha; // for spray effect
|
|
|
|
#ifdef OPENGL
|
|
SDL_Surface *realscreen;
|
|
|
|
extern GLuint tex;
|
|
extern float texw,texh;
|
|
extern GLint sampleBuffers, samples;
|
|
|
|
int rm = 0x000000ff;
|
|
int gm = 0x0000ff00;
|
|
int bm = 0x00ff0000;
|
|
int am = 0xff000000;
|
|
#endif
|
|
|
|
|
|
regrow_t regrow[MAXREGROW]; // for tile regrowth
|
|
int numregrow = 0;
|
|
|
|
int gameover;
|
|
int firstlevel;
|
|
|
|
SDL_Surface *pausedtext, *pausedshadow;
|
|
int paused;
|
|
|
|
int wantframerate = B_FALSE;
|
|
|
|
int initialswapplayers = B_FALSE;
|
|
|
|
int fps;
|
|
int fpscount;
|
|
|
|
int titlemode = TS_INSERTCOIN;
|
|
int blinkspeed;
|
|
int credits = 0;
|
|
int titledone;
|
|
|
|
int forcegold = B_FALSE;
|
|
int forcegoldlev = -1;
|
|
|
|
|
|
int skiplevels;
|
|
|
|
int force1up = B_FALSE;
|
|
int force2up = B_FALSE;
|
|
|
|
|
|
/* the order in which fruit will appear */
|
|
int fruittypes[] = {
|
|
P_CHEESE,
|
|
P_ICECREAM,
|
|
P_CHIPS,
|
|
P_BURGER,
|
|
P_PIZZA,
|
|
P_SUNDAE,
|
|
P_CAKE,
|
|
P_CHOCOLATE,
|
|
-1
|
|
};
|
|
|
|
|
|
/* the order in which powerups will appear */
|
|
int poweruptypes[] = {
|
|
P_NUMNETS,
|
|
P_BIGNET,
|
|
P_BELL,
|
|
P_NUMNETS,
|
|
P_GEMBOOST,
|
|
P_MASKPOWERUP,
|
|
P_HONEY,
|
|
P_NUMNETS,
|
|
P_GEMBOOST,
|
|
P_HELMET,
|
|
P_UMBRELLA,
|
|
P_WINGBOOTS,
|
|
-1
|
|
};
|
|
|
|
|
|
int fruittime = -1;
|
|
int curfruittype = 0;
|
|
int curpoweruptype[2];
|
|
|
|
int tilefadex[LEVELW*LEVELH];
|
|
int tilefadey[LEVELW*LEVELH];
|
|
int nfadingtiles = 0;
|
|
|
|
int gtime = 0;
|
|
int fpsticks = 0;
|
|
int fpsstart = 0;
|
|
|
|
int skipto = -1; // which level to skip to
|
|
level_t *curlevel;
|
|
int levelcompletetime;
|
|
int oldlevelcomplete;
|
|
|
|
sprite_t *sprite = NULL; /* main sprite list */
|
|
sprite_t *lastsprite;
|
|
|
|
sprite_t *lastmet;
|
|
|
|
|
|
int pokereffect;
|
|
int pokerpoints;
|
|
|
|
|
|
SDL_Color red = {255, 0, 0, 0};
|
|
SDL_Color red2 = {150, 0, 0, 0};
|
|
SDL_Color red3 = {90, 0, 0, 0};
|
|
SDL_Color orange = {255, 167, 88, 1};
|
|
SDL_Color black = {0, 0, 0, 0};
|
|
SDL_Color blue = {0, 0, 255, 0};
|
|
SDL_Color cyan = {0, 255, 255, 0};
|
|
SDL_Color purple = {200, 0, 200, 0};
|
|
SDL_Color brown = {166, 97, 7, 0};
|
|
SDL_Color brown2 = {116, 47, 0, 0};
|
|
SDL_Color white = {255, 255, 255, 0};
|
|
SDL_Color white2 = {150, 150, 150, 0};
|
|
SDL_Color grey = {210, 210, 210, 0};
|
|
SDL_Color grey2 = {90, 90, 90, 0};
|
|
SDL_Color green = {0, 255, 0, 0};
|
|
SDL_Color green1 = {0, 200, 0, 0};
|
|
SDL_Color green2 = {0, 150, 0, 0};
|
|
SDL_Color yellow = {255, 255, 0, 0};
|
|
SDL_Color greenish = {82, 125, 74, 0};
|
|
|
|
char *endtext[] = {
|
|
"As the chest opens, a great light bursts forth...",
|
|
"A feast of purloined food rains from the sky!",
|
|
"The dwarven couple eagerly gather the bounty",
|
|
"and return in triumph to their castle",
|
|
"where a grand banquet awaits.",
|
|
" ",
|
|
"CONGRATULATIONS!",
|
|
NULL
|
|
};
|
|
|
|
SDL_Color *endtextcol[] = {
|
|
&green1,
|
|
&green1,
|
|
&green1,
|
|
&green1,
|
|
&green1,
|
|
&green1,
|
|
&green,
|
|
NULL
|
|
};
|
|
|
|
int endtextid = 0;
|
|
int endtexttimer = 0;
|
|
int endtexty = 0;
|
|
|
|
int vidargs = 0;
|
|
|
|
int fullscreen = B_FALSE;
|
|
|
|
int timer = 0;
|
|
int toggletimer = 0;
|
|
|
|
int main (int argc, char **argv) {
|
|
//sprite_t *s,*nextsprite;
|
|
char filename[BUFLEN];
|
|
int i;
|
|
int *animtile,*l3tile;
|
|
|
|
levelbg = NULL;
|
|
|
|
datadir = NULL;
|
|
|
|
// default
|
|
sprintf(hiscoreserver, "ratcatcher.nethack.net");
|
|
hiscoreport = 80;
|
|
|
|
gamemode = GM_NORM; // default
|
|
showhelp = B_FALSE; // default
|
|
|
|
|
|
// set program name (including version string)
|
|
sprintf(progname, "Rat Catcher");
|
|
|
|
/* handle arguments */
|
|
if (argc >= 2) {
|
|
for (i = 1; i < argc; i++) {
|
|
if (!strcmp(argv[i], "-fs")) {
|
|
printf("Fullscreen mode enabled.\n");
|
|
fullscreen = B_TRUE;
|
|
} else if (!strcmp(argv[i], "-v")) {
|
|
printf("%s\n",progname);
|
|
exit(1);
|
|
} else if (!strcmp(argv[i], "-d")) {
|
|
if (++i >= argc) {
|
|
printf("Missing data dir.\n");
|
|
usage();
|
|
exit(1);
|
|
}
|
|
datadir = strdup(argv[i]);
|
|
} else if (!strcmp(argv[i], "-c")) {
|
|
printf("Cheat mode.\n");
|
|
cheat = B_TRUE;
|
|
} else if (!strcmp(argv[i], "-as")) {
|
|
printf("Automatic screenshot mode activated.\n");
|
|
autoshot = B_TRUE;
|
|
} else if (!strcmp(argv[i], "-s")) {
|
|
printf("Swapplayers mode activated.\n");
|
|
initialswapplayers = B_TRUE;
|
|
} else if (!strcmp(argv[i], "-t")) {
|
|
printf("Tutorial mode activated.\n");
|
|
showhelp = B_TRUE;
|
|
} else if (!strcmp(argv[i], "-l")) {
|
|
if (++i >= argc) {
|
|
printf("Missing level number.\n");
|
|
usage();
|
|
exit(1);
|
|
}
|
|
skipto = atoi(argv[i]);
|
|
printf("Skipping to level %d.\n",skipto);
|
|
} else if (!strcmp(argv[i], "-1")) {
|
|
printf("1up added.\n");
|
|
force1up = B_TRUE;
|
|
} else if (!strcmp(argv[i], "-2")) {
|
|
printf("2up added.\n");
|
|
force2up = B_TRUE;
|
|
} else if (!strcmp(argv[i], "-jt")) {
|
|
printf("Joystick test mode enabled.\n");
|
|
joytest = B_TRUE;
|
|
/*} else if (!strcmp(argv[i], "-hs")) {
|
|
if (++i >= argc) {
|
|
printf("Missing hiscore server name.\n");
|
|
usage();
|
|
exit(1);
|
|
}
|
|
if (strstr(argv[i], ":")) {
|
|
char *p,*p2;
|
|
// use port as well
|
|
p2 = hiscoreserver;
|
|
for (p = argv[i];p; p++) {
|
|
if (*p == ':') {
|
|
p++;
|
|
break;
|
|
} else {
|
|
*p2 = *p;
|
|
}
|
|
p2++;
|
|
}
|
|
*p2 = '\0';
|
|
hiscoreport = atoi(p);
|
|
printf("Hiscore server set to '%s'\n",hiscoreserver);
|
|
printf("Hiscore port set to '%d'\n",hiscoreport);
|
|
} else {
|
|
sprintf(hiscoreserver, "%s",argv[i]);
|
|
printf("Hiscore server set to '%s'\n",hiscoreserver);
|
|
}
|
|
} else if (!strcmp(argv[i], "-hp")) {
|
|
if (++i >= argc) {
|
|
printf("Missing hiscore port.\n");
|
|
usage();
|
|
exit(1);
|
|
}
|
|
hiscoreport = atoi(argv[i]);
|
|
printf("Hiscore port set to '%d'\n",hiscoreport);
|
|
*/
|
|
} else {
|
|
usage();
|
|
exit(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (datadir == NULL) {
|
|
datadir = strdup("data");
|
|
}
|
|
|
|
initsdl();
|
|
|
|
if (TTF_Init()) {
|
|
printf("TTF_Init: %s\n", TTF_GetError());
|
|
}
|
|
|
|
atexit(cleanup);
|
|
|
|
if (joytest) {
|
|
if (havejoysticks) {
|
|
int done = B_FALSE;
|
|
SDL_Event event;
|
|
printf("Joystick test mode\n");
|
|
printf("------------------\n\n");
|
|
while (!done) {
|
|
/* check for key releases */
|
|
SDL_PumpEvents();
|
|
while (SDL_PollEvent(&event)) {
|
|
if (event.type == SDL_KEYDOWN) {
|
|
if (event.key.keysym.sym == SDLK_ESCAPE) {
|
|
done = B_TRUE;
|
|
}
|
|
} else if (event.type == SDL_JOYBUTTONUP) {
|
|
printf("Joy %d: Button %d pressed.\n",event.jbutton.which, event.jbutton.button);
|
|
} else if (event.type == SDL_JOYAXISMOTION) {
|
|
int j,jx,jy;
|
|
j = event.jaxis.which;
|
|
jx = SDL_JoystickGetAxis(joy[j],0);
|
|
jy = SDL_JoystickGetAxis(joy[j],1);
|
|
printf("Joy %d: Moved ",j);
|
|
if (jy <= -6000) printf("UP\n");
|
|
if (jy >= 6000) printf("DOWN\n");
|
|
if (jx <= -6000) printf("LEFT\n");
|
|
if (jx >= 6000) printf("RIGHT\n");
|
|
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
printf("ERROR: no joysticks found.\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
if (loadimagesets()) {
|
|
printf("Error loading images.\n");
|
|
return 1;
|
|
}
|
|
|
|
if (loadlevellist()) {
|
|
printf("Error loading level list from %s.\n",FILE_LEVELMAP);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*
|
|
fakeblock.id = T_LAND;
|
|
strcpy(fakeblock.name,"Fake");
|
|
for (i = 0; i < TILEW; i++) {
|
|
fakeblock.lowness[i] = 0;
|
|
}
|
|
fakeblock.solid = S_SOLID;
|
|
fakeblock.img[0] = IMG_Load("newtiles/land.png");
|
|
fakeblock.numframes = 1;
|
|
fakeblock.next = NULL;
|
|
fakeblock.prev = NULL;
|
|
*/
|
|
|
|
|
|
/* load fonts */
|
|
sprintf(filename, "%s/gamefont.ttf",datadir);
|
|
for (i = 1; i < MAXLETTERHEIGHT; i++) {
|
|
SDL_Surface *surf;
|
|
font[i] = TTF_OpenFont(filename,i);
|
|
if (!font[i]) {
|
|
printf("Error opening font: %s\n", TTF_GetError());
|
|
return 1;
|
|
}
|
|
surf = TTF_RenderText_Solid(font[i], "test", red);
|
|
if (!surf) {
|
|
printf("Error during font test, size %d\n",i);
|
|
return 1;
|
|
}
|
|
SDL_FreeSurface(surf);
|
|
}
|
|
|
|
/* calculate fps delay */
|
|
SDL_initFramerate(&manager);
|
|
SDL_setFramerate(&manager, WANTFPS);
|
|
|
|
|
|
|
|
/* init sound */
|
|
if (initsound()) {
|
|
printf("sound error.\n");
|
|
return 1;
|
|
}
|
|
|
|
/* init tiles */
|
|
if (loadtiletypes(FILE_TILEDEFS)) {
|
|
printf("Cannot initialise tiles\n");
|
|
exit(1);
|
|
}
|
|
|
|
|
|
/* generate images for "PAUSED" text */
|
|
pausedtext = TTF_RenderText_Solid(font[TEXTSIZE_PAUSED], "PAUSED", yellow);
|
|
pausedshadow = TTF_RenderText_Solid(font[TEXTSIZE_PAUSED], "PAUSED", black);
|
|
paused = B_FALSE;
|
|
|
|
temptilesurf = SDL_CreateRGBSurface(SDL_SWSURFACE, TILEW, TILEH,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask, 0);
|
|
SDL_FillRect(temptilesurf, NULL, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
SDL_SetAlpha(temptilesurf, SDL_SRCALPHA, 25);
|
|
|
|
|
|
endgamebox = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
screen->w,
|
|
screen->h,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask, 0);
|
|
SDL_FillRect(endgamebox, NULL, SDL_MapRGB(screen->format,white.r,white.g,white.b));
|
|
|
|
// try to get hiscores
|
|
//printf("Attepting to download hiscores from %s:%d...\n",hiscoreserver,hiscoreport); fflush(stdout);
|
|
printf("Loading hiscore data...\n");
|
|
if (gethiscores(B_FALSE)) {
|
|
printf("Couldn't download hiscores. Disabling hiscore code.\n");
|
|
wanthiscores = B_FALSE;
|
|
} else {
|
|
printf("Hiscores successfully downloaded.\n");
|
|
wanthiscores = B_TRUE;
|
|
}
|
|
|
|
player = NULL;
|
|
player2 = NULL;
|
|
|
|
// outside loop
|
|
while (1) {
|
|
// title screen
|
|
if (skipto <= 0) {
|
|
dotitlescreen();
|
|
srand(time(NULL));
|
|
} else {
|
|
// skipping to a level from command line
|
|
if (force1up) want1up = B_TRUE;
|
|
if (force2up) want2up = B_TRUE;
|
|
if (!want1up && !want2up) {
|
|
// must have at least 1 player!!
|
|
want1up = B_TRUE;
|
|
}
|
|
}
|
|
|
|
// shuffle cards
|
|
shufflecards();
|
|
|
|
startgame();
|
|
|
|
// main loop
|
|
while (!gameover) {
|
|
removeall();
|
|
|
|
// check for sprite death and update moevment counters
|
|
checksprites();
|
|
|
|
/**********************************************
|
|
* check for end of level
|
|
*/
|
|
if (levelcomplete == LV_CLEAR) {
|
|
sprite_t *s2, *nexts;
|
|
if (!endgame) {
|
|
addoutlinetext(320,240,TEXTSIZE_LEVEL,"Level Complete!",&green,&black,LEVELWINDELAY, TT_NORM);
|
|
playfx(FX_WINLEVEL);
|
|
}
|
|
levelcomplete = LV_WAIT;
|
|
// turn off certain powerups
|
|
if (globpowerup == PW_CLOCK) {
|
|
Mix_ResumeMusic();
|
|
globpowerup = -1;
|
|
} else if (globpowerup == PW_LAMP) {
|
|
Mix_ResumeMusic();
|
|
globpowerup = -1;
|
|
} else if ((curlevel->iced == WATER_INPROGRESS) || (curlevel->iced == WATER_COMPLETE)) {
|
|
curlevel->iced = B_FALSE;
|
|
undoflood();
|
|
} else if (haspowerupany(PW_GUNNER)) {
|
|
disablepowerups(PW_GUNNER);
|
|
}
|
|
|
|
// certain things disappear at end of level
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (iscard(s2->id) || s2->id == P_MOVINGCARD) {
|
|
// kill all cards, so we don't have a pokereffect during endoflevel
|
|
s2->dead = D_FINAL;
|
|
} else if (strstr(s2->name, "random_up")) {
|
|
// also kill the random level powerup if it exists
|
|
s2->dead = D_FINAL;
|
|
puffin(-1, s2->x, s2->y, "end_of_lev_pw_die", 0);
|
|
} else if (isflower(s2->id)) {
|
|
// also kill flowers
|
|
s2->dead = D_FINAL;
|
|
puffin(-1, s2->x, s2->y, "end_of_lev_fl_die", 0);
|
|
}
|
|
}
|
|
|
|
// stop teleporting
|
|
if (player) {
|
|
if (player->teleporting) {
|
|
stopteleporting(player);
|
|
}
|
|
}
|
|
if (player2) {
|
|
if (player2->teleporting) {
|
|
stopteleporting(player2);
|
|
}
|
|
}
|
|
} else if (levelcomplete == LV_WAIT) {
|
|
int mcount = 0;
|
|
sprite_t *s2;
|
|
|
|
/* when all monsters have become fruits */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (ismonster(s2->id)) {
|
|
if (s2->id != P_BLACKCLOUD) {
|
|
mcount++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (mcount == 0) {
|
|
levelcompletetime = gtime;
|
|
levelcomplete = LV_FINAL;
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************
|
|
* check for keypress or other input (joystick etc)
|
|
*/
|
|
handleinput();
|
|
|
|
if (!paused) {
|
|
/**********************************************
|
|
* Special effects #1 - ones which change the level by
|
|
* modifiying tiles, etc, or by moving sprites.
|
|
*/
|
|
if (globpowerup != PW_CLOCK) {
|
|
// for each animated tile on the level...
|
|
for (animtile = curlevel->animtiles; animtile && *animtile != -1; animtile++) {
|
|
int offset,numframes;
|
|
tiletype_t *tt;
|
|
|
|
offset = *animtile;
|
|
|
|
// Is l2 tile animated?
|
|
tt = gettile(curlevel->map2[offset]);
|
|
if (tt->numframes == 1) { // if no l2, use l1
|
|
tt = gettile(curlevel->map[offset]);
|
|
}
|
|
|
|
numframes = tt->numframes;
|
|
|
|
// is it time to change frames?
|
|
if ((timer % tt->animspeed) == 0) {
|
|
// change its frame
|
|
curlevel->tileframe[offset]++;
|
|
if (curlevel->tileframe[offset] >= numframes) {
|
|
curlevel->tileframe[offset] = 0;
|
|
}
|
|
// redraw it
|
|
drawtile(temps, offset%LEVELW,offset/LEVELW);
|
|
}
|
|
|
|
}
|
|
|
|
// ice effect
|
|
if (curlevel->iced == ICE_INPROGRESS) {
|
|
doice();
|
|
}
|
|
|
|
// water effect
|
|
if (timer % FLOODSPEED == 0) {
|
|
if (curlevel->iced == WATER_INPROGRESS) {
|
|
doflood();
|
|
}
|
|
}
|
|
}
|
|
// gunner effect - red overlay
|
|
if (haspowerupany(PW_GUNNER)) {
|
|
if (levelcomplete != LV_DOPOKER) {
|
|
SDL_BlitSurface(redbox,NULL,screen,NULL);
|
|
}
|
|
if (uncaughtmonsters() <= 0) {
|
|
// finish if no monsters are left alive & uncaught
|
|
disablepowerups(PW_GUNNER);
|
|
}
|
|
}
|
|
|
|
/**********************************************
|
|
* Move sprites
|
|
*/
|
|
if (levelcomplete == LV_DOPOKER) {
|
|
// only fivecards sprite can move
|
|
sprite_t *this;
|
|
for (this = sprite; this ; this = this->next) {
|
|
if (this->id == P_FIVECARDS) {
|
|
movesprite(this);
|
|
}
|
|
}
|
|
} else { // all other states...
|
|
if (levelcomplete != LV_HELPFREEZE) {
|
|
// move sprites
|
|
moveallsprites();
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************
|
|
* Intro sequence
|
|
*/
|
|
if (inintro()) {
|
|
dointroseq();
|
|
}
|
|
|
|
/**********************************************
|
|
* Move onscreen text
|
|
*/
|
|
if (levelcomplete != LV_HELPFREEZE) {
|
|
movetext();
|
|
}
|
|
|
|
|
|
/**********************************************
|
|
* Gravity
|
|
*/
|
|
if (levelcomplete == LV_INIT) {
|
|
// only player
|
|
dogravity(player);
|
|
checkwrap(player);
|
|
dotileeffects(player);
|
|
if (player2) {
|
|
dogravity(player2);
|
|
checkwrap(player2);
|
|
dotileeffects(player2);
|
|
}
|
|
} else {
|
|
sprite_t *s;
|
|
switch (levelcomplete) {
|
|
case LV_INPROGRESS:
|
|
case LV_CLEAR:
|
|
case LV_WAIT:
|
|
case LV_FINAL:
|
|
case LV_CLOUD:
|
|
/* gravity */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
dogravity(s);
|
|
checkwrap(s);
|
|
}
|
|
|
|
/* tile effects */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
|
|
if (levelcomplete == LV_CLOUD) {
|
|
if (isplayer(s)) {
|
|
if (!s->oncloud) dotileeffects(s);
|
|
} else {
|
|
dotileeffects(s);
|
|
}
|
|
} else {
|
|
dotileeffects(s);
|
|
}
|
|
}
|
|
break;
|
|
case LV_GAMEOVER: // no collision detection or player movement
|
|
/* gravity */
|
|
for (s = sprite; s ; s = s->next) {
|
|
if (!isplayer(s)) {
|
|
dogravity(s);
|
|
checkwrap(s);
|
|
}
|
|
}
|
|
break;
|
|
case LV_DOPOKER: // do nothing
|
|
case LV_HELPFREEZE: // do nothing
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**********************************************
|
|
* Special effects #2 - ones which need to happen
|
|
* after sprite movement
|
|
*/
|
|
if ((player && player->hasbell) || (player2 && player2->hasbell)) {
|
|
int dobell = B_FALSE;
|
|
SDL_Color fcol;
|
|
/* check for bell sound */
|
|
|
|
/* play a bell sound if the powerup will be a permenant one */
|
|
if (ispermenant(level->poweruptype)) {
|
|
// flash white
|
|
dobell = B_TRUE;
|
|
fcol.r = 255; fcol.g = 255; ; fcol.b = 255;
|
|
} else if (isabilitypowerup(level->poweruptype)) {
|
|
// flash green
|
|
dobell = B_TRUE;
|
|
fcol.r = 0; fcol.g = 255; ; fcol.b = 0;
|
|
} else if (iswinpowerup(level->poweruptype)) {
|
|
// flash red
|
|
dobell = B_TRUE;
|
|
fcol.r = 255; fcol.g = 0; ; fcol.b = 0;
|
|
} else if (isbadpowerup(level->poweruptype)) {
|
|
// flash purple
|
|
dobell = B_TRUE;
|
|
fcol.r = 255; fcol.g = 0; ; fcol.b = 255;
|
|
}
|
|
|
|
if (dobell) {
|
|
// play sound once
|
|
if (!playedbell) {
|
|
playfx(FX_BELL);
|
|
playedbell = BELL_DONESOUND;
|
|
}
|
|
if (playedbell != BELL_DONEFLASH) {
|
|
if (timer >= BELLTIME) {
|
|
playedbell = BELL_DONEFLASH;
|
|
} else if (timer % 10 == 0) {
|
|
SDL_Rect area;
|
|
area.x = 0;
|
|
area.y = 0;
|
|
area.w = SCREENW;
|
|
area.h = SCREENH;
|
|
SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,fcol.r,fcol.g,fcol.b));
|
|
flip(B_TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// melting/fading tiles
|
|
for (i = nfadingtiles-1; i >= 0; i--) {
|
|
int tx,ty;
|
|
|
|
tx = tilefadex[i];
|
|
ty = tilefadey[i];
|
|
if (--(curlevel->tilewalkvanish[ty*LEVELW+tx]) <= 0) {
|
|
int n;
|
|
melttile(tx,ty,REGROWTIMER_SHORT, B_NOPUFF);
|
|
// remove from list.
|
|
for (n = i; n < nfadingtiles-1; n++) {
|
|
tilefadex[n] = tilefadex[n+1];
|
|
tilefadey[n] = tilefadey[n+1];
|
|
}
|
|
nfadingtiles--;
|
|
} else if (curlevel->tilewalkvanish[ty*LEVELW+tx] >= 20) { // maybe drip if not too faded
|
|
//printf("curmelt ---- %d\n",curlevel->tilewalkvanish[ty*LEVELW+tx]);
|
|
if ((timer % 10 == 0) && !(rand() % 3)) {
|
|
sprite_t *s;
|
|
// add drip
|
|
s = addsprite(P_DRIP, tx*TILEW + (TILEW/4) + (rand() % (TILEW/2)), (ty*TILEH) + TILEH, "drip");
|
|
s->fallspeed = ICEDRIPSPEED;
|
|
}
|
|
}
|
|
// now re-draw it to change transparency
|
|
drawtile(temps, tx, ty);
|
|
}
|
|
|
|
// endgame flash
|
|
if (globpowerup == PW_ENDGAME) {
|
|
int val;
|
|
SDL_Rect area;
|
|
area.x = 0;
|
|
area.y = 0;
|
|
area.w = SCREENW;
|
|
area.h = SCREENH;
|
|
|
|
// screen fades from white to black
|
|
val = 255 - globtimer;
|
|
if (val < 0) val = 0;
|
|
|
|
SDL_FillRect(screen, &area, SDL_MapRGB(screen->format, val, val, val));
|
|
}
|
|
|
|
// camera flash
|
|
if ((globpowerup == PW_CAMERA) && (cameraalpha)) {
|
|
|
|
SDL_Surface *whitebox;
|
|
|
|
whitebox = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
screen->w,
|
|
screen->h,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask, 0);
|
|
SDL_FillRect(whitebox, NULL, SDL_MapRGB(screen->format,255,255,255));
|
|
SDL_SetAlpha(whitebox, SDL_SRCALPHA, cameraalpha);
|
|
|
|
// clear screen
|
|
SDL_BlitSurface(whitebox,NULL,screen,NULL);
|
|
SDL_FreeSurface(whitebox);
|
|
if (timer % 10 == 0) {
|
|
cameraalpha -= 35;
|
|
if (cameraalpha < 0) cameraalpha = 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************
|
|
* Collision detection
|
|
*/
|
|
if ((levelcomplete != LV_DOPOKER) && (levelcomplete != LV_HELPFREEZE)) {
|
|
checkcollideall();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**********************************************
|
|
* Drawing routines
|
|
*/
|
|
|
|
// player netting
|
|
if (levelcomplete != LV_DOPOKER) {
|
|
drawnetting(player);
|
|
drawnetting(player2);
|
|
}
|
|
|
|
// cannon firing
|
|
if ((levelcomplete != LV_DOPOKER) && (levelcomplete != LV_HELPFREEZE)) { // cannon firing
|
|
if (haspowerup(player, PW_CANNONFIRE)) {
|
|
docannoneffect(player);
|
|
}
|
|
if (haspowerup(player2, PW_CANNONFIRE)) {
|
|
docannoneffect(player2);
|
|
}
|
|
}
|
|
|
|
|
|
// draw sprites
|
|
if (levelcomplete != LV_DOPOKER) {
|
|
drawallsprites();
|
|
}
|
|
|
|
/// draw layer 3 tiles
|
|
// for each layer 3 tile on the level...
|
|
for (l3tile = curlevel->l3tiles; l3tile && *l3tile != -1; l3tile++) {
|
|
int offset;
|
|
tiletype_t *tt;
|
|
|
|
offset = *l3tile;
|
|
|
|
tt = gettile(curlevel->map3[offset]);
|
|
|
|
// redraw it
|
|
drawl3tile(screen, offset%LEVELW,offset/LEVELW);
|
|
|
|
}
|
|
|
|
|
|
// warning for cloud
|
|
if (!isbosslevel(curlevelnum)) {
|
|
if ((gtime >= nexthurryup + 10) && (gtime < nexthurryup+15)) { // 15 secs after hurryup
|
|
if (levelcomplete == LV_INPROGRESS) {
|
|
if (timer % 4 == 0) {
|
|
// add puffs
|
|
puffin(-1, 320 + (rand() % (TILEW*4)) - (TILEW*2),
|
|
240 + (rand() % (TILEH*2)) - TILEH, "cloudwarn", rand() % 5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// poker effect
|
|
// this must come last as it clears the screen and blanks out other sprites
|
|
if (levelcomplete == LV_DOPOKER) {
|
|
SDL_Rect area;
|
|
sprite_t *this;
|
|
|
|
area.x = 0;
|
|
area.y = 0;
|
|
area.w = SCREENW;
|
|
area.h = SCREENH;
|
|
// clear screen
|
|
SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
|
|
// only fivecards sprite is drawn
|
|
for (this = sprite; this ; this = this->next) {
|
|
if (this->id == P_FIVECARDS) {
|
|
drawsprite(this);
|
|
}
|
|
}
|
|
} else if (levelcomplete == LV_HELPFREEZE) {
|
|
SDL_Rect area;
|
|
SDL_Surface *blackbox;
|
|
blackbox = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
screen->w,
|
|
screen->h,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask, 0);
|
|
SDL_FillRect(blackbox, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
SDL_SetAlpha(blackbox, SDL_SRCALPHA, 175);
|
|
|
|
// clear screen
|
|
SDL_BlitSurface(blackbox,NULL,screen,NULL);
|
|
SDL_FreeSurface(blackbox);
|
|
|
|
}
|
|
|
|
// draw text
|
|
drawtext();
|
|
|
|
if (!inintro()) {
|
|
// draw score
|
|
drawscore();
|
|
}
|
|
|
|
// draw boss health
|
|
if (boss) {
|
|
drawbosshealth();
|
|
}
|
|
|
|
|
|
// draw 'PAUSED' text
|
|
if (paused) {
|
|
SDL_Rect area;
|
|
// show that we are paused
|
|
area.x = (SCREENW/2) - (pausedshadow->w/2) - 2;
|
|
area.y = (SCREENH/2) - (pausedshadow->h/2) + 2;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(pausedshadow, NULL, screen, &area);
|
|
area.x = (SCREENW/2) - (pausedtext->w/2);
|
|
area.y = (SCREENH/2) - (pausedtext->h/2);
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(pausedtext, NULL, screen, &area);
|
|
}
|
|
|
|
/**********************************************
|
|
* Special effects #3 - ones which need to happen
|
|
* after graphics drawing
|
|
*/
|
|
if (!paused) {
|
|
/* is screen shaking? */
|
|
if (globpowerup == PW_BOMB) {
|
|
if (timer % 5 == 0) {
|
|
int amt;
|
|
SDL_Rect area;
|
|
amt = (rand() % 20)+1;
|
|
area.x = 0;
|
|
area.y = amt;
|
|
area.w = SCREENW;
|
|
area.h = SCREENH-amt;
|
|
|
|
SDL_BlitSurface(screen, &area, screen, NULL);
|
|
|
|
area.x = 0;
|
|
area.y = SCREENH-amt;
|
|
area.w = SCREENW;
|
|
area.h = amt;
|
|
SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
}
|
|
|
|
if (--globtimer == 0) {
|
|
globpowerup = -1;
|
|
}
|
|
} else if (globpowerup == PW_SPRAYUP) { // green overlay for fly spray
|
|
if (levelcomplete != LV_DOPOKER) {
|
|
SDL_SetAlpha(greenbox, SDL_SRCALPHA, sprayalpha);
|
|
sprayalpha += 5;
|
|
if (sprayalpha >= 100) {
|
|
globpowerup = PW_SPRAYDOWN;
|
|
}
|
|
SDL_BlitSurface(greenbox,NULL,screen,NULL);
|
|
}
|
|
} else if (globpowerup == PW_SPRAYDOWN) { // green overlay for fly spray
|
|
if (levelcomplete != LV_DOPOKER) {
|
|
SDL_SetAlpha(greenbox, SDL_SRCALPHA, sprayalpha);
|
|
sprayalpha -= 5;
|
|
if (sprayalpha <= 0) {
|
|
globpowerup = PW_SPRAYUP;
|
|
}
|
|
SDL_BlitSurface(greenbox,NULL,screen,NULL);
|
|
}
|
|
} else if (globpowerup == PW_RATSHAKE) { // horizontal shake due to rat
|
|
// shake screen
|
|
if (timer % 5 == 0) {
|
|
int amt;
|
|
SDL_Rect area;
|
|
amt = (rand() % 20)+1;
|
|
area.x = amt;
|
|
area.y = 0;
|
|
area.w = SCREENW-amt;
|
|
area.h = SCREENH;
|
|
|
|
SDL_BlitSurface(screen, &area, screen, NULL);
|
|
|
|
area.x = SCREENW-amt;
|
|
area.y = 0;
|
|
area.w = amt;
|
|
area.h = SCREENH;
|
|
SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
}
|
|
|
|
|
|
// create rat
|
|
if (timer % 10 == 0) {
|
|
if (countmonsters(-1) < 8) { // max 7 rats + king rat
|
|
puffin(P_RAT, rand() % (SCREENW-(TILEW*8))+(TILEW*4), TILEH, "gen_rat",0);
|
|
}
|
|
}
|
|
|
|
|
|
if (--globtimer == 0) {
|
|
globpowerup = -1;
|
|
}
|
|
} else if (globpowerup == PW_SNAILSHAKE) { // vertical shake due to king snail
|
|
// shake screen
|
|
if (timer % 5 == 0) {
|
|
int amt;
|
|
SDL_Rect area;
|
|
|
|
amt = (rand() % 20)+1;
|
|
|
|
// offset screen upwards
|
|
area.x = 0;
|
|
area.y = amt;
|
|
area.w = SCREENW;
|
|
area.h = SCREENH-amt;
|
|
SDL_BlitSurface(screen, &area, screen, NULL);
|
|
|
|
// fill in empty bit
|
|
area.x = 0;
|
|
area.y = SCREENH-amt;
|
|
area.w = SCREENW;
|
|
area.h = amt;
|
|
SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
}
|
|
|
|
if (--globtimer == 0) {
|
|
globpowerup = -1;
|
|
}
|
|
} else if (globpowerup == PW_CATWIND) {
|
|
if (boss) {
|
|
// move players
|
|
if (player) {
|
|
movex(player, (double)boss->dir*1.5, B_FALSE);
|
|
}
|
|
if (player2) {
|
|
movex(player2, (double)boss->dir*1.5, B_FALSE);
|
|
}
|
|
if (countsprites(P_LEAF) < 10) {
|
|
int xx,yy,xs;
|
|
sprite_t *ss;
|
|
// add a leaf
|
|
if (boss->dir > 0) {
|
|
xx = TILEW/2;
|
|
xs = 10 + (rand() % 7);
|
|
} else {
|
|
xx = (LEVELW * TILEW) + (TILEW/2);
|
|
xs = -(10 + (rand() % 7));
|
|
}
|
|
yy = rand() % (LEVELH * TILEH);
|
|
|
|
ss = addsprite(P_LEAF,xx, yy, "leaf" );
|
|
ss->ys = 0;
|
|
ss->xs = xs;
|
|
ss->dir = boss->dir;
|
|
}
|
|
} else {
|
|
globpowerup = -1;
|
|
}
|
|
} else if (globpowerup == PW_CATBRICKS) {
|
|
if (boss) {
|
|
// shake screen
|
|
if (timer % 5 == 0) {
|
|
int amt;
|
|
SDL_Rect area;
|
|
|
|
amt = (rand() % 20)+1;
|
|
|
|
// offset screen upwards
|
|
area.x = 0;
|
|
area.y = amt;
|
|
area.w = SCREENW;
|
|
area.h = SCREENH-amt;
|
|
SDL_BlitSurface(screen, &area, screen, NULL);
|
|
|
|
// fill in empty bit
|
|
area.x = 0;
|
|
area.y = SCREENH-amt;
|
|
area.w = SCREENW;
|
|
area.h = amt;
|
|
SDL_FillRect(screen, &area, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
}
|
|
// drop bricks
|
|
if ((timer % KC_BRICKTIME) == 0) {
|
|
int i,tx,poss[LEVELW],nposs = 0;
|
|
tiletype_t *tt;
|
|
printf("timer = %d\n",timer);
|
|
// select a random top tile
|
|
for (i = 0; i < LEVELW; i++) {
|
|
tt = gettileat(i*TILEW,0, NULL, NULL);
|
|
if (tt && tt->solid) {
|
|
poss[nposs++] = i;
|
|
}
|
|
}
|
|
if (nposs) {
|
|
sprite_t *ss;
|
|
tx = poss[rand() % nposs];
|
|
// destroy the tile
|
|
melttile(tx,0,REGROWTIMER_SHORT, B_PUFF);
|
|
// add a falling brick
|
|
ss = addsprite(P_FALLINGBRICK,
|
|
(tx*TILEW) + (TILEW/2), TILEH,"fallingbrick");
|
|
ss->ys = 1;
|
|
ss->xs = 0;
|
|
ss->dir = 1; // doesn't really matter
|
|
} else {
|
|
globpowerup = -1;
|
|
}
|
|
}
|
|
} else {
|
|
globpowerup = -1;
|
|
}
|
|
} else if (globpowerup == PW_ENDGAME) {
|
|
// timer will control background fade
|
|
if (globtimer < 1024) {
|
|
globtimer++;
|
|
}
|
|
|
|
if (countfruits() < 10) {
|
|
sprite_t *ss;
|
|
int x,y;
|
|
// spawn a new fruit
|
|
x = (rand() % (SCREENW-(TILEW*2))) + TILEW;
|
|
y = 0;
|
|
ss = addsprite(fruittypes[curfruittype], x,y, "fruit_endgame");
|
|
incfruittype();
|
|
ss->xs = 0;
|
|
ss->ys = rand() % 2;
|
|
}
|
|
if (countsprites(P_UPSTAR) < MINUPSTARS) {
|
|
addupstar();
|
|
}
|
|
|
|
if (endgame == EG_FADETOBLACK) {
|
|
int val;
|
|
|
|
// screen fades out to black
|
|
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, black.r, black.g, black.b));
|
|
|
|
val = 255 - globtimer;
|
|
if (val < 0) val = 0;
|
|
|
|
|
|
SDL_SetAlpha(endgamebox, SDL_SRCALPHA, val);
|
|
SDL_BlitSurface(endgamebox,NULL,screen,NULL);
|
|
if (val <= 0) {
|
|
// really finished now - back to title screen
|
|
gameover = B_TRUE;
|
|
}
|
|
} else if (endgame == EG_FADETOWHITE) {
|
|
int val;
|
|
// screen fades out to white
|
|
val = globtimer;
|
|
if (val > 255) val = 255;
|
|
|
|
SDL_SetAlpha(endgamebox, SDL_SRCALPHA, val);
|
|
SDL_BlitSurface(endgamebox,NULL,screen,NULL);
|
|
if (val >= 255) {
|
|
endgame = EG_FADETOBLACK;
|
|
globtimer = 0;
|
|
}
|
|
} else if (endgame == EG_FRUITFALL) {
|
|
if (++endtexttimer >= ENDTEXTTIME) {
|
|
endtexttimer = 0;
|
|
|
|
// display next ending text
|
|
if (endtext[endtextid]) {
|
|
addoutlinetext(320,endtexty,TEXTSIZE_ENDING, endtext[endtextid],
|
|
endtextcol[endtextid],&black,FOREVER,TT_ENDING);
|
|
endtextid++;
|
|
|
|
endtexty += TTF_FontHeight(font[TEXTSIZE_ENDING]);
|
|
endtexty += 2;
|
|
} else {
|
|
// trigger very end of game
|
|
levelcomplete = LV_FINAL;
|
|
levelcompletetime = gtime;
|
|
endgame = EG_FADEPAUSE;
|
|
//gtime += 10;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**********************************************
|
|
* Update the screen
|
|
*/
|
|
flip(B_TRUE);
|
|
|
|
|
|
/**********************************************
|
|
* Timers
|
|
*/
|
|
if (!paused) {
|
|
int n;
|
|
if (++timer == 100) timer = 0;
|
|
|
|
for (n = 0 ; n < numregrow; n++) {
|
|
regrow[n].timer--;
|
|
if (regrow[n].timer <= 0) {
|
|
int nn,tx,ty;
|
|
// put original tile back
|
|
tx = regrow[n].tx;
|
|
ty = regrow[n].ty;
|
|
curlevel->map[ty * LEVELW + tx] = regrow[n].origid;
|
|
curlevel->tilewalkvanish[ty * LEVELW + tx] = getwalkvanish(regrow[n].origid);
|
|
|
|
drawtile(temps, tx,ty);
|
|
puffin(-1, tx*TILEW+(TILEW/2), ty*TILEH+TILEH, "nothing", 0);
|
|
|
|
// remove from list
|
|
for (nn = n ; nn < (numregrow-1); nn++) {
|
|
regrow[nn].tx = regrow[nn+1].tx;
|
|
regrow[nn].ty = regrow[nn+1].ty;
|
|
regrow[nn].origid = regrow[nn+1].origid;
|
|
regrow[nn].timer = regrow[nn+1].timer;
|
|
}
|
|
numregrow--;
|
|
// do this number again
|
|
n--;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (toggletimer > 0) toggletimer--;
|
|
|
|
if (haspowerupany(PW_GUNNER)) {
|
|
int n;
|
|
// delay between shots
|
|
for (n = 0; n < 2; n++) {
|
|
if (gundelay[n] > 0) {
|
|
gundelay[n]--;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// screenshot
|
|
if (autoshot && (levelcomplete == LV_INPROGRESS)) {
|
|
if (shottaken) {
|
|
sprite_t *s2, *nexts;
|
|
// go to next level
|
|
// kill all enemies and fruits
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id) || ismonster(s2->id) || isfruit(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
if (ismonster(s2->id)) {
|
|
if (s2->caughtby) {
|
|
uncatch(s2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// call in cloud immediately
|
|
levelcomplete = LV_FINAL;
|
|
} else {
|
|
savebmp(screen);
|
|
shottaken = B_TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
fpscount++;
|
|
tick();
|
|
} // end main loop
|
|
|
|
// turn off level skip now, if it was selected at commandline
|
|
skipto = -1;
|
|
|
|
// clear screen
|
|
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
|
|
stopmusic();
|
|
|
|
if (wanthiscores) {
|
|
// check for a hiscore, if so submit it
|
|
if (player) checkhiscores(player);
|
|
if (player2) checkhiscores(player2);
|
|
|
|
// clear screen
|
|
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
|
|
// show high scores
|
|
showhiscores();
|
|
|
|
// clear screen ready to start again...
|
|
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
}
|
|
} // end outside loop
|
|
|
|
return 0;
|
|
}
|
|
|
|
void tick(void) {
|
|
sprite_t *s;
|
|
|
|
if (!paused) {
|
|
SDL_framerateDelay(&manager);
|
|
}
|
|
|
|
if (paused) return;
|
|
if (levelcomplete == LV_HELPFREEZE) return;
|
|
|
|
|
|
fpsticks = SDL_GetTicks();
|
|
if (fpsstart == 0) {
|
|
fpsstart = fpsticks;
|
|
} else {
|
|
/* once per second */
|
|
if (fpsticks - fpsstart >= 1000) {
|
|
// calculate frames per second
|
|
fps = fpscount;
|
|
fpscount = 0;
|
|
|
|
// incremenet game time
|
|
gtime++;
|
|
|
|
// check for game over - 5 seocnds after game over text disappears
|
|
if (gameovertime > 0) {
|
|
if (gtime >= (gameovertime + GAMEOVERWAIT)) {
|
|
gameover = B_TRUE;
|
|
}
|
|
}
|
|
|
|
// handle visual countdown timers
|
|
if (levelcomplete == LV_INPROGRESS) {
|
|
// clock
|
|
if (globpowerup == PW_CLOCK) {
|
|
char tempm[SMALLBUFLEN];
|
|
// text
|
|
if (clocktime > 0) {
|
|
sprintf(tempm, "%d",clocktime);
|
|
addoutlinetext(320,120,TEXTSIZE_LEVEL, tempm, &yellow,&black,15, TT_NORM);
|
|
// sound effect
|
|
playfx(FX_CLOCK);
|
|
}
|
|
// never reach hurryup time
|
|
nexthurryup++;
|
|
// decrement counter
|
|
clocktime--;
|
|
if (clocktime < 0) {
|
|
// finished!
|
|
Mix_ResumeMusic();
|
|
globpowerup = -1;
|
|
}
|
|
} else if (globpowerup == PW_LAMP) {
|
|
int maxdoom = -1;
|
|
sprite_t *s2;
|
|
// never reach hurryup time
|
|
nexthurryup++;
|
|
//////// display countdown
|
|
// find goldcoin with highest doomcount
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if ((s2->id == P_GOLDCOIN) && (s2->doomcount > maxdoom)) {
|
|
maxdoom = s2->doomcount;
|
|
}
|
|
}
|
|
if (maxdoom > -1) {
|
|
int secondsleft;
|
|
secondsleft = (maxdoom / fps);
|
|
if (secondsleft != lamptime) {
|
|
SDL_Color *col;
|
|
lamptime = secondsleft;
|
|
sprintf(tempm, "%d",lamptime);
|
|
if (lamptime < 5) {
|
|
col = &red;
|
|
} else if (lamptime < 15) {
|
|
col = &yellow;
|
|
} else {
|
|
col = &green;
|
|
}
|
|
addoutlinetext(320,120,TEXTSIZE_LEVEL, tempm, col,&black,15, TT_NORM);
|
|
}
|
|
}
|
|
}
|
|
|
|
// handle flood effect
|
|
if (curlevel->iced == WATER_COMPLETE) {
|
|
char tempm[SMALLBUFLEN];
|
|
// text
|
|
if (watertime > 0) {
|
|
sprintf(tempm, "%d",watertime);
|
|
addoutlinetext(320,120,TEXTSIZE_LEVEL, tempm, &cyan,&black,15, TT_NORM);
|
|
}
|
|
// never reach hurryup time
|
|
resethurryup(curlevel);
|
|
|
|
// decrement counter
|
|
watertime--;
|
|
if (watertime < 0) {
|
|
// finished!
|
|
curlevel->iced = B_FALSE;
|
|
undoflood();
|
|
}
|
|
}
|
|
// handle gunner effect
|
|
if (haspowerupany(PW_GUNNER)) {
|
|
char tempm[SMALLBUFLEN];
|
|
|
|
// text
|
|
if (guntime > 0) {
|
|
sprintf(tempm, "%d",guntime);
|
|
addoutlinetext(320,120,TEXTSIZE_LEVEL, tempm, &red,&black,15, TT_NORM);
|
|
}
|
|
// never reach hurryup time
|
|
resethurryup(curlevel);
|
|
|
|
|
|
|
|
// decrement counter
|
|
guntime--;
|
|
if (guntime < 0) {
|
|
// finished!
|
|
disablepowerups(PW_GUNNER);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* check for hurryup*/
|
|
if (!isbosslevel(curlevelnum)) {
|
|
if ((gtime == nexthurryup) && (curlevel->iced != WATER_COMPLETE)) {
|
|
if (!levelcomplete) {
|
|
// all sprites get angry and un-iced
|
|
for (s = sprite; s; s = s->next) {
|
|
if (!isplayer(s) && ismonster(s->id) ) {
|
|
s->angry = B_TRUE;
|
|
s->iced = B_FALSE;
|
|
}
|
|
}
|
|
|
|
// rings are disabled
|
|
disablepowerups(PW_RINGWALK);
|
|
disablepowerups(PW_RINGJUMP);
|
|
|
|
addoutlinetext(320,240,TEXTSIZE_HURRY, "Hurry up!", &yellow,&black,HURRYDELAY, TT_NORM);
|
|
|
|
stopmusic();
|
|
Mix_PlayChannel(CH_HURRYUP, sfx[FX_HURRYUP], 0);
|
|
}
|
|
} else if (gtime == nexthurryup + 15) { // 15 secs after hurryup
|
|
if (!levelcomplete) {
|
|
sprite_t *bc,*s2;
|
|
int found = B_FALSE;
|
|
|
|
// does cloud already exist? (could happen if someone
|
|
// picked up the whistle powerup)
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (s2->id == P_BLACKCLOUD) {
|
|
found = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
bc = addsprite(P_BLACKCLOUD, 320,240,"cloud");
|
|
makeinvuln(bc);
|
|
}
|
|
addoutlinetext(320,240,TEXTSIZE_HURRY, "Too slow!", &red,&black,HURRYDELAY, TT_NORM);
|
|
playfx(FX_TOOSLOW);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* check for random power up */
|
|
if ((curlevel->powerupx != -1) && (curlevel->powerupy != -1)) {
|
|
if (!curlevel->gotpowerup) {
|
|
if (gtime == curlevel->poweruptime) {
|
|
if (!levelcomplete) {
|
|
/* add a random powerup at the right position */
|
|
/* the type of powerup is randomly determined when the level is
|
|
loaded */
|
|
/* IMPORTANT: the name 'random_up' is important as it tells addsprite() to
|
|
give it a higher doomcount */
|
|
puffin(level->poweruptype,
|
|
curlevel->powerupx*TILEW + (TILEW/2),
|
|
curlevel->powerupy*TILEH + TILEH - 1,
|
|
"random_up",0);
|
|
curlevel->gotpowerup = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* 5 seconds after level completion */
|
|
if (levelcomplete == LV_FINAL) {
|
|
if (gtime - levelcompletetime >= 5) {
|
|
if (endgame == EG_FRUITFALL) {
|
|
// ... do nothing
|
|
} else if (endgame == EG_FADEPAUSE) {
|
|
endgame = EG_FADETOWHITE;
|
|
globtimer = 0;
|
|
} else if ((endgame == EG_FADETOWHITE) || (endgame == EG_FADETOBLACK)) {
|
|
// ... do nothing
|
|
} else if (endgame == EG_FINAL) {
|
|
// ... do nothing
|
|
} else if (playersalive()) {
|
|
sprite_t *newsp;
|
|
int x,y;
|
|
levelcomplete = LV_CLOUD;
|
|
switch (curlevel->exitdir) {
|
|
case D_RIGHT:
|
|
default:
|
|
x = TILEW/2;
|
|
y = rand() % SCREENH;
|
|
break;
|
|
case D_LEFT:
|
|
x = SCREENW-(TILEW/2);
|
|
y = rand() % SCREENH;
|
|
break;
|
|
case D_UP:
|
|
x = rand() % SCREENW;
|
|
y = SCREENH-(TILEW/2);
|
|
break;
|
|
case D_DOWN:
|
|
x = rand() % SCREENW;
|
|
y = TILEW/2;
|
|
break;
|
|
}
|
|
|
|
if (player && player->lives > 0) {
|
|
newsp = addsprite(P_PINKCLOUD, x, y, "pinkcloud_1");
|
|
newsp->timer1 = LV_CLOUD;
|
|
newsp->owner = player;
|
|
puffin(-1, x, y, "nothing", 0);
|
|
}
|
|
if (player2 && player2->lives > 0) {
|
|
newsp = addsprite(P_PINKCLOUD, x, y, "pinkcloud_2");
|
|
newsp->timer1 = LV_CLOUD;
|
|
newsp->owner = player2;
|
|
puffin(-1, x, y, "nothing", 0);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
fpsstart = fpsticks;
|
|
}
|
|
}
|
|
}
|
|
|
|
void nextlevel(void) {
|
|
char msg[SMALLBUFLEN];
|
|
sprite_t *cloudp;
|
|
int x,y;
|
|
int curworld;
|
|
|
|
|
|
// remove the players
|
|
if (!firstlevel) {
|
|
removesprite(player);
|
|
removesprite(player2);
|
|
}
|
|
|
|
/* in case we skipped the level due to a powerup etc */
|
|
levelcomplete = LV_NEXTLEV;
|
|
|
|
|
|
// disable "forcegold" (comes form magic lamp) unless we got
|
|
// if on this level
|
|
if (forcegold) {
|
|
if (forcegoldlev != curlevelnum) {
|
|
forcegold = B_FALSE;
|
|
}
|
|
}
|
|
|
|
/* go to next level */
|
|
// this won't trigger on the first load of the intro
|
|
// becasue curlevelnum is decremented before this function
|
|
// is called. When the intro ENDs, the next line will
|
|
// be true.
|
|
if (curlevelnum == INTRO_LEVELNUM) {
|
|
curlevelnum = 1;
|
|
} else {
|
|
curlevelnum++;
|
|
}
|
|
|
|
curworld = getcurworld();
|
|
if (!musicplaying || (curmusic == fastmusic[curworld])) {
|
|
if (curlevelnum != INTRO_LEVELNUM) {
|
|
playmusic(normalmusic[curworld]);
|
|
}
|
|
}
|
|
|
|
// don't want the player flashing while scrolling
|
|
if (player) player->invuln = 0;
|
|
if (player2) player2->invuln = 0;
|
|
|
|
// not on a trampoline!
|
|
if (player) {
|
|
player->ontramp = B_FALSE;
|
|
player->trampx = -1;
|
|
player->trampy = -1;
|
|
player->oncloud = B_FALSE;
|
|
}
|
|
if (player2) {
|
|
player2->ontramp = B_FALSE;
|
|
player2->trampx = -1;
|
|
player2->trampy = -1;
|
|
player2->oncloud = B_FALSE;
|
|
}
|
|
|
|
// clear regrowth
|
|
numregrow = 0;
|
|
|
|
// load next level data
|
|
if (haspowerupany(PW_PHONE) && !isbosslevel(curlevelnum)) {
|
|
// don't add monsters
|
|
loadlevel(curlevelnum, B_FALSE);
|
|
} else {
|
|
loadlevel(curlevelnum, B_TRUE);
|
|
}
|
|
|
|
// remmeber layer 2 in case we replace it with water
|
|
for (y = 0 ; y < LEVELH; y++) {
|
|
for (x = 0 ; x < LEVELW; x++) {
|
|
savemap[y*LEVELW+x] = curlevel->map2[y*LEVELW+x];
|
|
}
|
|
}
|
|
watertime = -1;
|
|
|
|
fruittime = -1;
|
|
|
|
// do the moving to next level transition (ie. scroll the screen)
|
|
drawlevel();
|
|
|
|
// now the player gets invincibility
|
|
if (!inintro()) {
|
|
if (!cheat) {
|
|
makeinvuln(player);
|
|
makeinvuln(player2);
|
|
}
|
|
}
|
|
|
|
// phone is cancelled on boss levels
|
|
if (haspowerupany(PW_PHONE)) {
|
|
if (isbosslevel(curlevelnum)) {
|
|
sprite_t *pp;
|
|
pp = haspowerupany(PW_PHONE);
|
|
losepowerup(pp);
|
|
skiplevels = 0;
|
|
}
|
|
}
|
|
|
|
/* reset game stats */
|
|
if (haspowerupany(PW_PHONE)) {
|
|
levelcomplete = LV_CLOUD;
|
|
} else {
|
|
levelcomplete = LV_INIT;
|
|
levelcompletetime = -1;
|
|
}
|
|
|
|
/* reset level stats */
|
|
level->gotpowerup = B_FALSE;
|
|
|
|
// this is based on the max number of monsters killed
|
|
// simulatneously on the previous level...
|
|
forcegoodcard = nextforcegoodcard;
|
|
nextforcegoodcard = B_FALSE;
|
|
|
|
if (isbosslevel(curlevelnum)) {
|
|
// don't play bell on boss levels
|
|
playedbell = BELL_DONEFLASH;
|
|
} else {
|
|
if ((player && player->hasbell) || (player2 && player2->hasbell)) {
|
|
playedbell = B_FALSE;
|
|
} else {
|
|
playedbell = BELL_DONEFLASH;
|
|
}
|
|
}
|
|
|
|
// if this is boss level, play music
|
|
if (isbosslevel(curlevelnum)) {
|
|
stopmusic();
|
|
playmusic(bossmusic);
|
|
} else {
|
|
if (curlevelnum != INTRO_LEVELNUM) {
|
|
if (curmusic != normalmusic[curworld]) {
|
|
stopmusic();
|
|
playmusic(normalmusic[curworld]);
|
|
}
|
|
}
|
|
}
|
|
|
|
level->iced = ICE_NONE;
|
|
level->icey = -1;
|
|
|
|
if (!inintro()) {
|
|
sprintf(msg, "Level %d-%d",getcurworld(), getcurlevel());
|
|
addoutlinetext(320,240-18,TEXTSIZE_LEVEL,msg,&white,&black,LEVELDELAY, TT_NORM);
|
|
|
|
sprintf(msg, "\"%s\"", curlevel->name);
|
|
addoutlinetext(320,240+18,TEXTSIZE_LEVEL2,msg,&cyan,&black,LEVELDELAY, TT_NORM);
|
|
}
|
|
|
|
/* reset player stats */
|
|
if (player && player->lives > 0) {
|
|
player->netting = B_FALSE;
|
|
player->slamming = B_FALSE;
|
|
player->jumping = B_FALSE;
|
|
player->netcaught = 0;
|
|
|
|
// make sure player is at the right position
|
|
player->x = (curlevel->p1x * TILEW) + (TILEW/2);
|
|
player->y = (curlevel->p1y * TILEH) + TILEH-2;
|
|
}
|
|
if (player2 && player2->lives > 0) {
|
|
player2->netting = B_FALSE;
|
|
player2->slamming = B_FALSE;
|
|
player2->jumping = B_FALSE;
|
|
player2->netcaught = 0;
|
|
|
|
// make sure player2 is at the right position
|
|
player2->x = (curlevel->p2x * TILEW) + (TILEW/2);
|
|
player2->y = (curlevel->p2y * TILEH) + TILEH-2;
|
|
}
|
|
|
|
// remove powerup, phone is a special case
|
|
if (haspowerupany(PW_PHONE)) {
|
|
skiplevels--;
|
|
if (skiplevels <= 0) {
|
|
disablepowerups(PW_PHONE);
|
|
}
|
|
} else {
|
|
// lose ALL temp powerups
|
|
if (player) losepowerup(player);
|
|
if (player2) losepowerup(player2);
|
|
}
|
|
|
|
// remove level powerup effect (bomb etc)
|
|
globpowerup = -1;
|
|
|
|
|
|
|
|
// add initial fading cloud
|
|
if (!inintro()) {
|
|
if (player && player->lives > 0) {
|
|
cloudp = addsprite(P_PINKCLOUD, player->x,player->y + (imageset[P_PINKCLOUD].img[F_WALK1]->h / 2),"initial_pinkcloud_1");
|
|
cloudp->timer1 = levelcomplete;
|
|
cloudp->size = 1.0;
|
|
cloudp->owner = player;
|
|
cloudp->rotated = 0;
|
|
cloudp->angle = 0;
|
|
}
|
|
if (player2 && player2->lives > 0) {
|
|
cloudp = addsprite(P_PINKCLOUD, player2->x,player2->y + (imageset[P_PINKCLOUD].img[F_WALK1]->h / 2),"initial_pinkcloud_2");
|
|
cloudp->timer1 = levelcomplete;
|
|
cloudp->size = 1.0;
|
|
cloudp->owner = player2;
|
|
cloudp->rotated = 0;
|
|
cloudp->angle = 0;
|
|
}
|
|
}
|
|
|
|
if (cheat) {
|
|
if (player) {
|
|
player->speed = PLAYERFAST;
|
|
player->netmax = 4;
|
|
}
|
|
if (player2) {
|
|
player2->speed = PLAYERFAST;
|
|
player2->netmax = 4;
|
|
}
|
|
|
|
}
|
|
|
|
// make players face the correct way
|
|
if (player) {
|
|
if (player->x < (SCREENW/2)) {
|
|
player->dir = D_RIGHT;
|
|
} else {
|
|
player->dir = D_LEFT;
|
|
}
|
|
}
|
|
if (player2) {
|
|
if (player2->x < (SCREENW/2)) {
|
|
player2->dir = D_RIGHT;
|
|
} else {
|
|
player2->dir = D_LEFT;
|
|
}
|
|
}
|
|
|
|
// haven't got a card yet
|
|
gotcard = B_FALSE;
|
|
|
|
// reset timer
|
|
timer = 0;
|
|
|
|
if (autoshot) {
|
|
shottaken = B_FALSE;
|
|
}
|
|
}
|
|
|
|
void jump(sprite_t *s, int dir) {
|
|
// if we've ust been hit with armour, bypass all these checks)
|
|
if (!s->recoiling) {
|
|
// can't jump if already jumping
|
|
if (s->jumping) {
|
|
// unless we have the doublejump powerup
|
|
if (!s->doublejump || s->useddoublejump || !s->doublejumpready) {
|
|
return;
|
|
}
|
|
}
|
|
if (s->jumptimer) return;
|
|
|
|
if (s->doublejump && (s->falling || s->jumping ) && (s->useddoublejump || !s->doublejumpready)) {
|
|
return;
|
|
}
|
|
|
|
// can only jump sideways when climbing
|
|
if (s->climbing && (dir == 0)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// check for recoiling here, because we always need to be able to
|
|
// "jump" backwards, even if already jumping
|
|
if (s->recoiling || isonground(s) || isinwater(s) || isonladder(s) || s->doublejump) {
|
|
if (ismonster(s->id) || (s->id == P_KSSHELL)) {
|
|
if (s->recoiling) { // recoiling monsters don't pause before jumping
|
|
if (s->id == P_KSSHELL) {
|
|
s->jumpspeed = 3;
|
|
s->jumpdir = dir*3;
|
|
} else {
|
|
s->jumpspeed = MONJUMPSPEED;
|
|
s->jumpdir = dir;
|
|
}
|
|
s->jumping = 1;
|
|
s->dir = -s->jumpdir; // face backwards
|
|
} else {
|
|
//s->jumpdir = s->dir * getspeed(s);
|
|
s->jumpdir = dir;
|
|
if (s->jumpdir != 0) {
|
|
s->dir = s->jumpdir;
|
|
}
|
|
// special case
|
|
if ((s->id == P_KINGRAT) && (s->timer1 == KRS_CHARGEWAIT)) {
|
|
// jump right away
|
|
s->jumpspeed = MONJUMPSPEED; // will be changed later
|
|
s->jumping = 1;
|
|
} else if (s->id == P_FROG) {
|
|
sprite_t *whoabove;
|
|
whoabove = isplayerabove(s);
|
|
|
|
if (whoabove) {
|
|
double ydis;
|
|
ydis = abs(s->y - whoabove->y);
|
|
if (ydis <= (TILEH*5)) {
|
|
s->jumpspeed = MONJUMPSPEED; // normal jump
|
|
} else {
|
|
s->jumpspeed = FROGJUMPSPEED2; // very high
|
|
}
|
|
} else {
|
|
s->jumpspeed = FROGJUMPSPEED1; // ie not high enough for most platforms
|
|
}
|
|
s->jumping = 1;
|
|
} else {
|
|
// delay then jump
|
|
s->jumptimer = getjumpdelay(s->id);
|
|
s->willjumpspeed = getmonjumpspeed(s);
|
|
}
|
|
}
|
|
} else if (isfruit(s->id)) {
|
|
s->jumping = 1;
|
|
s->jumpspeed = 2;
|
|
s->jumpdir = dir;
|
|
} else { // player
|
|
tiletype_t *tt;
|
|
s->jumpdir = dir;
|
|
if (s->jumpdir != 0) {
|
|
s->dir = s->jumpdir;
|
|
}
|
|
|
|
if (s->doublejump) {
|
|
if (s->falling || s->jumping) {
|
|
// we just used up the doublejump
|
|
s->useddoublejump = B_TRUE;
|
|
puffin(-1, s->x, s->y, "nothing", 0);
|
|
} else {
|
|
// we're jumping off the ground
|
|
// need to let go of jump before double jumping
|
|
s->doublejumpready = B_FALSE;
|
|
}
|
|
}
|
|
|
|
if ((s->powerup == PW_JETPACK) && (!s->useddoublejump)) {
|
|
// jetpack makes a blast of fire
|
|
addsprite(P_SMASH, s->x, s->y, "jet_smash");
|
|
addsprite(P_SMASH, s->x+(TILEW/2), s->y, "jet_smash");
|
|
addsprite(P_SMASH, s->x-(TILEW/2), s->y, "jet_smash");
|
|
|
|
// jetpack always adds speed to sideways jumps
|
|
if (s->jumpdir > 0) {
|
|
s->jumpdir++;
|
|
if (!haspowerup(s, P_SPEED) == PLAYERSLOW) s->jumpdir++; // go fast even if player is slow
|
|
} else if (s->jumpdir < 0) {
|
|
s->jumpdir--;
|
|
if (!haspowerup(s, P_SPEED) == PLAYERSLOW) s->jumpdir--; // go fast even if player is slow
|
|
}
|
|
} else {
|
|
tt= gettileat(s->x, s->y, NULL, NULL);
|
|
// if on rollers, they add to your inertia
|
|
// if you are facing their direction
|
|
if ((tt->id == T_RIGHT) && (s->jumpdir > 0)) {
|
|
s->jumpdir++;
|
|
} else if ((tt->id == T_LEFT) && (s->jumpdir < 0)) {
|
|
s->jumpdir--;
|
|
} else if (tt->slippery && !isinwater(s)) {
|
|
s->jumpdir = s->xs / getspeed(s);
|
|
//if (s->jumpdir > getspeed(s)) s->jumpdir -= getspeed(s);
|
|
//if (s->jumpdir < -getspeed(s)) s->jumpdir += getspeed(s);
|
|
}
|
|
}
|
|
|
|
|
|
s->jumping = 1;
|
|
if (s->climbing) {
|
|
s->jumpspeed = 3;
|
|
} else if (!s->useddoublejump && (s->powerup == PW_JETPACK) && (s->jumpdir == 0)) {
|
|
s->jumpspeed = 7;
|
|
} else if (s->ontramp) {
|
|
s->jumpspeed = 7;
|
|
} else {
|
|
s->jumpspeed = 5;
|
|
}
|
|
|
|
// Special hidden cheat - jumping on the up sign on level 1
|
|
// skips you to level 3 (to avoid boring levels at the start)
|
|
// Only if you haven't lost a life too!
|
|
if ((levelcomplete == LV_INPROGRESS) && (!s->lostlife) && (s->jumpdir == 0)) {
|
|
sprite_t *ss;
|
|
int found = B_FALSE;
|
|
// make sure a warp doesn't already exist
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_PHONE) && (strstr(ss->name, "warp"))) {
|
|
found = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
int tx,ty;
|
|
tt= gettileat(s->x, s->y - (TILEH/2), &tx, &ty);
|
|
if (tt->id == T_WARP) {
|
|
// it disappears
|
|
curlevel->map[ty*LEVELW+tx] = getuniq(T_WARP);
|
|
// puff in a telephone
|
|
puffin(P_PHONE, tx*TILEW + (TILEW/2), ty*TILEH+TILEH, "warpphone", -1);
|
|
playfx(FX_WARP);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
// stop climbing
|
|
s->climbing = B_FALSE;
|
|
if (isplayer(s) ) {
|
|
// stop recoiling
|
|
if (s->recoiling) {
|
|
s->recoiling = B_FALSE;
|
|
} else {
|
|
// play sound effect
|
|
if (s->ontramp) {
|
|
playfx(FX_SPRING);
|
|
} else if (!s->useddoublejump && (s->powerup == PW_JETPACK)) {
|
|
playfx(FX_JETPACK);
|
|
} else {
|
|
playfx(FX_JUMP);
|
|
}
|
|
}
|
|
}
|
|
|
|
adjustx(s, F_JUMP);
|
|
|
|
}
|
|
}
|
|
|
|
void die(sprite_t *s) {
|
|
sprite_t *s2;
|
|
/* clouds can't die like this */
|
|
if (s->id == P_BLACKCLOUD) return;
|
|
if (s->id == P_PINKCLOUD) return;
|
|
|
|
/* if this is the player, hurryup time counter resets */
|
|
// We already do this in the cloud movement routine, but
|
|
// this handles cases where the cloud hasn't appeared yet.
|
|
if (isplayer(s)) {
|
|
// if we have armour, we lose it instead of dying
|
|
if (s->armour) {
|
|
// lose armour
|
|
s->armour = B_FALSE;
|
|
if (s == player) {
|
|
s->id = swapplayers ? P_PLAYER2 : P_PLAYER;
|
|
} else {
|
|
s->id = swapplayers ? P_PLAYER : P_PLAYER2;
|
|
}
|
|
// become invulnerable temporarily
|
|
makeinvuln(s);
|
|
// bounce back
|
|
s->recoiling = B_TRUE;
|
|
jump(s, -s->dir);
|
|
// play sound
|
|
playfx(FX_OW);
|
|
// don't process rest of the death code
|
|
return;
|
|
} else {
|
|
int tnum;
|
|
int curworld;
|
|
curworld = getcurworld();
|
|
|
|
if (globpowerup == PW_CLOCK) {
|
|
Mix_ResumeMusic();
|
|
}
|
|
if (globpowerup == PW_LAMP) {
|
|
sprite_t *s2;
|
|
Mix_ResumeMusic();
|
|
// kill all gold coins
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (s2->id == P_GOLDCOIN) {
|
|
s2->dead = D_FINAL;
|
|
puffin(-1, s2->x, s2->y, "gcpuff", rand() % 5);
|
|
} else if ((s2->id == P_PUFF) && (s2->timer3 == P_GOLDCOIN)) {
|
|
s2->dead = D_FINAL;
|
|
puffin(-1, s2->x, s2->y, "gcpuff", rand() % 5);
|
|
}
|
|
}
|
|
}
|
|
|
|
// turn off some global powerups
|
|
switch (globpowerup) {
|
|
case PW_CLOCK:
|
|
case PW_SPRAYUP:
|
|
case PW_SPRAYDOWN:
|
|
case PW_WHISTLE:
|
|
globpowerup = -1;
|
|
break;
|
|
}
|
|
|
|
// lose normal powerups immediately
|
|
s->powerup = PW_NONE;
|
|
s->umbrella = B_FALSE;
|
|
|
|
resethurryup(curlevel);
|
|
if (curmusic == fastmusic[curworld]) {
|
|
playmusic(normalmusic[curworld]);
|
|
}
|
|
|
|
// mark sprite as dead
|
|
s->lostlife = B_TRUE;
|
|
|
|
// turn off attributes
|
|
s->climbing = B_FALSE;
|
|
s->swimming = B_FALSE;
|
|
s->slamming = B_FALSE;
|
|
s->netting = B_FALSE;
|
|
|
|
// kill mask sprite
|
|
for (s2 = sprite ; s2 ; s2 = s2->next) {
|
|
if ((s2->id == P_MASK) && (s2->owner == s)) {
|
|
s2->dead = D_FINAL;
|
|
}
|
|
}
|
|
|
|
// reset powerup types
|
|
curpoweruptype[0] = 0;
|
|
curpoweruptype[1] = 0;
|
|
|
|
/* lose a life */
|
|
s->lives--;
|
|
|
|
|
|
/* play sound */
|
|
playfx(FX_DIE);
|
|
|
|
// draw text
|
|
tnum = rand() % MAXDEATHTEXT;
|
|
addoutlinetext(s->x,s->y,TEXTSIZE_DEATH,deathtext[tnum],getptextcol(s),&black,DIEDELAY, TT_NORM);
|
|
|
|
/* release anything we've caught */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (s2->caughtby == s) {
|
|
uncatch(s2);
|
|
s2->angry = B_TRUE;
|
|
}
|
|
}
|
|
|
|
// un-ice everything if player dies
|
|
}
|
|
} else if (s == boss) { // boss effects
|
|
sprite_t *ss;
|
|
// stop screen shaking and rats falling
|
|
if (globpowerup == PW_RATSHAKE) {
|
|
globpowerup = -1;
|
|
} else if (globpowerup == PW_SNAILSHAKE) {
|
|
globpowerup = -1;
|
|
}
|
|
// reset timers
|
|
s->timer1 = 0;
|
|
s->timer2 = 0;
|
|
// death timer
|
|
s->timer3 = BOSSDIETIME;
|
|
|
|
if (s->id == P_KINGRAT) {
|
|
// stop rats from coming in
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((s->id == P_PUFF) && (ss->timer3 == P_RAT)) {
|
|
// cancel the puffin
|
|
ss->timer3 = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// give a permenant powerup!
|
|
switch (s->id) {
|
|
case P_KINGRAT:
|
|
addsprite(P_BIGSPEED, (SCREENW/2), 0, "bigspeed");
|
|
break;
|
|
case P_KINGSNAIL:
|
|
addsprite(P_BIGSCUBA, (SCREENW/2), 0, "bigscuba");
|
|
break;
|
|
case P_KINGFLY:
|
|
addsprite(P_SUPERUMBRELLA, (SCREENW/2), 0, "bigumbrella");
|
|
break;
|
|
case P_KINGANT:
|
|
addsprite(P_BIGHELMET, (SCREENW/2), 0, "bighelmet");
|
|
break;
|
|
case P_KINGCAT:
|
|
addsprite(P_BIGCHEST, (SCREENW/2), 0, "bigchest");
|
|
break;
|
|
}
|
|
} else if ((s->id == P_SNAIL) && (s->lives > 0)) { // snails can't die but turn into slugs instead
|
|
sprite_t *newsp;
|
|
sprite_t *catcher;
|
|
|
|
if (s->caughtby) {
|
|
catcher = s->caughtby;
|
|
} else {
|
|
double dist1, dist2;
|
|
// pick closest one
|
|
if (player) dist1 = getdistance(player->x,player->y,s->x,s->y);
|
|
else dist1 = 99999;
|
|
if (player2) dist2 = getdistance(player2->x,player2->y,s->x,s->y);
|
|
else dist2 = 99999;
|
|
|
|
if (dist1 < dist2) {
|
|
catcher = player;
|
|
} else {
|
|
catcher = player2;
|
|
}
|
|
|
|
}
|
|
|
|
// create a slug here
|
|
newsp = addsprite(P_SLUG, s->x,s->y, "slug" );
|
|
puffin(-1, s->x, s->y, "nothing", 0); // create the illusion of a puff
|
|
newsp->dir = catcher->dir; // facing away from player
|
|
// make sure it can't be netted right away!
|
|
if (globpowerup != PW_CLOCK) {
|
|
newsp->invuln = SLUGINVULNTIME;
|
|
}
|
|
|
|
|
|
// the shell recoils (other code will kill us off when this is done)
|
|
// -become invulnerable temporarily
|
|
s->invuln = INVULNTIME*2; // make sure this lasts until we die
|
|
// -bounce back
|
|
s->recoiling = B_TRUE;
|
|
jump(s,catcher->dir); // ie. away from the player
|
|
|
|
playfx(FX_CRACK);
|
|
|
|
|
|
// when we hit the ground, later code will check for this.
|
|
// if a snail with lives=0 hits the ground, they die (it actually
|
|
// looks like a shell)
|
|
s->lives = 0;
|
|
|
|
// attributes
|
|
s->angry = 0;
|
|
s->iced = 0;
|
|
|
|
|
|
// don't do rest of code
|
|
return;
|
|
}
|
|
|
|
/* set death attribute */
|
|
s->dead = D_INITIAL;
|
|
s->netcaught = B_FALSE;
|
|
s->netting = 0;
|
|
s->slamming = 0;
|
|
s->iced = 0;
|
|
s->angry = 0;
|
|
|
|
// play effect if they are going to be flaming
|
|
if (globpowerup == PW_CANDLE) {
|
|
playfx(FX_METEOR);
|
|
}
|
|
|
|
// check for level clear
|
|
checklevelend();
|
|
|
|
}
|
|
|
|
void checklevelend(void) {
|
|
sprite_t *s2;
|
|
int mcount;
|
|
|
|
if (inintro()) return;
|
|
|
|
// can't win until monsters have appeared
|
|
if (levelcomplete == LV_INIT) return;
|
|
|
|
if (!levelcomplete) {
|
|
if (globpowerup == PW_LAMP) {
|
|
// level ends when all gold coins are gone
|
|
mcount = 0;
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (s2->id == P_GOLDCOIN) {
|
|
mcount++;
|
|
} else if ((s2->id == P_PUFF) && (s2->timer3 == P_GOLDCOIN)) {
|
|
mcount++;
|
|
}
|
|
}
|
|
if (mcount == 0) {
|
|
levelcomplete = LV_CLEAR;
|
|
}
|
|
} else {
|
|
// level ends when all monsters are dead
|
|
mcount = 0;
|
|
/* any monsters left? */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (ismonster(s2->id) && !s2->dead) {
|
|
if (s2->id != P_BLACKCLOUD) {
|
|
mcount++;
|
|
}
|
|
}
|
|
}
|
|
if (mcount == 0) {
|
|
levelcomplete = LV_CLEAR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int countcaughtfruits(sprite_t *who) {
|
|
sprite_t *s;
|
|
int count = 0;
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if ((s != who) && isfruit(s->id) && (s->caughtby == who)) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int countfruits(void) {
|
|
sprite_t *s2;
|
|
int mcount;
|
|
mcount = 0;
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (!s2->dead) {
|
|
if (isfruit(s2->id)) {
|
|
mcount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return mcount;
|
|
}
|
|
|
|
// count monsters of a given type (-1 for all) on level
|
|
int countmonsters(int montype) {
|
|
sprite_t *s2;
|
|
int mcount;
|
|
mcount = 0;
|
|
/* any monsters left? */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (ismonster(s2->id) && !s2->dead) {
|
|
if (s2->id != P_BLACKCLOUD) {
|
|
if ((montype == -1) || (s2->id == montype)) {
|
|
mcount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return mcount;
|
|
}
|
|
|
|
int counttextoftype(int wanttype) {
|
|
text_t *t;
|
|
int count = 0;
|
|
for (t = text ; t ; t = t->next) {
|
|
if (t->type == wanttype) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int countsprites(int montype) {
|
|
sprite_t *s2;
|
|
int mcount;
|
|
mcount = 0;
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (!s2->dead) {
|
|
if (s2->id != P_BLACKCLOUD) {
|
|
if ((montype == -1) || (s2->id == montype)) {
|
|
mcount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return mcount;
|
|
}
|
|
|
|
// count of monsters left alive and uncaught
|
|
int uncaughtmonsters(void) {
|
|
sprite_t *s2;
|
|
int mcount;
|
|
mcount = 0;
|
|
/* any monsters left? */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (ismonster(s2->id) && !s2->dead && !s2->caughtby) {
|
|
if (s2->id != P_BLACKCLOUD) {
|
|
mcount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return mcount;
|
|
}
|
|
|
|
void cleanup(void) {
|
|
int i;
|
|
printf("commencing cleanup routine....\n");
|
|
SDL_FreeSurface(endgamebox);
|
|
SDL_FreeSurface(pausedtext);
|
|
SDL_FreeSurface(pausedshadow);
|
|
Mix_HaltMusic();
|
|
Mix_CloseAudio();
|
|
for (i = 1; i < MAXLETTERHEIGHT; i++) {
|
|
TTF_CloseFont(font[i]);
|
|
}
|
|
TTF_Quit();
|
|
SDL_Quit();
|
|
printf("complete.\n");
|
|
}
|
|
|
|
sprite_t *getrandomaliveplayer() {
|
|
if (!playersalive()) return NULL;
|
|
if (player2 && (rand() & 2)) {
|
|
return player2;
|
|
} else if (player) {
|
|
return player;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int isonplatform(double x, double y) {
|
|
sprite_t *s2;
|
|
for (s2 = sprite ; s2 ; s2 = s2->next) {
|
|
if (s2->id == P_PLATFORM) {
|
|
if ((x >= (s2->x - s2->img->w/2)) && (x <= (s2->x + s2->img->w/2)) &&
|
|
(y >= (s2->y - s2->img->h)) && (y <= s2->y)) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void checkcollideplatform(sprite_t *s) {
|
|
sprite_t *s2;
|
|
SDL_Surface *walkimg;
|
|
|
|
for (s2 = sprite ; s2 ; s2 = s2->next) {
|
|
// only monsters and players and fruits can be on platforms
|
|
if (!ismonster(s2->id) && (!isplayer(s2)) && (!isfruit(s2->id))) {
|
|
continue;
|
|
} else if (s2->id == P_BLACKCLOUD) {
|
|
continue;
|
|
}
|
|
|
|
if (s2->onplatform == s) {
|
|
// if already on us, default to not being on us in case
|
|
// it's moved away
|
|
s2->onplatform = NULL;
|
|
}
|
|
|
|
walkimg = imageset[s2->id].img[F_WALK1];
|
|
if (walkimg != NULL) {
|
|
// has it hit the top half of us?
|
|
if ((s2->x >= (s->x - s->img->w/2 - walkimg->w/2 ) ) && (s2->x <= (s->x + s->img->w/2 + walkimg->w/2)) &&
|
|
(s2->y >= (s->y - s->img->h) ) && (s2->y <= s->y - s->img->h/2)) {
|
|
/* COLLISION! */
|
|
if ((!s2->jumping) && (!s2->dead)) {
|
|
s2->y = s->y - s->img->h;
|
|
s2->onplatform = s;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// check whether a corpse has collided with a monster
|
|
void checkfruitcollide (sprite_t *s) {
|
|
double xdiff,ydiff,xthresh,ythresh;
|
|
sprite_t *s2;
|
|
|
|
// for all other monsters
|
|
for (s2 = sprite ; s2 ; s2 = s2->next) {
|
|
|
|
if (s2 == s) continue;
|
|
else if (!ismonster(s2->id)) continue;
|
|
else if (s2->dead) continue;
|
|
else if (s2->caughtby) continue;
|
|
else if (s2->teleporting) continue;
|
|
else if (!isnettable(s2)) continue;
|
|
|
|
// did we hit it?
|
|
xdiff = s->x - s2->x;
|
|
if (xdiff < 0) xdiff = -xdiff;
|
|
ydiff = (s->y-(s->img->h/2)) - (s2->y-(s2->img->h/2));
|
|
if (ydiff < 0) ydiff = -ydiff;
|
|
|
|
// adjust for zapper
|
|
xthresh = s->img->w/2 + s2->img->w/2;
|
|
ythresh = s->img->h/2 + s2->img->h/2;
|
|
|
|
|
|
if ((xdiff <= xthresh) && (ydiff <= ythresh)) {
|
|
// Colllision!
|
|
playfx(FX_KILL);
|
|
// if so, it turns into a fruit too!
|
|
s2->id = fruittypes[curfruittype];
|
|
|
|
// stop jumping etc and allocate score
|
|
setdefaults(s2);
|
|
|
|
/* increment fruit type */
|
|
incfruittype();
|
|
// fruit time
|
|
fruittime = gtime;
|
|
|
|
// bounce backwards
|
|
if (s->xs > 0) {
|
|
jump(s2, D_RIGHT);
|
|
} else {
|
|
jump(s2, D_LEFT);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void checkcollide(sprite_t *s) {
|
|
sprite_t *s2;
|
|
int keepchecking;
|
|
double xdiff,ydiff;
|
|
double xthresh, ythresh;
|
|
int netsleft;
|
|
|
|
|
|
// for all other sprites
|
|
for (s2 = sprite ; s2 ; s2 = s2->next) {
|
|
|
|
if (s2 == s) continue;
|
|
else if (s->dead) continue;
|
|
else if (s2->dead) continue;
|
|
else if (s->caughtby && !isfruit(s->id)) continue;
|
|
else if (s2->caughtby && !isfruit(s2->id)) continue;
|
|
else if (s2->teleporting) continue;
|
|
else if (iseffect(s2->id)) continue;
|
|
|
|
|
|
keepchecking = B_TRUE;
|
|
|
|
/* check for collision with our net */
|
|
if ((s->netting ) && (s->powerup != PW_RAYGUN)) {
|
|
if ((isnettable(s2) && !s2->invuln) || (s->netsticky && isfruit(s2->id))){
|
|
double nety;
|
|
if ((s->x + s->netlen*s->netdir) > s2->x) {
|
|
xdiff = (s->x + s->netlen*s->netdir) - s2->x;
|
|
} else {
|
|
xdiff = s2->x - (s->x + s->netlen*s->netdir);
|
|
}
|
|
if (xdiff < 0) xdiff = -xdiff;
|
|
|
|
nety = (s->y - (s->img->h/2) - 1);
|
|
|
|
if (nety > (s2->y - s2->img->h/2)) {
|
|
ydiff = nety - (s2->y - s2->img->h/2);
|
|
} else {
|
|
ydiff = (s2->y - s2->img->h/2) - nety;
|
|
}
|
|
if (ydiff < 0) ydiff = -ydiff;
|
|
|
|
xthresh = s2->img->w;
|
|
ythresh = s2->img->h;
|
|
// check...
|
|
if (ythresh > TILEH*2) {
|
|
//printf("*DEBUG* ythresh too high: %0.0f\n",ythresh);
|
|
ythresh = TILEH*2;
|
|
}
|
|
|
|
// take numnets into account for y check
|
|
netsleft = s->netmax - s->netcaught;
|
|
if (netsleft > 1) {
|
|
ythresh += ((int)s->img->h / (int)(netsleft+1) );
|
|
if (ythresh > TILEH*3) {
|
|
//printf("*DEBUG2* ythresh too high: %0.0f\n",ythresh);
|
|
ythresh = TILEH*3;
|
|
}
|
|
}
|
|
|
|
//if ((xdiff <= s2->img->w/2) && (ydiff <= s2->img->h)) {
|
|
if ((xdiff <= xthresh) && (ydiff <= ythresh)) {
|
|
// we hit something!
|
|
if (s->netsticky && isfruit(s2->id) && !s2->caughtby) {
|
|
//ooooooooo
|
|
//getfruit(s, s2, 1);
|
|
|
|
// delay movement back with net a little.
|
|
s2->caughtdelay = (countcaughtfruits(s) * (TILEW/2));
|
|
printf("%s caughtdelay = %d\n",s2->name, s2->caughtdelay);
|
|
|
|
// grab it, but don't use up one of our nets.
|
|
s2->caughtby = s;
|
|
s2->caughtstate = C_NETTING;
|
|
} else {
|
|
// Otherwise, it must be a monster
|
|
|
|
// if we have a boxing glove, it dies
|
|
if (s->powerup == PW_BOXING) {
|
|
s2->dead = D_BOUNCING;// die as soon as it hits a wall
|
|
s2->bounces = 1;
|
|
s2->quickdie = B_TRUE;
|
|
|
|
/* go FAST in the direction player is facing */
|
|
s2->xs = s->dir * 5;
|
|
s2->ys = 0;
|
|
|
|
/* slightly raise the sprite to avoid isonground() being true */
|
|
s2->y -= 3;
|
|
|
|
/* make sure we're not too high since we'll never get lower now */
|
|
if (s2->y <= TILEH) s2->y = TILEH+1;
|
|
|
|
// become something special
|
|
s2->willbecome = P_DIAMOND;
|
|
|
|
playfx(FX_KILL);
|
|
strncpy(tempm, bifftext[rand() % MAXBIFFTEXT], BUFLEN);
|
|
addoutlinetext(s2->x,s2->y - s->img->h/2, TEXTSIZE_BIFF, tempm,&red,&yellow,POINTSDELAY, TT_NORM);
|
|
keepchecking = B_FALSE;
|
|
} else if (s2->iced) {
|
|
// it dies
|
|
s2->willbecome = P_DIAMOND;
|
|
playfx(FX_ICEBREAK);
|
|
if (s2->id == P_SNAIL) s2->id = P_SLUG;
|
|
die(s2);
|
|
} else {
|
|
// otherwise we caught it if we have enough nets
|
|
|
|
if (s->netcaught < s->netmax) {
|
|
//printf("caught: ydiff=%0.0f,ythresh=%0.0f,s='%s',%0.0f,%0.0f s2='%s',%0.0f,%0.0f\n",
|
|
//ydiff,ythresh,
|
|
//s->name, s->x, s->y, s2->name,s2->x,s2->y);
|
|
|
|
s2->caughtby = s;
|
|
s2->jumping = B_FALSE;
|
|
s2->falling = 0;
|
|
s2->caughtstate = C_NETTING;
|
|
s->netcaught++;
|
|
|
|
// special case for whitetail
|
|
if (s2->id == P_WSPIDER) {
|
|
s2->timer2 = 0;
|
|
}
|
|
|
|
// special case for bosses
|
|
if (isbosslevel(curlevelnum)) {
|
|
if (s2->owner) {
|
|
s2->owner = NULL;
|
|
}
|
|
}
|
|
|
|
// special case for spider, so that it will
|
|
// recover if we release it
|
|
if (s2->id == P_SPIDER) {
|
|
s2->flies = B_FALSE;
|
|
}
|
|
|
|
playfx(FX_CATCH);
|
|
|
|
keepchecking = B_FALSE;
|
|
}
|
|
}
|
|
} // end if isfruit or ismonster
|
|
}
|
|
}
|
|
} // end if s->netting
|
|
|
|
|
|
// don't keep going if this sprite has now been killed/caught
|
|
if (!keepchecking) continue;
|
|
|
|
/* now check for collision with us */
|
|
xdiff = s->x - s2->x;
|
|
if (xdiff < 0) xdiff = -xdiff;
|
|
ydiff = (s->y-(s->img->h/2)) - (s2->y-(s2->img->h/2));
|
|
if (ydiff < 0) ydiff = -ydiff;
|
|
|
|
// adjust for zapper
|
|
xthresh = s->img->w/2 + s2->img->w/2;
|
|
ythresh = s->img->h/2 + s2->img->h/2;
|
|
|
|
if (s->id == P_ZAPPER) {
|
|
xthresh += (TILEW*2.5);
|
|
ythresh += (TILEH*2.5);
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((xdiff <= xthresh) && (ydiff <= ythresh)) {
|
|
/* COLLISION! */
|
|
|
|
// are we the player?
|
|
if (isplayer(s)) {
|
|
//if (isfruit(s2->id) && (s2->teleporting == 0)) {
|
|
if (isfruit(s2->id)) {
|
|
getfruit(s, s2, 1);
|
|
} else if (ismonster(s2->id) || isbullet(s2->id)) {
|
|
if (s2->iced) {
|
|
// monster dies
|
|
playfx(FX_ICEBREAK);
|
|
if (s2->id == P_SNAIL) s2->id = P_SLUG;
|
|
s2->willbecome = P_DIAMOND;
|
|
die(s2);
|
|
} else if (!s->invuln) {
|
|
if (s->umbrella && s->umbrellaup && isbullet(s2->id) &&
|
|
(s2->id != P_BIGFIREBALL) &&
|
|
(s2->y <= s->y - s->img->h) ) {
|
|
// umbrella will block most bullets,
|
|
// if they are above you
|
|
} else {
|
|
// player dies (unless it was the initial black cloud)
|
|
if (s2->id != P_BLACKCLOUD) {
|
|
if ((s2->id == P_SNAIL) && (s2->invuln)) {
|
|
// snail shell doesn't hurt us
|
|
} else if (s->caughtby) {
|
|
// can't die while being slammed
|
|
if (!s->caughtby->slamming) {
|
|
die(s);
|
|
}
|
|
} else {
|
|
printf("DB: player killed by %s\n",s2->name); fflush(stdout);
|
|
die(s);
|
|
}
|
|
} else {
|
|
// initial flashing black cloud doesn't kill player;
|
|
if ((s2->id == P_BLACKCLOUD) && (!s2->invuln)) {
|
|
die(s);
|
|
printf("DB: player killed by blackclodu\n"); fflush(stdout);
|
|
// play sound
|
|
playfx(FX_EVILLAUGH);
|
|
}
|
|
}
|
|
}
|
|
// add puffs if this was the cloud
|
|
if (s2->id == P_BLACKCLOUD) {
|
|
int xx,yy;
|
|
int halfwid = s2->img->w/2;
|
|
for (xx = s2->x - halfwid; xx <= s2->x + halfwid; xx += TILEW) {
|
|
for (yy = s2->y - s2->img->h; yy <= s2->y; yy += TILEH) {
|
|
puffin(-1, xx, yy, "nothing", 0);
|
|
}
|
|
}
|
|
}
|
|
// if a bullet hit us, it dies too
|
|
if (isbullet(s2->id)) {
|
|
if (s2->id != P_BIGFIREBALL) {
|
|
s2->dead = D_FINAL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if ((s->id == P_SMASH) || (s->id == P_STAR) || (s->id == P_METEOR) || (s->id == P_RAYGUNBULLET) ) {
|
|
if (ismonster(s2->id)) {
|
|
switch (s->id) {
|
|
case P_STAR: playfx(FX_STARHIT); break;
|
|
}
|
|
// monster dies
|
|
if (s2->id == P_SNAIL) s2->id = P_SLUG;
|
|
die(s2);
|
|
// become something special
|
|
s2->willbecome = P_DIAMOND;
|
|
}
|
|
} else if ((s->id == P_BLACKCLOUD) && (globpowerup == PW_WHISTLE)) {
|
|
if (ismonster(s2->id)) {
|
|
// monster dies
|
|
if (s2->id == P_SNAIL) s2->id = P_SLUG;
|
|
die(s2);
|
|
// become something special
|
|
s2->willbecome = P_DIAMOND;
|
|
// play sound
|
|
playfx(FX_EVILLAUGH);
|
|
}
|
|
} else if (s->id == P_ZAPPER) {
|
|
if (ismonster(s2->id)) {
|
|
if (s->timer4 == 0) {
|
|
// set timer for zap effect
|
|
s->timer4 = ZAPPERTIME;
|
|
s->zapping = s2;
|
|
playfx(FX_ZAP);
|
|
|
|
// monster dies
|
|
if (s2->id == P_SNAIL) s2->id = P_SLUG;
|
|
die(s2);
|
|
// become something special
|
|
s2->willbecome = P_DIAMOND;
|
|
}
|
|
}
|
|
} else if ((s->id == P_ANT1) || (s->id == P_ANT2) || (s->id == P_ANT3)) {
|
|
int isfr;
|
|
int goal = 5;
|
|
// eat fruits
|
|
isfr = isfruit(s2->id);
|
|
if (isfr) {
|
|
int fruitamt;
|
|
// eat the fruit
|
|
s2->dead = D_FINAL;
|
|
playfx(FX_CHOMP);
|
|
puffin(-1, s2->x, s2->y, "nothing", 0);
|
|
// increase health
|
|
switch (isfr) {
|
|
case FT_FRUIT:
|
|
case FT_PERM:
|
|
case FT_TEMP:
|
|
fruitamt = 5;
|
|
break;
|
|
case FT_GEM:
|
|
default:
|
|
fruitamt = 1;
|
|
break;
|
|
}
|
|
// override for ant egg..
|
|
if (s2->id == P_EGG) fruitamt = 5;
|
|
|
|
s->timer1 += fruitamt;
|
|
// huw much fruit is needed to grow?
|
|
if (s->id == P_ANT3) {
|
|
goal = 1;
|
|
} else {
|
|
goal = 5;
|
|
}
|
|
|
|
if (s->timer1 >= goal) {
|
|
s->timer1 = 0;
|
|
playfx(FX_GROWL);
|
|
// grow
|
|
if (s->id == P_ANT1) {
|
|
s->id = P_ANT2;
|
|
} else if (s->id == P_ANT2) {
|
|
s->id = P_ANT3;
|
|
} else if (s->id == P_ANT3) {
|
|
sprite_t *newsp;
|
|
// spawn a new ant
|
|
newsp = addsprite(P_ANT1, s2->x, s2->y, "spawned_ant");
|
|
puffin(-1, s->x+(s->dir*TILEH), s->y, "nothing", 0);
|
|
newsp->dir = -s->dir;
|
|
}
|
|
}
|
|
}
|
|
} else if (inintro() && (s->id == P_RAT)) {
|
|
// collect fruits
|
|
if (isfruit(s2->id)) {
|
|
playfx(FX_FRUIT);
|
|
s2->dead = D_FINAL;
|
|
puffin(-1, s2->x, s2->y, "nothing", 0);
|
|
}
|
|
}
|
|
}
|
|
} // end for each sprite
|
|
}
|
|
|
|
|
|
// do death bouncing effect
|
|
void bouncesprite(sprite_t *s) {
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
|
|
if (s->x >= (SCREENW-TILEW-(s->img->w/2))) {
|
|
// move back onto screen
|
|
while (s->x >= (SCREENW-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 >= (SCREENH-(s->img->h/2))) {
|
|
while (s->y >= (SCREENH-(s->img->h/2))) {
|
|
s->y--;
|
|
}
|
|
if (s->ys > 0) s->ys = -s->ys; // reverse direction
|
|
s->bounces++;
|
|
} else if (s->y <= s->img->h) {
|
|
while (s->y <= s->img->h) {
|
|
s->y++;
|
|
}
|
|
if (s->ys < 0) s->ys = -s->ys; // reverse direction
|
|
s->bounces++;
|
|
}
|
|
}
|
|
|
|
|
|
// returns TRUE if we finished the level
|
|
int movesprite(sprite_t *s) {
|
|
int rv;
|
|
tiletype_t *tt;
|
|
|
|
if ((isplayer(s)) && (s->powerup == PW_GUNNER)) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
if (levelcomplete == LV_INIT) {
|
|
// most things can't move in this state
|
|
//if ((s->id != P_PUFF) && (s != player)) {
|
|
if (!iseffect(s->id) && (!isplayer(s))) {
|
|
// caught or dead sprites can move, in case
|
|
// the player catches something before level start time
|
|
if ((!s->caughtby) && (!s->dead)) return B_FALSE;
|
|
} else if (s->id == P_PLATFORM) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
// only player can move if you have a clock
|
|
if (globpowerup == PW_CLOCK) {
|
|
if (!iseffect(s->id) && (!isplayer(s)) && !s->caughtby) {
|
|
return B_FALSE;
|
|
}
|
|
}
|
|
|
|
// iced monsters can't move
|
|
if (ismonster(s->id) && s->iced) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
// for random powerup, pick a random image
|
|
if ((timer % 5) == 0) {
|
|
if (s->id == P_RANDOM) {
|
|
s->timer1 = randompowerup();
|
|
while (s->timer1 == P_RANDOM) {
|
|
s->timer1 = randompowerup();
|
|
}
|
|
// set image
|
|
s->img = imageset[s->timer1].img[F_WALK1];
|
|
}
|
|
}
|
|
|
|
|
|
/* timer */
|
|
if (s->doomcount) {
|
|
// fruits don't time out in gunner mode
|
|
if (!haspowerupany(PW_GUNNER)) {
|
|
s->doomcount--;
|
|
}
|
|
if (s->doomcount == 0) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
}
|
|
|
|
/* avoid edges of screen */
|
|
if (s->y < s->img->h) {
|
|
// if (!s->flies) {
|
|
if (s->dead) {
|
|
s->y = s->img->h;
|
|
}
|
|
}
|
|
if (s->x > (SCREENW - s->img->w/2)) {
|
|
s->x = SCREENW - s->img->w/2;
|
|
}
|
|
if (s->x < (s->img->w/2)) {
|
|
s->x = s->img->w/2;
|
|
}
|
|
|
|
if (s->invuln) {
|
|
s->invuln--;
|
|
}
|
|
|
|
// anchor weighs down flying enemies
|
|
if (ismonster(s->id) && s->flies && !s->dead && (globpowerup == PW_ANCHOR)) {
|
|
if (s->id != P_BLACKCLOUD) {
|
|
if (!isonground(s)) {
|
|
// move down
|
|
s->y += 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s->caughtby) {
|
|
if (s->caughtby->slamming) {
|
|
/* */
|
|
|
|
s->x = s->caughtby->netxstart;
|
|
s->y = s->caughtby->netystart;
|
|
} else {
|
|
/* stay at position of net */
|
|
s->y = s->caughtby->y;
|
|
if (s->caughtstate == C_NETTING) {
|
|
// at the end of the player's net
|
|
s->x = s->caughtby->x + (s->caughtby->netlen*s->caughtby->netdir);
|
|
if (isfruit(s->id)) {
|
|
s->x += (s->caughtdelay * s->caughtby->netdir);
|
|
}
|
|
} else {
|
|
// behind the player's back
|
|
s->x = s->caughtby->x + (s->caughtby->img->w/2) * -(s->caughtby->dir);
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
} else if (s->dead == D_INITIAL) { /* just set to dead */
|
|
if (s == boss) {
|
|
// flash
|
|
s->timer3--;
|
|
if (s->timer3 == 0) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else {
|
|
// 0 through 5
|
|
s->xs = 0.5 + ((rand() % 50) / 10); // 0.5 through 5.5
|
|
if (rand() % 2) { // 50% change of going left
|
|
s->xs = s->xs * -1;
|
|
}
|
|
s->ys = -1 * (4 + ((rand() % 30) / 10)); // -4 through -7
|
|
|
|
s->dead = D_BOUNCING;
|
|
s->bounces = 0;
|
|
if (isplayer(s)) {
|
|
s->jumpspeed = 8;
|
|
s->jumping = 1;
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
} else if (s->dead == D_BOUNCING) { /* dying */
|
|
if (isplayer(s)) {
|
|
/* shoot up in the air, then fall */
|
|
s->y -= s->jumpspeed;
|
|
|
|
s->jumping++;
|
|
if (s->jumping % 5 == 0) {
|
|
s->jumpspeed--;
|
|
}
|
|
|
|
/* if we've fallen off the bottom... */
|
|
if (s->y >= (SCREENH+s->img->h)) {
|
|
/* pause before respawning */
|
|
s->jumpspeed = 0; /* this is now a timer */
|
|
s->dead = D_LASTBOUNCE;
|
|
}
|
|
} else {
|
|
/* bounch around the screen 3 times */
|
|
bouncesprite(s);
|
|
if ((s->bounces >= 2) && (s->ys >= 0)) {
|
|
// make sure we're not on the ground
|
|
if (!isonground(s)) {
|
|
//int tx,ty;
|
|
//tiletype_t *tt;
|
|
//tt = gettileat(s->x,s->y,&tx,&ty);
|
|
s->dead = D_LASTBOUNCE;
|
|
}
|
|
}
|
|
|
|
// if flaming...
|
|
if (globpowerup == PW_CANDLE) {
|
|
if (timer % 5 == 0) {
|
|
// add explosion
|
|
addsprite(P_SMASH, s->x, s->y, "candle_exp");
|
|
}
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
} else if (s->dead == D_LASTBOUNCE) { /* final fall */
|
|
if (isplayer(s)) {
|
|
/* just delay... */
|
|
s->jumpspeed++;
|
|
if (s->jumpspeed == 50) {
|
|
/* really die */
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else { /* bounce around, stop when we hit the ground */
|
|
bouncesprite(s);
|
|
|
|
if ((s->ys >= 0) && (s->y >= TILEH)) {
|
|
int x,y,ty;
|
|
// get position for puff/fruit
|
|
x = s->x;
|
|
gettileat(s->x,s->y-1,NULL,&ty);
|
|
//y = ty*TILEH + TILEH - 2;
|
|
y = ty*TILEH - 2;
|
|
|
|
/* make sure it's within the screen */
|
|
if (x > (SCREENW-TILEW)) x = SCREENW-TILEW;
|
|
if (x < (TILEW)) x = TILEW;
|
|
|
|
if (s->quickdie || (isonground(s) && !isongroundpoint(s, s->x, s->y-TILEH))) {
|
|
|
|
/* change into a fruit */
|
|
s->dead = D_FINAL;
|
|
if (boss) {
|
|
puffin(-1, x, y, "nothing", 0);
|
|
} else {
|
|
puffin(s->willbecome, x, y, "fruit", 0);
|
|
// check for collision with a live monster
|
|
checkfruitcollide(s);
|
|
}
|
|
//ss = addsprite(P_PUFF, x, y, "Fruit", B_FALSE);
|
|
//ss->timer3 = s->willbecome;
|
|
|
|
} else if (s->bounces >= 6) {
|
|
// just die
|
|
s->dead = D_FINAL;
|
|
puffin(-1, x, y, "nothing_sprd", 0);
|
|
}
|
|
|
|
// if flaming...
|
|
if (globpowerup == PW_CANDLE) {
|
|
if (timer % 5 == 0) {
|
|
// add explosion
|
|
addsprite(P_SMASH, s->x, s->y, "candle_exp");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
} else if (s->teleporting > 0) {
|
|
SDL_Surface *ts;
|
|
if (timer % 2 == 0) {
|
|
int prew,preh;
|
|
prew = s->img->w;
|
|
preh = s->img->h;
|
|
/* shrink */
|
|
if (s->teleporting == TP_SHRINKING) {
|
|
ts = rotozoomSurfaceXY(s->img,0, 0.9 , 0.9 ,0);
|
|
s->img = ts;
|
|
} else {
|
|
ts = rotozoomSurfaceXY(s->img,0, 0.9 , 0.9 ,0);
|
|
SDL_FreeSurface(s->img);
|
|
s->img = ts;
|
|
}
|
|
// mark that we've allocated the player's teleport image
|
|
s->allocimg = B_TRUE;
|
|
|
|
if (((s->img->w <= 2) || (s->img->h <= 2)) ||
|
|
((s->img->w == prew) && (s->img->h == preh))) {
|
|
/* go to tele dest */
|
|
int x,y;
|
|
/* find destination */
|
|
for (y = 0; y < LEVELH; y++) {
|
|
for (x = 0; x < LEVELW; x++) {
|
|
tt = gettile(curlevel->map[y*LEVELW+x]);
|
|
if (tt->id == T_TELEPORTDEST) {
|
|
/* teleport there */
|
|
s->x = (x * TILEW) + (TILEW/2);
|
|
s->y = (y * TILEH) + TILEH-2;
|
|
break;
|
|
} else { // search map2
|
|
tt = gettile(curlevel->map2[y*LEVELW+x]);
|
|
if (tt->id == T_TELEPORTDEST) {
|
|
/* teleport there */
|
|
s->x = (x * TILEW) + (TILEW/2);
|
|
s->y = (y * TILEH) + TILEH-2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
s->teleporting = -1;
|
|
} else s->teleporting++;
|
|
}
|
|
} else if (s->teleporting < 0) {
|
|
double size;
|
|
if (timer % 2 == 0) {
|
|
/* grow */
|
|
size = (double) -s->teleporting / 10;
|
|
|
|
SDL_FreeSurface(s->img);
|
|
if (size >= 1) {
|
|
s->allocimg = B_FALSE;
|
|
s->teleporting = 0;
|
|
s->img = imageset[s->id].img[F_WALK1];
|
|
} else {
|
|
s->img = rotozoomSurfaceXY(imageset[s->id].img[F_WALK1],0,size,size,0);
|
|
s->teleporting--;
|
|
}
|
|
}
|
|
} else if (s->jumping) {
|
|
if (s->id != P_KINGRAT) {
|
|
int rv;
|
|
rv = movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
// frogs bounce off walls
|
|
/*
|
|
if (s->id == P_FROG) {
|
|
if (rv == NM_SIDE) {
|
|
if (!isongroundpoint(s,s->x,s->y - (TILEH/2))) {
|
|
if (!isroofabove(s)) {
|
|
s->dir = -s->dir;
|
|
s->jumpdir = -s->jumpdir;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
// adjust height to match the ground
|
|
if (!iseffect(s->id) ) {
|
|
if (isonground(s) || ((s->id == P_KINGRAT) && (s->timer1 == KRS_WALK))) {
|
|
if ((!s->falling) && (!s->jumping)) {
|
|
if (!s->climbing && !s->dropping) {
|
|
if (!isonladder(s) ) {
|
|
if ((s->id == P_KINGFLY) || ((s->id == P_FLY) && (s->owner))) {
|
|
// don't adjust
|
|
} else {
|
|
adjustheight(s);
|
|
}
|
|
} else if (!s->climbing) { // on ladder but not climbing
|
|
adjustheight(s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* sprite is about to jump */
|
|
if (s->jumptimer) {
|
|
s->jumptimer--;
|
|
if (s->jumptimer == 0) {
|
|
s->jumping = 1;
|
|
if (globpowerup == PW_ANCHOR) {
|
|
// jump very low
|
|
s->jumpspeed = 1;
|
|
} else {
|
|
s->jumpspeed = s->willjumpspeed;
|
|
}
|
|
if (s->jumpdir != 0) s->dir = s->jumpdir;
|
|
return B_FALSE;
|
|
} else if (s->jumptimer % 20 == 0) {
|
|
if (s->id != P_SLUG) { // slugs don't turn back and forth before jumping
|
|
s->dir = -s->dir;
|
|
}
|
|
}
|
|
} else if ((s->id == P_SMASH) || (s->id == P_FLAME)) {
|
|
// still delaying
|
|
if (s->timer1 < 0) {
|
|
// increment "frame"
|
|
s->timer1++;
|
|
} else {
|
|
// increment frame at a slower pace
|
|
if (++s->timer2 >= 10) {
|
|
s->timer2 = 0;
|
|
}
|
|
if (timer % PUFFSPEED == 0) {
|
|
s->timer1++;
|
|
// finished animating
|
|
if (s->timer1 == imageset[s->id].numimages) {
|
|
s->timer1 = 999; // for debugging
|
|
s->dead = D_FINAL;
|
|
}
|
|
}
|
|
}
|
|
} else if (s->id == P_MOVINGCARD) {
|
|
// timer1 is the actual cardid
|
|
// timer2 is the target x position
|
|
// timer3 is the target y position
|
|
//
|
|
|
|
// move towards end position
|
|
moveto(s, s->timer2, s->timer3, CARDSPEED, CARDSPEED);
|
|
|
|
// are we there yet?
|
|
if ((s->x == s->timer2) && (s->y == s->timer3)) {
|
|
gaincard(s->owner, s->timer1);
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if ((s->id == P_PUFF) || (s->id == P_SPARKLE)) {
|
|
/* SUMMARY:
|
|
timer1:
|
|
indicates current frame. if < 0, don't draw.
|
|
if >= PUFFFRAMES, use last frame.
|
|
|
|
when timer1 gets to PUFFAPPEAR, create a gem
|
|
of type s->
|
|
|
|
timer2:
|
|
loops from 0 to 9.
|
|
at intervals of PUFFSPEED, increment timer1.
|
|
|
|
*/
|
|
|
|
// still delaying
|
|
if (s->timer1 < 0) {
|
|
// increment "frame"
|
|
s->timer1++;
|
|
} else {
|
|
// increment frame at a slower pace
|
|
if (++s->timer2 >= 10) {
|
|
s->timer2 = 0;
|
|
}
|
|
if (timer % PUFFSPEED == 0) {
|
|
s->timer1++;
|
|
// finished animating
|
|
if (s->timer1 == PUFFAPPEAR) {
|
|
// create a gem/fruit/etc
|
|
if (s->id == P_PUFF) {
|
|
if (s->timer3 >= 0) {
|
|
sprite_t *newsp;
|
|
|
|
// if both players already have this, and no cards already on screen,
|
|
// we get a card instead (and also haven't got a card yet htis
|
|
// level)
|
|
if (!gotcard && s->timer3 != P_SPEED) {
|
|
if ((isfruit(s->timer3) == FT_PERM) && (haspowerup(player, s->timer3) && haspowerup(player2, s->timer3))) {
|
|
sprite_t *search;
|
|
int found;
|
|
found = B_FALSE;
|
|
|
|
// is there already a card here or about to appear?
|
|
for (search = sprite; search ; search = search->next) {
|
|
if (iscard(search->id)) {
|
|
found = B_TRUE;
|
|
break;
|
|
}
|
|
// if it's a puff that will become a card...
|
|
if ((search->id == P_PUFF) && (iscard(search->timer3))) {
|
|
found = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
s->timer3 = P_FIRSTCARD;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s->timer3 == P_FIRSTCARD) {
|
|
if (levelcomplete != LV_INPROGRESS ) {
|
|
// no cards at end of level!
|
|
s->timer3 = P_CHEESE;
|
|
} else {
|
|
s->timer3 = getrandomcard();
|
|
gotcard = B_TRUE;
|
|
}
|
|
}
|
|
|
|
newsp = addsprite(s->timer3, s->x,s->y,s->name );
|
|
|
|
if (s->timer3 == P_FROG) {
|
|
// so all frogs don't jump at once.
|
|
newsp->timer3 = (rand() % FROGPAUSE);
|
|
}
|
|
|
|
// is it a boss? if so update boss pointer
|
|
switch (s->timer3) {
|
|
case P_KINGRAT:
|
|
case P_KINGSNAIL:
|
|
case P_KINGFLY:
|
|
case P_KINGANT:
|
|
case P_KINGCAT:
|
|
boss = newsp;
|
|
}
|
|
|
|
// is it in the water?
|
|
if (isinwater(newsp)) {
|
|
newsp->swimming = B_TRUE;
|
|
newsp->watertimer = rand() % BUBBLETIME;
|
|
}
|
|
|
|
// is it a points fruit appearing on top of us?
|
|
if (isfruit(newsp->id) == FT_FRUIT) {
|
|
int xdiff,ydiff;
|
|
int gotit = B_FALSE;
|
|
/* now check for collision with players */
|
|
if (player) {
|
|
xdiff = player->x - newsp->x;
|
|
if (xdiff < 0) xdiff = -xdiff;
|
|
ydiff = (player->y-(player->img->h/2)) - (newsp->y-(newsp->img->h/2));
|
|
if (ydiff < 0) ydiff = -ydiff;
|
|
|
|
// appeared on top of us
|
|
if ((xdiff <= player->img->w/2 + newsp->img->w/2) &&
|
|
(ydiff <= player->img->h/2 + newsp->img->h/2)) {
|
|
if ((!player->dead) && (player->powerup != PW_GUNNER)) {
|
|
if (newsp->id != P_GOLDCOIN) {
|
|
// bonus!
|
|
getfruit(player, newsp, 4);
|
|
addoutlinetext(player->x,player->y - (player->img->h*1.5), TEXTSIZE_MULTI, "Nice catch!", &green,&black,MULTIDELAY, TT_NORM);
|
|
gotit = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!gotit && player2) {
|
|
xdiff = player2->x - newsp->x;
|
|
if (xdiff < 0) xdiff = -xdiff;
|
|
ydiff = (player2->y-(player2->img->h/2)) - (newsp->y-(newsp->img->h/2));
|
|
if (ydiff < 0) ydiff = -ydiff;
|
|
|
|
// appeared on top of us
|
|
if ((xdiff <= player2->img->w/2 + newsp->img->w/2) &&
|
|
(ydiff <= player2->img->h/2 + newsp->img->h/2)) {
|
|
if ((!player2->dead) && (player2->powerup != PW_GUNNER)) {
|
|
// bonus!
|
|
getfruit(player2, newsp, 4);
|
|
addoutlinetext(player2->x,player2->y - (player2->img->h*1.5), TEXTSIZE_MULTI, "Nice catch!", &green,&black,MULTIDELAY, TT_NORM);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
} else if (s->timer1 >= PUFFFRAMES) {
|
|
s->timer1 = 999; // for debugging
|
|
s->dead = D_FINAL;
|
|
}
|
|
}
|
|
}
|
|
} else if (s->id == P_MOVINGCARD) {
|
|
// timer1 is the actual cardid
|
|
// timer2 is the target x position
|
|
// timer3 is the target y position
|
|
//
|
|
|
|
// move towards end position
|
|
moveto(s, s->timer2, s->timer3, CARDSPEED, CARDSPEED);
|
|
|
|
// are we there yet?
|
|
if ((s->x == s->timer2) && (s->y == s->timer3)) {
|
|
gaincard(s->owner, s->timer1);
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_FIVECARDS) {
|
|
// are we there yet?
|
|
if ((s->x == 320) && (s->y == 240 )) {
|
|
if (s->timer2 == 0) {
|
|
int i;
|
|
SDL_Surface *blackness, *cardimg;
|
|
SDL_Rect area;
|
|
int cardwidth;
|
|
|
|
cardwidth = imageset[P_FIRSTCARD].img[F_WALK1]->w;
|
|
|
|
s->timer2 = -1; //this means we are counting down
|
|
s->timer1 = POKERWAITTIME;
|
|
|
|
// hide non-used cards
|
|
cardimg = imageset[P_FIRSTCARD].img[F_WALK1];
|
|
|
|
if (s->owner == player) {
|
|
area.x = 0;
|
|
area.y = 0;
|
|
area.w = cardimg->w;
|
|
area.h = cardimg->h;
|
|
} else {
|
|
area.x = 4*(cardwidth+2);
|
|
area.y = 0;
|
|
area.w = cardimg->w;
|
|
area.h = cardimg->h;
|
|
}
|
|
|
|
// create semi-transparent black surface the size of a card
|
|
blackness = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
cardimg->w, cardimg->h,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask,
|
|
screen->format->Amask);
|
|
SDL_FillRect(blackness, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
|
|
SDL_SetAlpha(blackness, SDL_SRCALPHA, 200);
|
|
|
|
|
|
for (i = 0; i < s->owner->numcards; i++) {
|
|
if (s->owner->usedcard[i] == B_FALSE) {
|
|
// hide it
|
|
//SDL_FillRect(s->img, &area, SDL_MapRGB(screen->format, 0, 0, 0));
|
|
SDL_BlitSurface(blackness, NULL, s->img, &area);
|
|
}
|
|
|
|
if (s->owner == player) {
|
|
area.x += (cardimg->w + 2);
|
|
} else {
|
|
area.x -= (cardimg->w + 2);
|
|
}
|
|
}
|
|
SDL_FreeSurface(blackness);
|
|
|
|
|
|
} else {
|
|
s->timer1--;
|
|
if (s->timer1 == 0) {
|
|
sprite_t *s2, *nexts;
|
|
int i;
|
|
// die
|
|
s->dead = D_FINAL;
|
|
// restore state
|
|
levelcomplete = oldlevelcomplete;
|
|
|
|
Mix_ResumeMusic();
|
|
|
|
// do effect!
|
|
dopokereffect(s->owner,pokereffect);
|
|
|
|
// clear player cards
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
s->owner->card[i] = -1;
|
|
}
|
|
s->owner->numcards = 0;
|
|
|
|
// shuffle cards
|
|
shufflecards();
|
|
|
|
// kill all monsters (if not skipping levels)
|
|
if (s->owner->powerup != PW_PHONE) {
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
} else if (ismonster(s2->id)) {
|
|
s2->willbecome = P_DIAMOND;
|
|
s2->lives = 0; // for snails
|
|
|
|
if (s2->caughtby) {
|
|
uncatch(s2);
|
|
}
|
|
die(s2);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
} else {
|
|
// move towards centre of the screen
|
|
moveto(s, 320, 240, FIVECARDSPEED, FIVECARDSPEED);
|
|
}
|
|
} else if (s->id == P_MASK) { // mask effect
|
|
// stay on top of player
|
|
if (s->owner->slamming) {
|
|
s->y = s->owner->y + MASKOFFSETSLAMY;
|
|
s->x = s->owner->x + (MASKOFFSETSLAMX*s->owner->dir);
|
|
} else {
|
|
s->y = s->owner->y + MASKOFFSETY;
|
|
s->x = s->owner->x + (MASKOFFSETX*s->owner->dir);
|
|
}
|
|
|
|
// die if player doesn't have a mask
|
|
if (!s->owner->hasmask) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_STAR) { // shuriken effect
|
|
// animate
|
|
s->timer1++;
|
|
if (s->timer1 >= STARFRAMES) {
|
|
s->timer1 = 0;
|
|
}
|
|
// move until we hit the edge of the screen
|
|
s->x = s->x + s->xs;
|
|
s->y = s->y + s->ys;
|
|
|
|
// if off screen
|
|
if ((s->x >= SCREENW - s->img->w/2) || (s->x <= s->img->w/2) || (s->y <= 0) || (s->y >= SCREENH+s->img->h)) {
|
|
// die
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_FIREUP) { // vertical fireball
|
|
s->y = s->y + s->ys;
|
|
s->ys += 0.1;
|
|
// if lower than starting y position & moving down
|
|
if ((s->y >= s->timer1) && (s->ys > 0)) {
|
|
// die
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if ((s->id == P_METEOR) || (s->id == P_FALLINGBRICK)) { // meteor
|
|
double oldy;
|
|
|
|
oldy = s->y;
|
|
// fall to bottom of screen then die
|
|
s->y = s->y + s->ys;
|
|
|
|
if (s->id == P_FALLINGBRICK) {
|
|
// increase speed
|
|
s->ys += 0.2;
|
|
}
|
|
|
|
// if just appeared onscreen
|
|
if (s->id == P_METEOR) {
|
|
if ((oldy < 0) && (s->y >= 0)) {
|
|
playfx(FX_METEOR);
|
|
}
|
|
}
|
|
|
|
// if off screen
|
|
if (s->y >= (SCREENH + s->img->h)) {
|
|
// die
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_UPSTAR) { // star at endgame
|
|
double oldy;
|
|
|
|
// rise to top of screen then die
|
|
oldy = s->y;
|
|
s->y = s->y - (s->ys*2);
|
|
|
|
// if off screen
|
|
if (s->y <= 0) {
|
|
// die
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_DRIP) { // water drip from melting tile
|
|
// fall downwards
|
|
if (isinwater(s) || isongroundpoint(s, s->x, s->y+1)) {
|
|
s->dead = D_FINAL;
|
|
} else {
|
|
s->y += s->fallspeed;
|
|
|
|
// gravity...
|
|
if ((timer % 10 == 0) && (s->fallspeed < FALLSPEED)) {
|
|
s->fallspeed++;
|
|
}
|
|
if (s->fallspeed > FALLSPEED) s->fallspeed = FALLSPEED;
|
|
}
|
|
|
|
// if off screen
|
|
if ((s->y <= 0) || (s->y >= (LEVELH*TILEH))) {
|
|
// die
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_BUBBLE) { // bubble effect
|
|
tiletype_t *tt;
|
|
// float up, die when we leave the water
|
|
tt = gettileat(s->x,s->y, NULL,NULL);
|
|
if (tt->water) {
|
|
s->y -= 0.5;
|
|
// move left/right
|
|
s->x += (sin(s->y/5)/5);
|
|
} else {
|
|
// die
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_ZAPPER) { // zapper effect
|
|
double degs;
|
|
/* timer1 is the frame
|
|
timer2 controls when to change frame
|
|
doomcount ?
|
|
*/
|
|
|
|
// die if level finished
|
|
if ((levelcomplete == LV_CLEAR) || (levelcomplete == LV_WAIT)) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
|
|
// move in figure 8 around player
|
|
s->x = s->owner->x;
|
|
s->y = s->owner->y;
|
|
|
|
degs = (double)s->timer3 * ((double)M_PI/(double)180);
|
|
|
|
s->x += (sin(degs)*(double)48);
|
|
s->y += (sin(degs*2)*(double)16);
|
|
|
|
// adjust position counter
|
|
s->timer3 += 3;
|
|
if (s->timer3 >= (360*2)) {
|
|
s->timer3 = 0;
|
|
}
|
|
|
|
// adjust frame
|
|
s->timer2--;
|
|
if (s->timer2 <= 0) {
|
|
s->timer1++;
|
|
if (s->timer1 >= imageset[P_ZAPPER].numimages) {
|
|
s->timer1 = 0;
|
|
}
|
|
s->timer2 = ZAPPERDELAY;
|
|
}
|
|
|
|
// adjust zap counter
|
|
if (s->timer4 > 0) {
|
|
s->timer4--;
|
|
}
|
|
} else if (s->id == P_CANNON) { // cannon effect
|
|
// die if owner dies
|
|
if (s->owner->dead) {
|
|
s->dead = D_FINAL;
|
|
} else if (s->owner->powerup == PW_CANNON) {
|
|
int targx,targy;
|
|
// try to stay behind player
|
|
targx = s->owner->x - (s->owner->dir * 32);
|
|
targy = s->owner->y;
|
|
if (s->x < targx) {
|
|
s->x += 2;
|
|
if (s->x > targx) s->x = targx;
|
|
}
|
|
if (s->y < targy) {
|
|
s->y += 2;
|
|
if (s->y > targy) s->y = targy;
|
|
}
|
|
if (s->x > targx) {
|
|
s->x -= 2;
|
|
if (s->x < targx) s->x = targx;
|
|
}
|
|
if (s->y > targy) {
|
|
s->y -= 2;
|
|
if (s->y < targy) s->y = targy;
|
|
}
|
|
}
|
|
|
|
} else if (s->id == P_GLOVE) { // boxing glove effect
|
|
// dies when the player finshes netting
|
|
if (!s->owner->netting) {
|
|
s->dead = D_FINAL;
|
|
} else {
|
|
// keep it at the end of the net
|
|
s->x = s->owner->x + (s->owner->netdir * s->owner->netlen);
|
|
s->y = s->owner->y - (s->owner->img->h/2) + 5;
|
|
s->dir = s->owner->dir;
|
|
}
|
|
} else if (s->id == P_MACE) { // mace slam effect
|
|
// dies when the player finishes slamming
|
|
if (!s->owner->slamming) {
|
|
s->dead = D_FINAL;
|
|
} else {
|
|
double dist;
|
|
// keep it at the end of the slam
|
|
dist = (s->owner->slamangle * (180/M_PI))/2;
|
|
|
|
s->x = s->owner->x + cos(s->owner->slamangle-(180*(M_PI/180)))*dist*s->owner->dir;
|
|
s->y = s->owner->y + sin(s->owner->slamangle-(180*(M_PI/180)))*dist + imageset[P_MACEPOWERUP].img[F_WALK1]->h/2;
|
|
s->dir = s->owner->dir;
|
|
}
|
|
} else if (s->id == P_RAT) {
|
|
if (inintro()) {
|
|
// move right FAST
|
|
double xpoint;
|
|
xpoint = (curlevel->powerupx * TILEW) + (TILEW/2);
|
|
if (s->x <= xpoint) {
|
|
int rv = B_FALSE;
|
|
rv = movex(s, s->speed, B_TRUE);
|
|
}
|
|
} else { // not in intro sequence
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff ,absxdiff;
|
|
tiletype_t *tunder;
|
|
|
|
/* distance to closest player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
// tile in front and below
|
|
tt = gettileat(s->x + s->dir*getspeed(s) + (s->dir * (s->img->w/2)),s->y + (TILEH/2),NULL,NULL);
|
|
// tile below
|
|
tunder = gettileat(s->x ,s->y + 1,NULL,NULL);
|
|
/* if there's a hole in front of us and below*/
|
|
if (tt->solid == S_NOTSOLID) {
|
|
// we're on a slope
|
|
if (tunder->solid == S_SLOPE) {
|
|
move = B_TRUE;
|
|
} else {
|
|
if (s->angry || boss) {
|
|
if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) {
|
|
/* if player is below, fall off */
|
|
if (xdiff <= (TILEW*8)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) {
|
|
if (globpowerup != PW_CAMERA) {
|
|
/* if player is at same level and close, jump */
|
|
if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) {
|
|
jump(s,D_RIGHT);
|
|
} else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) {
|
|
jump(s,D_LEFT);
|
|
}
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
if ((s->angry) || (boss)) {
|
|
if ((!s->jumping) && (!s->jumptimer)) {
|
|
|
|
/* if player is above us, jump */
|
|
if ( (player && (!player->dead) && (player->y < s->y)) ||
|
|
(player2 && (!player2->dead) && (player2->y < s->y))) {
|
|
if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) {
|
|
/* jump right */
|
|
jump(s, 1);
|
|
} else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) {
|
|
/* jump left */
|
|
jump(s, -1);
|
|
} else if ((player && (s->y - player->y <= (TILEH*6))) ||
|
|
(player2 && (s->y - player2->y <= (TILEH*6)))) {
|
|
if ((xdiff >= 0) && (xdiff < (TILEW*2))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
} else if ((xdiff <= 0) && (xdiff > -(TILEW*2))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
} else {
|
|
/* jump whichever way we're facing */
|
|
/*
|
|
s->jumpdir = s->dir;
|
|
s->jumping = 1;
|
|
s->jumpspeed = 5;
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else { // falling
|
|
tiletype_t *tunder, *t2under;
|
|
|
|
// tile below
|
|
tunder = gettileat(s->x ,s->y,NULL,NULL);
|
|
t2under = gettileat(s->x ,s->y+s->img->h,NULL,NULL);
|
|
if ((tunder->solid == S_SLOPE) || (t2under->solid == S_SLOPE)) {
|
|
movex(s, s->dir*getspeed(s), B_TRUE);
|
|
} else if (s->jumpdir) {
|
|
movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
}
|
|
}
|
|
} // end if inintro
|
|
} else if (s->id == P_ANT1) { // worker ant - moves like a rat
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff ,absxdiff;
|
|
tiletype_t *tunder;
|
|
|
|
/* distance to closest player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
// tile in front and below
|
|
tt = gettileat(s->x + s->dir*getspeed(s) + (s->dir * (s->img->w/2)),s->y + (TILEH/2),NULL,NULL);
|
|
// tile below
|
|
tunder = gettileat(s->x ,s->y + 1,NULL,NULL);
|
|
/* if there's a hole in front of us and below*/
|
|
if (tt->solid == S_NOTSOLID) {
|
|
// we're on a slope
|
|
if (tunder->solid == S_SLOPE) {
|
|
move = B_TRUE;
|
|
} else {
|
|
if (s->angry || boss) {
|
|
if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) {
|
|
/* if player is below, fall off */
|
|
if (xdiff <= (TILEW*8)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) {
|
|
if (globpowerup != PW_CAMERA) {
|
|
/* if player is at same level and close, jump */
|
|
if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) {
|
|
jump(s,D_RIGHT);
|
|
} else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) {
|
|
jump(s,D_LEFT);
|
|
}
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
if (s->angry) {
|
|
if ((!s->jumping) && (!s->jumptimer)) {
|
|
/* if player is above us, jump */
|
|
if ( (player && (!player->dead) && (player->y < s->y)) ||
|
|
(player2 && (!player2->dead) && (player2->y < s->y))) {
|
|
if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) {
|
|
/* jump right */
|
|
jump(s, 1);
|
|
} else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) {
|
|
/* jump left */
|
|
jump(s, -1);
|
|
} else if ((player && (s->y - player->y <= (TILEH*6))) ||
|
|
(player2 && (s->y - player2->y <= (TILEH*6)))) {
|
|
if ((xdiff >= 0) && (xdiff < (TILEW*2))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
} else if ((xdiff <= 0) && (xdiff > -(TILEW*2))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
} else {
|
|
/* jump whichever way we're facing */
|
|
/*
|
|
s->jumpdir = s->dir;
|
|
s->jumping = 1;
|
|
s->jumpspeed = 5;
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else { // falling
|
|
tiletype_t *tunder, *t2under;
|
|
|
|
// tile below
|
|
tunder = gettileat(s->x ,s->y,NULL,NULL);
|
|
t2under = gettileat(s->x ,s->y+s->img->h,NULL,NULL);
|
|
if ((tunder->solid == S_SLOPE) || (t2under->solid == S_SLOPE)) {
|
|
movex(s, s->dir*getspeed(s), B_TRUE);
|
|
} else if (s->jumpdir) {
|
|
movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
}
|
|
}
|
|
} else if (s->id == P_ANT2) { // soldier ant - moves like a tick
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff;
|
|
|
|
/* distance to player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL);
|
|
/* if there's a hole in front of us */
|
|
if (tt->solid == S_NOTSOLID) {
|
|
double ycutoff = s->y + (TILEH/2);
|
|
if ((player && (player->y >= ycutoff)) || (player2 && (player2->y >= ycutoff ))) {
|
|
/* if player is below and nearby, fall off */
|
|
if (xdiff <= (TILEW*16)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if ((player && (player->y == s->y)) || (player2 && (player2->y == s->y ))) {
|
|
if (globpowerup != PW_CAMERA) {
|
|
/* if player is at same level and close, jump */
|
|
if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) {
|
|
jump(s,D_RIGHT);
|
|
} else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) {
|
|
jump(s,D_LEFT);
|
|
}
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
|
|
|
|
/* moves like an angry rat all the time */
|
|
if (globpowerup != PW_CAMERA) {
|
|
if ((playersalive()) && (!s->jumping) && (!s->jumptimer)) {
|
|
sprite_t *abovep;
|
|
/* if player is above us...*/
|
|
abovep = isplayerabove(s);
|
|
if (abovep) {
|
|
if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { // if 2-3 tiles right
|
|
/* jump right */
|
|
jump(s, D_RIGHT);
|
|
} else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { // if 2-3 tiles left
|
|
/* jump left */
|
|
jump(s, D_LEFT);
|
|
} else if (s->y - abovep->y <= (TILEH*6)) { // player less than 6 tiles above
|
|
if ((xdiff >= 0) && (xdiff < (TILEW*4))) { // ... and within 4 tiles
|
|
/* jump up */
|
|
jump(s, 0);
|
|
} else if ((xdiff <= 0) && (xdiff > -(TILEW*4))) { // ... and within 4 tiles
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else { // falling
|
|
movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
}
|
|
} else if (s->id == P_ANT3) { // moves like a snake
|
|
/* timer1 loopsfrom 0 - 19
|
|
|
|
if timer2 is 0, we can shoot. if it is 1, we can't.
|
|
|
|
*/
|
|
|
|
// inc shooting timer
|
|
if (s->timer1) {
|
|
s->timer1--;
|
|
if (s->timer1 == 0) {
|
|
}
|
|
}
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff,ydiff;
|
|
|
|
/* distance to player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL);
|
|
/* if there's a hole in front of us */
|
|
if (tt->solid == S_NOTSOLID) {
|
|
if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) {
|
|
/* if player is below, fall off */
|
|
if (xdiff <= (TILEW*8)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) {
|
|
if (s->angry) {
|
|
/* if player is at same level and close, jump */
|
|
if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) {
|
|
jump(s,D_RIGHT);
|
|
} else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) {
|
|
jump(s,D_LEFT);
|
|
}
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* shoot */
|
|
ydiff = getydisttoplayer(s);
|
|
ydiff = abs(ydiff);
|
|
|
|
// if there's a player close up/down...
|
|
if (ydiff <= (TILEH*4)) {
|
|
sprite_t *ss;
|
|
sprite_t *closeplayer;
|
|
int shoot = B_FALSE;
|
|
if (player && (s->y - player->y <= (TILEH*12)) ) {
|
|
closeplayer = player;
|
|
} else if (player2 && (s->y - player2->y <= (TILEH*12))) {
|
|
closeplayer = player2;
|
|
} else {
|
|
closeplayer = NULL;
|
|
}
|
|
|
|
if (closeplayer) {
|
|
if (s->bullet == NULL) { // if we don't already have a bullet
|
|
// if we are facing the player
|
|
if ( (closeplayer->x < s->x) && (s->dir == D_LEFT) ) {
|
|
shoot = B_TRUE;
|
|
} else if ( (closeplayer->x > s->x) && (s->dir == D_RIGHT) ) {
|
|
shoot = B_TRUE;
|
|
}
|
|
}
|
|
if (globpowerup == PW_CAMERA) shoot = B_FALSE;
|
|
if (shoot) {
|
|
// if our shooting timer is okay
|
|
if (s->timer1 == 0) {
|
|
playfx(FX_METEOR);
|
|
ss = addsprite(P_FIREBALL,s->x,s->y - s->img->h/2,"spit" );
|
|
ss->ys = 0;
|
|
ss->xs = s->dir * (getspeed(s)*2);
|
|
ss->dir = s->dir;
|
|
ss->owner = s;
|
|
|
|
s->bullet = ss;
|
|
|
|
// start timer for shooting again
|
|
s->timer1 = 200;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
|
|
if (globpowerup != PW_CAMERA) {
|
|
if (playersalive() && (!s->jumping) && (!s->jumptimer)) {
|
|
/* if player is above us, jump */
|
|
if ( (player && (!player->dead) && (player->y < s->y)) ||
|
|
(player2 && (!player2->dead) && (player2->y < s->y))) {
|
|
if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) {
|
|
/* jump right */
|
|
jump(s, 1);
|
|
} else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) {
|
|
/* jump left */
|
|
jump(s, -1);
|
|
} else if ((player && (s->y - player->y <= (TILEH*6))) ||
|
|
(player2 && (s->y - player2->y <= (TILEH*6)))) {
|
|
if ((xdiff >= 0) && (xdiff < (TILEW*2))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
} else if ((xdiff <= 0) && (xdiff > -(TILEW*2))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
} else {
|
|
/* jump whichever way we're facing */
|
|
/*
|
|
s->jumpdir = s->dir;
|
|
s->jumping = 1;
|
|
s->jumpspeed = 5;
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else { // falling
|
|
movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
}
|
|
|
|
} else if (s->id == P_SNAIL) {
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff;
|
|
|
|
|
|
/* distance to closest player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
tt = gettileat(s->x + s->dir+getspeed(s) + (s->dir * (s->img->w/2)),s->y,NULL,NULL);
|
|
/* if there's a hole in front of us */
|
|
if (tt->solid == S_NOTSOLID) {
|
|
if (s->angry || boss) {
|
|
if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) {
|
|
/* if player is below, fall off */
|
|
if (xdiff <= (TILEW*8)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
// always move
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
// jump?
|
|
if (boss) {
|
|
if ((!s->jumping) && (!s->jumptimer)) {
|
|
/* if player is above us or at same level...*/
|
|
if ( (player && (!player->dead) && (player->y <= s->y-TILEH)) ||
|
|
(player2 && (!player2->dead) && (player2->y <= s->y-TILEH))) {
|
|
int ydiff;
|
|
|
|
if (player && (!player->dead) && (player->y <= s->y-TILEH)) {
|
|
ydiff = s->y - player->y;
|
|
} else {
|
|
ydiff = s->y - player2->y;
|
|
}
|
|
|
|
if ((ydiff >= (TILEH*4)) && (ydiff <= (TILEH*8))) { // player between 4 and 8 tiles above
|
|
if (xdiff <= (TILEW*16)) { // if closeish horizontally
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
} else if ((xdiff >= (TILEW*1)) && (xdiff <= (TILEW*9))) { // if 1-9 tiles right
|
|
if (s->dir == D_RIGHT) {
|
|
/* jump right */
|
|
jump(s, D_RIGHT);
|
|
}
|
|
} else if ((xdiff <= -(TILEW*1)) && (xdiff >= -(TILEW*9))) { // if 1-9 tiles left
|
|
if (s->dir == D_LEFT) {
|
|
/* jump left */
|
|
jump(s, D_LEFT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} else { // falling
|
|
if (s->recoiling) {
|
|
// fall backwards
|
|
rv = movex(s, -s->dir*getspeed(s), B_TRUE);
|
|
} else if (s->jumpdir) {
|
|
movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
}
|
|
}
|
|
} else if (s->id == P_FROG) {
|
|
if (isinwater(s)) {
|
|
// move like a fish
|
|
double absxs,absys;
|
|
|
|
s->flies = B_TRUE;
|
|
s->falling = B_FALSE;
|
|
|
|
if ((s->xs == -99) || (s->ys == -99)) {
|
|
s->xs = getspeed(s) * s->dir;
|
|
s->ys = getspeed(s);
|
|
}
|
|
|
|
if (s->xs > 0) absxs = 1;
|
|
else absxs = -1;
|
|
|
|
if (s->ys > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
/* can we move? */
|
|
tt = gettileat(s->x + (s->dir * ((s->img->w/2)+3)) + s->xs , s->y-(s->img->h/2),NULL,NULL);
|
|
if ((tt->solid) || (tt->spikes )) {
|
|
/* turn */
|
|
s->xs = -s->xs;
|
|
}
|
|
|
|
tt = gettileat(s->x, s->y-(s->img->h/2) + s->ys,NULL,NULL);
|
|
if ((tt->solid) || (tt->spikes) ) {
|
|
/* turn */
|
|
s->ys = -s->ys;
|
|
} else if (!tt->water) {
|
|
s->flies = B_FALSE;
|
|
// exit water
|
|
jump(s, s->dir);
|
|
// force big jump
|
|
s->jumpspeed = FROGJUMPSPEED2;
|
|
|
|
}
|
|
/* move */
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
s->dir = absxs;
|
|
s->moved = MV_WALK;
|
|
} else {
|
|
// for if we get back in the water
|
|
s->xs = -99;
|
|
s->ys = -99;
|
|
s->flies = B_FALSE;
|
|
|
|
// timer3 used for pause inbetween jump
|
|
if ((!s->falling) && (!s->jumping)) {
|
|
if (s->timer3) {
|
|
s->timer3--;
|
|
} else {
|
|
// jump forwards
|
|
jump(s, s->dir);
|
|
s->timer3 = FROGPAUSE;
|
|
}
|
|
} else { // falling
|
|
int rv;
|
|
// move forwards
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv == NM_SIDE) { // bounce off walls
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
}
|
|
}
|
|
} else if (s->id == P_SLUG) {
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff;
|
|
sprite_t *target = NULL;
|
|
|
|
/* distance to closest player */
|
|
xdiff = getxdisttoplayer(s, &target);
|
|
if (target != NULL) {
|
|
absxdiff = abs(xdiff);
|
|
xdiff = target->x - s->x;
|
|
|
|
tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL);
|
|
/* if there's a hole in front of us */
|
|
if (tt->solid == S_NOTSOLID) {
|
|
if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) {
|
|
/* if player is below and nearby, fall off */
|
|
if (xdiff <= (TILEW*16)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) {
|
|
if (globpowerup != PW_CAMERA) {
|
|
/* if player is at same level and close, try to jump over the gap */
|
|
if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*9))) {
|
|
jump(s,D_RIGHT);
|
|
} else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*9))) {
|
|
jump(s,D_LEFT);
|
|
}
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
|
|
|
|
if (globpowerup != PW_CAMERA) {
|
|
/* moves like an angry rat all the time */
|
|
if ((!s->jumping) && (!s->jumptimer)) {
|
|
/* if player is above us or at same level...*/
|
|
if ( (player && (!player->dead) && (player->y <= s->y)) ||
|
|
(player2 && (!player2->dead) && (player2->y <= s->y))) {
|
|
int ydiff;
|
|
|
|
if ( (player && (!player->dead) && (player->y <= s->y))) {
|
|
ydiff = s->y - player->y;
|
|
} else if (player2) {
|
|
ydiff = s->y - player2->y;
|
|
} else {
|
|
ydiff = 999;
|
|
}
|
|
|
|
if (isplayerabove(s) && (ydiff >= (TILEH*4)) && (ydiff <= (TILEH*8))) { // player between 4 and 8 tiles above
|
|
if (xdiff <= (TILEW*8)) { // if closeish horizontally
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
} else if ((xdiff >= (TILEW*1)) && (xdiff <= (TILEW*10))) { // if 1-9 tiles right
|
|
if (s->dir == D_RIGHT) {
|
|
/* jump right */
|
|
jump(s, D_RIGHT);
|
|
}
|
|
} else if ((xdiff <= -(TILEW*1)) && (xdiff >= -(TILEW*10))) { // if 1-9 tiles left
|
|
if (s->dir == D_LEFT) {
|
|
/* jump left */
|
|
jump(s, D_LEFT);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else { // falling
|
|
int rv;
|
|
// move forwards
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
}
|
|
} else if (s->id == P_PLANT) {
|
|
/* timer1 loopsfrom 0 - 19
|
|
|
|
if timer1 is 0, we can shoot. if it is 1, we can't.
|
|
|
|
*/
|
|
|
|
// don't move!
|
|
s->moved = MV_WALK;
|
|
|
|
|
|
if (!s->falling) {
|
|
int xdiff, absxdiff;
|
|
sprite_t *pp;
|
|
|
|
/* distance to player */
|
|
xdiff = getxdisttoplayer(s, &pp);
|
|
if (pp) {
|
|
absxdiff = abs(xdiff);
|
|
|
|
if (!s->bullet) {
|
|
if (s->timer1 == 0) {
|
|
if ((pp->y < s->y) && (absxdiff <= (TILEW*4)) ) {
|
|
sprite_t *ss;
|
|
ss = addsprite(P_FIREUP,s->x,s->y - TILEH,"fireup" );
|
|
ss->ys = -4;
|
|
ss->xs = 0;
|
|
ss->dir = s->dir;
|
|
|
|
ss->owner = s;
|
|
s->bullet = ss;
|
|
|
|
// remember our starting y pos.
|
|
ss->timer1 = ss->y;
|
|
|
|
// reset out shoot timer
|
|
s->timer1 = 75;
|
|
}
|
|
} else {
|
|
s->timer1--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (s->id == P_KINGRAT) {
|
|
/* timer1 is state
|
|
|
|
0 == walk back and forth
|
|
|
|
|
|
timer2 counts down, at zero we change state
|
|
*/
|
|
if (s->timer1 == KRS_WALK) {
|
|
int canseeplayer = B_TRUE;
|
|
int ydis;
|
|
// move
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
// if player is in front, charge!
|
|
if (!playersalive()) {
|
|
canseeplayer = B_FALSE;
|
|
} else {
|
|
if (player) {
|
|
ydis = abs(s->y - player->y);
|
|
if (ydis > 2) {
|
|
canseeplayer = B_FALSE;
|
|
} else if ((s->dir < 0) && (player->x > s->x)) {
|
|
canseeplayer = B_FALSE;
|
|
} else if ((s->dir > 0) && (player->x < s->x)) {
|
|
canseeplayer = B_FALSE;
|
|
}
|
|
}
|
|
if ((canseeplayer == B_TRUE) && (player2)) {
|
|
ydis = abs(s->y - player2->y);
|
|
if (ydis > 2) {
|
|
canseeplayer = B_FALSE;
|
|
} else if ((s->dir < 0) && (player2->x > s->x)) {
|
|
canseeplayer = B_FALSE;
|
|
} else if ((s->dir > 0) && (player2->x < s->x)) {
|
|
canseeplayer = B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (canseeplayer) {
|
|
// CHARGE!
|
|
playfx(FX_BOSSWINDUP);
|
|
s->timer1 = KRS_CHARGEWAIT;
|
|
s->timer2 = KR_NUMJUMPS;
|
|
} else {
|
|
// dec timer
|
|
s->timer2--;
|
|
if (s->timer2 == 0) {
|
|
if (!playersalive()) {
|
|
// reset timer
|
|
s->timer2 = KR_WALKTIME;
|
|
} else {
|
|
// jump to player's height
|
|
s->timer1 = KRS_JUMP;
|
|
}
|
|
}
|
|
}
|
|
} else if (s->timer1 == KRS_CHARGEWAIT) {
|
|
// jump timer2 times.
|
|
|
|
if (timer % 2 == 0) {
|
|
// add puffs
|
|
puffin(-1, s->x + (rand() % (s->img->w)) - (s->img->w/2), s->y, "nothing", rand() % 5);
|
|
}
|
|
|
|
if (!s->jumping && !s->falling) {
|
|
s->timer2--;
|
|
if ((s->timer2 <= 0) && (!s->jumping)){
|
|
//CHARGE
|
|
s->timer1 = KRS_CHARGE;
|
|
s->flies = B_TRUE;
|
|
playfx(FX_BOSSCHARGE);
|
|
} else {
|
|
// bounce
|
|
jump(s,0);
|
|
s->jumpspeed = 1;
|
|
}
|
|
}
|
|
} else if (s->timer1 == KRS_CHARGE) {
|
|
int rv;
|
|
// move fast forwards
|
|
rv = movex(s, s->dir*KR_CHARGESPEED, B_TRUE);
|
|
if (rv) {
|
|
// hit a wall - get stunned
|
|
s->timer1 = KRS_STUN;
|
|
s->timer2 = KR_STUNTIME;
|
|
s->flies = B_FALSE;
|
|
|
|
playfx(FX_BOSSWALL);
|
|
|
|
// shake the screen via a fake player powerup
|
|
globpowerup = PW_RATSHAKE;
|
|
globtimer = RATSHAKETIME;
|
|
}
|
|
} else if (s->timer1 == KRS_STUN) {
|
|
s->timer2--;
|
|
if (s->timer2 == 0) {
|
|
s->timer1 = KRS_WALK;
|
|
s->timer2 = KR_WALKTIME;
|
|
}
|
|
} else if (s->timer1 == KRS_JUMP) {
|
|
// jump to closest player height
|
|
if (!s->jumping) {
|
|
int ydis;
|
|
int try;
|
|
int tot;
|
|
int n;
|
|
|
|
if ((!playersalive()) || isplayerbelow(s) ) { // player below or dead
|
|
try = 2;
|
|
} else {
|
|
// get distance
|
|
ydis = getydisttoplayer(s);
|
|
ydis = abs(ydis);
|
|
// figure out how much we need to jump
|
|
for (try = 2; try < (KR_MAXJUMP-1); try++) {
|
|
tot = 0;
|
|
for (n = try; n >= 1; n--) {
|
|
tot = tot + (5*n);
|
|
}
|
|
if (tot >= ydis) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
jump(s, 0);
|
|
// manually adjust speed
|
|
try++; // one more just to be sure
|
|
s->willjumpspeed = try;
|
|
|
|
// next state
|
|
s->timer1 = KRS_WAITFORTOP;
|
|
}
|
|
} else if (s->timer1 == KRS_WAITFORTOP) {
|
|
if (!s->jumping) {
|
|
s->timer1 = KRS_FALL;
|
|
}
|
|
} else if (s->timer1 == KRS_FALL) {
|
|
// fall to player height
|
|
if (!s->jumping && ((player && (s->y >= player->y)) || (player2 && (s->y >= player2->y))) ) {
|
|
// back to normal state but lower timer
|
|
s->timer1 = KRS_WALK;
|
|
s->timer2 = KR_WALKTIME; // low delay
|
|
}
|
|
}
|
|
|
|
|
|
} else if (s->id == P_KINGSNAIL) {
|
|
/* timer1 is state
|
|
|
|
0 == walk back and forth
|
|
|
|
|
|
timer2 counts down, at zero we change state
|
|
*/
|
|
if ((s->timer1 == KSS_WALK1) || (s->timer1 == KSS_WALK2)) {
|
|
// walk back and forth
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
// dec timer
|
|
s->timer2--;
|
|
if (s->timer2 == 0) {
|
|
if (!playersalive()) {
|
|
// reset timer
|
|
s->timer2 = KR_WALKTIME;
|
|
} else {
|
|
// release snails or jump, depending on state
|
|
|
|
if ((countmonsters(P_SNAIL) == 0) || (s->timer1 == KSS_WALK1)) { // next state is shooting
|
|
s->timer1 = KSS_PAUSE1;
|
|
s->timer2 = KS_SHOOTWAIT;
|
|
playfx(FX_SNAILPREPARE);
|
|
} else { // next state is jump
|
|
s->timer1 = KSS_PAUSE2;
|
|
s->timer2 = KS_JUMPWAIT;
|
|
}
|
|
}
|
|
}
|
|
} else if (s->timer1 == KSS_PAUSE1) {
|
|
// add puffs on shell
|
|
if (timer % 6 == 0) {
|
|
puffin(-1, s->x + -s->dir*((s->img->w/4) + (rand() % 7)-3),
|
|
s->y-(s->img->h/2) - (rand() % 7) - 3, "nothing", rand() % 5);
|
|
}
|
|
s->timer2--;
|
|
if (s->timer2 == 0) {
|
|
sprite_t *newsp;
|
|
// shoot!
|
|
s->timer1 = KSS_SHOOT;
|
|
// shell cracks
|
|
playfx(FX_CRACK);
|
|
newsp = addsprite(P_KSSHELL, s->x + -s->dir*((s->img->w/4) + (rand() % 7)-3),
|
|
s->y-(s->img->h/2) - (rand() % 7) - 3, "ksshell");
|
|
|
|
// the shell recoils (other code will kill us off when this is done)
|
|
// -become invulnerable temporarily
|
|
newsp->invuln = INVULNTIME*2; // make sure this lasts until we die
|
|
// -bounce back
|
|
newsp->recoiling = B_TRUE;
|
|
jump(newsp,-s->dir); // ie. away from king snail
|
|
}
|
|
|
|
} else if (s->timer1 == KSS_SHOOT) {
|
|
// shoot out snails
|
|
if (timer % 20 == 0) {
|
|
if (countmonsters(-1) < 6) { // max 5 snails + king snail
|
|
sprite_t *newsp;
|
|
newsp = addsprite(P_SNAIL, s->x + -s->dir*(s->img->w/4), s->y-(s->img->h/2),"babsnail");
|
|
// make it shoot upwards
|
|
newsp->jumping = 1;
|
|
newsp->jumpspeed = (rand() % 7) + 7; // 7 - 13
|
|
newsp->jumpdir = (((double)(rand() % 110) - 50) / 10); // -5 to 5
|
|
if (rand() % 2) newsp->dir = 1;
|
|
else newsp->dir = -1;
|
|
playfx(FX_WHOOSH);
|
|
} else {
|
|
// enough, regenerate shell
|
|
s->timer1 = KSS_REGEN;
|
|
s->timer3 = 1; // percentage of shell size
|
|
}
|
|
}
|
|
} else if (s->timer1 == KSS_REGEN) {
|
|
// shell gets bigger
|
|
s->timer3++;
|
|
|
|
// wait for shell to finish
|
|
if (s->timer3 >= 120) {
|
|
// walk again
|
|
s->timer1 = KSS_WALK2;
|
|
s->timer2 = KS_WALKTIME;
|
|
}
|
|
|
|
} else if (s->timer1 == KSS_PAUSE2) {
|
|
if (!s->jumptimer) {
|
|
int ydis;
|
|
int try;
|
|
int tot;
|
|
int n;
|
|
|
|
// remember our height
|
|
s->timer3 = s->y;
|
|
|
|
// delay then jump
|
|
s->jumptimer = getjumpdelay(s->id);
|
|
s->jumpdir = 0;
|
|
|
|
if ((!playersalive()) || isplayerbelow(s)) { // player below or dead
|
|
try = 2;
|
|
} else {
|
|
// get distance
|
|
ydis = getydisttoplayer(s);
|
|
ydis = abs(ydis);
|
|
// figure out how much we need to jump
|
|
for (try = 2; try < (KR_MAXJUMP-1); try++) {
|
|
tot = 0;
|
|
for (n = try; n >= 1; n--) {
|
|
tot = tot + (5*n);
|
|
}
|
|
if (tot >= ydis) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
jump(s, 0);
|
|
// manually adjust speed
|
|
try++; // one more just to be sure
|
|
s->willjumpspeed = try;
|
|
|
|
// next state
|
|
s->timer1 = KSS_JUMPING;
|
|
}
|
|
} else if (s->timer1 == KSS_JUMPING) {
|
|
// wait until we land...
|
|
if (!s->jumptimer && !s->jumping && !s->falling) {
|
|
sprite_t *ss, *nexts;
|
|
|
|
// snails turn to slugs!!
|
|
for (ss = sprite ; ss ; ss = nexts) {
|
|
nexts = ss->next;
|
|
if ((ss->id == P_SNAIL) && !ss->caughtby && !ss->dead) {
|
|
die(ss);
|
|
}
|
|
}
|
|
// now pause a while before moving again
|
|
s->timer1 = KSS_PAUSE3;
|
|
s->timer2 = KS_RELOADWAIT;
|
|
|
|
// shake the screen via a fake player powerup
|
|
playfx(FX_BOSSWALL);
|
|
globpowerup = PW_SNAILSHAKE;
|
|
globtimer = SNAILSHAKETIME;
|
|
|
|
}
|
|
} else if (s->timer1 == KSS_PAUSE3) {
|
|
s->timer2--;
|
|
if (s->timer2 == 0) {
|
|
// go back to start!
|
|
s->timer1 = KSS_WALK1;
|
|
s->timer2 = KS_WALKTIME;
|
|
}
|
|
}
|
|
|
|
} else if (s->id == P_KINGFLY) {
|
|
double absxs,absys;
|
|
if ((s->timer1 == KFS_FLY1) || (s->timer1 == KFS_FLY2)) {
|
|
if ((s->xs == -99) || (s->ys == -99)) {
|
|
s->xs = getspeed(s);
|
|
s->ys = getspeed(s);
|
|
}
|
|
|
|
if (s->xs > 0) absxs = 1;
|
|
else absxs = -1;
|
|
|
|
if (s->ys > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
/* this will fix the speed if ANGRY is set */
|
|
s->xs = absxs*getspeed(s);
|
|
s->ys = absys*getspeed(s);
|
|
|
|
|
|
/* can we move? */
|
|
if (s->x >= SCREENW - (s->img->w/2) - 2) {
|
|
/* turn */
|
|
s->xs = -abs(s->xs);
|
|
} else if (s->x <= (s->img->w/2)) {
|
|
s->xs = abs(s->xs);
|
|
}
|
|
|
|
|
|
if (s->y <= s->img->h) {
|
|
s->ys = abs(s->ys);
|
|
} else if (s->y >= SCREENH-2 ) {
|
|
s->ys = -abs(s->ys);
|
|
}
|
|
|
|
/* move */
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
s->dir = absxs;
|
|
s->moved = MV_FLY;
|
|
|
|
// generate babies
|
|
if (timer % 25 == 0) {
|
|
int numbabies, numflies;
|
|
sprite_t *ss;
|
|
|
|
numflies = countmonsters(P_FLY);
|
|
// count how many babies we have
|
|
numbabies = 0;
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_FLY) && (ss->owner == s)) {
|
|
numbabies++;
|
|
}
|
|
}
|
|
|
|
|
|
if (numflies < 12) {
|
|
if (numbabies < 6) {
|
|
sprite_t *newsp;
|
|
puffin(-1, s->x, s->y, "nothing", 0);
|
|
newsp = addsprite(P_FLY, s->x, s->y, "gen_fly");
|
|
newsp->invuln = FLYINVULNTIME * (numbabies+1);
|
|
newsp->xs = s->xs;
|
|
newsp->ys = s->ys;
|
|
newsp->owner = s;
|
|
}
|
|
}
|
|
}
|
|
|
|
s->timer2--;
|
|
if (s->timer2 <= 0) {
|
|
if ((s->y >= s->img->h*4) && (s->y <= (SCREENH-s->img->h*2))) {
|
|
if ((s->x >= s->img->w) && (s->x <= SCREENW-(s->img->w))) {
|
|
if (s->timer1 == KFS_FLY1) {
|
|
s->timer1 = KFS_HORZWAIT;
|
|
s->timer3 = s->y;
|
|
} else {
|
|
s->timer1 = KFS_VERTWAIT;
|
|
s->timer3 = s->x;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (s->timer1 == KFS_HORZWAIT) {
|
|
double ymod;
|
|
sprite_t *ss;
|
|
int ready = B_TRUE;
|
|
// hover
|
|
s->ys = 2;
|
|
ymod = sin(((double)timer * (double)3.6) * (M_PI/180));
|
|
if (s->ys * (ymod) > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
s->y += (s->ys * ymod);
|
|
|
|
s->moved = MV_FLY;
|
|
|
|
|
|
// if all babies attached
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_FLY) && (ss->owner == s) && (ss->timer1 != KFS_HORZWAIT)) {
|
|
ready = B_FALSE;
|
|
}
|
|
}
|
|
|
|
if (ready) {
|
|
int numflies,n;
|
|
s->timer1 = KFS_HORZPUSH;
|
|
s->timer3 = s->y;
|
|
// set position for babies
|
|
numflies = countbabies(s, P_FLY);
|
|
n = 1;
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_FLY) && (ss->owner == s)) {
|
|
ss->timer1 = KFS_HORZPUSH;
|
|
ss->timer2 = n * (SCREENW/(numflies+1)); // target x
|
|
//printf("setting target to %d\n",ss->timer2);
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
} else if (s->timer1 == KFS_HORZPUSH) {
|
|
double ymod;
|
|
int ready = B_TRUE;
|
|
sprite_t *ss;
|
|
|
|
// hover
|
|
s->ys = 2;
|
|
ymod = sin(((double)timer * (double)3.6) * (M_PI/180));
|
|
if (s->ys * (ymod) > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
s->y += (s->ys * ymod);
|
|
|
|
s->moved = MV_FLY;
|
|
|
|
// if all flies in position, release them
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_FLY) && (ss->owner == s) && (ss->x != ss->timer2)) {
|
|
ready = B_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (ready) {
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_FLY) && (ss->owner = s)) {
|
|
// release it!
|
|
ss->owner = NULL;
|
|
}
|
|
}
|
|
|
|
s->timer1 = KFS_HORZ;
|
|
s->timer2 = KF_HOVERTIME;
|
|
|
|
}
|
|
} else if (s->timer1 == KFS_HORZ) {
|
|
double ymod;
|
|
// hover
|
|
s->ys = 2;
|
|
ymod = sin(((double)timer * (double)3.6) * (M_PI/180));
|
|
if (s->ys * (ymod) > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
s->y += (s->ys * ymod);
|
|
|
|
s->moved = MV_FLY;
|
|
|
|
s->timer2--;
|
|
if (s->timer2 == 0) {
|
|
// fly around again
|
|
s->timer1 = KFS_FLY2;
|
|
s->timer2 = KF_FLYTIME;
|
|
s->timer3 = 0;
|
|
}
|
|
} else if (s->timer1 == KFS_VERTWAIT) {
|
|
double ymod;
|
|
sprite_t *ss;
|
|
int ready = B_TRUE;
|
|
// hover
|
|
s->ys = 2;
|
|
ymod = sin(((double)timer * (double)3.6) * (M_PI/180));
|
|
if (s->ys * (ymod) > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
s->y += (s->ys * ymod);
|
|
|
|
s->moved = MV_FLY;
|
|
|
|
|
|
// if all babies attached
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_FLY) && (ss->owner == s) && (ss->timer1 != KFS_VERTWAIT)) {
|
|
ready = B_FALSE;
|
|
}
|
|
}
|
|
|
|
if (ready) {
|
|
int numflies,n;
|
|
s->timer1 = KFS_VERTPUSH;
|
|
s->timer3 = s->x;
|
|
// set position for babies
|
|
numflies = countbabies(s, P_FLY);
|
|
n = 1;
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_FLY) && (ss->owner == s)) {
|
|
ss->timer1 = KFS_VERTPUSH;
|
|
ss->timer2 = n * (SCREENH/(numflies+1)); // target x
|
|
//printf("setting target to y = %d\n",ss->timer2);
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
} else if (s->timer1 == KFS_VERTPUSH) {
|
|
double ymod;
|
|
int ready = B_TRUE;
|
|
sprite_t *ss;
|
|
|
|
// hover
|
|
s->ys = 2;
|
|
ymod = sin(((double)timer * (double)3.6) * (M_PI/180));
|
|
if (s->ys * (ymod) > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
s->y += (s->ys * ymod);
|
|
|
|
s->moved = MV_FLY;
|
|
|
|
// if all flies in position, release them
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_FLY) && (ss->owner == s) && (ss->y != ss->timer2)) {
|
|
ready = B_FALSE;
|
|
break;
|
|
}
|
|
}
|
|
if (ready) {
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == P_FLY) && (ss->owner = s)) {
|
|
// release it!
|
|
ss->owner = NULL;
|
|
}
|
|
}
|
|
|
|
s->timer1 = KFS_VERT;
|
|
s->timer2 = KF_HOVERTIME;
|
|
|
|
}
|
|
} else if (s->timer1 == KFS_VERT) {
|
|
double ymod;
|
|
// hover
|
|
s->ys = 2;
|
|
ymod = sin(((double)timer * (double)3.6) * (M_PI/180));
|
|
if (s->ys * (ymod) > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
s->y += (s->ys * ymod);
|
|
|
|
s->moved = MV_FLY;
|
|
|
|
s->timer2--;
|
|
if (s->timer2 == 0) {
|
|
// fly around again
|
|
s->timer1 = KFS_FLY1;
|
|
s->timer2 = KF_FLYTIME;
|
|
}
|
|
}
|
|
} else if (s->id == P_KINGANT) {
|
|
/*
|
|
- Move back and forth for a while
|
|
- spawn out ants if not enough
|
|
|
|
- Jump to top, destroying platforms
|
|
|
|
- Move back and forth for a while
|
|
- spawn out ant food
|
|
|
|
- Jump to bottom, destroying platforms
|
|
*/
|
|
// add flames on it
|
|
if (( timer % 2) == 0) {
|
|
addsprite(P_FLAME, s->x + (rand() % s->img->w) - (s->img->w/2),
|
|
s->y - (s->img->h/2) + (rand() % s->img->h/2), "antflame");
|
|
}
|
|
|
|
// move back and forth
|
|
if ((s->timer1 == KAS_WALK1) || (s->timer1 == KAS_WALK2)) {
|
|
// move
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
|
|
// shoot out monsters
|
|
s->timer3--;
|
|
|
|
if (s->timer3 <= 0) {
|
|
// reset shoot timer
|
|
s->timer3 = KA_SHOOTTIME;
|
|
|
|
if (s->timer1 == KAS_WALK1) {
|
|
// shoot an ant out
|
|
if (countmonsters(-1) < 7) { // max 6 ants + king ant
|
|
sprite_t *newsp;
|
|
puffin(-1, s->x, s->y - (s->img->h/2), "nothing", 0);
|
|
newsp = addsprite(P_ANT1, s->x, s->y-(s->img->h/2),"babant");
|
|
// make it shoot upwards
|
|
newsp->jumping = 1;
|
|
newsp->jumpspeed = (rand() % 7) + 7; // 7 - 13
|
|
newsp->jumpdir = (((double)(rand() % 110) - 50) / 10); // -5 to 5
|
|
if (rand() % 2) newsp->dir = 1;
|
|
else newsp->dir = -1;
|
|
playfx(FX_WHOOSH);
|
|
} else {
|
|
// enough monsters, shoot food instead
|
|
sprite_t *newsp;
|
|
puffin(-1, s->x, s->y - (s->img->h/2), "nothing", 0);
|
|
newsp = addsprite(P_EGG, s->x, s->y-(s->img->h/2),"antegg");
|
|
// make it shoot upwards
|
|
newsp->jumping = 1;
|
|
newsp->jumpspeed = (rand() % 7) + 7; // 7 - 13
|
|
newsp->jumpdir = (((double)(rand() % 110) - 50) / 10); // -5 to 5
|
|
if (rand() % 2) newsp->dir = 1;
|
|
else newsp->dir = -1;
|
|
playfx(FX_WHOOSH);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// dec walk timer
|
|
s->timer2--;
|
|
if (s->timer2 == 0) {
|
|
if (playersalive()) {
|
|
// jump to other side height
|
|
if (s->timer1 == KAS_WALK1) s->timer1 = KAS_JUMP1;
|
|
else s->timer1 = KAS_JUMP2;
|
|
} else {
|
|
// nobody alive - reset timer
|
|
s->timer2 = KA_WALKTIME;
|
|
s->timer3 = KA_SHOOTTIME;
|
|
}
|
|
}
|
|
} else if ((s->timer1 == KAS_JUMP1) || (s->timer1 == KAS_JUMP2)) {
|
|
|
|
// jump to closest player height
|
|
if (!s->jumping) {
|
|
if (!playersalive() ) { // player below or dead
|
|
// go back to walking
|
|
s->timer1 = KAS_WALK1;
|
|
s->timer2 = KA_WALKTIME;
|
|
s->timer3 = KA_SHOOTTIME;
|
|
} else {
|
|
int jumpheight, jumptarget,nextstate;
|
|
jump(s, 0);
|
|
if (s->timer1 == KAS_JUMP1) {
|
|
jumpheight = 13;
|
|
jumptarget = TILEH*3; // jump to top
|
|
nextstate = KAS_WAITFORTOP1;
|
|
} else {
|
|
jumpheight = 3;
|
|
jumptarget = SCREENH - (TILEH*3); // jump to bottom
|
|
nextstate = KAS_WAITFORTOP2;
|
|
}
|
|
|
|
s->willjumpspeed = jumpheight;
|
|
|
|
// next state
|
|
s->timer1 = nextstate;
|
|
s->timer3 = jumptarget;
|
|
}
|
|
}
|
|
} else if (s->timer1 == KAS_WAITFORTOP1) {
|
|
if (!s->jumping) {
|
|
s->timer1 = KAS_FALL1;
|
|
}
|
|
} else if (s->timer1 == KAS_WAITFORTOP2) {
|
|
if (!s->jumping) {
|
|
s->timer1 = KAS_FALL2;
|
|
}
|
|
} else if ((s->timer1 == KAS_FALL1) || (s->timer1 == KAS_FALL2)) {
|
|
// King Ant's jump is handled specially in dogravity()
|
|
if (s->falling) {
|
|
if (!s->bullet) {
|
|
sprite_t *mytarget;
|
|
// shoot fireball if player in front!
|
|
mytarget = isplayerahead(s);
|
|
if (mytarget) {
|
|
sprite_t *ss;
|
|
// shoot!
|
|
playfx(FX_METEOR);
|
|
ss = addsprite(P_BIGFIREBALL,s->x,mytarget->y+(TILEH/2),"horzfireball" );
|
|
ss->ys = 0;
|
|
ss->xs = s->dir * 4;
|
|
ss->dir = s->dir;
|
|
ss->owner = s;
|
|
|
|
s->bullet = ss;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
// back to normal state
|
|
if (s->timer1 == KAS_FALL1) {
|
|
s->timer1 = KAS_WALK2;
|
|
} else {
|
|
s->timer1 = KAS_WALK1;
|
|
}
|
|
s->timer2 = KA_WALKTIME;
|
|
s->timer3 = KA_SHOOTTIME;
|
|
}
|
|
}
|
|
} else if (s->id == P_KINGCAT) {
|
|
/* timer1 is state
|
|
|
|
0 == walk back and forth
|
|
timer2 counts down, at zero we change state
|
|
1 == spell
|
|
|
|
|
|
*/
|
|
if (s->timer1 == KCS_WALK) {
|
|
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff ,absxdiff;
|
|
tiletype_t *tunder;
|
|
|
|
/* distance to closest player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
// tile in front and below
|
|
tt = gettileat(s->x + s->dir*getspeed(s) + (s->dir * (s->img->w/2)),s->y + (TILEH/2),NULL,NULL);
|
|
// tile below
|
|
tunder = gettileat(s->x ,s->y + 1,NULL,NULL);
|
|
/* if there's a hole in front of us and below*/
|
|
if (tt->solid == S_NOTSOLID) {
|
|
// we're on a slope
|
|
if (tunder->solid == S_SLOPE) {
|
|
move = B_TRUE;
|
|
} else {
|
|
if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) {
|
|
/* if player is below, fall off */
|
|
if (xdiff <= (TILEW*8)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) {
|
|
/* if player is at same level and close, jump */
|
|
if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*10))) {
|
|
jump(s,D_RIGHT);
|
|
} else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*10))) {
|
|
jump(s,D_LEFT);
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
if ((!s->jumping) && (!s->jumptimer)) {
|
|
/* if player is above us, jump */
|
|
if ( (player && (!player->dead) && (player->y < s->y)) ||
|
|
(player2 && (!player2->dead) && (player2->y < s->y))) {
|
|
if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*7))) {
|
|
/* jump right */
|
|
jump(s, 1);
|
|
} else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*7))) {
|
|
/* jump left */
|
|
jump(s, -1);
|
|
} else if ((player && (s->y - player->y <= (TILEH*6))) ||
|
|
(player2 && (s->y - player2->y <= (TILEH*6)))) {
|
|
if ((xdiff >= 0) && (xdiff < (TILEW*4))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
} else if ((xdiff <= 0) && (xdiff > -(TILEW*4))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
} else {
|
|
/* jump whichever way we're facing */
|
|
/*
|
|
s->jumpdir = s->dir;
|
|
s->jumping = 1;
|
|
s->jumpspeed = 5;
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
} else { // falling
|
|
tiletype_t *tunder, *t2under;
|
|
|
|
// tile below
|
|
tunder = gettileat(s->x ,s->y,NULL,NULL);
|
|
t2under = gettileat(s->x ,s->y+s->img->h,NULL,NULL);
|
|
if ((tunder->solid == S_SLOPE) || (t2under->solid == S_SLOPE)) {
|
|
movex(s, s->dir*getspeed(s), B_TRUE);
|
|
} else if (s->jumpdir) {
|
|
movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
}
|
|
}
|
|
|
|
// inc timer
|
|
if (s->timer2 == KC_WALKTIME) {
|
|
if (!playersalive()) {
|
|
// reset timer
|
|
s->timer2 = 0;
|
|
} else if (!s->jumping && !s->falling) {
|
|
// cast a spell
|
|
//TODO: sfx
|
|
s->timer1 = KCS_SPELLPAUSE;
|
|
s->timer2 = KC_SPELLPAUSETIME;
|
|
}
|
|
// otherwise wait until we're not jumping/falling
|
|
} else {
|
|
s->timer2++;
|
|
}
|
|
} else if (s->timer1 == KCS_SPELLPAUSE) {
|
|
// go to pause frame...
|
|
if (timer % 2 == 0) {
|
|
// add puffs above
|
|
puffin(-1, s->x + (rand() % (s->img->w)) - (s->img->w/2),
|
|
s->y - (s->img->h) + (rand() % TILEH) - (TILEH/2), "nothing", rand() % 5);
|
|
}
|
|
|
|
s->timer2--;
|
|
if (s->timer2 <= 0) {
|
|
//CHARGE
|
|
selectspell(s);
|
|
}
|
|
|
|
} else if (s->timer1 == KCS_SPELLCAST) {
|
|
if (s->timer3 == SPL_TELEPORT) {
|
|
// move to player
|
|
if (s->timer4 < KC_TELETIME) {
|
|
// add random puff at destination
|
|
puffin(-1, s->newx + (rand() % s->img->w) - (s->img->w/2),
|
|
s->newy - (rand() % s->img->h), "nothing", rand() % 5);
|
|
s->timer4++;
|
|
} else {
|
|
int x,y;
|
|
// cover destination with puffs
|
|
for (y = s->newy - s->img->h; y < s->newy; y += TILEH) {
|
|
for (x = s->newx - (s->img->w/2); x < s->newx + (s->img->w/2); x += TILEW) {
|
|
puffin(-1, x, y, "nothing", 0);
|
|
}
|
|
}
|
|
// teleport!
|
|
s->x = s->newx;
|
|
s->y = s->newy;
|
|
// finished
|
|
s->timer2 = 0;
|
|
}
|
|
} else if (s->timer3 == SPL_SUMMON) {
|
|
// summon monsters
|
|
int numsummon = 5,i;
|
|
if (s->timer2 == KC_SPELLCASTTIME) { // ie. once only.
|
|
for (i = 0; i < numsummon; i++) {
|
|
tiletype_t *tt = NULL;
|
|
int x = -1,y = -1;
|
|
int tooclose = B_TRUE;
|
|
while ((x == -1) || (y == -1) || !tt || tt->solid || tooclose) {
|
|
sprite_t *closeplayer = NULL;
|
|
tooclose = B_FALSE;
|
|
x = ((rand() % (LEVELW-1)) * TILEW) + (TILEW/2);
|
|
y = ((rand() % (LEVELH-1)) * TILEH) + (TILEH/2);
|
|
tt = gettileat(x, y, NULL, NULL);
|
|
closeplayer = getclosestplayerxy(x, y);
|
|
if (closeplayer) {
|
|
double dist;
|
|
dist = getdistance(x, y, closeplayer->x, closeplayer->y);
|
|
if (dist <= (5*TILEW)) {
|
|
// too close
|
|
tooclose = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
puffin(randommonster(), x, y, "randmonster", 0);
|
|
}
|
|
}
|
|
|
|
|
|
// delay before finishing.
|
|
if (s->timer2) s->timer2--;
|
|
} else if (s->timer3 == SPL_FIREBALLS) {
|
|
if (s->timer2 == KC_SPELLCASTTIME) { // ie. once only.
|
|
int dir;
|
|
playfx(FX_METEOR);
|
|
for (dir = -1; dir <= 1; dir += 2) {
|
|
sprite_t *ss;
|
|
// horz
|
|
ss = addsprite(P_BIGFIREBALL,s->x,s->y - (s->img->h / 2) ,"horzfireball" );
|
|
ss->ys = 0;
|
|
ss->xs = dir * 4;
|
|
ss->dir = dir;
|
|
// up
|
|
ss = addsprite(P_BIGFIREBALL,s->x,s->y - (s->img->h / 2) ,"up_horzfireball" );
|
|
ss->ys = -2;
|
|
ss->xs = dir * 4;
|
|
ss->dir = dir;
|
|
// down
|
|
ss = addsprite(P_BIGFIREBALL,s->x,s->y - (s->img->h / 2) ,"down_horzfireball" );
|
|
ss->ys = 2;
|
|
ss->xs = dir * 4;
|
|
ss->dir = dir;
|
|
}
|
|
}
|
|
s->timer2--;
|
|
} else if (s->timer3 == SPL_WIND) {
|
|
globpowerup = PW_CATWIND;
|
|
s->timer2--;
|
|
} else if (s->timer3 == SPL_BRICKS) {
|
|
globpowerup = PW_CATBRICKS;
|
|
s->timer2--;
|
|
}
|
|
|
|
|
|
// timer2 will become 0 once spell is finished.
|
|
if (s->timer2 <= 0) {
|
|
// turn off spell effects
|
|
|
|
switch (s->timer3) {
|
|
case SPL_WIND:
|
|
case SPL_BRICKS:
|
|
globpowerup = -1;
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
// back to walking.
|
|
s->timer1 = KCS_WALK;
|
|
s->timer2 = 0;
|
|
s->timer3 = 0;
|
|
s->timer4 = 0;
|
|
}
|
|
}
|
|
|
|
|
|
} else if (s->id == P_PLATFORM) { // moving platform
|
|
// timer1 tells whether we are at top speed
|
|
double dstx,dsty;
|
|
int rv;
|
|
|
|
if (s->numwaypoints > 0) {
|
|
sprite_t *s2;
|
|
double oldx,oldy,xdiff,ydiff;
|
|
|
|
if (s->timer1 == 0) {
|
|
oldx = s->x;
|
|
oldy = s->y;
|
|
// move torwaeds next waypoints
|
|
dstx = s->wayx[s->curwaypoint];
|
|
dsty = s->wayy[s->curwaypoint];
|
|
|
|
rv = moveto(s,dstx,dsty,s->speed,s->speed);
|
|
|
|
// remember how far we moved
|
|
xdiff = s->x - oldx;
|
|
ydiff = s->y - oldy;
|
|
|
|
// got there?
|
|
if (rv == 0) {
|
|
// pause
|
|
s->timer1 = PLATFORMPAUSE;
|
|
}
|
|
|
|
// move anything on top of us by the same amount
|
|
for (s2 = sprite ; s2 ; s2 = s2->next) {
|
|
if (s2->onplatform == s) {
|
|
int ii,oldmoved;
|
|
int preroof = B_FALSE;
|
|
double dir,amt;
|
|
amt = abs(xdiff);
|
|
if (xdiff > 0) dir = 1;
|
|
else dir = -1;
|
|
|
|
if (isroofabove(s2) && (ydiff < 0)) {
|
|
preroof = B_TRUE;
|
|
}
|
|
|
|
oldmoved = s2->moved;
|
|
|
|
for (ii = 0; ii < amt; ii++) {
|
|
//s2->x += dir;
|
|
if (movex(s2, dir, B_TRUE)) break;
|
|
}
|
|
s2->moved = oldmoved; // so that we don't animate
|
|
s2->y += ydiff;
|
|
|
|
// check if s2's head has hit something
|
|
if (preroof && isroofabove(s2) && (ydiff < 0) && (s2->id != P_BLACKCLOUD)) {
|
|
if (isplayer(s2)) {
|
|
die(s2);
|
|
printf("DB: killed by head crush\n"); fflush(stdout);
|
|
} else if (isfruit(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
puffin(-1, s2->x, s2->y, "nothing", 0);
|
|
} else if (ismonster(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
puffin(-1, s2->x, s2->y, "nothing", 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
s->timer1--;
|
|
if (s->timer1 == 0) {
|
|
// go to next waypoint
|
|
s->curwaypoint++;
|
|
if (s->curwaypoint >= s->numwaypoints) {
|
|
s->curwaypoint = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
} else if (s->id == P_TICK) {
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff;
|
|
|
|
|
|
/* distance to player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL);
|
|
/* if there's a hole in front of us */
|
|
if (tt->solid == S_NOTSOLID) {
|
|
double ycutoff = s->y + (TILEH/2);
|
|
if ((player && (player->y >= ycutoff)) || (player2 && (player2->y >= ycutoff ))) {
|
|
/* if player is below and nearby, fall off */
|
|
if (xdiff <= (TILEW*16)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if ((player && (player->y == s->y)) || (player2 && (player2->y == s->y ))) {
|
|
if (globpowerup != PW_CAMERA) {
|
|
/* if player is at same level and close, jump */
|
|
if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) {
|
|
jump(s,D_RIGHT);
|
|
} else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) {
|
|
jump(s,D_LEFT);
|
|
}
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
|
|
|
|
/* moves like an angry rat all the time */
|
|
if (globpowerup != PW_CAMERA) {
|
|
if ((playersalive()) && (!s->jumping) && (!s->jumptimer)) {
|
|
sprite_t *abovep;
|
|
/* if player is above us...*/
|
|
abovep = isplayerabove(s);
|
|
if (abovep) {
|
|
if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { // if 2-3 tiles right
|
|
/* jump right */
|
|
jump(s, D_RIGHT);
|
|
} else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { // if 2-3 tiles left
|
|
/* jump left */
|
|
jump(s, D_LEFT);
|
|
} else if (s->y - abovep->y <= (TILEH*6)) { // player less than 6 tiles above
|
|
if ((xdiff >= 0) && (xdiff < (TILEW*4))) { // ... and within 4 tiles
|
|
/* jump up */
|
|
jump(s, 0);
|
|
} else if ((xdiff <= 0) && (xdiff > -(TILEW*4))) { // ... and within 4 tiles
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else { // falling
|
|
movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
}
|
|
} else if (s->id == P_WSPIDER) { // white spider - very intelligent!
|
|
// timer3 is climb direction
|
|
// timer2 is drop countdown
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff;
|
|
int ladderx = isladderabove(s);
|
|
|
|
if (s->timer2) {
|
|
int mod,mod2;
|
|
mod = (s->timer2 / (WS_DROPDELAY/2));
|
|
s->timer2--;
|
|
if (s->timer2 == 0) {
|
|
// drop!
|
|
|
|
/* drop down */
|
|
s->dropping = B_TRUE;
|
|
s->dropx = s->x / TILEW;
|
|
s->dropy = s->y / TILEH;
|
|
} else {
|
|
mod2 = (s->timer2 / (WS_DROPDELAY/2));
|
|
if (mod2 != mod) {
|
|
// change direction
|
|
if (s->dir == D_RIGHT) s->dir = D_LEFT;
|
|
else if (s->dir == D_LEFT) s->dir = D_RIGHT;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* distance to closest player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
|
|
/* already climbing */
|
|
if (s->climbing) {
|
|
// TODO: replace with just climbing the current dir
|
|
if (s->timer3 == D_UP) {
|
|
// climb up
|
|
int ladderx = isladderabove(s);
|
|
// if tile above is non-solid, or a ladder
|
|
if (ladderx || !isroofabove(s)) {
|
|
/*
|
|
// lock to ladder
|
|
if (ladderx) {
|
|
s->x = ladderx; // lock to ladder
|
|
}
|
|
*/
|
|
// continue climbing
|
|
s->y -= getspeed(s);
|
|
s->jumping = 0;
|
|
s->falling = 0;
|
|
s->climbing = B_TRUE;
|
|
s->moved = MV_WALK;
|
|
faceplayer(s);
|
|
} else {
|
|
s->climbing = B_FALSE;
|
|
// face a player
|
|
faceplayer(s);
|
|
}
|
|
} else { // down
|
|
if (isonladder(s)) {
|
|
if (isladderbelow(s)) {
|
|
// climb down
|
|
s->y += getspeed(s);
|
|
s->jumping = 0;
|
|
s->falling = 0;
|
|
s->climbing = B_TRUE;
|
|
s->moved = MV_WALK;
|
|
faceplayer(s);
|
|
} else {
|
|
s->climbing = B_FALSE;
|
|
faceplayer(s);
|
|
}
|
|
}
|
|
}
|
|
} else if (ladderx && isplayerabovegt(s,TILEW)) { // if we are at the bottom of a ladder
|
|
// start climbing
|
|
s->x = ladderx; // lock to ladder
|
|
s->y -= getspeed(s);
|
|
s->jumping = 0;
|
|
s->falling = 0;
|
|
s->climbing = B_TRUE;
|
|
s->moved = MV_WALK;
|
|
s->timer3 = D_UP;
|
|
} else if (isonladder(s) && isplayerbelowgt(s,TILEW)) { // are we at top of ladder
|
|
int ladderx = isonladder(s);
|
|
if (isladderbelow(s)) {
|
|
s->y += getspeed(s);
|
|
s->jumping = 0;
|
|
s->falling = 0;
|
|
s->climbing = B_TRUE;
|
|
s->moved = MV_WALK;
|
|
// lock to centre of ladder
|
|
s->x = ladderx;
|
|
s->timer3 = D_DOWN;
|
|
} else {
|
|
s->climbing = B_FALSE;
|
|
}
|
|
} else if (!s->dropping && (s->timer2 == 0)) {
|
|
/// not climbing - walk or drop down
|
|
int willdrop = B_FALSE;
|
|
|
|
|
|
s->climbing = B_FALSE;
|
|
|
|
// drop down?
|
|
if (isonbridge(s) && !s->falling) {
|
|
int dist = 9999;
|
|
/* player below (get the one with closest x distance)? */
|
|
if (player && !player->dead && player->y > s->y) dist = abs(player->x - s->x);
|
|
if (player2 && !player2->dead && player2->y > s->y) {
|
|
int dist2;
|
|
dist2 = abs(player2->x - s->x);
|
|
if (dist2 < dist) dist = dist2;
|
|
}
|
|
if (dist <= (TILEW*3)) {
|
|
willdrop = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (willdrop) {
|
|
s->timer2 = WS_DROPDELAY;
|
|
} else {
|
|
// walk
|
|
tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL);
|
|
/* if there's a hole in front of us */
|
|
if (tt->solid == S_NOTSOLID) {
|
|
double ycutoff = s->y + (TILEH/2);
|
|
if ((player && (player->y >= ycutoff)) || (player2 && (player2->y >= ycutoff ))) {
|
|
/* if player is below and nearby, fall off */
|
|
if (xdiff <= (TILEW*16)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if ((player && (player->y == s->y)) || (player2 && (player2->y == s->y ))) {
|
|
if (globpowerup != PW_CAMERA) {
|
|
/* if player is at same level and close, jump */
|
|
if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) {
|
|
jump(s,D_RIGHT);
|
|
} else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) {
|
|
jump(s,D_LEFT);
|
|
}
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/* moves like an angry rat all the time */
|
|
if (globpowerup != PW_CAMERA) {
|
|
if ((playersalive()) && (!s->jumping) && (!s->jumptimer)) {
|
|
sprite_t *abovep;
|
|
/* if player is within 5 tiles above us...*/
|
|
abovep = isplayerabovelt(s,TILEH*5);
|
|
if (abovep) {
|
|
if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) { // if 2-3 tiles right
|
|
/* jump right */
|
|
jump(s, D_RIGHT);
|
|
} else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) { // if 2-3 tiles left
|
|
/* jump left */
|
|
jump(s, D_LEFT);
|
|
} else if (s->y - abovep->y <= (TILEH*6)) { // player less than 6 tiles above
|
|
if ((xdiff >= 0) && (xdiff < (TILEW*4))) { // ... and within 4 tiles
|
|
/* jump up */
|
|
jump(s, 0);
|
|
} else if ((xdiff <= 0) && (xdiff > -(TILEW*4))) { // ... and within 4 tiles
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else { // falling
|
|
movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
faceplayer(s);
|
|
}
|
|
} else if (s->id == P_BAT) {
|
|
/* timer1 tracks state, timer2 tracks previous direction
|
|
timer3 is current direction
|
|
*/
|
|
if (s->timer1 == BS_FLY) {
|
|
if (s->timer3 == D_NONE) {
|
|
int tx,ty;
|
|
int d;
|
|
int maxdist = -99;
|
|
int newdir = D_NONE;
|
|
tiletype_t *tt;
|
|
|
|
// get current pos
|
|
tt = gettileat(s->x,s->y-2,&tx,&ty);
|
|
// pick a direction
|
|
// scan each direction...
|
|
for (d = 0; d < 4; d++) {
|
|
int xm,ym,dir;
|
|
if (d == 0) {
|
|
dir = D_UP;
|
|
xm = 0; ym = -1;
|
|
} else if (d == 1) {
|
|
dir = D_RIGHT;
|
|
xm = 1; ym = 0;
|
|
} else if (d == 2) {
|
|
dir = D_DOWN;
|
|
xm = 0; ym = 1;
|
|
} else { // ie. d == 3
|
|
dir = D_LEFT;
|
|
xm = -1; ym = 0;
|
|
}
|
|
// are we allowed to go this dir?
|
|
if ((dir != s->timer2) && (dir != oppositedir(s->timer2))) {
|
|
int curx,cury,hitwall=B_FALSE;
|
|
int dist = 0;
|
|
curx = tx;
|
|
cury = ty;
|
|
// check distance until wall
|
|
while (!hitwall) {
|
|
curx += xm;
|
|
cury += ym;
|
|
tt = gettilexy(curx, cury);
|
|
|
|
if (tt->solid) hitwall = 1;
|
|
if (curx <= 0) hitwall = 2;
|
|
if (cury <= 0) hitwall = 3;
|
|
if (curx >= LEVELW) hitwall = 4;
|
|
if (cury >= LEVELH) hitwall = 5;
|
|
dist++;
|
|
}
|
|
if (dist > maxdist) {
|
|
newdir = dir;
|
|
maxdist = dist;
|
|
}
|
|
}
|
|
}
|
|
// update our direction
|
|
s->timer2 = s->timer3; // old dir
|
|
s->timer3 = newdir; // current dir
|
|
} else { // we DO have a current direction
|
|
tiletype_t *tt;
|
|
if (s->timer3 == D_UP) {
|
|
tt = gettileat(s->x, s->y - s->img->h - getspeed(s), NULL, NULL);
|
|
if (tt->solid || (s->y - s->img->h) <= TILEH) {
|
|
// hit a wall
|
|
s->timer1 = BS_PAUSE1;
|
|
s->timer2 = s->timer3; // old dir
|
|
s->timer3 = BAT_PAUSE;
|
|
} else {
|
|
s->moved = MV_FLY;
|
|
s->y -= getspeed(s);
|
|
}
|
|
} else if (s->timer3 == D_DOWN) {
|
|
tt = gettileat(s->x, s->y + getspeed(s), NULL, NULL);
|
|
if (tt->solid) {
|
|
// hit a wall
|
|
s->timer1 = BS_PAUSE1;
|
|
s->timer2 = s->timer3; // old dir
|
|
s->timer3 = BAT_PAUSE;
|
|
} else {
|
|
s->moved = MV_FLY;
|
|
s->y += getspeed(s);
|
|
}
|
|
} else { // right or left
|
|
s->dir = s->timer3;
|
|
if (movex(s, s->dir * getspeed(s), B_TRUE)) {
|
|
// hit a wall
|
|
s->timer1 = BS_PAUSE1;
|
|
s->timer2 = s->timer3; // old dir
|
|
s->timer3 = BAT_PAUSE;
|
|
} else {
|
|
s->moved = MV_FLY;
|
|
}
|
|
}
|
|
}
|
|
} else if (s->timer1 == BS_PAUSE1) {
|
|
s->moved = MV_FLY;
|
|
// wait for countdown...
|
|
s->timer3--;
|
|
if ((s->timer3 == BAT_FIRESPACE*2) || (s->timer3 == BAT_FIRESPACE) || (s->timer3 == 0)) {
|
|
sprite_t *ss,*target = NULL;
|
|
// closest player
|
|
target = getclosestplayer(s);
|
|
if (target) {
|
|
double ang;
|
|
// get angle towards target
|
|
ang = atan2(target->y - s->y, target->x - s->x);
|
|
// shoot
|
|
playfx(FX_SONAR);
|
|
ss = addsprite(P_SONAR,s->x,s->y - s->img->h/2,"bat_sonar" );
|
|
ss->xs = cos(ang) * getspeed(ss);
|
|
ss->ys = sin(ang) * getspeed(ss);
|
|
ss->timer1 = 0;
|
|
}
|
|
}
|
|
if (s->timer3 == 0) {
|
|
// go to next state
|
|
s->timer1 = BS_PAUSE2;
|
|
s->timer3 = BAT_PAUSE;
|
|
}
|
|
} else if (s->timer1 == BS_PAUSE2) {
|
|
s->moved = MV_FLY;
|
|
s->timer3--;
|
|
if (s->timer3 == 0) {
|
|
// go to next state
|
|
s->timer1 = BS_FLY;
|
|
s->timer3 = D_NONE;
|
|
}
|
|
}
|
|
} else if (s->id == P_SNAKE) {
|
|
/* timer1 loopsfrom 0 - 19
|
|
|
|
if timer2 is 0, we can shoot. if it is 1, we can't.
|
|
|
|
*/
|
|
|
|
// inc shooting timer
|
|
if (s->timer1) {
|
|
s->timer1--;
|
|
if (s->timer1 == 0) {
|
|
}
|
|
}
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff,ydiff;
|
|
|
|
|
|
/* distance to player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
tt = gettileat(s->x + s->dir+getspeed(s),s->y,NULL,NULL);
|
|
/* if there's a hole in front of us */
|
|
if (tt->solid == S_NOTSOLID) {
|
|
if (s->angry) {
|
|
if ((player && (player->y > s->y)) || (player2 && (player2->y > s->y))) {
|
|
/* if player is below, fall off */
|
|
if (xdiff <= (TILEW*8)) {
|
|
move = B_TRUE;
|
|
}
|
|
} else if ((player && (player->y == s->y)) || (player2 && player2->y == s->y)) {
|
|
if (s->angry) {
|
|
/* if player is at same level and close, jump */
|
|
if ((s->dir == D_RIGHT) && (xdiff > 0) && (xdiff <= (TILEW*7))) {
|
|
jump(s,D_RIGHT);
|
|
} else if ((s->dir == D_LEFT) && (xdiff < 0) && (xdiff >= -(TILEW*7))) {
|
|
jump(s,D_LEFT);
|
|
}
|
|
}
|
|
} else if (level->bottomopen && (s->y >= (SCREENH - 100)) && isplayerabove(s)) {
|
|
// if near bottom of the screen and can fall through...
|
|
move = B_TRUE;
|
|
}
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
if (globpowerup == PW_CAMERA) {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* shoot */
|
|
ydiff = getydisttoplayer(s);
|
|
ydiff = abs(ydiff);
|
|
|
|
// if there's a player close up/down...
|
|
if (ydiff <= (TILEH*4)) {
|
|
sprite_t *ss;
|
|
sprite_t *closeplayer;
|
|
int shoot = B_FALSE;
|
|
if (player && (s->y - player->y <= (TILEH*4)) ) {
|
|
closeplayer = player;
|
|
} else if (player2 && (s->y - player2->y <= (TILEH*4))) {
|
|
closeplayer = player2;
|
|
} else {
|
|
closeplayer = NULL;
|
|
}
|
|
|
|
if (closeplayer) {
|
|
if (s->bullet == NULL) { // if we don't already have a bullet
|
|
// if we are facing the player
|
|
if ( (closeplayer->x < s->x) && (s->dir == D_LEFT) ) {
|
|
shoot = B_TRUE;
|
|
} else if ( (closeplayer->x > s->x) && (s->dir == D_RIGHT) ) {
|
|
shoot = B_TRUE;
|
|
}
|
|
}
|
|
if (globpowerup == PW_CAMERA) shoot = B_FALSE;
|
|
if (shoot) {
|
|
// if our shooting timer is okay
|
|
if (s->timer1 == 0) {
|
|
playfx(FX_HISS);
|
|
//ss = addsprite(P_SPIT,s->x,s->y - s->img->h/2,"spit" );
|
|
ss = addsprite(P_SPIT,s->x,s->y - TILEH,"spit" );
|
|
ss->ys = 0;
|
|
ss->xs = s->dir * (getspeed(s)*2);
|
|
ss->dir = s->dir;
|
|
ss->owner = s;
|
|
|
|
s->bullet = ss;
|
|
|
|
// start timer for shooting again
|
|
s->timer1 = 200;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
|
|
|
|
if (s->angry && (globpowerup != PW_CAMERA)) {
|
|
if (playersalive() && (!s->jumping) && (!s->jumptimer)) {
|
|
/* if player is above us, jump */
|
|
if ( (player && (!player->dead) && (player->y < s->y)) ||
|
|
(player2 && (!player2->dead) && (player2->y < s->y))) {
|
|
if ((xdiff >= (TILEW*2)) && (xdiff <= (TILEW*3))) {
|
|
/* jump right */
|
|
jump(s, 1);
|
|
} else if ((xdiff <= -(TILEW*2)) && (xdiff >= -(TILEW*3))) {
|
|
/* jump left */
|
|
jump(s, -1);
|
|
} else if ((player && (s->y - player->y <= (TILEH*6))) ||
|
|
(player2 && (s->y - player2->y <= (TILEH*6)))) {
|
|
if ((xdiff >= 0) && (xdiff < (TILEW*2))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
} else if ((xdiff <= 0) && (xdiff > -(TILEW*2))) {
|
|
/* jump up */
|
|
jump(s, 0);
|
|
}
|
|
} else {
|
|
/* jump whichever way we're facing */
|
|
/*
|
|
s->jumpdir = s->dir;
|
|
s->jumping = 1;
|
|
s->jumpspeed = 5;
|
|
*/
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else { // falling
|
|
movex(s, s->jumpdir*getspeed(s), B_TRUE);
|
|
}
|
|
|
|
} else if (s->id == P_BEE) {
|
|
double absxs,absys;
|
|
if ((s->xs == -99) || (s->ys == -99)) {
|
|
s->xs = getspeed(s);
|
|
s->ys = getspeed(s);
|
|
}
|
|
|
|
if (s->xs > 0) absxs = 1;
|
|
else absxs = -1;
|
|
|
|
if (s->ys > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
/* this will fix the speed if ANGRY is set */
|
|
s->xs = absxs*getspeed(s);
|
|
s->ys = absys*getspeed(s);
|
|
|
|
|
|
/* can we move? */
|
|
tt = gettileat(s->x + absxs*((s->img->w/2)+8), s->y-(s->img->h/2),NULL,NULL);
|
|
if ((tt->solid) || (tt->spikes )) {
|
|
/* turn */
|
|
s->xs = -s->xs;
|
|
}
|
|
tt = gettileat(s->x, s->y-(s->img->h/2) + absys*((s->img->h/2)+8),NULL,NULL);
|
|
if ((tt->solid) || (tt->spikes)) {
|
|
/* turn */
|
|
s->ys = -s->ys;
|
|
}
|
|
/* move */
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
s->dir = absxs;
|
|
s->moved = MV_WALK;
|
|
} else if (s->id == P_FLY) { // fly - like bee but more erratic flight and can walk on ground if player far away
|
|
if (s->owner) { // move like king fly
|
|
if (!s->invuln) {
|
|
if (s->timer1 == KFS_HORZWAIT) {
|
|
// hover
|
|
s->y = s->owner->y;
|
|
|
|
s->moved = MV_FLY;
|
|
} else if (s->timer1 == KFS_VERTWAIT) {
|
|
double ymod;
|
|
// hover
|
|
s->ys = 2;
|
|
ymod = sin(((double)timer * (double)3.6) * (M_PI/180));
|
|
|
|
s->y += (s->ys * ymod);
|
|
|
|
s->x = s->owner->x;
|
|
|
|
s->moved = MV_FLY;
|
|
} else if (s->timer1 == KFS_HORZPUSH) {
|
|
// move towards target position
|
|
if (s->timer2 > s->x) {
|
|
s->x += (getspeed(s)*2);
|
|
if (s->x > s->timer2) s->x = s->timer2;
|
|
} else if (s->timer2 < s->x) {
|
|
s->x -= (getspeed(s)*2);
|
|
if (s->x < s->timer2) s->x = s->timer2;
|
|
}
|
|
s->moved = MV_FLY;
|
|
} else if (s->timer1 == KFS_VERTPUSH) {
|
|
// move towards target position
|
|
if (s->timer2 > s->y) {
|
|
s->y += (getspeed(s)*2);
|
|
if (s->y > s->timer2) s->y = s->timer2;
|
|
} else if (s->timer2 < s->y) {
|
|
s->y -= (getspeed(s)*2);
|
|
if (s->y < s->timer2) s->y = s->timer2;
|
|
}
|
|
s->moved = MV_FLY;
|
|
} else {
|
|
double absxs,absys;
|
|
if ((s->xs == -99) || (s->ys == -99)) {
|
|
s->xs = getspeed(s);
|
|
s->ys = getspeed(s);
|
|
}
|
|
|
|
if (s->xs > 0) absxs = 1;
|
|
else absxs = -1;
|
|
|
|
if (s->ys > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
/* this will fix the speed if ANGRY is set */
|
|
s->xs = absxs*getspeed(s);
|
|
s->ys = absys*getspeed(s);
|
|
|
|
|
|
/* can we move? */
|
|
if (s->x >= SCREENW - (boss->img->w/2) - 2) {
|
|
/* turn */
|
|
s->xs = -abs(s->xs);
|
|
} else if (s->x <= (boss->img->w/2)) {
|
|
s->xs = abs(s->xs);
|
|
}
|
|
|
|
|
|
if (s->y <= boss->img->h) {
|
|
s->ys = abs(s->ys);
|
|
} else if (s->y >= SCREENH-2 ) {
|
|
s->ys = -abs(s->ys);
|
|
}
|
|
|
|
/* move */
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
|
|
if (s->owner->timer1 == KFS_HORZWAIT) {
|
|
// fly until we're level with owner
|
|
if (abs((s->y-(s->img->h/2)) - (s->owner->y - (s->owner->img->h/2))) <= (s->img->h/2)) {
|
|
// lock y
|
|
s->timer1 = KFS_HORZWAIT;
|
|
}
|
|
} else if (s->owner->timer1 == KFS_VERTWAIT) {
|
|
// fly until we're level with owner
|
|
if (abs(s->x - s->owner->x) <= (s->img->w/2)) {
|
|
// lock x
|
|
s->timer1 = KFS_VERTWAIT;
|
|
}
|
|
}
|
|
|
|
|
|
s->dir = absxs;
|
|
s->moved = MV_FLY;
|
|
}
|
|
}
|
|
} else {
|
|
double absxs,absys;
|
|
double xmod,ymod;
|
|
if (s->flies) {
|
|
if ((s->xs == -99) || (s->ys == -99)) {
|
|
s->xs = getspeed(s);
|
|
s->ys = -getspeed(s);
|
|
}
|
|
|
|
if (s->xs > 0) absxs = 1;
|
|
else absxs = -1;
|
|
|
|
if (s->ys > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
/* this will fix the speed if ANGRY is set */
|
|
s->xs = absxs*getspeed(s);
|
|
s->ys = absys*getspeed(s);
|
|
|
|
if (s->flies == F_FLYVERT) {
|
|
ymod = sin(((double)timer * (double)3.6) * (M_PI/180));
|
|
//ymod *= 0.8;
|
|
// XXX
|
|
xmod = 0;
|
|
if (s->ys * (ymod) > 0) absys = 1;
|
|
else absys = -1;
|
|
} else if (s->flies == F_FLYHORZ) {
|
|
xmod = sin(((double)timer * (double)3.6) * (M_PI/180));
|
|
// XXX
|
|
ymod = 0;
|
|
if (s->xs * (xmod) > 0) absxs = 1;
|
|
else absxs = -1;
|
|
} else {
|
|
xmod = 0;
|
|
ymod = 0;
|
|
}
|
|
|
|
|
|
|
|
/* can we move? */
|
|
tt = gettileat(s->x + absxs*((s->img->w/2)+8), s->y-(s->img->h/2),NULL,NULL);
|
|
if ((tt->solid) || (tt->spikes )) {
|
|
/* turn */
|
|
s->xs = -s->xs;
|
|
}
|
|
|
|
tt = gettileat(s->x, s->y-(s->img->h/2) + absys*((s->img->h/2)+8),NULL,NULL);
|
|
if ((tt->solid) || (tt->spikes)) {
|
|
/* turn */
|
|
s->ys = -s->ys;
|
|
}
|
|
if (tt->water && !s->swimming) {
|
|
/* turn */
|
|
s->ys = -s->ys;
|
|
}
|
|
|
|
/* move */
|
|
if (s->flies == F_FLYVERT) {
|
|
s->x += s->xs;
|
|
s->y += (s->ys * ymod);
|
|
} else {
|
|
s->x += (s->xs * xmod);
|
|
s->y += s->ys;
|
|
}
|
|
|
|
s->dir = absxs;
|
|
s->moved = MV_FLY;
|
|
|
|
// inc flying timer
|
|
s->timer1++;
|
|
if (s->timer1 >= FLY_FLYTIME) {
|
|
if (s->flies == F_FLYHORZ) {
|
|
s->flies = F_FLYVERT;
|
|
} else {
|
|
s->flies = F_WALK;
|
|
}
|
|
s->timer1 = 0;
|
|
}
|
|
} else { // walking - move like a rat
|
|
double myspeed = getspeed(s) * 0.75;
|
|
double playerdist1,playerdist2,playerdist;
|
|
if (!s->falling) {
|
|
int move = B_FALSE;
|
|
int xdiff, absxdiff;
|
|
tiletype_t *tunder;
|
|
|
|
/* distance to player */
|
|
xdiff = getxdisttoplayer(s, NULL);
|
|
absxdiff = abs(xdiff);
|
|
|
|
// tile in front and below
|
|
tt = gettileat(s->x + s->dir*myspeed + (s->dir * (s->img->w/2)),s->y + (TILEH/2),NULL,NULL);
|
|
// tile below
|
|
tunder = gettileat(s->x ,s->y + 1,NULL,NULL);
|
|
/* if there's a hole in front of us and below*/
|
|
if (tt->solid == S_NOTSOLID) {
|
|
// we're on a slope
|
|
if (tunder->solid == S_SLOPE) {
|
|
move = B_TRUE;
|
|
}
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*myspeed, B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
s->moved = MV_WALK;
|
|
|
|
// take off if player is close
|
|
if (player) {
|
|
playerdist1 = getdistance(player->x,player->y,s->x,s->y);
|
|
} else {
|
|
playerdist1 = 9999;
|
|
}
|
|
if (player2) {
|
|
playerdist2 = getdistance(player2->x,player2->y,s->x,s->y);
|
|
} else {
|
|
playerdist2 = 9999;
|
|
}
|
|
if (playerdist1 < playerdist2) {
|
|
playerdist = playerdist1;
|
|
} else {
|
|
playerdist = playerdist2;
|
|
}
|
|
|
|
if (globpowerup != PW_CAMERA) {
|
|
if (playerdist <= (TILEW*10)) {
|
|
s->timer1 = 0;
|
|
s->flies = F_FLYHORZ;
|
|
s->xs = -99;
|
|
s->ys = -99;
|
|
}
|
|
}
|
|
|
|
// ...and take off eventually anyway
|
|
s->timer1++;
|
|
if (s->timer1 >= FLY_WALKTIME) {
|
|
s->timer1 = 0;
|
|
s->flies = F_FLYHORZ;
|
|
s->xs = -99;
|
|
s->ys = -99;
|
|
}
|
|
} else { // falling
|
|
tiletype_t *tunder, *t2under;
|
|
|
|
// tile below
|
|
tunder = gettileat(s->x ,s->y,NULL,NULL);
|
|
t2under = gettileat(s->x ,s->y+s->img->h,NULL,NULL);
|
|
if ((tunder->solid == S_SLOPE) || (t2under->solid == S_SLOPE)) {
|
|
movex(s, s->dir*myspeed, B_TRUE);
|
|
// reset walk timer
|
|
s->timer1 = 0;
|
|
}
|
|
|
|
|
|
// take off eventually
|
|
// ...and take off eventually anyway, or if spikes underneath
|
|
s->timer1++;
|
|
if ((s->timer1 >= FLY_WALKTIME) || (t2under->spikes) || tunder->spikes) {
|
|
s->timer1 = 0;
|
|
s->flies = F_FLYHORZ;
|
|
s->xs = -99;
|
|
s->ys = -99;
|
|
}
|
|
}
|
|
}
|
|
} // end if s->owner
|
|
} else if (s->id == P_FISH) { // very similar to bee
|
|
double absxs,absys;
|
|
|
|
// dies if not in water
|
|
if (!isinwater(s)) {
|
|
s->dead = D_FINAL;
|
|
puffin(-1, s->x, s->y, "nothing", 0);
|
|
}
|
|
|
|
if ((s->xs == -99) || (s->ys == -99)) {
|
|
s->xs = getspeed(s)*2;
|
|
s->ys = getspeed(s);
|
|
}
|
|
|
|
if (s->xs > 0) absxs = 1;
|
|
else absxs = -1;
|
|
|
|
if (s->ys > 0) absys = 1;
|
|
else absys = -1;
|
|
|
|
/* this will fix the speed if ANGRY is set */
|
|
s->xs = absxs*getspeed(s)*2;
|
|
s->ys = absys*getspeed(s);
|
|
|
|
|
|
/* can we move? */
|
|
tt = gettileat(s->x + absxs*((s->img->w/2)+8), s->y-(s->img->h/2),NULL,NULL);
|
|
if ((tt->solid) || (tt->spikes )) {
|
|
/* turn */
|
|
s->xs = -s->xs;
|
|
}
|
|
tt = gettileat(s->x, s->y-(s->img->h/2) + absys*((s->img->h/2)+8),NULL,NULL);
|
|
if ((tt->solid) || (tt->spikes) || !tt->water) {
|
|
/* turn */
|
|
s->ys = -s->ys;
|
|
}
|
|
/* move */
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
s->dir = absxs;
|
|
s->moved = MV_WALK;
|
|
} else if (s->id == P_SPIDER) {
|
|
/* timer1 loopsfrom 0 - 45
|
|
|
|
if timer2 is 0, we can shoot. if it is 1, we can't.
|
|
|
|
*/
|
|
|
|
if (s->timer1) {
|
|
s->timer1--;
|
|
}
|
|
|
|
/* if on ground, go up */
|
|
if (!s->flies && (isonground(s) || (s->y >= (SCREENH-TILEH) ) )) {
|
|
s->flies = B_TRUE;
|
|
s->falling = B_FALSE;
|
|
s->ys = -getspeed(s);
|
|
} else if (s->falling) {
|
|
/* if we are about to hit spikes, go back up */
|
|
tt = gettileat(s->x,s->y + 8,NULL,NULL);
|
|
if (tt->spikes) {
|
|
/* go back up */
|
|
s->flies = B_TRUE;
|
|
s->falling = B_FALSE;
|
|
s->ys = -getspeed(s);
|
|
}
|
|
} else {
|
|
if (s->ys != -99) {
|
|
/* if roof above us */
|
|
tt = gettileat(s->x,s->y - s->img->h,NULL,NULL);
|
|
if (tt->solid) {
|
|
int tiley;
|
|
/* start walking again */
|
|
tiley = (int) (s->y / TILEH);
|
|
s->y = tiley*TILEH;
|
|
s->ys = -99;
|
|
s->flies = B_TRUE;
|
|
} else {
|
|
s->y += s->ys;
|
|
s->flies = B_TRUE;
|
|
}
|
|
} else {
|
|
int move = B_FALSE;
|
|
int xdiff;
|
|
sprite_t *pp = NULL;
|
|
|
|
/* walk back and forwards */
|
|
|
|
/* drop if player is close */
|
|
xdiff = getxdisttoplayer(s, &pp);
|
|
xdiff = abs(xdiff);
|
|
|
|
if (pp) {
|
|
|
|
if ((pp->y > s->y) && (xdiff <= (TILEW*2)) && (s->timer1 == 0)) {
|
|
s->timer1 = 200;
|
|
s->flies = B_FALSE;
|
|
s->falling = B_TRUE;
|
|
s->fallspeed = 8;
|
|
} else {
|
|
int tx,ty;
|
|
s->flies = B_TRUE;
|
|
|
|
/* if there's a hole in front of us */
|
|
tt = gettileat(s->x + s->dir*((s->img->w/2)+2),s->y - s->img->h - 4,&tx,&ty);
|
|
if (tt->solid == S_NOTSOLID) {
|
|
move = B_FALSE;
|
|
} else {
|
|
move = B_TRUE;
|
|
}
|
|
|
|
/* either move or turn around */
|
|
if (move) {
|
|
rv = movex(s, s->dir*getspeed(s), B_TRUE);
|
|
if (rv) {
|
|
/* if we couldn't move (hit a wall), turn */
|
|
s->dir = -s->dir;
|
|
}
|
|
} else {
|
|
s->dir = -s->dir;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if ((s->id == P_SPIT) || (s->id == P_FIREBALL)) {
|
|
if (movex(s, s->xs, B_TRUE)) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_BIGFIREBALL) {
|
|
tiletype_t *tt;
|
|
int yyy,tx,ty;
|
|
// move
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
|
|
// melt any ice bridges it touches
|
|
for (yyy = s->y - s->img->h ; yyy < s->y ; yyy += 4) {
|
|
tt = gettileat(s->x + (s->img->w/2),yyy, &tx,&ty);
|
|
if (isbridge(tt->id)) {
|
|
melttile(tx,ty,REGROWTIMER_SHORT, B_PUFF);
|
|
}
|
|
}
|
|
|
|
// die if it leaves screen
|
|
if (s->x >= (SCREENW-TILEW)) {
|
|
s->dead = D_FINAL;
|
|
} else if (s->x <= TILEW) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_LEAF) { // blowing leaf
|
|
s->x = s->x + s->xs;
|
|
s->y = s->y + s->ys;
|
|
|
|
// if off screen
|
|
if ((s->xs > 0) && (s->x >= (SCREENW - s->img->w))) {
|
|
s->dead = D_FINAL;
|
|
} else if ((s->xs < 0) && (s->x <= (s->img->w))) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_SONAR) {
|
|
// timer1 = frame
|
|
// update frame
|
|
if ((timer % 5) == 0) {
|
|
s->timer1++;
|
|
if (s->timer1 >= imageset[P_SONAR].numimages) {
|
|
s->timer1 = 0;
|
|
}
|
|
}
|
|
// move
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
// die if it leaves screen
|
|
if (s->x >= (SCREENW-TILEW)) {
|
|
s->dead = D_FINAL;
|
|
} else if (s->x <= TILEW) {
|
|
s->dead = D_FINAL;
|
|
} else if (s->y >= (SCREENH+(s->img->h))) {
|
|
s->dead = D_FINAL;
|
|
} else if (s->y <= TILEH) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_RAYGUNBULLET) {
|
|
s->x += s->xs;
|
|
if (s->x >= (SCREENW-TILEW)) {
|
|
s->dead = D_FINAL;
|
|
} else if (s->x <= TILEW) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else if (s->id == P_PINKCLOUD) {
|
|
if (s->timer1 == LV_CLOUD) {
|
|
SDL_Surface *ts;
|
|
double targx,targy;
|
|
double amtleft;
|
|
double xdis,ydis,dis;
|
|
int turnsleft;
|
|
|
|
if (s->owner->dead) {
|
|
if (s->owner->lives <= 0) { // out of the game
|
|
// no use for us anymore...
|
|
s->dead = D_FINAL;
|
|
}
|
|
} else {
|
|
/*
|
|
If small, grow and move towards player's feet (at a speed
|
|
which will get us there when we are fully grown.
|
|
*/
|
|
targx = s->owner->x;
|
|
targy = s->owner->y + (imageset[P_PINKCLOUD].img[F_WALK1]->h / 2);
|
|
|
|
if (s->img->w < imageset[P_PINKCLOUD].img[F_WALK1]->w) {
|
|
// grow
|
|
s->size += ((double)PCGROWSPEED);
|
|
ts = rotozoomSurfaceXY(imageset[P_PINKCLOUD].img[F_WALK1],0, s->size, s->size,0);
|
|
SDL_FreeSurface(s->img);
|
|
s->img = ts;
|
|
}
|
|
|
|
|
|
// calculate number of turns left
|
|
amtleft = 1.0 - s->size; // amount left
|
|
turnsleft = (int) (amtleft / (double)PCGROWSPEED);
|
|
|
|
if (turnsleft < 1) {
|
|
// make sure we're in the right place
|
|
s->x = targx;
|
|
s->y = targy;
|
|
s->rotated = 0;
|
|
|
|
s->timer1 = LV_CLOUDLOOP;
|
|
// stop the player teleporting if required
|
|
if (s->owner->teleporting) {
|
|
stopteleporting(s->owner);
|
|
}
|
|
// mark the player as on top of us
|
|
s->owner->oncloud = B_TRUE;
|
|
|
|
} else {
|
|
|
|
// calculate distance to player
|
|
xdis = abs(targx - s->x);
|
|
ydis = abs(targy - s->y);
|
|
dis = sqrt((xdis*xdis) + (ydis*ydis));
|
|
// calculate speed needed to reach player x/y in time
|
|
s->speed = dis / turnsleft;
|
|
// figure out angle to player
|
|
s->angle = atan2(targy - s->y, targx - s->x);
|
|
|
|
// keep between 0 and 360
|
|
if (s->angle > (360*(M_PI/180))) {
|
|
s->angle -= (360*(M_PI/180));
|
|
}
|
|
if (s->angle < 0) {
|
|
s->angle += (360*(M_PI/180));
|
|
}
|
|
|
|
// figure out x/y speed
|
|
s->xs = (cos(s->angle) * s->speed);
|
|
s->ys = (sin(s->angle) * s->speed);
|
|
|
|
//printf("cloud: amtleft = %0.2f (1.0 - ssize=%0.2f)",amtleft,s->size);
|
|
// printf("cloud: speed = %0.2f, xdis=%0.2f,ydis=%0.2f,dis=%0.2f, turnsleft=%d,xs=%0.2f,ys=%0.2f\n",speed,xdis,ydis,dis,turnsleft,s->xs,s->ys);
|
|
// move
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
|
|
// keep on screen!!
|
|
keeponscreen(s);
|
|
}
|
|
}
|
|
} else if (s->timer1 == LV_CLOUDLOOP) {
|
|
|
|
// make sure we are on the screen!!
|
|
// should never happen, but...
|
|
if (s->x < 0) s->x = 320;
|
|
if (s->y < 0) s->y = 240;
|
|
if (s->x >= SCREENW) s->x = 320;
|
|
if (s->y >= SCREENH) s->y = 240;
|
|
|
|
// stick player to us
|
|
s->owner->x = s->x;
|
|
s->owner->y = s->y - (imageset[P_PINKCLOUD].img[F_WALK1]->h / 2);
|
|
|
|
// turn off player attributes
|
|
s->owner->climbing = B_FALSE;
|
|
s->owner->netting = B_FALSE;
|
|
s->owner->slamming = B_FALSE;
|
|
s->owner->jumping = B_FALSE;
|
|
|
|
// keep turning towards exit (2 degrees at a time)
|
|
s->angle += (PCTURN * (M_PI/180));
|
|
|
|
// keep between 0 and 360
|
|
if (s->angle > (360*(M_PI/180))) {
|
|
s->angle -= (360*(M_PI/180));
|
|
}
|
|
if (s->angle < 0) {
|
|
s->angle += (360*(M_PI/180));
|
|
}
|
|
// track total rotation
|
|
s->rotated += (PCTURN * (M_PI/180));
|
|
|
|
if (s->angle < (270 * (M_PI/180))) {
|
|
// decellerate
|
|
if (s->speed > 5) {
|
|
s->speed -= 1;
|
|
}
|
|
} else {
|
|
// accellerate
|
|
if (s->speed < 10) {
|
|
s->speed += 0.5;
|
|
}
|
|
}
|
|
// figure out x/y speed
|
|
s->xs = (cos(s->angle) * s->speed);
|
|
s->ys = (sin(s->angle) * s->speed);
|
|
// move
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
|
|
// keep on screen (but use player height
|
|
if (s->x > SCREENW-(s->img->w/2)) {
|
|
s->x = SCREENW - (s->img->w/2);
|
|
}
|
|
if (s->y > SCREENH-(s->img->h/2)) {
|
|
s->y = SCREENH - (s->img->h/2);
|
|
}
|
|
if (s->x < s->img->w/2) {
|
|
s->x = s->img->w/2;
|
|
}
|
|
if (s->y < s->owner->img->h/2) {
|
|
s->y = s->owner->img->h/2;
|
|
}
|
|
|
|
|
|
// if we've done at least one revolution
|
|
if (s->rotated >= 360 * (M_PI/180)) { // done one revolution
|
|
sprite_t *c;
|
|
int ready = B_TRUE;
|
|
// and other cloud is finished or dead...
|
|
for (c = sprite ; c ; c = c->next) {
|
|
if ((c->id == P_PINKCLOUD) && (c->timer1 != LV_CLOUDLOOP) && (c->owner->lives > 0)) {
|
|
ready = B_FALSE;
|
|
}
|
|
}
|
|
|
|
if (ready) {
|
|
// level clear!
|
|
levelcomplete = LV_NEXTLEV;
|
|
}
|
|
return B_TRUE;
|
|
}
|
|
} else if ((levelcomplete == LV_INIT) || (levelcomplete == LV_INPROGRESS)) {
|
|
SDL_Surface *ts;
|
|
// shrink
|
|
s->size -= ((double)PCSHRINKSPEED);
|
|
|
|
if (s->size <= 0.1) {
|
|
s->dead = D_FINAL;
|
|
} else {
|
|
ts = rotozoomSurfaceXY(imageset[P_PINKCLOUD].img[F_WALK1],0, s->size, s->size,0);
|
|
SDL_FreeSurface(s->img);
|
|
s->img = ts;
|
|
}
|
|
|
|
// move up slightly
|
|
s->y -= PCSHRINKSPEED;
|
|
}
|
|
} else if (s->id == P_BLACKCLOUD) {
|
|
if ((player && player->dead) || (player2 && player2->dead) || (levelcomplete)) {
|
|
if (s->size <= 0.2) {
|
|
s->dead = D_FINAL;
|
|
/* reset hurryup timer */
|
|
resethurryup(curlevel);
|
|
} else {
|
|
SDL_Surface *ts, *cloudim;
|
|
//printf("shrink\n");
|
|
if (s->angry) {
|
|
cloudim = imageset[P_BLACKCLOUD].img[MAXFRAMES*2];
|
|
} else {
|
|
cloudim = imageset[P_BLACKCLOUD].img[0];
|
|
}
|
|
/* get smaller */
|
|
s->size -= 0.1;
|
|
ts = rotozoomSurfaceXY(cloudim,0,s->size, s->size, 0);
|
|
//ts = rotozoomSurfaceXY(s->img,0, 0.9 , 0.9 ,0);
|
|
SDL_FreeSurface(s->img); // free old image
|
|
s->img = ts;
|
|
s->y--;
|
|
}
|
|
} else {
|
|
if (!s->invuln) {
|
|
if ((s->xs == -99) || (s->ys == -99)) {
|
|
if (isplayerabove(s)) {
|
|
s->ys = -0.5;
|
|
} else {
|
|
s->ys = 0.5;
|
|
}
|
|
if (isplayerright(s)) {
|
|
s->xs = 1;
|
|
} else {
|
|
s->xs = -1;
|
|
}
|
|
}
|
|
|
|
s->x += s->xs;
|
|
s->y += s->ys;
|
|
|
|
if (s->x >= (SCREENW - s->img->w/2)) {
|
|
s->xs = -s->xs;
|
|
s->x = SCREENW - s->img->w/2;
|
|
}
|
|
if (s->x <= (s->img->w/2)) {
|
|
s->xs = -s->xs;
|
|
s->x = s->img->w/2;
|
|
}
|
|
//if (s->y >= (SCREENH - s->img->h)) {
|
|
if (s->y >= SCREENH-1) {
|
|
s->ys = -s->ys;
|
|
//s->y = SCREENH - s->img->h;
|
|
s->y = SCREENH-1;
|
|
}
|
|
if (s->y <= (s->img->h)) {
|
|
s->ys = -s->ys;
|
|
s->y = s->img->h;
|
|
}
|
|
|
|
|
|
//if (timer % CLOUDGROWSPEED == 0) {
|
|
if (1) {
|
|
double growamt;
|
|
//int w,h;
|
|
SDL_Surface *ts, *cloudim;
|
|
|
|
|
|
if (s->angry) {
|
|
cloudim = imageset[P_BLACKCLOUD].img[MAXFRAMES*2];
|
|
} else {
|
|
cloudim = imageset[P_BLACKCLOUD].img[0];
|
|
}
|
|
//w = s->img->w;
|
|
//h = s->img->h;
|
|
//ts = rotozoomSurfaceXY(s->img,0, 1.1 , 1.1 ,0);
|
|
growamt = ((double)CLOUDGROWAMT / (double)CLOUDGROWSPEED);
|
|
s->size += growamt;
|
|
//printf("grow, now %0.2f\n",s->size);
|
|
// TODO: free old first? depends if we ever use a preset one
|
|
ts = rotozoomSurfaceXY(cloudim,0,s->size, s->size, 0);
|
|
SDL_FreeSurface(s->img);
|
|
s->img = ts;
|
|
|
|
s->y += growamt;
|
|
|
|
}
|
|
} // end if !s->invuln
|
|
}
|
|
} else if (haspowerupany(PW_MAGNET) && isfruit(s->id) && (isfruit(s->id) != FT_SUPER)) {
|
|
sprite_t *who;
|
|
|
|
who = haspowerupany(PW_MAGNET);
|
|
if (abs(who->y - s->y) <= (TILEH)) {
|
|
double dis;
|
|
double spd;
|
|
dis = abs(who->x - s->x); // ie. 0 - SCREENW
|
|
if (dis <= 320) {
|
|
spd = dis / 45; // ie. 0 - 10
|
|
// now reverse it (so the closer it is, the faster it goes)
|
|
spd = 7 - spd;
|
|
if (spd > 7) spd = 7;
|
|
if (who->x > s->x) {
|
|
movex(s, spd, B_FALSE);
|
|
} else if (who->x < s->x) {
|
|
movex(s, -spd, B_FALSE);
|
|
}
|
|
}
|
|
}
|
|
} else if (haspowerupany(PW_BADMAGNET) && isfruit(s->id)) {
|
|
sprite_t *who;
|
|
|
|
who = haspowerupany(PW_BADMAGNET);
|
|
if (abs(who->y - s->y) <= (TILEH)) {
|
|
double dis;
|
|
double spd;
|
|
dis = abs(who->x - s->x); // ie. 0 - SCREENW
|
|
if (dis <= 320) {
|
|
spd = dis / 45; // ie. 0 - 10
|
|
// now reverse it (so the closer it is, the faster it goes)
|
|
spd = 7 - spd;
|
|
if (spd > 7) spd = 7;
|
|
if (who->x > s->x) {
|
|
movex(s, -spd, B_TRUE);
|
|
} else if (who->x < s->x) {
|
|
movex(s, spd, B_TRUE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// at endgame, fruits fall down
|
|
if (isfruit(s->id) && endgame) {
|
|
s->y = s->y + s->ys;
|
|
|
|
// increase speed
|
|
s->ys += 0.2;
|
|
if (s->ys > ENDGAMEFALLSPEED) s->ys = ENDGAMEFALLSPEED;
|
|
|
|
// if off screen
|
|
if (s->y >= (SCREENH + s->img->h)) {
|
|
// die
|
|
s->dead = D_FINAL;
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void dotileeffects(sprite_t *s) {
|
|
tiletype_t *tt;
|
|
int finished = B_FALSE;
|
|
int state = 0;
|
|
int tilex,tiley,checkingx = 0, checkingy = 0;
|
|
|
|
if (!s) return;
|
|
|
|
if (iseffect(s->id) || isbullet(s->id)) {
|
|
return;
|
|
}
|
|
|
|
if (s->jumping || s->dead || s->caughtby) {
|
|
return;
|
|
}
|
|
|
|
// no tile effects for machine gun
|
|
if (haspowerupany(PW_GUNNER)) {
|
|
if (isplayer(s)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* check where we are */
|
|
tt = gettileat(s->x,s->y-2,&tilex,&tiley);
|
|
|
|
// teleporters
|
|
if ((tt->id == T_TELEPORT) || (tt->id == T_TELEPORT2)) {
|
|
//if (!isendoflev()) { // can't enter teleporters after level end to avoid cloud moving too far
|
|
if (isplayer(s) || ismonster(s->id)) {
|
|
if (s->id != P_BLACKCLOUD) {
|
|
if (!s->teleporting) {
|
|
playfx(FX_TELEPORT);
|
|
s->teleporting = 1;
|
|
}
|
|
}
|
|
}
|
|
// }
|
|
}
|
|
|
|
/* check on top of us */
|
|
tt = gettileat(s->x,s->y-(s->img->h/2),&tilex,&tiley);
|
|
switch (tt->id) {
|
|
case T_WATERRIGHT:
|
|
if (!ismonster(s->id) && !isfruit(s->id)) {
|
|
movex(s, 1.5, B_TRUE);
|
|
} else if (s->id == P_PLANT) {
|
|
movex(s, 1.5, B_TRUE);
|
|
}
|
|
break;
|
|
case T_WATERLEFT:
|
|
if (!ismonster(s->id) && !isfruit(s->id)) {
|
|
movex(s, -1.5, B_TRUE);
|
|
} else if (s->id == P_PLANT) {
|
|
movex(s, -1.5, B_TRUE);
|
|
}
|
|
break;
|
|
case T_WATERDOWN:
|
|
if (!ismonster(s->id) && !isfruit(s->id)) {
|
|
s->y += 1.5;
|
|
} else if (s->id == P_PLANT) {
|
|
s->y += 1.5;
|
|
}
|
|
break;
|
|
}
|
|
if (isdeadly(tt, tilex, tiley)) {
|
|
if (!isfruit(s->id) ) {
|
|
if (!s->invuln) {
|
|
if ((s->id != P_BLACKCLOUD) && (s->id != P_KINGSNAIL) && (s->id != P_KINGCAT)) {
|
|
die(s);
|
|
printf("DB: killed by deadly tile\n"); fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
finished = B_TRUE;
|
|
}
|
|
|
|
|
|
if (!finished) {
|
|
/* check under us */
|
|
tt = gettileat(s->x,s->y+3,&tilex,&tiley);
|
|
}
|
|
|
|
// remember the exact x/y location we're checking.
|
|
checkingx = s->x;
|
|
checkingy = s->y+3;
|
|
|
|
// CHECKS WHICH COULD APPLY TO TILES UNDER AND SLIGHTLY LEFT/RIGHT OF US
|
|
while (!finished) {
|
|
if (tt->id == T_RIGHT) {
|
|
if (globpowerup != PW_CLOCK) {
|
|
if (!ismonster(s->id) && !isfruit(s->id)) {
|
|
movex(s, 1.5, B_FALSE);
|
|
} else if (s->id == P_PLANT) {
|
|
movex(s, 1.5, B_FALSE);
|
|
}
|
|
}
|
|
finished = B_TRUE;
|
|
} else if (tt->id == T_LEFT) {
|
|
if (globpowerup != PW_CLOCK) {
|
|
if (!ismonster(s->id) && !isfruit(s->id)) {
|
|
movex(s, -1.5, B_FALSE);
|
|
} else if (s->id == P_PLANT) {
|
|
movex(s, -1.5, B_FALSE);
|
|
}
|
|
}
|
|
finished = B_TRUE;
|
|
} else if (tt->slippery) {
|
|
if (isplayer(s) && !isinwater(s)) {
|
|
if (globpowerup != PW_CLOCK) {
|
|
if (!s->moved) {
|
|
if (s->xs != 0) {
|
|
// slide along the ground
|
|
movex(s, s->xs, B_FALSE);
|
|
|
|
// slow down
|
|
if (s->xs > 0) {
|
|
s->xs -= ICEDECCEL;
|
|
if (s->xs < 0) s->xs = 0;
|
|
} else if (s->xs < 0) {
|
|
s->xs += ICEDECCEL;
|
|
if (s->xs > 0) s->xs = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
finished = B_TRUE;
|
|
} else if (isspikes(tt, tilex, tiley)) {
|
|
if (!isfruit(s->id) ) {
|
|
if (!s->invuln) {
|
|
if ((s->id != P_BLACKCLOUD) && (s->id != P_KINGSNAIL) && (s->id != P_KINGCAT)) {
|
|
die(s);
|
|
printf("DB: killed by spikes\n"); fflush(stdout);
|
|
}
|
|
}
|
|
}
|
|
finished = B_TRUE;
|
|
} else if (tt->id == T_TRAMPUP) {
|
|
/* tile changes to trampoline down */
|
|
//if (!isfruit(s->id) && !iseffect(s->id) && !isbullet(s->id)) {
|
|
if (isplayer(s)) {
|
|
// are we on a trampoline already?
|
|
if (s->ontramp) {
|
|
// a different one?
|
|
if ((s->trampx != tilex) || (s->trampy != tiley)) {
|
|
// if a different one, release it
|
|
if (s->tramplayer == 1) {
|
|
curlevel->map[s->trampy * LEVELW + s->trampx] = getuniq(T_TRAMPUP);
|
|
} else {
|
|
curlevel->map2[s->trampy * LEVELW + s->trampx] = getuniq(T_TRAMPUP);
|
|
}
|
|
drawtile(temps, s->trampx, s->trampy);
|
|
}
|
|
} else {
|
|
tiletype_t *temptile, *tt;
|
|
int xoff;
|
|
// remember we were on it so it can release
|
|
s->ontramp = B_TRUE;
|
|
s->trampx = tilex;
|
|
s->trampy = tiley;
|
|
// which layer was it on?
|
|
temptile = gettile(curlevel->map2[s->trampy*LEVELW+s->trampx]);
|
|
if (temptile->id == T_TRAMPUP) {
|
|
s->tramplayer = 2;
|
|
} else {
|
|
s->tramplayer = 1;
|
|
}
|
|
|
|
// move it down then draw it
|
|
if (s->tramplayer == 1) {
|
|
curlevel->map[tiley*LEVELW+tilex] = getuniq(T_TRAMPDOWN);
|
|
} else {
|
|
curlevel->map2[tiley*LEVELW+tilex] = getuniq(T_TRAMPDOWN);
|
|
}
|
|
drawtile(temps, tilex, tiley);
|
|
|
|
// move player to new trampoline height
|
|
tt = gettile(T_TRAMPDOWN);
|
|
xoff = checkingx - (tilex*TILEW);
|
|
s->y = (tiley * TILEH) + tt->lowness[xoff];
|
|
}
|
|
}
|
|
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);
|
|
checkingx = s->x + s->img->w/2;
|
|
checkingy = s->y+3;
|
|
state = 1;
|
|
} else if (state == 1) {
|
|
/* check tile to our left */
|
|
tt = gettileat(s->x - s->img->w/2,s->y+3,&tilex,&tiley);
|
|
checkingx = s->x - s->img->w/2;
|
|
checkingy = s->y+3;
|
|
state = 2;
|
|
} else {
|
|
finished = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// initial transition to a new level
|
|
void drawlevel(void) {
|
|
int x,y,i;
|
|
double turns;
|
|
double dist[2];
|
|
int speed = 16;
|
|
//SDL_Surface *playerbg = NULL, *playerbg2 = NULL;
|
|
//SDL_Surface *cloudbg = NULL,*cloudbg2 = NULL;
|
|
SDL_Surface *screencopy = NULL;
|
|
int got1p = B_FALSE,got2p = B_FALSE;
|
|
sprite_t tempcloud, tempcloud2;
|
|
levscrollinfo_t scrollinfo;
|
|
|
|
|
|
// this will hold a copy of the NEW level that we're going to.
|
|
if (temps) {
|
|
SDL_FreeSurface(temps);
|
|
temps = NULL;
|
|
}
|
|
temps = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREENW, SCREENH,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask,
|
|
screen->format->Amask);
|
|
SDL_DisplayFormat(temps);
|
|
|
|
// this will be a copy of the real screen we take before
|
|
// drawing the player and cloud sprites.
|
|
//
|
|
// no alpha mask on screen copy - otherwise we'll need to draw
|
|
// black all over it to make clear out alpha channel.
|
|
screencopy = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREENW, SCREENH,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask, 0);
|
|
SDL_DisplayFormat(screencopy);
|
|
|
|
if (player && player->lives > 0) got1p = B_TRUE;
|
|
if (player2 && player2->lives > 0) got2p = B_TRUE;
|
|
|
|
if (!got1p && !got2p) {
|
|
// ERROR!!
|
|
printf("trying to transition level with no players!!\n ");
|
|
return;
|
|
}
|
|
|
|
// initialise values so we don't accidentally use them
|
|
// uninitialied...
|
|
scrollinfo.player = player;
|
|
scrollinfo.player2 = player2;
|
|
scrollinfo.cloud = NULL;
|
|
scrollinfo.cloud2 = NULL;
|
|
for (i = 0; i < 2; i++) {
|
|
scrollinfo.dstx[i] = 0;
|
|
scrollinfo.dsty[i] = 0;
|
|
scrollinfo.xdis[i] = 0;
|
|
scrollinfo.ydis[i] = 0;
|
|
scrollinfo.pspeed[i] = 1;
|
|
}
|
|
|
|
|
|
// init clouds
|
|
if (got1p) {
|
|
scrollinfo.cloud = &tempcloud;
|
|
scrollinfo.cloud->id = P_PINKCLOUD;
|
|
scrollinfo.cloud->iceimg = NULL;
|
|
setdefaults(scrollinfo.cloud);
|
|
// redo image
|
|
scrollinfo.cloud->img =rotozoomSurfaceXY(imageset[P_PINKCLOUD].img[F_WALK1],0,1,1,0);
|
|
// set player image
|
|
player->img = imageset[player->id].img[F_SHOOT];
|
|
}
|
|
if (got2p) {
|
|
scrollinfo.cloud2 = &tempcloud2;
|
|
scrollinfo.cloud2->id = P_PINKCLOUD;
|
|
scrollinfo.cloud2->iceimg = NULL;
|
|
setdefaults(scrollinfo.cloud2);
|
|
// redo image
|
|
scrollinfo.cloud2->img =rotozoomSurfaceXY(imageset[P_PINKCLOUD].img[F_WALK1],0,1,1,0);
|
|
// set player image
|
|
player2->img = imageset[player2->id].img[F_SHOOT];
|
|
}
|
|
|
|
// draw the full (new) 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 players' new start positions are
|
|
if (player) {
|
|
scrollinfo.dstx[0] = (curlevel->p1x * TILEW) + (TILEW/2);
|
|
scrollinfo.dsty[0] = (curlevel->p1y * TILEH) + TILEH-2;
|
|
}
|
|
if (player2) {
|
|
scrollinfo.dstx[1] = (curlevel->p2x * TILEW) + (TILEW/2);
|
|
scrollinfo.dsty[1] = (curlevel->p2y * TILEH) + TILEH-2;
|
|
}
|
|
|
|
// figure out distance to newposition
|
|
if (player) {
|
|
scrollinfo.xdis[0] = player->x - scrollinfo.dstx[0];
|
|
if (scrollinfo.xdis[0] < 0) scrollinfo.xdis[0] = -scrollinfo.xdis[0];
|
|
scrollinfo.ydis[0] = player->y - scrollinfo.dsty[0];
|
|
if (scrollinfo.ydis[0] < 0) scrollinfo.ydis[0] = -scrollinfo.ydis[0];
|
|
}
|
|
if (player2) {
|
|
scrollinfo.xdis[1] = player2->x - scrollinfo.dstx[1];
|
|
if (scrollinfo.xdis[1] < 0) scrollinfo.xdis[1] = -scrollinfo.xdis[1];
|
|
scrollinfo.ydis[1] = player2->y - scrollinfo.dsty[1];
|
|
if (scrollinfo.ydis[1] < 0) scrollinfo.ydis[1] = -scrollinfo.ydis[1];
|
|
}
|
|
|
|
// figure out how many loops it will take to scroll to the next level
|
|
switch (oldexitdir) {
|
|
case D_LEFT:
|
|
case D_RIGHT:
|
|
speed = 16;
|
|
turns = SCREENW / speed;
|
|
break;
|
|
case D_UP:
|
|
case D_DOWN:
|
|
default:
|
|
speed = 12;
|
|
turns = SCREENH / speed;
|
|
break;
|
|
}
|
|
//turns -= 2; // just to be safe
|
|
|
|
if (turns < 1) turns = 1;
|
|
|
|
// figure out how fast player needs to move to get there in time
|
|
if (player) {
|
|
dist[0] = sqrt((scrollinfo.xdis[0]*scrollinfo.xdis[0]) + (scrollinfo.ydis[0]*scrollinfo.ydis[0]));
|
|
scrollinfo.pspeed[0] = dist[0] / turns;
|
|
}
|
|
if (player2) {
|
|
dist[1] = sqrt((scrollinfo.xdis[1]*scrollinfo.xdis[1]) + (scrollinfo.ydis[1]*scrollinfo.ydis[1]));
|
|
scrollinfo.pspeed[1] = dist[1] / turns;
|
|
}
|
|
|
|
// just to be sure
|
|
//pspeed += 1;
|
|
|
|
// The overall plan here is:
|
|
// - Move player(s) + cloud(s) to new position
|
|
// - shuffle screen along
|
|
// - blit the next column of the new level in place
|
|
if (oldexitdir == D_LEFT) {
|
|
for (x = 0; x < SCREENW; x += speed) {
|
|
leveltransition_moveplayer(&scrollinfo);
|
|
|
|
leveltransition_scrolllevel( 0, 0, SCREENW-speed, SCREENH,
|
|
speed, 0,
|
|
SCREENW-x, 0, speed, SCREENH,
|
|
0, 0, 0, 0);
|
|
|
|
leveltransition_blit(&scrollinfo, screencopy);
|
|
}
|
|
} else if (oldexitdir == D_UP) {
|
|
for (y = 0; y < SCREENH; y += speed) {
|
|
leveltransition_moveplayer(&scrollinfo);
|
|
|
|
leveltransition_scrolllevel( 0, 0, SCREENW, SCREENH-speed,
|
|
0, speed,
|
|
0, SCREENH-y, SCREENW, speed,
|
|
0, 0, 0, 0);
|
|
|
|
leveltransition_blit(&scrollinfo, screencopy);
|
|
}
|
|
} else if (oldexitdir == D_DOWN) {
|
|
for (y = 0; y < SCREENH; y += speed) {
|
|
leveltransition_moveplayer(&scrollinfo);
|
|
|
|
leveltransition_scrolllevel( 0, speed, SCREENW, SCREENH-speed,
|
|
0, 0,
|
|
0, y, SCREENW, speed,
|
|
0, SCREENH-speed, 0, 0);
|
|
|
|
leveltransition_blit(&scrollinfo, screencopy);
|
|
}
|
|
} else { // RIGHT right, or default
|
|
for (x = 0; x < SCREENW; x += speed) {
|
|
leveltransition_moveplayer(&scrollinfo);
|
|
|
|
leveltransition_scrolllevel( speed, 0, SCREENW-speed, SCREENH,
|
|
0, 0,
|
|
x, 0, speed, SCREENH,
|
|
SCREENW-speed, 0, 0, 0);
|
|
|
|
leveltransition_blit(&scrollinfo, screencopy);
|
|
}
|
|
}
|
|
|
|
SDL_BlitSurface(screencopy, NULL, screen, NULL);
|
|
|
|
levelcomplete = B_FALSE;
|
|
}
|
|
|
|
double getspeed(sprite_t *s ) {
|
|
int id = s->id;
|
|
double speed = DEFAULTSPEED;
|
|
|
|
if ((s == player) || (s == player2)) {
|
|
if (haspowerup(s, PW_PILL)) {
|
|
speed = PLAYERPILL;
|
|
} else {
|
|
speed = s->speed;
|
|
}
|
|
} else if (id == P_SNAIL) {
|
|
if (s->recoiling) {
|
|
speed = 2;
|
|
} else {
|
|
if (s->angry) speed = 1;
|
|
else speed = 0.5;
|
|
}
|
|
} else if (id == P_SLUG) {
|
|
if (s->angry) speed = 1;
|
|
else speed = 0.5;
|
|
if (s->jumping) {
|
|
speed = 8; // very fast jumping
|
|
}
|
|
} else if (id == P_FROG) {
|
|
if (s->angry) speed = 1.5;
|
|
else speed = 1;
|
|
} else if (id == P_RAT) {
|
|
if (s->angry) speed = 1.5;
|
|
else speed = 1;
|
|
} else if (id == P_WSPIDER) {
|
|
if (s->angry) speed = 1.5;
|
|
else speed = 1;
|
|
} else if (id == P_ANT1) {
|
|
if (s->angry) speed = 1.5;
|
|
else speed = 1;
|
|
} else if (id == P_ANT2) {
|
|
if (s->angry) speed = 2.5;
|
|
else speed = 2;
|
|
} else if (id == P_ANT3) {
|
|
if (s->angry) speed = 2.5;
|
|
else speed = 2;
|
|
} else if (id == P_SNAKE) {
|
|
if (s->angry) speed = 1.5;
|
|
else speed = 1;
|
|
} else if (id == P_BEE) {
|
|
if (s->angry) speed = 2;
|
|
else speed = 1;
|
|
} else if (id == P_FLY) {
|
|
if (s->owner) {
|
|
speed = 2;
|
|
} else {
|
|
if (s->angry) speed = 2.5;
|
|
else speed = 1.5;
|
|
}
|
|
} else if (id == P_SPIDER) {
|
|
if (s->angry) speed = 2;
|
|
else speed = 1.5;
|
|
} else if (id == P_BAT) {
|
|
if (s->angry) speed = 3;
|
|
else speed = 2.5;
|
|
} else if (id == P_SONAR) {
|
|
speed = 2.5;
|
|
} else if (id == P_KINGRAT) {
|
|
speed = 1.5;
|
|
} else if (id == P_KINGANT) {
|
|
speed = 1.5;
|
|
} else if (id == P_KINGFLY) {
|
|
speed = 2;
|
|
} else if (id == P_KINGCAT) {
|
|
speed = 2;
|
|
} else if (id == P_PLATFORM) {
|
|
speed = PLATFORM_MAXSPEED;
|
|
}
|
|
|
|
if (isinwater(s) && (s->id != P_FISH) && (s->id != P_FROG)) {
|
|
if (!s->hasmask) {
|
|
speed /= 2;
|
|
}
|
|
}
|
|
|
|
if ((globpowerup == PW_SPRAYUP) || (globpowerup == PW_SPRAYDOWN)) {
|
|
if (!isplayer(s)) {
|
|
speed /= 2;
|
|
}
|
|
}
|
|
|
|
return speed;
|
|
}
|
|
|
|
void addfadingtile(int x, int y) {
|
|
int i;
|
|
sprite_t *s;
|
|
for (i = 0; i < nfadingtiles; i++) {
|
|
if ((tilefadex[i] == x) && (tilefadey[i] == y)) {
|
|
// already there
|
|
return;
|
|
}
|
|
}
|
|
tilefadex[nfadingtiles] = x;
|
|
tilefadey[nfadingtiles] = y;
|
|
nfadingtiles++;
|
|
|
|
// add drip
|
|
s = addsprite(P_DRIP, x*TILEW + (TILEW/4) + (rand() % (TILEW/2)), (y*TILEH) + TILEH, "drip");
|
|
s->fallspeed = ICEDRIPSPEED;
|
|
}
|
|
|
|
int addtext(int x, int y, int size, char *string, SDL_Color *c, int delay, int ttype) {
|
|
text_t *t;
|
|
|
|
if (text == NULL) {
|
|
text = malloc(sizeof(text_t));
|
|
t = text;
|
|
t->prev = NULL;
|
|
} else {
|
|
t = lasttext;
|
|
t->next = malloc(sizeof(text_t));
|
|
t->next->prev = t;
|
|
|
|
t = t->next;
|
|
}
|
|
|
|
t->bg = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
300, 110,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask,
|
|
screen->format->Amask);
|
|
|
|
t->type = ttype;
|
|
t->c = c;
|
|
t->x = x;
|
|
t->y = y;
|
|
t->maxsize = size;
|
|
t->size = 3;
|
|
strcpy(t->txt, string);
|
|
t->state = 0;
|
|
t->delay = delay;
|
|
|
|
t->img = TTF_RenderText_Solid(font[t->size], t->txt, *t->c);
|
|
|
|
if (t->img == NULL) {
|
|
printf("rendertext failed for '%s'\n", t->txt);
|
|
fflush(stdout);
|
|
}
|
|
|
|
t->next = NULL;
|
|
lasttext = t;
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
void movetext(void) {
|
|
text_t *t,*nextt;
|
|
int newhelpfreeze = B_FALSE;
|
|
|
|
for (t = text ; t ; t = nextt) {
|
|
nextt = t->next;
|
|
if (t->state == 0) {
|
|
t->size += TEXTSPEED;
|
|
if (t->size >= t->maxsize) {
|
|
if (t->type == TT_HELP) {
|
|
// freeze
|
|
oldlevelcomplete = levelcomplete;
|
|
levelcomplete = LV_HELPFREEZE;
|
|
t->state = t->delay;
|
|
newhelpfreeze = B_TRUE;
|
|
} else {
|
|
t->state = 1;
|
|
}
|
|
}
|
|
} else if (t->state == t->delay) {
|
|
t->size -= TEXTSPEED;
|
|
if (t->size <= 3) {
|
|
if ((t->type == TT_GAMEOVER) && (levelcomplete == LV_GAMEOVER)) {
|
|
// start game over timer
|
|
gameovertime = gtime;
|
|
}
|
|
if (t->type == TT_INTROTEXT) {
|
|
introstate = IS_JUMP;
|
|
}
|
|
killtext(t);
|
|
}
|
|
|
|
} else {
|
|
t->state++;
|
|
}
|
|
}
|
|
|
|
if (newhelpfreeze) {
|
|
// expire delay on all help text
|
|
for (t = text ; t ; t = t->next) {
|
|
if (t->type == TT_HELPSHADOW) {
|
|
t->state = t->delay;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void drawbosshealth(void) {
|
|
int i;
|
|
SDL_Rect area;
|
|
int healthframe;
|
|
int maxhealth;
|
|
|
|
maxhealth = getbosshealth(boss->id);
|
|
|
|
area.x = (SCREENW/2) - maxhealth*(healthbar[0]->w+HEALTHBARGAP);
|
|
area.y = HEALTHBARY;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
|
|
|
|
|
|
// for each health point, draw two bars
|
|
for (i = 0; i < boss->lives; i++) {
|
|
if (i < (maxhealth/8)) {
|
|
healthframe = HF_RED;
|
|
} else if (i <= (maxhealth/3)) {
|
|
healthframe = HF_YELLOW;
|
|
} else {
|
|
healthframe = HF_GREEN;
|
|
}
|
|
|
|
SDL_BlitSurface(healthbar[healthframe], NULL, screen, &area);
|
|
area.x += (healthbar[healthframe]->w + HEALTHBARGAP);
|
|
SDL_BlitSurface(healthbar[healthframe], NULL, screen, &area);
|
|
area.x += (healthbar[healthframe]->w + HEALTHBARGAP);
|
|
}
|
|
}
|
|
|
|
void drawscore(void) {
|
|
SDL_Surface *score;
|
|
SDL_Rect area;
|
|
SDL_Color scorecol;
|
|
int i;
|
|
int numtoshow;
|
|
int numtoshow2;
|
|
int scoreval;
|
|
|
|
|
|
if (player) {
|
|
SDL_Surface *myhead,*myhead5;
|
|
|
|
if (swapplayers) {
|
|
myhead = head2;
|
|
myhead5 = head52;
|
|
} else {
|
|
myhead = head;
|
|
myhead5 = head5;
|
|
}
|
|
|
|
if (forcegoodcard) {
|
|
if ((timer / LUCKYFLASH) % 2 == 0) {
|
|
scorecol = green;
|
|
} else {
|
|
scorecol = red;
|
|
}
|
|
} else {
|
|
scorecol = red;
|
|
}
|
|
|
|
if (wantframerate) {
|
|
scoreval = fps;
|
|
sprintf(tempm, "%d fps",scoreval);
|
|
} else {
|
|
scoreval = player->score;
|
|
addcommas(tempm, scoreval);
|
|
}
|
|
|
|
|
|
/* shadow */
|
|
score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, black);
|
|
area.x = P1SCOREX-2;
|
|
area.y = SCOREY;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(score, NULL, screen, &area);
|
|
SDL_FreeSurface(score);
|
|
/* score */
|
|
score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, scorecol);
|
|
area.x = P1SCOREX;
|
|
area.y = SCOREY-2;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(score, NULL, screen, &area);
|
|
SDL_FreeSurface(score);
|
|
|
|
// lives
|
|
|
|
if (player->lives > 0) {
|
|
// show 1 less than lives
|
|
numtoshow = player->lives-1;
|
|
area.x = P1LIVESX;
|
|
area.y = LIVESY;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
|
|
// show "x5" for lots of lives
|
|
while (numtoshow >= 5) {
|
|
SDL_BlitSurface(myhead5, NULL, screen, &area);
|
|
area.x += (myhead5->w + 3);
|
|
numtoshow -= 5;
|
|
}
|
|
|
|
for (i = 0; i < numtoshow; i++) {
|
|
SDL_BlitSurface(myhead, NULL, screen, &area);
|
|
area.x += (myhead->w + 3);
|
|
}
|
|
} else {
|
|
area.x = P1LIVESX;
|
|
area.y = LIVESY;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
|
|
SDL_BlitSurface(grave, NULL, screen, &area);
|
|
}
|
|
|
|
|
|
// cards
|
|
if (levelcomplete != LV_DOPOKER) {
|
|
area.x = CARDX;
|
|
area.y = CARDY;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
for (i = 0; i < player->numcards; i++) {
|
|
SDL_Surface *cardimg;
|
|
cardimg = imageset[player->card[i]].img[F_WALK1];
|
|
SDL_BlitSurface(cardimg, NULL, screen, &area);
|
|
area.x += (cardimg->w + 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (player2) {
|
|
SDL_Surface *myhead,*myhead5;
|
|
|
|
if (swapplayers) {
|
|
myhead = head;
|
|
myhead5 = head5;
|
|
} else {
|
|
myhead = head2;
|
|
myhead5 = head52;
|
|
}
|
|
|
|
if (forcegoodcard) {
|
|
if ((timer / LUCKYFLASH) % 2 == 0) {
|
|
scorecol = green;
|
|
} else {
|
|
scorecol = purple;
|
|
}
|
|
} else {
|
|
scorecol = purple;
|
|
}
|
|
|
|
if (wantframerate) {
|
|
scoreval = fps;
|
|
sprintf(tempm, "%d fps",scoreval);
|
|
} else {
|
|
scoreval = player2->score;
|
|
addcommas(tempm, scoreval);
|
|
}
|
|
|
|
|
|
/* shadow */
|
|
score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, black);
|
|
area.x = SCREENW - score->w - P1SCOREX - 2;
|
|
area.y = SCOREY-2;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(score, NULL, screen, &area);
|
|
SDL_FreeSurface(score);
|
|
/* score */
|
|
score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, scorecol);
|
|
area.x = SCREENW - score->w - P1SCOREX;
|
|
area.y = SCOREY;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(score, NULL, screen, &area);
|
|
SDL_FreeSurface(score);
|
|
|
|
// lives
|
|
|
|
if (player2->lives > 0) {
|
|
// show 1 less than lives
|
|
numtoshow = player2->lives-1;
|
|
area.x = SCREENW - P1LIVESX;
|
|
area.y = LIVESY;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
|
|
// go left correct amount
|
|
numtoshow2 = numtoshow;
|
|
while (numtoshow2 >= 5) {
|
|
area.x -= (myhead->w + 3);
|
|
numtoshow2 -= 5;
|
|
}
|
|
for (i = 0; i < numtoshow2; i++) {
|
|
area.x -= (myhead->w + 3);
|
|
}
|
|
|
|
|
|
// now start displaying
|
|
|
|
// show "x5" for lots of lives
|
|
while (numtoshow >= 5) {
|
|
SDL_BlitSurface(myhead5, NULL, screen, &area);
|
|
area.x += (myhead5->w + 3);
|
|
numtoshow -= 5;
|
|
}
|
|
|
|
for (i = 0; i < numtoshow; i++) {
|
|
SDL_BlitSurface(myhead, NULL, screen, &area);
|
|
area.x += (myhead->w + 3);
|
|
}
|
|
} else {
|
|
area.x = SCREENW - P1LIVESX - (myhead->w);
|
|
area.y = LIVESY;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
|
|
SDL_BlitSurface(grave, NULL, screen, &area);
|
|
}
|
|
|
|
|
|
// cards
|
|
if (levelcomplete != LV_DOPOKER) {
|
|
//area.x = SCREENW - CARDX - (5*(imageset[P_FIRSTCARD].img[F_WALK1]->w + 2));
|
|
area.x = SCREENW - CARDX - (imageset[P_FIRSTCARD].img[F_WALK1]->w );
|
|
area.y = CARDY;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
for (i = 0; i < player2->numcards; i++) {
|
|
SDL_Surface *cardimg;
|
|
cardimg = imageset[player2->card[i]].img[F_WALK1];
|
|
SDL_BlitSurface(cardimg, NULL, screen, &area);
|
|
area.x -= (cardimg->w + 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
// level #
|
|
if (globpowerup != PW_ENDGAME) {
|
|
sprintf(tempm, "Level %d-%d",getcurworld(), getcurlevel());
|
|
/* shadow */
|
|
score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, black);
|
|
area.x = 320-(score->w/2)-2;
|
|
area.y = 7;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(score, NULL, screen, &area);
|
|
SDL_FreeSurface(score);
|
|
/* text */
|
|
score = TTF_RenderText_Solid(font[TEXTSIZE_SCORE], tempm, white);
|
|
area.x = 320-(score->w/2);
|
|
area.y = 5;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
SDL_BlitSurface(score, NULL, screen, &area);
|
|
SDL_FreeSurface(score);
|
|
}
|
|
|
|
|
|
drawcredits();
|
|
|
|
}
|
|
|
|
void drawtext(void) {
|
|
text_t *t;
|
|
SDL_Rect area;
|
|
|
|
for (t = text ; t ; t = t->next) {
|
|
if ((levelcomplete != LV_HELPFREEZE) || (t->type == TT_HELP)) {
|
|
|
|
/* create text */
|
|
if (t->img) {
|
|
SDL_FreeSurface(t->img);
|
|
t->img = NULL;
|
|
}
|
|
t->img = TTF_RenderText_Solid(font[t->size], t->txt, *t->c);
|
|
|
|
// make sure it's on the screen (leave space for border)
|
|
if (t->x - (t->img->w / 2) < 2) { // left
|
|
t->x = 2 + (t->img->w/2);
|
|
}
|
|
if (t->x + (t->img->w / 2) > SCREENW-2) { // right
|
|
t->x = SCREENW-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) > SCREENH-2) { // bottom
|
|
t->y = SCREENH-2 - (t->img->h/2);
|
|
}
|
|
|
|
|
|
/* get bg */
|
|
/*
|
|
t->bgarea.x = t->x - t->img->w/2;
|
|
t->bgarea.y = t->y - t->img->h/2;
|
|
t->bgarea.w = t->img->w;
|
|
t->bgarea.h = t->img->h;
|
|
SDL_BlitSurface(screen, &t->bgarea, t->bg, NULL);
|
|
*/
|
|
|
|
/* draw text */
|
|
area.x = t->x - t->img->w/2;
|
|
area.y = t->y - t->img->h/2;
|
|
area.w = t->img->w;
|
|
area.h = t->img->h;
|
|
SDL_BlitSurface(t->img,NULL, screen, &area);
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
/* copy background buffer (ie. tiles) to screen, erasing sprites */
|
|
void removeall(void) {
|
|
sprite_t *s;
|
|
text_t *t;
|
|
SDL_Rect area;
|
|
int clearfull = B_FALSE;
|
|
int *animtile;
|
|
|
|
|
|
/*
|
|
switch (player->powerup) {
|
|
case PW_CANNONFIRE:
|
|
case PW_SPRAYUP:
|
|
case PW_SPRAYDOWN:
|
|
case PW_BOMB:
|
|
case PW_RATSHAKE:
|
|
clearfull = B_TRUE;
|
|
break;
|
|
}
|
|
switch (levelcomplete) {
|
|
case LV_DOPOKER:
|
|
case LV_HELPFREEZE:
|
|
case LV_CLOUDLOOP:
|
|
case LV_CLOUD:
|
|
case LV_NEXTLEV:
|
|
clearfull = B_TRUE;
|
|
break;
|
|
}
|
|
if (curlevel->iced) clearfull = B_TRUE;
|
|
if (paused) clearfull = B_TRUE;
|
|
|
|
if (playedbell == BELL_DONESOUND) {
|
|
if (timer < BELLTIME) {
|
|
clearfull = B_TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
if (isbosslevel(curlevelnum)) {
|
|
clearfull = B_TRUE;
|
|
}
|
|
*/
|
|
clearfull = B_TRUE;
|
|
|
|
|
|
if (clearfull) {
|
|
// clear the entire screen
|
|
SDL_BlitSurface(temps, NULL, screen, NULL);
|
|
} else {
|
|
for (s = sprite; s ; s = s->next) {
|
|
/*
|
|
// blit every tile coverting this sprite
|
|
startx = s->x - (s->img->w/2);
|
|
starty = s->y - s->img->h;
|
|
endx = s->x + (s->img->w/2);
|
|
endy = s->y;
|
|
|
|
for (y = starty ; y <= endy; y++) {
|
|
for (x = startx ; x <= endx; x++) {
|
|
drawtile(screen,x,y);
|
|
}
|
|
}*/
|
|
removesprite(s);
|
|
}
|
|
|
|
|
|
// animated tiles
|
|
for (animtile = curlevel->animtiles; animtile && *animtile != -1; animtile++) {
|
|
int offset,tx,ty;
|
|
|
|
offset = *animtile;
|
|
|
|
tx = offset%LEVELW; ty = offset / LEVELW;
|
|
area.x = tx*TILEW;
|
|
area.y = ty*TILEH;
|
|
area.w = TILEW;
|
|
area.h = TILEH;
|
|
SDL_BlitSurface(temps, &area, screen, &area);
|
|
|
|
}
|
|
|
|
// remove all text
|
|
for (t = text ; t ; t = t->next) {
|
|
/* draw text */
|
|
area.x = t->x - t->img->w/2;
|
|
area.y = t->y - t->img->h/2;
|
|
area.w = t->img->w;
|
|
area.h = t->img->h;
|
|
SDL_BlitSurface(temps, &area, screen, &area);
|
|
}
|
|
|
|
// clear top left (with score +cards)
|
|
area.x = 0;
|
|
area.y = 0;
|
|
area.w = 200;
|
|
area.h = 80;
|
|
SDL_BlitSurface(temps, &area, screen, &area);
|
|
|
|
// clear top middle (level)
|
|
area.x = 250;
|
|
area.y = 0;
|
|
area.w = 100;
|
|
area.h = 25;
|
|
SDL_BlitSurface(temps, &area, screen, &area);
|
|
|
|
// clear bottom middle (credits)
|
|
area.x = 270;
|
|
area.y = 455;
|
|
area.w = 130;
|
|
area.h = 24;
|
|
SDL_BlitSurface(temps, &area, screen, &area);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void drawnetting(sprite_t *s) {
|
|
int sx;
|
|
int xx;
|
|
SDL_Rect area;
|
|
|
|
if (!s) return;
|
|
|
|
if (s->powerup == PW_RAYGUN) return;
|
|
|
|
if (s->netting) {
|
|
int y,yy;
|
|
int dis;
|
|
int netsleft;
|
|
|
|
sx = s->x;
|
|
s->nety = s->y - (s->img->h/2) + 2;
|
|
|
|
s->netxstart = s->x;
|
|
s->netystart = s->nety - 3;
|
|
|
|
|
|
|
|
|
|
if (s->netdir == 1) {
|
|
area.x = s->netxstart + TILEW/2;
|
|
} else {
|
|
area.x = s->netxstart - TILEW/2 - s->netlen;
|
|
}
|
|
//area.y = s->netystart;
|
|
area.y = s->y - s->img->h-2 + 2;
|
|
area.w = s->netlen;
|
|
area.h = s->img->h+2;
|
|
SDL_BlitSurface(screen, &area,s->netbg, NULL);
|
|
|
|
netsleft = s->netmax - s->netcaught;
|
|
if (netsleft < 1) netsleft = 1;
|
|
dis = (int)s->img->h / (int)(netsleft+1) + 1;
|
|
|
|
for (y = dis; y < s->img->h; y += dis) {
|
|
SDL_Rect endarea;
|
|
SDL_Surface *netim;
|
|
|
|
yy = s->y - s->img->h;
|
|
yy += y;
|
|
|
|
xx = s->x + s->netdir*s->netlen;
|
|
if (s->netsticky) {
|
|
drawdotline16(screen,sx,s->nety,xx,yy,orange,yellow);
|
|
} else {
|
|
drawdotline16(screen,sx,s->nety,xx,yy,white,white2);
|
|
}
|
|
// add sparkle
|
|
xx = s->x + s->netdir*s->netlen;
|
|
if (levelcomplete != LV_HELPFREEZE) {
|
|
addsprite(P_SPARKLE, xx + (rand() % 14) - 7, yy + (rand() % 8) - 4, "sparkle");
|
|
}
|
|
|
|
netim = imageset[P_NET].img[(s->netdir == 1) ? 0 : 1];
|
|
endarea.x = xx;
|
|
endarea.y = yy - (netim->h/2);
|
|
|
|
SDL_BlitSurface(netim, NULL, screen, &endarea);
|
|
}
|
|
|
|
|
|
//drawline(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety-3,white);
|
|
//drawline(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety,white);
|
|
//drawline(screen,sx,s->nety,s->x + s->netdir*s->netlen,s->nety+3,white);
|
|
} else if (s->slamming) {
|
|
double dist;
|
|
int x,y;
|
|
int ii;
|
|
SDL_Color *col1,*col2;
|
|
dist = (s->slamangle * (180/M_PI))/2;
|
|
if (s->powerup == PW_SMALLNET) {
|
|
dist /= 2;
|
|
}
|
|
|
|
s->netxstart = s->x + cos(s->slamangle-(180*(M_PI/180)))*dist*s->dir;
|
|
s->netystart = s->y + sin(s->slamangle-(180*(M_PI/180)))*dist;
|
|
|
|
// select colours
|
|
if (s->netsticky) {
|
|
col1 = &orange;
|
|
col2 = &yellow;
|
|
} else {
|
|
col1 = &white;
|
|
col2 = &white2;
|
|
}
|
|
|
|
/* middle dotline */
|
|
drawdotline16(screen,s->x,s->y - s->img->h/2,
|
|
s->netxstart,s->netystart,*col1,*col2);
|
|
/* left dotline */
|
|
x = s->x + cos(s->slamangle-(5*(M_PI/180))-(180*(M_PI/180)))*dist*s->dir;
|
|
y = s->y + sin(s->slamangle-(5*(M_PI/180))-(180*(M_PI/180)))*dist;
|
|
drawdotline16(screen,s->x,s->y - s->img->h/2,x, y, *col1,*col2);
|
|
|
|
/* right dotline */
|
|
x = s->x + cos(s->slamangle+(5*(M_PI/180))-(180*(M_PI/180)))*dist*s->dir;
|
|
y = s->y + sin(s->slamangle+(5*(M_PI/180))-(180*(M_PI/180)))*dist;
|
|
drawdotline16(screen,s->x,s->y - s->img->h/2,x, y, *col1,*col2);
|
|
|
|
// add sparkles
|
|
for (ii = 0 ; ii < s->netmax; ii++) {
|
|
addsprite(P_SPARKLE, s->netxstart + (rand() % 8) - 4, s->netystart + (rand() % 8) - 4, "sparkle");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void removenetting(sprite_t *s) {
|
|
SDL_Rect area,sarea;
|
|
|
|
if (s->netting) {
|
|
sarea.x = 0;
|
|
sarea.y = 0;
|
|
sarea.w = s->netlen;
|
|
sarea.h = s->img->h+2;
|
|
|
|
if (s->netdir == 1) {
|
|
area.x = s->netxstart + TILEW/2;
|
|
} else {
|
|
area.x = s->netxstart - TILEW/2 - s->netlen;
|
|
}
|
|
//area.y = s->netystart;
|
|
area.y = s->y - s->img->h-2;
|
|
area.w = s->netlen;
|
|
area.h = s->img->h+2;
|
|
|
|
if (s->netbg != NULL) {
|
|
SDL_BlitSurface(s->netbg, &sarea, screen, &area);
|
|
}
|
|
}
|
|
}
|
|
|
|
int randommonster(void) {
|
|
switch (rand() % 4) {
|
|
case 0: return P_RAT;
|
|
case 1: return P_BEE;
|
|
case 2: return P_ANT2;
|
|
case 3: return P_WSPIDER;
|
|
}
|
|
return P_RAT;
|
|
}
|
|
|
|
void removesprite(sprite_t *s) {
|
|
int startx,starty,endx,endy;
|
|
int x,y;
|
|
|
|
if (s == NULL) return;
|
|
|
|
|
|
// find topleft-most tile
|
|
gettileat(s->x - s->img->w, s->y - s->img->h,&startx,&starty);
|
|
// find bottomright-most tile
|
|
gettileat(s->x + s->img->w, s->y + s->img->h,&endx,&endy);
|
|
|
|
if (s->slamming) {
|
|
if (s->dir == D_LEFT) {
|
|
startx -= 5;
|
|
endx += 1;
|
|
} else {
|
|
startx -= 1;
|
|
endx += 5;
|
|
}
|
|
starty -= 2;
|
|
endy += 1;
|
|
}
|
|
if (s->netting) {
|
|
if (s->dir == D_LEFT) {
|
|
if (s->powerup == PW_ACCORDION) {
|
|
startx = 0;
|
|
} else {
|
|
startx -= 5;
|
|
}
|
|
} else {
|
|
if (s->powerup == PW_ACCORDION) {
|
|
endx = LEVELW-1;
|
|
} else {
|
|
endx += 5;
|
|
}
|
|
}
|
|
starty -= 1;
|
|
endy += 1;
|
|
}
|
|
if (s->doublejump) {
|
|
if (s->dir == D_LEFT) {
|
|
endx += 2;
|
|
} else {
|
|
startx -= 2;
|
|
}
|
|
}
|
|
// handle spider's web
|
|
if ((s->id == P_SPIDER) && ((s->ys != -99) || s->falling) && !s->dead && !s->caughtby && !s->iced) {
|
|
// do entire column
|
|
starty = 0;
|
|
}
|
|
|
|
// draw the tiles
|
|
for (y = starty; y <= endy; y++) {
|
|
for (x = startx; x <= endx; x++) {
|
|
drawtile(screen,x,y);
|
|
}
|
|
}
|
|
}
|
|
|
|
int isonbridge(sprite_t *s) {
|
|
tiletype_t *tthere;
|
|
tthere = gettileat(s->x,s->y, NULL,NULL);
|
|
if (isbridge(tthere->id)) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isladder(int tid) {
|
|
switch (tid) {
|
|
case T_LADDER:
|
|
case T_LADDERTOP:
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
|
|
// return the x position of the middle of the ladder if so
|
|
int isonladder(sprite_t *s) {
|
|
int tx;
|
|
tiletype_t *tthere;
|
|
tthere = gettileat(s->x,s->y, &tx,NULL);
|
|
if (isladder(tthere->id)) {
|
|
return (tx*TILEW)+(TILEW/2);
|
|
}
|
|
|
|
// if ladder above and climbing
|
|
if (isladderabove(s) && s->climbing) {
|
|
return isladderabove(s);
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
// return the x position of the middle of the ladder if so
|
|
int isladderabove(sprite_t *s) {
|
|
tiletype_t *tthere;
|
|
int tx;
|
|
//tthere = gettileat(s->x,s->y-TILEH, NULL,NULL);
|
|
tthere = gettileat(s->x,s->y-s->img->h, &tx,NULL);
|
|
if (isladder(tthere->id)) {
|
|
return (tx*TILEW)+(TILEW/2);
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
// return the x position of the middle of the ladder if so
|
|
int isladderbelow(sprite_t *s) {
|
|
tiletype_t *tthere;
|
|
int tx;
|
|
//tthere = gettileat(s->x,s->y-TILEH, NULL,NULL);
|
|
tthere = gettileat(s->x,s->y, &tx,NULL);
|
|
if (isladder(tthere->id)) {
|
|
return (tx*TILEW)+(TILEW/2);
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isdeadly(tiletype_t *tt, int tx, int ty) {
|
|
int curframe;
|
|
|
|
curframe = curlevel->tileframe[ty*LEVELW+tx];
|
|
if (tt->killframe[curframe]) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isspikes(tiletype_t *tt, int tx, int ty) {
|
|
int curframe;
|
|
if (tt->spikes) return B_TRUE;
|
|
|
|
curframe = curlevel->tileframe[ty*LEVELW+tx];
|
|
if (tt->spikeframe[curframe]) {
|
|
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);
|
|
if (ypos < 0) return B_TRUE;
|
|
|
|
/* get tile above sprite's head */
|
|
tt = gettileat(s->x, ypos,NULL,NULL);
|
|
if (tt->solid) return B_TRUE;
|
|
tt = gettileat(s->x + (s->img->w/2 - 2), ypos,NULL,NULL);
|
|
if (tt->solid) return B_TRUE;
|
|
tt = gettileat(s->x - (s->img->w/2 - 2), ypos,NULL,NULL);
|
|
if (tt->solid) return B_TRUE;
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isonground(sprite_t *s) {
|
|
// are we on a platform?
|
|
if (s->onplatform) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
// antigrav?
|
|
if (s->antigrav ) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
/* get tile below sprite's feet */
|
|
if (isongroundpoint(s, s->x, s->y)) {
|
|
return B_TRUE;
|
|
}
|
|
if ((s->dead) || (!s->falling && !s->dropping)) {
|
|
if (!s->swimming) {
|
|
if (isongroundpoint(s, s->x + s->img->w/2, s->y)) {
|
|
return B_TRUE;
|
|
}
|
|
if (isongroundpoint(s, s->x - s->img->w/2, s->y)) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//if (s->falling && s->id == P_KINGRAT) {
|
|
if (s->id == P_KINGRAT) {
|
|
if (isongroundpoint(s, s->x + s->img->w/2, s->y)) {
|
|
return B_TRUE;
|
|
}
|
|
if (isongroundpoint(s, s->x - s->img->w/2, s->y)) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int isongroundpoint(sprite_t *s, int x,int y) {
|
|
tiletype_t *tt;
|
|
int tilex,tiley;
|
|
int xoff;
|
|
int groundy;
|
|
|
|
if (s->onplatform) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
tt = gettileat(x,y, &tilex, &tiley);
|
|
|
|
// slope etc doesn't matter if you're dead
|
|
if (s->dead && tt->solid) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
// when dropping, the tile you dropped from doesn't count
|
|
// as "ground".
|
|
//if (s->dropping && (tilex == s->dropx) && (tiley == s->dropy)) {
|
|
if (s->dropping && (tiley == s->dropy)) {
|
|
return B_FALSE;
|
|
}
|
|
|
|
/* get offset */
|
|
xoff = x - (tilex*TILEW);
|
|
|
|
/* if it's not solid... */
|
|
if (tt->solid == 0) {
|
|
return B_FALSE;
|
|
} else {
|
|
/* check height of tile at that position */
|
|
groundy = tiley*TILEH + tt->lowness[xoff];
|
|
|
|
/* above ground level */
|
|
if (y < groundy) {
|
|
return B_FALSE;
|
|
} else if (y > groundy + 3) {
|
|
/* below ground level */
|
|
if (s->jumping) {
|
|
return B_FALSE;
|
|
}
|
|
} else if (s->falling) {
|
|
tiletype_t *abovetile;
|
|
/* falling, on a tile, but with tiles above you */
|
|
// ie. you've jumped up through a single tile (can't
|
|
// jump through two or more tiles
|
|
abovetile = gettileat(x,y-TILEH, NULL, NULL);
|
|
if (abovetile->solid) {
|
|
return B_FALSE;
|
|
}
|
|
// } else if (s->dropping) {
|
|
// tiletype_t *abovetile;
|
|
/* if the tile we're on is solid but not the one
|
|
above, then we've "dropped" and are still
|
|
travelling through the tile we dropped from. */
|
|
// abovetile = gettileat(x,y-TILEH, NULL, NULL);
|
|
// if (!abovetile->solid) {
|
|
// return B_FALSE;
|
|
// }
|
|
}
|
|
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
void dogravity(sprite_t *s) {
|
|
sprite_t *s2;
|
|
tiletype_t *tt;
|
|
int tilex,tiley;
|
|
|
|
if (!s) return;
|
|
|
|
if (s->id == P_PINKCLOUD) return;
|
|
|
|
// only player can move if you have a clock
|
|
if (globpowerup == PW_CLOCK) {
|
|
if (!iseffect(s->id) && (!isplayer(s)) && !s->caughtby && !s->dead) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// no gravity for players if you have the machine gun
|
|
if (haspowerupany(PW_GUNNER)) {
|
|
if (isplayer(s)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
// if we were on a trampoline and are now not, it releases */
|
|
if (s->id != P_BLACKCLOUD) {
|
|
tt = gettileat(s->x,s->y,&tilex,&tiley);
|
|
if (s->ontramp) {
|
|
if (s->trampy == tiley) {
|
|
// you jump automatically!
|
|
jump(s, s->xs / getspeed(s));
|
|
} else {
|
|
//if (s->trampy != tiley) {
|
|
// change tile type
|
|
if (s->tramplayer == 1) {
|
|
curlevel->map[s->trampy * LEVELW + s->trampx] = getuniq(T_TRAMPUP);
|
|
} else {
|
|
curlevel->map2[s->trampy * LEVELW + s->trampx] = getuniq(T_TRAMPUP);
|
|
}
|
|
drawtile(temps, s->trampx, s->trampy);
|
|
|
|
// update sprite settings
|
|
s->ontramp = B_FALSE;
|
|
s->trampx = -1;
|
|
s->trampy = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s->dead) return;
|
|
|
|
// update flashing bosses
|
|
if ((s == boss) && (s->angry)) {
|
|
s->angry--;
|
|
}
|
|
|
|
if (s->flies && !s->iced) return; // no gravity if you fly, but ice cancels flying
|
|
if (s->id != P_KSSHELL) {
|
|
if (iseffect(s->id)) return;
|
|
}
|
|
if (isbullet(s->id)) return;
|
|
|
|
|
|
//if (isonladder(s) && !s->falling && !s->jumping) {
|
|
/*
|
|
if (isonladder(s) ) {
|
|
s->falling = B_FALSE;
|
|
return;
|
|
}
|
|
*/
|
|
// iced sprites can't jump
|
|
if (s->iced) {
|
|
s->jumping = B_FALSE;
|
|
}
|
|
|
|
// update water stats
|
|
if ((isplayer(s) || ismonster(s->id)) && !s->oncloud) {
|
|
if (isinwater(s)) {
|
|
if (!s->swimming) {
|
|
// we just entered the water
|
|
s->swimming = B_TRUE;
|
|
s->watertimer = rand() % BUBBLETIME;
|
|
// play a splash sound
|
|
if (curlevel->iced != WATER_INPROGRESS) {
|
|
if (!s->caughtby && !s->dead) {
|
|
playfx(FX_SPLASH);
|
|
}
|
|
}
|
|
|
|
// give player a mask if they don't have one
|
|
if (isplayer(s) && (s->hasmask)) {
|
|
sprite_t *ms;
|
|
int found = B_FALSE;
|
|
// is there one already?
|
|
for (ms = sprite; ms ; ms = ms->next) {
|
|
if ((ms->id == P_MASK) && (ms->owner == s)) {
|
|
found = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
ms = addsprite(P_MASK, s->x + MASKOFFSETX*s->dir, s->y + MASKOFFSETY, "mask");
|
|
ms->owner = s;
|
|
}
|
|
}
|
|
|
|
// adjust x pos so we don't get stuck in a wall
|
|
if (isplayer(s)) adjustx(s, F_SWIM1);
|
|
else adjustx(s, F_WALK1);
|
|
|
|
if (isplayer(s)) {
|
|
// dim the music
|
|
Mix_VolumeMusic(MIX_MAX_VOLUME/3);
|
|
}
|
|
}
|
|
// generate bubbles
|
|
// just use s->x and s->y to add randomness, so that
|
|
// all sprites don't make bubbles at the same time
|
|
s->watertimer++;
|
|
if (s->watertimer >= BUBBLETIME) {
|
|
addsprite(P_BUBBLE,s->x + (s->dir*((s->img->w/4)+(rand() % 12 - 6))),s->y-(s->img->h/2),"bubble" );
|
|
s->watertimer = 0;
|
|
}
|
|
} else {
|
|
if (s->swimming) {
|
|
sprite_t *ms;
|
|
// exitted the water
|
|
s->swimming = B_FALSE;
|
|
if (isplayer(s)) {
|
|
Mix_VolumeMusic(MIX_MAX_VOLUME);
|
|
}
|
|
// get rid of the mask
|
|
for (ms = sprite; ms ; ms = ms->next) {
|
|
if ((ms->id == P_MASK) && (ms->owner == s)) {
|
|
ms->dead = D_FINAL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s->climbing) {
|
|
int attop = B_FALSE;
|
|
// check if we are at the top of our ladder
|
|
//tt = gettileat(s->x, s->y - s->img->h-1,NULL,NULL);
|
|
|
|
if (!isonladder(s)) {
|
|
attop = B_TRUE;
|
|
}
|
|
|
|
if (isongroundpoint(s, s->x, s->y)) {
|
|
if (!isongroundpoint(s, s->x, s->y-1)) {
|
|
attop = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (attop) {
|
|
s->climbing = B_FALSE;
|
|
} else {
|
|
// don't do any more checking
|
|
return;
|
|
}
|
|
}
|
|
|
|
// handle jumps
|
|
if (s->jumping) {
|
|
s->falling = B_FALSE;
|
|
s->y -= s->jumpspeed;
|
|
s->jumping++;
|
|
if (s->jumping % 5 == 0) {
|
|
if (s->jumpspeed > 0) {
|
|
s->jumpspeed--;
|
|
} else {
|
|
s->jumping = B_FALSE;
|
|
s->falling = B_TRUE;
|
|
s->fallspeed = 0;
|
|
}
|
|
|
|
if (s->powerup == PW_JETPACK) {
|
|
puffin(-1, s->x, s->y, "jet_puff", 0);
|
|
}
|
|
}
|
|
|
|
// handle ring
|
|
if (isplayer(s)) {
|
|
if (s->powerup == PW_RINGJUMP) {
|
|
if (timer % 2 == 0) {
|
|
int xx,yy;
|
|
// add sparkle
|
|
xx = s->x + (rand() % s->img->w) - (s->img->w/2);
|
|
yy = s->y - (rand() % (s->img->h/2));
|
|
addsprite(P_SPARKLE, xx, yy, "sparkle");
|
|
|
|
// gain points
|
|
addscore(s, 65);
|
|
}
|
|
}
|
|
}
|
|
|
|
// king ant makes flames
|
|
if (s->id == P_KINGANT) {
|
|
// add flames on it
|
|
if (( timer % 2) == 0) {
|
|
addsprite(P_FLAME, s->x + (rand() % s->img->w) - (s->img->w/2),
|
|
s->y - (s->img->h/2) + (rand() % s->img->h/2), "antflame");
|
|
}
|
|
}
|
|
|
|
|
|
/* have we hit a roof ? */
|
|
if (isroofabove(s)) {
|
|
// king ANT destroys tiles when jumping, and shoots at players
|
|
if (s->id == P_KINGANT) {
|
|
int xxx;
|
|
int tx,ty;
|
|
|
|
// melt roof
|
|
for (xxx = s->x - (s->img->w/2) ; xxx < s->x + (s->img->w/2) ; xxx += TILEW) {
|
|
tt = gettileat(xxx, s->y - s->img->h,&tx,&ty);
|
|
if (isbridge(tt->id)) {
|
|
// melt it!
|
|
melttile(tx,ty,REGROWTIMER_LONG, B_PUFF);
|
|
}
|
|
}
|
|
|
|
|
|
// shoot at players
|
|
if (!s->bullet) {
|
|
sprite_t *mytarget;
|
|
// shoot fireball if player in front!
|
|
mytarget = isplayerahead(s);
|
|
if (mytarget) {
|
|
sprite_t *ss;
|
|
// shoot!
|
|
playfx(FX_METEOR);
|
|
ss = addsprite(P_BIGFIREBALL,s->x,mytarget->y+(TILEH/2),"horzfireball" );
|
|
ss->ys = 0;
|
|
ss->xs = s->dir * 4;
|
|
ss->dir = s->dir;
|
|
ss->owner = s;
|
|
|
|
s->bullet = ss;
|
|
}
|
|
}
|
|
|
|
}
|
|
/* can jump through one tile, but not two or more */
|
|
if (isroofnabove(s,2)) {
|
|
if ((s->id != P_KINGRAT) && (s->id != P_KINGANT)) { // king rat can't hit roof
|
|
/* stop jumping */
|
|
s->jumping = B_FALSE;
|
|
s->falling = B_TRUE;
|
|
s->fallspeed = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else { // not jumping
|
|
int ontheground;
|
|
if ((isfruit(s->id) == FT_SUPER) && (s->y < SCREENH/2)) {
|
|
ontheground = B_FALSE;
|
|
} else {
|
|
ontheground = isonground(s);
|
|
}
|
|
|
|
if (ontheground) {
|
|
// reset doublejump
|
|
if (s->doublejump) {
|
|
s->useddoublejump = B_FALSE;
|
|
}
|
|
|
|
// reset jumpdir
|
|
if (!s->jumptimer) {
|
|
s->jumpdir = 0;
|
|
}
|
|
|
|
if (s->falling && s->iced) {
|
|
// when an iced monster hits the ground, it smashes
|
|
s->willbecome = P_DIAMOND;
|
|
if (s->id == P_SNAIL) s->id = P_SLUG;
|
|
playfx(FX_ICEBREAK);
|
|
die(s);
|
|
}
|
|
if ((s->id == P_KINGRAT) && (s->timer1 == KRS_FALL)) { // special case
|
|
// king rat drops until he is at player height
|
|
if (!playersalive() || isplayerbelow(s)) { // above player
|
|
ontheground = B_FALSE;
|
|
} else { // above player
|
|
s->dropping = B_FALSE;
|
|
s->falling = B_FALSE;
|
|
s->climbing = B_FALSE;
|
|
}
|
|
} else if ((s->id == P_KINGANT) && ((s->timer1 == KAS_FALL1) || (s->timer1 == KAS_FALL2))) { // special case
|
|
int xxx,tx,ty;
|
|
// add extra flames on it
|
|
if (( timer % 2) == 0) {
|
|
addsprite(P_FLAME, s->x + (rand() % s->img->w) - (s->img->w/2),
|
|
s->y - (s->img->h/2) + (rand() % s->img->h/2), "antflame");
|
|
}
|
|
// king ant drops until he is at the wanted height
|
|
if (s->y >= s->timer3) {
|
|
s->dropping = B_FALSE;
|
|
s->falling = B_FALSE;
|
|
s->climbing = B_FALSE;
|
|
} else {
|
|
// keep falling through
|
|
ontheground = B_FALSE;
|
|
}
|
|
|
|
// king ant melts ground
|
|
for (xxx = s->x - (s->img->w/2) ; xxx < s->x + (s->img->w/2) ; xxx += TILEW) {
|
|
tt = gettileat(xxx, s->y + 2 ,&tx,&ty);
|
|
if (isbridge(tt->id)) {
|
|
melttile(tx,ty,REGROWTIMER_LONG, B_PUFF);
|
|
}
|
|
}
|
|
} else if ((s->id == P_KINGSNAIL) && (s->timer1 == KSS_JUMPING)) { // special case
|
|
// king snail drops until he is at original height
|
|
if (s->y < s->timer3) { // above orig height
|
|
ontheground = B_FALSE;
|
|
} else {
|
|
s->dropping = B_FALSE;
|
|
s->falling = B_FALSE;
|
|
s->climbing = B_FALSE;
|
|
}
|
|
} else if ((s->id == P_SNAIL) && (s->lives == 0) && s->falling) {
|
|
// snail dies - this is actuall the snail's shell
|
|
s->dead = D_FINAL;
|
|
} else if ((s->id == P_KSSHELL) && s->falling) {
|
|
// king snail's shell dies when it hits the ground
|
|
s->dead = D_FINAL;
|
|
} else { // everyone else
|
|
s->dropping = B_FALSE;
|
|
s->falling = B_FALSE;
|
|
s->climbing = B_FALSE;
|
|
}
|
|
}
|
|
|
|
// snail also dies if it's been alive too long
|
|
if ((s->id == P_SNAIL) && (s->lives == 0) && (!s->invuln)) {
|
|
s->dead = D_FINAL;
|
|
}
|
|
|
|
// don't use an ELSE here because king rat needs to fall through
|
|
if (!ontheground) {
|
|
//if ((s->id == P_KINGRAT) && ((s->timer1 == KRS_CHARGE) || (s->timer1 == KRS_WALK))) {
|
|
// do nothing
|
|
//} else {
|
|
//if (!s->climbing) {
|
|
if (s->falling == B_FALSE) {
|
|
s->fallspeed = 1;
|
|
}
|
|
s->falling = B_TRUE;
|
|
|
|
if (isplayer(s)) {
|
|
// stop ice inertia
|
|
if (!s->moved) {
|
|
s->xs = 0;
|
|
}
|
|
}
|
|
|
|
if (endgame && isplayer(s)) {
|
|
// don't fall
|
|
} else if (s->id == P_FLY) {
|
|
// constant speed - we are flying down, not falling
|
|
s->y += getspeed(s);
|
|
} else {
|
|
double termvel;
|
|
|
|
if (isinwater(s) && !s->iced) {
|
|
if (s->hasmask) {
|
|
// bob around
|
|
s->y += (sin(timer/5)/3);
|
|
} else {
|
|
// sink
|
|
s->y += (s->fallspeed/2);
|
|
}
|
|
} else {
|
|
s->y += s->fallspeed;
|
|
}
|
|
|
|
if (s->umbrella && s->umbrellaup) {
|
|
termvel = UMBFALLSPEED;
|
|
} else {
|
|
termvel = FALLSPEED;
|
|
}
|
|
|
|
if ((timer % 10 == 0) && (s->fallspeed < termvel)) {
|
|
s->fallspeed++;
|
|
}
|
|
|
|
if (s->fallspeed > termvel) s->fallspeed = termvel;
|
|
}
|
|
//}
|
|
//}
|
|
|
|
}
|
|
}
|
|
|
|
// extend/withdraw player net
|
|
if (s->netting) {
|
|
tiletype_t *tt;
|
|
double xx,yy;
|
|
double disfromtop,incamt;
|
|
int stop = B_FALSE;
|
|
|
|
// check for net hitting bad tile.
|
|
xx = s->x + (s->netlen * s->netdir);
|
|
//incamt = (int)s->img->h / (int)(netsleft+1) + 1;
|
|
incamt = (int)s->img->h / (int)(s->netmax+1) + 1;
|
|
for (disfromtop = incamt; disfromtop < s->img->h; disfromtop += incamt) {
|
|
yy = s->y - s->img->h + disfromtop;
|
|
tt = gettileat(xx,yy,NULL,NULL);
|
|
if (tt->stopnet) {
|
|
stop = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (stop) {
|
|
// net immediately starts returning.
|
|
s->netspeed = -NETSPEED;
|
|
adjustx(s, F_WALK1);
|
|
}
|
|
|
|
// net is still going
|
|
if (s->powerup == PW_ACCORDION) {
|
|
if (s->netspeed > 0) {
|
|
s->netlen += s->netspeed;
|
|
} else {
|
|
s->netlen += (s->netspeed*2);
|
|
}
|
|
} else {
|
|
s->netlen += s->netspeed;
|
|
}
|
|
|
|
s->netting++;
|
|
|
|
if ((s->powerup == PW_ACCORDION) || (s->netting % 2 == 0)) {
|
|
if ((s->netlen > 0) && (s->netspeed > -NETSPEED)) {
|
|
s->netspeed--;
|
|
} else {
|
|
if (s->netlen <= 0) {
|
|
// finished netting
|
|
if ((s->powerup == PW_RAYGUN) && (s->timer1 <= 0)) {
|
|
// finished using ray gun
|
|
s->powerup = PW_NONE;
|
|
}
|
|
|
|
s->netting = 0;
|
|
adjustx(s, F_WALK1);
|
|
for (s2 = sprite ; s2 ; s2 = s2->next) {
|
|
if ((s2->caughtby == s) && (s2->caughtstate == C_NETTING)) {
|
|
s2->caughtstate = C_NETTED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (s->slamming) {
|
|
int netx,nety;
|
|
double dist;
|
|
int hitwall = B_FALSE;
|
|
|
|
s->slamangle += (10 * (M_PI/180));
|
|
|
|
|
|
dist = (s->slamangle * (180/M_PI))/2;
|
|
if (s->powerup == PW_SMALLNET) {
|
|
dist /= 2;
|
|
}
|
|
netx = s->x + cos(s->slamangle-(180*(M_PI/180)))*dist*s->dir;
|
|
nety = s->y + sin(s->slamangle-(180*(M_PI/180)))*dist;
|
|
if ((netx >= (SCREENW-TILEW)) || (netx <= TILEW)) {
|
|
hitwall = B_TRUE;
|
|
}
|
|
|
|
// hit a boss?
|
|
if (boss) {
|
|
if ( (netx >= boss->x-(boss->img->w/2)) && (netx <= boss->x+(boss->img->w/2))) {
|
|
if ((nety >= boss->y - boss->img->h) && (nety <= boss->y)) {
|
|
hitwall = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s->slamangle >= (180 * (M_PI/180)) || (hitwall && (s->slamangle >= (90 * (M_PI/180))))) {
|
|
/* finished slamming */
|
|
int xdiff,ydiff,xnet = 0,ynet = 0;
|
|
int pointsinc = 250;
|
|
int psize = 6;
|
|
int gotsomething = B_FALSE;
|
|
int gotclover = B_FALSE;
|
|
int hitboss = B_FALSE;
|
|
int macex,macey;
|
|
int numcaught = 0;
|
|
|
|
// initialise just in case
|
|
macex = s->x ; macey = s->y;
|
|
|
|
s->slamming = 0;
|
|
|
|
// if we have a mace, add an explosion and play a thump sound
|
|
if (s->powerup == PW_MACE) {
|
|
// play sound
|
|
playfx(FX_MACE);
|
|
|
|
// find location of mace
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (s2->id == P_MACE) {
|
|
if (s2->owner == s) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!s2) {
|
|
// should never happen
|
|
macex = s->x ; macey = s->y;
|
|
} else {
|
|
int xx,yy;
|
|
macex = s2->x;
|
|
macey = s2->y - s2->img->h/2;
|
|
|
|
// add explosion
|
|
addsprite(P_SMASH, macex, macey, "smash");
|
|
addsprite(P_SMASH, macex+TILEW, macey, "smash");
|
|
addsprite(P_SMASH, macex-TILEW, macey, "smash");
|
|
addsprite(P_SMASH, macex, macey+TILEH, "smash");
|
|
addsprite(P_SMASH, macex, macey-TILEH, "smash");
|
|
for (yy = 1; yy <= MACEEXPY; yy++) {
|
|
for (xx = 1; xx <= MACEEXPX; xx++) {
|
|
addsprite(P_SMASH, macex+xx*TILEW, macey-yy*TILEH, "smash");
|
|
addsprite(P_SMASH, macex-xx*TILEW, macey-yy*TILEH, "smash");
|
|
addsprite(P_SMASH, macex+xx*TILEW, macey+yy*TILEH, "smash");
|
|
addsprite(P_SMASH, macex-xx*TILEW, macey+yy*TILEH, "smash");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* kill anything we've caught */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
/* kill anything we have caught */
|
|
if (s2->caughtby == s) {
|
|
tiletype_t *tt;
|
|
int onplatform;
|
|
|
|
if (!isplayer(s2)) {
|
|
numcaught++; // used later in slam code
|
|
}
|
|
|
|
tt = gettileat(s2->x,s2->y+2,NULL,NULL);
|
|
|
|
// check for platform
|
|
onplatform = isonplatform(s2->x,s2->y+2);
|
|
|
|
/* if on ground or hitting a wall, monster dies */
|
|
if ((hitwall) || (onplatform) || (tt == NULL) || (tt->solid)) {
|
|
if (isplayer(s2)) {
|
|
tiletype_t *tt2;
|
|
// release player
|
|
playfx(FX_KILL);
|
|
uncatch(s2);
|
|
tt2 = gettileat(s2->x, s2->y-(TILEH), NULL, NULL);
|
|
// if they were slammed into solid wall, they die
|
|
if (tt2->solid) {
|
|
die(s2);
|
|
} else {
|
|
// otherwise they recoil
|
|
s2->recoiling = B_TRUE;
|
|
jump(s2, s->dir); // away from the one who caught them
|
|
s2->jumpspeed = 3;
|
|
}
|
|
// still counts as a monster for hitting others
|
|
gotsomething++;
|
|
xnet = s2->x;
|
|
ynet = s2->y - s2->img->h/2;
|
|
} else {
|
|
/* will become a fruit when it finishes dying */
|
|
if (boss) {
|
|
s2->willbecome = -1;
|
|
} else if (s->powerup == PW_TOPHAT) {
|
|
/* all fruits are powerups! */
|
|
s2->willbecome = poweruptypes[curpoweruptype[getpnum(s)]];
|
|
if (poweruptypes[++(curpoweruptype[getpnum(s)])] == -1) {
|
|
curpoweruptype[getpnum(s)] = 0;
|
|
}
|
|
} else {
|
|
if (forcegold) {
|
|
s2->willbecome = P_GOLDBAR;
|
|
} else {
|
|
s2->willbecome = fruittypes[curfruittype];
|
|
/* increment fruit type */
|
|
incfruittype();
|
|
|
|
// fruit time
|
|
fruittime = gtime;
|
|
}
|
|
}
|
|
|
|
if ((s->powerup == PW_MACE) && (s2->id == P_SNAIL)) {
|
|
// turn into a slug so that it really dies
|
|
s2->id = P_SLUG;
|
|
}
|
|
die(s2);
|
|
|
|
if ((s->powerup == PW_MACE) || (s2->id != P_SNAIL)) {
|
|
pointsinc *= 2;
|
|
psize += 10;
|
|
gotsomething++;
|
|
// killing 5 at a time gives us a clover for good luck
|
|
if ((!gotclover) && (gotsomething >= 5)) {
|
|
puffin(P_CLOVER, s2->x, s2->y, "clover", 0);
|
|
gotclover = B_TRUE;
|
|
}
|
|
}
|
|
xnet = s2->x;
|
|
ynet = s2->y - s2->img->h/2;
|
|
} // end if isplayer()
|
|
|
|
} else {
|
|
/* otherwise it gets angry */
|
|
if (!isplayer(s2)) {
|
|
s2->angry = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if we have a powerup, centre of net is the mace position
|
|
if (s->powerup == PW_MACE) {
|
|
xnet = macex;
|
|
ynet = macey;
|
|
}
|
|
|
|
|
|
// only check for hitting something if we already had a monster caught,
|
|
// or we have a mace
|
|
if (gotsomething || (s->powerup == PW_MACE)) {
|
|
/* kill anything we hit */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if ((s2->caughtby != s) && !s2->dead && !s2->invuln && (ismonster(s2->id))) {
|
|
int xthresh,ythresh;
|
|
|
|
xdiff = s2->x - xnet;
|
|
if (xdiff < 0) xdiff =-xdiff;
|
|
ydiff = (s2->y - s2->img->h/2) - ynet;
|
|
if (ydiff < 0) ydiff =-ydiff;
|
|
|
|
/*
|
|
if (player->powerup == PW_MACE) {
|
|
xthresh = TILEW*MACEEXPX*2;
|
|
ythresh = TILEW*MACEEXPY*2;
|
|
} else {
|
|
*/
|
|
xthresh = s2->img->w;
|
|
ythresh = s2->img->h;
|
|
//}
|
|
|
|
if ((xdiff <= xthresh) && (ydiff <= ythresh)) {
|
|
if (s2 == boss) {
|
|
int n;
|
|
// flash white, longer for each monster we were
|
|
// holding
|
|
s2->angry = BOSSFLASHTIME*numcaught;
|
|
// lose health
|
|
s2->lives -= numcaught;
|
|
|
|
// if no health left < 0, it dies
|
|
if (s2->lives <= 0) {
|
|
sprite_t *s3;
|
|
// todo: change to big fruit!
|
|
s2->willbecome = P_DIAMOND;
|
|
|
|
// add puffs
|
|
for (n = 0; n < 30; n++) {
|
|
puffin(-1, s2->x - (s2->img->w/2) + (rand() % s2->img->w), s2->y - (rand() % s2->img->h), "nothing", rand() % 80);
|
|
}
|
|
|
|
playfx(FX_BOSSDIE);
|
|
die(s2);
|
|
|
|
|
|
pointsinc *= 2;
|
|
pointsinc = 64000; // hardcode for a boss
|
|
psize += 10;
|
|
|
|
gotsomething++;
|
|
|
|
// kill everything else too
|
|
for (s3 = sprite; s3 ; s3=s3->next) {
|
|
if (ismonster(s3->id) && !s3->dead) {
|
|
s3->willbecome = P_DIAMOND;
|
|
|
|
if (s3->caughtby) {
|
|
uncatch(s3);
|
|
}
|
|
die(s3);
|
|
}
|
|
}
|
|
hitboss = B_TRUE;
|
|
} else { // remaining health
|
|
playfx(FX_BOSSHIT);
|
|
hitboss = B_TRUE;
|
|
}
|
|
} else if (s2->id != P_BLACKCLOUD) { // non bosses
|
|
/* dies and becomes a powerup */
|
|
// if we were holding something, we can get a powerup.
|
|
// if we used a mace, it becomes a diamond.
|
|
if (gotsomething) {
|
|
if (boss) { // no fruits on boss levels
|
|
s2->willbecome = -1;
|
|
} else {
|
|
int forcespeed = B_FALSE;
|
|
|
|
if (!haspowerup(s, P_SPEED)) forcespeed = B_TRUE;
|
|
// if anyone is alive and not fast isn't fast, give a speed.
|
|
if (forcespeed) {
|
|
s2->willbecome = P_SPEED;
|
|
} else if (!gotcard & (gotsomething >= 4)) { // card for killing 4 at once
|
|
s2->willbecome = getrandomcard();
|
|
gotcard = B_TRUE;
|
|
} else if (!gotcard && (rand() % 5 == 0)) { // random chance of a card
|
|
s2->willbecome = getrandomcard();
|
|
gotcard = B_TRUE;
|
|
} else {
|
|
// otherwise use normal powerup counter
|
|
s2->willbecome = poweruptypes[curpoweruptype[getpnum(s)]];
|
|
if (poweruptypes[++(curpoweruptype[getpnum(s)])] == -1) {
|
|
curpoweruptype[getpnum(s)] = 0;
|
|
}
|
|
}
|
|
|
|
}
|
|
} else if (s->powerup == PW_MACE) {
|
|
s2->willbecome = P_DIAMOND;
|
|
} else { // should never happen
|
|
if (s->powerup == PW_TOPHAT) {
|
|
s2->willbecome = poweruptypes[curpoweruptype[getpnum(s)]];
|
|
if (poweruptypes[++(curpoweruptype[getpnum(s)])] == -1) {
|
|
curpoweruptype[getpnum(s)] = 0;
|
|
}
|
|
} else {
|
|
if (forcegold) {
|
|
s2->willbecome = P_GOLDBAR;
|
|
} else {
|
|
/* will become a fruit when it finishes dying */
|
|
s2->willbecome = fruittypes[curfruittype];
|
|
incfruittype();
|
|
fruittime = gtime;
|
|
}
|
|
}
|
|
}
|
|
if (s2->id == P_SNAIL) {
|
|
// turn into a slug so that it really dies
|
|
s2->id = P_SLUG;
|
|
}
|
|
|
|
/*
|
|
if (s2->id == P_SNAIL) {
|
|
// avoid triggering death code twice for caught snails
|
|
// since for them s->dead won't be set after we
|
|
// slam them.
|
|
if (s2->lives != 0) { // ie if we didn't just catch+slam it
|
|
die(s2);
|
|
}
|
|
} else {
|
|
*/
|
|
die(s2);
|
|
pointsinc *= 2;
|
|
psize += 10;
|
|
gotsomething++;
|
|
// killing 5 at a time gives us a clover for good luck
|
|
if ((!gotclover) && (gotsomething >= 5)) {
|
|
puffin(P_CLOVER, s2->x, s2->y, "clover", 0);
|
|
gotclover = B_TRUE;
|
|
}
|
|
//}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
} // end if gotsomething || PW_MACE
|
|
|
|
// play sound effect
|
|
if (!hitboss) {
|
|
if (gotsomething >= 1) {
|
|
playfx(FX_KILL);
|
|
}
|
|
if (gotsomething > 1) {
|
|
playfx(FX_MULTIKILL);
|
|
}
|
|
}
|
|
|
|
gotsomething = B_FALSE;
|
|
|
|
/* release anything we've caught */
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (s2->caughtby == s) {
|
|
/* release it */
|
|
uncatch(s2);
|
|
}
|
|
}
|
|
|
|
s->netcaught = 0;
|
|
|
|
/* show points */
|
|
if (psize >= MAXLETTERHEIGHT) {
|
|
psize = MAXLETTERHEIGHT-1;
|
|
}
|
|
if (pointsinc > 250) {
|
|
/* give points to player */
|
|
//s->score += pointsinc;
|
|
sprintf(tempm, "%d",addscore(s, pointsinc));
|
|
addoutlinetext(xnet,ynet-TILEH, psize, tempm, &white,&black,POINTSDELAY, TT_NORM);
|
|
}
|
|
|
|
} // end if slamangle > 180degrees
|
|
} // end if slamming
|
|
|
|
if (isonground(s) && isplayer(s) && !s->jumping && !s->falling && !s->swimming) {
|
|
//int tx,ty,xoff;
|
|
int px[3],py[3],i;
|
|
|
|
// make list of tiles:
|
|
// firstctly at feet, and left, and right, just like isonground() !
|
|
px[0] = s->x;
|
|
py[0] = s->y + 1;
|
|
|
|
px[1] = s->x - s->img->w/2;
|
|
py[1] = s->y + 1;
|
|
|
|
px[2] = s->x + s->img->w/2;
|
|
py[2] = s->y + 1;
|
|
|
|
// under+left, underneath, under+right
|
|
for (i = 0; i < 3; i++) {
|
|
int off,tx,ty;
|
|
tx = px[i] / TILEW;
|
|
ty = py[i] / TILEH;
|
|
off = ty*LEVELW+tx;
|
|
if ((off > 0) && (off < LEVELW*LEVELH)) {
|
|
tiletype_t *tt;
|
|
// only check layer 1
|
|
tt = gettile(curlevel->map[off]);
|
|
if (tt && (tt->walkvanish != -1) && (curlevel->tilewalkvanish[off] > 0)) {
|
|
// instead of this, just add the newx+ty to a list of fading tiles.
|
|
addfadingtile(tx, ty);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int movex(sprite_t *s,double amt,int onpurpose) {
|
|
double newx,newy;
|
|
double curx,cury;
|
|
int tilex,tiley;
|
|
tiletype_t *tt,*tt2;
|
|
int newxoff,newgroundy;
|
|
int newtilex,newtiley;
|
|
int domove = B_FALSE;
|
|
|
|
double amtdir;
|
|
|
|
tt = gettileat(s->x, s->y, &tilex,&tiley);
|
|
|
|
if (amt > 0) amtdir = 1;
|
|
else (amtdir = -1);
|
|
|
|
// walking on sticky tiles?
|
|
if (isplayer(s) || ismonster(s->id)) {
|
|
if (tt->sticky && onpurpose && !s->falling) {
|
|
amt /= 2;
|
|
// enforce minimum speed for player
|
|
if (isplayer(s)) {
|
|
if (amt > 0 && amt < 1) {
|
|
amt = 1;
|
|
} else if (amt < 0 && amt > -1) {
|
|
amt = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
curx = s->x;
|
|
cury = s->y;
|
|
|
|
/* check for blockage to E/W */
|
|
if ((s->id == P_SNAIL) && (s->jumping) && (boss)) {
|
|
// unless we're a snail on kingsnail level
|
|
} else {
|
|
newx = s->x + (amtdir*(s->img->w/2)) ;
|
|
//newx = s->x + (amtdir*TILEW/2);
|
|
newy = cury-TILEH;
|
|
tt2 = gettileat(newx,newy,&newtilex,&newtiley);
|
|
if (tt2->solid == S_SOLID) {
|
|
s->xs = 0;
|
|
return NM_SIDE;
|
|
}
|
|
if ((tt2->solid == S_SLOPE) && (!candoslopes(s->id))) {
|
|
s->xs = 0;
|
|
return NM_SIDE;
|
|
}
|
|
}
|
|
|
|
// if falling, check the tile directly to our SW/SEtoo */
|
|
if ((s->falling) && (s->id != P_KINGSNAIL)) {
|
|
newx = s->x + (amtdir*TILEW/2);
|
|
newy = cury;
|
|
tt2 = gettileat(newx,newy,&newtilex,&newtiley);
|
|
if (tt2->solid == S_SOLID) {
|
|
//s->xs = 0;
|
|
return NM_BELOW;
|
|
}
|
|
if (tt2->solid == S_SLOPE && (!candoslopes(s->id))) {
|
|
//s->xs = 0;
|
|
return NM_BELOW;
|
|
}
|
|
}
|
|
|
|
/* get new position */
|
|
if (isplayer(s) && tt->slippery && !isinwater(s) && onpurpose ) {
|
|
double newxs;
|
|
double accel = ICEACCEL;
|
|
// change speed
|
|
newxs = s->xs + (s->dir*accel);
|
|
s->xs += (s->dir*accel);
|
|
// don't get too fast!
|
|
if (newxs > getspeed(s)) newxs = getspeed(s);
|
|
if (newxs < -getspeed(s)) newxs = -getspeed(s);
|
|
|
|
newx = curx + newxs;
|
|
amt = newx - curx;
|
|
} else {
|
|
newx = curx + amt;
|
|
}
|
|
|
|
|
|
|
|
newy = cury-2;
|
|
tt2 = gettileat(newx,newy,&newtilex,&newtiley);
|
|
newxoff = newx - (newtilex*TILEW);
|
|
newgroundy = newtiley*TILEH + tt2->lowness[newxoff];
|
|
|
|
/* new block is at least partially solid */
|
|
domove = B_FALSE;
|
|
if (tt2->solid == S_SOLID) {
|
|
// s->xs = 0;
|
|
return NM_SIDE;
|
|
} else if ((tt2->solid == S_SLOPE) && candoslopes(s->id)) {
|
|
/* we can move, but need to adjust our height */
|
|
domove = B_TRUE;
|
|
} else {
|
|
/* new block is empty */
|
|
domove = B_TRUE;
|
|
}
|
|
|
|
if (domove) {
|
|
if (isplayer(s) && tt->slippery && !isinwater(s) && onpurpose) {
|
|
double accel = ICEACCEL;
|
|
// change speed
|
|
s->xs += (s->dir*accel);
|
|
// don't get too fast!
|
|
if (s->xs > getspeed(s)) s->xs = getspeed(s);
|
|
if (s->xs < -getspeed(s)) s->xs = -getspeed(s);
|
|
|
|
s->x += s->xs;
|
|
s->moved = MV_WALK;
|
|
} else {
|
|
s->x += amt;
|
|
s->xs = amt;
|
|
if (!onpurpose) {
|
|
if (tt->slippery && !isinwater(s)) {
|
|
s->moved = MV_ICE;
|
|
} else if (!isconveyor(tt->id)) {
|
|
s->moved = MV_WALK;
|
|
}
|
|
} else {
|
|
s->moved = MV_WALK;
|
|
}
|
|
}
|
|
} else {
|
|
s->xs = 0;
|
|
}
|
|
|
|
// rings
|
|
if (isplayer(s)) {
|
|
if (s->powerup == PW_RINGWALK) {
|
|
if (isonground(s) && !s->swimming) {
|
|
int xx,yy;
|
|
// add sparkle
|
|
xx = s->x + (rand() % s->img->w) - (s->img->w/2);
|
|
yy = s->y - (rand() % (s->img->h/2));
|
|
addsprite(P_SPARKLE, xx, yy, "sparkle");
|
|
|
|
// gain points
|
|
addscore(s, 15);
|
|
}
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void adjustheight(sprite_t *s) {
|
|
tiletype_t *tt;
|
|
int xoff,groundy;
|
|
int tilex,tiley;
|
|
double origy;
|
|
int totmoved;
|
|
|
|
if ((s->flies) || isbullet(s->id) ) {
|
|
return;
|
|
}
|
|
|
|
tt = gettileat(s->x,s->y-1,&tilex,&tiley);
|
|
if (!tt) return;
|
|
if (tt->solid == S_SLOPE) {
|
|
xoff = s->x - (tilex*TILEW);
|
|
groundy = tiley*TILEH + tt->lowness[xoff];
|
|
s->y = groundy;
|
|
} else if (tt->solid == S_SOLID) {
|
|
origy = s->y;
|
|
totmoved = 0;
|
|
// keep moving up
|
|
while (tt->solid == S_SOLID) {
|
|
s->y--;
|
|
totmoved++;
|
|
// don't move more than 1 tile worth!
|
|
// don't go off top of screen
|
|
if ((totmoved >= TILEH) || (s->y <= TILEH)) {
|
|
break;
|
|
}
|
|
tt = gettileat(s->x,s->y-1,&tilex,&tiley);
|
|
}
|
|
}
|
|
}
|
|
|
|
int dofruiteffect(sprite_t *pp, sprite_t *s) {
|
|
if (s->id == P_SPEED) {
|
|
playfx(FX_POWERUP);
|
|
pp->speed = PLAYERFAST;
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, "Speed up!", &white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_BIGSPEED) {
|
|
// both players
|
|
playfx(FX_POWERUP);
|
|
if (player) {
|
|
player->permspeed = B_TRUE;
|
|
player->speed = PLAYERFAST;
|
|
addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_LIFE, "SUPER SPEED UP!", &cyan,&black,POINTSDELAY, TT_NORM);
|
|
}
|
|
if (player2) {
|
|
player2->permspeed = B_TRUE;
|
|
player2->speed = PLAYERFAST;
|
|
addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_LIFE, "SUPER SPEED UP!", &cyan,&black,POINTSDELAY, TT_NORM);
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_BIGSCUBA) {
|
|
// both players
|
|
playfx(FX_POWERUP);
|
|
if (player) {
|
|
player->permmask = B_TRUE;
|
|
player->hasmask = B_TRUE;
|
|
if ((player->lives > 0) && !player->dead) {
|
|
addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_LIFE, "SUPER MASK!", &cyan,&black,POINTSDELAY, TT_NORM);
|
|
}
|
|
}
|
|
if (player2) {
|
|
player2->permmask = B_TRUE;
|
|
player2->hasmask = B_TRUE;
|
|
if ((player2->lives > 0) && !player2->dead) {
|
|
addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_LIFE, "SUPER MASK!", &cyan,&black,POINTSDELAY, TT_NORM);
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_SUPERUMBRELLA) {
|
|
// both players
|
|
playfx(FX_POWERUP);
|
|
if (player) {
|
|
player->permumbrella = B_TRUE;
|
|
player->umbrella = B_TRUE;
|
|
if ((player->lives > 0) && !player->dead) {
|
|
addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_LIFE, "SUPER UMBRELLA!", &cyan,&black,POINTSDELAY, TT_NORM);
|
|
}
|
|
}
|
|
if (player2) {
|
|
player2->permumbrella = B_TRUE;
|
|
player2->umbrella = B_TRUE;
|
|
if ((player2->lives > 0) && !player2->dead) {
|
|
addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_LIFE, "SUPER UMBRELLA!", &cyan,&black,POINTSDELAY, TT_NORM);
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_BIGHELMET) {
|
|
// both players
|
|
playfx(FX_POWERUP);
|
|
if (player) {
|
|
player->permarmour = B_TRUE;
|
|
player->armour = B_TRUE;
|
|
if ((player->lives > 0) && !player->dead) {
|
|
int xx,yy;
|
|
addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_LIFE, "SUPER ARMOUR!", &cyan,&black,POINTSDELAY, TT_NORM);
|
|
for (xx = player->x - TILEW; xx <= player->x + TILEW; xx += TILEW) {
|
|
for (yy = player->y - TILEW*2; yy <= player->y; yy += TILEH) {
|
|
puffin(-1, xx, yy, "nothing", 0);
|
|
}
|
|
}
|
|
}
|
|
player->id = P_ARMOUR; // change how the player looks
|
|
}
|
|
if (player2) {
|
|
player2->permarmour = B_TRUE;
|
|
player2->armour = B_TRUE;
|
|
if ((player2->lives > 0) && !player2->dead) {
|
|
int xx,yy;
|
|
addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_LIFE, "SUPER ARMOUR!", &cyan,&black,POINTSDELAY, TT_NORM);
|
|
// add puffs
|
|
for (xx = player2->x - TILEW; xx <= player2->x + TILEW; xx += TILEW) {
|
|
for (yy = player2->y - TILEW*2; yy <= player2->y; yy += TILEH) {
|
|
puffin(-1, xx, yy, "nothing", 0);
|
|
}
|
|
}
|
|
}
|
|
player2->id = P_ARMOUR; // change how the player looks
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_BIGCHEST) { // trigger endgame!
|
|
int tx,ty,i;
|
|
sprite_t *s2,*nexts;
|
|
endgame = EG_FRUITFALL;
|
|
endtexttimer = 0;
|
|
endtexty = 120;
|
|
|
|
stopmusic();
|
|
playmusic(hiscoremusic);
|
|
|
|
// kill all monsters
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id) || ismonster(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
}
|
|
}
|
|
globpowerup = PW_ENDGAME;
|
|
globtimer = 0;
|
|
// add initial stars
|
|
for (i = 0; i < MINUPSTARS; i++) {
|
|
sprite_t *ss;
|
|
ss = addupstar();
|
|
ss->y = (rand() % (SCREENH-(TILEH*2))) + TILEH;
|
|
}
|
|
// all tiles become fruit
|
|
for (ty = 0 ; ty < LEVELH; ty++) {
|
|
for (tx = 0 ; tx < LEVELW; tx++) {
|
|
tiletype_t *tt;
|
|
tt = gettileat(tx*TILEW,ty*TILEH, NULL, NULL);
|
|
if (tt->id != T_BLANK) {
|
|
sprite_t *sp;
|
|
// clear layer 2 as well
|
|
curlevel->map2[ty * LEVELW + tx ] = getuniq(T_BLANK);
|
|
melttile(tx, ty, FOREVER, B_PUFF);
|
|
|
|
sp = addsprite(fruittypes[curfruittype],
|
|
tx * TILEW + (TILEW/2),
|
|
ty * TILEH + (TILEH/2), "end_fruit");
|
|
incfruittype();
|
|
|
|
sp->xs = 0;
|
|
sp->ys = (rand() % 2);
|
|
}
|
|
}
|
|
}
|
|
} else if (s->id == P_NUMNETS) {
|
|
playfx(FX_POWERUP);
|
|
if (pp->netmax < 4) {
|
|
pp->netmax++;
|
|
}
|
|
sprintf(tempm, "%d nets!",pp->netmax);
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_BIGNET) {
|
|
playfx(FX_POWERUP);
|
|
pp->netbig = B_TRUE;
|
|
sprintf(tempm, "Big net!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_TROPHY) {
|
|
// all powerups
|
|
playfx(FX_POWERUP);
|
|
pp->netmax = 4; // all nets
|
|
pp->netbig = B_TRUE; // big net
|
|
pp->speed = PLAYERFAST; // fast
|
|
sprintf(tempm, "Full power!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_MASKPOWERUP) {
|
|
playfx(FX_POWERUP);
|
|
pp->hasmask = B_TRUE;
|
|
sprintf(tempm, "Scuba Mask!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_BELL) {
|
|
// powerup detector - makes the level flash depending on what power up will appear.
|
|
// white = permenant
|
|
// green = temporary ability
|
|
// red = instawin
|
|
// purple = bad
|
|
playfx(FX_BELL); // different sound effect
|
|
pp->hasbell = B_TRUE;
|
|
sprintf(tempm, "Powerup Detector!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_RINGGOLD) {
|
|
// points for walking
|
|
playfx(FX_POWERUP);
|
|
pp->powerup = PW_RINGWALK;
|
|
sprintf(tempm, "Walk Ring!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_RINGSILVER) {
|
|
// points for walking
|
|
playfx(FX_POWERUP);
|
|
pp->powerup = PW_RINGJUMP;
|
|
sprintf(tempm, "Jump Ring!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_MACEPOWERUP) {
|
|
playfx(FX_POWERUP);
|
|
pp->powerup = PW_MACE;
|
|
sprintf(tempm, "Mace Slam!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_BOXING) {
|
|
playfx(FX_POWERUP);
|
|
pp->powerup = PW_BOXING;
|
|
sprintf(tempm, "Boxing Glove!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_HELMET) {
|
|
int xx,yy;
|
|
playfx(FX_ARMOR);
|
|
if (pp == player) {
|
|
pp->id = P_ARMOUR; // change how the player looks
|
|
} else {
|
|
pp->id = P_ARMOUR2; // change how the player looks
|
|
}
|
|
pp->armour = B_TRUE;
|
|
sprintf(tempm, "Armour!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
// add puffs
|
|
for (xx = pp->x - TILEW; xx <= pp->x + TILEW; xx += TILEW) {
|
|
for (yy = pp->y - TILEW*2; yy <= pp->y; yy += TILEH) {
|
|
puffin(-1, xx, yy, "nothing", 0);
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_GEMBOOST) {
|
|
playfx(FX_POWERUP);
|
|
if (pp->gemboost <= 1) {
|
|
pp->gemboost = 2;
|
|
} else {
|
|
pp->gemboost = 3;
|
|
}
|
|
sprintf(tempm, "Bonus x%d!",pp->gemboost);
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_FTODIAMOND) {
|
|
sprite_t *s2, *nexts;
|
|
// convert all flowers to diamonds
|
|
playfx(FX_MORPH);
|
|
sprintf(tempm, "Make diamonds!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isflower(s2->id)) {
|
|
puffin(-1, s2->x, s2->y, "nothing", 0);
|
|
// replace with a diamond
|
|
s2->id = P_DIAMOND;
|
|
s2->score = getpoints(P_DIAMOND);
|
|
sprintf(s2->name, "made_diamond");
|
|
}
|
|
}
|
|
playfx(FX_MORPH);
|
|
return B_TRUE;
|
|
} else if (s->id == P_FTOGEM) {
|
|
sprite_t *s2, *nexts;
|
|
int howmany;
|
|
int puffdelay;
|
|
int gemtype = P_GEMYELLOW;
|
|
int xx;
|
|
tiletype_t *tt;
|
|
|
|
// convert all flowers to gems
|
|
playfx(FX_MORPH);
|
|
sprintf(tempm, "Make gems!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isflower(s2->id)) {
|
|
puffin(-1, s2->x, s2->y, "nothing", 0);
|
|
// replace with a diamond
|
|
s2->id = flowertogem(s2->id);
|
|
s2->score = getpoints(s2->id);
|
|
sprintf(s2->name, "made_gem");
|
|
}
|
|
}
|
|
|
|
// and also make a stream of gems underneath us
|
|
howmany = (STREAMWID+1)*3;
|
|
// RIGHT
|
|
puffdelay = 0;
|
|
for (xx = s->x+TILEW; xx < s->x + (TILEW*howmany); xx += TILEW) {
|
|
// if on a wall, exit
|
|
tt = gettileat(xx,s->y-TILEH,NULL,NULL);
|
|
if (tt->solid) {
|
|
break;
|
|
}
|
|
switch (puffdelay % 3) {
|
|
case 0: gemtype = P_GEMYELLOW; break;
|
|
case 1: gemtype = P_GEMRED; break;
|
|
case 2: gemtype = P_GEMPURPLE; break;
|
|
}
|
|
/* create a gem */
|
|
puffin(gemtype, xx, s->y, "gem", puffdelay);
|
|
|
|
puffdelay += 1;
|
|
}
|
|
// LEFT
|
|
puffdelay = 0;
|
|
for (xx = s->x+TILEW; xx > s->x - (TILEW*howmany); xx -= TILEW) {
|
|
// if on a wall, exit
|
|
tt = gettileat(xx,s->y-TILEH,NULL,NULL);
|
|
if (tt->solid) {
|
|
break;
|
|
}
|
|
switch (puffdelay % 3) {
|
|
case 0: gemtype = P_GEMYELLOW; break;
|
|
case 1: gemtype = P_GEMRED; break;
|
|
case 2: gemtype = P_GEMPURPLE; break;
|
|
}
|
|
/* create a gem */
|
|
puffin(gemtype, xx, s->y, "gem", puffdelay);
|
|
puffdelay += 1;
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_CLOCK) {
|
|
// Freeze monsters
|
|
playfx(FX_POWERUP);
|
|
globpowerup = PW_CLOCK;
|
|
clocktime = CLOCKTIME;
|
|
sprintf(tempm, "Freeze time!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
// pause music
|
|
Mix_PauseMusic();
|
|
return B_TRUE;
|
|
} else if (s->id == P_TAP) {
|
|
// flood level
|
|
playfx(FX_FLOOD);
|
|
sprintf(tempm, "Flood!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&blue,&black,POINTSDELAY, TT_NORM);
|
|
if (!curlevel->iced) {
|
|
curlevel->iced = WATER_INPROGRESS;
|
|
curlevel->icey = LEVELH-1;
|
|
// water for 20 seconds
|
|
watertime = 20;
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_SNOWMAN) {
|
|
// ice
|
|
playfx(FX_FREEZE);
|
|
sprintf(tempm, "Blizzard!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&cyan,&black,POINTSDELAY, TT_NORM);
|
|
if (!curlevel->iced) {
|
|
curlevel->iced = ICE_INPROGRESS;
|
|
curlevel->icey = 0;
|
|
}
|
|
|
|
// postpone hurryup
|
|
nexthurryup += 10;
|
|
return B_TRUE;
|
|
} else if (s->id == P_SPRAY) {
|
|
// flyspray
|
|
playfx(FX_SPRAY);
|
|
sprintf(tempm, "Fly Spray!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
globpowerup = PW_SPRAYUP;
|
|
sprayalpha = 0;
|
|
return B_TRUE;
|
|
} else if (s->id == P_RAYGUN) {
|
|
// ray gun
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Ray Gun!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
pp->powerup = PW_RAYGUN;
|
|
pp->timer1 = 5; // # of shots
|
|
return B_TRUE;
|
|
} else if (s->id == P_TOPHAT) {
|
|
// Top Hat
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Top Hat!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
pp->powerup = PW_TOPHAT;
|
|
return B_TRUE;
|
|
} else if (s->id == P_LAMP) {
|
|
int xx,yy,delay;
|
|
sprite_t *s2;
|
|
tiletype_t *tt;
|
|
// Magic Lamp
|
|
Mix_PauseMusic(); // pause music
|
|
playfx(FX_LAMP);
|
|
sprintf(tempm, "Magic Lamp!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
|
|
globpowerup = PW_LAMP;
|
|
lamptime = -1;
|
|
|
|
// create gold coins
|
|
delay = 0;
|
|
for (xx = 0; xx < LEVELW; xx++) {
|
|
for (yy = 0; yy < (LEVELH-1); yy++) {
|
|
tt = gettileat(xx*TILEW,yy*TILEH, NULL,NULL);
|
|
if (!tt->solid && !tt->spikes) {
|
|
// check tile below
|
|
tt = gettileat(xx*TILEW,(yy+1)*TILEH, NULL,NULL);
|
|
if (tt->id == T_LAND) {
|
|
// add a coin ! (NAME is important as it gives a higher doom
|
|
// count when being placed in addsprite()!)
|
|
puffin(P_GOLDCOIN, xx*TILEW+(TILEW/2), yy*TILEH+(TILEH),"goldcoin", delay);
|
|
}
|
|
}
|
|
}
|
|
//inc delay
|
|
delay += 1;
|
|
}
|
|
|
|
// remove all monsters
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (ismonster(s2->id) && !s2->dead ) {
|
|
s2->dead = D_FINAL;
|
|
//puffs
|
|
puffin(-1, s2->x - (s2->img->w/2), s2->y, "wandpuff", rand() % 5);
|
|
puffin(-1, s2->x + (s2->img->w/2), s2->y, "wandpuff", rand() % 5);
|
|
puffin(-1, s2->x, s2->y - (s2->img->h/2), "wandpuff", rand() % 5);
|
|
puffin(-1, s2->x, s2->y + (s2->img->h/2), "wandpuff", rand() % 5);
|
|
}
|
|
}
|
|
|
|
return B_TRUE;
|
|
} else if (s->id == P_CANNONPOWERUP) {
|
|
sprite_t *newsp;
|
|
// cannon
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Fusion Cannon");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
pp->powerup = PW_CANNON;
|
|
puffin(-1, pp->x, pp->y,"nothign", 0);
|
|
newsp = addsprite(P_CANNON, pp->x, pp->y, "cannon");
|
|
newsp->owner = pp;
|
|
return B_TRUE;
|
|
} else if (s->id == P_HONEY) {
|
|
playfx(FX_POWERUP);
|
|
pp->netsticky = B_TRUE;
|
|
sprintf(tempm, "Sticky net!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
} else if (s->id == P_LIFE) {
|
|
extralife(pp);
|
|
return B_TRUE;
|
|
} else if (s->id == P_PHONE) {
|
|
sprite_t *s2, *nexts;
|
|
|
|
// can't skip levels if the nxet one is a boss level
|
|
if (isbosslevel(curlevelnum + 1)) {
|
|
playfx(FX_ENGAGED);
|
|
sprintf(tempm, "Engaged");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
} else {
|
|
if (!strstr(s->name, "warp")) {
|
|
playfx(FX_PHONE);
|
|
sprintf(tempm, "Telephone!");
|
|
} else {
|
|
sprintf(tempm, "Warp!");
|
|
}
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
// set powerup
|
|
pp->powerup = PW_PHONE;
|
|
skiplevels = 1;
|
|
// kill all enemies and fruits
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id) || ismonster(s2->id) || isfruit(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
if (ismonster(s2->id)) {
|
|
if (s2->caughtby) {
|
|
uncatch(s2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// call in cloud immediately
|
|
levelcomplete = LV_FINAL;
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_UFO) {
|
|
int n;
|
|
int wid,hei;
|
|
sprite_t *sp;
|
|
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Meteor Shower!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
wid = imageset[P_METEOR].img[0]->w;
|
|
hei = imageset[P_METEOR].img[0]->h;
|
|
for (n = 0; n < 7; n++) {
|
|
sp = addsprite(P_METEOR, rand() % (SCREENW - (wid*2)) + (wid/2), - (rand() % (hei*7)), "meteor");
|
|
sp->ys = (rand() % METEORMAXSPEED)+2;
|
|
}
|
|
lastmet = sp;
|
|
return B_TRUE;
|
|
} else if (s->id == P_STARPOWERUP) {
|
|
int n;
|
|
double ang;
|
|
sprite_t *sp;
|
|
// add a starburst
|
|
ang = (rand() % 360) * (M_PI/180);
|
|
for (n = 0; n < 8; n++) {
|
|
sp = addsprite(P_STAR, pp->x, pp->y, "star");
|
|
/*
|
|
switch (n) {
|
|
case 0: sp->xs = 0; sp->ys = -STARSPEED; break;
|
|
case 1: sp->xs = STARSPEED; sp->ys = -STARSPEED; break;
|
|
case 2: sp->xs = STARSPEED; sp->ys = 0; break;
|
|
case 3: sp->xs = STARSPEED; sp->ys = STARSPEED; break;
|
|
case 4: sp->xs = 0; sp->ys = STARSPEED; break;
|
|
case 5: sp->xs = -STARSPEED; sp->ys = STARSPEED; break;
|
|
case 6: sp->xs = -STARSPEED; sp->ys = 0; break;
|
|
case 7: sp->xs = -STARSPEED; sp->ys = -STARSPEED; break;
|
|
}
|
|
*/
|
|
sp->xs = cos(ang)*STARSPEED;
|
|
sp->ys = sin(ang)*STARSPEED;
|
|
|
|
ang = ang + (45 * (M_PI/180));
|
|
|
|
// use timer1 as the frame counter
|
|
sp->timer1 = rand() % STARFRAMES;
|
|
|
|
}
|
|
playfx(FX_STAR);
|
|
sprintf(tempm, "Shuriken!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
return B_TRUE;
|
|
|
|
} else if (s->id == P_BOMB) {
|
|
sprite_t *s2, *nexts;
|
|
|
|
// make the screen shake
|
|
globpowerup = PW_BOMB;
|
|
globtimer = BOMBSHAKETIME;
|
|
|
|
// kill all monsters
|
|
playfx(FX_BOOM);
|
|
sprintf(tempm, "KABOOM!!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_BOMB, tempm,&red,&yellow,POINTSDELAY, TT_NORM);
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
} else if (ismonster(s2->id)) {
|
|
|
|
addsprite(P_SMASH, s2->x, s2->y, "kaboom");
|
|
|
|
s2->willbecome = P_DIAMOND;
|
|
s2->lives = 0; // for snails
|
|
|
|
uncatch(s2);
|
|
die(s2);
|
|
}
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_SHIELD) {
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Shield!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
// temp invincibility
|
|
pp->invuln = SHIELDTIME;
|
|
return B_TRUE;
|
|
} else if (s->id == P_CLOVER) {
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Lucky!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_CLOVER, tempm,&green2,&black,CLOVERDELAY, TT_NORM);
|
|
nextforcegoodcard = B_TRUE;
|
|
forcegoodcard = B_TRUE;
|
|
return B_TRUE;
|
|
} else if (s->id == P_ACCORDION) {
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Extra Long Net!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
pp->powerup = PW_ACCORDION;
|
|
return B_TRUE;
|
|
} else if (s->id == P_WINGBOOTS) {
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Double jump!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
pp->doublejump = B_TRUE;
|
|
return B_TRUE;
|
|
} else if (s->id == P_PILL) {
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Hyper speed!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
pp->powerup = PW_PILL;
|
|
return B_TRUE;
|
|
} else if (s->id == P_GUN) {
|
|
playfx(FX_ALARM);
|
|
sprintf(tempm, "Machine gunner!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
guntime = 10;
|
|
gundelay[0] = 0; // used to control shooting speed
|
|
gundelay[1] = 0; // used to control shooting speed
|
|
// gunner works on BOTH players
|
|
if (player) {
|
|
player->netting = B_FALSE;
|
|
player->slamming = B_FALSE;
|
|
player->powerup = PW_GUNNER;
|
|
gunorigx[0] = player->x;
|
|
gunorigy[0] = player->y;
|
|
|
|
}
|
|
if (player2) {
|
|
player2->netting = B_FALSE;
|
|
player2->slamming = B_FALSE;
|
|
player2->powerup = PW_GUNNER;
|
|
gunorigx[1] = player2->x;
|
|
gunorigy[1] = player2->y;
|
|
}
|
|
return B_TRUE;
|
|
} else if (s->id == P_GNOME) {
|
|
sprite_t *s2;
|
|
playfx(FX_BOOM2);
|
|
sprintf(tempm, "Exploding Flowers!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
puffin(-1, s->x, s->y, "gnomepuff", 0);
|
|
// turn all flowers into explosions
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (isflower(s2->id)) {
|
|
// replace with an explosion
|
|
s2->dead = D_FINAL;
|
|
addsprite(P_SMASH, s2->x, s2->y, "gnom_exp");
|
|
}
|
|
}
|
|
|
|
return B_TRUE;
|
|
} else if (s->id == P_WHISTLE) {
|
|
sprite_t *bc;
|
|
sprite_t *s2;
|
|
int found = B_FALSE;
|
|
|
|
playfx(FX_WHISTLE);
|
|
|
|
// if black cloud exists, it gets angry
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (s2->id == P_BLACKCLOUD) {
|
|
found = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
s2->angry = B_TRUE;
|
|
addoutlinetext(320,240,TEXTSIZE_HURRY, "Angry cloud!", &red,&black,HURRYDELAY, TT_NORM);
|
|
} else {
|
|
bc = addsprite(P_BLACKCLOUD, 320,240,"cloud");
|
|
makeinvuln(bc);
|
|
bc->angry = B_TRUE;
|
|
addoutlinetext(320,240,TEXTSIZE_HURRY, "Angry cloud!", &red,&black,HURRYDELAY, TT_NORM);
|
|
playfx(FX_TOOSLOW);
|
|
}
|
|
|
|
globpowerup = PW_WHISTLE;
|
|
|
|
return B_TRUE;
|
|
} else if (s->id == P_CANDLE) {
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Flaming Corpses!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
globpowerup = PW_CANDLE;
|
|
return B_TRUE;
|
|
} else if (s->id == P_MAGNET) {
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Attract fruits!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
pp->powerup = PW_MAGNET;
|
|
return B_TRUE;
|
|
} else if (s->id == P_JETPACK) {
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Jet pack!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
pp->powerup = PW_JETPACK;
|
|
return B_TRUE;
|
|
} else if (s->id == P_UMBRELLA) {
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Umbrella!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
pp->umbrella = B_TRUE;
|
|
return B_TRUE;
|
|
} else if (s->id == P_BADMAGNET) {
|
|
playfx(FX_SKULL);
|
|
sprintf(tempm, "Repel fruits!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&black,&grey,POINTSDELAY, TT_NORM);
|
|
pp->powerup = PW_BADMAGNET;
|
|
return B_TRUE;
|
|
} else if (s->id == P_ANCHOR) {
|
|
playfx(FX_MORPH);
|
|
sprintf(tempm, "Anchor!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
globpowerup = PW_ANCHOR;
|
|
return B_TRUE;
|
|
} else if (s->id == P_CAMERA) {
|
|
playfx(FX_CAMERA);
|
|
sprintf(tempm, "Blind enemies!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
globpowerup = PW_CAMERA;
|
|
cameraalpha = 255;
|
|
return B_TRUE;
|
|
} else if (s->id == P_WAND) {
|
|
sprite_t *s2;
|
|
|
|
playfx(FX_WAND);
|
|
sprintf(tempm, "Weaken monsters!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
// turn all live monsters into weaker versions
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (ismonster(s2->id) && !s2->dead && !s2->caughtby) {
|
|
// don't get ones which we just created!
|
|
if (!strstr(s2->name, "created")) {
|
|
int newtype = -1;
|
|
|
|
// make it non-angry
|
|
if (s2->angry) s2->angry = B_FALSE;
|
|
|
|
// change to a weaker version
|
|
switch (s2->id) {
|
|
case P_SNAKE:
|
|
case P_TICK:
|
|
case P_SNAIL:
|
|
case P_SLUG:
|
|
newtype = P_RAT;
|
|
break;
|
|
case P_FISH:
|
|
case P_FLY:
|
|
newtype = P_BEE;
|
|
break;
|
|
}
|
|
|
|
s2->dead = D_FINAL;
|
|
|
|
if (newtype != -1) {
|
|
// morph into something else...
|
|
addsprite(newtype, s2->x, s2->y, "created_mon");
|
|
}
|
|
//puffs anyway
|
|
puffin(-1, s2->x - (s2->img->w/2), s2->y, "wandpuff", rand() % 5);
|
|
puffin(-1, s2->x + (s2->img->w/2), s2->y, "wandpuff", rand() % 5);
|
|
puffin(-1, s2->x, s2->y - (s2->img->h/2), "wandpuff", rand() % 5);
|
|
puffin(-1, s2->x, s2->y + (s2->img->h/2), "wandpuff", rand() % 5);
|
|
}
|
|
}
|
|
}
|
|
|
|
return B_TRUE;
|
|
} else if (s->id == P_ZAPPOWERUP) {
|
|
sprite_t *newsp;
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Bug Zapper!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY, TT_NORM);
|
|
puffin(-1, pp->x, pp->y, "bzpuff", 0);
|
|
newsp = addsprite(P_ZAPPER, pp->x,pp->y, "bugzapper" );
|
|
newsp->timer1 = 0;
|
|
newsp->timer2 = ZAPPERDELAY;
|
|
newsp->timer3 = 0;
|
|
newsp->doomcount = 800;
|
|
newsp->owner = pp;
|
|
return B_TRUE;
|
|
} else if (s->id == P_SKULL) {
|
|
playfx(FX_SKULL);
|
|
sprintf(tempm, "Power Down!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&black,&grey,POINTSDELAY, TT_NORM);
|
|
pp->powerup = PW_SMALLNET;
|
|
return B_TRUE;
|
|
} else if (s->id == P_HELP) {
|
|
playfx(FX_POWERUP);
|
|
addoutlinetext(320,240,TEXTSIZE_HELP, s->name, &white,&black,HELPDELAY,TT_HELP);
|
|
return B_TRUE;
|
|
} else if (iscard(s->id)) {
|
|
if (pp->numcards < MAXCARDS) {
|
|
sprite_t *newc;
|
|
int cardwidth,cardheight;
|
|
|
|
playfx(FX_CARD);
|
|
|
|
// show text
|
|
sprintf(tempm, getcardname(s->id), BUFLEN);
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY,TT_NORM);
|
|
|
|
// add a "card" effect. it will move slowly towards the corner.
|
|
newc = addsprite(P_MOVINGCARD,s->x, s->y, "moving_card");
|
|
|
|
newc->owner = pp;
|
|
|
|
// timer1 is the actual cardid
|
|
// timer2 is the target x position
|
|
// timer3 is the target y position
|
|
cardwidth = imageset[P_FIRSTCARD].img[F_WALK1]->w;
|
|
cardheight = imageset[P_FIRSTCARD].img[F_WALK1]->h;
|
|
newc->timer1 = s->id;
|
|
if (pp == player) {
|
|
newc->timer2 = CARDX + (pp->numcards * (cardwidth+2)) + (cardwidth/2);
|
|
} else if (pp == player2) {
|
|
int cardx2 = SCREENW - CARDX - (imageset[P_FIRSTCARD].img[F_WALK1]->w + 2);
|
|
newc->timer2 = cardx2 - (pp->numcards * (cardwidth+2)) + (cardwidth/2);
|
|
}
|
|
newc->timer3 = CARDY + cardheight;
|
|
|
|
// set image
|
|
newc->img = imageset[s->timer1].img[F_WALK1];
|
|
} else {
|
|
// is this possible?!
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_POINTS, "Full cards!",getptextcol(s),&black,POINTSDELAY,TT_NORM);
|
|
}
|
|
return B_TRUE;
|
|
} else if (isflower(s->id)) {
|
|
int xx;
|
|
sprite_t *ss;
|
|
tiletype_t *tt;
|
|
int found = B_FALSE;
|
|
|
|
/* was this the last fruit of its kind on the level? */
|
|
for (ss = sprite; ss; ss = ss->next) {
|
|
if ((ss != s) && (ss->id == s->id)) {
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
/* if so, create a left/right stream of flowers */
|
|
if (!found) {
|
|
int howmany = (STREAMWID + 1) * pp->gemboost;
|
|
int puffdelay;
|
|
|
|
// RIGHT
|
|
puffdelay = 0;
|
|
for (xx = s->x+TILEW; xx < s->x + (TILEW*howmany); xx += TILEW) {
|
|
// if on a wall, exit
|
|
tt = gettileat(xx,s->y-TILEH,NULL,NULL);
|
|
if (tt->solid) {
|
|
break;
|
|
}
|
|
/* create a flower */
|
|
puffin(flowertogem(s->id), xx, s->y, "flower", puffdelay);
|
|
|
|
puffdelay += 1;
|
|
}
|
|
// LEFT
|
|
puffdelay = 0;
|
|
for (xx = s->x+TILEW; xx > s->x - (TILEW*howmany); xx -= TILEW) {
|
|
// if on a wall, exit
|
|
tt = gettileat(xx,s->y-TILEH,NULL,NULL);
|
|
if (tt->solid) {
|
|
break;
|
|
}
|
|
puffin(flowertogem(s->id), xx, s->y, "flower", puffdelay);
|
|
puffdelay += 1;
|
|
}
|
|
playfx(FX_BONUS);
|
|
sprintf(tempm, "BONUS!");
|
|
addoutlinetext(s->x,s->y - s->img->h/2, TEXTSIZE_BONUS, tempm,&white,&black,BONUSDELAY,TT_NORM);
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void usage(void) {
|
|
printf("usage: rc [-fs] [-l xx]\n");
|
|
printf(" -fs Start in full-screen mode.\n");
|
|
printf(" -l xx Skip to level xx.\n");
|
|
//printf(" -hs xx Set hiscore_server to http://xx.\n");
|
|
//printf(" -hp xx Connect to hiscore_server on port xx.\n");
|
|
printf(" -js Joystick test mode.\n");
|
|
printf(" -as Auto screenshot mode (dumps to /tmp/levelxx.bmp).\n");
|
|
printf(" -t Enable tutorial (ie. help text).\n");
|
|
printf(" -s Enable swapplayers mode (ie. player 1 is Mrs Dwarf)\n");
|
|
printf("\n");
|
|
}
|
|
|
|
// returns B_TRUE if the given player is able to walk/fall left/right
|
|
int canmove(sprite_t *pl) {
|
|
if (!pl->jumping && !pl->slamming ) {
|
|
if (!pl->netting) {
|
|
if ( pl->climbing || pl->falling || isonground(pl)) {
|
|
return B_TRUE;
|
|
}
|
|
} else if (pl->netting && pl->falling) { // netting and falling
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
// returns B_TRUE if the given player is able to change which direction they're facing
|
|
int canturn(sprite_t *pl) {
|
|
if (!pl->slamming && !pl->netting) {
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int loadfx(int sid , char *filename) {
|
|
char tempname[BUFLEN];
|
|
|
|
sprintf(tempname, "%s/sounds/",datadir);
|
|
strncat(tempname, filename, BUFLEN);
|
|
sfx[sid] = Mix_LoadWAV(tempname);
|
|
if (!sfx[sid]) {
|
|
printf("error loading %s\n",tempname);
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int initsound(void) {
|
|
int i;
|
|
char filename[BUFLEN];
|
|
|
|
/* init */
|
|
//if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 1024) < 0) {
|
|
//if (Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 512) < 0) {
|
|
if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 512) < 0) {
|
|
printf("Error initialising sound: %s.\n",Mix_GetError());
|
|
return B_TRUE;
|
|
}
|
|
|
|
Mix_AllocateChannels(CH_LASTCHANNEL);
|
|
|
|
loadfx(FX_SHOOT, "shoot.wav");
|
|
loadfx(FX_SLAM, "slam.wav");
|
|
loadfx(FX_KILL, "kill.wav");
|
|
loadfx(FX_MULTIKILL, "multikill.wav");
|
|
loadfx(FX_JUMP, "jump.wav");
|
|
loadfx(FX_FRUIT, "fruit.wav");
|
|
loadfx(FX_POWERUP, "powerup.wav");
|
|
loadfx(FX_DIE, "die.wav");
|
|
loadfx(FX_WINLEVEL, "winlevel.wav");
|
|
loadfx(FX_HURRYUP, "hurryup.wav");
|
|
loadfx(FX_TOOSLOW, "tooslow.wav");
|
|
loadfx(FX_BONUS, "bonus.wav");
|
|
loadfx(FX_MORPH, "morph.wav");
|
|
loadfx(FX_BOOM, "boom.wav");
|
|
loadfx(FX_SPRING, "spring.wav");
|
|
loadfx(FX_TELEPORT, "teleport.wav");
|
|
loadfx(FX_SPLASH, "splash.wav");
|
|
loadfx(FX_MACE, "mace.wav");
|
|
loadfx(FX_COIN, "coin.wav");
|
|
loadfx(FX_GAMEOVER, "gameover.wav");
|
|
loadfx(FX_OW, "ow.wav");
|
|
loadfx(FX_BELL, "bell.wav");
|
|
loadfx(FX_CLOCK, "clock.wav");
|
|
loadfx(FX_ARMOR, "armor.wav");
|
|
loadfx(FX_FREEZE, "freeze.wav");
|
|
loadfx(FX_ICEBREAK, "icebreak.wav");
|
|
loadfx(FX_BOSSWINDUP, "chargewait.wav");
|
|
loadfx(FX_BOSSCHARGE, "bosscharge.wav");
|
|
loadfx(FX_BOSSDIE, "bossdie.wav");
|
|
loadfx(FX_BOSSHIT, "bosshit.wav");
|
|
loadfx(FX_BOSSWALL, "bosswall.wav");
|
|
loadfx(FX_SPRAY, "spray.wav");
|
|
loadfx(FX_CANNON, "fusion.wav");
|
|
loadfx(FX_CRACK, "crack.wav");
|
|
loadfx(FX_PHONE, "phone.wav");
|
|
loadfx(FX_STAR, "star.wav");
|
|
loadfx(FX_STARHIT, "starhit.wav");
|
|
loadfx(FX_METEOR, "meteor.wav");
|
|
loadfx(FX_ENGAGED, "engaged.wav");
|
|
loadfx(FX_FLOOD, "flood.wav");
|
|
loadfx(FX_CARD, "card.wav");
|
|
loadfx(FX_POKER, "poker.wav");
|
|
loadfx(FX_SKULL, "skull.wav");
|
|
loadfx(FX_KEYPRESS, "1up.wav");
|
|
loadfx(FX_CATCH, "catch.wav");
|
|
loadfx(FX_GUN, "gun.wav");
|
|
loadfx(FX_ALARM, "alarm.wav");
|
|
loadfx(FX_ZAP, "zap.wav");
|
|
loadfx(FX_SNAILPREPARE, "longdrum.wav");
|
|
loadfx(FX_WHOOSH, "whoosh.wav");
|
|
loadfx(FX_BOOM2, "boom2.wav");
|
|
loadfx(FX_WAND, "wand.wav");
|
|
loadfx(FX_WHISTLE, "whistle.wav");
|
|
loadfx(FX_EVILLAUGH, "evillaugh.wav");
|
|
loadfx(FX_BIRDS, "birds.wav");
|
|
loadfx(FX_EXTRALIFE, "extralife.wav");
|
|
loadfx(FX_WARP, "warp.wav");
|
|
loadfx(FX_JETPACK, "jetpack.wav");
|
|
loadfx(FX_CAMERA, "camera.wav");
|
|
loadfx(FX_LASER, "laser.wav");
|
|
loadfx(FX_HISS, "hiss.wav");
|
|
loadfx(FX_CHOMP, "chomp.wav");
|
|
loadfx(FX_GROWL, "growl.wav");
|
|
loadfx(FX_LAMP, "lamp.wav");
|
|
loadfx(FX_SONAR, "pea.wav");
|
|
|
|
// load sound effects
|
|
for (i = 0; i < MAXFX; i++) {
|
|
if (!sfx[i]) {
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
// set up callback
|
|
Mix_ChannelFinished(channeldone);
|
|
|
|
// load music
|
|
for (i = 1; i <= MAXWORLDS; i++) {
|
|
sprintf(filename, "%s/music/main%d.mod",datadir, i);
|
|
normalmusic[i] = Mix_LoadMUS(filename);
|
|
if (!normalmusic[i]) {
|
|
printf("can't load music: %s\n", Mix_GetError());
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
sprintf(filename, "%s/music/mainfast%d.mod",datadir,i);
|
|
fastmusic[i] = Mix_LoadMUS(filename);
|
|
if (!fastmusic[i]) {
|
|
printf("can't load fast music\n");
|
|
return B_TRUE;
|
|
}
|
|
}
|
|
|
|
sprintf(filename, "%s/music/boss.mod",datadir);
|
|
bossmusic = Mix_LoadMUS(filename);
|
|
if (!bossmusic) {
|
|
printf("can't load music\n");
|
|
return B_TRUE;
|
|
}
|
|
|
|
sprintf(filename, "%s/music/hiscore.mod",datadir);
|
|
hiscoremusic = Mix_LoadMUS(filename);
|
|
if (!hiscoremusic) {
|
|
printf("can't load music\n");
|
|
return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
void playfx(int num) {
|
|
Mix_PlayChannel(-1, sfx[num], 0);
|
|
}
|
|
|
|
void playmusic(Mix_Music *toplay) {
|
|
// is this one already playing?
|
|
if ((curmusic == toplay) && (musicplaying)) {
|
|
return;
|
|
}
|
|
|
|
/* stop music */
|
|
if (musicplaying) {
|
|
Mix_HaltMusic();
|
|
}
|
|
|
|
/* start music */
|
|
//music = toplay;
|
|
|
|
Mix_PlayMusic(toplay, -1);
|
|
if ((player && player->swimming) || (player2 && player2->swimming)) {
|
|
Mix_VolumeMusic(MIX_MAX_VOLUME/3);
|
|
} else {
|
|
Mix_VolumeMusic(MIX_MAX_VOLUME);
|
|
}
|
|
|
|
curmusic = toplay;
|
|
musicplaying = B_TRUE;
|
|
}
|
|
|
|
void stopmusic(void) {
|
|
/* stop music */
|
|
if (musicplaying) {
|
|
Mix_HaltMusic();
|
|
}
|
|
musicplaying = B_FALSE;
|
|
curmusic = NULL;
|
|
}
|
|
|
|
// callback for sound effects finishing
|
|
void channeldone(int channel) {
|
|
if (channel == CH_HURRYUP) {
|
|
// start fast music
|
|
playmusic(fastmusic[getcurworld()]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// move player towards new position
|
|
// return distance left
|
|
int moveto(sprite_t *p, int dstx, int dsty, double xspeed, double yspeed) {
|
|
double ang,xs,ys;
|
|
int distanceleft;
|
|
int therex = B_FALSE,therey = B_FALSE;
|
|
// figure out angle to player
|
|
ang = atan2(dsty - p->y, dstx - p->x);
|
|
xs = (cos(ang) * xspeed);
|
|
ys = (sin(ang) * yspeed);
|
|
|
|
|
|
if (p->x < dstx) {
|
|
p->x += xs;
|
|
if (p->x >= dstx) {
|
|
p->x = dstx;
|
|
}
|
|
}
|
|
if (p->x > dstx) {
|
|
p->x += xs;
|
|
if (p->x <= dstx) {
|
|
p->x = dstx;
|
|
}
|
|
}
|
|
if (p->x == dstx) {
|
|
therex = B_TRUE;
|
|
}
|
|
if (p->y < dsty) {
|
|
p->y += ys;
|
|
if (p->y >= dsty) {
|
|
p->y = dsty;
|
|
}
|
|
}
|
|
if (p->y > dsty) {
|
|
p->y += ys;
|
|
if (p->y <= dsty) {
|
|
p->y = dsty;
|
|
}
|
|
}
|
|
if (p->y == dsty) {
|
|
therey = B_TRUE;
|
|
}
|
|
|
|
// figure out distance to target
|
|
distanceleft = getdistance(p->x,p->y,dstx,dsty);
|
|
|
|
if (therex && therey) return 0;
|
|
|
|
return distanceleft;
|
|
}
|
|
|
|
// grabs area behind a sprite into a temp buffer
|
|
SDL_Surface *grabbehind(sprite_t *s, SDL_Surface *surf) {
|
|
SDL_Rect area;
|
|
|
|
// create buffer for player background
|
|
/*
|
|
if (surf) {
|
|
SDL_FreeSurface(surf);
|
|
surf = NULL;
|
|
}
|
|
surf = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
s->img->w, s->img->h,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask,
|
|
screen->format->Amask);
|
|
SDL_DisplayFormat(surf);
|
|
*/
|
|
|
|
// remember area behind player
|
|
area.x = s->x - s->img->w/2;
|
|
area.y = s->y - s->img->h;
|
|
area.w = surf->w;
|
|
area.h = surf->h;
|
|
SDL_BlitSurface(screen, &area, surf, NULL);
|
|
|
|
return surf;
|
|
}
|
|
|
|
void dumpsprites(void) {
|
|
sprite_t *s;
|
|
int i = 0;
|
|
int mcount = 0;
|
|
for (s = sprite; s ; s = s->next) {
|
|
printf("Sprite #%d: %s at %1.0f,%1.0f id=%d (",i,s->name,s->x,s->y, s->id);
|
|
if (ismonster(s->id)) { printf("MONSTER, "); mcount++; }
|
|
if (isfruit(s->id)) printf("FRUIT, ");
|
|
if (isflower(s->id)) printf("FLOWER, ");
|
|
if (isbullet(s->id)) printf("BULLET, ");
|
|
if (iseffect(s->id)) printf("EFFECT, ");
|
|
printf(")\n");
|
|
i++;
|
|
}
|
|
|
|
printf("--------\n");
|
|
printf("Total monsters: %d\n",mcount);
|
|
printf("\n\n");
|
|
}
|
|
|
|
// returns width
|
|
int drawoutlinetext(SDL_Surface *where,int x, int y, int size, char *msg, SDL_Color *col, SDL_Color *bgcol) {
|
|
SDL_Surface *surf;
|
|
SDL_Rect area;
|
|
int wid;
|
|
|
|
area.w=0;area.h=0;
|
|
|
|
//shadow
|
|
surf = TTF_RenderText_Solid(font[size], msg, *bgcol);
|
|
|
|
area.x = x-1; area.y = y; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x-1; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x+1; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x+1; area.y = y; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x+1; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x-1; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
|
|
// text
|
|
SDL_SetColors(surf, col, 1, 1);
|
|
area.x = x; area.y = y; SDL_BlitSurface(surf, NULL, where, &area);
|
|
|
|
wid = surf->w;
|
|
SDL_FreeSurface(surf);
|
|
|
|
return wid;
|
|
}
|
|
|
|
void drawoutlinecentretext(SDL_Surface *where, int y, int size, char *msg, SDL_Color *col, SDL_Color *bgcol) {
|
|
SDL_Surface *surf;
|
|
SDL_Rect area;
|
|
int x;
|
|
|
|
area.w=0;area.h=0;
|
|
|
|
//shadow
|
|
surf = TTF_RenderText_Solid(font[size], msg, *bgcol);
|
|
x = 320 - (surf->w/2);
|
|
|
|
|
|
area.x = x-1; area.y = y; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x-1; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x+1; area.y = y-1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x+1; area.y = y; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x+1; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
area.x = x-1; area.y = y+1; SDL_BlitSurface(surf, NULL, where, &area);
|
|
|
|
// text
|
|
SDL_SetColors(surf, col, 1, 1);
|
|
area.x = x; area.y = y; SDL_BlitSurface(surf, NULL, where, &area);
|
|
|
|
SDL_FreeSurface(surf);
|
|
}
|
|
|
|
void addoutlinetext(int x, int y, int size, char *msg, SDL_Color *col, SDL_Color *bgcol, int delay, int ttype) {
|
|
int shadowtype;
|
|
if (ttype == TT_HELP) {
|
|
shadowtype = TT_HELPSHADOW;
|
|
} else {
|
|
shadowtype = TT_NORM;
|
|
}
|
|
addtext(x-1,y,size,msg,bgcol,delay,shadowtype); // outline
|
|
addtext(x-1,y-1,size,msg,bgcol,delay,shadowtype); // outline
|
|
addtext(x,y-1,size,msg,bgcol,delay,shadowtype); // outline
|
|
addtext(x+1,y-1,size,msg,bgcol,delay,shadowtype); // outline
|
|
addtext(x+1,y,size,msg,bgcol,delay,shadowtype); // outline
|
|
addtext(x+1,y+1,size,msg,bgcol,delay,shadowtype); // outline
|
|
addtext(x,y+1,size,msg,bgcol,delay,shadowtype); // outline
|
|
addtext(x-1,y+1,size,msg,bgcol,delay,shadowtype); // outline
|
|
addtext(x,y,size,msg,col,delay,ttype); // main text
|
|
}
|
|
|
|
char *addcommas(char *buffer, long num) {
|
|
char tempbuf[MIDBUFLEN];
|
|
char *p;
|
|
char *p2;
|
|
int count;
|
|
|
|
sprintf(tempbuf, "%ld",num);
|
|
|
|
p2 = buffer;
|
|
p = tempbuf;
|
|
if (strlen(tempbuf) <= 3) {
|
|
strcpy(buffer,tempbuf);
|
|
return buffer;
|
|
} else {
|
|
count = ((strlen(tempbuf)-1) % 3)+1;
|
|
}
|
|
|
|
for (p = tempbuf; *p; p++) {
|
|
if (count == 0) {
|
|
count = 3;
|
|
*p2 = ',';
|
|
p2++;
|
|
}
|
|
*p2 = *p;
|
|
p2++;
|
|
count--;
|
|
}
|
|
*p2 = '\0';
|
|
|
|
return buffer;
|
|
}
|
|
|
|
sprite_t *addupstar(void) {
|
|
sprite_t *ss;
|
|
int x,y;
|
|
// spawn a new star
|
|
x = (rand() % (SCREENW-(TILEW*2))) + TILEW;
|
|
y = SCREENH;
|
|
ss = addsprite(P_UPSTAR, x, y, "upstar");
|
|
ss->xs = 0;
|
|
ss->ys = (rand() % 4)+1;
|
|
return ss;
|
|
}
|
|
|
|
int addscore(sprite_t *s, long amt) {
|
|
int oldscore;
|
|
oldscore = s->score;
|
|
|
|
/*
|
|
// less points in easy mode
|
|
if (gamemode == GM_EASY) {
|
|
amt /= 2;
|
|
}
|
|
*/
|
|
|
|
s->score += amt;
|
|
|
|
// each multiple of 100,000
|
|
if (isplayer(s) && !endgame) {
|
|
if ((s->score / 100000) > (oldscore / 100000)) {
|
|
extralife(s);
|
|
}
|
|
}
|
|
|
|
return amt;
|
|
}
|
|
|
|
void extralife(sprite_t *which) {
|
|
playfx(FX_EXTRALIFE);
|
|
which->lives += 1;
|
|
addoutlinetext(which->x,which->y - which->img->h/2, TEXTSIZE_LIFE, "Extra life!",&green,&black,LIFEDELAY,TT_NORM);
|
|
}
|
|
|
|
// slowly change level to ice
|
|
void doice(void) {
|
|
int yy,xx,changed;
|
|
sprite_t *s;
|
|
int l2id;
|
|
|
|
// just in case
|
|
if (!curlevel->iced) {
|
|
curlevel->iced = ICE_INPROGRESS;
|
|
}
|
|
// slowly change a level to ice
|
|
//if (timer % ICESPEED == 0) {
|
|
xx = 0;
|
|
for (yy = curlevel->icey; yy >= 0; yy--) {
|
|
// make sure tile is valid
|
|
if ((yy >= 0) && (yy < LEVELH) && (xx >= 0) && (xx < LEVELW)) {
|
|
tiletype_t *tt;
|
|
changed = B_FALSE;
|
|
// if not already a second layer here...
|
|
//l2id = curlevel->map2[yy*LEVELW+xx];
|
|
tt = gettile(curlevel->map2[yy*LEVELW+xx]);
|
|
l2id = tt->id;
|
|
if (l2id == T_BLANK) {
|
|
// add ice layer
|
|
tt = gettile(curlevel->map[yy*LEVELW+xx]);
|
|
switch (tt->id) {
|
|
case T_FULL:
|
|
curlevel->map2[yy*LEVELW+xx] = getuniq(T_ICE);
|
|
changed = B_TRUE;
|
|
break;
|
|
case T_LAND:
|
|
curlevel->map2[yy*LEVELW+xx] = getuniq(T_ICETOP);
|
|
changed = B_TRUE;
|
|
break;
|
|
}
|
|
} else { // certain l2 ids can still be replaced
|
|
switch (l2id) {
|
|
case T_FULL:
|
|
curlevel->map2[yy*LEVELW+xx] = getuniq(T_ICE);
|
|
changed = B_TRUE;
|
|
break;
|
|
case T_LAND:
|
|
curlevel->map2[yy*LEVELW+xx] = getuniq(T_ICETOP);
|
|
changed = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (changed) {
|
|
drawtile(temps, xx, yy);
|
|
}
|
|
}
|
|
// finished?
|
|
if ((xx == LEVELW-1) && (yy == LEVELH-1)) {
|
|
curlevel->iced = ICE_COMPLETE;
|
|
break;
|
|
}
|
|
xx++;
|
|
if (xx >= LEVELW) break;
|
|
}
|
|
|
|
// ice any monsters
|
|
for (s = sprite; s ; s = s->next) {
|
|
if (ismonster(s->id)) {
|
|
if ((s->x <= (xx*TILEW)) && (s->y <= (curlevel->icey*TILEH))) {
|
|
if (!s->iced && !s->dead && !s->caughtby) {
|
|
// ice it!
|
|
s->iced = B_TRUE;
|
|
s->jumping = B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// increase icey for next time
|
|
curlevel->icey++;
|
|
}
|
|
|
|
void adjustx(sprite_t *s,int framenum) {
|
|
int newx,newy,diff;
|
|
tiletype_t *tt;
|
|
|
|
if (imageset[s->id].img[framenum] == NULL) {
|
|
return;
|
|
}
|
|
|
|
if ((levelcomplete == LV_CLOUD) || (levelcomplete == LV_CLOUDLOOP)) {
|
|
return;
|
|
}
|
|
|
|
if (imageset[s->id].img[framenum]->w > s->img->w) {
|
|
diff = (imageset[s->id].img[framenum]->w - s->img->w) +1 ;
|
|
} else {
|
|
diff = (s->img->w - imageset[s->id].img[framenum]->w) +1 ;
|
|
}
|
|
newy = s->y-TILEH;
|
|
|
|
// check RIGHT
|
|
newx = s->x + (s->img->w/2);
|
|
tt = gettileat(newx,newy,NULL,NULL);
|
|
if (tt->solid == S_SOLID) {
|
|
s->x -= diff;
|
|
}
|
|
// check LEFT
|
|
newx = s->x - (s->img->w/2);
|
|
tt = gettileat(newx,newy,NULL,NULL);
|
|
if (tt->solid == S_SOLID) {
|
|
s->x += diff;
|
|
}
|
|
}
|
|
|
|
/* check for death & update movement status*/
|
|
void checksprites(void) {
|
|
sprite_t *s, *nextsprite;
|
|
int inair = 0;
|
|
|
|
|
|
for (s = sprite ; s ; s = nextsprite) {
|
|
s->moved = MV_NONE;
|
|
nextsprite = s->next;
|
|
|
|
if (ismonster(s->id)) {
|
|
if ((s->dead && (s->dead != D_FINAL))) {
|
|
inair++;
|
|
}
|
|
}
|
|
|
|
|
|
if (s->dead == D_FINAL) {
|
|
if (isplayer(s)) {
|
|
int alldead;
|
|
if (s->lives > 0) {
|
|
/* if we have lives left, go back to start position */
|
|
setdefaults(s);
|
|
if (s == player) {
|
|
s->x = (curlevel->p1x * TILEW) + (TILEW/2);
|
|
s->y = (curlevel->p1y * TILEH) + (TILEH/2);
|
|
} else {
|
|
s->x = (curlevel->p2x * TILEW) + (TILEW/2);
|
|
s->y = (curlevel->p2y * TILEH) + (TILEH/2);
|
|
}
|
|
makeinvuln(s);
|
|
} else {
|
|
// permenantly dead - mark for later
|
|
s->lives = -1;
|
|
}
|
|
|
|
// is everyone dead?
|
|
alldead = B_TRUE;
|
|
if (player) {
|
|
if ((player->dead != D_FINAL) || (player->lives > 0)) alldead = B_FALSE;
|
|
}
|
|
if (player2) {
|
|
if ((player2->dead != D_FINAL) || (player2->lives > 0)) alldead = B_FALSE;
|
|
}
|
|
|
|
if (alldead) {
|
|
if (levelcomplete != LV_GAMEOVER) {
|
|
// special type - when it expires, gameover timer will start
|
|
addoutlinetext(320,240,TEXTSIZE_GAMEOVER,"Game Over",&red,&black,GAMEOVERDELAY,TT_GAMEOVER);
|
|
levelcomplete = LV_GAMEOVER;
|
|
stopmusic();
|
|
playfx(FX_GAMEOVER);
|
|
}
|
|
}
|
|
} else {
|
|
if ((s->id == P_PUFF) && (s->timer1 != 999)) {
|
|
printf("puff died without changing!!!\n");
|
|
}
|
|
killsprite(s);
|
|
// check for level completion
|
|
checklevelend();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ((inair == 0) && (fruittime != -1)) {
|
|
|
|
// reset fruit counter
|
|
fruittime = -1;
|
|
curfruittype = 0;
|
|
}
|
|
|
|
|
|
// check if we've hit the cloud
|
|
if (levelcomplete == LV_NEXTLEV) {
|
|
nextlevel();
|
|
}
|
|
}
|
|
|
|
void moveallsprites(void) {
|
|
sprite_t *s;
|
|
for (s = sprite; s ; s = s->next) {
|
|
movesprite(s);
|
|
|
|
}
|
|
}
|
|
|
|
void checkcollideall(void) {
|
|
sprite_t *s;
|
|
|
|
/* check collisions for player and effects */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if (isplayer(s)) {
|
|
if (!inintro()) {
|
|
if (s->powerup != PW_GUNNER) {
|
|
checkcollide(s);
|
|
}
|
|
}
|
|
} else if (needscollisions(s->id)) {
|
|
if (isplatform(s->id)) {
|
|
checkcollideplatform(s);
|
|
} else {
|
|
checkcollide(s);
|
|
}
|
|
} else if ((s->id == P_BLACKCLOUD) && (globpowerup == PW_WHISTLE)) {
|
|
checkcollide(s);
|
|
} else if (inintro() && s->id == P_RAT) {
|
|
checkcollide(s);
|
|
} else if ((s->id == P_ANT1) || (s->id == P_ANT2) || (s->id == P_ANT3)) {
|
|
checkcollide(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
void drawallsprites(void) {
|
|
sprite_t *s;
|
|
int lastframe;
|
|
/* draw non-puff sprites */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if (s->id != P_PUFF) {
|
|
lastframe = s->frame;
|
|
drawsprite(s);
|
|
if (s->frame != lastframe) {
|
|
if ((s->id == P_KINGFLY) || ((s->id == P_FLY) && (s->owner))) {
|
|
// don't adjust
|
|
} else {
|
|
adjustx(s, s->frame);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* draw puff sprites */
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if (s->id == P_PUFF) drawsprite(s);
|
|
}
|
|
}
|
|
|
|
// check if sprite has passed off bottom/top of screen
|
|
void checkwrap(sprite_t *s) {
|
|
if (!s) return;
|
|
if (!s->dead) {
|
|
if (!iseffect(s->id)) {
|
|
/* if we've fallen off the bottom... */
|
|
if (s->y > (SCREENH+s->img->h)) {
|
|
if (inintro()) {
|
|
// die
|
|
s->dead = D_FINAL;
|
|
} else {
|
|
// move to top
|
|
s->y = -s->img->h;
|
|
}
|
|
}
|
|
/* if we've gone off the top */
|
|
if (s->y < -s->img->h) {
|
|
// move to bottom
|
|
s->y = (SCREENH+s->img->h);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
int getcurworld(void) {
|
|
return getworld(curlevelnum);
|
|
}
|
|
|
|
int getcurlevel(void) {
|
|
return getlevel(curlevelnum);
|
|
}
|
|
|
|
// returns how high a given monster will jump
|
|
int getmonjumpspeed(sprite_t *s ) {
|
|
switch (s->id) {
|
|
case P_SLUG:
|
|
if (s->jumpdir == 0) { // jumping straight up
|
|
return MONJUMPSPEED;
|
|
} else { // jumping horizontally
|
|
return 3;
|
|
}
|
|
case P_KINGSNAIL:
|
|
return 3;
|
|
case P_KINGCAT:
|
|
return 7;
|
|
default:
|
|
return MONJUMPSPEED;
|
|
}
|
|
}
|
|
|
|
|
|
// returns how long to pause before jumping
|
|
int getjumpdelay(int mid) {
|
|
switch (mid) {
|
|
case P_SLUG:
|
|
return 30;
|
|
case P_KINGSNAIL:
|
|
return 60;
|
|
default:
|
|
return 60;
|
|
}
|
|
}
|
|
|
|
|
|
void togglepause(void) {
|
|
if (paused) {
|
|
Mix_ResumeMusic();
|
|
paused = B_FALSE;
|
|
} else {
|
|
Mix_PauseMusic();
|
|
paused = B_TRUE;
|
|
}
|
|
}
|
|
|
|
void togglefullscreen(void) {
|
|
int vidargs;
|
|
// close window
|
|
//SDL_Quit();
|
|
|
|
// set fullscreen variable
|
|
if (fullscreen) {
|
|
fullscreen = B_FALSE;
|
|
} else {
|
|
fullscreen = B_TRUE;
|
|
}
|
|
|
|
vidargs = SDL_SWSURFACE|(fullscreen?SDL_FULLSCREEN:0);
|
|
#ifdef OPENGL
|
|
vidargs |= SDL_OPENGL;
|
|
#endif
|
|
|
|
#ifdef OPENGL
|
|
preinitgl();
|
|
realscreen=SDL_SetVideoMode(realscreen->w,realscreen->h,realscreen->format->BitsPerPixel,vidargs);
|
|
initgl();
|
|
#else
|
|
screen=SDL_SetVideoMode(screen->w,screen->h,screen->format->BitsPerPixel,vidargs);
|
|
#endif
|
|
|
|
// set title bar if required
|
|
if (!fullscreen) {
|
|
SDL_WM_SetCaption(progname, progname);
|
|
}
|
|
|
|
// redraw background
|
|
SDL_BlitSurface(temps, NULL, screen, NULL);
|
|
if (!paused) {
|
|
/* redo framerate manager */
|
|
SDL_setFramerate(&manager, WANTFPS);
|
|
}
|
|
|
|
flip(B_CLEAR);
|
|
/*
|
|
gengl(screen);
|
|
|
|
blittoscreen();
|
|
*/
|
|
}
|
|
|
|
#ifdef OPENGL
|
|
void preinitgl(void) {
|
|
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_DOUBLEBUFFER, 1);
|
|
}
|
|
|
|
void initgl(void) {
|
|
glClearColor( 0, 0, 0, 0 );
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_NEVER);
|
|
glEnable( GL_TEXTURE_2D ); // Need this to display a texture
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glViewport( 0, 0, SCREENW, SCREENH ); // set screen size
|
|
glMatrixMode( GL_PROJECTION );
|
|
glLoadIdentity();
|
|
glOrtho( 0, SCREENW, SCREENH, 0, -1, 1 );
|
|
glMatrixMode( GL_MODELVIEW );
|
|
glLoadIdentity();
|
|
}
|
|
#endif
|
|
|
|
void initsdl(void) {
|
|
int i;
|
|
int wantbpp = 32;
|
|
if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE)==-1) {
|
|
printf("SDL_Init: %s\n", SDL_GetError());
|
|
exit(1);
|
|
}
|
|
|
|
vidargs = 0;
|
|
if (fullscreen) {
|
|
vidargs |= SDL_FULLSCREEN;
|
|
}
|
|
|
|
#ifdef OPENGL
|
|
preinitgl();
|
|
|
|
realscreen = SDL_SetVideoMode(SCREENW,SCREENH,wantbpp,SDL_SWSURFACE|SDL_OPENGL|vidargs);
|
|
screen = SDL_CreateRGBSurface(SDL_SWSURFACE, realscreen->w, realscreen->h, wantbpp, rm, gm, bm ,am);
|
|
|
|
SDL_SetAlpha(screen, SDL_SRCALPHA, 0);
|
|
#else
|
|
//screen = SDL_SetVideoMode(SCREENW,SCREENH,16,SDL_SWSURFACE|SDL_DOUBLEBUF|vidargs);
|
|
|
|
// Try for 16 bit mode, but SDL_ANYFORMAT means that 32 bit is acceptable.
|
|
screen = SDL_SetVideoMode(SCREENW,SCREENH,wantbpp,SDL_SWSURFACE|SDL_ANYFORMAT|vidargs);
|
|
#endif
|
|
|
|
// set drawpixel function based on what depth we ended up with
|
|
if (realscreen->format->BitsPerPixel == 32) {
|
|
drawpixel = drawpixel32;
|
|
printf("32 bit mode in use.\n");
|
|
} else {
|
|
drawpixel = drawpixel16;
|
|
printf("16 bit mode in use.\n");
|
|
}
|
|
|
|
#ifdef OPENGL
|
|
initgl();
|
|
#endif
|
|
|
|
// set title bar
|
|
SDL_WM_SetCaption(progname, progname);
|
|
|
|
if (!screen) {
|
|
printf("Failed to open window: %s\n", SDL_GetError());
|
|
exit(1);
|
|
}
|
|
SDL_ShowCursor(SDL_DISABLE);
|
|
|
|
// find joysticks
|
|
havejoysticks = 0;
|
|
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
|
for (i = 0; i < 2; i++) {
|
|
joy[i] = SDL_JoystickOpen(i);
|
|
if (joy[i]) {
|
|
joyname[i] = SDL_JoystickName(i);
|
|
|
|
printf("Joystick #%d found: %s",i, joyname[i]);
|
|
if (strstr(joyname[i], "aystati")) {
|
|
joytype[i] = J_PLAYSTATION;
|
|
printf(" (PS3 controller)\n");
|
|
} else if (strstr(joyname[i], "Wii")) {
|
|
joytype[i] = J_WII;
|
|
printf(" (Wiimote)\n");
|
|
} else {
|
|
joytype[i] = J_OTHER;
|
|
printf(" (Generic joystick)\n");
|
|
}
|
|
havejoysticks++;
|
|
joybuttons[i] = SDL_JoystickNumButtons(joy[i]);
|
|
printf("Joy %d has %d buttons\n",i,joybuttons[i]);
|
|
if (joytype[i] == J_PLAYSTATION) {
|
|
joyanalog[i] = B_TRUE;
|
|
} else {
|
|
joyanalog[i] = B_FALSE;
|
|
}
|
|
if (joyanalog[i]) {
|
|
joythresh[i] = JOYTHRESH_ANA;
|
|
} else {
|
|
joythresh[i] = JOYTHRESH_DIG;
|
|
}
|
|
}
|
|
}
|
|
if (havejoysticks) {
|
|
setjoymappings();
|
|
SDL_JoystickEventState(SDL_ENABLE);
|
|
} else {
|
|
printf("No joysticks found.\n");
|
|
}
|
|
|
|
SDL_EnableUNICODE(1);
|
|
}
|
|
|
|
// player collects the given fruit
|
|
void getfruit(sprite_t *giveto, sprite_t *fruit, int multiplier) {
|
|
char tempm[MIDBUFLEN];
|
|
char tempm2[BUFLEN];
|
|
int gotscore = fruit->score;
|
|
int modscore; // default
|
|
int i;
|
|
SDL_Color *col, *bgcol;
|
|
|
|
/* kill the fruit */
|
|
fruit->dead = D_FINAL;
|
|
|
|
// 100x points at endgame
|
|
if (endgame) {
|
|
gotscore *= 100;
|
|
}
|
|
|
|
modscore = gotscore; // default
|
|
|
|
/* give points to the player */
|
|
for (i = 0; i < multiplier; i++) {
|
|
modscore = addscore(giveto, gotscore);
|
|
}
|
|
|
|
if (fruit->id == P_RANDOM) {
|
|
// change id to whatever it currently looks like
|
|
fruit->id = fruit->timer1;
|
|
}
|
|
|
|
/* handle fruit effects */
|
|
if (!dofruiteffect(giveto, fruit)) {
|
|
int pointsx,pointsy;
|
|
playfx(FX_FRUIT);
|
|
col = getcolour(fruit->id);
|
|
bgcol = getbgcolour(fruit->id);
|
|
pointsx = fruit->x;
|
|
pointsy = fruit->y - fruit->img->h/2;
|
|
if (fruit->caughtby) {
|
|
// offset a little.
|
|
pointsx += (fruit->caughtdelay * fruit->caughtby->netdir);
|
|
pointsy -= (fruit->caughtdelay/4);
|
|
}
|
|
if (multiplier <= 1) {
|
|
addcommas(tempm, modscore);
|
|
//sprintf(tempm, "%d", modscore);
|
|
if (modscore > 0) {
|
|
addoutlinetext(pointsx,pointsy, TEXTSIZE_POINTS, tempm, col,bgcol,POINTSDELAY,TT_NORM);
|
|
}
|
|
} else {
|
|
|
|
addcommas(tempm, modscore);
|
|
sprintf(tempm2, "%s x %d" , tempm,multiplier);
|
|
if (modscore > 0) {
|
|
addoutlinetext(pointsx,pointsy, TEXTSIZE_POINTS + 2*multiplier, tempm2, col,bgcol,POINTSDELAY,TT_NORM);
|
|
}
|
|
}
|
|
|
|
// last goin coin is special...
|
|
if (fruit->id == P_GOLDCOIN) {
|
|
int ccount;
|
|
sprite_t *s2;
|
|
ccount = 0;
|
|
for (s2 = sprite; s2 ; s2 = s2->next) {
|
|
if (s2 != fruit) {
|
|
if (s2->id == P_GOLDCOIN) {
|
|
ccount++;
|
|
} else if ((s2->id == P_PUFF) && (s2->timer3 == P_GOLDCOIN)) {
|
|
ccount++;
|
|
}
|
|
}
|
|
}
|
|
if (ccount == 0) {
|
|
addoutlinetext(fruit->x,fruit->y - fruit->img->h/2, TEXTSIZE_BOMB, "Perfect!", &green,&black,CLOVERDELAY,TT_NORM);
|
|
forcegold = B_TRUE;
|
|
forcegoldlev = curlevelnum;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// slowly change level to water
|
|
void doflood(void) {
|
|
int yy,xx,changed;
|
|
int l2id;
|
|
|
|
// just in case
|
|
if (!curlevel->iced) {
|
|
curlevel->iced = WATER_INPROGRESS;
|
|
}
|
|
// slowly change a level to water
|
|
//if (timer % ICESPEED == 0) {
|
|
|
|
for (yy = curlevel->icey ; (yy <= curlevel->icey+1) && (yy < LEVELH); yy++) {
|
|
for (xx = 0; xx < LEVELW; xx++) {
|
|
tiletype_t *tt;
|
|
changed = B_FALSE;
|
|
// if not already a second layer here...
|
|
//l2id = curlevel->map2[yy*LEVELW+xx];
|
|
tt = gettile(curlevel->map2[yy*LEVELW+xx]);
|
|
l2id = tt->id;
|
|
if (l2id == T_BLANK) {
|
|
// maybe change to water ice layer
|
|
tt = gettile(curlevel->map[yy*LEVELW+xx]);
|
|
switch (tt->id) {
|
|
case T_BLANK:
|
|
case T_SKY:
|
|
case T_SPIKES:
|
|
case T_WATER:
|
|
case T_WATERTOP:
|
|
if (yy == curlevel->icey) {
|
|
curlevel->map2[yy*LEVELW+xx] = getuniq(T_WATERTOP);
|
|
} else {
|
|
curlevel->map2[yy*LEVELW+xx] = getuniq(T_WATER);
|
|
}
|
|
changed = B_TRUE;
|
|
break;
|
|
}
|
|
} else { // certain l2 ids can still be replaced
|
|
switch (l2id) {
|
|
case T_SKY:
|
|
case T_WATER:
|
|
case T_WATERTOP:
|
|
if (yy == curlevel->icey) {
|
|
curlevel->map2[yy*LEVELW+xx] = getuniq(T_WATERTOP);
|
|
} else {
|
|
curlevel->map2[yy*LEVELW+xx] = getuniq(T_WATER);
|
|
}
|
|
changed = B_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (changed) {
|
|
drawtile(temps, xx, yy);
|
|
}
|
|
}
|
|
}
|
|
|
|
// decrease icey for next time
|
|
curlevel->icey--;
|
|
if (curlevel->icey < 0) {
|
|
curlevel->iced = WATER_COMPLETE;
|
|
}
|
|
}
|
|
|
|
// put flood effect back to normal
|
|
void undoflood(void) {
|
|
int x,y;
|
|
for (y = 0 ; y < LEVELH; y++) {
|
|
for (x = 0 ; x < LEVELW; x++) {
|
|
curlevel->map2[y*LEVELW+x] = savemap[y*LEVELW+x];
|
|
drawtile(temps, x, y);
|
|
}
|
|
}
|
|
SDL_BlitSurface(temps, NULL, screen, NULL);
|
|
|
|
}
|
|
|
|
|
|
sprite_t *haspowerupany(int pid) {
|
|
if (player && haspowerup(player,pid)) return player;
|
|
if (player2 && haspowerup(player2,pid)) return player2;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
int haspowerup(sprite_t *s, int pid) {
|
|
if (!s) return B_FALSE;
|
|
switch (pid) {
|
|
case P_SPEED:
|
|
if (s->speed != PLAYERSLOW) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case P_NUMNETS:
|
|
if (s->netmax >= 4 ) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case P_BIGNET:
|
|
if (s->netbig) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case P_MASKPOWERUP:
|
|
if (s->hasmask) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case P_TROPHY:
|
|
if ((s->netmax >= 4) && (s->netbig) && (s->speed != PLAYERSLOW)) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case P_HELMET:
|
|
if (s->armour) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case P_BELL:
|
|
if (s->hasbell) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case P_GEMBOOST:
|
|
if (s->gemboost >= 3) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case P_HONEY:
|
|
if (s->netsticky) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
case P_WINGBOOTS:
|
|
if (s->doublejump) {
|
|
return B_TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
if (s->powerup == pid) return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
void gaincard(sprite_t *s, int cardid) {
|
|
int i;
|
|
char msg[BUFLEN];
|
|
|
|
// just in case
|
|
if (s->numcards >= MAXCARDS) return;
|
|
|
|
// gain the card
|
|
s->card[s->numcards] = cardid;
|
|
s->numcards++;
|
|
|
|
|
|
// check for a full hand of cards
|
|
if (s->numcards == MAXCARDS) {
|
|
int cardwidth,cardheight;
|
|
SDL_Rect area;
|
|
sprite_t *newsp;
|
|
|
|
cardwidth = imageset[P_FIRSTCARD].img[F_WALK1]->w;
|
|
cardheight = imageset[P_FIRSTCARD].img[F_WALK1]->h;
|
|
|
|
// remember old level state
|
|
oldlevelcomplete = levelcomplete;
|
|
// change state to LV_CARDCOMPLETE
|
|
// (in this state, everything is frozen )
|
|
levelcomplete = LV_DOPOKER;
|
|
|
|
|
|
// generate FIVECARDS sprite
|
|
if (s == player) {
|
|
newsp = addsprite(P_FIVECARDS, CARDX, CARDY, "fivecards");
|
|
} else {
|
|
int cardx2 = SCREENW - CARDX - (5*(imageset[P_FIRSTCARD].img[F_WALK1]->w + 2));
|
|
newsp = addsprite(P_FIVECARDS, cardx2, CARDY, "fivecards");
|
|
}
|
|
newsp->owner = s;
|
|
|
|
// create blank image
|
|
newsp->img = SDL_CreateRGBSurface(SDL_SWSURFACE,
|
|
(cardwidth+2)*MAXCARDS, cardheight,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask,
|
|
screen->format->Amask);
|
|
SDL_FillRect(newsp->img, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
|
|
// fill in the cards
|
|
if (s == player) { // left to right
|
|
area.x = 0;
|
|
area.y = 0;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
for (i = 0; i < s->numcards; i++) {
|
|
SDL_Surface *cardimg;
|
|
cardimg = imageset[s->card[i]].img[F_WALK1];
|
|
if (cardimg == NULL){
|
|
printf("ERROR! Card image is null!!\n");
|
|
fflush(stdout);
|
|
}
|
|
SDL_BlitSurface(cardimg, NULL, newsp->img, &area);
|
|
area.x += (cardimg->w + 2);
|
|
}
|
|
} else { // right to left
|
|
area.x = 4*(cardwidth+2);
|
|
area.y = 0;
|
|
area.w = 0;
|
|
area.h = 0;
|
|
for (i = 0; i < s->numcards; i++) {
|
|
SDL_Surface *cardimg;
|
|
cardimg = imageset[s->card[i]].img[F_WALK1];
|
|
if (cardimg == NULL){
|
|
printf("ERROR! Card image is null!!\n");
|
|
fflush(stdout);
|
|
}
|
|
SDL_BlitSurface(cardimg, NULL, newsp->img, &area);
|
|
area.x -= (cardimg->w + 2);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// adjust x value so we can use drawsprite()
|
|
newsp->x += (newsp->img->w / 2);
|
|
newsp->y += (newsp->img->h);
|
|
|
|
// figure out what happened
|
|
pokereffect = getpokereffect(s);
|
|
|
|
getpokermsg2(pokereffect, msg);
|
|
// display BIG message
|
|
addoutlinetext(320,180,TEXTSIZE_POKER,getpokermsg(pokereffect),&green, &black, POKERDELAY,TT_NORM);
|
|
addoutlinetext(320,290,TEXTSIZE_POKER,msg,&green, &black, POKERDELAY,TT_NORM);
|
|
|
|
// pause music
|
|
Mix_PauseMusic();
|
|
|
|
// sound effect
|
|
playfx(FX_POKER);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// figure out what poker effect to apply and set variables
|
|
// also record which cards were used in pl->usedcards
|
|
int getpokereffect(sprite_t *pl) {
|
|
int i, c, count, curval, val, suit, found;
|
|
// default
|
|
pokerpoints = 0;
|
|
|
|
/// mark all player cards as unused
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
pl->usedcard[c] = B_FALSE;
|
|
}
|
|
|
|
|
|
// * check for royal straight flush (perm trophy)
|
|
// for each card, count up from here
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
count = 1;
|
|
val = getcardvalue(pl->card[i]);
|
|
suit = getcardsuit(pl->card[i]);
|
|
curval = val;
|
|
found = B_TRUE;
|
|
// start at this card
|
|
while (found && count < 5) {
|
|
found = B_FALSE;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c != i) {
|
|
if (getcardsuit(pl->card[c]) == suit) { // same suit?
|
|
if (getcardvalue(pl->card[c]) == curval + 1) {
|
|
curval++;
|
|
count++;
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count >= 5) {
|
|
if (curval == 13) { // last card was a king
|
|
// GOT IT!
|
|
/// mark all player cards as USED
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
pl->usedcard[c] = B_TRUE;
|
|
}
|
|
return PE_ROYALFLUSH;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// * check for straight flush (skip 7 levels)
|
|
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
count = 1;
|
|
val = getcardvalue(pl->card[i]);
|
|
suit = getcardsuit(pl->card[i]);
|
|
curval = val;
|
|
found = B_TRUE;
|
|
// start at this card
|
|
while (found && count < 5) {
|
|
found = B_FALSE;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c != i) {
|
|
if (getcardsuit(pl->card[c]) == suit) { // same suit?
|
|
if (getcardvalue(pl->card[c]) == curval + 1) {
|
|
curval++;
|
|
count++;
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count >= 5) {
|
|
// GOT IT!
|
|
/// mark all player cards as USED
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
pl->usedcard[c] = B_TRUE;
|
|
}
|
|
return PE_STRAIGHTFLUSH;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// * check for four of a kind (perm 4 nets )
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
val = getcardvalue(pl->card[i]);
|
|
count = 1;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c != i) {
|
|
if (getcardvalue(pl->card[c]) == val ) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count >= 4) {
|
|
// GOT IT!
|
|
/// mark all player cards with correct value as USED
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (getcardvalue(pl->card[c]) == val) {
|
|
pl->usedcard[c] = B_TRUE;
|
|
}
|
|
}
|
|
return PE_FOUR;
|
|
}
|
|
}
|
|
|
|
|
|
// * check for full house (perm bignet )
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
val = getcardvalue(pl->card[i]);
|
|
count = 1;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c != i) {
|
|
if (getcardvalue(pl->card[c]) == val ) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count >= 3) {
|
|
int ii, val2,cc,count2;
|
|
// got a triple with this card - now look for doubles
|
|
|
|
for (ii = 0; ii < MAXCARDS; ii++) {
|
|
val2 = getcardvalue(pl->card[ii]);
|
|
if (val2 != val) { // must be a DIFFERENT value!
|
|
count2 = 1;
|
|
for (cc = 0; cc < MAXCARDS; cc++) {
|
|
if (cc != ii) {
|
|
if (getcardvalue(pl->card[cc]) == val2 ) {
|
|
count2++;
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count2 >= 2) {
|
|
// GOT IT! - double with this one
|
|
/// mark all player cards as USED
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
pl->usedcard[c] = B_TRUE;
|
|
}
|
|
return PE_FULLHOUSE;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// * check for flush (skip 5 levels )
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
suit = getcardsuit(pl->card[i]);
|
|
count = 1;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c != i) {
|
|
if (getcardsuit(pl->card[c]) == suit ) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count >= 5) {
|
|
// GOT IT!
|
|
/// mark all player cards as USED
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
pl->usedcard[c] = B_TRUE;
|
|
}
|
|
return PE_FLUSH;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// * check for straight (perm honey)
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
count = 1;
|
|
val = getcardvalue(pl->card[i]);
|
|
suit = getcardsuit(pl->card[i]);
|
|
curval = val;
|
|
found = B_TRUE;
|
|
// start at this card
|
|
while (found && count < 5) {
|
|
found = B_FALSE;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c != i) {
|
|
if (getcardvalue(pl->card[c]) == curval + 1) {
|
|
curval++;
|
|
count++;
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count >= 5) {
|
|
// GOT IT!
|
|
/// mark all player cards as USED
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
pl->usedcard[c] = B_TRUE;
|
|
}
|
|
return PE_STRAIGHT;
|
|
}
|
|
}
|
|
|
|
|
|
// * check for triple (skip 3 levels )
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
val = getcardvalue(pl->card[i]);
|
|
count = 1;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c != i) {
|
|
if (getcardvalue(pl->card[c]) == val ) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count >= 3) {
|
|
// GOT IT!
|
|
/// mark all player cards with correct value as USED
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (getcardvalue(pl->card[c]) == val) {
|
|
pl->usedcard[c] = B_TRUE;
|
|
}
|
|
}
|
|
return PE_TRIPLE;
|
|
}
|
|
}
|
|
|
|
|
|
// * check for two pair (value * 2000 for each card in pair )
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
val = getcardvalue(pl->card[i]);
|
|
count = 1;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c != i) {
|
|
if (getcardvalue(pl->card[c]) == val ) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count >= 2) {
|
|
int ii, val2,cc,count2;
|
|
// got a pair with this card - now look for another one
|
|
|
|
for (ii = 0; ii < MAXCARDS; ii++) {
|
|
val2 = getcardvalue(pl->card[ii]);
|
|
if (val2 != val) { // must be a DIFFERENT value!
|
|
count2 = 1;
|
|
for (cc = 0; cc < MAXCARDS; cc++) {
|
|
if (cc != ii) {
|
|
if (getcardvalue(pl->card[cc]) == val2 ) {
|
|
count2++;
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count2 >= 2) {
|
|
// GOT IT! - double with this one
|
|
/// mark all player cards as USED and assign points
|
|
pokerpoints = 0;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
int thisval;
|
|
thisval = getcardvalue(pl->card[c]);
|
|
if ((thisval == val) || (thisval == val2)) {
|
|
pokerpoints += (thisval * 4000);
|
|
pl->usedcard[c] = B_TRUE;
|
|
}
|
|
}
|
|
return PE_TWOPAIR;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// * check for pair (value * 2000 for each card in pair )
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
val = getcardvalue(pl->card[i]);
|
|
count = 1;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c != i) {
|
|
if (getcardvalue(pl->card[c]) == val ) {
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
// got it?
|
|
if (count >= 2) {
|
|
// GOT IT!
|
|
// assign points and
|
|
// mark all player cards with correct value as USED
|
|
pokerpoints = 0;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
int thisval;
|
|
thisval = getcardvalue(pl->card[c]);
|
|
if (thisval == val) {
|
|
pokerpoints += (thisval * 4000);
|
|
pl->usedcard[c] = B_TRUE;
|
|
}
|
|
}
|
|
return PE_PAIR;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// * default is high card (value * 1000)
|
|
// find highest card
|
|
count = -1;// use this to track highest card index
|
|
curval = -1;
|
|
for (i = 0; i < MAXCARDS; i++) {
|
|
val = getcardvalue(pl->card[i]);
|
|
if (val > curval) {
|
|
curval = val;
|
|
count = i;
|
|
}
|
|
}
|
|
// assign points
|
|
pokerpoints = curval * 1000;
|
|
|
|
// mark used card
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
if (c == count) {
|
|
pl->usedcard[c] = B_TRUE;
|
|
} else {
|
|
pl->usedcard[c] = B_FALSE;
|
|
}
|
|
}
|
|
return PE_HIGHCARD;
|
|
}
|
|
|
|
// actually apply the current poker effect (in global "pokereffect")
|
|
void dopokereffect(sprite_t *pl, int effect) {
|
|
char tempmsg[BUFLEN];
|
|
sprite_t *s2, *nexts;
|
|
|
|
switch (effect) {
|
|
case PE_HIGHCARD:
|
|
case PE_TWOPAIR:
|
|
case PE_PAIR:
|
|
// points
|
|
sprintf(tempmsg, "%d",addscore(pl, pokerpoints));
|
|
addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM);
|
|
break;
|
|
case PE_TRIPLE:
|
|
// skip 3 levels
|
|
sprintf(tempmsg, "Skip 3 levels!");
|
|
addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM);
|
|
// set powerup
|
|
pl->powerup = PW_PHONE;
|
|
skiplevels = 2;
|
|
// kill all enemies
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id) || ismonster(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
|
|
if (s2->caughtby) {
|
|
uncatch(s2);
|
|
}
|
|
}
|
|
}
|
|
// call in cloud immediately
|
|
levelcomplete = LV_FINAL;
|
|
break;
|
|
case PE_STRAIGHT:
|
|
// permenant big net
|
|
pl->permbignet = B_TRUE;
|
|
pl->netbig = B_TRUE;
|
|
sprintf(tempmsg, "Permenant Big Nets!");
|
|
addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM);
|
|
break;
|
|
case PE_FLUSH:
|
|
// skip 5 levels
|
|
sprintf(tempmsg, "Skip 5 levels!");
|
|
addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM);
|
|
// set powerup
|
|
pl->powerup = PW_PHONE;
|
|
skiplevels = 4;
|
|
// kill all enemies
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id) || ismonster(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
|
|
if (s2->caughtby) {
|
|
uncatch(s2);
|
|
}
|
|
}
|
|
}
|
|
// call in cloud immediately
|
|
levelcomplete = LV_FINAL;
|
|
break;
|
|
case PE_FULLHOUSE:
|
|
// permenant double jump
|
|
pl->permdoublejump = B_TRUE;
|
|
pl->doublejump = B_TRUE;
|
|
sprintf(tempmsg, "Permenant Double Jump!");
|
|
addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM);
|
|
break;
|
|
case PE_FOUR:
|
|
// permenant max nets
|
|
pl->permnumnets = 4;
|
|
pl->netmax = 4;
|
|
sprintf(tempmsg, "Permenant Max Nets!");
|
|
addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM);
|
|
break;
|
|
case PE_STRAIGHTFLUSH:
|
|
// skip 7 levels
|
|
sprintf(tempmsg, "Skip 7 levels!");
|
|
addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM);
|
|
// set powerup
|
|
pl->powerup = PW_PHONE;
|
|
skiplevels = 6;
|
|
// kill all enemies
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id) || ismonster(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
|
|
if (s2->caughtby) {
|
|
uncatch(s2);
|
|
}
|
|
}
|
|
}
|
|
// call in cloud immediately
|
|
levelcomplete = LV_FINAL;
|
|
break;
|
|
case PE_ROYALFLUSH:
|
|
// permenant trophy
|
|
pl->permspeed = B_TRUE;
|
|
pl->permbignet = B_TRUE;
|
|
pl->permnumnets = 4;
|
|
pl->speed = PLAYERFAST;
|
|
pl->netbig = B_TRUE;
|
|
pl->netmax = 4;
|
|
sprintf(tempmsg, "Permenant full power!");
|
|
addoutlinetext(pl->x,pl->y - pl->img->h/2, TEXTSIZE_BONUS, tempmsg,&cyan,&black,POKERMSGDELAY,TT_NORM);
|
|
break;
|
|
}
|
|
}
|
|
|
|
char *getpokermsg(int effect) {
|
|
switch (effect) {
|
|
case PE_HIGHCARD:
|
|
return "High Card";
|
|
case PE_PAIR:
|
|
return "Pair!";
|
|
case PE_TWOPAIR:
|
|
return "Two Pairs!";
|
|
case PE_TRIPLE:
|
|
return "Triple!";
|
|
case PE_STRAIGHT:
|
|
return "Straight!";
|
|
case PE_FLUSH:
|
|
return "Flush!";
|
|
case PE_FULLHOUSE:
|
|
return "Full House!";
|
|
case PE_FOUR:
|
|
return "Four of a Kind!";
|
|
case PE_STRAIGHTFLUSH:
|
|
return "Straight Flush!";
|
|
case PE_ROYALFLUSH:
|
|
return "ROYAL FLUSH!";
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
char *getpokermsg2(int effect, char *buf) {
|
|
sprintf(buf, "Unknown");
|
|
switch (effect) {
|
|
case PE_HIGHCARD:
|
|
sprintf(buf, "%d points",pokerpoints);
|
|
break;
|
|
case PE_PAIR:
|
|
sprintf(buf, "%d points",pokerpoints);
|
|
break;
|
|
case PE_TWOPAIR:
|
|
sprintf(buf, "%d points",pokerpoints);
|
|
break;
|
|
case PE_TRIPLE:
|
|
sprintf(buf, "Skip 3 levels");
|
|
break;
|
|
case PE_STRAIGHT:
|
|
sprintf(buf, "Permenant Big Nets");
|
|
break;
|
|
case PE_FLUSH:
|
|
sprintf(buf, "Skip 5 levels");
|
|
break;
|
|
case PE_FULLHOUSE:
|
|
sprintf(buf, "Permenant Double Jump");
|
|
break;
|
|
case PE_FOUR:
|
|
sprintf(buf, "Permenant 4x Nets");
|
|
break;
|
|
case PE_STRAIGHTFLUSH:
|
|
sprintf(buf, "Skip 7 levels");
|
|
break;
|
|
case PE_ROYALFLUSH:
|
|
sprintf(buf, "Permenant Full Power");
|
|
break;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
|
|
|
|
void handleinput(void) {
|
|
SDL_Event event;
|
|
|
|
/* check for key releases */
|
|
SDL_PumpEvents();
|
|
while (SDL_PollEvent(&event)) {
|
|
if (event.type == SDL_KEYUP) {
|
|
// TODO: can only add credits in title screen ?
|
|
// lose points for each credit after the first.
|
|
if ((event.key.keysym.sym == SDLK_5) || (event.key.keysym.sym == SDLK_6)) {
|
|
addcredit();
|
|
}
|
|
if (levelcomplete == LV_HELPFREEZE) {
|
|
if ((event.key.keysym.sym == KEY_SHOOT) || (event.key.keysym.sym == KEY_SLAM) ||
|
|
(event.key.keysym.sym == SDLK_s) || (event.key.keysym.sym == SDLK_f)) {
|
|
levelcomplete = oldlevelcomplete;
|
|
}
|
|
}
|
|
} else if (havejoysticks && (event.type == SDL_JOYBUTTONUP)) {
|
|
if (levelcomplete == LV_HELPFREEZE) {
|
|
if ((joybuttontokey(event.jbutton.button) == KEY_SHOOT) || (joybuttontokey(event.jbutton.button) == KEY_SLAM)) {
|
|
levelcomplete = oldlevelcomplete;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// don't accept other input in helpfreeze state
|
|
if (levelcomplete == LV_HELPFREEZE) return;
|
|
|
|
// now handle key preses /joystick
|
|
getinput();
|
|
|
|
|
|
/* ************************************************************
|
|
These keys can always be pressed
|
|
************************************************************/
|
|
|
|
|
|
// toggle fullscreen
|
|
if (keydown(0, SDLK_F3) || keydown(0, SDLK_BACKSLASH)) {
|
|
if (toggletimer == 0) {
|
|
// always pause first
|
|
paused = B_TRUE;
|
|
togglefullscreen();
|
|
toggletimer = 40;
|
|
}
|
|
}
|
|
|
|
// pause
|
|
if (keydown(0, SDLK_p)) {
|
|
if (toggletimer == 0) {
|
|
togglepause();
|
|
toggletimer = 80;
|
|
}
|
|
}
|
|
// quit
|
|
if (keydown(0, SDLK_ESCAPE)) {
|
|
exit(1);
|
|
}
|
|
if (keydown(0, SDLK_F2)) { // show framerate
|
|
if (toggletimer == 0) {
|
|
if (wantframerate) {
|
|
wantframerate = B_FALSE;
|
|
} else {
|
|
wantframerate = B_TRUE;
|
|
}
|
|
toggletimer = 80;
|
|
}
|
|
}
|
|
|
|
// 1up/2up
|
|
if ( (player && keydown(0, SDLK_1)) || (player2 && keydown(0, SDLK_2))) {
|
|
if (inintro()) {
|
|
// skip intro
|
|
nextlevel();
|
|
}
|
|
}
|
|
if (cheat) {
|
|
if (keydown(0, SDLK_q)) {
|
|
gtime = nexthurryup-1;
|
|
//gtime = nexthurryup+14;
|
|
}
|
|
if (keydown(0, SDLK_b)) {
|
|
//gtime = nexthurryup-1;
|
|
if (player && !player->dead) {
|
|
player->lives = 1;
|
|
}
|
|
if (player2 && !player2->dead) {
|
|
player2->lives = 1;
|
|
}
|
|
}
|
|
if (keydown(0, SDLK_t)) {
|
|
if (player->numcards == 0) {
|
|
//gaincard(player, getrandomcard());
|
|
//gaincard(player, getrandomcard());
|
|
//gaincard(player, getrandomcard());
|
|
//gaincard(player, getrandomcard());
|
|
gaincard(player, P_CARDD4);
|
|
gaincard(player, P_CARDD5);
|
|
gaincard(player, P_CARDD1);
|
|
gaincard(player, P_CARDDJ);
|
|
gaincard(player, P_CARDD10);
|
|
}
|
|
}
|
|
if (keydown(0, SDLK_u)) {
|
|
if (player2->numcards == 0) {
|
|
//gaincard(player, getrandomcard());
|
|
//gaincard(player, getrandomcard());
|
|
//gaincard(player, getrandomcard());
|
|
//gaincard(player, getrandomcard());
|
|
gaincard(player2, P_CARDD4);
|
|
gaincard(player2, P_CARDC5);
|
|
gaincard(player2, P_CARDD5);
|
|
gaincard(player2, P_CARDSJ);
|
|
gaincard(player2, P_CARDD10);
|
|
}
|
|
}
|
|
if (keydown(0, SDLK_e)) {
|
|
if (toggletimer == 0) {
|
|
addscore(player, 100001);
|
|
toggletimer = 30;
|
|
}
|
|
}
|
|
if (keydown(0, SDLK_v)) { // cheat
|
|
if (toggletimer == 0) {
|
|
// addsprite(P_BIGCHEST, (SCREENW/2), 0, "bigchest");
|
|
// all powerups
|
|
playfx(FX_POWERUP);
|
|
sprintf(tempm, "Cheat!");
|
|
if (player) {
|
|
//player->powerup = PW_MAGNET;
|
|
player->powerup = PW_RAYGUN;
|
|
player->netmax = 4; // all nets
|
|
player->netbig = B_TRUE; // big net
|
|
player->speed = PLAYERFAST; // fast
|
|
player->netsticky = B_TRUE;
|
|
player->doublejump = B_TRUE;
|
|
player->hasbell = B_TRUE;
|
|
player->umbrella = B_TRUE;
|
|
player->armour = B_TRUE;
|
|
player->id = P_ARMOUR; // change how the player looks
|
|
player->hasmask = B_TRUE;
|
|
addoutlinetext(player->x,player->y - player->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY,TT_NORM);
|
|
}
|
|
if (player2) {
|
|
player2->netmax = 4; // all nets
|
|
player2->netbig = B_TRUE; // big net
|
|
player2->speed = PLAYERFAST; // fast
|
|
player2->netsticky = B_TRUE;
|
|
player2->doublejump = B_TRUE;
|
|
player2->hasbell = B_TRUE;
|
|
player2->hasmask = B_TRUE;
|
|
player2->umbrella = B_TRUE;
|
|
addoutlinetext(player2->x,player2->y - player2->img->h/2, TEXTSIZE_POINTS, tempm,&white,&black,POINTSDELAY,TT_NORM);
|
|
}
|
|
toggletimer = 80;
|
|
}
|
|
}
|
|
if (keydown(0, SDLK_n)) {
|
|
if (toggletimer == 0) {
|
|
// nextlevel();
|
|
sprite_t *s2, *nexts;
|
|
// kill all enemies and fruits
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id) || ismonster(s2->id) || isfruit(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
if (ismonster(s2->id)) {
|
|
if (s2->caughtby) {
|
|
uncatch(s2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// call in cloud immediately
|
|
levelcomplete = LV_FINAL;
|
|
|
|
toggletimer = 50;
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (keydown(0, SDLK_d)) {
|
|
if (toggletimer == 0) {
|
|
// dump sprites
|
|
dumpsprites();
|
|
toggletimer = 50;
|
|
}
|
|
}
|
|
*/
|
|
/*
|
|
if (keydown(SDLK_d)) {
|
|
sprite_t *s2,*nexts;
|
|
// set powerup
|
|
player->powerup = PW_PHONE;
|
|
// kill all enemies
|
|
for (s2 = sprite; s2 ; s2 = nexts) {
|
|
nexts = s2->next;
|
|
if (isbullet(s2->id) || ismonster(s2->id)) {
|
|
s2->dead = D_FINAL;
|
|
|
|
if (s2->caughtby) {
|
|
uncatch(s2);
|
|
player->netcaught--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
// revive from dead or join in?
|
|
if (levelcomplete == LV_INPROGRESS) {
|
|
if (keydown(0, SDLK_1)) {
|
|
if (player) {
|
|
if ((player->dead == D_FINAL) && (player->lives == -1)) {
|
|
if (credits >= 1) {
|
|
double px,py;
|
|
// lose credit and come back to life
|
|
credits--;
|
|
setdefaults(player);
|
|
player->lives = INITPLAYERLIVES;
|
|
player->score = 0;
|
|
playfx(FX_EXTRALIFE);
|
|
px = (curlevel->p1x * TILEW) + (TILEW/2);
|
|
py = (curlevel->p1y * TILEH) + TILEH-2;
|
|
puffin(-1, px, py-TILEH, "nothing", 0);
|
|
puffin(-1, px, py, "nothing", 0);
|
|
if (!lockcredits) {
|
|
lockcredits = B_TRUE;
|
|
addoutlinetext(px,py - TILEH, TEXTSIZE_SCORE, "Credits locked",&yellow,&red2,DIEDELAY, TT_NORM);
|
|
}
|
|
}
|
|
}
|
|
} else { // !player
|
|
if (credits >= 1) {
|
|
double px,py;
|
|
|
|
// join the game
|
|
credits--;
|
|
px = (curlevel->p1x * TILEW) + (TILEW/2);
|
|
py = (curlevel->p1y * TILEH) + TILEH-2;
|
|
want1up = B_TRUE;
|
|
|
|
player = addsprite(swapplayers ? P_PLAYER2 : P_PLAYER, px, py, "Player 1" );
|
|
setdefaults(player);
|
|
puffin(-1, px, py-TILEH, "nothing", 0);
|
|
puffin(-1, px, py, "nothing", 0);
|
|
|
|
makeinvuln(player);
|
|
player->score = 0;
|
|
if (gamemode == GM_EASY) {
|
|
player->permarmour = B_TRUE;
|
|
player->armour = B_TRUE;
|
|
player->id = swapplayers ? P_ARMOUR2 : P_ARMOUR;
|
|
} else {
|
|
player->permarmour = B_FALSE;
|
|
player->armour = B_FALSE;
|
|
player->id = swapplayers ? P_PLAYER2 : P_PLAYER;
|
|
}
|
|
player->lives = INITPLAYERLIVES;
|
|
|
|
playfx(FX_EXTRALIFE);
|
|
}
|
|
}
|
|
}
|
|
if (keydown(0, SDLK_2)) {
|
|
if (player2) {
|
|
if ((player2->dead == D_FINAL) && (player2->lives == -1)) {
|
|
if (credits >= 1) {
|
|
double px,py;
|
|
// lose credit and come back to life
|
|
credits--;
|
|
setdefaults(player2);
|
|
player2->lives = INITPLAYERLIVES;
|
|
player2->score = 0;
|
|
playfx(FX_EXTRALIFE);
|
|
px = (curlevel->p2x * TILEW) + (TILEW/2);
|
|
py = (curlevel->p2y * TILEH) + TILEH-2;
|
|
puffin(-1, px, py-TILEH, "nothing", 0);
|
|
puffin(-1, px, py, "nothing", 0);
|
|
if (!lockcredits) {
|
|
lockcredits = B_TRUE;
|
|
addoutlinetext(px,py - TILEH, TEXTSIZE_SCORE, "Credits locked",&yellow,&red2,DIEDELAY, TT_NORM);
|
|
}
|
|
}
|
|
}
|
|
} else { // !player2
|
|
if (credits >= 1) {
|
|
double px,py;
|
|
|
|
// join the game
|
|
credits--;
|
|
px = (curlevel->p2x * TILEW) + (TILEW/2);
|
|
py = (curlevel->p2y * TILEH) + TILEH-2;
|
|
want1up = B_TRUE;
|
|
|
|
player2 = addsprite(swapplayers ? P_PLAYER : P_PLAYER2, px, py, "Player 2" );
|
|
setdefaults(player2);
|
|
puffin(-1, px, py-TILEH, "nothing", 0);
|
|
puffin(-1, px, py, "nothing", 0);
|
|
|
|
makeinvuln(player2);
|
|
player2->score = 0;
|
|
if (gamemode == GM_EASY) {
|
|
player2->permarmour = B_TRUE;
|
|
player2->armour = B_TRUE;
|
|
player2->id = swapplayers ? P_ARMOUR : P_ARMOUR2;
|
|
} else {
|
|
player2->permarmour = B_FALSE;
|
|
player2->armour = B_FALSE;
|
|
player2->id = swapplayers ? P_PLAYER : P_PLAYER2;
|
|
}
|
|
player2->lives = INITPLAYERLIVES;
|
|
|
|
playfx(FX_EXTRALIFE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* ************************************************************
|
|
Player movement
|
|
************************************************************/
|
|
if ((!inintro()) && !paused && (!levelcomplete != LV_DOPOKER) ) {
|
|
// is cloud touching the player?
|
|
if (levelcomplete == LV_CLOUD) {
|
|
sprite_t *c;
|
|
int hitplayer1 = B_FALSE,hitplayer2 = B_FALSE;
|
|
for (c = sprite ; c ; c = c->next) {
|
|
if (player) {
|
|
if ((c->owner == player) && (c->timer1 == LV_CLOUDLOOP)) {
|
|
// can't move
|
|
hitplayer1 = B_TRUE;
|
|
}
|
|
}
|
|
if (player2) {
|
|
if ((c->owner == player2) && (c->timer1 == LV_CLOUDLOOP)) {
|
|
// can't move
|
|
hitplayer2 = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
if (!hitplayer1) doplayermovement(player);
|
|
if (!hitplayer2) doplayermovement(player2);
|
|
} else {
|
|
doplayermovement(player);
|
|
doplayermovement(player2);
|
|
}
|
|
}
|
|
// ignore other events
|
|
while (SDL_PollEvent(&event)) {
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void swimup(sprite_t *pl) {
|
|
int pnum;
|
|
if (pl == player) {
|
|
pnum = 0;
|
|
} else if (pl == player2) {
|
|
pnum = 1;
|
|
} else return; // only valid for players
|
|
|
|
if (pl->moved & MV_SWIM) {
|
|
return;
|
|
}
|
|
|
|
pl->falling = B_FALSE;
|
|
if (!isroofabove(pl)) {
|
|
// is there water above us too?
|
|
if (isinwaterpoint(pl->x, pl->y-TILEH)) {
|
|
double swimspeed;
|
|
|
|
swimspeed = getspeed(pl);
|
|
if (pl->hasmask) {
|
|
swimspeed *= 1.5;
|
|
} else {
|
|
swimspeed *= 2;
|
|
}
|
|
// if so, swim up
|
|
pl->y -= swimspeed;
|
|
pl->moved |= MV_SWIM;
|
|
} else {
|
|
int whichway;
|
|
// if not, jump up
|
|
pl->climbing = B_FALSE;
|
|
if (keydown(pnum, KEY_RIGHT)) {
|
|
whichway = 1;
|
|
} else if (keydown(pnum, KEY_LEFT)) {
|
|
whichway = -1;
|
|
} else {
|
|
whichway = 0;
|
|
}
|
|
playfx(FX_SPLASH);
|
|
jump(pl, whichway);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void swimdown(sprite_t *pl) {
|
|
if (pl->moved & MV_SWIM) {
|
|
return;
|
|
}
|
|
|
|
pl->falling = B_FALSE;
|
|
if (!isonground(pl)) {
|
|
double swimspeed;
|
|
// swim down
|
|
swimspeed = getspeed(pl);
|
|
if (pl->hasmask) {
|
|
swimspeed *= 1.5;
|
|
} else {
|
|
swimspeed *= 2;
|
|
}
|
|
pl->y += swimspeed;
|
|
pl->moved |= MV_SWIM;
|
|
}
|
|
}
|
|
|
|
void leveltransition_blit(levscrollinfo_t *l, SDL_Surface *copybuffer) {
|
|
// remember entire screen
|
|
SDL_BlitSurface(screen, NULL, copybuffer, NULL);
|
|
|
|
// draw player(s)
|
|
if (curlevelnum != INTRO_LEVELNUM) {
|
|
if (l->player && l->player->lives > 0) {
|
|
drawsprite(l->player);
|
|
drawsprite(l->cloud);
|
|
}
|
|
if (l->player2 && l->player2->lives > 0) {
|
|
drawsprite(l->player2);
|
|
drawsprite(l->cloud2);
|
|
}
|
|
}
|
|
|
|
// update screen
|
|
flip(B_FALSE);
|
|
|
|
if (!paused) SDL_framerateDelay(&manager);
|
|
|
|
// remove players
|
|
if (curlevelnum != INTRO_LEVELNUM) {
|
|
// restore copy of screen
|
|
SDL_BlitSurface(copybuffer, NULL, screen, NULL);
|
|
}
|
|
}
|
|
|
|
void leveltransition_moveplayer(levscrollinfo_t *l) {
|
|
// move player
|
|
if (l->player && l->player->lives > 0) moveto(l->player,l->dstx[0],l->dsty[0],l->pspeed[0],l->pspeed[0]);
|
|
if (l->player2 && l->player2->lives > 0) moveto(l->player2,l->dstx[1],l->dsty[1],l->pspeed[1],l->pspeed[1]);
|
|
// set cloud location
|
|
if (l->player && l->player->lives > 0) {
|
|
l->cloud->x = l->player->x;
|
|
l->cloud->y = l->player->y + (l->cloud->img->h / 2);
|
|
}
|
|
if (l->player2 && l->player2->lives > 0) {
|
|
l->cloud2->x = l->player2->x;
|
|
l->cloud2->y = l->player2->y + (l->cloud2->img->h / 2);
|
|
}
|
|
}
|
|
|
|
void leveltransition_scrolllevel(int srcx, int srcy, int srcw, int srch,
|
|
int dstx, int dsty,
|
|
int nextcolx, int nextcoly, int nextcolw, int nextcolh,
|
|
int nextcol_dstx, int nextcol_dsty, int nextcol_dstw, int nextcol_dsth) {
|
|
SDL_Rect src,dst,area;
|
|
SDL_Surface *buf = NULL;
|
|
|
|
|
|
// shuffle real screen. Use a temp surface cause sdl doesn't seem to like
|
|
// blitting to and from the same surface.
|
|
src.x = srcx;
|
|
src.y = srcy;
|
|
src.w = srcw;
|
|
src.h = srch;
|
|
|
|
dst.x = dstx;
|
|
dst.y = dsty;
|
|
dst.w = 0;
|
|
dst.h = 0;
|
|
|
|
|
|
buf = SDL_CreateRGBSurface(SDL_SWSURFACE, srcw, srch,
|
|
screen->format->BitsPerPixel, screen->format->Rmask,
|
|
screen->format->Gmask,screen->format->Bmask, 0);
|
|
SDL_BlitSurface(screen, &src, buf, NULL);
|
|
|
|
SDL_BlitSurface(buf, NULL, screen, &dst);
|
|
SDL_FreeSurface(buf);
|
|
|
|
// blit next column from temp surface (take last column first)
|
|
area.x = nextcolx;
|
|
area.y = nextcoly;
|
|
area.w = nextcolw;
|
|
area.h = nextcolh;
|
|
|
|
dst.x = nextcol_dstx;
|
|
dst.y = nextcol_dsty;
|
|
dst.w = nextcol_dstw;
|
|
dst.h = nextcol_dsth;
|
|
SDL_BlitSurface(temps, &area, screen, &dst);
|
|
}
|
|
|
|
void trytojump(sprite_t *pl) {
|
|
int pnum;
|
|
|
|
if (pl == player) {
|
|
pnum = 0;
|
|
} else if (pl == player2) {
|
|
pnum = 1;
|
|
} else return; // only valid for players
|
|
|
|
if (pl->caughtby) return;
|
|
|
|
|
|
// can't jump while slamming
|
|
if (pl->slamming) return;
|
|
|
|
if (isinwater(pl)) { // in water?
|
|
// swim up
|
|
if (!pl->jumping) {
|
|
swimup(pl);
|
|
}
|
|
} else { // not in water
|
|
// jump
|
|
if (!pl->jumping || (pl->doublejump && pl->doublejumpready && !pl->useddoublejump)) {
|
|
if (!pl->falling || (pl->doublejump && pl->doublejumpready && !pl->useddoublejump)) {
|
|
if (isonground(pl) || isonladder(pl) || pl->doublejump ) {
|
|
/* dropping through a bridge */
|
|
if (keydown(pnum,KEY_DOWN)) {
|
|
if (isonbridge(pl) && !pl->falling) {
|
|
/* drop down */
|
|
pl->dropping = B_TRUE;
|
|
pl->dropx = pl->x / TILEW;
|
|
pl->dropy = pl->y / TILEH;
|
|
}
|
|
} else { // jumping
|
|
int whichway;
|
|
if (keydown(pnum,KEY_RIGHT)) {
|
|
whichway = 1;
|
|
} else if (keydown(pnum,KEY_LEFT)) {
|
|
whichway = -1;
|
|
} else {
|
|
whichway = 0;
|
|
}
|
|
|
|
jump(pl, whichway);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void trytoslam(sprite_t *pl) {
|
|
if (pl->caughtby) return;
|
|
|
|
if ((!pl->netting) && (!pl->slamming)) {
|
|
/* slam */
|
|
if ((!pl->slamming) && (isonground(pl) && !pl->climbing)) {
|
|
playfx(FX_SLAM);
|
|
pl->slamming = B_TRUE;
|
|
pl->slamangle = 0;
|
|
pl->netxstart = pl->x - (pl->img->w/2)*pl->dir;
|
|
|
|
|
|
adjustx(pl, F_SLAM1);
|
|
pl->netystart = pl->y;
|
|
|
|
/* handle mace */
|
|
if (pl->powerup == PW_MACE) {
|
|
sprite_t *s;
|
|
int found;
|
|
// use existing mace if it is there
|
|
found = B_FALSE;
|
|
for (s = sprite; s ; s = s->next) {
|
|
if ((s->id == P_MACE) && (s->owner == pl)) {
|
|
s->x = pl->x;
|
|
s->y = pl->y - (imageset[pl->id].img[F_SHOOT]->h / 2) + 5;
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
sprite_t *newsp;
|
|
newsp = addsprite(P_MACE, pl->x,
|
|
pl->y - (imageset[pl->id].img[F_SHOOT]->h / 2) + 5,
|
|
"mace");
|
|
newsp->owner = pl;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
void trytoshoot(sprite_t *pl) {
|
|
if (pl->caughtby) return;
|
|
|
|
if ((!pl->netting) && (!pl->slamming)) {
|
|
if ((pl->netcaught < pl->netmax) && (pl->climbing == B_FALSE)) {
|
|
// handle cannon
|
|
if (pl->powerup == PW_CANNON) {
|
|
playfx(FX_CANNON);
|
|
pl->powerup = PW_CANNONFIRE;
|
|
pl->timer3 = CANNONSIZE+5; // use this for size
|
|
|
|
} else {
|
|
if (pl->powerup == PW_RAYGUN) {
|
|
// fire a ray gun bullet
|
|
sprite_t *ss;
|
|
|
|
playfx(FX_LASER);
|
|
|
|
ss = addsprite(P_RAYGUNBULLET, pl->x, pl->y - (pl->img->h/2) + 4, "raygunbullet");
|
|
ss->xs = pl->dir * RAYGUNSPEED;
|
|
ss->dir = pl->dir;
|
|
|
|
pl->timer1--; // reduce # of shots
|
|
if (pl->timer1 > 0) {
|
|
sprintf(tempm, "%d shots left",pl->timer1);
|
|
addoutlinetext(pl->x,pl->y - pl->img->h, TEXTSIZE_POINTS, tempm,&cyan,&black,POINTSDELAY, TT_NORM);
|
|
} else {
|
|
sprintf(tempm, "Out of ammo");
|
|
addoutlinetext(pl->x,pl->y - pl->img->h, TEXTSIZE_POINTS, tempm,&grey2,&black,POINTSDELAY, TT_NORM);
|
|
}
|
|
} else {
|
|
// net sound effect
|
|
playfx(FX_SHOOT);
|
|
}
|
|
/* shoot net */
|
|
|
|
pl->netting = 1;
|
|
|
|
adjustx(pl, F_SHOOT);
|
|
if (pl->powerup == PW_ACCORDION) {
|
|
pl->netspeed = ACCNETSPEED;
|
|
} else if (pl->powerup == PW_SMALLNET) {
|
|
pl->netspeed = SMALLNETSPEED;
|
|
} else if (pl->netbig) {
|
|
pl->netspeed = BIGNETSPEED;
|
|
} else {
|
|
pl->netspeed = NETSPEED;
|
|
}
|
|
pl->netlen = 0;
|
|
pl->netdir = pl->dir;
|
|
|
|
// set up initial...
|
|
pl->nety = pl->y - (pl->img->h/2) + 2;
|
|
}
|
|
|
|
|
|
/* handle boxing glove */
|
|
if (pl->powerup == PW_BOXING) {
|
|
sprite_t *s;
|
|
int found;
|
|
// use existing glove if it is there
|
|
found = B_FALSE;
|
|
for (s = sprite; s ; s = s->next) {
|
|
if ((s->id == P_GLOVE) && (s->owner == pl)) {
|
|
s->x = pl->x;
|
|
s->y = pl->y - (imageset[pl->id].img[F_SHOOT]->h / 2) + 5;
|
|
found = B_TRUE;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
sprite_t *newsp;
|
|
newsp = addsprite(P_GLOVE, pl->x,
|
|
pl->y - (imageset[pl->id].img[F_SHOOT]->h / 2) + 5,
|
|
"glove");
|
|
newsp->owner = pl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int keydown(int whichplayer, int checkfor) {
|
|
int checkkey;
|
|
|
|
checkkey = checkfor;
|
|
|
|
// adjust checkkey based on player
|
|
if (whichplayer == 1) {
|
|
if (checkfor == KEY_RIGHT) checkkey = KEY2_RIGHT;
|
|
if (checkfor == KEY_LEFT) checkkey = KEY2_LEFT;
|
|
if (checkfor == KEY_UP) checkkey = KEY2_UP;
|
|
if (checkfor == KEY_DOWN) checkkey = KEY2_DOWN;
|
|
if (checkfor == KEY_SHOOT) checkkey = KEY2_SHOOT;
|
|
if (checkfor == KEY_JUMP) checkkey = KEY2_JUMP;
|
|
if (checkfor == KEY_SLAM) checkkey = KEY2_SLAM;
|
|
}
|
|
// check for keypress
|
|
if (keys[checkkey]) {
|
|
return B_TRUE;
|
|
}
|
|
|
|
// check for joystick
|
|
if (havejoysticks) {
|
|
//if (joybut[keytojoybutton(checkfor)]) return B_TRUE;
|
|
if (joybuttondown(whichplayer, checkfor)) return B_TRUE;
|
|
if ((checkfor == KEY_UP) && (joyy[whichplayer] <= -joythresh[whichplayer])) return B_TRUE;
|
|
if ((checkfor == KEY_DOWN) && (joyy[whichplayer] >= joythresh[whichplayer])) return B_TRUE;
|
|
if ((checkfor == KEY_LEFT) && (joyx[whichplayer] <= -joythresh[whichplayer])) return B_TRUE;
|
|
if ((checkfor == KEY_RIGHT) && (joyx[whichplayer] >= joythresh[whichplayer])) return B_TRUE;
|
|
}
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
// draw cannon lasers and check for collision from them
|
|
void docannoneffect(sprite_t *pp) {
|
|
if (timer % 2 == 0) {
|
|
int found;
|
|
sprite_t *s;
|
|
|
|
// find cannon
|
|
found = B_FALSE;
|
|
for (s = sprite; s ; s = s->next) {
|
|
if (s->id == P_CANNON) {
|
|
if (s->owner == pp) {
|
|
found = B_TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
printf("weird error - no cannon!!\n");
|
|
losepowerup(pp);
|
|
} else {
|
|
int initx,inity;
|
|
int i;
|
|
int initsize;
|
|
int xx,yy;
|
|
sprite_t *s3;
|
|
|
|
initsize = pp->timer3;
|
|
if (initsize > CANNONSIZE) initsize = CANNONSIZE;
|
|
|
|
// calc init positions
|
|
inity = s->y - (s->img->h/2) - (initsize/2);
|
|
initx = s->x - (initsize/2);
|
|
yy = inity;
|
|
xx = initx;
|
|
|
|
// horiz lines
|
|
for (i = 0; i < initsize ; i++) {
|
|
drawline(screen,0,yy,SCREENW,yy,white);
|
|
for (s3 = sprite; s3 ; s3 = s3->next) {
|
|
if (ismonster(s3->id) && !s3->dead) {
|
|
if (!s3->caughtby) {
|
|
if ((yy >= s3->y - s3->img->h) && (yy <= s3->y)) {
|
|
s3->willbecome = P_DIAMOND;
|
|
if (s3->id == P_SNAIL) s3->id = P_SLUG;
|
|
die(s3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
yy++;
|
|
}
|
|
// vert lines
|
|
for (i = 0; i < initsize ; i++) {
|
|
drawline(screen,xx,0,xx,SCREENH,white);
|
|
for (s3 = sprite; s3 ; s3 = s3->next) {
|
|
if (ismonster(s3->id) && !s3->dead) {
|
|
if (!s3->caughtby) {
|
|
if ((xx >= s3->x - (s3->img->w/2)) && (xx <= s3->x + (s3->img->w/2))) {
|
|
s3->willbecome = P_DIAMOND;
|
|
if (s3->id == P_SNAIL) s3->id = P_SLUG;
|
|
die(s3);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
xx++;
|
|
}
|
|
// dec size
|
|
if (timer % 8 == 0) {
|
|
pp->timer3--;
|
|
if (pp->timer3 <= 0) {
|
|
losepowerup(pp);
|
|
s->dead = D_FINAL;
|
|
SDL_BlitSurface(temps, NULL, screen, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void dotitlescreen(void) {
|
|
char tempst[BUFLEN];
|
|
char svnver[MIDBUFLEN];
|
|
SDL_Surface *titlebg;
|
|
SDL_Surface *cointext, *text, *text2, *easy, *norm, *ver;
|
|
SDL_Surface *help, *helpon, *helpoff;
|
|
SDL_Surface *p1ready,*p2ready;
|
|
SDL_Surface *p1readyalt,*p2readyalt;
|
|
SDL_Surface *ts;
|
|
SDL_Event event;
|
|
SDL_Rect area;
|
|
int timer = 0;
|
|
double bouncetimer = 0;
|
|
//int i;
|
|
int texton = B_TRUE;
|
|
int htstart = 0, htime = 0,hticks;
|
|
|
|
// allow credits
|
|
lockcredits = B_FALSE;
|
|
|
|
// clear all sprites!!
|
|
want1up = B_FALSE;
|
|
want2up = B_FALSE;
|
|
swapplayers = initialswapplayers;
|
|
|
|
while (sprite) {
|
|
killsprite(sprite);
|
|
}
|
|
sprite = NULL;
|
|
player = NULL;
|
|
player2 = NULL;
|
|
|
|
// reset gothiscore setting
|
|
gothiscore = -1;
|
|
gothiscore2 = -1;
|
|
|
|
|
|
// load title screen
|
|
sprintf(tempst, "%s/backgrounds/title.png",datadir);
|
|
ts = IMG_Load(tempst);
|
|
SDL_SetColorKey(ts, SDL_RLEACCEL, 0);
|
|
titlebg = SDL_DisplayFormat(ts);
|
|
SDL_FreeSurface(ts);
|
|
if (!titlebg) {
|
|
printf("cannot load title screen (%s)\n",tempst);
|
|
exit(1);
|
|
}
|
|
|
|
// load ready text
|
|
sprintf(tempst, "%s/sprites/p1ready.png",datadir);
|
|
ts = IMG_Load(tempst);
|
|
SDL_SetColorKey(ts, SDL_RLEACCEL, 0);
|
|
p1ready = SDL_DisplayFormat(ts);
|
|
SDL_FreeSurface(ts);
|
|
if (!p1ready) {
|
|
printf("cannot load p1 ready img (%s)\n",tempst);
|
|
exit(1);
|
|
}
|
|
sprintf(tempst, "%s/sprites/p1ready_alt.png",datadir);
|
|
ts = IMG_Load(tempst);
|
|
SDL_SetColorKey(ts, SDL_RLEACCEL, 0);
|
|
p1readyalt = SDL_DisplayFormat(ts);
|
|
SDL_FreeSurface(ts);
|
|
if (!p1readyalt) {
|
|
printf("cannot load p1 ready alt img (%s)\n",tempst);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
sprintf(tempst, "%s/sprites/p2ready.png",datadir);
|
|
ts = IMG_Load(tempst);
|
|
SDL_SetColorKey(ts, SDL_RLEACCEL, 0);
|
|
p2ready = SDL_DisplayFormat(ts);
|
|
SDL_FreeSurface(ts);
|
|
if (!p2ready) {
|
|
printf("cannot load p2 ready img (%s)\n",tempst);
|
|
exit(1);
|
|
}
|
|
|
|
sprintf(tempst, "%s/sprites/p2ready_alt.png",datadir);
|
|
ts = IMG_Load(tempst);
|
|
SDL_SetColorKey(ts, SDL_RLEACCEL, 0);
|
|
p2readyalt = SDL_DisplayFormat(ts);
|
|
SDL_FreeSurface(ts);
|
|
if (!p2readyalt) {
|
|
printf("cannot load p2 ready alt img (%s)\n",tempst);
|
|
exit(1);
|
|
}
|
|
|
|
// set up text
|
|
cointext = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Insert Coin", white);
|
|
text = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Press 1UP or 2UP to start", red);
|
|
text2 = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Select game mode:", red);
|
|
easy = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Easy Mode", red2);
|
|
norm = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Normal Mode", red2);
|
|
help = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Hints:", green);
|
|
helpoff = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "Off", green2);
|
|
helpon = TTF_RenderText_Solid(font[TEXTSIZE_TITLE], "On", green2);
|
|
|
|
//sprintf(svnver, "rpearce, 2006-2016 - %s", REV);
|
|
sprintf(svnver, "By rpearce, 2006-2016");
|
|
ver = TTF_RenderText_Solid(font[TEXTSIZE_VER], svnver, greenish);
|
|
|
|
|
|
if (credits > 0) {
|
|
titlemode = TS_WAIT1UP;
|
|
} else {
|
|
titlemode = TS_INSERTCOIN;
|
|
}
|
|
gamemode = GM_NORM; // default
|
|
|
|
blinkspeed = 20;
|
|
|
|
|
|
// wait for keypress
|
|
titledone = B_FALSE;
|
|
while (!titledone) {
|
|
if (SDL_PollEvent(&event)) {
|
|
int j;
|
|
switch (event.type) {
|
|
case SDL_JOYAXISMOTION:
|
|
j = event.jaxis.which;
|
|
joyx[j] = SDL_JoystickGetAxis(joy[j],0);
|
|
joyy[j] = SDL_JoystickGetAxis(joy[j],1);
|
|
//printf("got joy motion: joy %d, x=%d,y=%d\n",j,joyx[j],joyy[j]);
|
|
|
|
if (joyy[j] <= -6000) handletitleinput(j, KEY_UP);
|
|
if (joyy[j] >= 6000) handletitleinput(j, KEY_DOWN);
|
|
if (joyx[j] <= -6000) handletitleinput(j, KEY_LEFT);
|
|
if (joyx[j] >= 6000) handletitleinput(j, KEY_RIGHT);
|
|
|
|
break;
|
|
case SDL_KEYUP:
|
|
handletitleinput(0, event.key.keysym.sym);
|
|
break;
|
|
case SDL_JOYBUTTONUP:
|
|
//printf("got joy button: joy %d, button=%d\n",j,event.jbutton.button);
|
|
handletitleinput(event.jbutton.which, joybuttontokey(event.jbutton.button));
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
if (++timer >= blinkspeed) {
|
|
// reset timer
|
|
timer = 0;
|
|
// blink text
|
|
if (texton) {
|
|
// disappear
|
|
texton = B_FALSE;
|
|
} else {
|
|
// appear
|
|
texton = B_TRUE;
|
|
}
|
|
}
|
|
|
|
// draw screen
|
|
if ((titlemode == TS_HISCORES) || (titlemode == TS_CREDITS)) {
|
|
// clear screen to black
|
|
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
|
|
} else {
|
|
// draw titlescreen background
|
|
SDL_BlitSurface(titlebg, NULL, screen, NULL);
|
|
}
|
|
|
|
if (titlemode == TS_INSERTCOIN) {
|
|
// version number
|
|
//area.x = SCREENW - (ver->w) - 10;
|
|
area.x = (SCREENW/2) - (ver->w/2) - 10;
|
|
area.y = 150;
|
|
SDL_SetColors(ver, &black, 1, 1);
|
|
SDL_BlitSurface(ver, NULL, screen, &area);
|
|
|
|
area.x -= 2;
|
|
area.y -= 2;
|
|
SDL_SetColors(ver, &greenish, 1, 1);
|
|
SDL_BlitSurface(ver, NULL, screen, &area);
|
|
}
|
|
|
|
// "insert coin" text
|
|
if ((titlemode == TS_INSERTCOIN) || (titlemode == TS_HISCORES) || (titlemode == TS_CREDITS)) {
|
|
if (texton) {
|
|
area.x = 320 - (cointext->w/2)+2;
|
|
area.y = 10;
|
|
SDL_SetColors(cointext, &black, 1, 1);
|
|
SDL_BlitSurface(cointext, NULL, screen, &area);
|
|
|
|
area.x -= 2;
|
|
area.y -= 2;
|
|
SDL_SetColors(cointext, &white, 1, 1);
|
|
SDL_BlitSurface(cointext, NULL, screen, &area);
|
|
}
|
|
}
|
|
if (titlemode == TS_WAIT1UP) {
|
|
//if (texton) {
|
|
area.x = 320 - (text->w/2)+2;
|
|
area.y = 240 - (text->h/2)+2;
|
|
SDL_SetColors(text, &black, 1, 1);
|
|
SDL_BlitSurface(text, NULL, screen, &area);
|
|
|
|
area.x -= 2;
|
|
area.y -= 2;
|
|
SDL_SetColors(text, &red, 1, 1);
|
|
SDL_BlitSurface(text, NULL, screen, &area);
|
|
//}
|
|
} else if (titlemode == TS_SELECTMODE) {
|
|
SDL_Surface *desc;
|
|
|
|
// who is in?
|
|
if (want1up) {
|
|
area.x = 10;
|
|
area.y = (SCREENH/2) - (p1ready->h/2);
|
|
|
|
area.y += (sin(bouncetimer * (M_PI/180)) * 20);
|
|
|
|
SDL_BlitSurface(swapplayers ? p1readyalt : p1ready, NULL, screen, &area);
|
|
}
|
|
if (want2up) {
|
|
area.x = SCREENW - p2ready->w - 10;
|
|
area.y = (SCREENH/2) - (p2ready->h/2);
|
|
|
|
area.y -= (sin(bouncetimer * (M_PI/180)) * 20);
|
|
|
|
SDL_BlitSurface(swapplayers ? p2readyalt : p2ready, NULL, screen, &area);
|
|
}
|
|
|
|
|
|
// "select mode"
|
|
area.x = 320 - (text2->w/2)+2;
|
|
area.y = 240 - (text2->h*3)+2;
|
|
SDL_SetColors(text2, &black, 1, 1);
|
|
SDL_BlitSurface(text2, NULL, screen, &area);
|
|
|
|
area.x -=2 ; area.y -= 2;
|
|
SDL_SetColors(text2, &red, 1, 1);
|
|
SDL_BlitSurface(text2, NULL, screen, &area);
|
|
|
|
// "easy"
|
|
area.x = 320 - (easy->w/2)+2;
|
|
area.y = 240 - (easy->h)+2;
|
|
SDL_SetColors(easy, &black, 1, 1);
|
|
SDL_BlitSurface(easy, NULL, screen, &area);
|
|
|
|
area.x -= 2; area.y -= 2;
|
|
if ((gamemode == GM_NORM) || (texton)) { // easy not blinking
|
|
// normal
|
|
SDL_SetColors(easy, &red2, 1, 1);
|
|
} else {
|
|
// white
|
|
SDL_SetColors(easy, &white, 1, 1);
|
|
}
|
|
SDL_BlitSurface(easy, NULL, screen, &area);
|
|
|
|
// "normal"
|
|
area.x = 320 - (norm->w/2)+2;
|
|
area.y = 240 +2;
|
|
SDL_SetColors(norm, &black, 1, 1);
|
|
SDL_BlitSurface(norm, NULL, screen, &area);
|
|
|
|
area.x -= 2; area.y -= 2;
|
|
if ((gamemode == GM_EASY) || (texton)) { // easy not blinking
|
|
// normal
|
|
SDL_SetColors(norm, &red2, 1, 1);
|
|
} else {
|
|
// white
|
|
SDL_SetColors(norm, &white, 1, 1);
|
|
}
|
|
SDL_BlitSurface(norm, NULL, screen, &area);
|
|
|
|
// help on/off
|
|
area.x = 320 - 100 +2;
|
|
area.y = SCREENH - 50 +2;
|
|
SDL_SetColors(help, &black, 1, 1);
|
|
SDL_BlitSurface(help, NULL, screen, &area);
|
|
|
|
area.x -= 2; area.y -= 2;
|
|
SDL_SetColors(help, &red, 1, 1);
|
|
SDL_BlitSurface(help, NULL, screen, &area);
|
|
|
|
// "on"
|
|
area.x += (help->w+10)+2;
|
|
area.y = SCREENH - 50 +2;
|
|
SDL_SetColors(helpon, &black, 1, 1);
|
|
SDL_BlitSurface(helpon, NULL, screen, &area);
|
|
|
|
area.x -= 2; area.y -= 2;
|
|
if ((showhelp == B_FALSE) || (texton)) { // on not blinking
|
|
// normal
|
|
SDL_SetColors(helpon, &red2, 1, 1);
|
|
} else {
|
|
// white
|
|
SDL_SetColors(helpon, &white, 1, 1);
|
|
}
|
|
SDL_BlitSurface(helpon, NULL, screen, &area);
|
|
|
|
// "off"
|
|
area.x += (helpon->w+10)+2;
|
|
area.y = SCREENH - 50 +2;
|
|
SDL_SetColors(helpoff, &black, 1, 1);
|
|
SDL_BlitSurface(helpoff, NULL, screen, &area);
|
|
|
|
area.x -= 2; area.y -= 2;
|
|
if ((showhelp == B_TRUE) || (texton)) { // off not blinking
|
|
// normal
|
|
SDL_SetColors(helpoff, &red2, 1, 1);
|
|
} else {
|
|
// white
|
|
SDL_SetColors(helpoff, &white, 1, 1);
|
|
}
|
|
SDL_BlitSurface(helpoff, NULL, screen, &area);
|
|
|
|
// level description
|
|
if (gamemode == GM_EASY) {
|
|
int x,y;
|
|
int startx,starty;
|
|
|
|
desc = TTF_RenderText_Solid(font[TEXTSIZE_TITLE2], "Permenant armour and extra time", black);
|
|
startx = 320 - (desc->w/2);
|
|
starty = 240 + (desc->h)*2;
|
|
for (x = startx-1 ; x <= startx+1; x++) {
|
|
for (y = starty-1 ; y <= starty+1; y++) {
|
|
area.x = x; area.y = y;
|
|
SDL_BlitSurface(desc, NULL, screen, &area);
|
|
}
|
|
}
|
|
|
|
area.x = startx;
|
|
area.y = starty;
|
|
SDL_SetColors(desc, &green, 1, 1);
|
|
SDL_BlitSurface(desc, NULL, screen, &area);
|
|
SDL_FreeSurface(desc);
|
|
}
|
|
} else if (titlemode == TS_HISCORES) {
|
|
drawhiscores();
|
|
} else if (titlemode == TS_CREDITS) {
|
|
drawgamecredits();
|
|
}
|
|
|
|
bouncetimer += 7;
|
|
if (bouncetimer >= 360) {
|
|
bouncetimer = 0;
|
|
}
|
|
|
|
// draw text
|
|
drawcredits();
|
|
|
|
SDL_framerateDelay(&manager);
|
|
flip(B_TRUE);
|
|
|
|
hticks = SDL_GetTicks();
|
|
if (htstart == 0) {
|
|
htstart = hticks;
|
|
} else {
|
|
/* once per second */
|
|
if (hticks - htstart >= 1000) {
|
|
htime++;
|
|
htstart = hticks;
|
|
|
|
if ((htime > 0) && (htime % TTIME == 0)) {
|
|
if (titlemode == TS_INSERTCOIN) {
|
|
// INSERTCOIN -> NORMAL HISCORES
|
|
titlemode = TS_HISCORES;
|
|
if (wanthiscores) gethiscores(easymode());
|
|
} else if (titlemode == TS_HISCORES) {
|
|
// next time, get other hiscores
|
|
if (gamemode == GM_EASY) gamemode = GM_NORM;
|
|
else gamemode = GM_EASY;
|
|
// NORMAL HISCORES -> INSERTCOIN
|
|
titlemode = TS_CREDITS;
|
|
} else if (titlemode == TS_CREDITS) {
|
|
titlemode = TS_INSERTCOIN;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
// clear screen to black
|
|
//SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
|
|
|
|
// free temp surfaces
|
|
SDL_FreeSurface(cointext );
|
|
SDL_FreeSurface(ver );
|
|
SDL_FreeSurface(text );
|
|
SDL_FreeSurface(text2 );
|
|
SDL_FreeSurface(easy );
|
|
SDL_FreeSurface(norm );
|
|
SDL_FreeSurface(help );
|
|
SDL_FreeSurface(helpon );
|
|
SDL_FreeSurface(helpoff );
|
|
SDL_FreeSurface(titlebg );
|
|
SDL_FreeSurface(p1ready);
|
|
SDL_FreeSurface(p2ready);
|
|
}
|
|
|
|
void startgame(void) {
|
|
int i;
|
|
|
|
// initial variables
|
|
curlevelnum = 1;
|
|
musicplaying = B_FALSE;
|
|
levelcompletetime = -1;
|
|
oldlevelcomplete = -1;
|
|
pokereffect = -1;
|
|
pokerpoints = 0;
|
|
skiplevels = 0;
|
|
|
|
gothiscore = -1;
|
|
gothiscore2 = -1;
|
|
|
|
forcegold = B_FALSE;
|
|
forcegoldlev = -1;
|
|
|
|
endgame = B_FALSE;
|
|
|
|
curfruittype = 0;
|
|
curpoweruptype[0] = 0;
|
|
curpoweruptype[1] = 0;
|
|
|
|
fpsticks = 0;
|
|
fpsstart = 0;
|
|
|
|
numregrow = 0;
|
|
|
|
// init player variables - if player
|
|
// hasn't been allocated yet then this will
|
|
// be done so in loadlevel(), and the below
|
|
// settings done in addsprite()
|
|
if (player) {
|
|
int c;
|
|
player->permspeed = B_FALSE;
|
|
player->permbignet = B_FALSE;
|
|
player->permnumnets = B_FALSE;
|
|
player->permmask = B_FALSE;
|
|
player->permarmour = B_FALSE;
|
|
player->permsticky = B_FALSE;
|
|
setdefaults(player);
|
|
player->numcards = 0;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
player->card[c] = -1;
|
|
player->usedcard[c] = 0;
|
|
}
|
|
}
|
|
if (player2) {
|
|
int c;
|
|
player2->permspeed = B_FALSE;
|
|
player2->permbignet = B_FALSE;
|
|
player2->permnumnets = B_FALSE;
|
|
player2->permmask = B_FALSE;
|
|
player2->permarmour = B_FALSE;
|
|
player2->permsticky = B_FALSE;
|
|
setdefaults(player2);
|
|
player2->numcards = 0;
|
|
for (c = 0; c < MAXCARDS; c++) {
|
|
player2->card[c] = -1;
|
|
player2->usedcard[c] = 0;
|
|
}
|
|
}
|
|
|
|
// is we're skipping to a level, do so now
|
|
if (skipto >= 0) {
|
|
for (i = 0; i < numlevels; i++) {
|
|
if (levelentry[i].id == skipto) {
|
|
curlevelnum = i;
|
|
}
|
|
}
|
|
} else {
|
|
// special intro level
|
|
curlevelnum = INTRO_LEVELNUM;
|
|
}
|
|
|
|
// allocate player
|
|
if (want1up) {
|
|
if (player == NULL) {
|
|
player = addsprite(swapplayers ? P_PLAYER2 : P_PLAYER, 32, 450, "Player 1" );
|
|
setdefaults(player);
|
|
}
|
|
}
|
|
if (want2up) {
|
|
if (player2 == NULL) {
|
|
player2 = addsprite(swapplayers ? P_PLAYER : P_PLAYER2, 32, 450, "Player 2" );
|
|
setdefaults(player2);
|
|
}
|
|
}
|
|
|
|
|
|
// more initial variables
|
|
if (player) {
|
|
makeinvuln(player);
|
|
player->score = 0;
|
|
if (gamemode == GM_EASY) {
|
|
player->permarmour = B_TRUE;
|
|
player->armour = B_TRUE;
|
|
player->id = swapplayers ? P_ARMOUR2 : P_ARMOUR;
|
|
} else {
|
|
player->permarmour = B_FALSE;
|
|
player->armour = B_FALSE;
|
|
player->id = swapplayers ? P_PLAYER2 : P_PLAYER;
|
|
}
|
|
player->lives = INITPLAYERLIVES;
|
|
}
|
|
|
|
if (player2) {
|
|
makeinvuln(player2);
|
|
player2->score = 0;
|
|
if (gamemode == GM_EASY) {
|
|
player2->permarmour = B_TRUE;
|
|
player2->armour = B_TRUE;
|
|
player2->id = swapplayers ? P_ARMOUR : P_ARMOUR2;
|
|
} else {
|
|
player2->permarmour = B_FALSE;
|
|
player2->armour = B_FALSE;
|
|
player2->id = swapplayers ? P_PLAYER : P_PLAYER2;
|
|
}
|
|
player2->lives = INITPLAYERLIVES;
|
|
}
|
|
|
|
forcegoodcard = B_FALSE;
|
|
nextforcegoodcard = B_FALSE;
|
|
|
|
gameover = B_FALSE;
|
|
gameovertime = -1;
|
|
|
|
gtime = 0;
|
|
|
|
|
|
curlevelnum-- ; // since nextlevel() will increment it
|
|
|
|
// start intro
|
|
introstate = IS_START;
|
|
firstlevel = B_TRUE;
|
|
nextlevel();
|
|
firstlevel = B_FALSE;
|
|
|
|
flip(B_TRUE);
|
|
|
|
if (skipto == -1) {
|
|
playfx(FX_BIRDS);
|
|
}
|
|
|
|
// start timer
|
|
timer = 0;
|
|
}
|
|
|
|
|
|
void uncatch(sprite_t *s) {
|
|
if (s->caughtby) {
|
|
s->caughtby->netcaught--;
|
|
}
|
|
s->caughtby = NULL;
|
|
s->caughtstate = B_FALSE;
|
|
|
|
if (s->id == P_SPIDER) {
|
|
// climb up!
|
|
s->flies = B_TRUE;
|
|
s->falling = B_FALSE;
|
|
s->ys = -getspeed(s);
|
|
}
|
|
}
|
|
|
|
void makeinvuln(sprite_t *s) {
|
|
if (!s) return;
|
|
if (s->id == P_BLACKCLOUD) {
|
|
s->invuln = INVULNTIME/2;
|
|
} else {
|
|
s->invuln = INVULNTIME;
|
|
}
|
|
}
|
|
|
|
|
|
void setjoymappings(void) {
|
|
// ps3
|
|
joymap[4] = KEY_UP;
|
|
joymap[5] = KEY_RIGHT;
|
|
joymap[6] = KEY_DOWN;
|
|
joymap[7] = KEY_LEFT;
|
|
joymap[14] = KEY_JUMP; //x == jump
|
|
joymap[13] = KEY_SLAM; //circle = slam
|
|
joymap[12] = KEY_SHOOT; // square/triangle = shoot
|
|
joymap[15] = KEY_SHOOT;
|
|
// mame (directions are joystick)
|
|
joymap[0] = KEY_SHOOT;
|
|
joymap[1] = KEY_JUMP;
|
|
joymap[2] = KEY_SLAM;
|
|
joymap[3] = KEY_SLAM;
|
|
}
|
|
|
|
int joybuttontokey(int buttonnum) {
|
|
return joymap[buttonnum];
|
|
}
|
|
|
|
int joybuttondown(int whichplayer, int key) {
|
|
int i;
|
|
for (i = 0; i < joybuttons[whichplayer]; i++) {
|
|
if ((joymap[i] == key) && (joybut[whichplayer][i])) return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
/*
|
|
int keytojoybutton(int key) {
|
|
int i;
|
|
for (i = 0; i < joybuttons; i++) {
|
|
if (joymap[i] == key) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
*/
|
|
|
|
|
|
void handletitleinput(int whichplayer, int key) {
|
|
if (key == SDLK_ESCAPE) {
|
|
// quit
|
|
exit(0);
|
|
}
|
|
if ((titlemode == TS_INSERTCOIN) || (titlemode == TS_HISCORES)) {
|
|
if ((key == SDLK_5) || (key == SDLK_6) || (key == SDLK_RETURN)) {
|
|
addcredit();
|
|
titlemode = TS_WAIT1UP;
|
|
}
|
|
} else if (titlemode == TS_WAIT1UP) {
|
|
if ((key == SDLK_5) || (key == SDLK_6)) {
|
|
addcredit();
|
|
// if this was the first credit, default to normal mode
|
|
if (credits == 1) {
|
|
gamemode = GM_NORM;
|
|
}
|
|
} else if ((key == SDLK_1) || (key == SDLK_2) || (key == SDLK_RETURN)) {
|
|
int usecredit = B_FALSE;
|
|
if (credits > 0) {
|
|
if ((key == SDLK_1) || (key == SDLK_RETURN)) {
|
|
if (!want1up) {
|
|
// add player 1
|
|
want1up = B_TRUE;
|
|
usecredit = B_TRUE;
|
|
}
|
|
} else if (key == SDLK_2) {
|
|
if (!want2up) {
|
|
// add player 2
|
|
want2up = B_TRUE;
|
|
usecredit = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (usecredit) {
|
|
playfx(FX_EXTRALIFE);
|
|
credits--;
|
|
titlemode = TS_SELECTMODE;
|
|
blinkspeed = 5;
|
|
}
|
|
}
|
|
} else if (titlemode == TS_SELECTMODE) {
|
|
// pick current mode
|
|
if (key == KEY_UP) {
|
|
gamemode = GM_EASY;
|
|
} else if (key == KEY_DOWN) {
|
|
gamemode = GM_NORM;
|
|
} else if (key == KEY_LEFT) {
|
|
showhelp = B_TRUE;
|
|
} else if (key == KEY_RIGHT) {
|
|
showhelp = B_FALSE;
|
|
} else if ((key == KEY_SHOOT) || (key == SDLK_RETURN)) {
|
|
playfx(FX_KEYPRESS);
|
|
titledone = B_TRUE;
|
|
} else if ((key == SDLK_1) || (key == SDLK_2) || (key == SDLK_RETURN)) {
|
|
// another player joining
|
|
int usecredit = B_FALSE;
|
|
if ((key == SDLK_1) || (key == SDLK_RETURN)) {
|
|
if (want1up) {
|
|
// toggle players
|
|
if (swapplayers) swapplayers = B_FALSE;
|
|
else swapplayers = B_TRUE;
|
|
} else if (credits > 0) {
|
|
want1up = B_TRUE;
|
|
usecredit = B_TRUE;
|
|
}
|
|
} else if (key == SDLK_2) {
|
|
if (want2up) {
|
|
// toggle players
|
|
if (swapplayers) swapplayers = B_FALSE;
|
|
else swapplayers = B_TRUE;
|
|
} else {
|
|
want2up = B_TRUE;
|
|
usecredit = B_TRUE;
|
|
}
|
|
}
|
|
if (usecredit) {
|
|
playfx(FX_EXTRALIFE);
|
|
credits--;
|
|
}
|
|
} else if ((key == SDLK_5) || (key == SDLK_6)) {
|
|
addcredit();
|
|
}
|
|
}
|
|
}
|
|
|
|
void drawcredits(void) {
|
|
char tempst[BUFLEN];
|
|
SDL_Rect area;
|
|
// credits
|
|
if (credits == MAXCREDITS) {
|
|
sprintf(tempst, "Credits: MAX");
|
|
} else {
|
|
sprintf(tempst, "Credits: %d",credits);
|
|
}
|
|
credittext = TTF_RenderText_Solid(font[TEXTSIZE_CREDIT], tempst, black);
|
|
area.x = 320 - (credittext->w / 2) + 2;
|
|
area.y = SCREENH - 2 - (credittext->h)+2;
|
|
if (lockcredits) {
|
|
SDL_SetColors(credittext, &red2, 1, 1);
|
|
} else {
|
|
SDL_SetColors(credittext, &black, 1, 1);
|
|
}
|
|
SDL_BlitSurface(credittext, NULL, screen, &area);
|
|
area.x -= 2; area.y -= 2;
|
|
SDL_SetColors(credittext, &white, 1, 1);
|
|
SDL_BlitSurface(credittext, NULL, screen, &area);
|
|
|
|
SDL_FreeSurface(credittext);
|
|
}
|
|
|
|
int submithiscore(int score,int level, char *name) {
|
|
return submithiscore_local(score, level, name);
|
|
}
|
|
|
|
void drawgamecredits(void) {
|
|
int x,y,sx,sy;
|
|
int indent = 200;
|
|
|
|
// draw credits for game
|
|
sx = 110;
|
|
sy = 50;
|
|
x = sx;
|
|
y = sy;
|
|
|
|
// headings
|
|
drawoutlinecentretext(screen, y, TEXTSIZE_CREDITS, "Credits", &cyan, &blue);
|
|
y += (TEXTSIZE_CREDITS*2);
|
|
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Code:", &white, &grey2);
|
|
x += indent;
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Rob", &red, &red2);
|
|
x = sx;
|
|
y += TEXTSIZE_CREDITS;
|
|
y += (TEXTSIZE_CREDITS/2);
|
|
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Graphics:", &white, &grey2);
|
|
x += indent;
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Rob", &red, &red2);
|
|
x = sx;
|
|
y += TEXTSIZE_CREDITS;
|
|
y += (TEXTSIZE_CREDITS/2);
|
|
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Music:", &white, &grey2);
|
|
x += indent;
|
|
// ingame
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Deelite", &red, &red2);
|
|
y += TEXTSIZE_CREDITS;
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "fingal", &red, &red2);
|
|
y += TEXTSIZE_CREDITS;
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "x-ceed", &red, &red2);
|
|
y += TEXTSIZE_CREDITS;
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "MELOMANIAC/VTY", &red, &red2);
|
|
y += TEXTSIZE_CREDITS;
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "BeaT", &red, &red2);
|
|
y += TEXTSIZE_CREDITS;
|
|
|
|
// boss
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Teo / Fatal Rage", &red, &red2);
|
|
y += TEXTSIZE_CREDITS;
|
|
|
|
// hiscores
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Jess", &red, &red2);
|
|
y += TEXTSIZE_CREDITS;
|
|
|
|
y += (TEXTSIZE_CREDITS/2);
|
|
x = sx;
|
|
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Giant Cookie:", &white, &grey2);
|
|
x += indent;
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_CREDITS, "Karen", &red, &red2);
|
|
x = sx;
|
|
y += TEXTSIZE_CREDITS;
|
|
y += (TEXTSIZE_CREDITS/2);
|
|
}
|
|
|
|
|
|
int submithiscore_inet(int score,int level, char *name) {
|
|
struct sockaddr_in serveraddress;
|
|
struct hostent *server;
|
|
int rv;
|
|
int sock;
|
|
char buf[1500];
|
|
char newtext[BUFLEN];
|
|
char buf2[512];
|
|
char *p,*p2;
|
|
|
|
server = gethostbyname(hiscoreserver);
|
|
|
|
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sock < 0) {
|
|
printf("Error getting socket.\n");
|
|
return B_TRUE;
|
|
}
|
|
//bzero((char *) &serveraddress, sizeof(serveraddress));
|
|
memset(&serveraddress, 0, sizeof(serveraddress));
|
|
serveraddress.sin_family = AF_INET;
|
|
memcpy(&serveraddress.sin_addr.s_addr, server->h_addr,
|
|
server->h_length);
|
|
serveraddress.sin_port = htons(hiscoreport);
|
|
|
|
|
|
|
|
// replace spaces in name with %20s
|
|
p2 = newtext;
|
|
for (p = name ; *p != '\0'; p++) {
|
|
if (*p == ' ') {
|
|
*p2 = '%'; p2++;
|
|
*p2 = '2'; p2++;
|
|
*p2 = '0';
|
|
} else {
|
|
*p2 = *p;
|
|
}
|
|
p2++;
|
|
} *p2 = '\0';
|
|
|
|
// connect
|
|
if (connect(sock,(struct sockaddr *)&serveraddress,sizeof(serveraddress)) < 0) {
|
|
printf("Error connecting to hiscore server.\n");
|
|
return B_TRUE;
|
|
}
|
|
|
|
// send request
|
|
sprintf(buf2, "GET HTTP://ratcatcher.nethack.net/hiscores/submitscore.php?score=%d&name=%s&level=%d&easymode=%d HTTP/1.0\n\n", score,newtext,level,easymode());
|
|
write(sock,buf2,strlen(buf2));
|
|
|
|
// wait for data
|
|
rv = read(sock, buf, 1500);
|
|
while (rv > 0) {
|
|
rv = read(sock, buf, 1500);
|
|
}
|
|
|
|
close(sock);
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int submithiscore_local(int score,int level, char *name) {
|
|
int rv;
|
|
sqlite3 *db;
|
|
char *cmd,*errmsg = NULL;
|
|
char filename[BUFLEN];
|
|
|
|
if (easymode()) {
|
|
snprintf(filename, BUFLEN, "%s", "data/hiscores.easy.db");
|
|
} else {
|
|
snprintf(filename, BUFLEN, "%s", "data/hiscores.db");
|
|
}
|
|
rv = sqlite3_open(filename, &db);
|
|
if (rv) {
|
|
printf("can't open database file %s\n",filename);
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
// request hiscores
|
|
asprintf(&cmd, "insert into 'hiscores' (name,level,score) VALUES ('%s',%d,%d)",name,level,score);
|
|
|
|
rv = sqlite3_exec(db, cmd, processhiscore, NULL, &errmsg);
|
|
if (rv != SQLITE_OK) {
|
|
printf("* error writing hiscores: '%s'\n", errmsg);
|
|
printf("* query was: '%s'\n", cmd);
|
|
sqlite3_free(errmsg);
|
|
}
|
|
free(cmd);
|
|
sqlite3_close(db);
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int gethiscores(int easyscores) {
|
|
return gethiscores_local(easyscores);
|
|
}
|
|
|
|
int gethiscores_inet(int easyscores) {
|
|
struct sockaddr_in serveraddress;
|
|
struct hostent *server;
|
|
int rv;
|
|
int sock;
|
|
char buf[BUFLEN];
|
|
char buf2[512];
|
|
int state = 0;
|
|
int pos;
|
|
int finished;
|
|
|
|
server = gethostbyname(hiscoreserver);
|
|
if (!server) {
|
|
printf("can't resolve hiscore server name\n");
|
|
return B_TRUE;
|
|
}
|
|
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sock < 0) {
|
|
printf("Error getting socket.\n");
|
|
return B_TRUE;
|
|
}
|
|
//bzero((char *) &serveraddress, sizeof(serveraddress));
|
|
memset(&serveraddress, 0, sizeof(serveraddress));
|
|
serveraddress.sin_family = AF_INET;
|
|
memcpy(&serveraddress.sin_addr.s_addr, server->h_addr,
|
|
server->h_length);
|
|
serveraddress.sin_port = htons(hiscoreport);
|
|
|
|
|
|
// connect
|
|
if (connect(sock,(struct sockaddr *)&serveraddress,sizeof(serveraddress)) < 0) {
|
|
perror("connect");
|
|
printf("Error connecting to hiscore server.\n");
|
|
return B_TRUE;
|
|
}
|
|
|
|
// send request
|
|
if (easyscores) {
|
|
sprintf(buf2, "GET HTTP://ratcatcher.nethack.net/hiscores/hiscores_plain.php?easymode=1 HTTP/1.0\n\n");
|
|
} else {
|
|
sprintf(buf2, "GET HTTP://ratcatcher.nethack.net/hiscores/hiscores_plain.php HTTP/1.0\n\n");
|
|
}
|
|
write(sock,buf2,strlen(buf2));
|
|
|
|
|
|
pos = 0;
|
|
|
|
finished = B_FALSE;
|
|
|
|
// wait for data
|
|
//rv = read(sock, buf, 1500);
|
|
rv = socket_readline(sock, buf);
|
|
while ((rv > 0) && !finished) {
|
|
|
|
buf[rv] = '\0';
|
|
if (state == 0) { // header
|
|
char *p;
|
|
p = strstr(buf, "text/plain");
|
|
if (p) {
|
|
state = 1;
|
|
}
|
|
} else if (state == 1) { // waiting for start of data
|
|
if (strstr(buf, "start")) {
|
|
state = 2;
|
|
}
|
|
} else {
|
|
char *p;
|
|
// validate line
|
|
if (strstr(buf, "endofscores")) {
|
|
finished = B_TRUE;
|
|
} else if (strstr(buf, "^")) {
|
|
// process line
|
|
p = strtok(buf, "^");
|
|
hiscore[pos].score = atoi(p);
|
|
p = strtok(NULL, "^");
|
|
hiscore[pos].level = atoi(p);
|
|
p = strtok(NULL, "^");
|
|
sprintf(hiscore[pos].name,"%s", p);
|
|
pos++;
|
|
if (pos >= MAXHISCORES) {
|
|
// too many - cut it off here
|
|
finished = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//rv = read(sock, buf, 1500);
|
|
rv = socket_readline(sock, buf);
|
|
}
|
|
|
|
numhiscores = pos;
|
|
close(sock);
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int gethiscores_local(int easyscores) {
|
|
int rv;
|
|
sqlite3 *db;
|
|
char *cmd,*errmsg = NULL;
|
|
char filename[BUFLEN];
|
|
|
|
if (easyscores) {
|
|
snprintf(filename, BUFLEN, "%s", "data/hiscores.easy.db");
|
|
} else {
|
|
snprintf(filename, BUFLEN, "%s", "data/hiscores.db");
|
|
}
|
|
rv = sqlite3_open(filename, &db);
|
|
if (rv) {
|
|
printf("can't open database file %s\n",filename);
|
|
return B_TRUE;
|
|
}
|
|
|
|
|
|
// request hiscores
|
|
asprintf(&cmd, " select (select count(*) from hiscores b where b.score > a.score) + 1 as rank,name,level,score from hiscores a order by score desc limit 10");
|
|
|
|
numhiscores = 0;
|
|
|
|
rv = sqlite3_exec(db, cmd, processhiscore, NULL, &errmsg);
|
|
if (rv != SQLITE_OK) {
|
|
printf("* error reading hiscores: '%s'\n", errmsg);
|
|
printf("* query was: '%s'\n", cmd);
|
|
sqlite3_free(errmsg);
|
|
}
|
|
free(cmd);
|
|
sqlite3_close(db);
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
int processhiscore(void *dataptr, int ncols, char **argv, char **colname) {
|
|
int i, rank = -1;
|
|
for (i = 0; i < ncols; i++) {
|
|
if (!strcmp(colname[i], "rank")) {
|
|
rank = atoi(argv[i]) - 1;
|
|
break;
|
|
}
|
|
}
|
|
if (rank == -1) {
|
|
printf("error processing hiscore data - no rank round.\n");
|
|
exit(1);
|
|
}
|
|
|
|
for (i = 0; i < ncols; i++) {
|
|
if (!strcmp(colname[i], "score")) {
|
|
hiscore[rank].score = atoi(argv[i]);
|
|
} else if (!strcmp(colname[i], "level")) {
|
|
hiscore[rank].level = atoi(argv[i]);
|
|
} else if (!strcmp(colname[i], "name")) {
|
|
snprintf(hiscore[rank].name, MIDBUFLEN, "%s", argv[i]);
|
|
}
|
|
}
|
|
numhiscores++;
|
|
return B_FALSE;
|
|
}
|
|
|
|
void checkhiscores(sprite_t *who){
|
|
int finished = B_FALSE;
|
|
int i;
|
|
char srank[BUFLEN],sscore[BUFLEN],slevel[BUFLEN],sname[BUFLEN];
|
|
//char line[BUFLEN];
|
|
char commascore[BUFLEN];
|
|
int x,y,sx,sy;
|
|
char thisname[BUFLEN];
|
|
int timer = 0,keytimer = 0;
|
|
int capital = B_TRUE;
|
|
|
|
int curlet;
|
|
|
|
int pnum;
|
|
|
|
// player number (for key input)
|
|
if (who == player) {
|
|
pnum = 0;
|
|
} else {
|
|
pnum = 1;
|
|
}
|
|
|
|
|
|
// no hiscores if we are cheating!
|
|
if (cheat) {
|
|
return;
|
|
}
|
|
|
|
// contact server and read appropriate list
|
|
if (gethiscores(easymode())) {
|
|
printf("Cannot contact hiscore server!\n");
|
|
return;
|
|
}
|
|
|
|
// check if we are higher than any
|
|
if (who == player) {
|
|
gothiscore = -1;
|
|
for (i = 0; i < numhiscores; i++) {
|
|
if (who->score > hiscore[i].score) {
|
|
// we got a hi score
|
|
gothiscore = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
gothiscore2 = -1;
|
|
for (i = 0; i < numhiscores; i++) {
|
|
if (who->score > hiscore[i].score) {
|
|
// we got a hi score
|
|
gothiscore2 = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ((who == player) && (gothiscore == -1)) return; // didn't get a hiscore
|
|
if ((who == player2) && (gothiscore2 == -1)) return; // didn't get a hiscore
|
|
|
|
// play hiscore music
|
|
//stopmusic();
|
|
playmusic(hiscoremusic);
|
|
|
|
// prompt user for a name
|
|
|
|
curlet = 'a';
|
|
strcpy(thisname, "");
|
|
while (!finished) {
|
|
SDL_Color *fg, *bg;
|
|
SDL_Event event;
|
|
char let[2];
|
|
|
|
// clear
|
|
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format,black.r,black.g,black.b));
|
|
|
|
//draw hiscore heading
|
|
sx = 110;
|
|
sy = 100;
|
|
x = sx;
|
|
y = sy;
|
|
|
|
// headings
|
|
if (who == player) {
|
|
drawoutlinecentretext(screen, 50, TEXTSIZE_HISCORE, "1UP - New high score!", &white, &grey2);
|
|
} else {
|
|
drawoutlinecentretext(screen, 50, TEXTSIZE_HISCORE, "2UP - New high score!", &white, &grey2);
|
|
}
|
|
|
|
// print rank
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Rank", &cyan, &blue);
|
|
x += 70;
|
|
// print score
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Score", &cyan, &blue);
|
|
x += 150;
|
|
// print level
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Level", &cyan, &blue);
|
|
x += 90;
|
|
// print name
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Name", &cyan, &blue);
|
|
|
|
y += (TEXTSIZE_HISCORE*2);
|
|
x = sx;
|
|
|
|
// player's score...
|
|
|
|
// generate hiscore lines
|
|
sprintf(srank, "%-2d.",((who == player) ? gothiscore : gothiscore2)+1);
|
|
addcommas(commascore, who->score );
|
|
sprintf(sscore, "%-14s",commascore);
|
|
sprintf(slevel, "%1d-%-2d",getworld(curlevelnum),getlevel(curlevelnum));
|
|
if (strlen(thisname) > 0) {
|
|
sprintf(sname, "%-32s",thisname);
|
|
}
|
|
|
|
fg = &white;
|
|
bg = &grey2;
|
|
|
|
// print rank
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, srank, fg, bg);
|
|
x += 70;
|
|
// print score
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, sscore, fg, bg);
|
|
x += 150;
|
|
// print level
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, slevel, fg, bg);
|
|
x += 90;
|
|
// print name
|
|
if (strlen(thisname) > 0) {
|
|
int wid;
|
|
wid = drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, thisname, fg, bg);
|
|
x += (wid + 2);
|
|
}
|
|
|
|
// print cursor
|
|
if (curlet == '*') {
|
|
if (((timer / 5) % 2) == 0) {
|
|
drawoutlinetext(screen, x, y+3, TEXTSIZE_HISCORE/2, "END", &white, &grey2);
|
|
} else {
|
|
drawoutlinetext(screen, x, y+3, TEXTSIZE_HISCORE/2, "END", &red, &red2);
|
|
}
|
|
} else {
|
|
sprintf(let, "%c",capital ? toupper(curlet) : curlet );
|
|
if (((timer / 5) % 2) == 0) {
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, let, &white, &grey2);
|
|
} else {
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, let, &red, &red2);
|
|
}
|
|
}
|
|
|
|
if (++timer == 100) {
|
|
timer = 0;
|
|
}
|
|
|
|
|
|
getinput();
|
|
|
|
if (keytimer == 0) {
|
|
// check for scrolling
|
|
if (keydown(pnum, KEY_UP) || keydown(pnum, KEY_LEFT)) { // scroll through letters
|
|
if (curlet == 'a') curlet = '*';
|
|
else if (curlet == '*') curlet = ' ';
|
|
else if (curlet == ' ') curlet = 'z';
|
|
else curlet--;
|
|
keytimer = 5;
|
|
} else if (keydown(pnum, KEY_DOWN) || keydown(pnum, KEY_RIGHT)) { // scroll through letters
|
|
if (curlet == 'z') curlet = ' ';
|
|
else if (curlet == ' ') curlet = '*';
|
|
else if (curlet == '*') curlet = 'a';
|
|
else curlet++;
|
|
keytimer = 5;
|
|
}
|
|
} else {
|
|
keytimer--;
|
|
}
|
|
if (strlen(thisname) >= MAXHISCORENAME) {
|
|
// have to END now
|
|
curlet='*';
|
|
}
|
|
|
|
|
|
// wait for a key...
|
|
if (SDL_PollEvent(&event)) {
|
|
int key = -1;
|
|
switch (event.type) {
|
|
case SDL_KEYUP:
|
|
key = event.key.keysym.sym;
|
|
// make sure it's the correct player
|
|
if (who == player ){
|
|
switch (key) {
|
|
case SDLK_s:
|
|
case SDLK_d:
|
|
case SDLK_f:
|
|
case SDLK_6:
|
|
case SDLK_2:
|
|
key = -1;
|
|
}
|
|
} else {
|
|
switch (key) {
|
|
case KEY_SHOOT:
|
|
case KEY_JUMP:
|
|
case KEY_SLAM:
|
|
case SDLK_5:
|
|
case SDLK_1:
|
|
key = -1;
|
|
}
|
|
}
|
|
break;
|
|
case SDL_JOYBUTTONUP:
|
|
if (event.jbutton.which == pnum) {
|
|
key = joybuttontokey(event.jbutton.button);
|
|
} else {
|
|
key = -1;
|
|
}
|
|
break;
|
|
|
|
}
|
|
if ((event.type == SDL_KEYUP) || (event.type == SDL_JOYBUTTONUP)) {
|
|
if (key != -1) {
|
|
if (key == SDLK_ESCAPE) {
|
|
// quit
|
|
exit(0);
|
|
} else if ((key == SDLK_RETURN) || (key == SDLK_5) || (key == SDLK_6)) {
|
|
if (strlen(thisname) > 0) {
|
|
playfx(FX_KEYPRESS);
|
|
finished = B_TRUE;
|
|
}
|
|
} else if ((key == SDLK_BACKSPACE) || (key == KEY_JUMP) || (key == SDLK_d)) {
|
|
thisname[strlen(thisname)-1] = '\0';
|
|
if (strlen(thisname) == 0) {
|
|
capital = B_TRUE;
|
|
} else if (thisname[strlen(thisname)-1] == ' ') {
|
|
capital = B_TRUE;
|
|
}
|
|
} else if ((key == KEY_SHOOT) || (key == SDLK_s)) {
|
|
// add current letter or finish if it is on "end"
|
|
if (curlet == '*') {
|
|
if (strlen(thisname) > 0) {
|
|
playfx(FX_KEYPRESS);
|
|
finished = B_TRUE;
|
|
}
|
|
} else {
|
|
// capital
|
|
let[0] = capital ? toupper(curlet) : curlet;
|
|
let[1] = '\0';
|
|
strcat(thisname, let);
|
|
// don't let name get too long
|
|
playfx(FX_POWERUP);
|
|
if (curlet == ' ') {
|
|
// next letter is a capital
|
|
capital = B_TRUE;
|
|
} else {
|
|
capital = B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!paused) SDL_framerateDelay(&manager);
|
|
flip(B_TRUE);
|
|
}
|
|
|
|
|
|
|
|
// submit the hiscore
|
|
if (submithiscore(who->score, curlevelnum, thisname)) {
|
|
printf("failed to submit hiscore.\n");
|
|
} else {
|
|
// downlaod the hiscores again
|
|
gethiscores(easymode());
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
void showhiscores(void){
|
|
int finished = B_FALSE;
|
|
//char line[BUFLEN];
|
|
int htstart = 0, htime = 0,hticks;
|
|
|
|
|
|
// contact server and read list
|
|
/*
|
|
if (gethiscores()) {
|
|
printf("Cannot contact hiscore server!\n");
|
|
return;
|
|
}
|
|
*/
|
|
/*
|
|
hiscore[0].score = 55000;
|
|
hiscore[0].level = 24;
|
|
sprintf(hiscore[0].name, "King Rat");
|
|
hiscore[1].score = 1000;
|
|
hiscore[1].level = 5;
|
|
sprintf(hiscore[1].name, "Queen Rat");
|
|
|
|
numscores = 2;
|
|
*/
|
|
|
|
// display list on screen and wait for key
|
|
|
|
while (!finished) {
|
|
SDL_Event event;
|
|
|
|
drawhiscores();
|
|
|
|
// check for a key...
|
|
if (SDL_PollEvent(&event)) {
|
|
int key = -1;
|
|
switch (event.type) {
|
|
case SDL_KEYUP:
|
|
key = event.key.keysym.sym;
|
|
break;
|
|
case SDL_JOYBUTTONUP:
|
|
key = joybuttontokey(event.jbutton.button);
|
|
break;
|
|
|
|
}
|
|
if (key != -1) {
|
|
if (key == SDLK_ESCAPE) {
|
|
// quit
|
|
exit(0);
|
|
} else if ((key == SDLK_1) || (key == SDLK_2)) {
|
|
// 1up buttons
|
|
finished = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
flip(B_TRUE);
|
|
|
|
hticks = SDL_GetTicks();
|
|
if (htstart == 0) {
|
|
htstart = hticks;
|
|
} else {
|
|
/* once per second */
|
|
if (hticks - htstart >= 1000) {
|
|
htime++;
|
|
htstart = hticks;
|
|
}
|
|
|
|
if (htime >= HISCORE_DISPLAYTIME) {
|
|
finished = B_TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
// stop music ready for title screen again (it will only be playing if
|
|
// we got a hiscore)
|
|
stopmusic();
|
|
}
|
|
|
|
int socket_readline(int sock, char* out) {
|
|
/* current location in buffer */
|
|
int i = 0;
|
|
/* whether the previous char was a \r */
|
|
int cr = 0;
|
|
char ch;
|
|
|
|
/* result, grows as we need it to */
|
|
//out = malloc(sizeof(char) * size);
|
|
|
|
for ( ; ; ) {
|
|
if (recv(sock, &ch, 1, 0) == -1) {
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
if (i >= size) {
|
|
// grow buffer
|
|
size *= 2;
|
|
out = realloc(out, size);
|
|
}
|
|
*/
|
|
|
|
if (ch == '\n') {
|
|
/* if preceded by a \r, we overwrite it */
|
|
if (cr) {
|
|
i--;
|
|
}
|
|
|
|
out[i] = '\0';
|
|
break;
|
|
|
|
} else {
|
|
cr = (ch == '\r' ? 1 : 0);
|
|
out[i] = ch;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
return i + 1;
|
|
}
|
|
|
|
|
|
void drawhiscores(void) {
|
|
char srank[BUFLEN],sscore[BUFLEN],slevel[BUFLEN],sname[BUFLEN];
|
|
char commascore[BUFLEN];
|
|
int x,y,sx,sy;
|
|
int i;
|
|
|
|
//draw hiscore list
|
|
sx = 110;
|
|
sy = 100;
|
|
x = sx;
|
|
y = sy;
|
|
|
|
// headings
|
|
if (easymode()) {
|
|
drawoutlinecentretext(screen, 50, TEXTSIZE_HISCORE, "High Scores - Easy", &cyan, &blue);
|
|
} else {
|
|
drawoutlinecentretext(screen, 50, TEXTSIZE_HISCORE, "High Scores - Normal", &cyan, &blue);
|
|
}
|
|
|
|
|
|
if (numhiscores <= 0) {
|
|
// print rank
|
|
y += (TEXTSIZE_HISCORE*4);
|
|
drawoutlinecentretext(screen, y, TEXTSIZE_HISCORE, "High score server unavailable", &red, &red3);
|
|
} else {
|
|
// print rank
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Rank", &cyan, &blue);
|
|
x += 70;
|
|
// print score
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Score", &cyan, &blue);
|
|
x += 150;
|
|
// print level
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Level", &cyan, &blue);
|
|
x += 90;
|
|
// print name
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, "Name", &cyan, &blue);
|
|
|
|
y += (TEXTSIZE_HISCORE*2);
|
|
x = sx;
|
|
|
|
for (i = 0; i < numhiscores; i++) {
|
|
SDL_Color *fg, *bg;
|
|
// generate hiscore lines
|
|
sprintf(srank, "%-2d.",i+1);
|
|
addcommas(commascore, hiscore[i].score);
|
|
sprintf(sscore, "%-14s",commascore);
|
|
sprintf(slevel, "%1d-%-2d",getworld(hiscore[i].level),getlevel(hiscore[i].level));
|
|
sprintf(sname, "%-32s",hiscore[i].name);
|
|
|
|
if ((gothiscore != -1) && (i == gothiscore)) {
|
|
fg = &white;
|
|
bg = &grey2;
|
|
} else if ((gothiscore2 != -1) && (i == gothiscore2)) {
|
|
fg = &white;
|
|
bg = &grey2;
|
|
} else {
|
|
fg = &red;
|
|
bg = &red3;
|
|
}
|
|
|
|
// print rank
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, srank, fg, bg);
|
|
x += 70;
|
|
// print score
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, sscore, fg, bg);
|
|
x += 150;
|
|
// print level
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, slevel, fg, bg);
|
|
x += 90;
|
|
// print name
|
|
drawoutlinetext(screen, x, y, TEXTSIZE_HISCORE, sname, fg, bg);
|
|
|
|
// go to next line
|
|
x = sx;
|
|
y += (TEXTSIZE_HISCORE+2);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// read keyboard info
|
|
void getinput(void) {
|
|
int i,j;
|
|
keys = SDL_GetKeyState(NULL);
|
|
|
|
if (havejoysticks) {
|
|
for (j = 0; j < 2; j++) {
|
|
joyx[j] = SDL_JoystickGetAxis(joy[j],0);
|
|
joyy[j] = SDL_JoystickGetAxis(joy[j],1);
|
|
for (i = 0; i < joybuttons[j]; i++) {
|
|
joybut[j][i] = SDL_JoystickGetButton(joy[j],i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int isendoflev(void) {
|
|
if (levelcomplete == LV_CLEAR) return B_TRUE;
|
|
if (levelcomplete == LV_WAIT) return B_TRUE;
|
|
if (levelcomplete == LV_FINAL) return B_TRUE;
|
|
if (levelcomplete == LV_CLOUD) return B_TRUE;
|
|
if (levelcomplete == LV_CLOUDLOOP) return B_TRUE;
|
|
if (levelcomplete == LV_NEXTLEV) return B_TRUE;
|
|
return B_FALSE;
|
|
}
|
|
|
|
void keeponscreen(sprite_t *s) {
|
|
if (s->x >= (SCREENW-(s->img->w/2))) {
|
|
s->x = SCREENW - (s->img->w/2)-1;
|
|
}
|
|
if (s->x <= s->img->w/2) {
|
|
s->x = (s->img->w/2)+1;
|
|
}
|
|
if (s->y <= s->img->h) {
|
|
s->y = s->img->h+1;
|
|
}
|
|
if (s->y >= SCREENH) {
|
|
s->y = SCREENH - 1;
|
|
}
|
|
}
|
|
|
|
void stopteleporting(sprite_t *s) {
|
|
if (s->teleporting) {
|
|
if (s->allocimg) {
|
|
SDL_FreeSurface(s->img);
|
|
s->img = NULL;
|
|
}
|
|
s->allocimg = B_FALSE;
|
|
s->teleporting = 0;
|
|
s->img = imageset[s->id].img[F_WALK1];
|
|
}
|
|
}
|
|
|
|
|
|
void disablepowerups(int pid) {
|
|
if (haspowerup(player, pid)) {
|
|
losepowerup(player);
|
|
}
|
|
if (haspowerup(player2, pid)) {
|
|
losepowerup(player2);
|
|
}
|
|
}
|
|
void losepowerup(sprite_t *s) {
|
|
if (s->powerup == PW_GUNNER) {
|
|
// go back to original position
|
|
if (s == player) {
|
|
s->x = gunorigx[0];
|
|
s->y = gunorigy[0];
|
|
} else if (s == player2) {
|
|
s->x = gunorigx[1];
|
|
s->y = gunorigy[1];
|
|
}
|
|
// invulnerable for a little while
|
|
s->invuln = INVULNTIME/2;
|
|
}
|
|
s->powerup = B_FALSE;
|
|
|
|
}
|
|
|
|
int easymode(void) {
|
|
if (gamemode == GM_EASY) return B_TRUE;
|
|
|
|
return B_FALSE;
|
|
}
|
|
|
|
double getdistance(double x1, double y1, double x2, double y2) {
|
|
double xdis,ydis;
|
|
xdis = abs(x1 - x2);
|
|
ydis = abs(y1 - y2);
|
|
if ((xdis == 0) && (ydis == 0)) {
|
|
return 0;
|
|
} else return sqrt((xdis*xdis) + (ydis*ydis));
|
|
}
|
|
|
|
|
|
|
|
void doplayermovement(sprite_t *pl) {
|
|
int pnum;
|
|
|
|
if (pl == player) {
|
|
pnum = 0;
|
|
} else if (pl == player2) {
|
|
pnum = 1;
|
|
} else return; // only valid for players
|
|
|
|
if (!pl) return;
|
|
|
|
if (pl->caughtby) return;
|
|
|
|
|
|
if (pl->powerup == PW_GUNNER) {
|
|
// move crosshairs
|
|
if (keydown(pnum,KEY_RIGHT)) {
|
|
if (pl->x < SCREENW-(TILEW/2)) {
|
|
pl->x += GUNNERSPEED;
|
|
}
|
|
}
|
|
if (keydown(pnum,KEY_LEFT)) {
|
|
if (pl->x > (TILEW/2)) {
|
|
pl->x -= GUNNERSPEED;
|
|
}
|
|
}
|
|
if (keydown(pnum,KEY_DOWN)) {
|
|
if (pl->y < SCREENH-(TILEH/2)) {
|
|
pl->y += GUNNERSPEED;
|
|
}
|
|
}
|
|
if (keydown(pnum,KEY_UP)) {
|
|
if (pl->y > (TILEH/2)) {
|
|
pl->y -= GUNNERSPEED;
|
|
}
|
|
}
|
|
if (keydown(pnum,KEY_SHOOT)) {
|
|
// shoot - add explosion
|
|
if (gundelay[pnum] == 0) {
|
|
playfx(FX_GUN);
|
|
addsprite(P_SMASH, pl->x, pl->y+(TILEH/2), "gunexplosion");
|
|
gundelay[pnum] = GUNNERDELAY;
|
|
}
|
|
}
|
|
} else {
|
|
if ((!pl->dead) && (!pl->teleporting)) {
|
|
int moveok = B_FALSE;
|
|
if (pl->climbing) {
|
|
tiletype_t *tt;
|
|
// can only move left/right if we're at the bottom of a ladder
|
|
tt = gettileat(pl->x,pl->y, NULL,NULL);
|
|
if (tt->solid) {
|
|
moveok = B_TRUE;
|
|
}
|
|
tt = gettileat(pl->x,pl->y+TILEH, NULL,NULL);
|
|
if (tt->solid ) {
|
|
moveok = B_TRUE;
|
|
}
|
|
} else moveok = B_TRUE;
|
|
|
|
if (moveok) {
|
|
if (keydown(pnum,KEY_RIGHT)) {
|
|
if (canmove(pl)) {
|
|
movex(pl, getspeed(pl), B_TRUE);
|
|
}
|
|
if (canturn(pl)) {
|
|
pl->dir = D_RIGHT;
|
|
}
|
|
} else if (keydown(pnum,KEY_LEFT)) {
|
|
if (canmove(pl)) {
|
|
movex(pl, -getspeed(pl), B_TRUE);
|
|
}
|
|
if (canturn(pl)) {
|
|
pl->dir = D_LEFT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (keydown(pnum,KEY_UP)) {
|
|
if (endgame) {
|
|
int spd;
|
|
spd = getspeed(pl)/2;
|
|
if (spd < 1) spd = 1;
|
|
// drift upwards
|
|
if (!isroofabove(pl)) pl->y -= spd;
|
|
pl->moved = MV_FLY;
|
|
} else if ((pl->swimming) && (pl->hasmask)) {
|
|
// swimming
|
|
swimup(pl);
|
|
} else if (!pl->netting && !pl->slamming && !pl->jumping) {
|
|
// climbing
|
|
if (pl->climbing) {
|
|
int ladderx = isladderabove(pl);
|
|
// if tile above is non-solid, or a ladder
|
|
if (ladderx || !isroofabove(pl)) {
|
|
// lock to ladder
|
|
if (ladderx) {
|
|
pl->x = ladderx; // lock to ladder
|
|
}
|
|
// continue climbing
|
|
pl->y -= getspeed(pl);
|
|
pl->jumping = 0;
|
|
pl->falling = 0;
|
|
pl->climbing = B_TRUE;
|
|
pl->moved = MV_WALK;
|
|
}
|
|
} else {// not climbing
|
|
int ladderx = isladderabove(pl);
|
|
if (ladderx) {
|
|
pl->x = ladderx; // lock to ladder
|
|
// start climbing
|
|
pl->y -= getspeed(pl);
|
|
pl->jumping = 0;
|
|
pl->falling = 0;
|
|
pl->climbing = B_TRUE;
|
|
pl->moved = MV_WALK;
|
|
}
|
|
|
|
}
|
|
}
|
|
if (pl->umbrella) pl->umbrellaup = B_TRUE;
|
|
|
|
} else {
|
|
if (pl->umbrella) pl->umbrellaup = B_FALSE;
|
|
}
|
|
if (keydown(pnum,KEY_DOWN)) {
|
|
if (endgame) {
|
|
int spd;
|
|
spd = getspeed(pl)/2;
|
|
if (spd < 1) spd = 1;
|
|
// drift downwards
|
|
if (pl->y < SCREENH-spd) pl->y += spd;
|
|
pl->moved = MV_FLY;
|
|
} else if ((pl->swimming) && (pl->hasmask)) {
|
|
// swimming
|
|
swimdown(pl);
|
|
} else if (!pl->netting && !pl->slamming && !pl->jumping) {
|
|
int ladderx = isonladder(pl);
|
|
if (ladderx) {
|
|
pl->y += getspeed(pl);
|
|
pl->jumping = 0;
|
|
pl->falling = 0;
|
|
pl->climbing = B_TRUE;
|
|
pl->moved = MV_WALK;
|
|
// lock player to centre of ladder
|
|
pl->x = ladderx;
|
|
}
|
|
}
|
|
}
|
|
// Jump
|
|
if (keydown(pnum,KEY_JUMP)) {
|
|
trytojump(pl);
|
|
} else {
|
|
if (pl->jumping && pl->doublejump) {
|
|
// have to let go of jump button to double jump
|
|
if (!pl->doublejumpready) {
|
|
pl->doublejumpready = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// Shoot
|
|
if (keydown(pnum,KEY_SHOOT)) {
|
|
if (!havejoysticks && keydown(pnum,KEY_DOWN)) {
|
|
trytoslam(pl);
|
|
} else if (havejoysticks && (joytype[pnum] == J_WII) && keydown(pnum, KEY_DOWN)) {
|
|
trytoslam(pl);
|
|
} else {
|
|
trytoshoot(pl);
|
|
}
|
|
}
|
|
|
|
// Slam
|
|
if (keydown(pnum,KEY_SLAM)) {
|
|
trytoslam(pl);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
sprite_t *getclosestplayer(sprite_t *s) {
|
|
double xdiff1,xdiff2,ydiff1,ydiff2,diff1,diff2;
|
|
sprite_t *closest = NULL;
|
|
// closest player
|
|
if (player && !player->dead) {
|
|
xdiff1 = abs(player->x - s->x);
|
|
ydiff1 = abs(player->y - s->y);
|
|
diff1 = xdiff1 + ydiff1;
|
|
closest = player;
|
|
} else {
|
|
diff1 = 9999;
|
|
}
|
|
|
|
if (player2 && !player2->dead) {
|
|
xdiff2 = abs(player2->x - s->x);
|
|
ydiff2 = abs(player2->y - s->y);
|
|
diff2 = xdiff2 + ydiff2;
|
|
if (closest == NULL) closest = player2;
|
|
else if (closest == player) {
|
|
if (diff2 > diff1) closest = player2;
|
|
}
|
|
}
|
|
return closest;
|
|
}
|
|
|
|
sprite_t *getclosestplayerxy(int x, int y) {
|
|
double xdiff1,xdiff2,ydiff1,ydiff2,diff1,diff2;
|
|
sprite_t *closest = NULL;
|
|
// closest player
|
|
if (player && !player->dead) {
|
|
xdiff1 = abs(player->x - x);
|
|
ydiff1 = abs(player->y - y);
|
|
diff1 = xdiff1 + ydiff1;
|
|
closest = player;
|
|
} else {
|
|
diff1 = 9999;
|
|
}
|
|
|
|
if (player2 && !player2->dead) {
|
|
xdiff2 = abs(player2->x - x);
|
|
ydiff2 = abs(player2->y - y);
|
|
diff2 = xdiff2 + ydiff2;
|
|
if (closest == NULL) closest = player2;
|
|
else if (closest == player) {
|
|
if (diff2 > diff1) closest = player2;
|
|
}
|
|
}
|
|
return closest;
|
|
}
|
|
|
|
double getxdisttoplayer(sprite_t *s, sprite_t **pl) {
|
|
double xdiff1,xdiff2,xdiff = 9999;
|
|
if (globpowerup == PW_CAMERA) return 9999;
|
|
|
|
/* distance to closest player */
|
|
if (player) {
|
|
xdiff1 = abs(player->x - s->x);
|
|
} else {
|
|
xdiff1 = 9999;
|
|
}
|
|
|
|
if (player2) {
|
|
xdiff2 = abs(player2->x - s->x);
|
|
} else {
|
|
xdiff2 = 9999;
|
|
}
|
|
|
|
if (pl != NULL) *pl = NULL; // default
|
|
|
|
if (xdiff1 < xdiff2) { // p1 closer
|
|
if (xdiff1 != 9999) {
|
|
xdiff = player->x - s->x;
|
|
}
|
|
if (pl != NULL) *pl = player;
|
|
} else { // p2 closer
|
|
if (xdiff2 != 9999) {
|
|
xdiff = player2->x - s->x;
|
|
}
|
|
if (pl != NULL) *pl = player2;
|
|
}
|
|
|
|
|
|
return xdiff;
|
|
}
|
|
|
|
double getydisttoplayer(sprite_t *s) {
|
|
double ydiff1,ydiff2,ydiff;
|
|
/* distance to closest player */
|
|
if (globpowerup == PW_CAMERA) return 9999;
|
|
|
|
if (player) {
|
|
ydiff1 = player->y - s->y;
|
|
} else {
|
|
ydiff1 = 9999;
|
|
}
|
|
|
|
if (player2) {
|
|
ydiff2 = player2->y - s->y;
|
|
} else {
|
|
ydiff2 = 9999;
|
|
}
|
|
|
|
if (ydiff1 < ydiff2) {
|
|
ydiff = ydiff1;
|
|
} else {
|
|
ydiff = ydiff2;
|
|
}
|
|
|
|
return ydiff;
|
|
}
|
|
|
|
|
|
sprite_t *isplayerbelow(sprite_t *s) {
|
|
if (globpowerup == PW_CAMERA) return NULL;
|
|
|
|
if (player && !player->dead && player->y > s->y) return player;
|
|
if (player2 && !player2->dead && player2->y > s->y) return player2;
|
|
|
|
return NULL;
|
|
}
|
|
// is there a player more than "dis" pixels below?
|
|
sprite_t *isplayerbelowgt(sprite_t *s,int dis) {
|
|
if (globpowerup == PW_CAMERA) return NULL;
|
|
|
|
if (player && !player->dead && (player->y - s->y) >= dis ) return player;
|
|
if (player2 && !player2->dead && (player2->y - s->y) >= dis) return player2;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
sprite_t *isplayerabove(sprite_t *s) {
|
|
if (globpowerup == PW_CAMERA) return NULL;
|
|
|
|
if (player && !player->dead && player->y < s->y) return player;
|
|
if (player2 && !player2->dead && player2->y < s->y) return player2;
|
|
|
|
return NULL;
|
|
}
|
|
//
|
|
// is there a player within "dis" pixels above?
|
|
sprite_t *isplayerabovelt(sprite_t *s,int dis) {
|
|
if (globpowerup == PW_CAMERA) return NULL;
|
|
|
|
if (player && !player->dead && (player->y < s->y) && ((s->y - player->y) <= dis )) return player;
|
|
if (player2 && !player2->dead && (player->y < s->y) && ((s->y - player2->y) <= dis)) return player2;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
// is there a player more than "dis" pixels above?
|
|
sprite_t *isplayerabovegt(sprite_t *s,int dis) {
|
|
if (globpowerup == PW_CAMERA) return NULL;
|
|
|
|
if (player && !player->dead && ((s->y - player->y) >= dis )) return player;
|
|
if (player2 && !player2->dead && ((s->y - player2->y) >= dis)) return player2;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
sprite_t *isplayerright(sprite_t *s) {
|
|
|
|
if (globpowerup == PW_CAMERA) return NULL;
|
|
|
|
if (player && !player->dead && player->x > s->x) return player;
|
|
if (player2 && !player2->dead && player2->x > s->x) return player2;
|
|
|
|
return NULL;
|
|
}
|
|
sprite_t *isplayerleft(sprite_t *s) {
|
|
|
|
if (globpowerup == PW_CAMERA) return NULL;
|
|
|
|
if (player && !player->dead && player->x < s->x) return player;
|
|
if (player2 && !player2->dead && player2->x < s->x) return player2;
|
|
|
|
return NULL;
|
|
}
|
|
sprite_t *isplayerahead(sprite_t *s) {
|
|
sprite_t *seen = NULL;
|
|
int ydis;
|
|
|
|
if (!playersalive()) {
|
|
seen = NULL;
|
|
} else {
|
|
if (player) {
|
|
ydis = abs((s->y - s->img->h/2) - (player->y - player->img->h/2));
|
|
if (ydis > TILEH*2) {
|
|
seen = NULL;
|
|
} else if ((s->dir < 0) && (player->x > s->x)) {
|
|
seen = NULL;
|
|
} else if ((s->dir > 0) && (player->x < s->x)) {
|
|
seen = NULL;
|
|
} else seen = player;
|
|
}
|
|
if (!seen && (player2)) {
|
|
ydis = abs((s->y - s->img->h/2) - (player2->y - player2->img->h/2));
|
|
if (ydis > TILEH*2) {
|
|
seen = NULL;
|
|
} else if ((s->dir < 0) && (player2->x > s->x)) {
|
|
seen = NULL;
|
|
} else if ((s->dir > 0) && (player2->x < s->x)) {
|
|
seen = NULL;
|
|
} else seen = player2;
|
|
}
|
|
}
|
|
return seen;
|
|
}
|
|
|
|
// turn to face a player
|
|
void faceplayer(sprite_t *s) {
|
|
// face a player
|
|
if ((s->dir == D_RIGHT) && !isplayerright(s) && isplayerleft(s)) {
|
|
s->dir = D_LEFT;
|
|
} else if ((s->dir == D_LEFT) && !isplayerleft(s) && isplayerright(s)) {
|
|
s->dir = D_RIGHT;
|
|
}
|
|
}
|
|
|
|
|
|
SDL_Color *getcolour(int id) {
|
|
switch (id) {
|
|
case P_FLOWERYELLOW:
|
|
case P_GEMYELLOW:
|
|
case P_CHEESE:
|
|
case P_PIZZA:
|
|
case P_GOLDCOIN:
|
|
case P_GOLDBAR:
|
|
return &yellow;
|
|
case P_FLOWERRED:
|
|
case P_GEMRED:
|
|
case P_CHIPS:
|
|
return &red;
|
|
case P_FLOWERPURPLE:
|
|
case P_GEMPURPLE:
|
|
return &purple;
|
|
case P_BURGER:
|
|
case P_SUNDAE:
|
|
case P_CHOCOLATE:
|
|
return &brown;
|
|
case P_DIAMOND:
|
|
return &cyan;
|
|
case P_CAKE:
|
|
return &blue;
|
|
case P_ICECREAM:
|
|
return &white;
|
|
}
|
|
|
|
return &white;
|
|
}
|
|
|
|
SDL_Color *getbgcolour (int id) {
|
|
switch (id) {
|
|
case P_PIZZA:
|
|
return &red2;
|
|
case P_CHIPS:
|
|
return &brown2;
|
|
}
|
|
|
|
return &black;
|
|
}
|
|
|
|
int inintro(void) {
|
|
if (curlevelnum == INTRO_LEVELNUM) return B_TRUE;
|
|
return B_FALSE;
|
|
}
|
|
|
|
void dointroseq(void) {
|
|
if (introstate == IS_START) {
|
|
if (gtime >= 2) {
|
|
playfx(FX_POWERUP);
|
|
introstate = IS_YUM;
|
|
}
|
|
} else if (introstate == IS_YUM) {
|
|
if (player) {
|
|
addoutlinetext(player->x,player->y - (player->img->h*1.5),TEXTSIZE_YUM,"Yum!",getptextcol(player), &black,YUMDELAY, TT_INTROTEXT);
|
|
}
|
|
if (player2) {
|
|
addoutlinetext(player2->x,player2->y - (player2->img->h*1.5),TEXTSIZE_YUM,"Yum!",getptextcol(player2),&black,YUMDELAY, TT_INTROTEXT);
|
|
}
|
|
|
|
introstate = IS_YUMWAIT; // exits when yum text is gone
|
|
} else if (introstate == IS_JUMP) {
|
|
if (player) {
|
|
if (!player->jumping && !player->falling) {
|
|
jump(player, D_RIGHT);
|
|
player->jumpspeed = 7;
|
|
} else if (player->falling) {
|
|
movex(player, getspeed(player)/2, B_TRUE);
|
|
}
|
|
}
|
|
if (player2) {
|
|
if (player) {
|
|
|
|
if (player->jumping && player->jumpspeed <= 5) {
|
|
if (!player2->jumping && !player2->falling) {
|
|
jump(player2, D_LEFT);
|
|
player2->jumpspeed = 7;
|
|
} else if (player2->falling) {
|
|
movex(player2, -getspeed(player2)/2, B_TRUE);
|
|
}
|
|
}
|
|
} else {
|
|
if (!player2->jumping && !player2->falling) {
|
|
jump(player2, D_LEFT);
|
|
player2->jumpspeed = 7;
|
|
} else if (player2->falling) {
|
|
movex(player2, -getspeed(player2)/2, B_TRUE);
|
|
}
|
|
}
|
|
}
|
|
if ((player && player->falling) || (player2 && player2->falling)) {
|
|
sprite_t *newsp;
|
|
double startx,starty;
|
|
// add rats
|
|
startx = TILEW;
|
|
starty = (curlevel->p1y * TILEH) + TILEH-2;
|
|
puffin(-1, startx, starty, "nothing", 0);
|
|
newsp = addsprite(P_RAT, startx, starty, "intro_rat");
|
|
newsp->speed = INTRO_RATSPEED;
|
|
newsp->antigrav = B_TRUE;
|
|
introstate = IS_RATS;
|
|
playfx(FX_BOSSCHARGE);
|
|
}
|
|
} else if ((introstate == IS_RATS) || (introstate == IS_RATS2)) {
|
|
sprite_t *s;
|
|
double xpoint;
|
|
// keep moving until we hit the ground
|
|
if (player) {
|
|
if (player->falling) {
|
|
movex(player, getspeed(player), B_TRUE);
|
|
|
|
}
|
|
if (introstate == IS_RATS2) {
|
|
// look around
|
|
if (timer % 20 == 0) {
|
|
player->dir = -player->dir;
|
|
}
|
|
}
|
|
}
|
|
if (player2) {
|
|
if (player2->falling) {
|
|
movex(player2, -getspeed(player2), B_TRUE);
|
|
|
|
}
|
|
if (introstate == IS_RATS2) {
|
|
// look around
|
|
if ((timer+5) % 20 == 0) {
|
|
player2->dir = -player2->dir;
|
|
}
|
|
}
|
|
}
|
|
// add more rats
|
|
if (introstate != IS_RATS2) {
|
|
if (countmonsters(P_RAT) <= 6) {
|
|
if (timer % 5 == 0) {
|
|
sprite_t *newsp;
|
|
double startx,starty;
|
|
// add rats
|
|
startx = TILEW;
|
|
starty = (curlevel->p1y * TILEH) + TILEH-2;
|
|
puffin(-1, startx, starty, "nothing", 0);
|
|
newsp = addsprite(P_RAT, startx, starty, "intro_rat");
|
|
newsp->speed = INTRO_RATSPEED;
|
|
newsp->antigrav = B_TRUE;
|
|
}
|
|
}
|
|
}
|
|
// if rats are past p2 start point, they fall
|
|
xpoint = (curlevel->p2x * TILEW) + (TILEW/2);
|
|
for (s = sprite ; s ; s = s->next) {
|
|
if (ismonster(s->id)) {
|
|
if (s->x >= xpoint) {
|
|
s->antigrav = B_FALSE;
|
|
s->speed = (INTRO_RATSPEED / 2);
|
|
introstate = IS_RATS2;
|
|
}
|
|
}
|
|
}
|
|
// next state
|
|
if (countmonsters(-1) <= 0) {
|
|
introstate = IS_FINISH;
|
|
if (player) {
|
|
player->timer1 = 0;
|
|
player->timer2 = 0;
|
|
}
|
|
if (player2) {
|
|
player2->timer1 = 0;
|
|
player2->timer2 = 0;
|
|
}
|
|
}
|
|
} else if (introstate == IS_FINISH) {
|
|
int finished = B_TRUE;
|
|
// players jump up and down 3 times
|
|
if (player) {
|
|
if (isonground(player)) {
|
|
if (player->timer1 < 3) {
|
|
playfx(FX_JUMP);
|
|
player->jumping = 1;
|
|
player->jumpdir = 0;
|
|
player->jumpspeed = 2;
|
|
|
|
player->timer1++;
|
|
finished = B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
if (player2) {
|
|
if (isonground(player2)) {
|
|
if (player2->timer1 < 3) {
|
|
playfx(FX_JUMP);
|
|
player2->jumping = 1;
|
|
player2->jumpdir = 0;
|
|
player2->jumpspeed = 2;
|
|
|
|
player2->timer1++;
|
|
finished = B_FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (finished) {
|
|
if (levelcomplete == LV_INPROGRESS) {
|
|
// clouds come in
|
|
levelcomplete = LV_FINAL;
|
|
// don't delay
|
|
levelcompletetime = gtime;
|
|
gtime += 10;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
int addcredit(void) {
|
|
// can't add credits during game
|
|
|
|
if (credits < MAXCREDITS) {
|
|
if (lockcredits) {
|
|
playfx(FX_SKULL);
|
|
} else {
|
|
credits++;
|
|
playfx(FX_COIN);
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
return B_TRUE;
|
|
}
|
|
|
|
int getpnum(sprite_t *s) {
|
|
if (s == player) return 0;
|
|
else return 1;
|
|
}
|
|
|
|
int countbabies(sprite_t *s, int babytype) {
|
|
sprite_t *ss;
|
|
int numbabies;
|
|
numbabies = 0;
|
|
for (ss = sprite ; ss ; ss = ss->next) {
|
|
if ((ss->id == babytype) && (ss->owner == s)) {
|
|
numbabies++;
|
|
}
|
|
}
|
|
return numbabies;
|
|
}
|
|
|
|
int isbridge(int id) {
|
|
switch (id) {
|
|
case T_BRIDGE:
|
|
case T_ICEBRIDGE:
|
|
case T_ICEBRIDGETH:
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
|
|
/*
|
|
int isice(int id) {
|
|
switch (id) {
|
|
case T_ICE:
|
|
case T_ICEBRIDGE:
|
|
case T_ICETOP:
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
*/
|
|
|
|
|
|
int isconveyor(int id) {
|
|
switch (id) {
|
|
case T_RIGHT:
|
|
case T_LEFT:
|
|
return B_TRUE;
|
|
}
|
|
return B_FALSE;
|
|
}
|
|
|
|
int savebmp(SDL_Surface *which) {
|
|
int rv;
|
|
char filename[BUFLEN];
|
|
sprintf(filename, "/tmp/level_%d_%d.bmp",getcurworld(), getcurlevel());
|
|
rv = SDL_SaveBMP(which, filename);
|
|
printf("Screenshot saved in %s\n",filename);
|
|
return rv;
|
|
}
|
|
|
|
void melttile(int tx, int ty,int howlong, int wantpuff) {
|
|
if (numregrow >= (MAXREGROW-1)) {
|
|
return;
|
|
}
|
|
|
|
if (howlong != FOREVER) {
|
|
regrow[numregrow].tx = tx;
|
|
regrow[numregrow].ty = ty;
|
|
regrow[numregrow].origid = curlevel->map[ty * LEVELW + tx ];
|
|
regrow[numregrow].timer = howlong;
|
|
numregrow++;
|
|
}
|
|
|
|
curlevel->map[ty * LEVELW + tx ] = getuniq(T_BLANK);
|
|
drawtile(temps, tx,ty);
|
|
if (wantpuff) {
|
|
puffin(-1, tx*TILEW+(TILEW/2), ty*TILEH+TILEH, "nothing", 0);
|
|
}
|
|
}
|
|
|
|
|
|
// select a random spell for king cat
|
|
void selectspell(sprite_t *s) {
|
|
// select spell
|
|
s->timer1 = KCS_SPELLCAST;
|
|
|
|
// defaults
|
|
s->timer2 = KC_SPELLCASTTIME;
|
|
s->timer4 = 0; // for spell effects
|
|
|
|
if (s->timer5 >= 3) {
|
|
s->timer3 = SPL_TELEPORT;
|
|
s->timer5 = 0;
|
|
} else if (countmonsters(ALL) <= 3) {
|
|
// if there aren't anough monsters, summon
|
|
// some more.
|
|
s->timer3 = SPL_SUMMON;
|
|
} else { // random spell
|
|
enum SPELL poss[SPL_LAST];
|
|
int nposs = 0;
|
|
|
|
/////////////////////////////////////
|
|
// add all possible spells to a list
|
|
/////////////////////////////////////
|
|
|
|
// only possible if a player is alive
|
|
if (getrandomaliveplayer()) {
|
|
poss[nposs++] = SPL_TELEPORT;
|
|
}
|
|
// always possible
|
|
poss[nposs++] = SPL_WIND;
|
|
poss[nposs++] = SPL_FIREBALLS;
|
|
poss[nposs++] = SPL_BRICKS;
|
|
|
|
// select one of them
|
|
if (!nposs) {
|
|
s->timer3 = SPL_NONE;
|
|
} else {
|
|
s->timer3 = poss[rand() % nposs];
|
|
}
|
|
}
|
|
|
|
// test...
|
|
//s->timer3 = SPL_BRICKS;
|
|
|
|
// fill in characteristics for spell
|
|
if (s->timer3 == SPL_TELEPORT) {
|
|
sprite_t *who = NULL;
|
|
who = getrandomaliveplayer();
|
|
if (who) {
|
|
s->newx = who->x;
|
|
s->newy = who->y;
|
|
} else {
|
|
// abort spell. back to walking.
|
|
s->timer1 = KCS_WALK;
|
|
s->timer2 = 0;
|
|
}
|
|
} else if (s->timer3 == SPL_WIND) {
|
|
s->timer2 = KC_SPELLCASTTIME*3;
|
|
} else if (s->timer3 == SPL_BRICKS) {
|
|
s->timer2 = KC_SPELLCASTTIME*3;
|
|
}
|
|
|
|
// inc teleport timer - when this reaches 2 we
|
|
// will do a teleport.
|
|
s->timer5++;
|
|
}
|
|
|
|
void incfruittype(void) {
|
|
curfruittype++;
|
|
if (fruittypes[curfruittype] == -1) {
|
|
curfruittype = 0;
|
|
}
|
|
}
|
|
|
|
SDL_Color *getptextcol(sprite_t *s) {
|
|
if (s == player) {
|
|
if (swapplayers) return &purple;
|
|
else return &red;
|
|
} else { // ie. player 2
|
|
if (swapplayers) return &red;
|
|
else return &purple;
|
|
}
|
|
return &red;
|
|
}
|