]> 4ch.mooo.com Git - 16.git/blobdiff - 16/sod8086/wl_agent.c
got 8086 port of wolf3d to work and sod to work
[16.git] / 16 / sod8086 / wl_agent.c
diff --git a/16/sod8086/wl_agent.c b/16/sod8086/wl_agent.c
new file mode 100755 (executable)
index 0000000..631478d
--- /dev/null
@@ -0,0 +1,1421 @@
+// WL_AGENT.C\r
+\r
+#include "WL_DEF.H"\r
+#pragma hdrstop\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define MAXMOUSETURN   10\r
+\r
+\r
+#define MOVESCALE              150l\r
+#define BACKMOVESCALE  100l\r
+#define ANGLESCALE             20\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+//\r
+// player state info\r
+//\r
+boolean                running;\r
+long           thrustspeed;\r
+\r
+unsigned       plux,pluy;                      // player coordinates scaled to unsigned\r
+\r
+int                    anglefrac;\r
+int                    gotgatgun;      // JR\r
+\r
+objtype                *LastAttacker;\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+void   T_Player (objtype *ob);\r
+void   T_Attack (objtype *ob);\r
+\r
+statetype s_player = {false,0,0,T_Player,NULL,NULL};\r
+statetype s_attack = {false,0,0,T_Attack,NULL,NULL};\r
+\r
+\r
+long   playerxmove,playerymove;\r
+\r
+struct atkinf\r
+{\r
+       char    tics,attack,frame;              // attack is 1 for gun, 2 for knife\r
+} attackinfo[4][14] =\r
+\r
+{\r
+{ {6,0,1},{6,2,2},{6,0,3},{6,-1,4} },\r
+{ {6,0,1},{6,1,2},{6,0,3},{6,-1,4} },\r
+{ {6,0,1},{6,1,2},{6,3,3},{6,-1,4} },\r
+{ {6,0,1},{6,1,2},{6,4,3},{6,-1,4} },\r
+};\r
+\r
+\r
+int    strafeangle[9] = {0,90,180,270,45,135,225,315,0};\r
+\r
+void DrawWeapon (void);\r
+void GiveWeapon (int weapon);\r
+void   GiveAmmo (int ammo);\r
+\r
+//===========================================================================\r
+\r
+//----------\r
+\r
+void Attack (void);\r
+void Use (void);\r
+void Search (objtype *ob);\r
+void SelectWeapon (void);\r
+void SelectItem (void);\r
+\r
+//----------\r
+\r
+boolean TryMove (objtype *ob);\r
+void T_Player (objtype *ob);\r
+\r
+void ClipMove (objtype *ob, long xmove, long ymove);\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                               CONTROL STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+/*\r
+======================\r
+=\r
+= CheckWeaponChange\r
+=\r
+= Keys 1-4 change weapons\r
+=\r
+======================\r
+*/\r
+\r
+void CheckWeaponChange (void)\r
+{\r
+       int     i,buttons;\r
+\r
+       if (!gamestate.ammo)            // must use knife with no ammo\r
+               return;\r
+\r
+       for (i=wp_knife ; i<=gamestate.bestweapon ; i++)\r
+               if (buttonstate[bt_readyknife+i-wp_knife])\r
+               {\r
+                       gamestate.weapon = gamestate.chosenweapon = i;\r
+                       DrawWeapon ();\r
+                       return;\r
+               }\r
+}\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= ControlMovement\r
+=\r
+= Takes controlx,controly, and buttonstate[bt_strafe]\r
+=\r
+= Changes the player's angle and position\r
+=\r
+= There is an angle hack because when going 70 fps, the roundoff becomes\r
+= significant\r
+=\r
+=======================\r
+*/\r
+\r
+void ControlMovement (objtype *ob)\r
+{\r
+       long    oldx,oldy;\r
+       int             angle,maxxmove;\r
+       int             angleunits;\r
+       long    speed;\r
+\r
+       thrustspeed = 0;\r
+\r
+       oldx = player->x;\r
+       oldy = player->y;\r
+\r
+//\r
+// side to side move\r
+//\r
+       if (buttonstate[bt_strafe])\r
+       {\r
+       //\r
+       // strafing\r
+       //\r
+       //\r
+               if (controlx > 0)\r
+               {\r
+                       angle = ob->angle - ANGLES/4;\r
+                       if (angle < 0)\r
+                               angle += ANGLES;\r
+                       Thrust (angle,controlx*MOVESCALE);      // move to left\r
+               }\r
+               else if (controlx < 0)\r
+               {\r
+                       angle = ob->angle + ANGLES/4;\r
+                       if (angle >= ANGLES)\r
+                               angle -= ANGLES;\r
+                       Thrust (angle,-controlx*MOVESCALE);     // move to right\r
+               }\r
+       }\r
+       else\r
+       {\r
+       //\r
+       // not strafing\r
+       //\r
+               anglefrac += controlx;\r
+               angleunits = anglefrac/ANGLESCALE;\r
+               anglefrac -= angleunits*ANGLESCALE;\r
+               ob->angle -= angleunits;\r
+\r
+               if (ob->angle >= ANGLES)\r
+                       ob->angle -= ANGLES;\r
+               if (ob->angle < 0)\r
+                       ob->angle += ANGLES;\r
+\r
+       }\r
+\r
+//\r
+// forward/backwards move\r
+//\r
+       if (controly < 0)\r
+       {\r
+               Thrust (ob->angle,-controly*MOVESCALE); // move forwards\r
+       }\r
+       else if (controly > 0)\r
+       {\r
+               angle = ob->angle + ANGLES/2;\r
+               if (angle >= ANGLES)\r
+                       angle -= ANGLES;\r
+               Thrust (angle,controly*BACKMOVESCALE);          // move backwards\r
+       }\r
+\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+               return;\r
+\r
+//\r
+// calculate total move\r
+//\r
+       playerxmove = player->x - oldx;\r
+       playerymove = player->y - oldy;\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                       STATUS WINDOW STUFF\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= StatusDrawPic\r
+=\r
+==================\r
+*/\r
+\r
+void StatusDrawPic (unsigned x, unsigned y, unsigned picnum)\r
+{\r
+       unsigned        temp;\r
+\r
+       temp = bufferofs;\r
+       bufferofs = 0;\r
+\r
+       bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH;\r
+       LatchDrawPic (x,y,picnum);\r
+       bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH;\r
+       LatchDrawPic (x,y,picnum);\r
+       bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH;\r
+       LatchDrawPic (x,y,picnum);\r
+\r
+       bufferofs = temp;\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= DrawFace\r
+=\r
+==================\r
+*/\r
+\r
+void DrawFace (void)\r
+{\r
+       if (gamestate.health)\r
+       {\r
+               #ifdef SPEAR\r
+               if (godmode)\r
+                       StatusDrawPic (17,4,GODMODEFACE1PIC+gamestate.faceframe);\r
+               else\r
+               #endif\r
+               StatusDrawPic (17,4,FACE1APIC+3*((100-gamestate.health)/16)+gamestate.faceframe);\r
+       }\r
+       else\r
+       {\r
+#ifndef SPEAR\r
+        if (LastAttacker->obclass == needleobj)\r
+          StatusDrawPic (17,4,MUTANTBJPIC);\r
+        else\r
+#endif\r
+          StatusDrawPic (17,4,FACE8APIC);\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= UpdateFace\r
+=\r
+= Calls draw face if time to change\r
+=\r
+===============\r
+*/\r
+\r
+#define FACETICS       70\r
+\r
+int    facecount;\r
+\r
+void   UpdateFace (void)\r
+{\r
+\r
+       if (SD_SoundPlaying() == GETGATLINGSND)\r
+         return;\r
+\r
+       facecount += tics;\r
+       if (facecount > US_RndT())\r
+       {\r
+               gamestate.faceframe = (US_RndT()>>6);\r
+               if (gamestate.faceframe==3)\r
+                       gamestate.faceframe = 1;\r
+\r
+               facecount = 0;\r
+               DrawFace ();\r
+       }\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= LatchNumber\r
+=\r
+= right justifies and pads with blanks\r
+=\r
+===============\r
+*/\r
+\r
+void   LatchNumber (int x, int y, int width, long number)\r
+{\r
+       unsigned        length,c;\r
+       char    str[20];\r
+\r
+       ltoa (number,str,10);\r
+\r
+       length = strlen (str);\r
+\r
+       while (length<width)\r
+       {\r
+               StatusDrawPic (x,y,N_BLANKPIC);\r
+               x++;\r
+               width--;\r
+       }\r
+\r
+       c= length <= width ? 0 : length-width;\r
+\r
+       while (c<length)\r
+       {\r
+               StatusDrawPic (x,y,str[c]-'0'+ N_0PIC);\r
+               x++;\r
+               c++;\r
+       }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawHealth\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawHealth (void)\r
+{\r
+       LatchNumber (21,16,3,gamestate.health);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeDamage\r
+=\r
+===============\r
+*/\r
+\r
+void   TakeDamage (int points,objtype *attacker)\r
+{\r
+       LastAttacker = attacker;\r
+\r
+       if (gamestate.victoryflag)\r
+               return;\r
+       if (gamestate.difficulty==gd_baby)\r
+         points>>=2;\r
+\r
+       if (!godmode)\r
+               gamestate.health -= points;\r
+\r
+       if (gamestate.health<=0)\r
+       {\r
+               gamestate.health = 0;\r
+               playstate = ex_died;\r
+               killerobj = attacker;\r
+       }\r
+\r
+       StartDamageFlash (points);\r
+\r
+       gotgatgun=0;\r
+\r
+       DrawHealth ();\r
+       DrawFace ();\r
+\r
+       //\r
+       // MAKE BJ'S EYES BUG IF MAJOR DAMAGE!\r
+       //\r
+       #ifdef SPEAR\r
+       if (points > 30 && gamestate.health!=0 && !godmode)\r
+       {\r
+               StatusDrawPic (17,4,BJOUCHPIC);\r
+               facecount = 0;\r
+       }\r
+       #endif\r
+\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= HealSelf\r
+=\r
+===============\r
+*/\r
+\r
+void   HealSelf (int points)\r
+{\r
+       gamestate.health += points;\r
+       if (gamestate.health>100)\r
+               gamestate.health = 100;\r
+\r
+       DrawHealth ();\r
+       gotgatgun = 0;  // JR\r
+       DrawFace ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawLevel\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawLevel (void)\r
+{\r
+#ifdef SPEAR\r
+       if (gamestate.mapon == 20)\r
+               LatchNumber (2,16,2,18);\r
+       else\r
+#endif\r
+       LatchNumber (2,16,2,gamestate.mapon+1);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawLives\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawLives (void)\r
+{\r
+       LatchNumber (14,16,1,gamestate.lives);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= GiveExtraMan\r
+=\r
+===============\r
+*/\r
+\r
+void   GiveExtraMan (void)\r
+{\r
+       if (gamestate.lives<9)\r
+               gamestate.lives++;\r
+       DrawLives ();\r
+       SD_PlaySound (BONUS1UPSND);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawScore\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawScore (void)\r
+{\r
+       LatchNumber (6,16,6,gamestate.score);\r
+}\r
+\r
+/*\r
+===============\r
+=\r
+= GivePoints\r
+=\r
+===============\r
+*/\r
+\r
+void   GivePoints (long points)\r
+{\r
+       gamestate.score += points;\r
+       while (gamestate.score >= gamestate.nextextra)\r
+       {\r
+               gamestate.nextextra += EXTRAPOINTS;\r
+               GiveExtraMan ();\r
+       }\r
+       DrawScore ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= DrawWeapon\r
+=\r
+==================\r
+*/\r
+\r
+void DrawWeapon (void)\r
+{\r
+       StatusDrawPic (32,8,KNIFEPIC+gamestate.weapon);\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= DrawKeys\r
+=\r
+==================\r
+*/\r
+\r
+void DrawKeys (void)\r
+{\r
+       if (gamestate.keys & 1)\r
+               StatusDrawPic (30,4,GOLDKEYPIC);\r
+       else\r
+               StatusDrawPic (30,4,NOKEYPIC);\r
+\r
+       if (gamestate.keys & 2)\r
+               StatusDrawPic (30,20,SILVERKEYPIC);\r
+       else\r
+               StatusDrawPic (30,20,NOKEYPIC);\r
+}\r
+\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= GiveWeapon\r
+=\r
+==================\r
+*/\r
+\r
+void GiveWeapon (int weapon)\r
+{\r
+       GiveAmmo (6);\r
+\r
+       if (gamestate.bestweapon<weapon)\r
+               gamestate.bestweapon = gamestate.weapon\r
+               = gamestate.chosenweapon = weapon;\r
+\r
+       DrawWeapon ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawAmmo\r
+=\r
+===============\r
+*/\r
+\r
+void   DrawAmmo (void)\r
+{\r
+       LatchNumber (27,16,2,gamestate.ammo);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= GiveAmmo\r
+=\r
+===============\r
+*/\r
+\r
+void   GiveAmmo (int ammo)\r
+{\r
+       if (!gamestate.ammo)                            // knife was out\r
+       {\r
+               if (!gamestate.attackframe)\r
+               {\r
+                       gamestate.weapon = gamestate.chosenweapon;\r
+                       DrawWeapon ();\r
+               }\r
+       }\r
+       gamestate.ammo += ammo;\r
+       if (gamestate.ammo > 99)\r
+               gamestate.ammo = 99;\r
+       DrawAmmo ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+==================\r
+=\r
+= GiveKey\r
+=\r
+==================\r
+*/\r
+\r
+void GiveKey (int key)\r
+{\r
+       gamestate.keys |= (1<<key);\r
+       DrawKeys ();\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                       MOVEMENT\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= GetBonus\r
+=\r
+===================\r
+*/\r
+void GetBonus (statobj_t *check)\r
+{\r
+       switch (check->itemnumber)\r
+       {\r
+       case    bo_firstaid:\r
+               if (gamestate.health == 100)\r
+                       return;\r
+\r
+               SD_PlaySound (HEALTH2SND);\r
+               HealSelf (25);\r
+               break;\r
+\r
+       case    bo_key1:\r
+       case    bo_key2:\r
+       case    bo_key3:\r
+       case    bo_key4:\r
+               GiveKey (check->itemnumber - bo_key1);\r
+               SD_PlaySound (GETKEYSND);\r
+               break;\r
+\r
+       case    bo_cross:\r
+               SD_PlaySound (BONUS1SND);\r
+               GivePoints (100);\r
+               gamestate.treasurecount++;\r
+               break;\r
+       case    bo_chalice:\r
+               SD_PlaySound (BONUS2SND);\r
+               GivePoints (500);\r
+               gamestate.treasurecount++;\r
+               break;\r
+       case    bo_bible:\r
+               SD_PlaySound (BONUS3SND);\r
+               GivePoints (1000);\r
+               gamestate.treasurecount++;\r
+               break;\r
+       case    bo_crown:\r
+               SD_PlaySound (BONUS4SND);\r
+               GivePoints (5000);\r
+               gamestate.treasurecount++;\r
+               break;\r
+\r
+       case    bo_clip:\r
+               if (gamestate.ammo == 99)\r
+                       return;\r
+\r
+               SD_PlaySound (GETAMMOSND);\r
+               GiveAmmo (8);\r
+               break;\r
+       case    bo_clip2:\r
+               if (gamestate.ammo == 99)\r
+                       return;\r
+\r
+               SD_PlaySound (GETAMMOSND);\r
+               GiveAmmo (4);\r
+               break;\r
+\r
+#ifdef SPEAR\r
+       case    bo_25clip:\r
+               if (gamestate.ammo == 99)\r
+                 return;\r
+\r
+               SD_PlaySound (GETAMMOBOXSND);\r
+               GiveAmmo (25);\r
+               break;\r
+#endif\r
+\r
+       case    bo_machinegun:\r
+               SD_PlaySound (GETMACHINESND);\r
+               GiveWeapon (wp_machinegun);\r
+               break;\r
+       case    bo_chaingun:\r
+               SD_PlaySound (GETGATLINGSND);\r
+               GiveWeapon (wp_chaingun);\r
+\r
+               StatusDrawPic (17,4,GOTGATLINGPIC);\r
+               facecount = 0;\r
+               gotgatgun = 1;\r
+               break;\r
+\r
+       case    bo_fullheal:\r
+               SD_PlaySound (BONUS1UPSND);\r
+               HealSelf (99);\r
+               GiveAmmo (25);\r
+               GiveExtraMan ();\r
+               gamestate.treasurecount++;\r
+               break;\r
+\r
+       case    bo_food:\r
+               if (gamestate.health == 100)\r
+                       return;\r
+\r
+               SD_PlaySound (HEALTH1SND);\r
+               HealSelf (10);\r
+               break;\r
+\r
+       case    bo_alpo:\r
+               if (gamestate.health == 100)\r
+                       return;\r
+\r
+               SD_PlaySound (HEALTH1SND);\r
+               HealSelf (4);\r
+               break;\r
+\r
+       case    bo_gibs:\r
+               if (gamestate.health >10)\r
+                       return;\r
+\r
+               SD_PlaySound (SLURPIESND);\r
+               HealSelf (1);\r
+               break;\r
+\r
+       case    bo_spear:\r
+               spearflag = true;\r
+               spearx = player->x;\r
+               speary = player->y;\r
+               spearangle = player->angle;\r
+               playstate = ex_completed;\r
+       }\r
+\r
+       StartBonusFlash ();\r
+       check->shapenum = -1;                   // remove from list\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= TryMove\r
+=\r
+= returns true if move ok\r
+= debug: use pointers to optimize\r
+===================\r
+*/\r
+\r
+boolean TryMove (objtype *ob)\r
+{\r
+       int                     xl,yl,xh,yh,x,y;\r
+       objtype         *check;\r
+       long            deltax,deltay;\r
+\r
+       xl = (ob->x-PLAYERSIZE) >>TILESHIFT;\r
+       yl = (ob->y-PLAYERSIZE) >>TILESHIFT;\r
+\r
+       xh = (ob->x+PLAYERSIZE) >>TILESHIFT;\r
+       yh = (ob->y+PLAYERSIZE) >>TILESHIFT;\r
+\r
+//\r
+// check for solid walls\r
+//\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (check && check<objlist)\r
+                               return false;\r
+               }\r
+\r
+//\r
+// check for actors\r
+//\r
+       if (yl>0)\r
+               yl--;\r
+       if (yh<MAPSIZE-1)\r
+               yh++;\r
+       if (xl>0)\r
+               xl--;\r
+       if (xh<MAPSIZE-1)\r
+               xh++;\r
+\r
+       for (y=yl;y<=yh;y++)\r
+               for (x=xl;x<=xh;x++)\r
+               {\r
+                       check = actorat[x][y];\r
+                       if (check > objlist\r
+                       && (check->flags & FL_SHOOTABLE) )\r
+                       {\r
+                               deltax = ob->x - check->x;\r
+                               if (deltax < -MINACTORDIST || deltax > MINACTORDIST)\r
+                                       continue;\r
+                               deltay = ob->y - check->y;\r
+                               if (deltay < -MINACTORDIST || deltay > MINACTORDIST)\r
+                                       continue;\r
+\r
+                               return false;\r
+                       }\r
+               }\r
+\r
+       return true;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ClipMove\r
+=\r
+===================\r
+*/\r
+\r
+void ClipMove (objtype *ob, long xmove, long ymove)\r
+{\r
+       long    basex,basey;\r
+\r
+       basex = ob->x;\r
+       basey = ob->y;\r
+\r
+       ob->x = basex+xmove;\r
+       ob->y = basey+ymove;\r
+       if (TryMove (ob))\r
+               return;\r
+\r
+       if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL &&\r
+       ob->x < (((long)(mapwidth-1))<<TILESHIFT)\r
+       && ob->y < (((long)(mapheight-1))<<TILESHIFT) )\r
+               return;         // walk through walls\r
+\r
+       if (!SD_SoundPlaying())\r
+               SD_PlaySound (HITWALLSND);\r
+\r
+       ob->x = basex+xmove;\r
+       ob->y = basey;\r
+       if (TryMove (ob))\r
+               return;\r
+\r
+       ob->x = basex;\r
+       ob->y = basey+ymove;\r
+       if (TryMove (ob))\r
+               return;\r
+\r
+       ob->x = basex;\r
+       ob->y = basey;\r
+}\r
+\r
+//==========================================================================\r
+\r
+/*\r
+===================\r
+=\r
+= VictoryTile\r
+=\r
+===================\r
+*/\r
+\r
+void VictoryTile (void)\r
+{\r
+#ifndef SPEAR\r
+       SpawnBJVictory ();\r
+#endif\r
+\r
+       gamestate.victoryflag = true;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= Thrust\r
+=\r
+===================\r
+*/\r
+\r
+void Thrust (int angle, long speed)\r
+{\r
+       long xmove,ymove;\r
+       long    slowmax;\r
+       unsigned        offset;\r
+\r
+\r
+       //\r
+       // ZERO FUNNY COUNTER IF MOVED!\r
+       //\r
+       #ifdef SPEAR\r
+       if (speed)\r
+               funnyticount = 0;\r
+       #endif\r
+\r
+       thrustspeed += speed;\r
+//\r
+// moving bounds speed\r
+//\r
+       if (speed >= MINDIST*2)\r
+               speed = MINDIST*2-1;\r
+\r
+       xmove = FixedByFrac(speed,costable[angle]);\r
+       ymove = -FixedByFrac(speed,sintable[angle]);\r
+\r
+       ClipMove(player,xmove,ymove);\r
+\r
+       player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
+       player->tiley = player->y >> TILESHIFT;\r
+\r
+       offset = farmapylookup[player->tiley]+player->tilex;\r
+       player->areanumber = *(mapsegs[0] + offset) -AREATILE;\r
+\r
+       if (*(mapsegs[1] + offset) == EXITTILE)\r
+               VictoryTile ();\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                               ACTIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= Cmd_Fire\r
+=\r
+===============\r
+*/\r
+\r
+void Cmd_Fire (void)\r
+{\r
+       buttonheld[bt_attack] = true;\r
+\r
+       gamestate.weaponframe = 0;\r
+\r
+       player->state = &s_attack;\r
+\r
+       gamestate.attackframe = 0;\r
+       gamestate.attackcount =\r
+               attackinfo[gamestate.weapon][gamestate.attackframe].tics;\r
+       gamestate.weaponframe =\r
+               attackinfo[gamestate.weapon][gamestate.attackframe].frame;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= Cmd_Use\r
+=\r
+===============\r
+*/\r
+\r
+void Cmd_Use (void)\r
+{\r
+       objtype         *check;\r
+       int                     checkx,checky,doornum,dir;\r
+       boolean         elevatorok;\r
+\r
+\r
+//\r
+// find which cardinal direction the player is facing\r
+//\r
+       if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8)\r
+       {\r
+               checkx = player->tilex + 1;\r
+               checky = player->tiley;\r
+               dir = di_east;\r
+               elevatorok = true;\r
+       }\r
+       else if (player->angle < 3*ANGLES/8)\r
+       {\r
+               checkx = player->tilex;\r
+               checky = player->tiley-1;\r
+               dir = di_north;\r
+               elevatorok = false;\r
+       }\r
+       else if (player->angle < 5*ANGLES/8)\r
+       {\r
+               checkx = player->tilex - 1;\r
+               checky = player->tiley;\r
+               dir = di_west;\r
+               elevatorok = true;\r
+       }\r
+       else\r
+       {\r
+               checkx = player->tilex;\r
+               checky = player->tiley + 1;\r
+               dir = di_south;\r
+               elevatorok = false;\r
+       }\r
+\r
+       doornum = tilemap[checkx][checky];\r
+       if (*(mapsegs[1]+farmapylookup[checky]+checkx) == PUSHABLETILE)\r
+       {\r
+       //\r
+       // pushable wall\r
+       //\r
+\r
+               PushWall (checkx,checky,dir);\r
+               return;\r
+       }\r
+       if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok)\r
+       {\r
+       //\r
+       // use elevator\r
+       //\r
+               buttonheld[bt_use] = true;\r
+\r
+               tilemap[checkx][checky]++;              // flip switch\r
+               if (*(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) == ALTELEVATORTILE)\r
+                       playstate = ex_secretlevel;\r
+               else\r
+                       playstate = ex_completed;\r
+               SD_PlaySound (LEVELDONESND);\r
+               SD_WaitSoundDone();\r
+       }\r
+       else if (!buttonheld[bt_use] && doornum & 0x80)\r
+       {\r
+               buttonheld[bt_use] = true;\r
+               OperateDoor (doornum & ~0x80);\r
+       }\r
+       else\r
+               SD_PlaySound (DONOTHINGSND);\r
+\r
+}\r
+\r
+/*\r
+=============================================================================\r
+\r
+                                                  PLAYER CONTROL\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= SpawnPlayer\r
+=\r
+===============\r
+*/\r
+\r
+void SpawnPlayer (int tilex, int tiley, int dir)\r
+{\r
+       player->obclass = playerobj;\r
+       player->active = true;\r
+       player->tilex = tilex;\r
+       player->tiley = tiley;\r
+       player->areanumber =\r
+               *(mapsegs[0] + farmapylookup[player->tiley]+player->tilex);\r
+       player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
+       player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
+       player->state = &s_player;\r
+       player->angle = (1-dir)*90;\r
+       if (player->angle<0)\r
+               player->angle += ANGLES;\r
+       player->flags = FL_NEVERMARK;\r
+       Thrust (0,0);                           // set some variables\r
+\r
+       InitAreas ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= T_KnifeAttack\r
+=\r
+= Update player hands, and try to do damage when the proper frame is reached\r
+=\r
+===============\r
+*/\r
+\r
+void   KnifeAttack (objtype *ob)\r
+{\r
+       objtype *check,*closest;\r
+       long    dist;\r
+\r
+       SD_PlaySound (ATKKNIFESND);\r
+// actually fire\r
+       dist = 0x7fffffff;\r
+       closest = NULL;\r
+       for (check=ob->next ; check ; check=check->next)\r
+               if ( (check->flags & FL_SHOOTABLE)\r
+               && (check->flags & FL_VISABLE)\r
+               && abs (check->viewx-centerx) < shootdelta\r
+               )\r
+               {\r
+                       if (check->transx < dist)\r
+                       {\r
+                               dist = check->transx;\r
+                               closest = check;\r
+                       }\r
+               }\r
+\r
+       if (!closest || dist> 0x18000l)\r
+       {\r
+       // missed\r
+\r
+               return;\r
+       }\r
+\r
+// hit something\r
+       DamageActor (closest,US_RndT() >> 4);\r
+}\r
+\r
+\r
+\r
+void   GunAttack (objtype *ob)\r
+{\r
+       objtype *check,*closest,*oldclosest;\r
+       int             damage;\r
+       int             dx,dy,dist;\r
+       long    viewdist;\r
+\r
+       switch (gamestate.weapon)\r
+       {\r
+       case wp_pistol:\r
+               SD_PlaySound (ATKPISTOLSND);\r
+               break;\r
+       case wp_machinegun:\r
+               SD_PlaySound (ATKMACHINEGUNSND);\r
+               break;\r
+       case wp_chaingun:\r
+               SD_PlaySound (ATKGATLINGSND);\r
+               break;\r
+       }\r
+\r
+       madenoise = true;\r
+\r
+//\r
+// find potential targets\r
+//\r
+       viewdist = 0x7fffffffl;\r
+       closest = NULL;\r
+\r
+       while (1)\r
+       {\r
+               oldclosest = closest;\r
+\r
+               for (check=ob->next ; check ; check=check->next)\r
+                       if ( (check->flags & FL_SHOOTABLE)\r
+                       && (check->flags & FL_VISABLE)\r
+                       && abs (check->viewx-centerx) < shootdelta\r
+                       )\r
+                       {\r
+                               if (check->transx < viewdist)\r
+                               {\r
+                                       viewdist = check->transx;\r
+                                       closest = check;\r
+                               }\r
+                       }\r
+\r
+               if (closest == oldclosest)\r
+                       return;                                         // no more targets, all missed\r
+\r
+       //\r
+       // trace a line from player to enemey\r
+       //\r
+               if (CheckLine(closest))\r
+                       break;\r
+\r
+       }\r
+\r
+//\r
+// hit something\r
+//\r
+       dx = abs(closest->tilex - player->tilex);\r
+       dy = abs(closest->tiley - player->tiley);\r
+       dist = dx>dy ? dx:dy;\r
+\r
+       if (dist<2)\r
+               damage = US_RndT() / 4;\r
+       else if (dist<4)\r
+               damage = US_RndT() / 6;\r
+       else\r
+       {\r
+               if ( (US_RndT() / 12) < dist)           // missed\r
+                       return;\r
+               damage = US_RndT() / 6;\r
+       }\r
+\r
+       DamageActor (closest,damage);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= VictorySpin\r
+=\r
+===============\r
+*/\r
+\r
+void VictorySpin (void)\r
+{\r
+       long    desty;\r
+\r
+       if (player->angle > 270)\r
+       {\r
+               player->angle -= tics * 3;\r
+               if (player->angle < 270)\r
+                       player->angle = 270;\r
+       }\r
+       else if (player->angle < 270)\r
+       {\r
+               player->angle += tics * 3;\r
+               if (player->angle > 270)\r
+                       player->angle = 270;\r
+       }\r
+\r
+       desty = (((long)player->tiley-5)<<TILESHIFT)-0x3000;\r
+\r
+       if (player->y > desty)\r
+       {\r
+               player->y -= tics*4096;\r
+               if (player->y < desty)\r
+                       player->y = desty;\r
+       }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= T_Attack\r
+=\r
+===============\r
+*/\r
+\r
+void   T_Attack (objtype *ob)\r
+{\r
+       struct  atkinf  *cur;\r
+\r
+       UpdateFace ();\r
+\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+       {\r
+               VictorySpin ();\r
+               return;\r
+       }\r
+\r
+       if ( buttonstate[bt_use] && !buttonheld[bt_use] )\r
+               buttonstate[bt_use] = false;\r
+\r
+       if ( buttonstate[bt_attack] && !buttonheld[bt_attack])\r
+               buttonstate[bt_attack] = false;\r
+\r
+       ControlMovement (ob);\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+               return;\r
+\r
+       plux = player->x >> UNSIGNEDSHIFT;                      // scale to fit in unsigned\r
+       pluy = player->y >> UNSIGNEDSHIFT;\r
+       player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
+       player->tiley = player->y >> TILESHIFT;\r
+\r
+//\r
+// change frame and fire\r
+//\r
+       gamestate.attackcount -= tics;\r
+       while (gamestate.attackcount <= 0)\r
+       {\r
+               cur = &attackinfo[gamestate.weapon][gamestate.attackframe];\r
+               switch (cur->attack)\r
+               {\r
+               case -1:\r
+                       ob->state = &s_player;\r
+                       if (!gamestate.ammo)\r
+                       {\r
+                               gamestate.weapon = wp_knife;\r
+                               DrawWeapon ();\r
+                       }\r
+                       else\r
+                       {\r
+                               if (gamestate.weapon != gamestate.chosenweapon)\r
+                               {\r
+                                       gamestate.weapon = gamestate.chosenweapon;\r
+                                       DrawWeapon ();\r
+                               }\r
+                       };\r
+                       gamestate.attackframe = gamestate.weaponframe = 0;\r
+                       return;\r
+\r
+               case 4:\r
+                       if (!gamestate.ammo)\r
+                               break;\r
+                       if (buttonstate[bt_attack])\r
+                               gamestate.attackframe -= 2;\r
+               case 1:\r
+                       if (!gamestate.ammo)\r
+                       {       // can only happen with chain gun\r
+                               gamestate.attackframe++;\r
+                               break;\r
+                       }\r
+                       GunAttack (ob);\r
+                       gamestate.ammo--;\r
+                       DrawAmmo ();\r
+                       break;\r
+\r
+               case 2:\r
+                       KnifeAttack (ob);\r
+                       break;\r
+\r
+               case 3:\r
+                       if (gamestate.ammo && buttonstate[bt_attack])\r
+                               gamestate.attackframe -= 2;\r
+                       break;\r
+               }\r
+\r
+               gamestate.attackcount += cur->tics;\r
+               gamestate.attackframe++;\r
+               gamestate.weaponframe =\r
+                       attackinfo[gamestate.weapon][gamestate.attackframe].frame;\r
+       }\r
+\r
+}\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= T_Player\r
+=\r
+===============\r
+*/\r
+\r
+void   T_Player (objtype *ob)\r
+{\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+       {\r
+               VictorySpin ();\r
+               return;\r
+       }\r
+\r
+       UpdateFace ();\r
+       CheckWeaponChange ();\r
+\r
+       if ( buttonstate[bt_use] )\r
+               Cmd_Use ();\r
+\r
+       if ( buttonstate[bt_attack] && !buttonheld[bt_attack])\r
+               Cmd_Fire ();\r
+\r
+       ControlMovement (ob);\r
+       if (gamestate.victoryflag)              // watching the BJ actor\r
+               return;\r
+\r
+\r
+       plux = player->x >> UNSIGNEDSHIFT;                      // scale to fit in unsigned\r
+       pluy = player->y >> UNSIGNEDSHIFT;\r
+       player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
+       player->tiley = player->y >> TILESHIFT;\r
+}\r
+\r
+\r