/* Hovertank 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. */ #include "HOVERDEF.H" //========================================================================== #define GUNARM 50 #define GUNCHARGE 70 #define EXPLODEANM 8 #define SHOTSPEED 8192l #define MSHOTSPEED 6000l #define REFUGEEANM 30 #define WARPANM 10 #define SPDMUTANT 2500l #define MUTANTANM 20 #define MUTANTATTACK 120 #define SPDDRONE 16384l #define DRONEANM 10 #define TANKRELOAD 200 #define ANGLESTEP 1 #define PLAYERTHRUST 4096l #define PLAYERREVERSE 2048l #define PLAYERAFTERBURN 8192l #define SHIELDANM 10 #define MINCHASE 4096 dirtype opposite[9] = {south,southwest,west,northwest,north,northeast,east,southeast,nodir}; //========================================================================== enum {rearming,ready,charging,maxpower} gunstate; int guncount; //========================================================================== void SpawnPlayer (fixed gx, fixed gy); void GetRefugee (objtype *hit); void CheckFire (void); void DamagePlayer (void); void Thrust (void); void Reverse (void); void AfterBurn (void); void PlayerThink (void); void SpawnShot (fixed gx, fixed gy, int angle, classtype class); void ExplodeShot(void); int ClipPointMove (void); void ShotThink (void); void InertThink (void); void ExplodeThink (void); void SpawnWarp (fixed gx, fixed gy); void WarpThink (void); void SpawnRefugee (fixed gx, fixed gy,int sex); void KillRefugee (objtype *hit); void RefugeeThink (void); void SpawnDrone (fixed gx, fixed gy); void KillDrone (objtype *hit); void DroneThink (void); void SpawnTank (fixed gx, fixed gy); void KillTank (objtype *hit); void AimAtPlayer (void); void TankThink (void); void SpawnMutant (fixed gx, fixed gy); void KillMutant (objtype *hit); int Walk (void); void ChaseThing (objtype *chase); void MutantThink (void); void SpawnShield (fixed gx, fixed gy); void ShieldThink (void); /* ============================================================================= PLAYER ============================================================================= */ /* =================== = = SpawnPlayer = =================== */ void SpawnPlayer (fixed gx, fixed gy) { objlist[0].x = gx; objlist[0].y = gy; objlist[0].angle = 0; objlist[0].think = PlayerThink; objlist[0].class = playerobj; objlist[0].size = MINDIST; objlist[0].radarcolor = 15; objlist[0].hitpoints = 3; objlist[0].xl = objlist[0].x - objlist[0].size; objlist[0].xh = objlist[0].x + objlist[0].size; objlist[0].yl = objlist[0].y - objlist[0].size; objlist[0].yh = objlist[0].y + objlist[0].size; gunstate = ready; } /* =================== = = GetRefugee = =================== */ void GetRefugee (objtype *hit) { PlaySound (SAVEHOSTAGESND); hit->class = nothing; if (hit->radarx) XPlot (hit->radarx,hit->radary,hit->radarcolor); DrawPic (2*savedcount+1,6,SAVEDGUYPIC); savedcount++; if (!--numrefugees) { PlaySound (LASTHOSTAGESND); SpawnWarp (warpx,warpy); } } /* =================== = = CheckFire = =================== */ void CheckFire (void) { if (gunstate == rearming) { if ( (guncount+=tics) > GUNARM) { gunstate = ready; PlaySound(GUNREADYSND); DrawPic (14,40,READYPIC); } return; } if (c.button1) { // holding down button if (gunstate==ready) { gunstate = charging; DrawPic (14,40,CHARGINGPIC); guncount = 0; } if ( gunstate == charging && (guncount+=tics) > GUNCHARGE) { PlaySound(MAXPOWERSND); gunstate = maxpower; DrawPic (14,40,MAXPOWERPIC); } } else // button up if (gunstate>ready) // fire small shot if charging, large if maxed { DrawPic (14,40,REARMINGPIC); guncount = 0; SpawnShot (obon.x,obon.y,obon.angle,pshotobj+(gunstate-charging)); gunstate = rearming; PlaySound (FIRESND); } } /* =================== = = DamagePlayer = =================== */ void DamagePlayer (void) { PlaySound (TAKEDAMAGESND); if (!godmode && !--objlist[0].hitpoints) { PlaySound(PLAYERDEADSND); while (SoundPlaying()) ; leveldone = -1; // all hit points gone } else DrawPic (24,36,SHIELDLOWPIC+1-objlist[0].hitpoints); ColorBorder(12); bordertime = 60; } void HealPlayer (void) { PlaySound (ARMORUPSND); if (objlist[0].hitpoints<3) objlist[0].hitpoints++; DrawPic (24,36,SHIELDLOWPIC+1-objlist[0].hitpoints); ColorBorder(9); bordertime = 60; } /* =================== = = Thrust = =================== */ void Thrust (void) { xmove = FixedByFrac(PLAYERTHRUST*tics,costable[obon.angle]); ymove = FixedByFrac(PLAYERTHRUST*tics,sintable[obon.angle])^SIGNBIT; ClipMove(); } /* =================== = = Reverse = =================== */ void Reverse (void) { xmove = FixedByFrac(PLAYERREVERSE*tics,costable[obon.angle])^SIGNBIT; ymove = FixedByFrac(PLAYERREVERSE*tics,sintable[obon.angle]); ClipMove(); } /* =================== = = AfterBurn = =================== */ void AfterBurn (void) { xmove = FixedByFrac(PLAYERAFTERBURN*tics,costable[obon.angle]); ymove = FixedByFrac(PLAYERAFTERBURN*tics,sintable[obon.angle])^SIGNBIT; ClipMove(); if (!SoundPlaying()) PlaySound(AFTERBURNSND); } void BeforeBurn (void) { xmove = FixedByFrac(PLAYERAFTERBURN*tics,costable[obon.angle]^SIGNBIT); ymove = FixedByFrac(PLAYERAFTERBURN*tics,sintable[obon.angle]); ClipMove(); if (!SoundPlaying()) PlaySound(AFTERBURNSND); } /* =================== = = PlayerThink = =================== */ void PlayerThink (void) { int anglechange; objtype *check; if (c.button1) // hold down fire for slow adjust { if (tics<=4) { anglechange = ANGLESTEP*tics/2; if (!anglechange) anglechange=1; } else anglechange = ANGLESTEP*2; } else anglechange = ANGLESTEP*tics; if (c.dir==west || c.dir==northwest || c.dir==southwest) { obon.angle+=anglechange; if ( obon.angle >= ANGLES ) obon.angle -= ANGLES; } else if (c.dir==east || c.dir==northeast || c.dir==southeast) { obon.angle-=anglechange; if ( obon.angle < 0) obon.angle += ANGLES; } if (c.button2 && (c.dir==south || c.dir==southeast || c.dir==southwest) ) BeforeBurn(); else if (c.button2) AfterBurn(); else if (c.dir==north || c.dir==northeast || c.dir==northwest) Thrust(); else if (c.dir==south || c.dir==southeast || c.dir==southwest) Reverse(); CheckFire (); for (check = &objlist[1];check<=lastobj;check++) if (check->class && check->xl <= obon.xh && check->xh >= obon.xl && check->yl <= obon.yh && check->yh >= obon.yl) { switch (check->class) { case refugeeobj: GetRefugee (check); break; case shieldobj: objlist[0] = obon; HealPlayer (); obon = objlist[0]; check->class = nothing; if (check->radarx) XPlot (check->radarx,check->radary,check->radarcolor); break; case warpobj: leveldone = 1; break; } } StartView(); // calculate view position and trace walls // FinishView in PlayLoop draws everything } /* ============================================================================= SHOTS ============================================================================= */ /* ==================== = = SpawnShot = ==================== */ void SpawnShot (fixed gx, fixed gy, int angle, classtype class) { FindFreeObj(); new->x = gx; new->y = gy; new->angle = angle; new->think = ShotThink; new->class = class; new->size = TILEGLOBAL/8; switch (class) { case pshotobj: new->shapenum = PSHOTPIC; new->speed = SHOTSPEED; break; case pbigshotobj: new->shapenum = BIGSHOTPIC; new->speed = SHOTSPEED; break; case mshotobj: new->shapenum = MSHOTPIC; new->speed = MSHOTSPEED; break; } CalcBoundsNew(); } /* =================== = = ExplodeShot = =================== */ void ExplodeShot(void) { PlaySound (SHOOTWALLSND); obon.class = inertobj; obon.shapenum = obon.temp1 = SHOTDIE1PIC; obon.think = ExplodeThink; obon.stage = 0; TransformObon(); } /* ==================== = = ClipPointMove = ==================== */ #define SHOTCLIP 0x1000 // explode 1/16th tile from wall int ClipPointMove (void) { int xt,yt; long xclipdist,yclipdist,intersect,basex,basey; unsigned inside,total; xmove = FixedByFrac(obon.speed*tics,costable[obon.angle]); if (xmove<0) xmove=-(xmove^SIGNBIT); ymove = FixedByFrac(obon.speed*tics,sintable[obon.angle])^SIGNBIT; if (ymove<0) ymove=-(ymove^SIGNBIT); obon.x += xmove; obon.y += ymove; xt = obon.x>>TILESHIFT; yt = obon.y>>TILESHIFT; if (!tilemap[xt][yt]) return 0; // // intersect the path with the tile edges to determine point of impact // basex = obon.x & 0xffff0000; basey = obon.y & 0xffff0000; obon.x &= 0xffff; // move origin to ul corner of tile obon.y &= 0xffff; if (xmove>0) { inside = obon.x; total = xmove; intersect = obon.y - ymove*inside/total; if (intersect <= TILEGLOBAL) { obon.x = basex - SHOTCLIP; obon.y = basey + intersect; return 1; } } else if (xmove<0) { inside = TILEGLOBAL-obon.x; total = -xmove; intersect = obon.y - ymove*inside/total; if (intersect <= TILEGLOBAL) { obon.x = basex + TILEGLOBAL + SHOTCLIP; obon.y = basey + intersect; return 1; } } if (ymove>0) { inside = obon.y; total = ymove; intersect = obon.x - xmove*inside/total; if (intersect <= TILEGLOBAL) { obon.x = basex + intersect; obon.y = basey - SHOTCLIP; return 1; } } else if (ymove < 0) { inside = TILEGLOBAL-obon.y; total = -ymove; intersect = obon.x - xmove*inside/total; if (intersect <= TILEGLOBAL) { obon.x = basex + intersect; obon.y = basey + TILEGLOBAL + SHOTCLIP; return 1; } } return 1; } /* =================== = = ShotThink = =================== */ void ShotThink (void) { int i,xt,yt; objtype *check; for (i=0;i<3;i++) // so it can move over one tile distance { if (ClipPointMove()) { ExplodeShot(); return; } CalcBounds(); for (check = &objlist[0];check<=lastobj;check++) if (check->class && check->xl <= obon.xh && check->xh >= obon.xl && check->yl <= obon.yh && check->yh >= obon.yl) { switch (check->class) { case playerobj: if (obon.class == mshotobj) { DamagePlayer (); obon.class = nothing; return; } break; case refugeeobj: KillRefugee (check); if (obon.class == pbigshotobj) break; obon.class = nothing; return; case mutantobj: KillMutant (check); if (obon.class == pbigshotobj) break; obon.class = nothing; return; case tankobj: if (obon.class != mshotobj) { KillTank (check); if (obon.class == pbigshotobj) break; obon.class = nothing; return; } break; case droneobj: KillDrone (check); if (obon.class == pbigshotobj) break; obon.class = nothing; return; } } } TransformObon(); } /* ================== = = InertThink = = Corpses, etc... = ================== */ void InertThink (void) { TransformObon(); } /* =================== = = ExplodeThink = =================== */ void ExplodeThink (void) { obon.ticcount+=tics; if (obon.ticcount>EXPLODEANM) { obon.ticcount -= EXPLODEANM; if (++obon.stage == 5) { if (obon.temp1 == SHOTDIE1PIC) // shopt explosions go away obon.class = nothing; else obon.think = InertThink; return; } obon.shapenum = obon.temp1 + obon.stage; } TransformObon(); } /* ============================================================================= WARP GATE ============================================================================= */ /* ================== = = SpawnWarp = ================== */ void SpawnWarp (fixed gx, fixed gy) { FindFreeObj(); new->x = gx; new->y = gy; new->angle = 0; new->think = WarpThink; new->class = warpobj; new->size = MINDIST; new->radarcolor = 14; new->shapenum = WARP1PIC; CalcBoundsNew(); } /* =================== = = WarpThink = =================== */ void WarpThink (void) { obon.ticcount+=tics; if (obon.ticcount>WARPANM) { obon.ticcount -= WARPANM; if (++obon.stage == 4) obon.stage = 0; obon.shapenum = WARP1PIC + obon.stage; } TransformObon(); } /* ============================================================================= REFUGEE ============================================================================= */ /* ================== = = SpawnRefugee = = obon.temp2 is true if a drone is seeking it = ================== */ void SpawnRefugee (fixed gx, fixed gy,int sex) { numrefugees++; FindFreeObj(); new->x = gx; new->y = gy; new->angle = 0; new->think = RefugeeThink; new->class = refugeeobj; new->size = TILEGLOBAL/3; new->radarcolor = 15; if (sex) { new->shapenum = MAN1PIC; new->temp1 = MAN1PIC; } else { new->shapenum = WOMAN1PIC; new->temp1 = WOMAN1PIC; } new->temp2 = 0; new->ticcount = Rnd(REFUGEEANM*3); CalcBoundsNew(); } /* =================== = = KillRefugee = =================== */ void KillRefugee (objtype *hit) { PlaySound (HOSTAGEDEADSND); if (hit->radarx) XPlot (hit->radarx,hit->radary,hit->radarcolor); killedcount++; DrawPic (2*(totalrefugees-killedcount)+1,6,DEADGUYPIC); if (!--numrefugees) { PlaySound (WARPGATESND); SpawnWarp (warpx,warpy); } hit->radarcolor = 0; hit->class = inertobj; if (hit->temp1 == MAN1PIC) hit->shapenum = hit->temp1 = MANDIE1PIC; else hit->shapenum = hit->temp1 = WOMANDIE1PIC; hit->think = ExplodeThink; hit->stage = hit->ticcount = 0; } /* =================== = = RefugeeThink = =================== */ void RefugeeThink (void) { obon.ticcount+=tics; if (obon.ticcount>REFUGEEANM) { obon.ticcount -= REFUGEEANM; if (++obon.stage == 2) obon.stage = 0; obon.shapenum = obon.temp1 + obon.stage; } TransformObon(); } /* ============================================================================= DRONE ============================================================================= */ /* ================== = = SpawnDrone = = obon.temp1 is a pointer to the refugee the drone is currently seeking = ================== */ void SpawnDrone (fixed gx, fixed gy) { FindFreeObj(); new->x = gx; new->y = gy; new->angle = 0; new->think = DroneThink; new->class = droneobj; new->size = MINDIST; new->radarcolor = 10; new->hitpoints = 2; new->shapenum = DRONE1PIC; new->ticcount = Rnd(DRONEANM*3); new->temp1 = (int)new; // will hunt first think CalcBoundsNew(); } /* =================== = = KillDrone = =================== */ void KillDrone (objtype *hit) { PlaySound (SHOOTTHINGSND); if (hit->radarx) XPlot (hit->radarx,hit->radary,hit->radarcolor); hit->radarcolor = 0; hit->class = inertobj; hit->shapenum = hit->temp1 = DRONEDIE1PIC; hit->think = ExplodeThink; hit->stage = hit->ticcount = 0; } /* ================== = = DroneLockOn = ================== */ void DroneLockOn (void) { objtype *check; for (check=&objlist[2];checkclass == refugeeobj && !check->temp2) { check->temp2++; obon.temp1 = (int)check; return; } obon.temp1 = (int)&objlist[0]; // go after player last } /* =================== = = DroneThink = =================== */ void DroneThink (void) { if ( ((objtype *)obon.temp1)->class != refugeeobj && ((objtype *)obon.temp1)->class != playerobj) DroneLockOn (); // target died obon.ticcount+=tics; if (obon.ticcount>DRONEANM) { obon.ticcount -= DRONEANM; if (++obon.stage == 4) obon.stage = 0; obon.shapenum = DRONE1PIC + obon.stage; } ChaseThing ((objtype *)obon.temp1); CalcBounds (); TransformObon(); for (check = &objlist[0];check<=lastobj;check++) if (check->class && check->xl <= obon.xh && check->xh >= obon.xl && check->yl <= obon.yh && check->yh >= obon.yl) { switch (check->class) { case playerobj: // kill player and blow up DamagePlayer (); PlaySound (SHOOTTHINGSND); if (obon.radarx) XPlot (obon.radarx,obon.radary,obon.radarcolor); obon.radarcolor = 0; obon.class = inertobj; obon.shapenum = obon.temp1 = DRONEDIE1PIC; obon.think = ExplodeThink; obon.stage = obon.ticcount = 0; return; case refugeeobj: KillRefugee (check); break; } } } /* ============================================================================= TANK ============================================================================= */ /* ================== = = SpawnTank = ================== */ void SpawnTank (fixed gx, fixed gy) { FindFreeObj(); new->x = gx; new->y = gy; new->angle = 0; new->think = TankThink; new->class = tankobj; new->size = MINDIST; new->shapenum = TANK1PIC; new->radarcolor = 13; new->hitpoints = 3; CalcBoundsNew(); } /* =================== = = KillTank = =================== */ void KillTank (objtype *hit) { PlaySound (SHOOTTHINGSND); if (hit->radarx) XPlot (hit->radarx,hit->radary,hit->radarcolor); hit->radarcolor = 0; hit->class = inertobj; hit->shapenum = hit->temp1 = TANKDIE1PIC; hit->think = ExplodeThink; hit->stage = hit->ticcount = 0; } /* ====================== = = AimAtPlayer = = Hunt for player = ====================== */ void AimAtPlayer (void) { long deltax,deltay; int i,xstep,ystep,tx,ty,steps; dirtype d[3],tdir, olddir, turnaround; olddir=obon.dir; turnaround=opposite[olddir]; deltax=objlist[0].x-obon.x; deltay=objlist[0].y-obon.y; d[1]=nodir; d[2]=nodir; if (deltax>MINCHASE) d[1]= east; else if (deltax<-MINCHASE) d[1]= west; if (deltay>MINCHASE) d[2]=south; else if (deltay<-MINCHASE) d[2]=north; if (LABS(deltay)MINCHASE) { xstep = 1; steps = ((objlist[0].x - obon.x)>>TILESHIFT)-1; obon.angle = 0; } else if (deltax<-MINCHASE) { xstep = -1; steps = ((obon.x - objlist[0].x)>>TILESHIFT)-1; obon.angle = 180; } if (deltay>MINCHASE) { ystep = 1; steps = ((objlist[0].y - obon.y)>>TILESHIFT)-1; obon.angle = 270; } else if (deltay<-MINCHASE) { ystep = -1; steps = ((obon.y - objlist[0].y)>>TILESHIFT)-1; obon.angle = 90; } tx = obon.x >> TILESHIFT; ty = obon.y >> TILESHIFT; for (i=0;i128) /*randomly determine direction of search*/ { for (tdir=north;tdir<=west;tdir+=2) if (tdir!=turnaround) { obon.dir=tdir; if (Walk()) return; } } else { for (tdir=west;tdir>=north;tdir-=2) if (tdir!=turnaround) { obon.dir=tdir; if (Walk()) return; } } obon.dir=turnaround; Walk(); // last chance, don't worry about returned value } /* =================== = = TankThink = =================== */ void TankThink (void) { if (obon.stage == 1) // just fired? { if ( (obon.ticcount += tics) >= TANKRELOAD) obon.stage = 0; } AimAtPlayer (); TransformObon(); } /* ============================================================================= MUTANT ============================================================================= */ /* ================== = = SpawnMutant = ================== */ void SpawnMutant (fixed gx, fixed gy) { FindFreeObj(); new->x = gx; new->y = gy; new->angle = 0; new->think = MutantThink; new->class = mutantobj; new->size = MINDIST; new->shapenum = MUTANT1PIC; new->radarcolor = 12; new->hitpoints = 1; new->ticcount = Rnd(MUTANTANM*3); CalcBoundsNew(); } /* =================== = = KillMutant = =================== */ void KillMutant (objtype *hit) { PlaySound (SHOOTTHINGSND); if (hit->radarx) XPlot (hit->radarx,hit->radary,hit->radarcolor); hit->radarcolor = 0; hit->class = inertobj; hit->shapenum = hit->temp1 = MUTANTDIE1PIC; hit->think = ExplodeThink; hit->stage = hit->ticcount = 0; } /* ====================== = = Walk = = Returns true if a movement of obon.dir/obon.speed is ok or causes = an attack at player = ====================== */ #define WALLZONE (2*TILEGLOBAL/3) int Walk (void) { int xmove,ymove,xl,yl,xh,yh,xt,yt; switch (obon.dir) { case north: xmove = 0; ymove = -SPDMUTANT; break; case east: xmove = SPDMUTANT; ymove = 0; break; case south: xmove = 0; ymove = SPDMUTANT; break; case west: xmove = -SPDMUTANT; ymove = 0; break; default: Quit ("Walk: Bad dir!"); } obon.x += xmove; obon.y += ymove; // // calculate a hit rect to stay away from walls in // obon.xl = obon.x - WALLZONE; obon.xh = obon.x + WALLZONE; obon.yl = obon.y - WALLZONE; obon.yh = obon.y + WALLZONE; // // tile coordinate edges // xt = obon.x>>TILESHIFT; yt = obon.y>>TILESHIFT; xl = obon.xl>>TILESHIFT; yl = obon.yl>>TILESHIFT; xh = obon.xh>>TILESHIFT; yh = obon.yh>>TILESHIFT; // // check corners // if (tilemap[xl][yl] || tilemap[xh][yl] || tilemap[xl][yh] || tilemap[xh][yh] || tilemap[xt][yh] || tilemap[xt][yl] || tilemap[xl][yt] || tilemap[xh][yt] ) { obon.x -= xmove; obon.y -= ymove; return 0; } // // check contact with player // return 1; } /* ====================== = = ChaseThing = = Hunt for player = ====================== */ void ChaseThing (objtype *chase) { long deltax,deltay; int i; dirtype d[3],tdir, olddir, turnaround; olddir=obon.dir; turnaround=opposite[olddir]; deltax=chase->x-obon.x; deltay=chase->y-obon.y; d[1]=nodir; d[2]=nodir; if (deltax>MINCHASE) d[1]= east; else if (deltax<-MINCHASE) d[1]= west; if (deltay>MINCHASE) d[2]=south; else if (deltay<-MINCHASE) d[2]=north; if (LABS(deltay)>LABS(deltax)) { tdir=d[1]; d[1]=d[2]; d[2]=tdir; } if (d[1]==turnaround) d[1]=nodir; if (d[2]==turnaround) d[2]=nodir; if (d[1]!=nodir) { obon.dir=d[1]; if (Walk()) { if (d[2]!=nodir) { obon.dir=d[2]; Walk(); // try to go diagonal if possible } return; } } if (d[2]!=nodir) { obon.dir=d[2]; if (Walk()) return; } /* there is no direct path to the player, so pick another direction */ obon.dir=olddir; if (Walk()) return; if (RndT()>128) /*randomly determine direction of search*/ { for (tdir=north;tdir<=west;tdir+=2) if (tdir!=turnaround) { obon.dir=tdir; if (Walk()) return; } } else { for (tdir=west;tdir>=north;tdir-=2) if (tdir!=turnaround) { obon.dir=tdir; if (Walk()) return; } } obon.dir=turnaround; Walk(); // last chance, don't worry about returned value } /* =================== = = MutantThink = =================== */ #define ATTACKZONE (TILEGLOBAL) void MutantThink (void) { obon.ticcount += tics; if (obon.stage==4) // attack stage { if (obon.ticcount < MUTANTATTACK) { TransformObon(); return; } obon.ticcount = MUTANTANM+1-tics; obon.stage = 0; } if (obon.ticcount>MUTANTANM) { obon.ticcount -= MUTANTANM; if (++obon.stage == 4) obon.stage = 0; obon.shapenum = MUTANT1PIC + obon.stage; } if (objlist[0].xl <= obon.x + ATTACKZONE && objlist[0].xh >= obon.x - ATTACKZONE && objlist[0].yl <= obon.y + ATTACKZONE && objlist[0].yh >= obon.y - ATTACKZONE) { obon.stage = 4; obon.ticcount = 0; obon.shapenum = MUTANTHITPIC; DamagePlayer(); } else ChaseThing(&objlist[0]); CalcBounds (); TransformObon(); } /* ============================================================================= SHIELD ============================================================================= */ /* ================== = = SpawnShield = ================== */ void SpawnShield (fixed gx, fixed gy) { FindFreeObj(); new->x = gx; new->y = gy; new->angle = 0; new->think = ShieldThink; new->class = shieldobj; new->size = MINDIST; new->shapenum = SHIELD1PIC; new->radarcolor = 9; new->hitpoints = 3; CalcBoundsNew(); } /* =================== = = ShieldThink = =================== */ void ShieldThink (void) { obon.ticcount += tics; if (obon.ticcount>SHIELDANM) { obon.ticcount -= SHIELDANM; if (++obon.stage == 2) obon.stage = 0; obon.shapenum = SHIELD1PIC + obon.stage; } TransformObon(); }