]> 4ch.mooo.com Git - 16.git/blobdiff - 16/keen456/KEEN4-6/KEEN4/K4_ACT3.C
extrcted keen code remake
[16.git] / 16 / keen456 / KEEN4-6 / KEEN4 / K4_ACT3.C
diff --git a/16/keen456/KEEN4-6/KEEN4/K4_ACT3.C b/16/keen456/KEEN4-6/KEEN4/K4_ACT3.C
new file mode 100755 (executable)
index 0000000..287a66f
--- /dev/null
@@ -0,0 +1,1317 @@
+/* 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
+K4_ACT3.C\r
+=========\r
+\r
+Contains the following actor types (in this order):\r
+\r
+- Treasure Eater\r
+- Mimrock\r
+- Dopefish\r
+- Schoolfish\r
+- Sprite\r
+- Mine\r
+- Lindsey\r
+- Dart Shooter & Dart\r
+- Wetsuit\r
+\r
+*/\r
+\r
+#include "CK_DEF.H"\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 TREASURE EATER\r
+\r
+temp1 = turn counter\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_eaterstand1 = {EATERSTAND1SPR, EATERSTAND1SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eaterstand2};\r
+statetype s_eaterstand2 = {EATERSTAND2SPR, EATERSTAND2SPR, step, false, false, 20, 0, 0, T_EaterJump, C_Eater, R_Draw, NULL};\r
+statetype s_eatertport1 = {SMOKE1SPR, SMOKE1SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport2};\r
+statetype s_eatertport2 = {SMOKE2SPR, SMOKE2SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport3};\r
+statetype s_eatertport3 = {SMOKE3SPR, SMOKE3SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport4};\r
+statetype s_eatertport4 = {SMOKE4SPR, SMOKE4SPR, step, false, false, 20, 0, 0, T_EaterTeleport, C_Eater, R_Draw, &s_eatertport5};\r
+statetype s_eatertport5 = {SMOKE4SPR, SMOKE4SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport6};\r
+statetype s_eatertport6 = {SMOKE3SPR, SMOKE3SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport7};\r
+statetype s_eatertport7 = {SMOKE2SPR, SMOKE2SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eatertport8};\r
+statetype s_eatertport8 = {SMOKE1SPR, SMOKE1SPR, step, false, false, 20, 0, 0, NULL, C_Eater, R_Draw, &s_eaterjump1};\r
+statetype s_eaterjump1  = {EATERJUMPL1SPR, EATERJUMPR1SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump2};\r
+statetype s_eaterjump2  = {EATERJUMPL2SPR, EATERJUMPR2SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump3};\r
+statetype s_eaterjump3  = {EATERJUMPL3SPR, EATERJUMPR3SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump4};\r
+statetype s_eaterjump4  = {EATERJUMPL2SPR, EATERJUMPR2SPR, stepthink, false, false, 6, 0, 0, T_WeakProjectile, C_Eater, R_EaterAir, &s_eaterjump1};\r
+statetype s_eaterstun   = {EATERJUMPL1SPR, EATERJUMPL1SPR, think, false, false, 0, 0, 0, T_Projectile, 0, R_Stunned, &s_eaterstun2};\r
+statetype s_eaterstun2  = {EATERSTUNSPR, EATERSTUNSPR, think, false, false, 0, 0, 0, T_Projectile, 0, R_Stunned, NULL};\r
+\r
+statetype s_eatenbonus1 = {EATENBONUS1SPR, EATENBONUS1SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, &s_eatenbonus2};\r
+statetype s_eatenbonus2 = {EATENBONUS2SPR, EATENBONUS2SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, &s_eatenbonus3};\r
+statetype s_eatenbonus3 = {EATENBONUS3SPR, EATENBONUS3SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, &s_eatenbonus4};\r
+statetype s_eatenbonus4 = {EATENBONUS4SPR, EATENBONUS4SPR, slide, false, false, 10, 0, 8, NULL, NULL, R_Draw, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnEater\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnEater(Sint16 x, Sint16 y)\r
+{\r
+       GetNewObj(false);\r
+       new->obclass = treasureeaterobj;\r
+       new->active = ac_yes;\r
+       new->priority = 3;\r
+       new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+       new->y = CONVERT_TILE_TO_GLOBAL(y) - 24*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_eaterstand1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_EaterJump\r
+=\r
+===========================\r
+*/\r
+\r
+void T_EaterJump(objtype *ob)\r
+{\r
+       objtype *ob2;\r
+       Uint16 x;\r
+       Sint16 y;\r
+       Uint16 far *map;\r
+       Uint16 intile, rowdiff, width;\r
+\r
+       ob->state = &s_eaterjump1;\r
+\r
+       //jump straight up if below bonus object:\r
+       for (ob2 = player->next; ob2; ob2 = ob2->next)\r
+       {\r
+               if (ob2->obclass == bonusobj && ob2->active == ac_yes\r
+                       && ob2->right > ob->left && ob2->left < ob->right\r
+                       && ob2->bottom < ob->top && ob2->bottom + 3*TILEGLOBAL > ob->top)\r
+               {\r
+                       ob->xspeed = 0;\r
+                       ob->yspeed = -48;\r
+                       return;\r
+               }\r
+       }\r
+\r
+       //jump straight up if below bonus tile:\r
+       map = mapsegs[1] + mapbwidthtable[ob->tiletop-3]/2 + ob->tileleft;\r
+       width = ob->tileright-ob->tileleft+1;\r
+       rowdiff = mapwidth-width;\r
+       for (y=0; y<3; y++, map+=rowdiff)\r
+       {\r
+               for (x=0; x<width; x++, map++)\r
+               {\r
+                       intile = tinf[INTILE+*map];\r
+                       if (intile == INTILE_DROP || intile >= INTILE_BONUS100 && intile <= INTILE_AMMO)\r
+                       {\r
+                               ob->xspeed = 0;\r
+                               ob->yspeed = -48;\r
+                               return;\r
+                       }\r
+               }\r
+       }\r
+\r
+       //vanish after having checked both directions:\r
+       if (ob->temp1 >= 2)\r
+       {\r
+               // BUG? this doesn't play a sound\r
+               ob->state = &s_eatertport1;\r
+               return;\r
+       }\r
+\r
+       //jump in current direction if there is a floor in that direction:\r
+       map = mapsegs[1] + mapbwidthtable[ob->tilebottom-2]/2 + ob->tilemidx;\r
+       map += ob->xdir * 4;\r
+       for (y=0; y<4; y++, map+=mapwidth)\r
+       {\r
+               if (tinf[NORTHWALL+*map])\r
+               {\r
+                       ob->xspeed = ob->xdir * 20;\r
+                       ob->yspeed = -24;\r
+                       return;\r
+               }\r
+       }\r
+\r
+       //couldn't jump in current direction, so turn around:\r
+       if (++ob->temp1 == 2)\r
+       {\r
+               SD_PlaySound(SND_TREASUREEATERVANISH);\r
+               ob->state = &s_eatertport1;\r
+               return;\r
+       }\r
+\r
+       //jump in opposite direction:\r
+       ob->xdir = -ob->xdir;\r
+       ob->xspeed = ob->xdir * 20;\r
+       ob->yspeed = -24;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_EaterTeleport\r
+=\r
+===========================\r
+*/\r
+\r
+void T_EaterTeleport(objtype *ob)\r
+{\r
+       objtype *ob2;\r
+\r
+       ob->temp1 = 0;\r
+       for (ob2=player->next; ob2; ob2=ob2->next)\r
+       {\r
+               if (ob2->obclass == bonusobj)\r
+               {\r
+                       ob->x = ob2->x - 8*PIXGLOBAL;\r
+                       ob->y = ob2->y;\r
+                       NewState(ob, &s_eatertport5);\r
+                       return;\r
+               }\r
+       }\r
+       RemoveObj(ob);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Eater\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Eater(objtype *ob, objtype *hit)\r
+{\r
+       if (hit->obclass == bonusobj)\r
+       {\r
+               //BUG? bonus object might be a key, and eating a key makes a level unwinnable\r
+               hit->obclass = inertobj;\r
+               hit->priority = 3;\r
+               ChangeState(hit, &s_eatenbonus1);\r
+               SD_PlaySound(SND_EATBONUS);\r
+       }\r
+       else if (hit->obclass == stunshotobj)\r
+       {\r
+               //basically StunObj(), but in different order:\r
+               ob->temp1 = 0;\r
+               ob->temp2 = 0;\r
+               ob->temp3 = 0;\r
+               ob->temp4 = ob->obclass;\r
+               ob->obclass = stunnedobj;\r
+               ExplodeShot(hit);\r
+               ChangeState(ob, &s_eaterstun);\r
+\r
+               ob->yspeed -= 16;\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= EaterInTile\r
+=\r
+===========================\r
+*/\r
+\r
+void EaterInTile(objtype *ob)\r
+{\r
+       Uint16 x, y;\r
+       Uint16 far *map;\r
+       Uint16 rowdiff, intile;\r
+\r
+       map = mapsegs[1] + mapbwidthtable[ob->tiletop]/2 + ob->tileleft;\r
+       rowdiff = mapwidth-(ob->tileright-ob->tileleft+1);\r
+       for (y=ob->tiletop; y<=ob->tilebottom; y++, map+=rowdiff)\r
+       {\r
+               for (x=ob->tileleft; x<=ob->tileright; x++, map++)\r
+               {\r
+                       intile = tinf[INTILE + *map] & INTILE_TYPEMASK;\r
+                       if (intile == INTILE_DROP || intile >= INTILE_BONUS100 && intile <= INTILE_AMMO)\r
+                       {\r
+                               RF_MemToMap(&zeromap, 1, x, y, 1, 1);\r
+                               GetNewObj(true);\r
+                               new->obclass = inertobj;\r
+                               new->priority = 3;\r
+                               new->needtoclip = cl_noclip;\r
+                               new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+                               new->y = CONVERT_TILE_TO_GLOBAL(y);\r
+                               new->active = ac_removable;\r
+                               ChangeState(new, &s_eatenbonus1);       //using ChangeState and not NewState is fine for noclipping objects\r
+                               //BUG? this doesn't play a sound\r
+                               break;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_EaterAir\r
+=\r
+===========================\r
+*/\r
+\r
+void R_EaterAir(objtype *ob)\r
+{\r
+       EaterInTile(ob);\r
+\r
+       if (ob->hitnorth)\r
+               ChangeState(ob, &s_eaterstand1);\r
+\r
+       if (ob->hiteast || ob->hitwest)\r
+       {\r
+               ob->temp1++;\r
+               ob->xdir = -ob->xdir;\r
+               ob->xspeed = 0;\r
+       }\r
+\r
+       if (ob->hitnorth)       //BUG? maybe this was supposed to check hitsouth as well?\r
+               ob->yspeed = 0;\r
+\r
+       RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 MIMROCK\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_mimrock   = {MIMROCKSPR, MIMROCKSPR, step, false, true, 20, 0, 0, T_MimrockWait, NULL, R_Walk, &s_mimrock};\r
+statetype s_mimsneak1 = {MIMROCKWALKR1SPR, MIMROCKWALKL1SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak2};\r
+statetype s_mimsneak2 = {MIMROCKWALKR2SPR, MIMROCKWALKL2SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak3};\r
+statetype s_mimsneak3 = {MIMROCKWALKR3SPR, MIMROCKWALKL3SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak4};\r
+statetype s_mimsneak4 = {MIMROCKWALKR4SPR, MIMROCKWALKL4SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak5};\r
+statetype s_mimsneak5 = {MIMROCKWALKR1SPR, MIMROCKWALKL1SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimsneak6};\r
+statetype s_mimsneak6 = {MIMROCKWALKR2SPR, MIMROCKWALKL2SPR, step, false, true, 6, 64, 0, T_MimrockSneak, C_Mimrock, R_Walk, &s_mimrock};\r
+statetype s_mimbonk1  = {MIMROCKJUMPL1SPR, MIMROCKJUMPR1SPR, stepthink, false, false, 24, 0, 0, T_WeakProjectile, C_MimLethal, R_MimAir, &s_mimbonk2};\r
+statetype s_mimbonk2  = {MIMROCKJUMPL2SPR, MIMROCKJUMPR2SPR, stepthink, false, false, 10, 0, 0, T_WeakProjectile, C_MimLethal, R_MimAir, &s_mimbonk3};\r
+statetype s_mimbonk3  = {MIMROCKJUMPL3SPR, MIMROCKJUMPR3SPR, think, false, false, 10, 0, 0, T_WeakProjectile, C_MimLethal, R_MimAir, &s_mimbonk2};\r
+statetype s_mimbounce = {MIMROCKJUMPL3SPR, MIMROCKJUMPR3SPR, think, false, false, 10, 0, 0, T_Projectile, C_Mimrock, R_MimBounce, NULL};\r
+statetype s_mimstun   = {MIMROCKJUMPL3SPR, MIMROCKJUMPL3SPR, think, false, false, 12, 0, 0, T_Projectile, NULL, R_Stunned, &s_mimstun2};\r
+statetype s_mimstun2  = {MINROCKSTUNSPR, MINROCKSTUNSPR, think, false, false, 12, 0, 0, T_Projectile, NULL, R_Stunned, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnMimrock\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnMimrock(Sint16 x, Sint16 y)\r
+{\r
+       GetNewObj(false);\r
+       new->obclass = mimrockobj;\r
+       new->active = ac_yes;\r
+       new->priority = 3;\r
+       new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+       new->y = CONVERT_TILE_TO_GLOBAL(y)+ -13*PIXGLOBAL;\r
+       new->ydir = new->xdir = 1;\r
+       NewState(new, &s_mimrock);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_MimrockWait\r
+=\r
+===========================\r
+*/\r
+\r
+void T_MimrockWait(objtype *ob)\r
+{\r
+       if (abs(ob->bottom - player->bottom) > 5*TILEGLOBAL)\r
+               return;\r
+\r
+       if (abs(ob->x - player->x) > 3*TILEGLOBAL)\r
+       {\r
+               if (player->x < ob->x)\r
+               {\r
+                       if (player->xdir == -1)\r
+                       {\r
+                               ob->xdir = -1;\r
+                               ob->state = &s_mimsneak1;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       if (player->xdir == 1)\r
+                       {\r
+                               ob->xdir = 1;\r
+                               ob->state = &s_mimsneak1;\r
+                       }\r
+               }\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_MimrockSneak\r
+=\r
+===========================\r
+*/\r
+\r
+void T_MimrockSneak(objtype *ob)\r
+{\r
+       if (abs(ob->bottom - player->bottom) > 5*TILEGLOBAL\r
+               || ob->xdir != player->xdir)\r
+       {\r
+               ob->state = &s_mimrock;\r
+       }\r
+       else if (abs(ob->x - player->x) < 4*TILEGLOBAL)\r
+       {\r
+               ob->xspeed = ob->xdir * 20;\r
+               ob->yspeed = -40;\r
+               ytry = ob->yspeed * tics;\r
+               ob->state = &s_mimbonk1;\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Mimrock\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Mimrock(objtype *ob, objtype *hit)\r
+{\r
+       if (hit->obclass == stunshotobj)\r
+       {\r
+               //basically StunObj(), but in different order:\r
+               ob->temp1 = 0;\r
+               ob->temp2 = 0;\r
+               ob->temp3 = 0;\r
+               ob->temp4 = ob->obclass;\r
+               ob->obclass = stunnedobj;\r
+               ExplodeShot(hit);\r
+               ChangeState(ob, &s_mimstun);\r
+\r
+               ob->yspeed -= 16;\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_MimLethal\r
+=\r
+===========================\r
+*/\r
+\r
+void C_MimLethal(objtype *ob, objtype *hit)\r
+{\r
+       if (hit->obclass == keenobj)\r
+       {\r
+               KillKeen();\r
+       }\r
+       else\r
+       {\r
+               C_Mimrock(ob, hit);\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_MimAir\r
+=\r
+===========================\r
+*/\r
+\r
+void R_MimAir(objtype *ob)\r
+{\r
+       if (ob->hitnorth)\r
+       {\r
+               SD_PlaySound(SND_HELMETHIT);\r
+               ob->yspeed = -20;\r
+               ChangeState(ob, &s_mimbounce);\r
+       }\r
+\r
+       if (ob->hiteast || ob->hitwest)\r
+               ob->xspeed = 0;\r
+\r
+       if (ob->hitnorth || ob->hitsouth)\r
+               ob->yspeed = 0;\r
+\r
+       RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_MimBounce\r
+=\r
+===========================\r
+*/\r
+\r
+void R_MimBounce(objtype *ob)\r
+{\r
+       if (ob->hitnorth)\r
+       {\r
+               SD_PlaySound(SND_HELMETHIT);\r
+               ChangeState(ob, &s_mimrock);\r
+       }\r
+\r
+       if (ob->hiteast || ob->hitwest)\r
+               ob->xspeed = 0;\r
+\r
+       if (ob->hitnorth)\r
+               ob->yspeed = 0;\r
+\r
+       RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 DOPEFISH\r
+\r
+temp1 = blocked (cannot change xdir to chase Keen while this is non-zero)\r
+temp2 = old x position\r
+temp3 = old y position\r
+temp4 = pointer to object being eaten\r
+        (BUG: pointer may be invalid after loading a saved game!)\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_dopefish1  = {DOPEFISHSWIML1SPR, DOPEFISHSWIMR1SPR, stepthink, false, false, 20, 0, 0, T_Dope, C_Dope, R_Fish, &s_dopefish2};\r
+statetype s_dopefish2  = {DOPEFISHSWIML2SPR, DOPEFISHSWIMR2SPR, stepthink, false, false, 20, 0, 0, T_Dope, C_Dope, R_Fish, &s_dopefish1};\r
+statetype s_dopeattack = {DOPEFISHHUNGRYLSPR, DOPEFISHHUNGRYRSPR, think, false, false, 0, 0, 0, T_DopeHunt, NULL, R_Draw, NULL};\r
+statetype s_dopeeat    = {DOPEFISHSWIML1SPR, DOPEFISHSWIMR1SPR, step, false, false, 60, 0, 0, NULL, NULL, R_Draw, &s_dopeburp1};\r
+statetype s_dopeburp1  = {DOPEFISHBURP1SPR, DOPEFISHBURP1SPR, step, false, false, 60, 0, 0, T_Burp, NULL, R_Draw, &s_dopeburp2};\r
+statetype s_dopeburp2  = {DOPEFISHBURP2SPR, DOPEFISHBURP2SPR, step, false, false, 60, 0, 0, NULL, NULL, R_Draw, &s_dopereturn};\r
+statetype s_dopereturn = {DOPEFISHSWIML1SPR, DOPEFISHSWIMR1SPR, think, false, false, 0, 0, 0, T_DopeReturn, NULL, R_Draw, &s_dopefish1};\r
+\r
+statetype s_dopefood     = {SCHOOLFISHL1SPR, SCHOOLFISHR1SPR, think, false, false, 0, 0, 0, NULL, NULL, R_Draw, NULL};\r
+statetype s_keendopefood = {SCUBAKEENDEAD1SPR, SCUBAKEENDEAD1SPR, think, false, false, 0, 0, 0, NULL, NULL, R_Draw, &s_keendieslow};\r
+statetype s_keendieslow  = {-1, -1, step, false, false, 180, 0, 0, T_EatenKeen, NULL, R_Draw, &s_keendieslow};\r
+\r
+statetype s_bubble1 = {BIGBUBBLE1SPR, BIGBUBBLE1SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble2};\r
+statetype s_bubble2 = {BIGBUBBLE2SPR, BIGBUBBLE2SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble3};\r
+statetype s_bubble3 = {BIGBUBBLE3SPR, BIGBUBBLE3SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble4};\r
+statetype s_bubble4 = {BIGBUBBLE4SPR, BIGBUBBLE4SPR, think, false, false, 20, 0, 20, T_Bubble, NULL, R_Draw, &s_bubble1};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnDopefish\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnDopefish(Sint16 x, Sint16 y)\r
+{\r
+       GetNewObj(false);\r
+       new->obclass = dopefishobj;\r
+       new->active = ac_yes;\r
+       new->priority = 2;\r
+       new->needtoclip = cl_fullclip;\r
+       new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+       new->y = CONVERT_TILE_TO_GLOBAL(y) + -3*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_dopefish1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_EatenKeen\r
+=\r
+===========================\r
+*/\r
+\r
+void T_EatenKeen(objtype *ob)\r
+{\r
+       ob++;                   // shut up compiler\r
+       playstate = ex_died;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Dope\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Dope(objtype *ob)\r
+{\r
+       if (ob->temp1 == 0)\r
+       {\r
+               if (ob->x < player->x)\r
+               {\r
+                       ob->xdir = 1;\r
+               }\r
+               else\r
+               {\r
+                       ob->xdir = -1;\r
+               }\r
+       }\r
+       AccelerateXv(ob, ob->xdir, 10);\r
+\r
+       if (ob->y < player->y)\r
+       {\r
+               AccelerateY(ob, 1, 10);\r
+       }\r
+       else\r
+       {\r
+               AccelerateY(ob, -1, 10);\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_DopeHunt\r
+=\r
+===========================\r
+*/\r
+\r
+void T_DopeHunt(objtype *ob)\r
+{\r
+       objtype *target;\r
+       Sint16 xdist, ydist;\r
+\r
+       target = (objtype *)(ob->temp4);\r
+       ydist = target->y - TILEGLOBAL - ob->y;\r
+       if (ob->xdir == 1)\r
+       {\r
+               xdist = target->right + 2*PIXGLOBAL - ob->right;\r
+       }\r
+       else\r
+       {\r
+               xdist = target->left - 2*PIXGLOBAL - ob->left;\r
+       }\r
+\r
+       if (xdist < 0)\r
+       {\r
+               xtry = tics * -32;\r
+               if (xtry < xdist)\r
+                       xtry = xdist;\r
+       }\r
+       else\r
+       {\r
+               xtry = tics * 32;\r
+               if (xtry > xdist)\r
+                       xtry = xdist;\r
+       }\r
+\r
+       if (ydist < 0)\r
+       {\r
+               ytry = tics * -32;\r
+               if (ytry < ydist)\r
+                       ytry = ydist;\r
+       }\r
+       else\r
+       {\r
+               ytry = tics * 32;\r
+               if (ytry > ydist)\r
+                       ytry = ydist;\r
+       }\r
+\r
+       if (xtry == xdist && ytry == ydist)\r
+       {\r
+               if (target == player)\r
+               {\r
+                       ChangeState(target, &s_keendieslow);\r
+               }\r
+               else if (target->state->nextstate)\r
+               {\r
+                       ChangeState(target, target->state->nextstate);\r
+               }\r
+               else\r
+               {\r
+                       RemoveObj(target);\r
+               }\r
+               ob->state = &s_dopeeat;\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_DopeReturn\r
+=\r
+===========================\r
+*/\r
+\r
+void T_DopeReturn(objtype *ob)\r
+{\r
+       Sint16 xdist, ydist;\r
+\r
+       ydist = ob->temp3 - ob->y;\r
+       xdist = ob->temp2 - ob->x;\r
+\r
+       if (xdist < 0)\r
+       {\r
+               xtry = tics * -32;\r
+               if (xtry < xdist)\r
+                       xtry = xdist;\r
+       }\r
+       else\r
+       {\r
+               xtry = tics * 32;\r
+               if (xtry > xdist)\r
+                       xtry = xdist;\r
+       }\r
+\r
+       if (ydist < 0)\r
+       {\r
+               ytry = tics * -32;\r
+               if (ytry < ydist)\r
+                       ytry = ydist;\r
+       }\r
+       else\r
+       {\r
+               ytry = tics * 32;\r
+               if (ytry > ydist)\r
+                       ytry = ydist;\r
+       }\r
+\r
+       if (xtry == xdist && ytry == ydist)\r
+       {\r
+               ob->state = ob->state->nextstate;\r
+               ob->needtoclip = cl_fullclip;\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Burp\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Burp(objtype *ob)\r
+{\r
+       GetNewObj(true);\r
+       new->x = ob->x + 56*PIXGLOBAL;\r
+       new->y = ob->y + 32*PIXGLOBAL;\r
+       new->obclass = inertobj;\r
+       new->priority = 3;\r
+       new->active = ac_removable;\r
+       new->needtoclip = cl_noclip;\r
+       new->yspeed = -20;\r
+       new->xspeed = 4;\r
+       NewState(new, &s_bubble1);\r
+       SD_PlaySound(SND_BURP);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Bubble\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Bubble(objtype *ob)\r
+{\r
+       T_Velocity(ob);\r
+       if (US_RndT() < tics * 16)\r
+               ob->xspeed = -ob->xspeed;\r
+\r
+       if (ob->y < 3*TILEGLOBAL)\r
+               RemoveObj(ob);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Dope\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Dope(objtype *ob, objtype *hit)\r
+{\r
+       if (hit->obclass == schoolfishobj)\r
+       {\r
+               ChangeState(hit, &s_dopefood);\r
+       }\r
+       else if (hit->obclass == keenobj && !godmode)\r
+       {\r
+               hit->obclass = inertobj;        //prevents other objects from killing Keen before he is fully swallowed\r
+               hit->needtoclip = cl_noclip;\r
+               SD_PlaySound(SND_KEENDEAD);\r
+               ChangeState(hit, &s_keendopefood);\r
+       }\r
+       else\r
+       {\r
+               return;\r
+       }\r
+\r
+       ob->temp2 = ob->x;\r
+       ob->temp3 = ob->y;\r
+       ob->temp4 = (Sint16)hit;\r
+       if (hit->midx < ob->midx)\r
+       {\r
+               ob->xdir = -1;\r
+       }\r
+       else\r
+       {\r
+               ob->xdir = 1;\r
+       }\r
+       ChangeState(ob, &s_dopeattack);\r
+       ob->needtoclip = cl_noclip;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Fish\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Fish(objtype *ob)       //for Dopefish and Schoolfish\r
+{\r
+       if ((ob->hitsouth || ob->hitnorth) && ob->temp1 == 0)\r
+               ob->temp1++;\r
+\r
+       if (ob->hiteast || ob->hitwest)\r
+       {\r
+               ob->xspeed = 0;\r
+               ob->xdir = -ob->xdir;\r
+               ob->temp1 = 1;\r
+       }\r
+\r
+       if (!ob->hitsouth && !ob->hitnorth)\r
+               ob->temp1 = 0;\r
+\r
+       RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 SCHOOLFISH\r
+\r
+temp1 = blocked (cannot change xdir to chase Keen while this is non-zero)\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_schoolfish1 = {SCHOOLFISHL1SPR, SCHOOLFISHR1SPR, stepthink, false, false, 20, 0, 0, T_SchoolFish, NULL, R_Fish, &s_schoolfish2};\r
+statetype s_schoolfish2 = {SCHOOLFISHL2SPR, SCHOOLFISHR2SPR, stepthink, false, false, 20, 0, 0, T_SchoolFish, NULL, R_Fish, &s_schoolfish1};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnSchoolfish\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnSchoolfish(Sint16 x, Sint16 y)\r
+{\r
+       GetNewObj(false);\r
+       new->obclass = schoolfishobj;\r
+       new->active = ac_yes;\r
+       new->needtoclip = cl_fullclip;\r
+       new->priority = 0;\r
+       new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+       new->y = CONVERT_TILE_TO_GLOBAL(y);\r
+       new->ydir = new->xdir = 1;\r
+       NewState(new, &s_schoolfish1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_SchoolFish\r
+=\r
+===========================\r
+*/\r
+\r
+void T_SchoolFish(objtype *ob)\r
+{\r
+       if (ob->temp1 == 0)\r
+       {\r
+               if (ob->x < player->x)\r
+               {\r
+                       ob->xdir = 1;\r
+               }\r
+               else\r
+               {\r
+                       ob->xdir = -1;\r
+               }\r
+       }\r
+       AccelerateXv(ob, ob->xdir, 10);\r
+\r
+       if (ob->y < player->y)\r
+       {\r
+               AccelerateY(ob, 1, 10);\r
+       }\r
+       else\r
+       {\r
+               AccelerateY(ob, -1, 10);\r
+       }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 PIXIE (a.k.a. SPRITE)\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_pixie       = {SPRITEFLOATSPR,  SPRITEFLOATSPR,  think, false, false, 10, 0, 0, T_Pixie, C_Lethal, R_Draw, &s_pixie};\r
+statetype s_pixielook   = {SPRITEAIMLSPR,   SPRITEAIMRSPR,   step, false, false, 40, 0, 0, T_PixieCheck, C_Lethal, R_Draw, &s_pixie};\r
+statetype s_pixieshoot  = {SPRITESHOOTLSPR, SPRITESHOOTRSPR, step, false, false, 40, 0, 0, T_PixieShoot, C_Lethal, R_Draw, &s_pixieshoot2};\r
+statetype s_pixieshoot2 = {SPRITESHOOTLSPR, SPRITESHOOTRSPR, step, false, false, 30, 0, 0, NULL, C_Lethal, R_Draw, &s_pixie};\r
+statetype s_pixiefire1  = {SPRITESHOT1SPR,  SPRITESHOT1SPR,  slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire2};\r
+statetype s_pixiefire2  = {SPRITESHOT2SPR,  SPRITESHOT2SPR,  slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire3};\r
+statetype s_pixiefire3  = {SPRITESHOT3SPR,  SPRITESHOT3SPR,  slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire4};\r
+statetype s_pixiefire4  = {SPRITESHOT4SPR,  SPRITESHOT4SPR,  slide, false, false, 10, 64, 0, NULL, C_Lethal, R_Mshot, &s_pixiefire1};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnPixie\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnPixie(Sint16 x, Sint16 y)\r
+{\r
+       GetNewObj(false);\r
+       new->obclass = pixieobj;\r
+       new->active = ac_yes;\r
+       new->priority = 0;\r
+       new->needtoclip = cl_noclip;\r
+       new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+       new->y = new->temp1 = CONVERT_TILE_TO_GLOBAL(y);\r
+       new->ydir = new->xdir = 1;\r
+       NewState(new, &s_pixie);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Pixie\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Pixie(objtype *ob)\r
+{\r
+       AccelerateY(ob, ob->ydir, 8);\r
+       if ((Sint16)(ob->temp1 - ob->y) > 2*PIXGLOBAL)\r
+       {\r
+               ob->ydir = 1;\r
+       }\r
+       if ((Sint16)(ob->y - ob->temp1) > 2*PIXGLOBAL)\r
+       {\r
+               ob->ydir = -1;\r
+       }\r
+\r
+       if (player->top < ob->bottom && player->bottom > ob->top)\r
+       {\r
+               if (player->x < ob->x)\r
+               {\r
+                       ob->xdir = -1;\r
+               }\r
+               else\r
+               {\r
+                       ob->xdir = 1;\r
+               }\r
+               ob->state = &s_pixielook;\r
+       }\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_PixieCheck\r
+=\r
+===========================\r
+*/\r
+\r
+void T_PixieCheck(objtype *ob)\r
+{\r
+       if (player->top < ob->bottom && player->bottom > ob->top)\r
+               ob->state = &s_pixieshoot;\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_PixieShoot\r
+=\r
+===========================\r
+*/\r
+\r
+void T_PixieShoot(objtype *ob)\r
+{\r
+       GetNewObj(true);\r
+       new->x = ob->x;\r
+       new->y = ob->y + 8*PIXGLOBAL;\r
+       new->priority = 0;\r
+       new->obclass = mshotobj;\r
+       new->active = ac_removable;\r
+       SD_PlaySound(SND_KEENFIRE);     //BUG?\r
+       new->xdir = ob->xdir;\r
+       NewState(new, &s_pixiefire1);\r
+       SD_PlaySound(SND_SPRITEFIRE);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_Mshot\r
+=\r
+===========================\r
+*/\r
+\r
+void R_Mshot(objtype *ob)\r
+{\r
+       if (ob->hitnorth || ob->hiteast || ob->hitsouth || 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
+                                                 MINE\r
+\r
+=============================================================================\r
+*/\r
+statetype s_mine      = {MINESPR,         MINESPR,         think, false, false, 10, 0, 0, T_Platform, C_Mine, R_Draw, &s_mine};\r
+statetype s_mineboom1 = {MINEEXPLODE1SPR, MINEEXPLODE1SPR, step, false, false, 30, 0, 0, NULL, NULL, R_Draw, &s_mineboom2};\r
+statetype s_mineboom2 = {MINEEXPLODE2SPR, MINEEXPLODE2SPR, step, false, false, 30, 0, 0, NULL, NULL, R_Draw, NULL};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnMine\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnMine(Sint16 x, Sint16 y, Sint16 dir)\r
+{\r
+       GetNewObj(false);\r
+       new->obclass = mineobj;\r
+       new->active = ac_allways;\r
+       new->priority = 0;\r
+       new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+       new->y = CONVERT_TILE_TO_GLOBAL(y);\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
+               break;\r
+       }\r
+       NewState(new, &s_mine);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Mine\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Mine(objtype *ob, objtype *hit)\r
+{\r
+       if (hit->obclass == keenobj)\r
+       {\r
+               ChangeState(ob, &s_mineboom1);\r
+               SD_PlaySound(SND_MINEEXPLODE);\r
+               KillKeen();\r
+       }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 PRINCESS LINDSEY\r
+\r
+temp1 = initial y position\r
+\r
+=============================================================================\r
+*/\r
+statetype s_lindsey1 = {LINDSEY1SPR, LINDSEY1SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey2};\r
+statetype s_lindsey2 = {LINDSEY2SPR, LINDSEY2SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey3};\r
+statetype s_lindsey3 = {LINDSEY3SPR, LINDSEY3SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey4};\r
+statetype s_lindsey4 = {LINDSEY4SPR, LINDSEY4SPR, stepthink, false, false, 20, 0, 0, T_Lindsey, NULL, R_Draw, &s_lindsey1};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnLindsey\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnLindsey(Sint16 x, Sint16 y)\r
+{\r
+       GetNewObj(false);\r
+       new->obclass = lindseyobj;\r
+       new->active = ac_yes;\r
+       new->priority = 0;\r
+       new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+       new->y = new->temp1 = CONVERT_TILE_TO_GLOBAL(y) - TILEGLOBAL;\r
+       new->ydir = 1;\r
+       NewState(new, &s_lindsey1);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_Lindsey\r
+=\r
+===========================\r
+*/\r
+\r
+void T_Lindsey(objtype *ob)\r
+{\r
+       AccelerateY(ob, ob->ydir, 8);\r
+       if (ob->temp1 - (Sint16)ob->y > 2*PIXGLOBAL)\r
+       {\r
+               ob->ydir = 1;\r
+       }\r
+       if ((Sint16)ob->y - ob->temp1 > 2*PIXGLOBAL)\r
+       {\r
+               ob->ydir = -1;\r
+       }\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 DARTS\r
+\r
+temp1 = direction\r
+\r
+=============================================================================\r
+*/\r
+\r
+statetype s_dartthrower = {0, 0, step, false, false, 150, 0, 0, T_DartShoot, NULL, NULL, &s_dartthrower};\r
+statetype s_dart1       = {DARTL1SPR, DARTR1SPR, slide, false, false, 6, 64, 0, NULL, C_Lethal, R_Mshot, &s_dart2};\r
+statetype s_dart2       = {DARTL2SPR, DARTR2SPR, slide, false, false, 6, 64, 0, NULL, C_Lethal, R_Mshot, &s_dart1};\r
+statetype s_dartup1     = {DARTU1SPR, DARTU1SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartup2};\r
+statetype s_dartup2     = {DARTU2SPR, DARTU2SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartup1};\r
+statetype s_dartdown1   = {DARTD1SPR, DARTD1SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartdown2};\r
+statetype s_dartdown2   = {DARTD2SPR, DARTD2SPR, slide, false, false, 6, 0, 64, NULL, C_Lethal, R_Mshot, &s_dartdown1};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnDartShooter\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnDartShooter(Sint16 x, Sint16 y, Sint16 dir)\r
+{\r
+       GetNewObj(false);\r
+       new->obclass = inertobj;\r
+       new->active = ac_yes;\r
+       new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+       new->needtoclip = cl_noclip;\r
+       new->y = CONVERT_TILE_TO_GLOBAL(y);\r
+       new->temp1 = dir;\r
+       switch (dir)\r
+       {\r
+       case 0:\r
+               new->y -= 3*PIXGLOBAL;\r
+               new->x += 9*PIXGLOBAL;\r
+               new->shapenum = DARTU1SPR;\r
+               break;\r
+       case 1:\r
+               new->x += 8*PIXGLOBAL;\r
+               new->y += 5*PIXGLOBAL;\r
+               new->shapenum = DARTR1SPR;\r
+               break;\r
+       case 2:\r
+               new->x += 9*PIXGLOBAL;\r
+               new->shapenum = DARTD1SPR;\r
+               break;\r
+       case 3:\r
+               new->y += 7*PIXGLOBAL;\r
+               new->x -= 3*PIXGLOBAL;\r
+               new->shapenum = DARTL1SPR;\r
+               break;\r
+       }\r
+       NewState(new, &s_dartthrower);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= T_DartShoot\r
+=\r
+===========================\r
+*/\r
+\r
+void T_DartShoot(objtype *ob)\r
+{\r
+       GetNewObj(true);\r
+       new->x = ob->x;\r
+       new->y = ob->y;\r
+       new->obclass = mshotobj;\r
+       new->active = ac_removable;\r
+       switch (ob->temp1)\r
+       {\r
+       case 0:\r
+               new->xdir = 0;\r
+               new->ydir = -1;\r
+               NewState(new, &s_dartup1);\r
+               break;\r
+       case 1:\r
+               new->xdir = 1;\r
+               new->ydir = 0;\r
+               NewState(new, &s_dart1);\r
+               break;\r
+       case 2:\r
+               new->xdir = 0;\r
+               new->ydir = 1;\r
+               NewState(new, &s_dartdown1);\r
+               break;\r
+       case 3:\r
+               new->xdir = -1;\r
+               new->ydir = 0;\r
+               NewState(new, &s_dart1);\r
+               break;\r
+       }\r
+       SD_PlaySound(SND_SHOOTDART);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= R_DartThrower\r
+=\r
+===========================\r
+*/\r
+\r
+void R_DartThrower(objtype *ob)        //never used\r
+{\r
+       RF_PlaceSprite(&ob->sprite, ob->x, ob->y, ob->shapenum, spritedraw, ob->priority);\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                 SCUBA GEAR\r
+\r
+=============================================================================\r
+*/\r
+statetype s_scuba = {SCUBASPR, SCUBASPR, step, false, false, 30000, 0, 0, NULL, C_Scuba, R_Draw, &s_scuba};\r
+\r
+/*\r
+===========================\r
+=\r
+= SpawnScuba\r
+=\r
+===========================\r
+*/\r
+\r
+void SpawnScuba(Sint16 x, Sint16 y)\r
+{\r
+       GetNewObj(false);\r
+       new->obclass = scubaobj;\r
+       new->active = ac_yes;\r
+       new->x = CONVERT_TILE_TO_GLOBAL(x);\r
+       new->y = CONVERT_TILE_TO_GLOBAL(y) + -TILEGLOBAL;\r
+       NewState(new, &s_scuba);\r
+}\r
+\r
+/*\r
+===========================\r
+=\r
+= C_Scuba\r
+=\r
+===========================\r
+*/\r
+\r
+void C_Scuba(objtype *ob, objtype *hit)\r
+{\r
+       if (hit->obclass == keenobj && hit->hitnorth)\r
+       {\r
+               gamestate.wetsuit = true;\r
+               SD_PlaySound(SND_MAKEFOOT);\r
+               GotScuba();\r
+               RF_ForceRefresh();\r
+               playstate = ex_completed;\r
+               ob++;                   // shut up compiler\r
+       }\r
+}
\ No newline at end of file