diff --git a/Makefile b/Makefile index f560530..a71063c 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,5 @@ -rc: rc.c rc.h +rc: rc.c rc.h shared.c shared.h defs.h gcc -Wall -DREV=`./getsvnrev.sh` -orc -g rc.c shared.c `sdl-config --cflags --libs` -I/usr/local/include -L/usr/local/lib -lSDLmain -lSDL -lSDL_image -lSDL_gfx -lSDL_ttf -lSDL_mixer + +edit: edit.c edit.h shared.c shared.h defs.h + gcc -D__EDITOR -Wall -DREV=`./getsvnrev.sh` -oedit -g edit.c shared.c `sdl-config --cflags --libs` -I/usr/local/include -L/usr/local/lib -lSDLmain -lSDL -lSDL_image -lSDL_gfx -lSDL_ttf -lSDL_mixer diff --git a/data/levels/level99.dat b/data/levels/level99.dat index 786927e..fc97ed9 100644 --- a/data/levels/level99.dat +++ b/data/levels/level99.dat @@ -4,9 +4,9 @@ hurryup 10 help endhelp monsters -134 18 15 0 17 15 -171 4 7 +134 18 15 +172 17 28 endmonsters exitdir 1 4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, diff --git a/data/sprites/moth.png b/data/sprites/moth.png new file mode 100644 index 0000000..014f2a6 Binary files /dev/null and b/data/sprites/moth.png differ diff --git a/data/sprites/moth1.png b/data/sprites/moth1.png new file mode 100644 index 0000000..ab5a22a Binary files /dev/null and b/data/sprites/moth1.png differ diff --git a/data/sprites/mothcaught.png b/data/sprites/mothcaught.png new file mode 100644 index 0000000..7e48caa Binary files /dev/null and b/data/sprites/mothcaught.png differ diff --git a/data/sprites/mothdead.png b/data/sprites/mothdead.png new file mode 100644 index 0000000..da43aa2 Binary files /dev/null and b/data/sprites/mothdead.png differ diff --git a/data/sprites/mothfire0.png b/data/sprites/mothfire0.png new file mode 100644 index 0000000..7ab07b0 Binary files /dev/null and b/data/sprites/mothfire0.png differ diff --git a/data/sprites/mothfire1.png b/data/sprites/mothfire1.png new file mode 100644 index 0000000..df01442 Binary files /dev/null and b/data/sprites/mothfire1.png differ diff --git a/data/sprites/mothfire2.png b/data/sprites/mothfire2.png new file mode 100644 index 0000000..e862fab Binary files /dev/null and b/data/sprites/mothfire2.png differ diff --git a/data/sprites/mothfire3.png b/data/sprites/mothfire3.png new file mode 100644 index 0000000..71786d9 Binary files /dev/null and b/data/sprites/mothfire3.png differ diff --git a/defs.h b/defs.h index 23bb84f..53c1433 100644 --- a/defs.h +++ b/defs.h @@ -1,4 +1,3 @@ -#define KAS_WAITFORTOP 2 #ifndef __DEFS_H #define __DEFS_H @@ -289,6 +288,15 @@ #define KAS_WALK2 6 #define KAS_JUMP2 7 +// moth +#define MOTH_PAUSE 20 +#define MOTH_FIRESPACE 5 // space between shots +// moth states +#define MS_FLY 0 +#define MS_PAUSE1 1 +#define MS_PAUSE2 2 + + // bell states #define BELL_DONESOUND 1 #define BELL_DONEFLASH 2 @@ -444,7 +452,7 @@ #define S_SLOPE 2 // Sprite types -#define MAXPTYPES 172 +#define MAXPTYPES 174 #define P_PLAYER 0 #define P_RAT 1 #define P_CHEESE 2 @@ -622,6 +630,8 @@ #define P_LAMP 169 #define P_GOLDBAR 170 #define P_WSPIDER 171 +#define P_MOTH 172 +#define P_MOTHFIRE 173 #define FLY_FLYTIME 150 @@ -811,6 +821,7 @@ #define D_LEFT (-1) #define D_UP (-2) #define D_DOWN (2) +#define D_NONE (0) // boss health bar #define HEALTHBARY 480-100 // y position of health bar diff --git a/rc.c b/rc.c index 91b7b50..b19ee6c 100644 --- a/rc.c +++ b/rc.c @@ -2800,12 +2800,14 @@ int movesprite(sprite_t *s) { 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 (!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); } } } @@ -5029,6 +5031,133 @@ int movesprite(sprite_t *s) { movex(s, s->jumpdir*getspeed(s), B_TRUE); faceplayer(s); } + } else if (s->id == P_MOTH) { + /* timer1 tracks state, timer2 tracks previous direction + timer3 is current direction + */ + if (s->timer1 == MS_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) { + // hit a wall + s->timer1 = MS_PAUSE1; + s->timer2 = s->timer3; // old dir + s->timer3 = MOTH_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 = MS_PAUSE1; + s->timer2 = s->timer3; // old dir + s->timer3 = MOTH_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 = MS_PAUSE1; + s->timer2 = s->timer3; // old dir + s->timer3 = MOTH_PAUSE; + } else { + s->moved = MV_FLY; + } + } + } + } else if (s->timer1 == MS_PAUSE1) { + s->moved = MV_FLY; + // wait for countdown... + s->timer3--; + if ((s->timer3 == MOTH_FIRESPACE*2) || (s->timer3 == MOTH_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 + ss = addsprite(P_MOTHFIRE,s->x,s->y - s->img->h/2,"mothfire" ); + ss->xs = cos(ang) * getspeed(ss); + ss->ys = sin(ang) * getspeed(ss); + } + } + if (s->timer3 == 0) { + // go to next state + s->timer1 = MS_PAUSE2; + s->timer3 = MOTH_PAUSE; + } + } else if (s->timer1 == MS_PAUSE2) { + s->moved = MV_FLY; + s->timer3--; + if (s->timer3 == 0) { + // go to next state + s->timer1 = MS_FLY; + s->timer3 = D_NONE; + } + } } else if (s->id == P_SNAKE) { /* timer1 loopsfrom 0 - 19 @@ -5628,6 +5757,20 @@ int movesprite(sprite_t *s) { } else if (s->x <= TILEW) { s->dead = D_FINAL; } + } else if (s->id == P_MOTHFIRE) { + // move + s->x += s->xs; + s->y += s->ys; + // die if it leaves screen + if (s->x >= (640-TILEW)) { + s->dead = D_FINAL; + } else if (s->x <= TILEW) { + s->dead = D_FINAL; + } else if (s->y >= (480-TILEH)) { + s->dead = D_FINAL; + } else if (s->y <= TILEH) { + s->dead = D_FINAL; + } } else if (s->id == P_RAYGUNBULLET) { s->x += s->xs; if (s->x >= (640-TILEW)) { @@ -6760,8 +6903,13 @@ double getspeed(sprite_t *s ) { else speed = 1.5; } } else if (id == P_SPIDER) { - if (s->angry) speed = 2; - else speed = 1.5; + if (s->angry) speed = 2.5; + else speed = 2.5; + } else if (id == P_MOTH) { + if (s->angry) speed = 3; + else speed = 2.5; + } else if (id == P_MOTHFIRE) { + speed = 2.5; } else if (id == P_KINGRAT) { speed = 1.5; } else if (id == P_KINGANT) { @@ -8542,7 +8690,7 @@ int movex(sprite_t *s,double amt,int onpurpose) { s->xs = 0; return NM_SIDE; } - if (tt2->solid == S_SLOPE && (!candoslopes(s->id))) { + if ((tt2->solid == S_SLOPE) && (!candoslopes(s->id))) { s->xs = 0; return NM_SIDE; } @@ -13497,6 +13645,32 @@ void doplayermovement(sprite_t *pl) { } } + +sprite_t *getclosestplayer(sprite_t *s) { + double xdiff1,xdiff2,ydiff1,ydiff2,diff1,diff2; + sprite_t *closest = NULL; + // closest player + if (player && !player->dead) { + xdiff1 = abs(player->x - s->x); + ydiff1 = abs(player->y - s->y); + diff1 = xdiff1 + ydiff1; + closest = player; + } else { + diff1 = 9999; + } + + if (player2 && !player2->dead) { + xdiff2 = abs(player2->x - s->x); + ydiff2 = abs(player2->y - s->y); + diff2 = xdiff2 + ydiff2; + if (closest == NULL) closest = player2; + else if (closest == player) { + if (diff2 > diff1) closest = player2; + } + } + return closest; +} + double getxdisttoplayer(sprite_t *s, sprite_t **pl) { double xdiff1,xdiff2,xdiff = 9999; if (globpowerup == PW_CAMERA) return 9999; diff --git a/rc.h b/rc.h index 0d6a060..cde44f4 100644 --- a/rc.h +++ b/rc.h @@ -113,6 +113,7 @@ void swimup(sprite_t *pl); void swimdown(sprite_t *pl); double getdistance(double x1, double y1, double x2, double y2); void doplayermovement(sprite_t *pl); +sprite_t *getclosestplayer(sprite_t *s); double getxdisttoplayer(sprite_t *s, sprite_t **pl); double getydisttoplayer(sprite_t *s); int playersalive(void); diff --git a/shared.c b/shared.c index f44303a..29f4eb8 100644 --- a/shared.c +++ b/shared.c @@ -843,7 +843,7 @@ void setdefaults(sprite_t *s) { s->lives = 1; } - // special for bosses + // special for bosses/other monsters if (s->id == P_KINGRAT) { s->timer1 = 0; s->timer2 = KR_WALKTIME; @@ -862,6 +862,10 @@ void setdefaults(sprite_t *s) { s->timer1 = KAS_WALK1; s->timer2 = KA_WALKTIME; s->timer3 = KA_SHOOTTIME; + } else if (s->id == P_MOTH) { + s->timer1 = MS_FLY; + s->timer2 = D_NONE; + s->timer3 = D_NONE; } if (isboss(s->id)) { s->lives = getbosshealth(s->id); // health @@ -875,6 +879,7 @@ void setdefaults(sprite_t *s) { case P_BLACKCLOUD: case P_SPIDER: case P_KINGFLY: + case P_MOTH: s->flies = B_TRUE; break; case P_FLY: @@ -1046,6 +1051,36 @@ tiletype_t *gettileat(int pixx,int pixy, int *tilex,int *tiley) { return gettile(tid); } +int oppositedir(int dir) { + if (dir == D_RIGHT) return D_LEFT; + if (dir == D_LEFT) return D_RIGHT; + if (dir == D_UP) return D_DOWN; + if (dir == D_DOWN) return D_UP; + + return D_NONE; +} + +tiletype_t *gettilexy(int tilex,int tiley) { + int tx,ty; + int tid; + + tx = tilex; + ty = tiley; + + if (tx >= LEVELW) tx = LEVELW-1; + if (ty >= LEVELH) ty = LEVELH-1; + + if (ty < 0) ty = 0; + if (tx < 0) tx = 0; + + // return layer2 if it exists + tid = curlevel->map2[ty*LEVELW+tx]; + if (tid == T_BLANK) { + tid = curlevel->map[ty*LEVELW+tx]; + } + return gettile(tid); +} + int loadtiletypes(char *filename) { char fullfile[BUFLEN]; tiletype_t *t = NULL; @@ -1417,6 +1452,14 @@ int loadimagesets(void) { loadspriteimage(P_WSPIDER,F_CLIMB2, "sprites/whitespiderclimb1.png"); imageset[P_WSPIDER].numimages = 10; + loadspriteimage(P_MOTH,F_WALK1, "sprites/moth.png"); + loadspriteimage(P_MOTH,F_JUMP, "sprites/moth1.png"); + loadspriteimage(P_MOTH,F_FALL, "sprites/moth1.png"); + loadspriteimage(P_MOTH,F_CAUGHT, "sprites/mothcaught.png"); + loadspriteimage(P_MOTH,F_DEAD, "sprites/mothdead.png"); + /* next 3 are auto generated */ + imageset[P_MOTH].numimages = 8; + loadspriteimage(P_SPIDER,F_WALK1, "sprites/newspider.png"); loadspriteimage(P_SPIDER,F_JUMP, "sprites/newspiderjump.png"); @@ -1906,6 +1949,14 @@ int loadimagesets(void) { loadspriteimage(P_BIGFIREBALL,1, "sprites/bigfire2.png"); imageset[P_BIGFIREBALL].numimages = 2; + loadspriteimage(P_MOTHFIRE,0, "sprites/mothfire0.png"); + loadspriteimage(P_MOTHFIRE,1, "sprites/mothfire1.png"); + loadspriteimage(P_MOTHFIRE,2, "sprites/mothfire2.png"); + loadspriteimage(P_MOTHFIRE,3, "sprites/mothfire3.png"); + loadspriteimage(P_MOTHFIRE,4, "sprites/mothfire2.png"); + loadspriteimage(P_MOTHFIRE,5, "sprites/mothfire1.png"); + imageset[P_MOTHFIRE].numimages = 6; + // manual angry image for black cloud @@ -2787,6 +2838,7 @@ int isbullet(int id) { if (id == P_SPIT) return B_TRUE; if (id == P_FIREBALL) return B_TRUE; if (id == P_BIGFIREBALL) return B_TRUE; + if (id == P_MOTHFIRE) return B_TRUE; return B_FALSE; } @@ -3246,6 +3298,7 @@ int ismonster(int id) { case P_ANT1: case P_ANT2: case P_ANT3: + case P_MOTH: return MT_MONSTER; case P_BLACKCLOUD: case P_KINGRAT: @@ -3761,6 +3814,7 @@ void setfruitinfo(void) { setinfo(P_SPIDER, "Redback", "Redback spiders will lurk quietly on the ceiling, crawling back and forth. If they notice a player nearby however they will swiftly pounce down onto their prey!", "spider.png"); setinfo(P_WSPIDER, "Whitetail", "Whitetail spiders are more intelligent than other monsters - they are aware of nearby players and will use the landscape to track them down!", "whitespider.png"); + setinfo(P_MOTH, "Moth", "The moth moves in straight lines until it hits a wall. Although simplistic in their movement, moths have the ability to fire a burst of hypno-rays to take out an unwary player!", "moth.png"); setinfo(P_FROG, "Frog", "Green frogs will continually bounce around, making them more difficult to catch. They are also excellent swimmers.", "frog.png"); @@ -3847,6 +3901,8 @@ void dumpinfo(void) { printf(""); } else if (i == P_WSPIDER) { printf(""); + } else if (i == P_MOTH) { + printf(""); } printf("
%s%s\n", diff --git a/shared.h b/shared.h index 14a2a5a..55ef9fa 100644 --- a/shared.h +++ b/shared.h @@ -10,6 +10,7 @@ void setdefaults(sprite_t *s); int loadtiletypes(char *filename); sprite_t *addsprite(int id,int x, int y, char *name); tiletype_t *gettileat(int pixx,int pixy, int *tilex, int *tiley); +tiletype_t *gettilexy(int tilex,int tiley); int loadimagesets(void); int isbullet(int id); void flip(void); @@ -71,6 +72,7 @@ int getnumplayers(void); int isbadpowerup(int id); int iswinpowerup(int id); int isabilitypowerup(int id); +int oppositedir(int dir); // for doco void setfruitinfo(void); void setinfo(int id, char *name, char *desc, char *file); diff --git a/website/img/moth.png b/website/img/moth.png new file mode 100644 index 0000000..d76cb94 Binary files /dev/null and b/website/img/moth.png differ diff --git a/website/img/mothfire.png b/website/img/mothfire.png new file mode 100644 index 0000000..33a3f71 Binary files /dev/null and b/website/img/mothfire.png differ diff --git a/website/info.html b/website/info.html index b5d736f..f632ff2 100644 --- a/website/info.html +++ b/website/info.html @@ -34,7 +34,9 @@
Queen AntAfter an ant has eaten enough, they become a Queen. Queens are just as fast as soldiers and can also breath fire. Furthermore, they are only one meal away from spawning additional ants!
WhitetailWhitetail spiders are more intelligent than other monsters - they are aware of nearby players and will use the landscape to track them down! - Bosses + +
MothThe moth moves in straight lines until it hits a wall. Although simplistic in their movement, moths have the ability to fire a burst of hypno-rays to take out an unwary player! +Bosses
Cloud of DoomThis unkillable cloud will appear if you spend too much time on one level. Beware, as the only way to defeat the cloud of doom is to complete the level before it grows too large to handle!
King RatThis mighty creature is the ruler of the rats, and impervious to the player's net. It can only be harmed by slamming another monster into it! King Rat will roam the level searching for a player, and upon spotting them will charge at high speed.
King SnailThe absolute ruler of the snail kingdom is far too large and heavy to catch in a net. In addition, its shell provides protection against all attacks, leaving only its head vulnerable. While King Snail is too proud to chase down enemies itself, it can use its snail army to destroy its foes.