8 =============================================================================
\r
12 =============================================================================
\r
15 #define MAXMOUSETURN 10
\r
18 #define MOVESCALE 150l
\r
19 #define BACKMOVESCALE 100l
\r
20 #define ANGLESCALE 20
\r
23 =============================================================================
\r
27 =============================================================================
\r
33 // player state info
\r
38 unsigned plux,pluy; // player coordinates scaled to unsigned
\r
41 int gotgatgun; // JR
\r
43 objtype *LastAttacker;
\r
46 =============================================================================
\r
50 =============================================================================
\r
54 void T_Player (objtype *ob);
\r
55 void T_Attack (objtype *ob);
\r
57 statetype s_player = {false,0,0,T_Player,NULL,NULL};
\r
58 statetype s_attack = {false,0,0,T_Attack,NULL,NULL};
\r
61 long playerxmove,playerymove;
\r
65 char tics,attack,frame; // attack is 1 for gun, 2 for knife
\r
66 } attackinfo[4][14] =
\r
69 { {6,0,1},{6,2,2},{6,0,3},{6,-1,4} },
\r
70 { {6,0,1},{6,1,2},{6,0,3},{6,-1,4} },
\r
71 { {6,0,1},{6,1,2},{6,3,3},{6,-1,4} },
\r
72 { {6,0,1},{6,1,2},{6,4,3},{6,-1,4} },
\r
76 int strafeangle[9] = {0,90,180,270,45,135,225,315,0};
\r
78 void DrawWeapon (void);
\r
79 void GiveWeapon (int weapon);
\r
80 void GiveAmmo (int ammo);
\r
82 //===========================================================================
\r
88 void Search (objtype *ob);
\r
89 void SelectWeapon (void);
\r
90 void SelectItem (void);
\r
94 boolean TryMove (objtype *ob);
\r
95 void T_Player (objtype *ob);
\r
97 void ClipMove (objtype *ob, long xmove, long ymove);
\r
100 =============================================================================
\r
104 =============================================================================
\r
108 ======================
\r
110 = CheckWeaponChange
\r
112 = Keys 1-4 change weapons
\r
114 ======================
\r
117 void CheckWeaponChange (void)
\r
121 if (!gamestate.ammo) // must use knife with no ammo
\r
124 for (i=wp_knife ; i<=gamestate.bestweapon ; i++)
\r
125 if (buttonstate[bt_readyknife+i-wp_knife])
\r
127 gamestate.weapon = gamestate.chosenweapon = i;
\r
135 =======================
\r
139 = Takes controlx,controly, and buttonstate[bt_strafe]
\r
141 = Changes the player's angle and position
\r
143 = There is an angle hack because when going 70 fps, the roundoff becomes
\r
146 =======================
\r
149 void ControlMovement (objtype *ob)
\r
152 int angle,maxxmove;
\r
162 // side to side move
\r
164 if (buttonstate[bt_strafe])
\r
172 angle = ob->angle - ANGLES/4;
\r
175 Thrust (angle,controlx*MOVESCALE); // move to left
\r
177 else if (controlx < 0)
\r
179 angle = ob->angle + ANGLES/4;
\r
180 if (angle >= ANGLES)
\r
182 Thrust (angle,-controlx*MOVESCALE); // move to right
\r
190 anglefrac += controlx;
\r
191 angleunits = anglefrac/ANGLESCALE;
\r
192 anglefrac -= angleunits*ANGLESCALE;
\r
193 ob->angle -= angleunits;
\r
195 if (ob->angle >= ANGLES)
\r
196 ob->angle -= ANGLES;
\r
198 ob->angle += ANGLES;
\r
203 // forward/backwards move
\r
207 Thrust (ob->angle,-controly*MOVESCALE); // move forwards
\r
209 else if (controly > 0)
\r
211 angle = ob->angle + ANGLES/2;
\r
212 if (angle >= ANGLES)
\r
214 Thrust (angle,controly*BACKMOVESCALE); // move backwards
\r
217 if (gamestate.victoryflag) // watching the BJ actor
\r
221 // calculate total move
\r
223 playerxmove = player->x - oldx;
\r
224 playerymove = player->y - oldy;
\r
228 =============================================================================
\r
230 STATUS WINDOW STUFF
\r
232 =============================================================================
\r
244 void StatusDrawPic (unsigned x, unsigned y, unsigned picnum)
\r
251 bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH;
\r
252 LatchDrawPic (x,y,picnum);
\r
253 bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH;
\r
254 LatchDrawPic (x,y,picnum);
\r
255 bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH;
\r
256 LatchDrawPic (x,y,picnum);
\r
270 void DrawFace (void)
\r
272 if (gamestate.health)
\r
276 StatusDrawPic (17,4,GODMODEFACE1PIC+gamestate.faceframe);
\r
279 StatusDrawPic (17,4,FACE1APIC+3*((100-gamestate.health)/16)+gamestate.faceframe);
\r
284 if (LastAttacker->obclass == needleobj)
\r
285 StatusDrawPic (17,4,MUTANTBJPIC);
\r
288 StatusDrawPic (17,4,FACE8APIC);
\r
298 = Calls draw face if time to change
\r
303 #define FACETICS 70
\r
307 void UpdateFace (void)
\r
310 if (SD_SoundPlaying() == GETGATLINGSND)
\r
314 if (facecount > US_RndT())
\r
316 gamestate.faceframe = (US_RndT()>>6);
\r
317 if (gamestate.faceframe==3)
\r
318 gamestate.faceframe = 1;
\r
332 = right justifies and pads with blanks
\r
337 void LatchNumber (int x, int y, int width, long number)
\r
342 ltoa (number,str,10);
\r
344 length = strlen (str);
\r
346 while (length<width)
\r
348 StatusDrawPic (x,y,N_BLANKPIC);
\r
353 c= length <= width ? 0 : length-width;
\r
357 StatusDrawPic (x,y,str[c]-'0'+ N_0PIC);
\r
372 void DrawHealth (void)
\r
374 LatchNumber (21,16,3,gamestate.health);
\r
386 void TakeDamage (int points,objtype *attacker)
\r
388 LastAttacker = attacker;
\r
390 if (gamestate.victoryflag)
\r
392 if (gamestate.difficulty==gd_baby)
\r
396 gamestate.health -= points;
\r
398 if (gamestate.health<=0)
\r
400 gamestate.health = 0;
\r
401 playstate = ex_died;
\r
402 killerobj = attacker;
\r
405 StartDamageFlash (points);
\r
413 // MAKE BJ'S EYES BUG IF MAJOR DAMAGE!
\r
416 if (points > 30 && gamestate.health!=0 && !godmode)
\r
418 StatusDrawPic (17,4,BJOUCHPIC);
\r
434 void HealSelf (int points)
\r
436 gamestate.health += points;
\r
437 if (gamestate.health>100)
\r
438 gamestate.health = 100;
\r
441 gotgatgun = 0; // JR
\r
446 //===========================================================================
\r
457 void DrawLevel (void)
\r
460 if (gamestate.mapon == 20)
\r
461 LatchNumber (2,16,2,18);
\r
464 LatchNumber (2,16,2,gamestate.mapon+1);
\r
467 //===========================================================================
\r
478 void DrawLives (void)
\r
480 LatchNumber (14,16,1,gamestate.lives);
\r
492 void GiveExtraMan (void)
\r
494 if (gamestate.lives<9)
\r
497 SD_PlaySound (BONUS1UPSND);
\r
500 //===========================================================================
\r
510 void DrawScore (void)
\r
512 LatchNumber (6,16,6,gamestate.score);
\r
523 void GivePoints (long points)
\r
525 gamestate.score += points;
\r
526 while (gamestate.score >= gamestate.nextextra)
\r
528 gamestate.nextextra += EXTRAPOINTS;
\r
534 //===========================================================================
\r
544 void DrawWeapon (void)
\r
546 StatusDrawPic (32,8,KNIFEPIC+gamestate.weapon);
\r
558 void DrawKeys (void)
\r
560 if (gamestate.keys & 1)
\r
561 StatusDrawPic (30,4,GOLDKEYPIC);
\r
563 StatusDrawPic (30,4,NOKEYPIC);
\r
565 if (gamestate.keys & 2)
\r
566 StatusDrawPic (30,20,SILVERKEYPIC);
\r
568 StatusDrawPic (30,20,NOKEYPIC);
\r
581 void GiveWeapon (int weapon)
\r
585 if (gamestate.bestweapon<weapon)
\r
586 gamestate.bestweapon = gamestate.weapon
\r
587 = gamestate.chosenweapon = weapon;
\r
593 //===========================================================================
\r
603 void DrawAmmo (void)
\r
605 LatchNumber (27,16,2,gamestate.ammo);
\r
617 void GiveAmmo (int ammo)
\r
619 if (!gamestate.ammo) // knife was out
\r
621 if (!gamestate.attackframe)
\r
623 gamestate.weapon = gamestate.chosenweapon;
\r
627 gamestate.ammo += ammo;
\r
628 if (gamestate.ammo > 99)
\r
629 gamestate.ammo = 99;
\r
633 //===========================================================================
\r
643 void GiveKey (int key)
\r
645 gamestate.keys |= (1<<key);
\r
652 =============================================================================
\r
656 =============================================================================
\r
661 ===================
\r
665 ===================
\r
667 void GetBonus (statobj_t *check)
\r
669 switch (check->itemnumber)
\r
672 if (gamestate.health == 100)
\r
675 SD_PlaySound (HEALTH2SND);
\r
683 GiveKey (check->itemnumber - bo_key1);
\r
684 SD_PlaySound (GETKEYSND);
\r
688 SD_PlaySound (BONUS1SND);
\r
690 gamestate.treasurecount++;
\r
693 SD_PlaySound (BONUS2SND);
\r
695 gamestate.treasurecount++;
\r
698 SD_PlaySound (BONUS3SND);
\r
700 gamestate.treasurecount++;
\r
703 SD_PlaySound (BONUS4SND);
\r
705 gamestate.treasurecount++;
\r
709 if (gamestate.ammo == 99)
\r
712 SD_PlaySound (GETAMMOSND);
\r
716 if (gamestate.ammo == 99)
\r
719 SD_PlaySound (GETAMMOSND);
\r
725 if (gamestate.ammo == 99)
\r
728 SD_PlaySound (GETAMMOBOXSND);
\r
733 case bo_machinegun:
\r
734 SD_PlaySound (GETMACHINESND);
\r
735 GiveWeapon (wp_machinegun);
\r
738 SD_PlaySound (GETGATLINGSND);
\r
739 GiveWeapon (wp_chaingun);
\r
741 StatusDrawPic (17,4,GOTGATLINGPIC);
\r
747 SD_PlaySound (BONUS1UPSND);
\r
751 gamestate.treasurecount++;
\r
755 if (gamestate.health == 100)
\r
758 SD_PlaySound (HEALTH1SND);
\r
763 if (gamestate.health == 100)
\r
766 SD_PlaySound (HEALTH1SND);
\r
771 if (gamestate.health >10)
\r
774 SD_PlaySound (SLURPIESND);
\r
780 spearx = player->x;
\r
781 speary = player->y;
\r
782 spearangle = player->angle;
\r
783 playstate = ex_completed;
\r
786 StartBonusFlash ();
\r
787 check->shapenum = -1; // remove from list
\r
792 ===================
\r
796 = returns true if move ok
\r
797 = debug: use pointers to optimize
\r
798 ===================
\r
801 boolean TryMove (objtype *ob)
\r
803 int xl,yl,xh,yh,x,y;
\r
805 long deltax,deltay;
\r
807 xl = (ob->x-PLAYERSIZE) >>TILESHIFT;
\r
808 yl = (ob->y-PLAYERSIZE) >>TILESHIFT;
\r
810 xh = (ob->x+PLAYERSIZE) >>TILESHIFT;
\r
811 yh = (ob->y+PLAYERSIZE) >>TILESHIFT;
\r
814 // check for solid walls
\r
816 for (y=yl;y<=yh;y++)
\r
817 for (x=xl;x<=xh;x++)
\r
819 check = actorat[x][y];
\r
820 if (check && check<objlist)
\r
825 // check for actors
\r
836 for (y=yl;y<=yh;y++)
\r
837 for (x=xl;x<=xh;x++)
\r
839 check = actorat[x][y];
\r
840 if (check > objlist
\r
841 && (check->flags & FL_SHOOTABLE) )
\r
843 deltax = ob->x - check->x;
\r
844 if (deltax < -MINACTORDIST || deltax > MINACTORDIST)
\r
846 deltay = ob->y - check->y;
\r
847 if (deltay < -MINACTORDIST || deltay > MINACTORDIST)
\r
859 ===================
\r
863 ===================
\r
866 void ClipMove (objtype *ob, long xmove, long ymove)
\r
873 ob->x = basex+xmove;
\r
874 ob->y = basey+ymove;
\r
878 if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL &&
\r
879 ob->x < (((long)(mapwidth-1))<<TILESHIFT)
\r
880 && ob->y < (((long)(mapheight-1))<<TILESHIFT) )
\r
881 return; // walk through walls
\r
883 if (!SD_SoundPlaying())
\r
884 SD_PlaySound (HITWALLSND);
\r
886 ob->x = basex+xmove;
\r
892 ob->y = basey+ymove;
\r
900 //==========================================================================
\r
903 ===================
\r
907 ===================
\r
910 void VictoryTile (void)
\r
916 gamestate.victoryflag = true;
\r
921 ===================
\r
925 ===================
\r
928 void Thrust (int angle, long speed)
\r
936 // ZERO FUNNY COUNTER IF MOVED!
\r
943 thrustspeed += speed;
\r
945 // moving bounds speed
\r
947 if (speed >= MINDIST*2)
\r
948 speed = MINDIST*2-1;
\r
950 xmove = FixedByFrac(speed,costable[angle]);
\r
951 ymove = -FixedByFrac(speed,sintable[angle]);
\r
953 ClipMove(player,xmove,ymove);
\r
955 player->tilex = player->x >> TILESHIFT; // scale to tile values
\r
956 player->tiley = player->y >> TILESHIFT;
\r
958 offset = farmapylookup[player->tiley]+player->tilex;
\r
959 player->areanumber = *(mapsegs[0] + offset) -AREATILE;
\r
961 if (*(mapsegs[1] + offset) == EXITTILE)
\r
967 =============================================================================
\r
971 =============================================================================
\r
983 void Cmd_Fire (void)
\r
985 buttonheld[bt_attack] = true;
\r
987 gamestate.weaponframe = 0;
\r
989 player->state = &s_attack;
\r
991 gamestate.attackframe = 0;
\r
992 gamestate.attackcount =
\r
993 attackinfo[gamestate.weapon][gamestate.attackframe].tics;
\r
994 gamestate.weaponframe =
\r
995 attackinfo[gamestate.weapon][gamestate.attackframe].frame;
\r
998 //===========================================================================
\r
1008 void Cmd_Use (void)
\r
1011 int checkx,checky,doornum,dir;
\r
1012 boolean elevatorok;
\r
1016 // find which cardinal direction the player is facing
\r
1018 if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8)
\r
1020 checkx = player->tilex + 1;
\r
1021 checky = player->tiley;
\r
1023 elevatorok = true;
\r
1025 else if (player->angle < 3*ANGLES/8)
\r
1027 checkx = player->tilex;
\r
1028 checky = player->tiley-1;
\r
1030 elevatorok = false;
\r
1032 else if (player->angle < 5*ANGLES/8)
\r
1034 checkx = player->tilex - 1;
\r
1035 checky = player->tiley;
\r
1037 elevatorok = true;
\r
1041 checkx = player->tilex;
\r
1042 checky = player->tiley + 1;
\r
1044 elevatorok = false;
\r
1047 doornum = tilemap[checkx][checky];
\r
1048 if (*(mapsegs[1]+farmapylookup[checky]+checkx) == PUSHABLETILE)
\r
1054 PushWall (checkx,checky,dir);
\r
1057 if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok)
\r
1062 buttonheld[bt_use] = true;
\r
1064 tilemap[checkx][checky]++; // flip switch
\r
1065 if (*(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) == ALTELEVATORTILE)
\r
1066 playstate = ex_secretlevel;
\r
1068 playstate = ex_completed;
\r
1069 SD_PlaySound (LEVELDONESND);
\r
1070 SD_WaitSoundDone();
\r
1072 else if (!buttonheld[bt_use] && doornum & 0x80)
\r
1074 buttonheld[bt_use] = true;
\r
1075 OperateDoor (doornum & ~0x80);
\r
1078 SD_PlaySound (DONOTHINGSND);
\r
1083 =============================================================================
\r
1087 =============================================================================
\r
1100 void SpawnPlayer (int tilex, int tiley, int dir)
\r
1102 player->obclass = playerobj;
\r
1103 player->active = true;
\r
1104 player->tilex = tilex;
\r
1105 player->tiley = tiley;
\r
1106 player->areanumber =
\r
1107 *(mapsegs[0] + farmapylookup[player->tiley]+player->tilex);
\r
1108 player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;
\r
1109 player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;
\r
1110 player->state = &s_player;
\r
1111 player->angle = (1-dir)*90;
\r
1112 if (player->angle<0)
\r
1113 player->angle += ANGLES;
\r
1114 player->flags = FL_NEVERMARK;
\r
1115 Thrust (0,0); // set some variables
\r
1121 //===========================================================================
\r
1128 = Update player hands, and try to do damage when the proper frame is reached
\r
1133 void KnifeAttack (objtype *ob)
\r
1135 objtype *check,*closest;
\r
1138 SD_PlaySound (ATKKNIFESND);
\r
1140 dist = 0x7fffffff;
\r
1142 for (check=ob->next ; check ; check=check->next)
\r
1143 if ( (check->flags & FL_SHOOTABLE)
\r
1144 && (check->flags & FL_VISABLE)
\r
1145 && abs (check->viewx-centerx) < shootdelta
\r
1148 if (check->transx < dist)
\r
1150 dist = check->transx;
\r
1155 if (!closest || dist> 0x18000l)
\r
1163 DamageActor (closest,US_RndT() >> 4);
\r
1168 void GunAttack (objtype *ob)
\r
1170 objtype *check,*closest,*oldclosest;
\r
1175 switch (gamestate.weapon)
\r
1178 SD_PlaySound (ATKPISTOLSND);
\r
1180 case wp_machinegun:
\r
1181 SD_PlaySound (ATKMACHINEGUNSND);
\r
1184 SD_PlaySound (ATKGATLINGSND);
\r
1191 // find potential targets
\r
1193 viewdist = 0x7fffffffl;
\r
1198 oldclosest = closest;
\r
1200 for (check=ob->next ; check ; check=check->next)
\r
1201 if ( (check->flags & FL_SHOOTABLE)
\r
1202 && (check->flags & FL_VISABLE)
\r
1203 && abs (check->viewx-centerx) < shootdelta
\r
1206 if (check->transx < viewdist)
\r
1208 viewdist = check->transx;
\r
1213 if (closest == oldclosest)
\r
1214 return; // no more targets, all missed
\r
1217 // trace a line from player to enemey
\r
1219 if (CheckLine(closest))
\r
1227 dx = abs(closest->tilex - player->tilex);
\r
1228 dy = abs(closest->tiley - player->tiley);
\r
1229 dist = dx>dy ? dx:dy;
\r
1232 damage = US_RndT() / 4;
\r
1234 damage = US_RndT() / 6;
\r
1237 if ( (US_RndT() / 12) < dist) // missed
\r
1239 damage = US_RndT() / 6;
\r
1242 DamageActor (closest,damage);
\r
1245 //===========================================================================
\r
1255 void VictorySpin (void)
\r
1259 if (player->angle > 270)
\r
1261 player->angle -= tics * 3;
\r
1262 if (player->angle < 270)
\r
1263 player->angle = 270;
\r
1265 else if (player->angle < 270)
\r
1267 player->angle += tics * 3;
\r
1268 if (player->angle > 270)
\r
1269 player->angle = 270;
\r
1272 desty = (((long)player->tiley-5)<<TILESHIFT)-0x3000;
\r
1274 if (player->y > desty)
\r
1276 player->y -= tics*4096;
\r
1277 if (player->y < desty)
\r
1278 player->y = desty;
\r
1283 //===========================================================================
\r
1293 void T_Attack (objtype *ob)
\r
1295 struct atkinf *cur;
\r
1299 if (gamestate.victoryflag) // watching the BJ actor
\r
1305 if ( buttonstate[bt_use] && !buttonheld[bt_use] )
\r
1306 buttonstate[bt_use] = false;
\r
1308 if ( buttonstate[bt_attack] && !buttonheld[bt_attack])
\r
1309 buttonstate[bt_attack] = false;
\r
1311 ControlMovement (ob);
\r
1312 if (gamestate.victoryflag) // watching the BJ actor
\r
1315 plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned
\r
1316 pluy = player->y >> UNSIGNEDSHIFT;
\r
1317 player->tilex = player->x >> TILESHIFT; // scale to tile values
\r
1318 player->tiley = player->y >> TILESHIFT;
\r
1321 // change frame and fire
\r
1323 gamestate.attackcount -= tics;
\r
1324 while (gamestate.attackcount <= 0)
\r
1326 cur = &attackinfo[gamestate.weapon][gamestate.attackframe];
\r
1327 switch (cur->attack)
\r
1330 ob->state = &s_player;
\r
1331 if (!gamestate.ammo)
\r
1333 gamestate.weapon = wp_knife;
\r
1338 if (gamestate.weapon != gamestate.chosenweapon)
\r
1340 gamestate.weapon = gamestate.chosenweapon;
\r
1344 gamestate.attackframe = gamestate.weaponframe = 0;
\r
1348 if (!gamestate.ammo)
\r
1350 if (buttonstate[bt_attack])
\r
1351 gamestate.attackframe -= 2;
\r
1353 if (!gamestate.ammo)
\r
1354 { // can only happen with chain gun
\r
1355 gamestate.attackframe++;
\r
1368 if (gamestate.ammo && buttonstate[bt_attack])
\r
1369 gamestate.attackframe -= 2;
\r
1373 gamestate.attackcount += cur->tics;
\r
1374 gamestate.attackframe++;
\r
1375 gamestate.weaponframe =
\r
1376 attackinfo[gamestate.weapon][gamestate.attackframe].frame;
\r
1383 //===========================================================================
\r
1393 void T_Player (objtype *ob)
\r
1395 if (gamestate.victoryflag) // watching the BJ actor
\r
1402 CheckWeaponChange ();
\r
1404 if ( buttonstate[bt_use] )
\r
1407 if ( buttonstate[bt_attack] && !buttonheld[bt_attack])
\r
1410 ControlMovement (ob);
\r
1411 if (gamestate.victoryflag) // watching the BJ actor
\r
1415 plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned
\r
1416 pluy = player->y >> UNSIGNEDSHIFT;
\r
1417 player->tilex = player->x >> TILESHIFT; // scale to tile values
\r
1418 player->tiley = player->y >> TILESHIFT;
\r