]> 4ch.mooo.com Git - 16.git/blobdiff - src/lib/hb/c6_state.c
[16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / src / lib / hb / c6_state.c
diff --git a/src/lib/hb/c6_state.c b/src/lib/hb/c6_state.c
new file mode 100755 (executable)
index 0000000..e17b77f
--- /dev/null
@@ -0,0 +1,736 @@
+/* Catacomb Apocalypse Source Code\r
+ * Copyright (C) 1993-2014 Flat Rock Software\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
+// C3_STATE.C\r
+\r
+#include "DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+dirtype opposite[9] =\r
+       {south,west,north,east,southwest,northwest,northeast,southeast,nodir};\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= Internal_SpawnNewObj\r
+=\r
+===================\r
+*/\r
+void Internal_SpawnNewObj (unsigned x, unsigned y, statetype *state, unsigned size, boolean UseDummy, boolean PutInActorat)\r
+{\r
+       extern objtype dummyobj;\r
+\r
+       GetNewObj(UseDummy);\r
+       new->size = size;\r
+       new->state = state;\r
+       new->ticcount = random (state->tictime)+1;\r
+\r
+       new->tilex = x;\r
+       new->tiley = y;\r
+       new->x = ((long)x<<TILESHIFT)+TILEGLOBAL/2;\r
+       new->y = ((long)y<<TILESHIFT)+TILEGLOBAL/2;\r
+       CalcBounds(new);\r
+       new->dir = nodir;\r
+       new->active = noalways;\r
+\r
+       if (new != &dummyobj && PutInActorat)\r
+               actorat[new->tilex][new->tiley] = new;\r
+}\r
+\r
+void Internal_SpawnNewObjFrac (long x, long y, statetype *state, unsigned size,boolean UseDummy)\r
+{\r
+       GetNewObj(UseDummy);\r
+       new->size = size;\r
+       new->state = state;\r
+       new->ticcount = random (state->tictime)+1;\r
+       new->active = noalways;\r
+\r
+       new->x = x;\r
+       new->y = y;\r
+       new->tilex = x>>TILESHIFT;\r
+       new->tiley = y>>TILESHIFT;\r
+       CalcBounds(new);\r
+       new->distance = 100;\r
+       new->dir = nodir;\r
+}\r
+\r
+\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= CheckHandAttack\r
+=\r
+= If the object can move next to the player, it will return true\r
+=\r
+===================\r
+*/\r
+\r
+boolean CheckHandAttack (objtype *ob)\r
+{\r
+       long deltax,deltay,size;\r
+\r
+       size = (long)ob->size + player->size + ob->speed*tics + SIZE_TEST;\r
+       deltax = ob->x - player->x;\r
+       deltay = ob->y - player->y;\r
+\r
+       if (deltax > size || deltax < -size || deltay > size || deltay < -size)\r
+               return false;\r
+\r
+       return true;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= T_DoDamage\r
+=\r
+= Attacks the player if still nearby, then immediately changes to next state\r
+=\r
+===================\r
+*/\r
+\r
+void T_DoDamage (objtype *ob)\r
+{\r
+       int     points;\r
+\r
+\r
+       if (CheckHandAttack(ob) && (!(ob->flags & of_damagedone)))\r
+       {\r
+               points = 0;\r
+\r
+               switch (ob->obclass)\r
+               {\r
+               case aquamanobj:\r
+                       points = 7;\r
+               break;\r
+\r
+               case wizardobj:\r
+                       points = 7;\r
+               break;\r
+\r
+               case trollobj:\r
+                       points = 10;\r
+               break;\r
+\r
+               case invisdudeobj:\r
+                       points = 10;\r
+               break;\r
+\r
+               case demonobj:\r
+               case cyborgdemonobj:\r
+                       points = 15;\r
+               break;\r
+\r
+               }\r
+               points = EasyDoDamage(points);\r
+               TakeDamage (points);\r
+               ob->flags |= of_damagedone;\r
+       }\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+/*\r
+==================================\r
+=\r
+= Walk\r
+=\r
+==================================\r
+*/\r
+\r
+boolean Walk (objtype *ob)\r
+{\r
+       switch (ob->dir)\r
+       {\r
+       case north:\r
+               if (actorat[ob->tilex][ob->tiley-1])\r
+                       return false;\r
+               ob->tiley--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case northeast:\r
+               if (actorat[ob->tilex+1][ob->tiley-1])\r
+                       return false;\r
+               ob->tilex++;\r
+               ob->tiley--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case east:\r
+               if (actorat[ob->tilex+1][ob->tiley])\r
+                       return false;\r
+               ob->tilex++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case southeast:\r
+               if (actorat[ob->tilex+1][ob->tiley+1])\r
+                       return false;\r
+               ob->tilex++;\r
+               ob->tiley++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case south:\r
+               if (actorat[ob->tilex][ob->tiley+1])\r
+                       return false;\r
+               ob->tiley++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case southwest:\r
+               if (actorat[ob->tilex-1][ob->tiley+1])\r
+                       return false;\r
+               ob->tilex--;\r
+               ob->tiley++;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case west:\r
+               if (actorat[ob->tilex-1][ob->tiley])\r
+                       return false;\r
+               ob->tilex--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case northwest:\r
+               if (actorat[ob->tilex-1][ob->tiley-1])\r
+                       return false;\r
+               ob->tilex--;\r
+               ob->tiley--;\r
+               ob->distance = TILEGLOBAL;\r
+               return true;\r
+\r
+       case nodir:\r
+               return false;\r
+       }\r
+\r
+       Quit ("Walk: Bad dir");\r
+       return false;\r
+}\r
+\r
+\r
+\r
+/*\r
+==================================\r
+=\r
+= ChaseThink\r
+= have the current monster go after the player,\r
+= either diagonally or straight on\r
+=\r
+==================================\r
+*/\r
+\r
+void ChaseThink (objtype *obj, boolean diagonal)\r
+{\r
+       int deltax,deltay,i;\r
+       dirtype d[3];\r
+       dirtype tdir, olddir, turnaround;\r
+\r
+\r
+       olddir=obj->dir;\r
+       turnaround=opposite[olddir];\r
+\r
+       deltax=player->tilex - obj->tilex;\r
+       deltay=player->tiley - obj->tiley;\r
+\r
+       d[1]=nodir;\r
+       d[2]=nodir;\r
+\r
+       if (deltax>0)\r
+               d[1]= east;\r
+       if (deltax<0)\r
+               d[1]= west;\r
+       if (deltay>0)\r
+               d[2]=south;\r
+       if (deltay<0)\r
+               d[2]=north;\r
+\r
+       if (abs(deltay)>abs(deltax))\r
+       {\r
+               tdir=d[1];\r
+               d[1]=d[2];\r
+               d[2]=tdir;\r
+       }\r
+\r
+       if (d[1]==turnaround)\r
+               d[1]=nodir;\r
+       if (d[2]==turnaround)\r
+               d[2]=nodir;\r
+\r
+\r
+       if (diagonal)\r
+       {                           /*ramdiagonals try the best dir first*/\r
+               if (d[1]!=nodir)\r
+               {\r
+                       obj->dir=d[1];\r
+                       if (Walk(obj))\r
+                               return;     /*either moved forward or attacked*/\r
+               }\r
+\r
+               if (d[2]!=nodir)\r
+               {\r
+                       obj->dir=d[2];\r
+                       if (Walk(obj))\r
+                               return;\r
+               }\r
+       }\r
+       else\r
+       {                  /*ramstraights try the second best dir first*/\r
+\r
+               if (d[2]!=nodir)\r
+               {\r
+                       obj->dir=d[2];\r
+                       if (Walk(obj))\r
+                               return;\r
+               }\r
+\r
+               if (d[1]!=nodir)\r
+               {\r
+                       obj->dir=d[1];\r
+                       if (Walk(obj))\r
+                               return;\r
+               }\r
+       }\r
+\r
+       // Kluge to make the running eye stay in place if blocked, ie, not divert\r
+       // from path\r
+       if (obj->obclass == reyeobj)\r
+               return;\r
+\r
+\r
+/* there is no direct path to the player, so pick another direction */\r
+\r
+       obj->dir=olddir;\r
+       if (Walk(obj))\r
+               return;\r
+\r
+       if (US_RndT()>128)      /*randomly determine direction of search*/\r
+       {\r
+               for (tdir=north;tdir<=west;tdir++)\r
+               {\r
+                       if (tdir!=turnaround)\r
+                       {\r
+                               obj->dir=tdir;\r
+                               if (Walk(obj))\r
+                                       return;\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               for (tdir=west;tdir>=north;tdir--)\r
+               {\r
+                       if (tdir!=turnaround)\r
+                       {\r
+                         obj->dir=tdir;\r
+                         if (Walk(obj))\r
+                               return;\r
+                       }\r
+               }\r
+       }\r
+\r
+       obj->dir=turnaround;\r
+       Walk(obj);              /*last chance, don't worry about returned value*/\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= MoveObj\r
+=\r
+=================\r
+*/\r
+\r
+void MoveObj (objtype *ob, long move)\r
+{\r
+       ob->distance -=move;\r
+\r
+       switch (ob->dir)\r
+       {\r
+       case north:\r
+               ob->y -= move;\r
+               return;\r
+       case northeast:\r
+               ob->x += move;\r
+               ob->y -= move;\r
+               return;\r
+       case east:\r
+               ob->x += move;\r
+               return;\r
+       case southeast:\r
+               ob->x += move;\r
+               ob->y += move;\r
+               return;\r
+       case south:\r
+               ob->y += move;\r
+               return;\r
+       case southwest:\r
+               ob->x -= move;\r
+               ob->y += move;\r
+               return;\r
+       case west:\r
+               ob->x -= move;\r
+               return;\r
+       case northwest:\r
+               ob->x -= move;\r
+               ob->y -= move;\r
+               return;\r
+\r
+       case nodir:\r
+               return;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+=================\r
+=\r
+= Chase\r
+=\r
+= returns true if hand attack range\r
+=\r
+=================\r
+*/\r
+\r
+boolean Chase (objtype *ob, boolean diagonal)\r
+{\r
+       long move;\r
+       long deltax,deltay,size;\r
+\r
+       ob->flags &= ~of_damagedone;\r
+\r
+       move = ob->speed*tics;\r
+       size = (long)ob->size + player->size + move + SIZE_TEST;\r
+\r
+       while (move)\r
+       {\r
+               deltax = ob->x - player->x;\r
+               deltay = ob->y - player->y;\r
+\r
+               if (deltax <= size && deltax >= -size\r
+               && deltay <= size && deltay >= -size)\r
+               {\r
+                       CalcBounds (ob);\r
+                       return true;\r
+               }\r
+\r
+               if (move < ob->distance)                //ob->distance - distance before you move\r
+               {                             //               over into next tile\r
+                       MoveObj (ob,move);\r
+                       break;\r
+               }\r
+               else\r
+                       if (ob->obclass == reyeobj)     // Kludge for the "running eye"\r
+                       {\r
+                               if (ob->temp1 < 2)\r
+                               {\r
+                                       MoveObj(ob, ob->distance/2);\r
+                                       ob->temp1 = 0;\r
+                               }\r
+                       }\r
+\r
+               actorat[ob->tilex][ob->tiley] = 0;      // pick up marker from goal\r
+               if (ob->dir == nodir)\r
+                       ob->dir = north;\r
+\r
+               ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+               ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+               move -= ob->distance;\r
+\r
+               ChaseThink (ob, diagonal);\r
+               if (!ob->distance)\r
+                       break;                  // no possible move\r
+               actorat[ob->tilex][ob->tiley] = ob;     // set down a new goal marker\r
+       }\r
+       CalcBounds (ob);\r
+       return false;\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ShootActor\r
+=\r
+===================\r
+*/\r
+\r
+void ShootActor (objtype *ob, unsigned damage)\r
+{\r
+\r
+       ob->hitpoints -= damage;\r
+\r
+       if (ob->hitpoints<=0)\r
+       {\r
+               switch (ob->obclass)\r
+               {\r
+\r
+               case headobj:\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->obclass = expobj;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));\r
+               break;\r
+\r
+               case aquamanobj:\r
+                       ob->state = &s_aqua_die1;\r
+                       ob->temp1 = 10;\r
+               break;\r
+\r
+               case wizardobj:\r
+                       ob->state = &s_wizard_die1;\r
+               break;\r
+\r
+               case trollobj:\r
+                       ob->state = &s_trolldie1;\r
+               break;\r
+\r
+               case blobobj:\r
+                       ob->state = &s_blob_die1;\r
+               break;\r
+\r
+               case rayobj:\r
+                       ob->state = &s_ray_die1;\r
+               break;\r
+\r
+               case ramboneobj:\r
+                       ob->state = &s_skel_die1;\r
+               break;\r
+\r
+               case fmageobj:\r
+                       ob->state = &s_fmagedie1;\r
+               break;\r
+\r
+               case robotankobj:\r
+                       ob->state = &s_robotank_death1;\r
+                       ob->temp1 = 10;\r
+               break;\r
+\r
+               case stompyobj:\r
+                       ob->state = &s_stompy_death1;\r
+               break;\r
+\r
+               case bugobj:\r
+                       ob->state = &s_bug_death1;\r
+               break;\r
+\r
+               case demonobj:\r
+                       ob->state = &s_demondie1;\r
+               break;\r
+\r
+               case cyborgdemonobj:\r
+                       ob->state = &s_cyborg_demondie1;\r
+               break;\r
+\r
+               case invisdudeobj:\r
+                       ob->state = &s_invis_death1;\r
+               break;\r
+\r
+               case grelmobj:\r
+                       ob->state = &s_greldie1;\r
+               break;\r
+\r
+               case eyeobj:\r
+                       ob->state = &s_eye_die1;\r
+               break;\r
+\r
+               case reyeobj:\r
+                       ob->state = &s_reye_die1;\r
+               break;\r
+\r
+               case bounceobj:\r
+                       ob->state = &s_pshot_exp1;\r
+                       ob->obclass = expobj;\r
+                       ob->ticcount = ob->state->tictime;\r
+                       SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));\r
+               break;\r
+\r
+               case rshotobj:\r
+               case eshotobj:\r
+               case wshotobj:\r
+               case hshotobj:\r
+               case bshotobj:\r
+               case rbshotobj:\r
+               case fmshotobj:\r
+               case rtshotobj:\r
+               case syshotobj:\r
+               case bgshotobj:\r
+                       ob->state = &s_bonus_die;\r
+#if USE_INERT_LIST\r
+                       ob->obclass = solidobj;         // don't add these objs to inert list\r
+#endif\r
+               break;\r
+\r
+               case bonusobj:\r
+               case freezeobj:\r
+                       switch (ob->temp1)\r
+                       {\r
+                               case B_POTION:\r
+                               case B_OLDCHEST:\r
+                               case B_CHEST:\r
+                               case B_NUKE:\r
+                               case B_BOLT:\r
+                                       ob->state = &s_pshot_exp1;\r
+                                       ob->obclass = expobj;\r
+                                       ob->ticcount = ob->state->tictime;\r
+                                       SpawnBigExplosion(ob->x,ob->y,12,(16l<<16L));\r
+                                       bordertime = FLASHTICS<<2;\r
+                                       bcolor = 14;\r
+                                       VW_ColorBorder(14 | 56);\r
+                                       DisplaySMsg("Item destroyed", NULL);\r
+                                       status_flag  = S_NONE;\r
+                                       status_delay = 80;\r
+                               break;\r
+                       }\r
+#if USE_INERT_LIST\r
+                       ob->obclass = solidobj;         // don't add this obj to inert list\r
+#endif\r
+               break;\r
+               }\r
+\r
+               if (ob->obclass != solidobj && ob->obclass != realsolidobj)\r
+               {\r
+                       ob->obclass = inertobj;\r
+                       ob->flags &= ~of_shootable;\r
+                       actorat[ob->tilex][ob->tiley] = NULL;\r
+#if USE_INERT_LIST\r
+                       MoveObjToInert(ob);\r
+#endif\r
+               }\r
+               else\r
+               {\r
+                       if (ob->flags & of_forcefield)\r
+                       {\r
+                               ob->state = &s_force_field_die;\r
+                               ob->flags &= ~of_shootable;\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               switch (ob->obclass)\r
+               {\r
+               case wizardobj:\r
+                       ob->state = &s_wizard_ouch;\r
+               break;\r
+\r
+               case trollobj:\r
+                       if (!random(5))\r
+                               ob->state = &s_trollouch;\r
+                       else\r
+                               return;\r
+               break;\r
+\r
+               case blobobj:\r
+                       ob->state = &s_blob_ouch;\r
+               break;\r
+\r
+               case ramboneobj:\r
+                       ob->state = &s_skel_ouch;\r
+               break;\r
+\r
+               case fmageobj:\r
+                       ob->state = &s_fmageouch;\r
+               break;\r
+\r
+               case stompyobj:\r
+                       ob->state = &s_stompy_ouch;\r
+               break;\r
+\r
+               case bugobj:\r
+                       ob->state = &s_bug_ouch;\r
+               break;\r
+\r
+               case cyborgdemonobj:\r
+                       if (!(random(8)))\r
+                               ob->state = &s_cyborg_demonouch;\r
+                       else\r
+                               return;\r
+               break;\r
+\r
+               case demonobj:\r
+                       if (!(random(8)))\r
+                               ob->state = &s_demonouch;\r
+                       else\r
+                               return;\r
+               break;\r
+\r
+               case invisdudeobj:\r
+                       ob->state = &s_invis_fizz1;\r
+               break;\r
+\r
+               case grelmobj:\r
+                       ob->state = &s_grelouch;\r
+               break;\r
+\r
+               case eyeobj:\r
+                       ob->state = &s_eye_ouch;\r
+               break;\r
+\r
+               case reyeobj:\r
+                       ob->state = &s_reye_ouch;\r
+               break;\r
+               }\r
+       }\r
+\r
+       ob->ticcount = ob->state->tictime;\r
+}\r
+\r
+\r