/* Catacomb 3-D Source Code * Copyright (C) 1993-2014 Flat Rock Software * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // C3_WIZ.C #include "C3_DEF.H" #pragma hdrstop /* ============================================================================= LOCAL CONSTANTS ============================================================================= */ #define NUMSCROLLS 8 #define SHOWITEMS 9 #define NUKETIME 40 #define NUMBOLTS 10 #define BOLTTICS 6 #define STATUSCOLOR 4 #define TEXTCOLOR 14 #define SIDEBARWIDTH 5 #define BODYLINE 8 #define POWERLINE 80 #define SPECTILESTART 18 #define SHOTDAMAGE 1 #define BIGSHOTDAMAGE 3 #define PLAYERSPEED 5120 #define RUNSPEED 8192 #define SHOTSPEED 10000 #define LASTWALLTILE 17 #define LASTSPECIALTILE 37 #define FIRETIME 4 // DEBUG 60 #define HANDPAUSE 60 #define COMPASSX 33 #define COMPASSY 0 /* ============================================================================= GLOBAL VARIABLES ============================================================================= */ long lastnuke,lasthand; int handheight; int boltsleft; /* ============================================================================= LOCAL VARIABLES ============================================================================= */ int lasttext,lastcompass; int bolttimer; unsigned lastfiretime; int strafeangle[9] = {0,90,180,270,45,135,225,315,0}; //=========================================================================== void DrawChar (unsigned x, unsigned y, unsigned tile); void RedrawStatusWindow (void); void GiveBolt (void); void TakeBolt (void); void GiveNuke (void); void TakeNuke (void); void GivePotion (void); void TakePotion (void); void GiveKey (int keytype); void TakeKey (int keytype); void GiveScroll (int scrolltype,boolean show); void ReadScroll (int scroll); void GivePoints (int points); void DrawLevelNumber (int number); void DrawText (void); void DrawBars (void); //---------- void Shoot (void); void BigShoot (void); void CastBolt (void); void CastNuke (void); void DrinkPotion (void); //---------- void SpawnPlayer (int tilex, int tiley, int dir); void Thrust (int angle, unsigned speed); void T_Player (objtype *ob); void AddPoints (int points); void ClipMove (objtype *ob, long xmove, long ymove); boolean ShotClipMove (objtype *ob, long xmove, long ymove); //=========================================================================== /* =============== = = DrawChar = =============== */ void DrawChar (unsigned x, unsigned y, unsigned tile) { unsigned junk = latchpics[0]; EGAWRITEMODE(1); asm mov bx,[y] asm shl bx,1 asm mov di,[WORD PTR ylookup+bx] asm add di,[x] asm mov si,[tile] asm shl si,1 asm shl si,1 asm shl si,1 asm add si,[junk] // the damn inline assembler won't reference latchpics asm mov ax,[screenseg] asm mov es,ax asm mov ds,ax asm mov dx,SCREENWIDTH-1 asm movsb asm add di,dx asm movsb asm add di,dx asm movsb asm add di,dx asm movsb asm add di,dx asm movsb asm add di,dx asm movsb asm add di,dx asm movsb asm add di,dx asm movsb asm mov ax,ss asm mov ds,ax EGAWRITEMODE(0); } //=========================================================================== /* =============== = = RedrawStatusWindow = =============== */ void RedrawStatusWindow (void) { int i,j,x; DrawLevelNumber (gamestate.mapon); lasttext = -1; lastcompass = -1; j = gamestate.bolts < SHOWITEMS ? gamestate.bolts : SHOWITEMS; for (i=0;itiley]+player->tilex)-NAMESTART; if ( number>26 ) number = 0; if (number == lasttext) return; bufferofs = 0; lasttext = number; PrintY = 4; WindowX = 26; WindowW = 232; text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number]; _fmemcpy (str,text,80); VW_Bar (26,4,232,9,STATUSCOLOR); temp = fontcolor; fontcolor = TEXTCOLOR^STATUSCOLOR; US_CPrintLine (str); fontcolor = temp; } //=========================================================================== /* =============== = = DrawCompass = =============== */ void DrawCompass (void) { int angle,number; // // draw the compass if needed // angle = player->angle-ANGLES/4; angle -= ANGLES/32; if (angle<0) angle+=ANGLES; number = angle/(ANGLES/16); if (number>15) // because 360 angles doesn't divide by 16 number = 15; if (number == lastcompass) return; lastcompass = number; bufferofs = 0; LatchDrawPic (COMPASSX,COMPASSY,COMPAS1PIC+15-number); } //=========================================================================== /* =============== = = DrawBars = =============== */ void DrawBars (void) { int i; unsigned source,dest,topline; for (i=0;i<3;i++) { bufferofs = screenloc[i]; VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1); } EGAWRITEMODE(1); asm mov es,[screenseg] // // shot power // if (gamestate.shotpower) { topline = MAXSHOTPOWER - gamestate.shotpower; source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH; dest = (POWERLINE+topline)*SCREENWIDTH+34; asm mov si,[source] asm mov di,[dest] asm mov cx,[WORD PTR gamestate.shotpower] newline: asm mov al,[es:si] asm mov [es:di+PAGE1START],al asm mov [es:di+PAGE2START],al asm mov [es:di+PAGE3START],al asm mov al,[es:si+1] asm mov [es:di+1+PAGE1START],al asm mov [es:di+1+PAGE2START],al asm mov [es:di+1+PAGE3START],al asm mov al,[es:si+2] asm mov [es:di+2+PAGE1START],al asm mov [es:di+2+PAGE2START],al asm mov [es:di+2+PAGE3START],al asm mov al,[es:si+3] asm mov [es:di+3+PAGE1START],al asm mov [es:di+3+PAGE2START],al asm mov [es:di+3+PAGE3START],al asm mov al,[es:si+4] asm mov [es:di+4+PAGE1START],al asm mov [es:di+4+PAGE2START],al asm mov [es:di+4+PAGE3START],al asm add di,SCREENWIDTH asm add si,5 asm loop newline } // // body // if (gamestate.body) { source = latchpics[BODYPIC-FIRSTLATCHPIC]; dest = BODYLINE*SCREENWIDTH+34; asm mov si,[source] asm mov di,[dest] asm mov cx,[WORD PTR gamestate.body] newline2: asm mov al,[es:si] asm mov [es:di+PAGE1START],al asm mov [es:di+PAGE2START],al asm mov [es:di+PAGE3START],al asm mov al,[es:si+1] asm mov [es:di+1+PAGE1START],al asm mov [es:di+1+PAGE2START],al asm mov [es:di+1+PAGE3START],al asm mov al,[es:si+2] asm mov [es:di+2+PAGE1START],al asm mov [es:di+2+PAGE2START],al asm mov [es:di+2+PAGE3START],al asm mov al,[es:si+3] asm mov [es:di+3+PAGE1START],al asm mov [es:di+3+PAGE2START],al asm mov [es:di+3+PAGE3START],al asm mov al,[es:si+4] asm mov [es:di+4+PAGE1START],al asm mov [es:di+4+PAGE2START],al asm mov [es:di+4+PAGE3START],al asm add di,SCREENWIDTH asm add si,5 asm loop newline2 } if (gamestate.body != MAXBODY) { source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH; dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34; topline = MAXBODY-gamestate.body; asm mov si,[source] asm mov di,[dest] asm mov cx,[WORD PTR topline] newline3: asm mov al,[es:si] asm mov [es:di+PAGE1START],al asm mov [es:di+PAGE2START],al asm mov [es:di+PAGE3START],al asm mov al,[es:si+1] asm mov [es:di+1+PAGE1START],al asm mov [es:di+1+PAGE2START],al asm mov [es:di+1+PAGE3START],al asm mov al,[es:si+2] asm mov [es:di+2+PAGE1START],al asm mov [es:di+2+PAGE2START],al asm mov [es:di+2+PAGE3START],al asm mov al,[es:si+3] asm mov [es:di+3+PAGE1START],al asm mov [es:di+3+PAGE2START],al asm mov [es:di+3+PAGE3START],al asm mov al,[es:si+4] asm mov [es:di+4+PAGE1START],al asm mov [es:di+4+PAGE2START],al asm mov [es:di+4+PAGE3START],al asm add di,SCREENWIDTH asm add si,5 asm loop newline3 } EGAWRITEMODE(0); } /* ============================================================================= SHOTS ============================================================================= */ void T_Pshot (objtype *ob); extern statetype s_pshot1; extern statetype s_pshot2; extern statetype s_bigpshot1; extern statetype s_bigpshot2; statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2}; statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1}; statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL}; statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2}; statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1}; /* =================== = = SpawnPShot = =================== */ void SpawnPShot (void) { SpawnNewObjFrac (player->x,player->y,&s_pshot1,PIXRADIUS*14); new->obclass = pshotobj; new->speed = SHOTSPEED; new->angle = player->angle; } void SpawnBigPShot (void) { SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS); new->obclass = bigpshotobj; new->speed = SHOTSPEED; new->angle = player->angle; } /* =============== = = T_Pshot = =============== */ void T_Pshot (objtype *ob) { objtype *check; long xmove,ymove,speed; // // check current position for monsters having moved into it // for (check = player->next; check; check=check->next) if (check->shootable && ob->xl <= check->xh && ob->xh >= check->xl && ob->yl <= check->yh && ob->yh >= check->yl) { SD_PlaySound (SHOOTMONSTERSND); if (ob->obclass == bigpshotobj) ShootActor (check,BIGSHOTDAMAGE); else ShootActor (check,SHOTDAMAGE); ob->state = &s_shotexplode; ob->ticcount = ob->state->tictime; return; } // // move ahead, possibly hitting a wall // speed = ob->speed*tics; xmove = FixedByFrac(speed,costable[ob->angle]); ymove = -FixedByFrac(speed,sintable[ob->angle]); if (ShotClipMove(ob,xmove,ymove)) { ob->state = &s_shotexplode; ob->ticcount = ob->state->tictime; return; } ob->tilex = ob->x >> TILESHIFT; ob->tiley = ob->y >> TILESHIFT; // // check final position for monsters hit // for (check = player->next; check; check=check->next) if (ob->shootable && ob->xl <= check->xh && ob->xh >= check->xl && ob->yl <= check->yh && ob->yh >= check->yl) { ShootActor (check,SHOTDAMAGE); ob->state = &s_shotexplode; ob->ticcount = ob->state->tictime; return; } } /* ============================================================================= PLAYER ACTIONS ============================================================================= */ /* =============== = = BuildShotPower = =============== */ void BuildShotPower (void) { int newlines,topline; long i; unsigned source,dest; if (gamestate.shotpower == MAXSHOTPOWER) return; newlines = 0; for (i=lasttimecount-tics;i MAXSHOTPOWER) { newlines -= (gamestate.shotpower - MAXSHOTPOWER); gamestate.shotpower = MAXSHOTPOWER; } topline = MAXSHOTPOWER - gamestate.shotpower; source = latchpics[L_SHOTBAR]+topline*SIDEBARWIDTH; dest = (POWERLINE+topline)*SCREENWIDTH+34; asm mov es,[screenseg] asm mov si,[source] asm mov di,[dest] EGAWRITEMODE(1); if (newlines) { asm mov cx,[newlines] newline: asm mov al,[es:si] asm mov [es:di+PAGE1START],al asm mov [es:di+PAGE2START],al asm mov [es:di+PAGE3START],al asm mov al,[es:si+1] asm mov [es:di+1+PAGE1START],al asm mov [es:di+1+PAGE2START],al asm mov [es:di+1+PAGE3START],al asm mov al,[es:si+2] asm mov [es:di+2+PAGE1START],al asm mov [es:di+2+PAGE2START],al asm mov [es:di+2+PAGE3START],al asm mov al,[es:si+3] asm mov [es:di+3+PAGE1START],al asm mov [es:di+3+PAGE2START],al asm mov [es:di+3+PAGE3START],al asm mov al,[es:si+4] asm mov [es:di+4+PAGE1START],al asm mov [es:di+4+PAGE2START],al asm mov [es:di+4+PAGE3START],al asm add di,SCREENWIDTH asm add si,5 asm loop newline } EGAWRITEMODE(0); } //=========================================================================== /* =============== = = ClearShotPower = =============== */ void ClearShotPower (void) { unsigned source,dest,topline; topline = MAXSHOTPOWER - gamestate.shotpower; source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH; dest = (POWERLINE+topline)*SCREENWIDTH+34; asm mov es,[screenseg] asm mov si,[source] asm mov di,[dest] if (!gamestate.shotpower) return; EGAWRITEMODE(1); asm mov cx,[WORD PTR gamestate.shotpower] newline: asm mov al,[es:si] asm mov [es:di+PAGE1START],al asm mov [es:di+PAGE2START],al asm mov [es:di+PAGE3START],al asm mov al,[es:si+1] asm mov [es:di+1+PAGE1START],al asm mov [es:di+1+PAGE2START],al asm mov [es:di+1+PAGE3START],al asm mov al,[es:si+2] asm mov [es:di+2+PAGE1START],al asm mov [es:di+2+PAGE2START],al asm mov [es:di+2+PAGE3START],al asm mov al,[es:si+3] asm mov [es:di+3+PAGE1START],al asm mov [es:di+3+PAGE2START],al asm mov [es:di+3+PAGE3START],al asm mov al,[es:si+4] asm mov [es:di+4+PAGE1START],al asm mov [es:di+4+PAGE2START],al asm mov [es:di+4+PAGE3START],al asm add di,SCREENWIDTH asm add si,5 asm loop newline EGAWRITEMODE(0); gamestate.shotpower = 0; } //=========================================================================== /* =============== = = Shoot = =============== */ void Shoot (void) { ClearShotPower (); SD_PlaySound (SHOOTSND); SpawnPShot (); } //=========================================================================== /* =============== = = BigShoot = =============== */ void BigShoot (void) { ClearShotPower (); SD_PlaySound (BIGSHOOTSND); SpawnBigPShot (); } //=========================================================================== /* =============== = = CastBolt = =============== */ void CastBolt (void) { if (!gamestate.bolts) { SD_PlaySound (NOITEMSND); return; } TakeBolt (); boltsleft = NUMBOLTS; bolttimer = BOLTTICS; BigShoot (); } /* =============== = = ContinueBolt = =============== */ void ContinueBolt (void) { bolttimer-=tics; if (bolttimer<0) { boltsleft--; bolttimer = BOLTTICS; BigShoot (); } } //=========================================================================== /* =============== = = CastNuke = =============== */ void CastNuke (void) { int angle; if (!gamestate.nukes) { SD_PlaySound (NOITEMSND); return; } TakeNuke (); lastnuke = TimeCount; for (angle = 0; angle < ANGLES; angle+= ANGLES/16) { SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS); new->obclass = bigpshotobj; new->speed = SHOTSPEED; new->angle = angle; } } //=========================================================================== /* =============== = = DrinkPotion = =============== */ void DrinkPotion (void) { unsigned source,dest,topline; if (!gamestate.potions) { SD_PlaySound (NOITEMSND); return; } TakePotion (); gamestate.body = MAXBODY; // // draw a full up bar // source = latchpics[L_BODYBAR]; dest = BODYLINE*SCREENWIDTH+34; asm mov es,[screenseg] asm mov si,[source] asm mov di,[dest] EGAWRITEMODE(1); asm mov cx,MAXBODY newline: asm mov al,[es:si] asm mov [es:di+PAGE1START],al asm mov [es:di+PAGE2START],al asm mov [es:di+PAGE3START],al asm mov al,[es:si+1] asm mov [es:di+1+PAGE1START],al asm mov [es:di+1+PAGE2START],al asm mov [es:di+1+PAGE3START],al asm mov al,[es:si+2] asm mov [es:di+2+PAGE1START],al asm mov [es:di+2+PAGE2START],al asm mov [es:di+2+PAGE3START],al asm mov al,[es:si+3] asm mov [es:di+3+PAGE1START],al asm mov [es:di+3+PAGE2START],al asm mov [es:di+3+PAGE3START],al asm mov al,[es:si+4] asm mov [es:di+4+PAGE1START],al asm mov [es:di+4+PAGE2START],al asm mov [es:di+4+PAGE3START],al asm add di,SCREENWIDTH asm add si,5 asm loop newline EGAWRITEMODE(0); } //=========================================================================== /* =============== = = ReadScroll = =============== */ extern boolean tileneeded[NUMFLOORS]; void ReadScroll (int scroll) { int i; // // make wall pictures purgable // for (i=0;i= gamestate.body) { points = gamestate.body; playstate = ex_died; } bordertime = points*FLASHTICS; VW_ColorBorder (FLASHCOLOR); if (gamestate.bodyxh < check->xl || ob->xl > check->xh || ob->yh < check->yl || ob->yl > check->yh) return false; // not quite touching switch (check->obclass) { case bonusobj: if (check->temp1 == B_BOLT) GiveBolt (); else if (check->temp1 == B_NUKE) GiveNuke (); else if (check->temp1 == B_POTION) GivePotion (); else if (check->temp1 >= B_RKEY && check->temp1 <= B_BKEY) GiveKey (check->temp1-B_RKEY); else if (check->temp1 >= B_SCROLL1 && check->temp1 <= B_SCROLL8) GiveScroll (check->temp1-B_SCROLL1,true); else if (check->temp1 == B_CHEST) GiveChest (); else if (check->temp1 == B_GOAL) GiveGoal (); (unsigned)actorat[check->tilex][check->tiley] = 0; RemoveObj (check); return false; } return true; } /* ================== = = CalcBounds = ================== */ void CalcBounds (objtype *ob) { // // calculate hit rect // ob->xl = ob->x - ob->size; ob->xh = ob->x + ob->size; ob->yl = ob->y - ob->size; ob->yh = ob->y + ob->size; } /* =================== = = LocationInActor = =================== */ boolean LocationInActor (objtype *ob) { int x,y,xmin,ymin,xmax,ymax; objtype *check; CalcBounds (ob); xmin = (ob->x >> TILESHIFT)-2; ymin = (ob->y >> TILESHIFT)-2; xmax = xmin+5; ymax = ymin+5; for (x=xmin;x(objtype *)LASTSPECIALTILE && check->shootable && ob->xl <= check->xh && ob->xh >= check->xl && ob->yl <= check->yh && ob->yh >= check->yl) return true; } return false; } /* =================== = = ClipMove = = Only checks corners, so the object better be less than one tile wide! = =================== */ void ClipMove (objtype *ob, long xmove, long ymove) { int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y; long intersect,basex,basey,pointx,pointy; unsigned inside,total,tile; objtype *check; boolean moveok; // // move player and check to see if any corners are in solid tiles // basex = ob->x; basey = ob->y; ob->x += xmove; ob->y += ymove; CalcBounds (ob); xl = ob->xl>>TILESHIFT; yl = ob->yl>>TILESHIFT; xh = ob->xh>>TILESHIFT; yh = ob->yh>>TILESHIFT; for (y=yl;y<=yh;y++) for (x=xl;x<=xh;x++) { check = actorat[x][y]; if (!check) continue; // blank floor, walk ok if ((unsigned)check<=LASTWALLTILE) goto blockmove; // solid wall if ((unsigned)check<=LASTSPECIALTILE) { if ( HitSpecialTile (x,y,(unsigned)check-SPECTILESTART) ) goto blockmove; // whatever it was, it blocked the move else continue; } TouchActor(ob,check); // pick up items } // // check nearby actors // if (LocationInActor(ob)) { ob->x -= xmove; if (LocationInActor(ob)) { ob->x += xmove; ob->y -= ymove; if (LocationInActor(ob)) ob->x -= xmove; } } return; // move is OK! blockmove: if (!SD_SoundPlaying()) SD_PlaySound (HITWALLSND); moveok = false; do { xmove /= 2; ymove /= 2; if (moveok) { ob->x += xmove; ob->y += ymove; } else { ob->x -= xmove; ob->y -= ymove; } CalcBounds (ob); xl = ob->xl>>TILESHIFT; yl = ob->yl>>TILESHIFT; xh = ob->xh>>TILESHIFT; yh = ob->yh>>TILESHIFT; if (tilemap[xl][yl] || tilemap[xh][yl] || tilemap[xh][yh] || tilemap[xl][yh] ) { moveok = false; if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048) { ob->x = basex; ob->y = basey; return; } } else { if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048) return; moveok = true; } } while (1); } //========================================================================== /* =================== = = ShotClipMove = = Only checks corners, so the object better be less than one tile wide! = =================== */ boolean ShotClipMove (objtype *ob, long xmove, long ymove) { int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y; long intersect,basex,basey,pointx,pointy; unsigned inside,total,tile; objtype *check; boolean moveok; // // move shot and check to see if any corners are in solid tiles // basex = ob->x; basey = ob->y; ob->x += xmove; ob->y += ymove; CalcBounds (ob); xl = ob->xl>>TILESHIFT; yl = ob->yl>>TILESHIFT; xh = ob->xh>>TILESHIFT; yh = ob->yh>>TILESHIFT; for (y=yl;y<=yh;y++) for (x=xl;x<=xh;x++) { tile = tilemap[x][y]; if (tile) { if ((unsigned)(tile-EXPWALLSTART)x += xmove; ob->y += ymove; } else { ob->x -= xmove; ob->y -= ymove; } CalcBounds (ob); xl = ob->xl>>TILESHIFT; yl = ob->yl>>TILESHIFT; xh = ob->xh>>TILESHIFT; yh = ob->yh>>TILESHIFT; if (tilemap[xl][yl] || tilemap[xh][yl] || tilemap[xh][yh] || tilemap[xl][yh] ) { moveok = false; if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048) { ob->x = basex; ob->y = basey; return true; } } else { if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048) return true; moveok = true; } } while (1); } /* ============================================================================= PLAYER CONTROL ============================================================================= */ void T_Player (objtype *ob); statetype s_player = {0,0,&T_Player,&s_player}; /* =============== = = SpawnPlayer = =============== */ void SpawnPlayer (int tilex, int tiley, int dir) { player->obclass = playerobj; player->active = true; player->tilex = tilex; player->tiley = tiley; player->x = ((long)tilex<y = ((long)tiley<state = &s_player; player->angle = (1-dir)*90; player->size = MINDIST; CalcBounds (player); if (player->angle<0) player->angle += ANGLES; } /* =================== = = Thrust = =================== */ void Thrust (int angle, unsigned speed) { long xmove,ymove; if (lasttimecount>>5 != ((lasttimecount-tics)>>5) ) { // // walk sound // if (lasttimecount&32) SD_PlaySound (WALK1SND); else SD_PlaySound (WALK2SND); } xmove = FixedByFrac(speed,costable[angle]); ymove = -FixedByFrac(speed,sintable[angle]); ClipMove(player,xmove,ymove); player->tilex = player->x >> TILESHIFT; player->tiley = player->y >> TILESHIFT; } /* ======================= = = ControlMovement = ======================= */ void ControlMovement (objtype *ob) { int angle; long speed; if (c.button1) { // // strafing // // // side to side move // if (!mousexmove) speed = 0; else if (mousexmove<0) speed = -(long)mousexmove*300; else speed = -(long)mousexmove*300; if (c.xaxis == -1) { if (running) speed += RUNSPEED*tics; else speed += PLAYERSPEED*tics; } else if (c.xaxis == 1) { if (running) speed -= RUNSPEED*tics; else speed -= PLAYERSPEED*tics; } if (speed > 0) { if (speed >= TILEGLOBAL) speed = TILEGLOBAL-1; angle = ob->angle + ANGLES/4; if (angle >= ANGLES) angle -= ANGLES; Thrust (angle,speed); // move to left } else if (speed < 0) { if (speed <= -TILEGLOBAL) speed = -TILEGLOBAL+1; angle = ob->angle - ANGLES/4; if (angle < 0) angle += ANGLES; Thrust (angle,-speed); // move to right } } else { // // not strafing // // // turning // if (c.xaxis == 1) { ob->angle -= tics; if (running) // fast turn ob->angle -= tics; } else if (c.xaxis == -1) { ob->angle+= tics; if (running) // fast turn ob->angle += tics; } ob->angle -= (mousexmove/10); if (ob->angle >= ANGLES) ob->angle -= ANGLES; if (ob->angle < 0) ob->angle += ANGLES; } // // forward/backwards move // if (!mouseymove) speed = 0; else if (mouseymove<0) speed = -(long)mouseymove*500; else speed = -(long)mouseymove*200; if (c.yaxis == -1) { if (running) speed += RUNSPEED*tics; else speed += PLAYERSPEED*tics; } else if (c.yaxis == 1) { if (running) speed -= RUNSPEED*tics; else speed -= PLAYERSPEED*tics; } if (speed > 0) { if (speed >= TILEGLOBAL) speed = TILEGLOBAL-1; Thrust (ob->angle,speed); // move forwards } else if (speed < 0) { if (speed <= -TILEGLOBAL) speed = -TILEGLOBAL+1; angle = ob->angle + ANGLES/2; if (angle >= ANGLES) angle -= ANGLES; Thrust (angle,-speed); // move backwards } } /* =============== = = T_Player = =============== */ void T_Player (objtype *ob) { int angle,speed,scroll; unsigned text,tilex,tiley; long lspeed; ControlMovement (ob); // // firing // if (boltsleft) { handheight+=(tics<<2); if (handheight>MAXHANDHEIGHT) handheight = MAXHANDHEIGHT; ContinueBolt (); lasthand = lasttimecount; } else { if (c.button0) { handheight+=(tics<<2); if (handheight>MAXHANDHEIGHT) handheight = MAXHANDHEIGHT; if ((unsigned)TimeCount/FIRETIME != lastfiretime) BuildShotPower (); lasthand = lasttimecount; } else { if (lasttimecount > lasthand+HANDPAUSE) { handheight-=(tics<<1); if (handheight<0) handheight = 0; } if (gamestate.shotpower == MAXSHOTPOWER) { lastfiretime = (unsigned)TimeCount/FIRETIME; BigShoot (); } else if (gamestate.shotpower) { lastfiretime = (unsigned)TimeCount/FIRETIME; Shoot (); } } } // // special actions // if ( (Keyboard[sc_Space] || Keyboard[sc_H]) && gamestate.body != MAXBODY) DrinkPotion (); if (Keyboard[sc_B] && !boltsleft) CastBolt (); if ( (Keyboard[sc_Enter] || Keyboard[sc_N]) && TimeCount-lastnuke > NUKETIME) CastNuke (); scroll = LastScan-2; if ( scroll>=0 && scroll