--- /dev/null
+// 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