--- /dev/null
+/* Reconstructed Commander Keen 4-6 Source Code\r
+ * Copyright (C) 2021 K1n9_Duk3\r
+ *\r
+ * This file is loosely based on:\r
+ * Keen Dreams Source Code\r
+ * Copyright (C) 2014 Javier M. Chavez\r
+ *\r
+ * This program is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License along\r
+ * with this program; if not, write to the Free Software Foundation, Inc.,\r
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
+ */\r
+\r
+/*\r
+K5_ACT2.C\r
+=========\r
+\r
+Contains the following actor types (in this order):\r
+\r
+- Sparky\r
+- Little Ampton\r
+- Slicestar\r
+- Shelley\r
+\r
+*/\r
+\r
+#include "CK_DEF.H"\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SPARKY\r
+\r
+temp1 = charge countdown\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_sparkywalk1 = {SPARKYWALKL1SPR, SPARKYWALKR1SPR, step, false, true, 8, 128, 0, T_Sparky, C_Sparky, R_Sparky, &s_sparkywalk2};\r
+statetype s_sparkywalk2 = {SPARKYWALKL2SPR, SPARKYWALKR2SPR, step, false, true, 8, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkywalk3};\r
+statetype s_sparkywalk3 = {SPARKYWALKL3SPR, SPARKYWALKR3SPR, step, false, true, 8, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkywalk4};\r
+statetype s_sparkywalk4 = {SPARKYWALKL4SPR, SPARKYWALKR4SPR, step, false, true, 8, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkywalk1};\r
+statetype s_sparkylook1 = {SPARKYTURN1SPR, SPARKYTURN1SPR, step, false, true, 6, 0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook2};\r
+statetype s_sparkylook2 = {SPARKYTURN2SPR, SPARKYTURN2SPR, step, false, true, 6, 0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook3};\r
+statetype s_sparkylook3 = {SPARKYTURN3SPR, SPARKYTURN3SPR, step, false, true, 6, 0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook4};\r
+statetype s_sparkylook4 = {SPARKYWALKR1SPR, SPARKYWALKR1SPR, step, false, true, 6, 0, 0, T_SparkyLookL, C_Sparky, R_Sparky, &s_sparkylook5};\r
+statetype s_sparkylook5 = {SPARKYTURN3SPR, SPARKYTURN3SPR, step, false, true, 6, 0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook6};\r
+statetype s_sparkylook6 = {SPARKYTURN2SPR, SPARKYTURN3SPR, step, false, true, 6, 0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook7};\r
+statetype s_sparkylook7 = {SPARKYTURN1SPR, SPARKYTURN3SPR, step, false, true, 6, 0, 0, NULL, C_Sparky, R_Draw, &s_sparkylook8};\r
+statetype s_sparkylook8 = {SPARKYWALKL1SPR, SPARKYWALKR1SPR, step, false, true, 6, 0, 0, T_SparkyLookR, C_Sparky, R_Sparky, &s_sparkywalk2};\r
+statetype s_sparkyspeed1 = {SPARKYWALKL1SPR, SPARKYWALKR1SPR, step, true, true, 4, 0, 0, NULL, C_Sparky, R_Sparky, &s_sparkyspeed2};\r
+statetype s_sparkyspeed2 = {SPARKYWALKL2SPR, SPARKYWALKR2SPR, step, true, true, 4, 0, 0, NULL, C_Sparky, R_Sparky, &s_sparkyspeed3};\r
+statetype s_sparkyspeed3 = {SPARKYWALKL3SPR, SPARKYWALKR3SPR, step, true, true, 4, 0, 0, NULL, C_Sparky, R_Sparky, &s_sparkyspeed4};\r
+statetype s_sparkyspeed4 = {SPARKYWALKL4SPR, SPARKYWALKR4SPR, step, true, true, 4, 0, 0, T_ChargeCount, C_Sparky, R_Sparky, &s_sparkyspeed1};\r
+statetype s_sparkycharge1 = {SPARKYWALKL1SPR, SPARKYWALKR1SPR, step, true, true, 4, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkycharge2};\r
+statetype s_sparkycharge2 = {SPARKYWALKL2SPR, SPARKYWALKR2SPR, step, true, true, 4, 128, 0, T_RunSnd1, C_Sparky, R_Sparky, &s_sparkycharge3};\r
+statetype s_sparkycharge3 = {SPARKYWALKL3SPR, SPARKYWALKR3SPR, step, true, true, 4, 128, 0, NULL, C_Sparky, R_Sparky, &s_sparkycharge4};\r
+statetype s_sparkycharge4 = {SPARKYWALKL4SPR, SPARKYWALKR4SPR, step, true, true, 4, 128, 0, T_RunSnd2, C_Sparky, R_Sparky, &s_sparkycharge1};\r
+statetype s_sparkyturn1 = {SPARKYTURN3SPR, SPARKYTURN1SPR, step, false, true, 8, 0, 0, NULL, C_Sparky, R_Draw, &s_sparkyturn2};\r
+statetype s_sparkyturn2 = {SPARKYTURN2SPR, SPARKYTURN2SPR, step, false, true, 8, 0, 0, NULL, C_Sparky, R_Draw, &s_sparkyturn3};\r
+statetype s_sparkyturn3 = {SPARKYTURN1SPR, SPARKYTURN3SPR, step, false, true, 8, 0, 0, NULL, C_Sparky, R_Draw, &s_sparkywalk1};\r
+statetype s_sparkystun = {SPARKYSTUNSPR, SPARKYSTUNSPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnSparky\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnSparky(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = sparkyobj;\r
+ new->active = ac_yes;\r
+ new->priority = 0;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -1*TILEGLOBAL;\r
+ if (US_RndT() < 0x80)\r
+ {\r
+ new->xdir = 1;\r
+ }\r
+ else\r
+ {\r
+ new->xdir = -1;\r
+ }\r
+ new->ydir = 1;\r
+ NewState(new, &s_sparkywalk1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Sparky\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Sparky(objtype *ob)\r
+{\r
+ if (US_RndT() < 0x40)\r
+ {\r
+ ob->state = &s_sparkylook1;\r
+ xtry = 0;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_ChargeCount\r
+=\r
+===========================\r
+*/\r
+\r
+void T_ChargeCount(objtype *ob)\r
+{\r
+ if (--ob->temp1 == 0)\r
+ ob->state = &s_sparkycharge1;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_SparkyLookL\r
+=\r
+===========================\r
+*/\r
+\r
+void T_SparkyLookL(objtype *ob)\r
+{\r
+ Uint16 dist = player->bottom + TILEGLOBAL - ob->bottom;\r
+ if (dist > 2*TILEGLOBAL)\r
+ return;\r
+\r
+ if (player->x < ob->x)\r
+ { \r
+ ob->xdir = -1;\r
+ SD_PlaySound(SND_SPARKYCHARGE);\r
+ ob->state = &s_sparkyspeed1;\r
+ ob->temp1 = 3;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_SparkyLookR\r
+=\r
+===========================\r
+*/\r
+\r
+void T_SparkyLookR(objtype *ob)\r
+{\r
+ Uint16 dist = player->bottom + TILEGLOBAL - ob->bottom;\r
+ if (dist > 2*TILEGLOBAL)\r
+ return;\r
+\r
+ if (player->x > ob->x)\r
+ {\r
+ ob->xdir = 1;\r
+ SD_PlaySound(SND_SPARKYCHARGE);\r
+ ob->state = &s_sparkyspeed1;\r
+ ob->temp1 = 3;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_RunSnd1\r
+=\r
+===========================\r
+*/\r
+\r
+#pragma argsused\r
+void T_RunSnd1(objtype *ob)\r
+{\r
+ SD_PlaySound(SND_WORLDWALK1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_RunSnd2\r
+=\r
+===========================\r
+*/\r
+\r
+#pragma argsused\r
+void T_RunSnd2(objtype *ob)\r
+{\r
+ SD_PlaySound(SND_WORLDWALK1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Sparky\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Sparky(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ }\r
+ else if (hit->obclass == stunshotobj)\r
+ {\r
+ StunObj(ob, hit, &s_sparkystun);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Sparky\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Sparky(objtype *ob)\r
+{\r
+ if (ob->xdir == 1 && ob->hitwest)\r
+ {\r
+ ob->x -= ob->xmove;\r
+ ob->xdir = -1;\r
+ ob->nothink = US_RndT() >> 5;\r
+ ChangeState(ob, &s_sparkyturn1);\r
+ }\r
+ else if (ob->xdir == -1 && ob->hiteast)\r
+ {\r
+ ob->x -= ob->xmove;\r
+ ob->xdir = 1;\r
+ ob->nothink = US_RndT() >> 5;\r
+ ChangeState(ob, &s_sparkyturn1);\r
+ }\r
+ else if (!ob->hitnorth)\r
+ {\r
+ ob->x -= ob->xmove;\r
+ ob->xdir = -ob->xdir;\r
+ ob->nothink = US_RndT() >> 5;\r
+ ChangeState(ob, &s_sparkyturn1);\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LITTLE AMPTON\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_amptonwalk1 = {AMTONWALKL1SPR, AMPTONWALKR1SPR, step, false, true, 8, 128, 0, T_Ampton, C_Ampton, R_Ampton, &s_amptonwalk2};\r
+statetype s_amptonwalk2 = {AMTONWALKL2SPR, AMPTONWALKR2SPR, step, false, true, 8, 128, 0, T_Ampton, C_Ampton, R_Ampton, &s_amptonwalk3};\r
+statetype s_amptonwalk3 = {AMTONWALKL3SPR, AMPTONWALKR3SPR, step, false, true, 8, 128, 0, T_Ampton, C_Ampton, R_Ampton, &s_amptonwalk4};\r
+statetype s_amptonwalk4 = {AMTONWALKL4SPR, AMPTONWALKR4SPR, step, false, true, 8, 128, 0, T_Ampton, C_Ampton, R_Ampton, &s_amptonwalk1};\r
+statetype s_amptonturn = {AMPTONFACESPR, AMPTONFACESPR, step, false, true, 8, 0, 0, NULL, C_Ampton, R_Draw, &s_amptonwalk1};\r
+statetype s_amptongrab1 = {AMPTONGRAB1SPR, AMPTONGRAB1SPR, step, false, true, 8, 0, 0, NULL, C_Ampton, R_Draw, &s_amptongrab2};\r
+statetype s_amptongrab2 = {AMPTONGRAB2SPR, AMPTONGRAB2SPR, step, false, true, 8, 0, 0, NULL, C_Ampton, R_Draw, &s_amptonclimb};\r
+statetype s_amptonclimb = {AMPTONGRAB2SPR, AMPTONGRAB2SPR, slidethink, false, false, 0, 0, 32, T_AmptonClimb, C_Ampton, R_Draw, NULL};\r
+statetype s_amptonrelease1 = {AMPTONGRAB2SPR, AMPTONGRAB2SPR, step, false, false, 8, 0, 0, NULL, C_Ampton, R_Draw, &s_amptonrelease2};\r
+statetype s_amptonrelease2 = {AMPTONGRAB1SPR, AMPTONGRAB1SPR, step, false, false, 8, 0, 0, T_SetNoThink, C_Ampton, R_Draw, &s_amptonwalk1};\r
+statetype s_amptonfiddle1 = {AMPTONGRAB1SPR, AMPTONGRAB1SPR, step, false, true, 12, 0, 0, NULL, C_Ampton, R_Draw, &s_amptonfiddle2};\r
+statetype s_amptonfiddle2 = {AMPTONGRAB2SPR, AMPTONGRAB2SPR, step, false, true, 12, 0, 0, NULL, C_Ampton, R_Draw, &s_amptonfiddle3};\r
+statetype s_amptonfiddle3 = {AMPTONGRAB1SPR, AMPTONGRAB1SPR, step, false, true, 12, 0, 0, NULL, C_Ampton, R_Draw, &s_amptonfiddle4};\r
+statetype s_amptonfiddle4 = {AMPTONGRAB2SPR, AMPTONGRAB2SPR, step, false, true, 12, 0, 0, NULL, C_Ampton, R_Draw, &s_amptonfiddle5};\r
+statetype s_amptonfiddle5 = {AMPTONGRAB1SPR, AMPTONGRAB1SPR, step, false, true, 12, 0, 0, T_SetNoThink, C_Ampton, R_Draw, &s_amptonwalk1};\r
+statetype s_amptonstun = {AMPTONSTUNSPR, AMPTONSTUNSPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnAmpton\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnAmpton(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = amptonobj;\r
+ new->active = ac_yes;\r
+ new->priority = 0;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -8*PIXGLOBAL;\r
+ if (US_RndT() < 0x80)\r
+ {\r
+ new->xdir = 1;\r
+ }\r
+ else\r
+ {\r
+ new->xdir = -1;\r
+ }\r
+ new->ydir = 1;\r
+ NewState(new, &s_amptonwalk1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Ampton\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Ampton(objtype *ob)\r
+{\r
+ Uint16 far *map;\r
+ Uint16 intile, var8;\r
+ boolean poleup, poledown;\r
+\r
+ if (ob->state == &s_amptonwalk1)\r
+ {\r
+ SD_PlaySound(SND_AMPTONWALK1);\r
+ }\r
+ else if (ob->state == &s_amptonwalk3)\r
+ {\r
+ SD_PlaySound(SND_AMPTONWALK2);\r
+ }\r
+ if (ob->x & 0xFF)\r
+ {\r
+ map = mapsegs[1] + mapbwidthtable[ob->tiletop]/2 + ob->tileleft + 1;\r
+ intile = tinf[*map + INTILE] & INTILE_TYPEMASK;\r
+ if (intile == INTILE_AMPTONCOMPUTER)\r
+ {\r
+ ob->state = &s_amptonfiddle1;\r
+ }\r
+ else if (intile == INTILE_POLE && US_RndT() < 196)\r
+ {\r
+ if ((tinf[*(map + mapwidth*2) + INTILE] & INTILE_TYPEMASK) == INTILE_POLE)\r
+ {\r
+ poledown = true;\r
+ }\r
+ else\r
+ {\r
+ poledown = false;\r
+ }\r
+ if ((tinf[*(map - mapwidth*2) + INTILE] & INTILE_TYPEMASK) == INTILE_POLE)\r
+ {\r
+ poleup = true;\r
+ }\r
+ else\r
+ {\r
+ poleup = false;\r
+ }\r
+ if (poleup && poledown)\r
+ {\r
+ if (US_RndT() < 0x80)\r
+ poleup = false;\r
+ else\r
+ poledown = false;\r
+ }\r
+\r
+ if (poleup)\r
+ {\r
+ ob->ydir = -1;\r
+ ob->state = &s_amptongrab1;\r
+ ob->needtoclip = cl_noclip;\r
+ ob->nothink = 6;\r
+ xtry = 0;\r
+ }\r
+ else if (poledown)\r
+ {\r
+ ob->ydir = 1;\r
+ ob->state = &s_amptongrab1;\r
+ ob->needtoclip = cl_noclip;\r
+ ob->nothink = 6;\r
+ xtry = 0;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_AmptonClimb\r
+=\r
+===========================\r
+*/\r
+\r
+void T_AmptonClimb(objtype *ob)\r
+{\r
+ Uint16 newtile;\r
+ Uint16 far *map;\r
+ Uint16 move;\r
+\r
+ newtile = CONVERT_GLOBAL_TO_TILE(ob->bottom + ytry);\r
+ if (ob->tilebottom != newtile)\r
+ {\r
+ if (ob->ydir == -1)\r
+ {\r
+ map = mapsegs[1] + mapbwidthtable[newtile]/2 + ob->tileleft + 1;\r
+ if (!tinf[map[0] + NORTHWALL] && tinf[map[mapwidth]+NORTHWALL])\r
+ {\r
+ if ((tinf[*(map-4*mapwidth)+INTILE] & INTILE_TYPEMASK) == INTILE_POLE && US_RndT() < 0x80)\r
+ return;\r
+\r
+ move = (ob->bottom & 0xFF) + 1;\r
+ ob->y -= move;\r
+ ob->bottom -= move;\r
+ ob->needtoclip = cl_midclip;\r
+ ob->state = &s_amptonrelease1;\r
+ ytry = PIXGLOBAL;\r
+ ob->ydir = 1;\r
+ ClipToWalls(ob);\r
+ ob->nothink = 4;\r
+ return;\r
+ }\r
+ if ((tinf[*(map-mapwidth)+INTILE] & INTILE_TYPEMASK) != INTILE_POLE)\r
+ {\r
+ ytry = 0;\r
+ ob->ydir = 1;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ map = mapsegs[1] + mapbwidthtable[newtile]/2 + ob->tileleft + 1;\r
+ if (tinf[map[0] + NORTHWALL] && !tinf[*(map-mapwidth)+NORTHWALL])\r
+ {\r
+ if ((tinf[map[2*mapwidth] + INTILE] & INTILE_TYPEMASK) == INTILE_POLE && US_RndT() < 0x80)\r
+ return;\r
+\r
+ move = 0xFF - (ob->bottom & 0xFF);\r
+ ob->y += move;\r
+ ob->bottom += move;\r
+ ob->needtoclip = cl_midclip;\r
+ ob->state = &s_amptonrelease1;\r
+ ytry = PIXGLOBAL;\r
+ ClipToWalls(ob);\r
+ ob->nothink = 4;\r
+ return;\r
+ }\r
+ if ((tinf[map[0] + INTILE] & INTILE_TYPEMASK) != INTILE_POLE)\r
+ {\r
+ ytry = 0;\r
+ ob->ydir = -1;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_SetNoThink\r
+=\r
+===========================\r
+*/\r
+\r
+void T_SetNoThink(objtype *ob)\r
+{\r
+ ob->nothink = 4;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Ampton\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Ampton(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj)\r
+ {\r
+ if (ob->state == &s_amptonclimb)\r
+ {\r
+ KillKeen();\r
+ }\r
+ else\r
+ {\r
+ ClipToSpriteSide(hit, ob);\r
+ }\r
+ }\r
+ else if (hit->obclass == stunshotobj)\r
+ {\r
+ ob->needtoclip = cl_midclip;\r
+ ob->ydir = 1;\r
+ ob->yspeed = 0;\r
+ SD_PlaySound(SND_AMPTONDIE);\r
+ StunObj(ob, hit, &s_amptonstun);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Ampton\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Ampton(objtype *ob)\r
+{\r
+ if (ob->xdir == 1 && ob->hitwest)\r
+ {\r
+ ob->x -= ob->xmove;\r
+ ob->xdir = -1;\r
+ ChangeState(ob, &s_amptonturn);\r
+ }\r
+ else if (ob->xdir == -1 && ob->hiteast)\r
+ {\r
+ ob->x -= ob->xmove;\r
+ ob->xdir = 1;\r
+ ChangeState(ob, &s_amptonturn);\r
+ }\r
+ else if (!ob->hitnorth)\r
+ {\r
+ ob->x -= ob->xmove;\r
+ ob->xdir = -ob->xdir;\r
+ ChangeState(ob, &s_amptonturn);\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SLICESTAR\r
+\r
+temp4 = health\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_slicestarslide = {SLICESTARSPR, SLICESTARSPR, think, false, false, 0, 0, 0, T_Platform, C_Slicestar, R_Draw, NULL};\r
+statetype s_slicestarbounce = {SLICESTARSPR, SLICESTARSPR, slide, false, false, 0, 24, 24, NULL, C_Slicestar, R_Slicestar, &s_slicestarbounce};\r
+statetype s_slicestarboom = {SLICESTARBOOMSPR, SLICESTARBOOMSPR, step, false, false, 20, 0, 0, NULL, NULL, R_Draw, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnSlicestarSlide\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnSlicestarSlide(Uint16 tileX, Uint16 tileY, Sint16 dir)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = slicestarobj;\r
+ new->active = ac_yes;\r
+ new->priority = 2;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY);\r
+ new->temp4 = 20; // health!\r
+ switch (dir)\r
+ {\r
+ case 0:\r
+ new->xdir = 0;\r
+ new->ydir = -1;\r
+ break;\r
+ case 1:\r
+ new->xdir = 1;\r
+ new->ydir = 0;\r
+ break;\r
+ case 2:\r
+ new->xdir = 0;\r
+ new->ydir = 1;\r
+ break;\r
+ case 3:\r
+ new->xdir = -1;\r
+ new->ydir = 0;\r
+ }\r
+ NewState(new, &s_slicestarslide);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnSlicestarBounce\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnSlicestarBounce(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = slicestarobj;\r
+ new->active = ac_yes;\r
+ new->priority = 2;\r
+ new->needtoclip = cl_fullclip;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY);\r
+ new->temp4 = 50; // health!\r
+ switch (US_RndT() / 0x40)\r
+ {\r
+ case 0:\r
+ new->xdir = -1;\r
+ new->ydir = -1;\r
+ break;\r
+ case 1:\r
+ new->xdir = 1;\r
+ new->ydir = 1;\r
+ break;\r
+ case 2:\r
+ new->xdir = -1;\r
+ new->ydir = 1;\r
+ break;\r
+ case 3:\r
+ new->xdir = 1;\r
+ new->ydir = -1;\r
+ }\r
+ NewState(new, &s_slicestarbounce);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Slicestar\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Slicestar(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ }\r
+ else if (hit->obclass == stunshotobj)\r
+ {\r
+ ExplodeShot(hit);\r
+ if (--ob->temp4 == 0)\r
+ {\r
+ ChangeState(ob, &s_slicestarboom);\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Slicestar\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Slicestar(objtype *ob)\r
+{\r
+ if (ob->hitnorth)\r
+ {\r
+ ob->ydir = -1;\r
+ SD_PlaySound(SND_SLICESTARBOUNCE);\r
+ }\r
+ else if (ob->hitsouth)\r
+ {\r
+ ob->ydir = 1;\r
+ SD_PlaySound(SND_SLICESTARBOUNCE);\r
+ }\r
+ if (ob->hitwest)\r
+ {\r
+ ob->xdir = -1;\r
+ SD_PlaySound(SND_SLICESTARBOUNCE);\r
+ }\r
+ else if (ob->hiteast)\r
+ {\r
+ ob->xdir = 1;\r
+ SD_PlaySound(SND_SLICESTARBOUNCE);\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SHELLEY\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_shellywalk1 = {SHELLEYL1SPR, SHELLEYR1SPR, step, false, true, 8, 128, 0, NULL, C_Shelly, R_Shelly, &s_shellywalk2};\r
+statetype s_shellywalk2 = {SHELLEYL2SPR, SHELLEYR2SPR, step, false, true, 8, 128, 0, NULL, C_Shelly, R_Shelly, &s_shellywalk3};\r
+statetype s_shellywalk3 = {SHELLEYL3SPR, SHELLEYR3SPR, step, false, true, 8, 128, 0, NULL, C_Shelly, R_Shelly, &s_shellywalk4};\r
+statetype s_shellywalk4 = {SHELLEYL4SPR, SHELLEYR4SPR, step, false, true, 8, 128, 0, NULL, C_Shelly, R_Shelly, &s_shellywalk1};\r
+statetype s_shellylook = {SHELLEYL2SPR, SHELLEYR2SPR, stepthink, false, true, 100, 0, 0, T_ShellyLook, C_Shelly, R_Draw, &s_shellylook2};\r
+statetype s_shellylook2 = {SHELLEYL2SPR, SHELLEYR2SPR, step, true, true, 1, 0, 0, T_Turn, C_Shelly, R_Draw, &s_shellywalk1};\r
+statetype s_shellyjump1 = {SHELLEYJUMPLSPR, SHELLEYJUMPRSPR, stepthink, false, false, 8, 0, 0, T_Projectile, C_Shelly, R_Shell, &s_shellyjump2};\r
+statetype s_shellyjump2 = {SHELLEYFALLLSPR, SHELLEYFALLRSPR, think, false, false, 8, 0, 0, T_Projectile, C_Shelly, R_Shell, NULL};\r
+statetype s_shellydie = {SHELLEYFALLLSPR, SHELLEYFALLRSPR, step, false, false, 8, 0, 0, T_ShellyFrag, NULL, R_Shell, NULL};\r
+statetype s_shellydieup = {SHELLEYL2SPR, SHELLEYR2SPR, step, false, false, 8, 0, 0, T_ShellyFrag, NULL, R_Shell, NULL};\r
+statetype s_shellyboom1 = {SHELLEYBOOM1SPR, SHELLEYBOOM1SPR, step, false, false, 20, 0, 0, NULL, C_Lethal, R_Draw, &s_shellyboom2};\r
+statetype s_shellyboom2 = {SHELLEYBOOM2SPR, SHELLEYBOOM2SPR, step, false, false, 20, 0, 0, NULL, C_Lethal, R_Draw, &s_shellyboom3};\r
+statetype s_shellyboom3 = {SHELLEYBOOM3SPR, SHELLEYBOOM3SPR, step, false, false, 20, 0, 0, NULL, C_Lethal, R_Draw, &s_shellyboom4};\r
+statetype s_shellyboom4 = {SHELLEYBOOM4SPR, SHELLEYBOOM4SPR, step, false, false, 20, 0, 0, NULL, C_Lethal, R_Draw, NULL};\r
+statetype s_shellypiece1 = {SHELLEYPIECE1SPR, SHELLEYPIECE1SPR, think, false, false, 8, 0, 0, T_Projectile, C_Lethal, R_Bounce, NULL};\r
+statetype s_shellypiece2 = {SHELLEYPIECE2SPR, SHELLEYPIECE2SPR, think, false, false, 8, 0, 0, T_Projectile, C_Lethal, R_Bounce, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnShelly\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnShelly(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = sparkyobj; // BUG: should use shelleyobj\r
+ new->active = ac_yes;\r
+ new->priority = 0;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY);\r
+ if (US_RndT() < 0x80)\r
+ {\r
+ new->xdir = 1;\r
+ }\r
+ else\r
+ {\r
+ new->xdir = -1;\r
+ }\r
+ new->ydir = 1;\r
+ NewState(new, &s_shellywalk1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_ShellyLook\r
+=\r
+===========================\r
+*/\r
+\r
+void T_ShellyLook(objtype *ob)\r
+{\r
+ Sint16 xdist;\r
+\r
+ if (player->top < ob->bottom)\r
+ return;\r
+\r
+ xdist = player->midx - ob->midx;\r
+ if (ob->xdir == 1)\r
+ {\r
+ if (xdist > 1*TILEGLOBAL && xdist < 3*TILEGLOBAL)\r
+ {\r
+ ob->xspeed = 16;\r
+ ob->yspeed = -24;\r
+ ob->state = &s_shellyjump1;\r
+ xtry = ytry = 0;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (xdist < -1*TILEGLOBAL && xdist > -3*TILEGLOBAL)\r
+ {\r
+ ob->xspeed = -16;\r
+ ob->yspeed = -24;\r
+ ob->state = &s_shellyjump1;\r
+ xtry = ytry = 0;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Turn\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Turn(objtype *ob)\r
+{\r
+ ob->xdir = -ob->xdir;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_ShellyFrag\r
+=\r
+===========================\r
+*/\r
+\r
+void T_ShellyFrag(objtype *ob)\r
+{\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ new->xspeed = 32;\r
+ new->yspeed = -24;\r
+ NewState(new, &s_shellypiece1);\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ new->xspeed = -32;\r
+ new->yspeed = -24;\r
+ NewState(new, &s_shellypiece2);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Shelly\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Shelly(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj)\r
+ {\r
+ ClipToSpriteSide(hit, ob);\r
+ if (player->midx < ob->left || player->midx > ob->right)\r
+ return;\r
+ }\r
+ else if (hit->obclass == stunshotobj)\r
+ {\r
+ ExplodeShot(hit);\r
+ }\r
+ else if (hit->obclass == mshotobj)\r
+ {\r
+ RemoveObj(hit);\r
+ }\r
+ else\r
+ return;\r
+\r
+explode:\r
+ SD_PlaySound(SND_SHELLEYEXPLODE);\r
+ if (ob->hitnorth)\r
+ {\r
+ ChangeState(ob, &s_shellydieup);\r
+ }\r
+ else\r
+ {\r
+ ChangeState(ob, &s_shellydie);\r
+ }\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ NewState(new, &s_shellyboom1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Shelly\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Shelly(objtype *ob)\r
+{\r
+ if (ob->xdir == 1 && ob->hitwest)\r
+ {\r
+ ob->x -= ob->xmove;\r
+ ob->xdir = -1;\r
+ }\r
+ else if (ob->xdir == -1 && ob->hiteast)\r
+ {\r
+ ob->x -= ob->xmove;\r
+ ob->xdir = 1;\r
+ }\r
+ else if (!ob->hitnorth)\r
+ {\r
+ ob->x -= ob->xmove;\r
+ ChangeState(ob, &s_shellylook);\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Shell\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Shell(objtype *ob)\r
+{\r
+ if (ob->hiteast || ob->hitwest)\r
+ {\r
+ ob->xspeed = 0;\r
+ }\r
+ if (ob->hitnorth)\r
+ {\r
+ SD_PlaySound(SND_SHELLEYEXPLODE);\r
+ ChangeState(ob, &s_shellydie);\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ NewState(new, &s_shellyboom1);\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}
\ No newline at end of file