--- /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_ACT3.C\r
+=========\r
+\r
+Contains the following actor types (in this order):\r
+\r
+- Shikadi Mine\r
+- Robo Red\r
+- Spirogrip\r
+- Spindred\r
+- Shikadi Master\r
+- Shikadi\r
+- Shockshund\r
+- Sphereful\r
+- Scottie\r
+- QED\r
+\r
+*/\r
+\r
+#include "CK_DEF.H"\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SHIKADI MINE\r
+\r
+temp2 = x position of the "eye", in global units (relative to the mine sprite)\r
+temp3 = y position of the "eye", in global units (relative to the mine sprite)\r
+temp4 = sprite pointer for the "eye"\r
+\r
+=============================================================================\r
+*/\r
+\r
+static Uint16 dopposite[] = {2, 3, 0, 1, 6, 7, 4, 5, 8};\r
+\r
+statetype s_mine = {SHIKADIMINESPR, SHIKADIMINESPR, think, false, false, 8, 0, 0, T_Mine, C_Solid, R_Mine, NULL};\r
+statetype s_minecenter = {SHIKADIMINESPR, SHIKADIMINESPR, think, false, false, 0, 0, 0, T_MineCenter, C_Solid, R_Mine, &s_mineshift};\r
+statetype s_mineshift = {SHIKADIMINESPR, SHIKADIMINESPR, think, false, false, 0, 0, 0, T_MineShift, C_Solid, R_Mine, &s_mine};\r
+statetype s_mineboom1 = {SHIKADIMINEPULSE1SPR, SHIKADIMINEPULSE1SPR, step, false, false, 10, 0, 0, NULL, C_Solid, R_Draw, &s_mineboom2};\r
+statetype s_mineboom2 = {SHIKADIMINEPULSE2SPR, SHIKADIMINEPULSE2SPR, step, false, false, 10, 0, 0, NULL, C_Solid, R_Draw, &s_mineboom3};\r
+statetype s_mineboom3 = {SHIKADIMINEPULSE1SPR, SHIKADIMINEPULSE1SPR, step, false, false, 10, 0, 0, NULL, C_Solid, R_Draw, &s_mineboom4};\r
+statetype s_mineboom4 = {SHIKADIMINEPULSE2SPR, SHIKADIMINEPULSE2SPR, step, false, false, 10, 0, 0, T_MineFrag, C_Solid, R_Draw, &s_mineboom5};\r
+statetype s_mineboom5 = {SHIKADIMINEBOOM1SPR, SHIKADIMINEBOOM1SPR, step, false, false, 20, 0, 0, NULL, C_Spindread, R_Draw, &s_mineboom6};\r
+statetype s_mineboom6 = {SHIKADIMINEBOOM2SPR, SHIKADIMINEBOOM2SPR, step, false, false, 20, 0, 0, NULL, C_Spindread, R_Draw, NULL};\r
+statetype s_minepiece = {SHIKADIMINEPIECESPR, SHIKADIMINEPIECESPR, think, false, false, 8, 0, 0, T_Projectile, C_MineFrag, R_Bounce, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnMine\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnMine(Uint16 tileX, Uint16 tileY)\r
+{\r
+ Sint16 i;\r
+\r
+ GetNewObj(false);\r
+ new->obclass = mineobj;\r
+ new->active = ac_yes;\r
+ new->needtoclip = cl_noclip;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -(31*PIXGLOBAL + 1);\r
+ new->temp2 = 16*PIXGLOBAL;\r
+ new->temp3 = 13*PIXGLOBAL;\r
+ NewState(new, &s_mineshift);\r
+ new->xspeed = TILEGLOBAL;\r
+\r
+ for (i=0; i<=3; i++)\r
+ {\r
+ if (Walk(new, i))\r
+ break;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= MinePosCheck\r
+=\r
+===========================\r
+*/\r
+\r
+boolean MinePosCheck(Uint16 tileX, Uint16 tileY)\r
+{\r
+ Uint16 far *map;\r
+ Uint16 x, y, tile;\r
+\r
+ map = mapsegs[1] + mapbwidthtable[tileY]/2 + tileX;\r
+ for (y=0; y<2; y++)\r
+ {\r
+ for (x=0; x<3; x++)\r
+ {\r
+ tile = *(map + y*mapwidth + x);\r
+ if (tinf[tile+NORTHWALL] || tinf[tile+EASTWALL] || tinf[tile+SOUTHWALL] || tinf[tile+WESTWALL])\r
+ return false;\r
+ }\r
+ }\r
+ return true;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= Walk\r
+=\r
+===========================\r
+*/\r
+\r
+boolean Walk(objtype *ob, Sint16 dir)\r
+{\r
+ Uint16 tileX, tileY;\r
+\r
+ tileX = CONVERT_GLOBAL_TO_TILE(ob->x + xtry);\r
+ tileY = CONVERT_GLOBAL_TO_TILE(ob->y + ytry);\r
+\r
+ switch (dir)\r
+ {\r
+ case 0:\r
+ if (MinePosCheck(tileX, tileY-1))\r
+ {\r
+ ob->xdir = 0;\r
+ ob->ydir = -1;\r
+ return true;\r
+ }\r
+ return false;\r
+ case 1:\r
+ if (MinePosCheck(tileX+1, tileY))\r
+ {\r
+ ob->xdir = 1;\r
+ ob->ydir = 0;\r
+ return true;\r
+ }\r
+ return false;\r
+ case 2:\r
+ if (MinePosCheck(tileX, tileY+1))\r
+ {\r
+ ob->xdir = 0;\r
+ ob->ydir = 1;\r
+ return true;\r
+ }\r
+ return false;\r
+ case 3:\r
+ if (MinePosCheck(tileX-1, tileY))\r
+ {\r
+ ob->xdir = -1;\r
+ ob->ydir = 0;\r
+ return true;\r
+ }\r
+ return false;\r
+ default:\r
+ Quit("Walk: Bad dir");\r
+ }\r
+ return false;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= ChaseThink\r
+=\r
+===========================\r
+*/\r
+\r
+void ChaseThink(objtype *ob)\r
+{\r
+ Sint16 temp;\r
+ Sint16 xdist, ydist, ydir, xdir;\r
+ Sint16 olddir[2], oppdir;\r
+\r
+ if (ob->xdir == 1)\r
+ {\r
+ olddir[0] = 1;\r
+ }\r
+ else if (ob->xdir == -1)\r
+ {\r
+ olddir[0] = 3;\r
+ }\r
+ else if (ob->ydir == -1)\r
+ {\r
+ olddir[0] = 0;\r
+ }\r
+ else if (ob->ydir == 1)\r
+ {\r
+ olddir[0] = 2;\r
+ }\r
+ oppdir = dopposite[olddir[0]];\r
+ xdist = player->x - (ob->x + xtry);\r
+ ydist = player->y - (ob->y + ytry);\r
+ xdir = 8;\r
+ ydir = 8;\r
+ if (xdist > 0)\r
+ {\r
+ xdir = 1;\r
+ }\r
+ if (xdist < 0)\r
+ {\r
+ xdir = 3;\r
+ }\r
+ if (ydist > 0)\r
+ {\r
+ ydir = 2;\r
+ }\r
+ if (ydist < 0)\r
+ {\r
+ ydir = 0;\r
+ }\r
+ if (abs(ydist) > abs(xdist))\r
+ {\r
+ temp = xdir;\r
+ xdir = ydir;\r
+ ydir = temp;\r
+ }\r
+ if (xdir == oppdir)\r
+ {\r
+ xdir = 8;\r
+ }\r
+ if (ydir == oppdir)\r
+ {\r
+ ydir = 8;\r
+ }\r
+ if (ydir != 8 && Walk(ob, ydir))\r
+ {\r
+ return;\r
+ }\r
+ if (xdir != 8 && Walk(ob, xdir))\r
+ {\r
+ return;\r
+ }\r
+ if (Walk(ob, olddir[0]))\r
+ {\r
+ return;\r
+ }\r
+ if (US_RndT() > 0x80)\r
+ {\r
+ for (temp=0; temp<=3; temp++)\r
+ {\r
+ if (temp != oppdir && Walk(ob, temp))\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ for (temp=3; temp>=0; temp--)\r
+ {\r
+ if (temp != oppdir && Walk(ob, temp))\r
+ return;\r
+ }\r
+ }\r
+ Walk(ob, oppdir);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Mine\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Mine(objtype *ob)\r
+{\r
+ Sint16 oldxdir, oldydir;\r
+ Sint16 xdist, ydist;\r
+ Sint16 speed;\r
+\r
+ xdist = ob->x - player->x;\r
+ ydist = ob->y - player->y;\r
+ if (xdist <= 2*TILEGLOBAL && xdist >= -5*TILEGLOBAL && ydist <= 3*TILEGLOBAL && ydist >= -5*PIXGLOBAL)\r
+ {\r
+ SD_PlaySound(SND_MINEEXPLODE);\r
+ ob->state = &s_mineboom1;\r
+ RF_RemoveSprite((void**)(&ob->temp4));\r
+ }\r
+ else\r
+ {\r
+ speed = tics * 10;\r
+ if (ob->xspeed <= speed)\r
+ {\r
+ xtry = ob->xdir * ob->xspeed;\r
+ ytry = ob->ydir * ob->xspeed; // yes, this uses xspeed!\r
+ speed -= ob->xspeed;\r
+ oldxdir = ob->xdir;\r
+ oldydir = ob->ydir;\r
+ ChaseThink(ob);\r
+ ob->xspeed = TILEGLOBAL;\r
+ if (ob->xdir != oldxdir || ob->ydir != oldydir)\r
+ {\r
+ ob->state = &s_minecenter;\r
+ return;\r
+ }\r
+ }\r
+ ob->xspeed -= speed;\r
+ xtry += ob->xdir * speed;\r
+ ytry += ob->ydir * speed;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Solid\r
+=\r
+===========================\r
+*/\r
+\r
+#pragma argsused\r
+void C_Solid(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == stunshotobj)\r
+ {\r
+ ExplodeShot(hit);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_MineFrag\r
+=\r
+===========================\r
+*/\r
+\r
+#pragma argsused\r
+void C_MineFrag(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == stunshotobj)\r
+ {\r
+ ExplodeShot(hit);\r
+ }\r
+ else if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ }\r
+ else if (hit->obclass == qedobj)\r
+ {\r
+ SpawnFuseFlash(hit->tileleft, hit->tiletop);\r
+ SpawnFuseFlash(hit->tileright, hit->tiletop);\r
+ SpawnFuseFlash(hit->tileleft, hit->tilebottom);\r
+ SpawnFuseFlash(hit->tileright, hit->tilebottom);\r
+ RF_MapToMap(0, 0, 16, 11, 4, 2);\r
+ RF_MapToMap(4, 0, 16, 13, 4, 2);\r
+ SpawnDeadMachine();\r
+ RemoveObj(hit);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_MineCenter\r
+=\r
+===========================\r
+*/\r
+\r
+void T_MineCenter(objtype *ob)\r
+{\r
+ Sint16 px, py, xdist, ydist;\r
+\r
+ xdist = ob->x - player->x;\r
+ ydist = ob->y - player->y;\r
+\r
+ if (xdist <= 2*TILEGLOBAL && xdist >= -3*TILEGLOBAL && ydist <= 3*TILEGLOBAL && ydist >= -3*TILEGLOBAL)\r
+ {\r
+ //BUG? this doesn't play a sound\r
+ ob->state = &s_mineboom1;\r
+ RF_RemoveSprite((void**)&ob->temp4);\r
+ }\r
+ else\r
+ {\r
+ ob->needtoreact = true;\r
+\r
+ px = 16*PIXGLOBAL;\r
+ py = 13*PIXGLOBAL;\r
+\r
+ if (ob->temp2 < px)\r
+ {\r
+ ob->temp2 = ob->temp2 + tics*4;\r
+ if (ob->temp2 >= px)\r
+ {\r
+ ob->temp2 = px;\r
+ ob->state = ob->state->nextstate;\r
+ }\r
+ }\r
+ else if (ob->temp2 > px)\r
+ {\r
+ ob->temp2 = ob->temp2 - tics*4;\r
+ if (ob->temp2 <= px)\r
+ {\r
+ ob->temp2 = px;\r
+ ob->state = ob->state->nextstate;\r
+ }\r
+ }\r
+ if (ob->temp3 < py)\r
+ {\r
+ ob->temp3 = ob->temp3 + tics*4;\r
+ if (ob->temp3 >= py)\r
+ {\r
+ ob->temp3 = py;\r
+ ob->state = ob->state->nextstate;\r
+ }\r
+ }\r
+ else if (ob->temp3 > py)\r
+ {\r
+ ob->temp3 = ob->temp3 - tics*4;\r
+ if (ob->temp3 <= py)\r
+ {\r
+ ob->temp3 = py;\r
+ ob->state = ob->state->nextstate;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_MineShift\r
+=\r
+===========================\r
+*/\r
+\r
+void T_MineShift(objtype *ob)\r
+{\r
+ Sint16 px, py, xdist, ydist;\r
+\r
+ xdist = ob->x - player->x;\r
+ ydist = ob->y - player->y;\r
+\r
+ if (xdist <= 2*TILEGLOBAL && xdist >= -3*TILEGLOBAL && ydist <= 3*TILEGLOBAL && ydist >= -3*TILEGLOBAL)\r
+ {\r
+ //BUG? this doesn't play a sound\r
+ ob->state = &s_mineboom1;\r
+ RF_RemoveSprite((void**)&ob->temp4);\r
+ }\r
+ else\r
+ {\r
+ ob->needtoreact = true;\r
+\r
+ switch (ob->xdir)\r
+ {\r
+ case -1:\r
+ px = 8*PIXGLOBAL;\r
+ break;\r
+ case 0:\r
+ px = 16*PIXGLOBAL;\r
+ break;\r
+ case 1:\r
+ px = 24*PIXGLOBAL;\r
+ }\r
+ switch (ob->ydir)\r
+ {\r
+ case -1:\r
+ py = 5*PIXGLOBAL;\r
+ break;\r
+ case 0:\r
+ py = 13*PIXGLOBAL;\r
+ break;\r
+ case 1:\r
+ py = 21*PIXGLOBAL;\r
+ }\r
+\r
+ if (ob->temp2 < px)\r
+ {\r
+ ob->temp2 = ob->temp2 + tics*4;\r
+ if (ob->temp2 >= px)\r
+ {\r
+ ob->temp2 = px;\r
+ ob->state = ob->state->nextstate;\r
+ }\r
+ }\r
+ else if (ob->temp2 > px)\r
+ {\r
+ ob->temp2 = ob->temp2 - tics*4;\r
+ if (ob->temp2 <= px)\r
+ {\r
+ ob->temp2 = px;\r
+ ob->state = ob->state->nextstate;\r
+ }\r
+ }\r
+ if (ob->temp3 < py)\r
+ {\r
+ ob->temp3 = ob->temp3 + tics*4;\r
+ if (ob->temp3 >= py)\r
+ {\r
+ ob->temp3 = py;\r
+ ob->state = ob->state->nextstate;\r
+ }\r
+ }\r
+ else if (ob->temp3 > py)\r
+ {\r
+ ob->temp3 = ob->temp3 - tics*4;\r
+ if (ob->temp3 <= py)\r
+ {\r
+ ob->temp3 = py;\r
+ ob->state = ob->state->nextstate;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_MineFrag\r
+=\r
+===========================\r
+*/\r
+\r
+void T_MineFrag(objtype *ob)\r
+{\r
+ SD_PlaySound(SND_MINEEXPLODE);\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ new->xspeed = -(US_RndT()>>3);\r
+ new->yspeed = -48;\r
+ NewState(new, &s_minepiece);\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x + TILEGLOBAL;\r
+ new->y = ob->y;\r
+ new->xspeed = (US_RndT()>>3);\r
+ new->yspeed = -48;\r
+ NewState(new, &s_minepiece);\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ new->xspeed = (US_RndT()>>4) + 40;\r
+ new->yspeed = -24;\r
+ NewState(new, &s_minepiece);\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x + TILEGLOBAL;\r
+ new->y = ob->y;\r
+ new->xspeed = -40 - (US_RndT()>>4);\r
+ new->yspeed = -24;\r
+ NewState(new, &s_minepiece);\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ new->xspeed = 24;\r
+ new->yspeed = 16;\r
+ NewState(new, &s_minepiece);\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x + TILEGLOBAL;\r
+ new->y = ob->y;\r
+ new->xspeed = 24;\r
+ new->yspeed = 16;\r
+ NewState(new, &s_minepiece);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Mine\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Mine(objtype *ob)\r
+{\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+ RF_PlaceSprite((void**)&ob->temp4, ob->x+ob->temp2, ob->y+ob->temp3, SHIKADIMINEEYESPR, spritedraw, 2);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ ROBO RED\r
+\r
+temp1 = number of shots to fire\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_robored = {ROBOREDLSPR, ROBOREDRSPR, step, false, true, 6, 64, 0, T_RoboRed, C_RoboRed, R_Walk, &s_robored};\r
+statetype s_roboredfire0 = {ROBOREDLSPR, ROBOREDRSPR, step, true, true, 40, 0, 0, NULL, C_Spindread, R_Draw, &s_roboredfire1};\r
+statetype s_roboredfire1 = {ROBOREDLSPR, ROBOREDRSPR, step, true, true, 4, 64, 0, NULL, C_Spindread, R_Draw, &s_roboredfire2};\r
+statetype s_roboredfire2 = {ROBOREDLSPR, ROBOREDRSPR, step, false, true, 6, 0, 0, T_RoboShoot, C_Spindread, R_Draw, &s_roboredfire1};\r
+statetype s_rshot1 = {ROBOSHOT1SPR, ROBOSHOT1SPR, stepthink, false, false, 8, 0, 0, T_Velocity, C_RShot, R_RShot, &s_rshot2};\r
+statetype s_rshot2 = {ROBOSHOT2SPR, ROBOSHOT2SPR, stepthink, false, false, 8, 0, 0, T_Velocity, C_RShot, R_RShot, &s_rshot1};\r
+statetype s_rshothit1 = {ROBOSHOTHIT1SPR, ROBOSHOTHIT1SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_rshothit2};\r
+statetype s_rshothit2 = {ROBOSHOTHIT2SPR, ROBOSHOTHIT2SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnRoboRed\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnRoboRed(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = roboredobj;\r
+ new->active = ac_yes;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -4*TILEGLOBAL;\r
+ if (US_RndT() < 0x80)\r
+ {\r
+ new->xdir = 1;\r
+ }\r
+ else\r
+ {\r
+ new->xdir = -1;\r
+ }\r
+ NewState(new, &s_robored);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_RoboRed\r
+=\r
+===========================\r
+*/\r
+\r
+void T_RoboRed(objtype *ob)\r
+{\r
+ if (!(ob->x & (4*PIXGLOBAL)) && player->bottom > ob->top && player->top < ob->bottom && US_RndT() < 16)\r
+ {\r
+ if (ob->x > player->x)\r
+ {\r
+ ob->xdir = -1;\r
+ }\r
+ else\r
+ {\r
+ ob->xdir = 1;\r
+ }\r
+ ob->temp1 = 10; // shoot 10 times\r
+ ob->state = &s_roboredfire0;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_RoboRed\r
+=\r
+===========================\r
+*/\r
+\r
+void C_RoboRed(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == stunshotobj)\r
+ {\r
+ ExplodeShot(hit);\r
+ ob->xdir = (player->x > ob->x)? 1 : -1;\r
+ ob->temp1 = 10; // shoot 10 times\r
+ ChangeState(ob, &s_roboredfire0);\r
+ }\r
+ else if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_RoboShoot\r
+=\r
+===========================\r
+*/\r
+\r
+void T_RoboShoot(objtype *ob)\r
+{\r
+ Uint16 x;\r
+\r
+ if (--ob->temp1 == 0)\r
+ {\r
+ ob->state = &s_robored;\r
+ }\r
+ if (ob->xdir == 1)\r
+ {\r
+ x = ob->x + 56*PIXGLOBAL;\r
+ }\r
+ else\r
+ {\r
+ x = ob->x;\r
+ }\r
+ if (CheckSpawnShot(x, ob->y + 32*PIXGLOBAL, &s_rshot1) != -1)\r
+ {\r
+ new->xspeed = ob->xdir * 60;\r
+ if (ob->temp1 & 1)\r
+ {\r
+ new->yspeed = 8;\r
+ }\r
+ else\r
+ {\r
+ new->yspeed = -8;\r
+ }\r
+ SD_PlaySound(SND_ENEMYSHOT);\r
+ xtry = (ob->xdir == 1)? -4*PIXGLOBAL : 4*PIXGLOBAL;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_RShot\r
+=\r
+===========================\r
+*/\r
+\r
+void C_RShot(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ ChangeState(ob, &s_rshothit1);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_RShot\r
+=\r
+===========================\r
+*/\r
+\r
+void R_RShot(objtype *ob)\r
+{\r
+ if (ob->hitnorth || ob->hiteast || ob->hitsouth || ob->hitwest)\r
+ {\r
+ SD_PlaySound(SND_ENEMYSHOTEXPLODE);\r
+ ChangeState(ob, &s_rshothit1);\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SPIROGRIP\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_gripsitd = {SPIROSITDSPR, SPIROSITDSPR, step, false, false, 150, 0, 0, NULL, C_Spindread, R_Draw, &s_gripjumpd};\r
+statetype s_gripjumpd = {SPIROSITDSPR, SPIROSITDSPR, slide, false, false, 64, 0, -16, NULL, C_Spindread, R_Draw, &s_gripspin7};\r
+statetype s_gripsitl = {SPIROSITLSPR, SPIROSITLSPR, step, false, false, 150, 0, 0, NULL, C_Spindread, R_Draw, &s_gripjumpl};\r
+statetype s_gripjumpl = {SPIROSITLSPR, SPIROSITLSPR, slide, false, false, 64, 16, 0, NULL, C_Spindread, R_Draw, &s_gripspin1};\r
+statetype s_gripsitr = {SPIROSITRSPR, SPIROSITRSPR, step, false, false, 150, 0, 0, NULL, C_Spindread, R_Draw, &s_gripjumpr};\r
+statetype s_gripjumpr = {SPIROSITRSPR, SPIROSITRSPR, slide, false, false, 64, -16, 0, NULL, C_Spindread, R_Draw, &s_gripspin5};\r
+statetype s_gripsitu = {SPIROSITUSPR, SPIROSITUSPR, step, false, false, 150, 0, 0, NULL, C_Spindread, R_Draw, &s_gripjumpu};\r
+statetype s_gripjumpu = {SPIROSITUSPR, SPIROSITUSPR, slide, false, false, 64, 0, 16, NULL, C_Spindread, R_Draw, &s_gripspin3};\r
+statetype s_gripspin1 = {SPIROSPINULSPR, SPIROSPINULSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_gripspin2};\r
+statetype s_gripspin2 = {SPIROSPINUSPR, SPIROSPINUSPR, step, false, false, 8, 0, 0, T_SpiroLaunch, C_Spindread, R_Draw, &s_gripspin3};\r
+statetype s_gripspin3 = {SPIROSPINURSPR, SPIROSPINURSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_gripspin4};\r
+statetype s_gripspin4 = {SPIROSPINRSPR, SPIROSPINRSPR, step, false, false, 8, 0, 0, T_SpiroLaunch, C_Spindread, R_Draw, &s_gripspin5};\r
+statetype s_gripspin5 = {SPIROSPINDRSPR, SPIROSPINDRSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_gripspin6};\r
+statetype s_gripspin6 = {SPIROSPINDSPR, SPIROSPINDSPR, step, false, false, 8, 0, 0, T_SpiroLaunch, C_Spindread, R_Draw, &s_gripspin7};\r
+statetype s_gripspin7 = {SPIROSPINDLSPR, SPIROSPINDLSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_gripspin8};\r
+statetype s_gripspin8 = {SPIROSPINLSPR, SPIROSPINLSPR, step, false, false, 8, 0, 0, T_SpiroLaunch, C_Spindread, R_Draw, &s_gripspin1};\r
+statetype s_gripflyd = {SPIROSITDSPR, SPIROSITDSPR, slide, false, false, 0, 0, 48, NULL, C_Spindread, R_SpiroFly, &s_gripsitd};\r
+statetype s_gripflyl = {SPIROSITLSPR, SPIROSITLSPR, slide, false, false, 0, -48, 0, NULL, C_Spindread, R_SpiroFly, &s_gripsitl};\r
+statetype s_gripflyr = {SPIROSITRSPR, SPIROSITRSPR, slide, false, false, 0, 48, 0, NULL, C_Spindread, R_SpiroFly, &s_gripsitr};\r
+statetype s_gripflyu = {SPIROSITUSPR, SPIROSITUSPR, slide, false, false, 0, 0, -48, NULL, C_Spindread, R_SpiroFly, &s_gripsitu};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnSpirogrip\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnSpirogrip(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = spirogripobj;\r
+ new->active = ac_yes;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -1*TILEGLOBAL;\r
+ new->xdir = 1;\r
+ new->ydir = 1;\r
+ NewState(new, &s_gripsitd);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_SpiroLaunch\r
+=\r
+===========================\r
+*/\r
+\r
+void T_SpiroLaunch(objtype *ob)\r
+{\r
+ if (US_RndT() <= 20)\r
+ {\r
+ SD_PlaySound(SND_SPIROFLY);\r
+ if (ob->state == &s_gripspin2)\r
+ {\r
+ ob->state = &s_gripflyu;\r
+ }\r
+ else if (ob->state == &s_gripspin4)\r
+ {\r
+ ob->state = &s_gripflyr;\r
+ }\r
+ else if (ob->state == &s_gripspin6)\r
+ {\r
+ ob->state = &s_gripflyd;\r
+ }\r
+ else if (ob->state == &s_gripspin8)\r
+ {\r
+ ob->state = &s_gripflyl;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_SpiroFly\r
+=\r
+===========================\r
+*/\r
+\r
+void R_SpiroFly(objtype *ob)\r
+{\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+ if (ob->hitnorth || ob->hiteast || ob->hitsouth || ob->hitwest)\r
+ {\r
+ ChangeState(ob, ob->state->nextstate);\r
+ SD_PlaySound(SND_SPIROGRAB);\r
+ }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SPINDRED\r
+\r
+temp1 = bounce counter\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_spindred1 = {SPINDRED1SPR, SPINDRED1SPR, stepthink, false, false, 8, 0, 0, T_Spindread, C_Spindread, R_Spindread, &s_spindred2};\r
+statetype s_spindred2 = {SPINDRED2SPR, SPINDRED2SPR, stepthink, false, false, 8, 0, 0, T_Spindread, C_Spindread, R_Spindread, &s_spindred3};\r
+statetype s_spindred3 = {SPINDRED3SPR, SPINDRED3SPR, stepthink, false, false, 8, 0, 0, T_Spindread, C_Spindread, R_Spindread, &s_spindred4};\r
+statetype s_spindred4 = {SPINDRED4SPR, SPINDRED4SPR, stepthink, false, false, 8, 0, 0, T_Spindread, C_Spindread, R_Spindread, &s_spindred1};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnSpindread\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnSpindread(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = spindredobj;\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
+ new->ydir = 1;\r
+ NewState(new, &s_spindred1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Spindread\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Spindread(objtype *ob)\r
+{\r
+ Sint32 i;\r
+\r
+ // BUG: this might be executed twice during the same frame if the\r
+ // object's animation/state changed during that frame, causing the\r
+ // object to move at twice the speed during that frame!\r
+ // To avoid that, return if ytry is not 0.\r
+\r
+ for (i=lasttimecount-tics; i<lasttimecount; i++)\r
+ {\r
+ if (i & 1)\r
+ {\r
+ if (ob->ydir == 1)\r
+ {\r
+ if (ob->yspeed < 0 && ob->yspeed >= -3)\r
+ {\r
+ ytry += ob->yspeed;\r
+ ob->yspeed = 0;\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ ob->yspeed += 3;\r
+ if (ob->yspeed > 70)\r
+ {\r
+ ob->yspeed = 70;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (ob->yspeed > 0 && ob->yspeed <= 3)\r
+ {\r
+ ytry += ob->yspeed;\r
+ ob->yspeed = 0;\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ ob->yspeed -= 3;\r
+ if (ob->yspeed < -70)\r
+ {\r
+ ob->yspeed = -70;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ ytry += ob->yspeed;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Spindread\r
+=\r
+===========================\r
+*/\r
+\r
+#pragma argsused\r
+void C_Spindread(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == stunshotobj)\r
+ {\r
+ ExplodeShot(hit);\r
+ }\r
+ else if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Spindread\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Spindread(objtype *ob)\r
+{\r
+ if (ob->hitsouth)\r
+ {\r
+ ob->yspeed = 0;\r
+ if (ob->ydir == -1)\r
+ {\r
+ if (++ob->temp1 == 3)\r
+ {\r
+ ob->temp1 = 0;\r
+ ob->yspeed = 68;\r
+ ob->ydir = -ob->ydir;\r
+ SD_PlaySound(SND_SPINDREDFLIP);\r
+ }\r
+ else\r
+ {\r
+ SD_PlaySound(SND_SPINDREDBOUNCE);\r
+ ob->yspeed = 40;\r
+ }\r
+ }\r
+ }\r
+ if (ob->hitnorth)\r
+ {\r
+ ob->yspeed = 0;\r
+ if (ob->ydir == 1)\r
+ {\r
+ if (++ob->temp1 == 3)\r
+ {\r
+ ob->temp1 = 0;\r
+ ob->yspeed = -68;\r
+ ob->ydir = -ob->ydir;\r
+ SD_PlaySound(SND_BOUNCE);\r
+ }\r
+ else\r
+ {\r
+ SD_PlaySound(SND_SPINDREDBOUNCE);\r
+ ob->yspeed = -40;\r
+ }\r
+ }\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SHIKADI MASTER\r
+\r
+temp1 = defines next action (0 = shoot, 1 = teleport)\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_master1 = {MASTER1SPR, MASTER1SPR, step, false, false, 8, 0, 0, NULL, C_Master, R_Draw, &s_master2};\r
+statetype s_master2 = {MASTER2SPR, MASTER2SPR, step, false, false, 8, 0, 0, NULL, C_Master, R_Draw, &s_master3};\r
+statetype s_master3 = {MASTER3SPR, MASTER3SPR, step, false, false, 8, 0, 0, NULL, C_Master, R_Draw, &s_master4};\r
+statetype s_master4 = {MASTER4SPR, MASTER4SPR, step, false, false, 8, 0, 0, T_Master, C_Master, R_Draw, &s_master1};\r
+statetype s_mastershoot1 = {SHIKMASTERCASTLSPR, SHIKMASTERCASTRSPR, step, false, false, 30, 0, 0, T_MasterShoot, C_Spindread, R_Draw, &s_mastershoot2};\r
+statetype s_mastershoot2 = {SHIKMASTERCASTLSPR, SHIKMASTERCASTRSPR, step, false, false, 8, 0, 0, NULL, C_Spindread, R_Draw, &s_master1};\r
+statetype s_mastertport1 = {MASTERTELEPORT1SPR, MASTERTELEPORT1SPR, step, false, true, 20, 0, 0, NULL, C_Spindread, R_Draw, &s_mastertport2};\r
+statetype s_mastertport2 = {MASTERTELEPORT2SPR, MASTERTELEPORT2SPR, step, false, true, 20, 0, 0, T_MasterTPort, C_Spindread, R_Draw, &s_mastertport3};\r
+statetype s_mastertport3 = {MASTERTELEPORT2SPR, MASTERTELEPORT2SPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Land, &s_mastertport4};\r
+statetype s_mastertport4 = {MASTERTELEPORT2SPR, MASTERTELEPORT2SPR, step, false, false, 60, 0, 0, NULL, C_Spindread, R_Draw, &s_master1};\r
+statetype s_mshot1 = {MASTERSHOT4SPR, MASTERSHOT1SPR, stepthink, false, false, 8, 0, 0, T_WeakProjectile, C_MShot, R_MShot, &s_mshot2};\r
+statetype s_mshot2 = {MASTERSHOT3SPR, MASTERSHOT2SPR, stepthink, false, false, 8, 0, 0, T_WeakProjectile, C_MShot, R_MShot, &s_mshot3};\r
+statetype s_mshot3 = {MASTERSHOT2SPR, MASTERSHOT3SPR, stepthink, false, false, 8, 0, 0, T_WeakProjectile, C_MShot, R_MShot, &s_mshot4};\r
+statetype s_mshot4 = {MASTERSHOT1SPR, MASTERSHOT4SPR, stepthink, false, false, 8, 0, 0, T_WeakProjectile, C_MShot, R_MShot, &s_mshot1};\r
+statetype s_mspray1 = {MASTERFLOORSPARK1SPR, MASTERFLOORSPARK1SPR, stepthink, false, false, 6, 0, 0, T_Projectile, C_MShot, R_MSpray, &s_mspray2};\r
+statetype s_mspray2 = {MASTERFLOORSPARK2SPR, MASTERFLOORSPARK2SPR, stepthink, false, false, 6, 0, 0, T_Projectile, C_MShot, R_MSpray, &s_mspray3};\r
+statetype s_mspray3 = {MASTERFLOORSPARK3SPR, MASTERFLOORSPARK3SPR, stepthink, false, false, 6, 0, 0, T_Projectile, C_MShot, R_MSpray, &s_mspray4};\r
+statetype s_mspray4 = {MASTERFLOORSPARK4SPR, MASTERFLOORSPARK4SPR, stepthink, false, false, 6, 0, 0, T_Projectile, C_MShot, R_MSpray, &s_mspray1};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnMaster\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnMaster(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = shikadimasterobj;\r
+ new->active = ac_yes;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -24*PIXGLOBAL;\r
+ NewState(new, &s_master1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Master\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Master(objtype *ob)\r
+{\r
+ Sint16 randval;\r
+\r
+ randval = US_RndT();\r
+ if (randval < 0x40)\r
+ {\r
+ if (ob->temp1)\r
+ {\r
+ ob->state = &s_mastertport1;\r
+ ob->temp1 = 0;\r
+ }\r
+ else\r
+ {\r
+ ob->temp1 = 1;\r
+ if (player->x > ob->x)\r
+ {\r
+ ob->xdir = 1;\r
+ }\r
+ else\r
+ {\r
+ ob->xdir = -1;\r
+ }\r
+ ob->state = &s_mastershoot1;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_MasterShoot\r
+=\r
+===========================\r
+*/\r
+\r
+void T_MasterShoot(objtype *ob)\r
+{\r
+ Uint16 x;\r
+\r
+ if (ob->xdir == 1)\r
+ {\r
+ x = ob->x + 16*PIXGLOBAL;\r
+ }\r
+ else\r
+ {\r
+ x = ob->x;\r
+ }\r
+ if (CheckSpawnShot(x, ob->y+8*PIXGLOBAL, &s_mshot1) != -1)\r
+ {\r
+ new->xspeed = ob->xdir * 48;\r
+ new->yspeed = -16;\r
+ SD_PlaySound(SND_MASTERATTACK);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Master\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Master(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == stunshotobj)\r
+ {\r
+ ExplodeShot(hit);\r
+ ob->xdir = (player->x > ob->x)? 1 : -1;\r
+ ob->temp1 = 1;\r
+ ChangeState(ob, &s_mastershoot1);\r
+ }\r
+ else if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_MasterTPort\r
+=\r
+===========================\r
+*/\r
+\r
+void T_MasterTPort(objtype *ob)\r
+{\r
+ Uint16 tile;\r
+ Sint16 tx, ty, redos, oldx, oldy;\r
+\r
+ oldx = ob->x;\r
+ oldy = ob->y;\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ new->xspeed = 48;\r
+ NewState(new, &s_mspray1); // BUG? new object is not made removable\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ new->xspeed = -48;\r
+ NewState(new, &s_mspray1); // BUG? new object is not made removable\r
+\r
+ SD_PlaySound(SND_MASTERBLAST);\r
+\r
+ redos = 0;\r
+redo:\r
+ if (++redos == 10)\r
+ {\r
+ US_RndT(); // call it, but ignore the result\r
+ // probably to avoid repeatedly getting the same same "random" values\r
+ // due to having an even number of US_RndT() calls in this routine and\r
+ // an even number of elements in the random table.\r
+\r
+ ob->state = &s_master1;\r
+ ob->x = oldx - 1;\r
+ ob->y = oldy;\r
+ xtry = 1;\r
+ ytry = 0;\r
+ }\r
+ else\r
+ {\r
+ tx = player->tilemidx - 16 + (US_RndT()>>3);\r
+ ty = player->tilebottom - 16 + (US_RndT()>>3);\r
+ if (tx < 2 || ty < 2 || tx > mapwidth-5 || ty > mapheight-5)\r
+ goto redo;\r
+\r
+\r
+ ob->x = CONVERT_TILE_TO_GLOBAL(tx);\r
+ ob->y = CONVERT_TILE_TO_GLOBAL(ty);\r
+ ob->tileleft = tx-1;\r
+ ob->tileright = tx+4;\r
+ ob->tiletop = ty-1;\r
+ ob->tilebottom = ty+4;\r
+\r
+ {\r
+ Uint16 x, y;\r
+ Uint16 far *map;\r
+ Uint16 mapdelta;\r
+\r
+ map = (Uint16 far *)mapsegs[1] + mapbwidthtable[ob->tiletop]/2 + ob->tileleft;\r
+ mapdelta = mapwidth - (ob->tileright - ob->tileleft + 1);\r
+\r
+ for (y = ob->tiletop; ob->tilebottom >= y; y++, map+=mapdelta)\r
+ {\r
+ for (x = ob->tileleft; ob->tileright >= x; x++)\r
+ {\r
+ tile = *map++;\r
+ if ((tinf[tile+INTILE] & INTILE_FOREGROUND) || tinf[tile+NORTHWALL] || tinf[tile+EASTWALL]\r
+ || tinf[tile+SOUTHWALL] || tinf[tile+WESTWALL])\r
+ {\r
+ goto redo;\r
+ }\r
+ }\r
+ }\r
+ xtry = ytry = 0;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_MShot\r
+=\r
+===========================\r
+*/\r
+\r
+void C_MShot(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ RemoveObj(ob);\r
+ }\r
+ else if (hit->obclass == stunshotobj)\r
+ {\r
+ ExplodeShot(hit);\r
+ RemoveObj(ob);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_MShot\r
+=\r
+===========================\r
+*/\r
+\r
+void R_MShot(objtype *ob)\r
+{\r
+ if (ob->hiteast || ob->hitwest)\r
+ {\r
+ ob->xspeed = -ob->xspeed;\r
+ }\r
+ if (ob->hitsouth)\r
+ {\r
+ ob->yspeed = 0;\r
+ }\r
+ if (ob->hitnorth)\r
+ {\r
+ SD_PlaySound(SND_MASTERATTACK);\r
+ ob->xspeed = 48;\r
+ ChangeState(ob, &s_mspray1);\r
+\r
+ GetNewObj(true);\r
+ new->x = ob->x;\r
+ new->y = ob->y;\r
+ new->xspeed = -48;\r
+ NewState(new, &s_mspray1); // BUG? new object is not made removable\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_MSpray\r
+=\r
+===========================\r
+*/\r
+\r
+void R_MSpray(objtype *ob)\r
+{\r
+ if (ob->hiteast || ob->hitwest)\r
+ {\r
+ RemoveObj(ob);\r
+ }\r
+ else\r
+ {\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+ }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SHIKADI\r
+\r
+temp1 = x tile position of the pole being grabbed (is set but never used)\r
+temp2 = health\r
+temp3 = flash countdown\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_shikadi1 = {SHIKADI1SPR, SHIKADI1SPR, step, false, true, 8, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadi2};\r
+statetype s_shikadi2 = {SHIKADI2SPR, SHIKADI2SPR, step, false, true, 8, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadi3};\r
+statetype s_shikadi3 = {SHIKADI3SPR, SHIKADI3SPR, step, false, true, 8, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadi4};\r
+statetype s_shikadi4 = {SHIKADI4SPR, SHIKADI4SPR, step, false, true, 8, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadiwalk1};\r
+statetype s_shikadiwalk1 = {SHIKADIWALKL1SPR, SHIKADIWALKR1SPR, step, false, true, 8, 128, 0, T_Shikadi, C_Shikadi, R_Shikadi, &s_shikadiwalk2};\r
+statetype s_shikadiwalk2 = {SHIKADIWALKL2SPR, SHIKADIWALKR2SPR, step, false, true, 8, 128, 0, T_Shikadi, C_Shikadi, R_Shikadi, &s_shikadiwalk3};\r
+statetype s_shikadiwalk3 = {SHIKADIWALKL3SPR, SHIKADIWALKR3SPR, step, false, true, 8, 128, 0, T_Shikadi, C_Shikadi, R_Shikadi, &s_shikadiwalk4};\r
+statetype s_shikadiwalk4 = {SHIKADIWALKL4SPR, SHIKADIWALKR4SPR, step, false, true, 8, 128, 0, T_Shikadi, C_Shikadi, R_Shikadi, &s_shikadiwalk1};\r
+statetype s_shikadigrab = {SHIKADIGRABLSPR, SHIKADIGRABRSPR, step, false, true, 20, 0, 0, T_PoleShock, C_Shikadi, R_Shikadi, &s_shikadigrab2};\r
+statetype s_shikadigrab2 = {SHIKADIGRABLSPR, SHIKADIGRABRSPR, step, false, true, 20, 0, 0, NULL, C_Shikadi, R_Shikadi, &s_shikadiwalk1};\r
+statetype s_shikadistun = {SHIKADISTUNSPR, SHIKADISTUNSPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL};\r
+\r
+statetype s_polespark1 = {SHIKADIPOLESPARK1SPR, SHIKADIPOLESPARK1SPR, stepthink, false, false, 0, 0, 0, T_PoleSpark, C_Lethal, R_Draw, &s_polespark2};\r
+statetype s_polespark2 = {SHIKADIPOLESPARK1SPR, SHIKADIPOLESPARK1SPR, stepthink, false, false, 0, 0, 0, T_PoleSpark, C_Lethal, R_Draw, &s_polespark1};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnShikadi\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnShikadi(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = shikadiobj;\r
+ new->active = ac_yes;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -1*TILEGLOBAL;\r
+ new->temp2 = 4; // health\r
+ if (US_RndT() < 0x80)\r
+ {\r
+ new->xdir = 1;\r
+ }\r
+ else\r
+ {\r
+ new->xdir = -1;\r
+ }\r
+ NewState(new, &s_shikadi1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Shikadi\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Shikadi(objtype *ob)\r
+{\r
+ Uint16 tx, tile;\r
+\r
+ if (player->state->contact == &KeenPosContact\r
+ || ob->bottom - player->bottom + TILEGLOBAL <= 2*TILEGLOBAL)\r
+ {\r
+ if (ob->x > player->x + TILEGLOBAL)\r
+ {\r
+ ob->xdir = -1;\r
+ }\r
+ else if (ob->x < player->x - TILEGLOBAL)\r
+ {\r
+ ob->xdir = 1;\r
+ }\r
+ if (ob->xdir == 1)\r
+ {\r
+ tx = ob->tileright;\r
+ }\r
+ else\r
+ {\r
+ tx = ob->tileleft;\r
+ }\r
+\r
+ if (player->tilemidx != tx)\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ if (US_RndT() < 0x10)\r
+ {\r
+ xtry = 0;\r
+ ob->state = &s_shikadi1;\r
+ return;\r
+ }\r
+ if ((ob->x & 0xFF) || !OnScreen(ob))\r
+ return;\r
+\r
+ if (ob->xdir == 1)\r
+ {\r
+ tx = ob->tileright;\r
+ }\r
+ else\r
+ {\r
+ tx = ob->tileleft;\r
+ }\r
+ }\r
+\r
+ tile = *(mapsegs[1]+mapbwidthtable[ob->tiletop]/2 + tx);\r
+ if (tinf[tile+INTILE] == INTILE_POLE)\r
+ {\r
+ ob->temp1 = tx;\r
+ ob->state = &s_shikadigrab;\r
+ xtry = 0;\r
+ SD_PlaySound(SND_SHIKADIATTACK);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Shikadi\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Shikadi(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ }\r
+ if (hit->obclass == stunshotobj)\r
+ {\r
+ if (--ob->temp2 == 0) // handle health\r
+ {\r
+ ob->xspeed = 0;\r
+ ob->yspeed = 0;\r
+ StunObj(ob, hit, &s_shikadistun);\r
+ }\r
+ else\r
+ {\r
+ ob->temp3 = 2; // draw white two times\r
+ ob->needtoreact = true;\r
+ ExplodeShot(hit);\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_PoleShock\r
+=\r
+===========================\r
+*/\r
+\r
+void T_PoleShock(objtype *ob)\r
+{\r
+ Uint16 x;\r
+\r
+ ob->nothink = 2;\r
+ if (ob->xdir == 1)\r
+ {\r
+ x = CONVERT_TILE_TO_GLOBAL(ob->tileright);\r
+ }\r
+ else\r
+ {\r
+ x = CONVERT_TILE_TO_GLOBAL(ob->tileleft);\r
+ }\r
+\r
+ GetNewObj(true);\r
+ new->x = x;\r
+ new->y = ob->y + 8*PIXGLOBAL;\r
+ new->obclass = mshotobj;\r
+ new->active = ac_removable;\r
+ new->needtoclip = cl_noclip;\r
+ NewState(new, &s_polespark1);\r
+ if (ob->y < player->y)\r
+ {\r
+ new->ydir = 1;\r
+ }\r
+ else\r
+ {\r
+ new->ydir = -1;\r
+ }\r
+ SD_PlaySound(SND_SHIKADIATTACK);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_PoleSpark\r
+=\r
+===========================\r
+*/\r
+\r
+void T_PoleSpark(objtype *ob)\r
+{\r
+ Uint16 tile;\r
+\r
+ if (ytry == 0)\r
+ {\r
+ ytry = ob->ydir * 48;\r
+ tile = *(mapsegs[1]+mapbwidthtable[ob->tiletop]/2 + ob->tilemidx);\r
+ if (tinf[tile+INTILE] != INTILE_POLE)\r
+ {\r
+ ob->state = NULL;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Shikadi\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Shikadi(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, ob->state);\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, ob->state);\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, ob->state);\r
+ }\r
+ if (ob->temp3)\r
+ {\r
+ ob->temp3--;\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, maskdraw, ob->priority);\r
+ }\r
+ else\r
+ {\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+ }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ PET (a.k.a. SHOCKSHUND)\r
+\r
+temp1 = countdown for sit animation\r
+temp2 = health\r
+temp3 = flash countdown\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_petsit1 = {PETSIT1SPR, PETSIT1SPR, step, false, true, 8, 0, 0, NULL, C_Pet, R_Pet, &s_petsit2};\r
+statetype s_petsit2 = {PETSIT2SPR, PETSIT2SPR, step, false, true, 8, 0, 0, T_PetSit, C_Pet, R_Pet, &s_petsit1};\r
+statetype s_petbark1 = {PETBARKL1SPR, PETBARKR1SPR, step, false, true, 8, 0, 0, NULL, C_Pet, R_Pet, &s_petbark2};\r
+statetype s_petbark2 = {PETBARKL2SPR, PETBARKR2SPR, step, false, true, 8, 0, 0, T_PetBark, C_Pet, R_Pet, &s_pet1};\r
+statetype s_pet1 = {PETRUNL1SPR, PETRUNR1SPR, step, false, true, 8, 128, 0, NULL, C_Pet, R_Pet, &s_pet2};\r
+statetype s_pet2 = {PETRUNL2SPR, PETRUNR2SPR, step, false, true, 8, 128, 0, NULL, C_Pet, R_Pet, &s_pet3};\r
+statetype s_pet3 = {PETRUNL3SPR, PETRUNR3SPR, step, false, true, 8, 128, 0, NULL, C_Pet, R_Pet, &s_pet4};\r
+statetype s_pet4 = {PETRUNL4SPR, PETRUNR4SPR, step, false, true, 8, 128, 0, T_Pet, C_Pet, R_Pet, &s_pet1};\r
+statetype s_petjump = {PETJUMPLSPR, PETJUMPRSPR, think, false, false, 8, 128, 0, T_Projectile, C_Pet, R_PetJump, &s_pet2};\r
+statetype s_pshot1 = {PETSPARK1SPR, PETSPARK1SPR, stepthink, false, false, 8, 0, 0, T_Velocity, C_PShot, R_PShot, &s_pshot2};\r
+statetype s_pshot2 = {PETSPARK2SPR, PETSPARK2SPR, stepthink, false, false, 8, 0, 0, T_Velocity, C_PShot, R_PShot, &s_pshot1};\r
+statetype s_pshothot1 = {PETSPARKHIT1SPR, PETSPARKHIT1SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, &s_pshothot2};\r
+statetype s_pshothot2 = {PETSPARKHIT2SPR, PETSPARKHIT2SPR, step, false, false, 10, 0, 0, NULL, NULL, R_Draw, NULL};\r
+statetype s_petstun = {PETSTUNSPR, PETSTUNSPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnPet\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnPet(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = petobj;\r
+ new->active = ac_yes;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -8*PIXGLOBAL;\r
+ new->temp2 = 2; // health\r
+ new->xdir = new->ydir = 1;\r
+ NewState(new, &s_pet1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Pet\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Pet(objtype *ob)\r
+{\r
+ if (ob->x > player->x)\r
+ {\r
+ ob->xdir = -1;\r
+ }\r
+ else\r
+ {\r
+ ob->xdir = 1;\r
+ }\r
+ if (US_RndT() < 0x10)\r
+ {\r
+ xtry = 0;\r
+ ob->state = &s_petsit1;\r
+ ob->temp1 = 10; // repeat animation 10 times;\r
+ }\r
+ else\r
+ {\r
+ if (ob->bottom != player->bottom)\r
+ {\r
+ ob->state = &s_petjump;\r
+ if (ob->xdir == 1)\r
+ {\r
+ ob->xspeed = 40;\r
+ }\r
+ else\r
+ {\r
+ ob->xspeed = -40;\r
+ }\r
+ ob->yspeed = -40;\r
+ }\r
+ if (US_RndT() < 0x80)\r
+ {\r
+ xtry = 0;\r
+ ob->state = &s_petbark1;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_PetSit\r
+=\r
+===========================\r
+*/\r
+\r
+void T_PetSit(objtype *ob)\r
+{\r
+ if (--ob->temp1 == 0)\r
+ {\r
+ ob->state = &s_pet1;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_PetBark\r
+=\r
+===========================\r
+*/\r
+\r
+void T_PetBark(objtype *ob)\r
+{\r
+ Uint16 x;\r
+\r
+ if (ob->xdir == 1)\r
+ {\r
+ x = ob->x + 7*PIXGLOBAL;\r
+ }\r
+ else\r
+ {\r
+ x = ob->x;\r
+ }\r
+ if (CheckSpawnShot(x, ob->y+4*PIXGLOBAL, &s_pshot1) != -1)\r
+ {\r
+ new->xspeed = ob->xdir * 60;\r
+ new->xdir = ob->xdir;\r
+ SD_PlaySound(SND_SHOCKSHUNDBARK);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Pet\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Pet(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ }\r
+ if (hit->obclass == stunshotobj) // no 'else if' in the original code!\r
+ {\r
+ if (--ob->temp2 == 0) // handle health\r
+ {\r
+ ob->xspeed = 0;\r
+ ob->yspeed = 0;\r
+ StunObj(ob, hit, &s_petstun);\r
+ }\r
+ else\r
+ {\r
+ ob->temp3 = 2; // draw white two times\r
+ ob->needtoreact = true;\r
+ ExplodeShot(hit);\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Pet\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Pet(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, ob->state);\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, ob->state);\r
+ }\r
+ else if (!ob->hitnorth)\r
+ {\r
+ if ((ob->xdir == 1 && player->x > ob->x) || (ob->xdir == -1 && player->x < ob->x))\r
+ {\r
+ ChangeState(ob, &s_petjump);\r
+ if (ob->xdir == 1)\r
+ {\r
+ ob->xspeed = 40;\r
+ }\r
+ else\r
+ {\r
+ ob->xspeed = -40;\r
+ }\r
+ ob->yspeed = -40;\r
+ }\r
+ else\r
+ {\r
+ ob->x -= ob->xmove*2;\r
+ ob->xdir = -ob->xdir;\r
+ ob->nothink = US_RndT() >> 5;\r
+ ChangeState(ob, ob->state);\r
+ }\r
+ }\r
+ if (ob->temp3)\r
+ {\r
+ ob->temp3--;\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, maskdraw, ob->priority);\r
+ }\r
+ else\r
+ {\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_PetJump\r
+=\r
+===========================\r
+*/\r
+\r
+void R_PetJump(objtype *ob)\r
+{\r
+ if (ob->hitnorth)\r
+ {\r
+ ob->nothink = US_RndT() >> 5;\r
+ ChangeState(ob, &s_pet1);\r
+ }\r
+ if (ob->temp3)\r
+ {\r
+ ob->temp3--;\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, maskdraw, ob->priority);\r
+ }\r
+ else\r
+ {\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_PShot\r
+=\r
+===========================\r
+*/\r
+\r
+void C_PShot(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj)\r
+ {\r
+ KillKeen();\r
+ ChangeState(ob, &s_pshothot1);\r
+ }\r
+ else if (hit->obclass == stunshotobj)\r
+ {\r
+ ExplodeShot(hit);\r
+ ChangeState(ob, &s_pshothot1);\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_PShot\r
+=\r
+===========================\r
+*/\r
+\r
+void R_PShot(objtype *ob)\r
+{\r
+ if (ob->hitnorth || ob->hiteast || ob->hitsouth || ob->hitwest)\r
+ {\r
+ SD_PlaySound(SND_SHOCKBALLEXPLODE);\r
+ ChangeState(ob, &s_pshothot1);\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SPHEREFUL\r
+\r
+temp1 ... temp4 = sprite pointers for the guards circling around the sphere\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_sphereful1 = {SPHEREFUL1SPR, SPHEREFUL1SPR, stepthink, false, false, 6, 0, 0, T_Sphereful, C_Spindread, R_Sphereful, &s_sphereful2};\r
+statetype s_sphereful2 = {SPHEREFUL2SPR, SPHEREFUL2SPR, stepthink, false, false, 6, 0, 0, T_Sphereful, C_Spindread, R_Sphereful, &s_sphereful3};\r
+statetype s_sphereful3 = {SPHEREFUL3SPR, SPHEREFUL3SPR, stepthink, false, false, 6, 0, 0, T_Sphereful, C_Spindread, R_Sphereful, &s_sphereful4};\r
+statetype s_sphereful4 = {SPHEREFUL4SPR, SPHEREFUL4SPR, stepthink, false, false, 6, 0, 0, T_Sphereful, C_Spindread, R_Sphereful, &s_sphereful1};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnSphereful\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnSphereful(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = spherefulobj;\r
+ new->needtoclip = cl_fullclip;\r
+ new->active = ac_yes;\r
+ new->x = CONVERT_TILE_TO_GLOBAL(tileX);\r
+ new->y = CONVERT_TILE_TO_GLOBAL(tileY) + -1*TILEGLOBAL;\r
+ new->priority = 1;\r
+ NewState(new, &s_sphereful1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Sphereful\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Sphereful(objtype *ob)\r
+{\r
+ Sint32 i;\r
+ ob->needtoreact = true;\r
+\r
+ //\r
+ // this code could be executed twice during the same frame because the\r
+ // object's animation/state changed during that frame, so don't update\r
+ // anything if we already have movement for the current frame i.e. the\r
+ // update code has already been executed this frame\r
+ //\r
+ if (xtry == 0 && ytry == 0)\r
+ {\r
+ for (i=lasttimecount-tics; i<lasttimecount; i++)\r
+ {\r
+ if (!(i & 0xF))\r
+ {\r
+ if (ob->yspeed < 8)\r
+ ob->yspeed++;\r
+\r
+ if (ob->x < player->x && ob->xspeed < 8)\r
+ ob->xspeed++;\r
+\r
+ if (ob->x > player->x && ob->xspeed > -8)\r
+ ob->xspeed--;\r
+ }\r
+ ytry += ob->yspeed;\r
+ xtry += ob->xspeed;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Sphereful\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Sphereful(objtype *ob)\r
+{\r
+ static Uint16 circle[16] = {\r
+ 384, 369, 328, 265, 192, 119, 58, 15,\r
+ 0, 15, 58, 119, 192, 265, 328, 369\r
+ };\r
+\r
+ Uint16 index, shapenum, priority;\r
+\r
+ if (ob->hitwest || ob->hiteast)\r
+ {\r
+ ob->xspeed = -ob->xspeed;\r
+ SD_PlaySound(SND_SPHEREFULBOUNCE);\r
+ }\r
+ if (ob->hitsouth)\r
+ {\r
+ ob->yspeed = -ob->yspeed;\r
+ SD_PlaySound(SND_SPHEREFULBOUNCE);\r
+ }\r
+\r
+ if (ob->hitnorth)\r
+ {\r
+ ob->yspeed = -ob->yspeed;\r
+ if (player->y < ob->y)\r
+ {\r
+ ob->yspeed--;\r
+ }\r
+ else\r
+ {\r
+ ob->yspeed++;\r
+ }\r
+ if (ob->yspeed > -4)\r
+ {\r
+ ob->yspeed = -4;\r
+ }\r
+ else if (ob->yspeed < -12)\r
+ {\r
+ ob->yspeed = -12;\r
+ }\r
+ SD_PlaySound(SND_BOUNCE);\r
+ }\r
+ RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+\r
+ index = ((Uint16)lasttimecount / 8) & 0xF;\r
+ shapenum = index / 4 + SPHEREGUARD1SPR;\r
+ if (index >= 8)\r
+ {\r
+ priority = 2;\r
+ }\r
+ else\r
+ {\r
+ priority = 0;\r
+ }\r
+ RF_PlaceSprite((void**)&ob->temp1, ob->x+circle[index], ob->y+circle[index], shapenum, spritedraw, priority);\r
+ RF_PlaceSprite((void**)&ob->temp2, ob->x+24*PIXGLOBAL-circle[index], ob->y+circle[index], shapenum, spritedraw, priority);\r
+\r
+ index += 8;\r
+ index &= 0xF;\r
+ if (index >= 8)\r
+ {\r
+ priority = 2;\r
+ }\r
+ else\r
+ {\r
+ priority = 0;\r
+ }\r
+ RF_PlaceSprite((void**)&ob->temp3, ob->x+circle[index], ob->y+circle[index], shapenum, spritedraw, priority);\r
+ RF_PlaceSprite((void**)&ob->temp4, ob->x+24*PIXGLOBAL-circle[index], ob->y+circle[index], shapenum, spritedraw, priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SCOTTIE\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_scottie1 = {SCOTTIEWALKL1SPR, SCOTTIEWALKR1SPR, step, false, true, 8, 128, 0, T_Scottie, C_Scottie, R_Walk, &s_scottie2};\r
+statetype s_scottie2 = {SCOTTIEWALKL2SPR, SCOTTIEWALKR2SPR, step, false, true, 8, 128, 0, T_Scottie, C_Scottie, R_Walk, &s_scottie3};\r
+statetype s_scottie3 = {SCOTTIEWALKL3SPR, SCOTTIEWALKR3SPR, step, false, true, 8, 128, 0, T_Scottie, C_Scottie, R_Walk, &s_scottie4};\r
+statetype s_scottie4 = {SCOTTIEWALKL4SPR, SCOTTIEWALKR4SPR, step, false, true, 8, 128, 0, T_Scottie, C_Scottie, R_Walk, &s_scottie1};\r
+statetype s_scottieface = {SCOTTIEFACESPR, SCOTTIEFACESPR, step, false, true, 30, 0, 0, NULL, C_Scottie, R_Walk, &s_scottie1};\r
+statetype s_scottiestun = {SCOTTIESTUNSPR, SCOTTIESTUNSPR, think, false, false, 0, 0, 0, T_Projectile, NULL, R_Stunned, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnScottie\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnScottie(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = scottieobj;\r
+ new->active = ac_yes;\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
+ NewState(new, &s_scottie1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Scottie\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Scottie(objtype *ob)\r
+{\r
+ if (US_RndT() < 0x10)\r
+ {\r
+ xtry = 0;\r
+ if (US_RndT() < 0x80)\r
+ {\r
+ ob->xdir = 1;\r
+ }\r
+ else\r
+ {\r
+ ob->xdir = -1;\r
+ }\r
+ ob->state = &s_scottieface;\r
+ }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Scottie\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Scottie(objtype *ob, objtype *hit)\r
+{\r
+ if (hit->obclass == keenobj && hit->state->contact)\r
+ {\r
+ ClipToSpriteSide(hit, ob);\r
+ }\r
+ else if (hit->obclass == stunshotobj)\r
+ {\r
+ StunObj(ob, hit, &s_scottiestun);\r
+ }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+ QED\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_qed = {-1, -1, step, false, true, 8, 128, 0, NULL, NULL, NULL, &s_qed};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnQed\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnQed(Uint16 tileX, Uint16 tileY)\r
+{\r
+ GetNewObj(false);\r
+ new->obclass = qedobj;\r
+ new->active = ac_yes;\r
+ new->tileleft = tileX;\r
+ new->tiletop = tileY;\r
+ new->tileright = new->tileleft + 1;\r
+ new->tilebottom = new->tiletop + 1;\r
+ new->x = new->left = CONVERT_TILE_TO_GLOBAL(tileX) + -1*PIXGLOBAL;\r
+ new->y = new->top = CONVERT_TILE_TO_GLOBAL(tileY) + -1*PIXGLOBAL;\r
+ new->right = new->left + 34*PIXGLOBAL;\r
+ new->bottom = new->top + 34*PIXGLOBAL;\r
+ NewState(new, &s_qed);\r
+}
\ No newline at end of file