--- /dev/null
+/* Catacomb 3-D 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_WIZ.C\r
+\r
+#include "C3_DEF.H"\r
+#pragma hdrstop\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL CONSTANTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+#define NUMSCROLLS 8\r
+\r
+#define SHOWITEMS 9\r
+\r
+#define NUKETIME 40\r
+#define NUMBOLTS 10\r
+#define BOLTTICS 6\r
+\r
+#define STATUSCOLOR 4\r
+#define TEXTCOLOR 14\r
+\r
+#define SIDEBARWIDTH 5\r
+\r
+#define BODYLINE 8\r
+#define POWERLINE 80\r
+\r
+#define SPECTILESTART 18\r
+\r
+\r
+#define SHOTDAMAGE 1\r
+#define BIGSHOTDAMAGE 3\r
+\r
+\r
+#define PLAYERSPEED 5120\r
+#define RUNSPEED 8192\r
+\r
+#define SHOTSPEED 10000\r
+\r
+#define LASTWALLTILE 17\r
+#define LASTSPECIALTILE 37\r
+\r
+#define FIRETIME 4 // DEBUG 60\r
+\r
+#define HANDPAUSE 60\r
+\r
+#define COMPASSX 33\r
+#define COMPASSY 0\r
+\r
+/*\r
+=============================================================================\r
+\r
+ GLOBAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+long lastnuke,lasthand;\r
+int handheight;\r
+int boltsleft;\r
+\r
+/*\r
+=============================================================================\r
+\r
+ LOCAL VARIABLES\r
+\r
+=============================================================================\r
+*/\r
+\r
+int lasttext,lastcompass;\r
+int bolttimer;\r
+unsigned lastfiretime;\r
+\r
+int strafeangle[9] = {0,90,180,270,45,135,225,315,0};\r
+\r
+\r
+//===========================================================================\r
+\r
+void DrawChar (unsigned x, unsigned y, unsigned tile);\r
+void RedrawStatusWindow (void);\r
+void GiveBolt (void);\r
+void TakeBolt (void);\r
+void GiveNuke (void);\r
+void TakeNuke (void);\r
+void GivePotion (void);\r
+void TakePotion (void);\r
+void GiveKey (int keytype);\r
+void TakeKey (int keytype);\r
+void GiveScroll (int scrolltype,boolean show);\r
+void ReadScroll (int scroll);\r
+void GivePoints (int points);\r
+void DrawLevelNumber (int number);\r
+void DrawText (void);\r
+void DrawBars (void);\r
+\r
+//----------\r
+\r
+void Shoot (void);\r
+void BigShoot (void);\r
+void CastBolt (void);\r
+void CastNuke (void);\r
+void DrinkPotion (void);\r
+\r
+//----------\r
+\r
+void SpawnPlayer (int tilex, int tiley, int dir);\r
+void Thrust (int angle, unsigned speed);\r
+void T_Player (objtype *ob);\r
+\r
+void AddPoints (int points);\r
+\r
+void ClipMove (objtype *ob, long xmove, long ymove);\r
+boolean ShotClipMove (objtype *ob, long xmove, long ymove);\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawChar\r
+=\r
+===============\r
+*/\r
+\r
+void DrawChar (unsigned x, unsigned y, unsigned tile)\r
+{\r
+ unsigned junk = latchpics[0];\r
+\r
+ EGAWRITEMODE(1);\r
+asm mov bx,[y]\r
+asm shl bx,1\r
+asm mov di,[WORD PTR ylookup+bx]\r
+asm add di,[x]\r
+asm mov si,[tile]\r
+asm shl si,1\r
+asm shl si,1\r
+asm shl si,1\r
+asm add si,[junk] // the damn inline assembler won't reference latchpics\r
+asm mov ax,[screenseg]\r
+asm mov es,ax\r
+asm mov ds,ax\r
+asm mov dx,SCREENWIDTH-1\r
+asm movsb\r
+asm add di,dx\r
+asm movsb\r
+asm add di,dx\r
+asm movsb\r
+asm add di,dx\r
+asm movsb\r
+asm add di,dx\r
+asm movsb\r
+asm add di,dx\r
+asm movsb\r
+asm add di,dx\r
+asm movsb\r
+asm add di,dx\r
+asm movsb\r
+\r
+asm mov ax,ss\r
+asm mov ds,ax\r
+ EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= RedrawStatusWindow\r
+=\r
+===============\r
+*/\r
+\r
+void RedrawStatusWindow (void)\r
+{\r
+ int i,j,x;\r
+\r
+ DrawLevelNumber (gamestate.mapon);\r
+ lasttext = -1;\r
+ lastcompass = -1;\r
+\r
+ j = gamestate.bolts < SHOWITEMS ? gamestate.bolts : SHOWITEMS;\r
+ for (i=0;i<j;i++)\r
+ DrawChar(7+i,20,BOLTCHAR);\r
+ j = gamestate.nukes < SHOWITEMS ? gamestate.nukes : SHOWITEMS;\r
+ for (i=0;i<j;i++)\r
+ DrawChar(7+i,30,NUKECHAR);\r
+ j = gamestate.potions < SHOWITEMS ? gamestate.potions : SHOWITEMS;\r
+ for (i=0;i<j;i++)\r
+ DrawChar(7+i,40,POTIONCHAR);\r
+\r
+ x=24;\r
+ for (i=0;i<4;i++)\r
+ for (j=0;j<gamestate.keys[i];j++)\r
+ DrawChar(x++,20,KEYCHARS+i);\r
+\r
+ x=24;\r
+ for (i=0;i<8;i++)\r
+ if (gamestate.scrolls[i])\r
+ DrawChar(x++,30,SCROLLCHARS+i);\r
+\r
+ AddPoints(0);\r
+\r
+ DrawBars ();\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveBolt\r
+=\r
+===============\r
+*/\r
+\r
+void GiveBolt (void)\r
+{\r
+ SD_PlaySound (GETBOLTSND);\r
+ if (++gamestate.bolts<=9)\r
+ DrawChar(6+gamestate.bolts,20,BOLTCHAR);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeBolt\r
+=\r
+===============\r
+*/\r
+\r
+void TakeBolt (void)\r
+{\r
+ SD_PlaySound (USEBOLTSND);\r
+ if (--gamestate.bolts<=9)\r
+ DrawChar(7+gamestate.bolts,20,BLANKCHAR);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveNuke\r
+=\r
+===============\r
+*/\r
+\r
+void GiveNuke (void)\r
+{\r
+ SD_PlaySound (GETNUKESND);\r
+ if (++gamestate.nukes<=9)\r
+ DrawChar(6+gamestate.nukes,30,NUKECHAR);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeNuke\r
+=\r
+===============\r
+*/\r
+\r
+void TakeNuke (void)\r
+{\r
+ SD_PlaySound (USENUKESND);\r
+ if (--gamestate.nukes<=9)\r
+ DrawChar(7+gamestate.nukes,30,BLANKCHAR);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GivePotion\r
+=\r
+===============\r
+*/\r
+\r
+void GivePotion (void)\r
+{\r
+ SD_PlaySound (GETPOTIONSND);\r
+ if (++gamestate.potions<=9)\r
+ DrawChar(6+gamestate.potions,40,POTIONCHAR);\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakePotion\r
+=\r
+===============\r
+*/\r
+\r
+void TakePotion (void)\r
+{\r
+ SD_PlaySound (USEPOTIONSND);\r
+ if (--gamestate.potions<=9)\r
+ DrawChar(7+gamestate.potions,40,BLANKCHAR);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveKey\r
+=\r
+===============\r
+*/\r
+\r
+void GiveKey (int keytype)\r
+{\r
+ int i,j,x;\r
+\r
+ SD_PlaySound (GETKEYSND);\r
+ gamestate.keys[keytype]++;\r
+\r
+ x=24;\r
+ for (i=0;i<4;i++)\r
+ for (j=0;j<gamestate.keys[i];j++)\r
+ DrawChar(x++,20,KEYCHARS+i);\r
+\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeKey\r
+=\r
+===============\r
+*/\r
+\r
+void TakeKey (int keytype)\r
+{\r
+ int i,j,x;\r
+\r
+ SD_PlaySound (USEKEYSND);\r
+ gamestate.keys[keytype]--;\r
+\r
+ x=24;\r
+ for (i=0;i<4;i++)\r
+ for (j=0;j<gamestate.keys[i];j++)\r
+ DrawChar(x++,20,KEYCHARS+i);\r
+\r
+ DrawChar(x,20,BLANKCHAR);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveScroll\r
+=\r
+===============\r
+*/\r
+\r
+void GiveScroll (int scrolltype,boolean show)\r
+{\r
+ int i,x;\r
+\r
+ SD_PlaySound (GETSCROLLSND);\r
+ gamestate.scrolls[scrolltype] = true;\r
+\r
+ x=24;\r
+ for (i=0;i<8;i++)\r
+ if (gamestate.scrolls[i])\r
+ DrawChar(x++,30,SCROLLCHARS+i);\r
+ if (show)\r
+ ReadScroll(scrolltype);\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GivePoints\r
+=\r
+===============\r
+*/\r
+\r
+void GivePoints (int points)\r
+{\r
+ pointcount = 1;\r
+ pointsleft += points;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= AddPoints\r
+=\r
+===============\r
+*/\r
+\r
+void AddPoints (int points)\r
+{\r
+ char str[10];\r
+ int len,x,i;\r
+\r
+ gamestate.score += points;\r
+\r
+ ltoa (gamestate.score,str,10);\r
+ len = strlen (str);\r
+\r
+ x=24+(8-len);\r
+ for (i=0;i<len;i++)\r
+ DrawChar(x++,40,NUMBERCHARS+str[i]-'0');\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveChest\r
+=\r
+===============\r
+*/\r
+\r
+void GiveChest (void)\r
+{\r
+ SD_PlaySound (GETPOINTSSND);\r
+ GivePoints ((gamestate.mapon+1)*100);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= GiveGoal\r
+=\r
+===============\r
+*/\r
+\r
+void GiveGoal (void)\r
+{\r
+ SD_PlaySound (GETPOINTSSND);\r
+ GivePoints (100000);\r
+ playstate = ex_victorious;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawLevelNumber\r
+=\r
+===============\r
+*/\r
+\r
+void DrawLevelNumber (int number)\r
+{\r
+ char str[10];\r
+ int len;\r
+ unsigned temp;\r
+\r
+ bufferofs = 0;\r
+ if (number<9)\r
+ PrintX=13;\r
+ else\r
+ PrintX = 5;\r
+ PrintY = 4;\r
+ VW_Bar (5,4,16,9,STATUSCOLOR);\r
+ temp = fontcolor;\r
+ fontcolor = TEXTCOLOR^STATUSCOLOR;\r
+ US_PrintUnsigned (number+1);\r
+ fontcolor = temp;\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawText\r
+=\r
+===============\r
+*/\r
+\r
+void DrawText (void)\r
+{\r
+ unsigned number;\r
+ char str[80];\r
+ char far *text;\r
+ unsigned temp;\r
+\r
+ //\r
+ // draw a new text description if needed\r
+ //\r
+ number = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex)-NAMESTART;\r
+\r
+ if ( number>26 )\r
+ number = 0;\r
+\r
+ if (number == lasttext)\r
+ return;\r
+\r
+ bufferofs = 0;\r
+ lasttext = number;\r
+\r
+ PrintY = 4;\r
+ WindowX = 26;\r
+ WindowW = 232;\r
+\r
+ text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number];\r
+\r
+ _fmemcpy (str,text,80);\r
+\r
+ VW_Bar (26,4,232,9,STATUSCOLOR);\r
+ temp = fontcolor;\r
+ fontcolor = TEXTCOLOR^STATUSCOLOR;\r
+ US_CPrintLine (str);\r
+ fontcolor = temp;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrawCompass\r
+=\r
+===============\r
+*/\r
+\r
+void DrawCompass (void)\r
+{\r
+ int angle,number;\r
+\r
+ //\r
+ // draw the compass if needed\r
+ //\r
+ angle = player->angle-ANGLES/4;\r
+ angle -= ANGLES/32;\r
+ if (angle<0)\r
+ angle+=ANGLES;\r
+ number = angle/(ANGLES/16);\r
+ if (number>15) // because 360 angles doesn't divide by 16\r
+ number = 15;\r
+\r
+ if (number == lastcompass)\r
+ return;\r
+\r
+ lastcompass = number;\r
+\r
+ bufferofs = 0;\r
+ LatchDrawPic (COMPASSX,COMPASSY,COMPAS1PIC+15-number);\r
+}\r
+\r
+//===========================================================================\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= DrawBars\r
+=\r
+===============\r
+*/\r
+\r
+void DrawBars (void)\r
+{\r
+ int i;\r
+ unsigned source,dest,topline;\r
+\r
+ for (i=0;i<3;i++)\r
+ {\r
+ bufferofs = screenloc[i];\r
+ VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1);\r
+ }\r
+ EGAWRITEMODE(1);\r
+ asm mov es,[screenseg]\r
+\r
+//\r
+// shot power\r
+//\r
+ if (gamestate.shotpower)\r
+ {\r
+ topline = MAXSHOTPOWER - gamestate.shotpower;\r
+\r
+ source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH;\r
+ dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
+\r
+ asm mov si,[source]\r
+ asm mov di,[dest]\r
+\r
+ asm mov cx,[WORD PTR gamestate.shotpower]\r
+newline:\r
+ asm mov al,[es:si]\r
+ asm mov [es:di+PAGE1START],al\r
+ asm mov [es:di+PAGE2START],al\r
+ asm mov [es:di+PAGE3START],al\r
+ asm mov al,[es:si+1]\r
+ asm mov [es:di+1+PAGE1START],al\r
+ asm mov [es:di+1+PAGE2START],al\r
+ asm mov [es:di+1+PAGE3START],al\r
+ asm mov al,[es:si+2]\r
+ asm mov [es:di+2+PAGE1START],al\r
+ asm mov [es:di+2+PAGE2START],al\r
+ asm mov [es:di+2+PAGE3START],al\r
+ asm mov al,[es:si+3]\r
+ asm mov [es:di+3+PAGE1START],al\r
+ asm mov [es:di+3+PAGE2START],al\r
+ asm mov [es:di+3+PAGE3START],al\r
+ asm mov al,[es:si+4]\r
+ asm mov [es:di+4+PAGE1START],al\r
+ asm mov [es:di+4+PAGE2START],al\r
+ asm mov [es:di+4+PAGE3START],al\r
+\r
+ asm add di,SCREENWIDTH\r
+ asm add si,5\r
+\r
+ asm loop newline\r
+ }\r
+\r
+//\r
+// body\r
+//\r
+ if (gamestate.body)\r
+ {\r
+ source = latchpics[BODYPIC-FIRSTLATCHPIC];\r
+ dest = BODYLINE*SCREENWIDTH+34;\r
+\r
+ asm mov si,[source]\r
+ asm mov di,[dest]\r
+\r
+ asm mov cx,[WORD PTR gamestate.body]\r
+newline2:\r
+ asm mov al,[es:si]\r
+ asm mov [es:di+PAGE1START],al\r
+ asm mov [es:di+PAGE2START],al\r
+ asm mov [es:di+PAGE3START],al\r
+ asm mov al,[es:si+1]\r
+ asm mov [es:di+1+PAGE1START],al\r
+ asm mov [es:di+1+PAGE2START],al\r
+ asm mov [es:di+1+PAGE3START],al\r
+ asm mov al,[es:si+2]\r
+ asm mov [es:di+2+PAGE1START],al\r
+ asm mov [es:di+2+PAGE2START],al\r
+ asm mov [es:di+2+PAGE3START],al\r
+ asm mov al,[es:si+3]\r
+ asm mov [es:di+3+PAGE1START],al\r
+ asm mov [es:di+3+PAGE2START],al\r
+ asm mov [es:di+3+PAGE3START],al\r
+ asm mov al,[es:si+4]\r
+ asm mov [es:di+4+PAGE1START],al\r
+ asm mov [es:di+4+PAGE2START],al\r
+ asm mov [es:di+4+PAGE3START],al\r
+\r
+ asm add di,SCREENWIDTH\r
+ asm add si,5\r
+\r
+ asm loop newline2\r
+ }\r
+\r
+ if (gamestate.body != MAXBODY)\r
+ {\r
+ source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH;\r
+ dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;\r
+ topline = MAXBODY-gamestate.body;\r
+\r
+ asm mov si,[source]\r
+ asm mov di,[dest]\r
+\r
+ asm mov cx,[WORD PTR topline]\r
+newline3:\r
+ asm mov al,[es:si]\r
+ asm mov [es:di+PAGE1START],al\r
+ asm mov [es:di+PAGE2START],al\r
+ asm mov [es:di+PAGE3START],al\r
+ asm mov al,[es:si+1]\r
+ asm mov [es:di+1+PAGE1START],al\r
+ asm mov [es:di+1+PAGE2START],al\r
+ asm mov [es:di+1+PAGE3START],al\r
+ asm mov al,[es:si+2]\r
+ asm mov [es:di+2+PAGE1START],al\r
+ asm mov [es:di+2+PAGE2START],al\r
+ asm mov [es:di+2+PAGE3START],al\r
+ asm mov al,[es:si+3]\r
+ asm mov [es:di+3+PAGE1START],al\r
+ asm mov [es:di+3+PAGE2START],al\r
+ asm mov [es:di+3+PAGE3START],al\r
+ asm mov al,[es:si+4]\r
+ asm mov [es:di+4+PAGE1START],al\r
+ asm mov [es:di+4+PAGE2START],al\r
+ asm mov [es:di+4+PAGE3START],al\r
+\r
+ asm add di,SCREENWIDTH\r
+ asm add si,5\r
+\r
+ asm loop newline3\r
+ }\r
+\r
+ EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ SHOTS\r
+\r
+=============================================================================\r
+*/\r
+\r
+void T_Pshot (objtype *ob);\r
+\r
+\r
+extern statetype s_pshot1;\r
+extern statetype s_pshot2;\r
+\r
+extern statetype s_bigpshot1;\r
+extern statetype s_bigpshot2;\r
+\r
+\r
+statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2};\r
+statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1};\r
+\r
+statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL};\r
+\r
+statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2};\r
+statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1};\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= SpawnPShot\r
+=\r
+===================\r
+*/\r
+\r
+void SpawnPShot (void)\r
+{\r
+ SpawnNewObjFrac (player->x,player->y,&s_pshot1,PIXRADIUS*14);\r
+ new->obclass = pshotobj;\r
+ new->speed = SHOTSPEED;\r
+ new->angle = player->angle;\r
+}\r
+\r
+void SpawnBigPShot (void)\r
+{\r
+ SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);\r
+ new->obclass = bigpshotobj;\r
+ new->speed = SHOTSPEED;\r
+ new->angle = player->angle;\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Pshot\r
+=\r
+===============\r
+*/\r
+\r
+void T_Pshot (objtype *ob)\r
+{\r
+ objtype *check;\r
+ long xmove,ymove,speed;\r
+\r
+//\r
+// check current position for monsters having moved into it\r
+//\r
+ for (check = player->next; check; check=check->next)\r
+ if (check->shootable\r
+ && ob->xl <= check->xh\r
+ && ob->xh >= check->xl\r
+ && ob->yl <= check->yh\r
+ && ob->yh >= check->yl)\r
+ {\r
+ SD_PlaySound (SHOOTMONSTERSND);\r
+ if (ob->obclass == bigpshotobj)\r
+ ShootActor (check,BIGSHOTDAMAGE);\r
+ else\r
+ ShootActor (check,SHOTDAMAGE);\r
+ ob->state = &s_shotexplode;\r
+ ob->ticcount = ob->state->tictime;\r
+ return;\r
+ }\r
+\r
+\r
+//\r
+// move ahead, possibly hitting a wall\r
+//\r
+ speed = ob->speed*tics;\r
+\r
+ xmove = FixedByFrac(speed,costable[ob->angle]);\r
+ ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
+\r
+ if (ShotClipMove(ob,xmove,ymove))\r
+ {\r
+ ob->state = &s_shotexplode;\r
+ ob->ticcount = ob->state->tictime;\r
+ return;\r
+ }\r
+\r
+ ob->tilex = ob->x >> TILESHIFT;\r
+ ob->tiley = ob->y >> TILESHIFT;\r
+\r
+//\r
+// check final position for monsters hit\r
+//\r
+ for (check = player->next; check; check=check->next)\r
+ if (ob->shootable\r
+ && ob->xl <= check->xh\r
+ && ob->xh >= check->xl\r
+ && ob->yl <= check->yh\r
+ && ob->yh >= check->yl)\r
+ {\r
+ ShootActor (check,SHOTDAMAGE);\r
+ ob->state = &s_shotexplode;\r
+ ob->ticcount = ob->state->tictime;\r
+ return;\r
+ }\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ PLAYER ACTIONS\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= BuildShotPower\r
+=\r
+===============\r
+*/\r
+\r
+void BuildShotPower (void)\r
+{\r
+ int newlines,topline;\r
+ long i;\r
+ unsigned source,dest;\r
+\r
+ if (gamestate.shotpower == MAXSHOTPOWER)\r
+ return;\r
+\r
+ newlines = 0;\r
+ for (i=lasttimecount-tics;i<lasttimecount;i++)\r
+ newlines += (i&1);\r
+\r
+ gamestate.shotpower += newlines;\r
+\r
+ if (gamestate.shotpower > MAXSHOTPOWER)\r
+ {\r
+ newlines -= (gamestate.shotpower - MAXSHOTPOWER);\r
+ gamestate.shotpower = MAXSHOTPOWER;\r
+ }\r
+\r
+ topline = MAXSHOTPOWER - gamestate.shotpower;\r
+\r
+ source = latchpics[L_SHOTBAR]+topline*SIDEBARWIDTH;\r
+ dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
+\r
+ asm mov es,[screenseg]\r
+ asm mov si,[source]\r
+ asm mov di,[dest]\r
+\r
+ EGAWRITEMODE(1);\r
+\r
+ if (newlines)\r
+ {\r
+ asm mov cx,[newlines]\r
+newline:\r
+ asm mov al,[es:si]\r
+ asm mov [es:di+PAGE1START],al\r
+ asm mov [es:di+PAGE2START],al\r
+ asm mov [es:di+PAGE3START],al\r
+ asm mov al,[es:si+1]\r
+ asm mov [es:di+1+PAGE1START],al\r
+ asm mov [es:di+1+PAGE2START],al\r
+ asm mov [es:di+1+PAGE3START],al\r
+ asm mov al,[es:si+2]\r
+ asm mov [es:di+2+PAGE1START],al\r
+ asm mov [es:di+2+PAGE2START],al\r
+ asm mov [es:di+2+PAGE3START],al\r
+ asm mov al,[es:si+3]\r
+ asm mov [es:di+3+PAGE1START],al\r
+ asm mov [es:di+3+PAGE2START],al\r
+ asm mov [es:di+3+PAGE3START],al\r
+ asm mov al,[es:si+4]\r
+ asm mov [es:di+4+PAGE1START],al\r
+ asm mov [es:di+4+PAGE2START],al\r
+ asm mov [es:di+4+PAGE3START],al\r
+\r
+ asm add di,SCREENWIDTH\r
+ asm add si,5\r
+\r
+ asm loop newline\r
+ }\r
+\r
+ EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= ClearShotPower\r
+=\r
+===============\r
+*/\r
+\r
+void ClearShotPower (void)\r
+{\r
+ unsigned source,dest,topline;\r
+\r
+ topline = MAXSHOTPOWER - gamestate.shotpower;\r
+\r
+ source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH;\r
+ dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
+\r
+ asm mov es,[screenseg]\r
+ asm mov si,[source]\r
+ asm mov di,[dest]\r
+\r
+ if (!gamestate.shotpower)\r
+ return;\r
+\r
+ EGAWRITEMODE(1);\r
+\r
+ asm mov cx,[WORD PTR gamestate.shotpower]\r
+newline:\r
+ asm mov al,[es:si]\r
+ asm mov [es:di+PAGE1START],al\r
+ asm mov [es:di+PAGE2START],al\r
+ asm mov [es:di+PAGE3START],al\r
+ asm mov al,[es:si+1]\r
+ asm mov [es:di+1+PAGE1START],al\r
+ asm mov [es:di+1+PAGE2START],al\r
+ asm mov [es:di+1+PAGE3START],al\r
+ asm mov al,[es:si+2]\r
+ asm mov [es:di+2+PAGE1START],al\r
+ asm mov [es:di+2+PAGE2START],al\r
+ asm mov [es:di+2+PAGE3START],al\r
+ asm mov al,[es:si+3]\r
+ asm mov [es:di+3+PAGE1START],al\r
+ asm mov [es:di+3+PAGE2START],al\r
+ asm mov [es:di+3+PAGE3START],al\r
+ asm mov al,[es:si+4]\r
+ asm mov [es:di+4+PAGE1START],al\r
+ asm mov [es:di+4+PAGE2START],al\r
+ asm mov [es:di+4+PAGE3START],al\r
+\r
+ asm add di,SCREENWIDTH\r
+ asm add si,5\r
+\r
+ asm loop newline\r
+\r
+ EGAWRITEMODE(0);\r
+\r
+ gamestate.shotpower = 0;\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= Shoot\r
+=\r
+===============\r
+*/\r
+\r
+void Shoot (void)\r
+{\r
+ ClearShotPower ();\r
+ SD_PlaySound (SHOOTSND);\r
+ SpawnPShot ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= BigShoot\r
+=\r
+===============\r
+*/\r
+\r
+void BigShoot (void)\r
+{\r
+ ClearShotPower ();\r
+ SD_PlaySound (BIGSHOOTSND);\r
+ SpawnBigPShot ();\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= CastBolt\r
+=\r
+===============\r
+*/\r
+\r
+void CastBolt (void)\r
+{\r
+ if (!gamestate.bolts)\r
+ {\r
+ SD_PlaySound (NOITEMSND);\r
+ return;\r
+ }\r
+\r
+ TakeBolt ();\r
+ boltsleft = NUMBOLTS;\r
+ bolttimer = BOLTTICS;\r
+ BigShoot ();\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= ContinueBolt\r
+=\r
+===============\r
+*/\r
+\r
+void ContinueBolt (void)\r
+{\r
+ bolttimer-=tics;\r
+ if (bolttimer<0)\r
+ {\r
+ boltsleft--;\r
+ bolttimer = BOLTTICS;\r
+ BigShoot ();\r
+ }\r
+}\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= CastNuke\r
+=\r
+===============\r
+*/\r
+\r
+void CastNuke (void)\r
+{\r
+ int angle;\r
+\r
+ if (!gamestate.nukes)\r
+ {\r
+ SD_PlaySound (NOITEMSND);\r
+ return;\r
+ }\r
+\r
+ TakeNuke ();\r
+ lastnuke = TimeCount;\r
+\r
+ for (angle = 0; angle < ANGLES; angle+= ANGLES/16)\r
+ {\r
+ SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);\r
+ new->obclass = bigpshotobj;\r
+ new->speed = SHOTSPEED;\r
+ new->angle = angle;\r
+ }\r
+}\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= DrinkPotion\r
+=\r
+===============\r
+*/\r
+\r
+void DrinkPotion (void)\r
+{\r
+ unsigned source,dest,topline;\r
+\r
+ if (!gamestate.potions)\r
+ {\r
+ SD_PlaySound (NOITEMSND);\r
+ return;\r
+ }\r
+\r
+ TakePotion ();\r
+ gamestate.body = MAXBODY;\r
+\r
+//\r
+// draw a full up bar\r
+//\r
+ source = latchpics[L_BODYBAR];\r
+ dest = BODYLINE*SCREENWIDTH+34;\r
+\r
+ asm mov es,[screenseg]\r
+ asm mov si,[source]\r
+ asm mov di,[dest]\r
+\r
+ EGAWRITEMODE(1);\r
+\r
+ asm mov cx,MAXBODY\r
+newline:\r
+ asm mov al,[es:si]\r
+ asm mov [es:di+PAGE1START],al\r
+ asm mov [es:di+PAGE2START],al\r
+ asm mov [es:di+PAGE3START],al\r
+ asm mov al,[es:si+1]\r
+ asm mov [es:di+1+PAGE1START],al\r
+ asm mov [es:di+1+PAGE2START],al\r
+ asm mov [es:di+1+PAGE3START],al\r
+ asm mov al,[es:si+2]\r
+ asm mov [es:di+2+PAGE1START],al\r
+ asm mov [es:di+2+PAGE2START],al\r
+ asm mov [es:di+2+PAGE3START],al\r
+ asm mov al,[es:si+3]\r
+ asm mov [es:di+3+PAGE1START],al\r
+ asm mov [es:di+3+PAGE2START],al\r
+ asm mov [es:di+3+PAGE3START],al\r
+ asm mov al,[es:si+4]\r
+ asm mov [es:di+4+PAGE1START],al\r
+ asm mov [es:di+4+PAGE2START],al\r
+ asm mov [es:di+4+PAGE3START],al\r
+ asm add di,SCREENWIDTH\r
+ asm add si,5\r
+\r
+ asm loop newline\r
+\r
+ EGAWRITEMODE(0);\r
+}\r
+\r
+\r
+\r
+//===========================================================================\r
+\r
+/*\r
+===============\r
+=\r
+= ReadScroll\r
+=\r
+===============\r
+*/\r
+\r
+extern boolean tileneeded[NUMFLOORS];\r
+\r
+void ReadScroll (int scroll)\r
+{\r
+ int i;\r
+\r
+//\r
+// make wall pictures purgable\r
+//\r
+ for (i=0;i<NUMSCALEWALLS;i++)\r
+ if (walldirectory[i])\r
+ MM_SetPurge (&(memptr)walldirectory[i],3);\r
+\r
+ CA_CacheGrChunk (SCROLLTOPPIC);\r
+ CA_CacheGrChunk (SCROLL1PIC + scroll);\r
+ VW_DrawPic (0,0,SCROLLTOPPIC);\r
+ VW_DrawPic (0,32,SCROLL1PIC + scroll);\r
+ UNMARKGRCHUNK(SCROLL1PIC + scroll);\r
+ UNMARKGRCHUNK(SCROLLTOPPIC);\r
+ MM_FreePtr (&grsegs[SCROLL1PIC + scroll]);\r
+ MM_FreePtr (&grsegs[SCROLLTOPPIC]);\r
+\r
+//\r
+// cache wall pictures back in\r
+//\r
+ for (i=1;i<NUMFLOORS;i++)\r
+ if (tileneeded[i])\r
+ {\r
+ SetupScaleWall (walllight1[i]);\r
+ SetupScaleWall (walllight2[i]);\r
+ SetupScaleWall (walldark1[i]);\r
+ SetupScaleWall (walldark2[i]);\r
+ }\r
+\r
+ VW_WaitVBL(80);\r
+waitkey:\r
+ IN_ClearKeysDown ();\r
+ IN_Ack();\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= TakeDamage\r
+=\r
+===============\r
+*/\r
+\r
+void TakeDamage (int points)\r
+{\r
+ unsigned source,dest,topline;\r
+\r
+ if (!gamestate.body || bordertime || godmode)\r
+ return;\r
+\r
+ if (points >= gamestate.body)\r
+ {\r
+ points = gamestate.body;\r
+ playstate = ex_died;\r
+ }\r
+\r
+ bordertime = points*FLASHTICS;\r
+ VW_ColorBorder (FLASHCOLOR);\r
+\r
+ if (gamestate.body<MAXBODY/3)\r
+ SD_PlaySound (TAKEDMGHURTSND);\r
+ else\r
+ SD_PlaySound (TAKEDAMAGESND);\r
+\r
+ gamestate.body -= points;\r
+//\r
+// shrink the body bar\r
+//\r
+ source = latchpics[L_NOBODY]+gamestate.body*SIDEBARWIDTH;\r
+ dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;\r
+\r
+\r
+ asm mov es,[screenseg]\r
+ asm mov si,[source]\r
+ asm mov di,[dest]\r
+\r
+ EGAWRITEMODE(1);\r
+\r
+ asm mov cx,[points]\r
+newline:\r
+ asm mov al,[es:si]\r
+ asm mov [es:di+PAGE1START],al\r
+ asm mov [es:di+PAGE2START],al\r
+ asm mov [es:di+PAGE3START],al\r
+ asm mov al,[es:si+1]\r
+ asm mov [es:di+1+PAGE1START],al\r
+ asm mov [es:di+1+PAGE2START],al\r
+ asm mov [es:di+1+PAGE3START],al\r
+ asm mov al,[es:si+2]\r
+ asm mov [es:di+2+PAGE1START],al\r
+ asm mov [es:di+2+PAGE2START],al\r
+ asm mov [es:di+2+PAGE3START],al\r
+ asm mov al,[es:si+3]\r
+ asm mov [es:di+3+PAGE1START],al\r
+ asm mov [es:di+3+PAGE2START],al\r
+ asm mov [es:di+3+PAGE3START],al\r
+ asm mov al,[es:si+4]\r
+ asm mov [es:di+4+PAGE1START],al\r
+ asm mov [es:di+4+PAGE2START],al\r
+ asm mov [es:di+4+PAGE3START],al\r
+\r
+ asm add di,SCREENWIDTH\r
+ asm add si,5\r
+\r
+ asm loop newline\r
+\r
+ EGAWRITEMODE(0);\r
+\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ INTERACTION\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= OpenDoor\r
+=\r
+==================\r
+*/\r
+\r
+void OpenDoor (unsigned bx, unsigned by, unsigned doorbase)\r
+{\r
+ int x,y;\r
+ unsigned far *map;\r
+\r
+ x=bx;\r
+ y=by;\r
+ map = mapsegs[0]+farmapylookup[y]+x;\r
+ while (tilemap[x][y]-doorbase<4)\r
+ {\r
+ tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+ map--;\r
+ x--;\r
+ }\r
+ x=bx+1;\r
+ map = mapsegs[0]+farmapylookup[y]+x;\r
+ while (tilemap[x][y]-doorbase<4)\r
+ {\r
+ tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+ map++;\r
+ x++;\r
+ }\r
+ x=bx;\r
+ y=by-1;\r
+ map = mapsegs[0]+farmapylookup[y]+x;\r
+ while (tilemap[x][y]-doorbase<4)\r
+ {\r
+ tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+ map-=mapwidth;\r
+ y--;\r
+ }\r
+ y=by+1;\r
+ map = mapsegs[0]+farmapylookup[y]+x;\r
+ while (tilemap[x][y]-doorbase<4)\r
+ {\r
+ tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
+ map+=mapwidth;\r
+ y++;\r
+ }\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= HitSpecialTile\r
+=\r
+= Returns true if the move is blocked\r
+=\r
+==================\r
+*/\r
+\r
+boolean HitSpecialTile (unsigned x, unsigned y, unsigned tile)\r
+{\r
+ switch (tile)\r
+ {\r
+ case 0:\r
+ case 1:\r
+ case 2:\r
+ case 3:\r
+ if (!gamestate.keys[0])\r
+ return true;\r
+ TakeKey(0);\r
+ OpenDoor (x,y,SPECTILESTART+0);\r
+ return false;\r
+\r
+ case 4:\r
+ case 5:\r
+ case 6:\r
+ case 7:\r
+ if (!gamestate.keys[1])\r
+ return true;\r
+ TakeKey(1);\r
+ OpenDoor (x,y,SPECTILESTART+4);\r
+ return false;\r
+\r
+ case 8:\r
+ case 9:\r
+ case 10:\r
+ case 11:\r
+ if (!gamestate.keys[2])\r
+ return true;\r
+ TakeKey(2);\r
+ OpenDoor (x,y,SPECTILESTART+8);\r
+ return false;\r
+\r
+ case 12:\r
+ case 13:\r
+ case 14:\r
+ case 15:\r
+ if (!gamestate.keys[3])\r
+ return true;\r
+ TakeKey(3);\r
+ OpenDoor (x,y,SPECTILESTART+12);\r
+ return false;\r
+\r
+ }\r
+\r
+ return true;\r
+}\r
+\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= TouchActor\r
+=\r
+= Returns true if the move is blocked\r
+=\r
+==================\r
+*/\r
+\r
+boolean TouchActor (objtype *ob, objtype *check)\r
+{\r
+ if (ob->xh < check->xl || ob->xl > check->xh ||\r
+ ob->yh < check->yl || ob->yl > check->yh)\r
+ return false; // not quite touching\r
+\r
+ switch (check->obclass)\r
+ {\r
+ case bonusobj:\r
+ if (check->temp1 == B_BOLT)\r
+ GiveBolt ();\r
+ else if (check->temp1 == B_NUKE)\r
+ GiveNuke ();\r
+ else if (check->temp1 == B_POTION)\r
+ GivePotion ();\r
+ else if (check->temp1 >= B_RKEY && check->temp1 <= B_BKEY)\r
+ GiveKey (check->temp1-B_RKEY);\r
+ else if (check->temp1 >= B_SCROLL1 && check->temp1 <= B_SCROLL8)\r
+ GiveScroll (check->temp1-B_SCROLL1,true);\r
+ else if (check->temp1 == B_CHEST)\r
+ GiveChest ();\r
+ else if (check->temp1 == B_GOAL)\r
+ GiveGoal ();\r
+ (unsigned)actorat[check->tilex][check->tiley] = 0;\r
+ RemoveObj (check);\r
+\r
+ return false;\r
+\r
+ }\r
+ return true;\r
+}\r
+\r
+\r
+/*\r
+==================\r
+=\r
+= CalcBounds\r
+=\r
+==================\r
+*/\r
+\r
+void CalcBounds (objtype *ob)\r
+{\r
+//\r
+// calculate hit rect\r
+//\r
+ ob->xl = ob->x - ob->size;\r
+ ob->xh = ob->x + ob->size;\r
+ ob->yl = ob->y - ob->size;\r
+ ob->yh = ob->y + ob->size;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= LocationInActor\r
+=\r
+===================\r
+*/\r
+\r
+boolean LocationInActor (objtype *ob)\r
+{\r
+ int x,y,xmin,ymin,xmax,ymax;\r
+ objtype *check;\r
+\r
+ CalcBounds (ob);\r
+\r
+ xmin = (ob->x >> TILESHIFT)-2;\r
+ ymin = (ob->y >> TILESHIFT)-2;\r
+ xmax = xmin+5;\r
+ ymax = ymin+5;\r
+\r
+ for (x=xmin;x<xmax;x++)\r
+ for (y=ymin;y<ymax;y++)\r
+ {\r
+ check = actorat[x][y];\r
+ if (check>(objtype *)LASTSPECIALTILE\r
+ && check->shootable\r
+ && ob->xl <= check->xh\r
+ && ob->xh >= check->xl\r
+ && ob->yl <= check->yh\r
+ && ob->yh >= check->yl)\r
+ return true;\r
+ }\r
+\r
+ return false;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ClipMove\r
+=\r
+= Only checks corners, so the object better be less than one tile wide!\r
+=\r
+===================\r
+*/\r
+\r
+void ClipMove (objtype *ob, long xmove, long ymove)\r
+{\r
+ int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
+ long intersect,basex,basey,pointx,pointy;\r
+ unsigned inside,total,tile;\r
+ objtype *check;\r
+ boolean moveok;\r
+\r
+//\r
+// move player and check to see if any corners are in solid tiles\r
+//\r
+ basex = ob->x;\r
+ basey = ob->y;\r
+\r
+ ob->x += xmove;\r
+ ob->y += ymove;\r
+\r
+ CalcBounds (ob);\r
+\r
+ xl = ob->xl>>TILESHIFT;\r
+ yl = ob->yl>>TILESHIFT;\r
+\r
+ xh = ob->xh>>TILESHIFT;\r
+ yh = ob->yh>>TILESHIFT;\r
+\r
+ for (y=yl;y<=yh;y++)\r
+ for (x=xl;x<=xh;x++)\r
+ {\r
+ check = actorat[x][y];\r
+ if (!check)\r
+ continue; // blank floor, walk ok\r
+\r
+ if ((unsigned)check<=LASTWALLTILE)\r
+ goto blockmove; // solid wall\r
+\r
+ if ((unsigned)check<=LASTSPECIALTILE)\r
+ {\r
+ if ( HitSpecialTile (x,y,(unsigned)check-SPECTILESTART) )\r
+ goto blockmove; // whatever it was, it blocked the move\r
+ else\r
+ continue;\r
+ }\r
+ TouchActor(ob,check); // pick up items\r
+ }\r
+\r
+//\r
+// check nearby actors\r
+//\r
+ if (LocationInActor(ob))\r
+ {\r
+ ob->x -= xmove;\r
+ if (LocationInActor(ob))\r
+ {\r
+ ob->x += xmove;\r
+ ob->y -= ymove;\r
+ if (LocationInActor(ob))\r
+ ob->x -= xmove;\r
+ }\r
+ }\r
+ return; // move is OK!\r
+\r
+\r
+blockmove:\r
+\r
+ if (!SD_SoundPlaying())\r
+ SD_PlaySound (HITWALLSND);\r
+\r
+ moveok = false;\r
+\r
+ do\r
+ {\r
+ xmove /= 2;\r
+ ymove /= 2;\r
+ if (moveok)\r
+ {\r
+ ob->x += xmove;\r
+ ob->y += ymove;\r
+ }\r
+ else\r
+ {\r
+ ob->x -= xmove;\r
+ ob->y -= ymove;\r
+ }\r
+ CalcBounds (ob);\r
+ xl = ob->xl>>TILESHIFT;\r
+ yl = ob->yl>>TILESHIFT;\r
+ xh = ob->xh>>TILESHIFT;\r
+ yh = ob->yh>>TILESHIFT;\r
+ if (tilemap[xl][yl] || tilemap[xh][yl]\r
+ || tilemap[xh][yh] || tilemap[xl][yh] )\r
+ {\r
+ moveok = false;\r
+ if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+ {\r
+ ob->x = basex;\r
+ ob->y = basey;\r
+ return;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+ return;\r
+ moveok = true;\r
+ }\r
+ } while (1);\r
+}\r
+\r
+\r
+//==========================================================================\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= ShotClipMove\r
+=\r
+= Only checks corners, so the object better be less than one tile wide!\r
+=\r
+===================\r
+*/\r
+\r
+boolean ShotClipMove (objtype *ob, long xmove, long ymove)\r
+{\r
+ int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
+ long intersect,basex,basey,pointx,pointy;\r
+ unsigned inside,total,tile;\r
+ objtype *check;\r
+ boolean moveok;\r
+\r
+//\r
+// move shot and check to see if any corners are in solid tiles\r
+//\r
+ basex = ob->x;\r
+ basey = ob->y;\r
+\r
+ ob->x += xmove;\r
+ ob->y += ymove;\r
+\r
+ CalcBounds (ob);\r
+\r
+ xl = ob->xl>>TILESHIFT;\r
+ yl = ob->yl>>TILESHIFT;\r
+\r
+ xh = ob->xh>>TILESHIFT;\r
+ yh = ob->yh>>TILESHIFT;\r
+\r
+ for (y=yl;y<=yh;y++)\r
+ for (x=xl;x<=xh;x++)\r
+ {\r
+ tile = tilemap[x][y];\r
+ if (tile)\r
+ {\r
+ if ((unsigned)(tile-EXPWALLSTART)<NUMEXPWALLS)\r
+ ExplodeWall (x,y);\r
+ goto blockmove;\r
+ }\r
+ }\r
+ return false; // move is OK!\r
+\r
+\r
+blockmove:\r
+\r
+ SD_PlaySound (SHOOTWALLSND);\r
+\r
+ moveok = false;\r
+\r
+ do\r
+ {\r
+ xmove /= 2;\r
+ ymove /= 2;\r
+ if (moveok)\r
+ {\r
+ ob->x += xmove;\r
+ ob->y += ymove;\r
+ }\r
+ else\r
+ {\r
+ ob->x -= xmove;\r
+ ob->y -= ymove;\r
+ }\r
+ CalcBounds (ob);\r
+ xl = ob->xl>>TILESHIFT;\r
+ yl = ob->yl>>TILESHIFT;\r
+ xh = ob->xh>>TILESHIFT;\r
+ yh = ob->yh>>TILESHIFT;\r
+ if (tilemap[xl][yl] || tilemap[xh][yl]\r
+ || tilemap[xh][yh] || tilemap[xl][yh] )\r
+ {\r
+ moveok = false;\r
+ if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+ {\r
+ ob->x = basex;\r
+ ob->y = basey;\r
+ return true;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
+ return true;\r
+ moveok = true;\r
+ }\r
+ } while (1);\r
+}\r
+\r
+\r
+\r
+/*\r
+=============================================================================\r
+\r
+ PLAYER CONTROL\r
+\r
+=============================================================================\r
+*/\r
+\r
+\r
+\r
+void T_Player (objtype *ob);\r
+\r
+statetype s_player = {0,0,&T_Player,&s_player};\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->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
+ player->size = MINDIST;\r
+ CalcBounds (player);\r
+ if (player->angle<0)\r
+ player->angle += ANGLES;\r
+}\r
+\r
+\r
+/*\r
+===================\r
+=\r
+= Thrust\r
+=\r
+===================\r
+*/\r
+\r
+void Thrust (int angle, unsigned speed)\r
+{\r
+ long xmove,ymove;\r
+\r
+ if (lasttimecount>>5 != ((lasttimecount-tics)>>5) )\r
+ {\r
+ //\r
+ // walk sound\r
+ //\r
+ if (lasttimecount&32)\r
+ SD_PlaySound (WALK1SND);\r
+ else\r
+ SD_PlaySound (WALK2SND);\r
+ }\r
+\r
+ xmove = FixedByFrac(speed,costable[angle]);\r
+ ymove = -FixedByFrac(speed,sintable[angle]);\r
+\r
+ ClipMove(player,xmove,ymove);\r
+ player->tilex = player->x >> TILESHIFT;\r
+ player->tiley = player->y >> TILESHIFT;\r
+}\r
+\r
+\r
+\r
+/*\r
+=======================\r
+=\r
+= ControlMovement\r
+=\r
+=======================\r
+*/\r
+\r
+void ControlMovement (objtype *ob)\r
+{\r
+ int angle;\r
+ long speed;\r
+\r
+\r
+ if (c.button1)\r
+ {\r
+ //\r
+ // strafing\r
+ //\r
+ //\r
+ // side to side move\r
+ //\r
+ if (!mousexmove)\r
+ speed = 0;\r
+ else if (mousexmove<0)\r
+ speed = -(long)mousexmove*300;\r
+ else\r
+ speed = -(long)mousexmove*300;\r
+\r
+ if (c.xaxis == -1)\r
+ {\r
+ if (running)\r
+ speed += RUNSPEED*tics;\r
+ else\r
+ speed += PLAYERSPEED*tics;\r
+ }\r
+ else if (c.xaxis == 1)\r
+ {\r
+ if (running)\r
+ speed -= RUNSPEED*tics;\r
+ else\r
+ speed -= PLAYERSPEED*tics;\r
+ }\r
+\r
+ if (speed > 0)\r
+ {\r
+ if (speed >= TILEGLOBAL)\r
+ speed = TILEGLOBAL-1;\r
+ angle = ob->angle + ANGLES/4;\r
+ if (angle >= ANGLES)\r
+ angle -= ANGLES;\r
+ Thrust (angle,speed); // move to left\r
+ }\r
+ else if (speed < 0)\r
+ {\r
+ if (speed <= -TILEGLOBAL)\r
+ speed = -TILEGLOBAL+1;\r
+ angle = ob->angle - ANGLES/4;\r
+ if (angle < 0)\r
+ angle += ANGLES;\r
+ Thrust (angle,-speed); // move to right\r
+ }\r
+ }\r
+ else\r
+ {\r
+ //\r
+ // not strafing\r
+ //\r
+\r
+ //\r
+ // turning\r
+ //\r
+ if (c.xaxis == 1)\r
+ {\r
+ ob->angle -= tics;\r
+ if (running) // fast turn\r
+ ob->angle -= tics;\r
+ }\r
+ else if (c.xaxis == -1)\r
+ {\r
+ ob->angle+= tics;\r
+ if (running) // fast turn\r
+ ob->angle += tics;\r
+ }\r
+\r
+ ob->angle -= (mousexmove/10);\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 (!mouseymove)\r
+ speed = 0;\r
+ else if (mouseymove<0)\r
+ speed = -(long)mouseymove*500;\r
+ else\r
+ speed = -(long)mouseymove*200;\r
+\r
+ if (c.yaxis == -1)\r
+ {\r
+ if (running)\r
+ speed += RUNSPEED*tics;\r
+ else\r
+ speed += PLAYERSPEED*tics;\r
+ }\r
+ else if (c.yaxis == 1)\r
+ {\r
+ if (running)\r
+ speed -= RUNSPEED*tics;\r
+ else\r
+ speed -= PLAYERSPEED*tics;\r
+ }\r
+\r
+ if (speed > 0)\r
+ {\r
+ if (speed >= TILEGLOBAL)\r
+ speed = TILEGLOBAL-1;\r
+ Thrust (ob->angle,speed); // move forwards\r
+ }\r
+ else if (speed < 0)\r
+ {\r
+ if (speed <= -TILEGLOBAL)\r
+ speed = -TILEGLOBAL+1;\r
+ angle = ob->angle + ANGLES/2;\r
+ if (angle >= ANGLES)\r
+ angle -= ANGLES;\r
+ Thrust (angle,-speed); // move backwards\r
+ }\r
+}\r
+\r
+\r
+/*\r
+===============\r
+=\r
+= T_Player\r
+=\r
+===============\r
+*/\r
+\r
+void T_Player (objtype *ob)\r
+{\r
+ int angle,speed,scroll;\r
+ unsigned text,tilex,tiley;\r
+ long lspeed;\r
+\r
+\r
+ ControlMovement (ob);\r
+\r
+\r
+ //\r
+ // firing\r
+ //\r
+ if (boltsleft)\r
+ {\r
+ handheight+=(tics<<2);\r
+ if (handheight>MAXHANDHEIGHT)\r
+ handheight = MAXHANDHEIGHT;\r
+\r
+ ContinueBolt ();\r
+ lasthand = lasttimecount;\r
+ }\r
+ else\r
+ {\r
+ if (c.button0)\r
+ {\r
+ handheight+=(tics<<2);\r
+ if (handheight>MAXHANDHEIGHT)\r
+ handheight = MAXHANDHEIGHT;\r
+\r
+ if ((unsigned)TimeCount/FIRETIME != lastfiretime)\r
+ BuildShotPower ();\r
+ lasthand = lasttimecount;\r
+ }\r
+ else\r
+ {\r
+ if (lasttimecount > lasthand+HANDPAUSE)\r
+ {\r
+ handheight-=(tics<<1);\r
+ if (handheight<0)\r
+ handheight = 0;\r
+ }\r
+\r
+ if (gamestate.shotpower == MAXSHOTPOWER)\r
+ {\r
+ lastfiretime = (unsigned)TimeCount/FIRETIME;\r
+ BigShoot ();\r
+ }\r
+ else if (gamestate.shotpower)\r
+ {\r
+ lastfiretime = (unsigned)TimeCount/FIRETIME;\r
+ Shoot ();\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // special actions\r
+ //\r
+\r
+ if ( (Keyboard[sc_Space] || Keyboard[sc_H]) && gamestate.body != MAXBODY)\r
+ DrinkPotion ();\r
+\r
+ if (Keyboard[sc_B] && !boltsleft)\r
+ CastBolt ();\r
+\r
+ if ( (Keyboard[sc_Enter] || Keyboard[sc_N]) && TimeCount-lastnuke > NUKETIME)\r
+ CastNuke ();\r
+\r
+ scroll = LastScan-2;\r
+ if ( scroll>=0 && scroll<NUMSCROLLS && gamestate.scrolls[scroll])\r
+ ReadScroll (scroll);\r
+\r
+ DrawText ();\r
+ DrawCompass ();\r
+\r
+}\r