greed/CODE/SPRITES.C
2014-12-12 00:00:00 +00:00

2250 lines
61 KiB
C

/**************************************************************************/
/* */
/* */
/* Raven 3D Engine */
/* Copyright (C) 1996 by Softdisk Publishing */
/* */
/* Original Design: */
/* John Carmack of id Software */
/* */
/* Enhancements by: */
/* Robert Morgan of Channel 7............................Main Engine Code */
/* Todd Lewis of Softdisk Publishing......Tools,Utilities,Special Effects */
/* John Bianca of Softdisk Publishing..............Low-level Optimization */
/* Carlos Hasan..........................................Music/Sound Code */
/* */
/* */
/***************************************************************************/
#include <DOS.H>
#include <STDIO.H>
#include <STDLIB.H>
#include <MATH.H>
#include <TIME.H>
#include "d_disk.h"
#include "d_global.h"
#include "r_refdef.h"
#include "d_ints.h"
#include "protos.h"
#include "d_misc.h"
/**** VARIABLES ****/
scaleobj_t *msprite, probe;
boolean spritehit, playerhit;
fixed_t hitx, hity, targx, targy, targz;
int spriteloc; // where did it hit on a sprite
/**** FUNCTIONS ****/
boolean SP_TryDoor (fixed_t xcenter, fixed_t ycenter)
{
int xl, yl, xh, yh, x, y;
doorobj_t *door_p, *last_p;
if (msprite==&probe) return true;
// These values will probably have to be tweaked for doors that are along
// the vertical opposite axis (northwall)
xl = (int)((xcenter-msprite->movesize) >> FRACTILESHIFT);
yl = (int)((ycenter-msprite->movesize/* - (TILEUNIT >> 1)*/) >> FRACTILESHIFT);
xh = (int)((xcenter+msprite->movesize) >> FRACTILESHIFT);
yh = (int)((ycenter+msprite->movesize/* - (TILEUNIT >> 1)*/) >> FRACTILESHIFT);
// check for doors on the north wall
for (y=yl+1;y<=yh;y++)
for (x=xl;x<=xh;x++)
{
if (mapflags[y*MAPSIZE+x] & FL_DOOR) // if tile has a door
{
last_p=&doorlist[numdoors];
for (door_p=doorlist;door_p!=last_p;door_p++)
if (door_p->tilex==x && door_p->tiley==y && (door_p->orientation==dr_horizontal || door_p->orientation==dr_horizontal2))
{
if (door_p->doorOpen && !door_p->doorClosing) return true; // can move, door is open
else if (!door_p->doorOpen && door_p->doorBumpable && !door_p->doorOpening)
{
door_p->doorOpening=true;
door_p->doorClosing=false;
SoundEffect(SN_DOOR,15,door_p->tilex<<FRACTILESHIFT,door_p->tiley<<FRACTILESHIFT);
door_p->doorTimer+=20;
if (door_p->orientation==dr_horizontal) SP_TryDoor(xcenter+64*FRACUNIT,ycenter);
else SP_TryDoor(xcenter-64*FRACUNIT,ycenter);
return false;
}
else if (!door_p->doorOpen && door_p->doorBumpable && door_p->doorClosing)
{
door_p->doorClosing=false;
door_p->doorOpening=true;
SoundEffect(SN_DOOR,15,door_p->tilex<<FRACTILESHIFT,door_p->tiley<<FRACTILESHIFT);
door_p->doorTimer+=20;
if (door_p->orientation==dr_horizontal) SP_TryDoor(xcenter+64*FRACUNIT,ycenter);
else SP_TryDoor(xcenter-64*FRACUNIT,ycenter);
return false;
}
else return false;
}
}
}
// check for doors on the west wall
xl = (int)((xcenter-msprite->movesize/* - (TILEUNIT >> 1)*/) >> FRACTILESHIFT);
yl = (int)((ycenter-msprite->movesize) >> FRACTILESHIFT);
xh = (int)((xcenter+msprite->movesize/* - (TILEUNIT >> 1)*/) >> FRACTILESHIFT);
yh = (int)((ycenter+msprite->movesize) >> FRACTILESHIFT);
for (y=yl;y<=yh;y++)
for (x=xl+1;x<=xh;x++)
{
if (mapflags[y*MAPSIZE+x] & FL_DOOR) // if tile has a door
{
last_p=&doorlist[numdoors];
for (door_p=doorlist; door_p != last_p; door_p++)
if (door_p->tilex==x && door_p->tiley==y && (door_p->orientation==dr_vertical || door_p->orientation==dr_vertical2))
{
if (door_p->doorOpen && !door_p->doorClosing) return true; // can move, door is open
else if (!door_p->doorOpen && door_p->doorBumpable && !door_p->doorOpening)
{
door_p->doorOpening=true;
door_p->doorClosing=false;
SoundEffect(SN_DOOR,15,door_p->tilex<<FRACTILESHIFT,door_p->tiley<<FRACTILESHIFT);
door_p->doorTimer+=20;
if (door_p->orientation==dr_vertical) SP_TryDoor(xcenter,ycenter+64*FRACUNIT);
else SP_TryDoor(xcenter,ycenter-64*FRACUNIT);
return false;
}
else if (!door_p->doorOpen && door_p->doorBumpable && door_p->doorClosing)
{
door_p->doorClosing=false;
door_p->doorOpening=true;
SoundEffect(SN_DOOR,15,door_p->tilex<<FRACTILESHIFT,door_p->tiley<<FRACTILESHIFT);
door_p->doorTimer+=20;
if (door_p->orientation==dr_vertical) SP_TryDoor(xcenter,ycenter+64*FRACUNIT);
else SP_TryDoor(xcenter,ycenter-64*FRACUNIT);
return false;
}
else return false;
}
}
}
return true;
}
int SP_TryMove(fixed_t xcenter, fixed_t ycenter)
{
int xl, yl, xh, yh, x, y, mapspot;
xl = (int)((xcenter-msprite->movesize) >> FRACTILESHIFT);
yl = (int)((ycenter-msprite->movesize) >> FRACTILESHIFT);
xh = (int)((xcenter+msprite->movesize) >> FRACTILESHIFT);
yh = (int)((ycenter+msprite->movesize) >> FRACTILESHIFT);
for (y=yl;y<=yh;y++)
for (x=xl;x<=xh;x++)
{
mapspot=MAPCOLS*y+x;
if ((y>yl && northwall[mapspot] && !(northflags[mapspot] & F_NOCLIP) &&
!(northflags[mapspot] & F_NOBULLETCLIP)) ||
(x>xl && westwall[mapspot] && !(westflags[mapspot] & F_NOCLIP) &&
!(westflags[mapspot] & F_NOBULLETCLIP))) return 2; // wall hit
if (msprite!=&probe)
{
if (msprite->z<RF_GetFloorZ((x<<FRACTILESHIFT)+(32<<FRACBITS),(y<<FRACTILESHIFT)+(32<<FRACBITS))) return 2; // below floor
if (msprite->z>RF_GetCeilingZ((x<<FRACTILESHIFT)+(32<<FRACBITS),(y<<FRACTILESHIFT)+(32<<FRACBITS))) return 2; // below ceiling
}
if (mapsprites[mapspot]==64) return 2; // instawall
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128 && mapspot!=msprite->startspot)
{
spritehit=true;
spriteloc=mapspot;
return 1;
}
if (mapspot==player.mapspot && mapspot!=msprite->startspot && msprite->spawnid!=playernum) // can't shot yourself
{
playerhit=true;
return 1;
}
}
return 0;
}
byte SP_ClipMove(fixed_t xmove,fixed_t ymove,fixed_t zmove)
{
int result;
fixed_t dx, dy;
dx=msprite->x+xmove;
dy=msprite->y+ymove;
spritehit=false;
result=SP_TryMove(dx,dy);
if (result)
{
hitx=dx;
hity=dy;
}
if (result!=2 && !SP_TryDoor(dx,dy)) result=2; // door hit or wall hit
if (result!=2)
{
msprite->x+=xmove;
msprite->y+=ymove;
msprite->z+=zmove;
}
return result;
}
byte SP_Thrust()
{
msprite->angle&=ANGLES;
msprite->angle2&=ANGLES;
return SP_ClipMove(costable[msprite->angle],-sintable[msprite->angle],sintable[msprite->angle2]);
}
boolean SP_TryMove2(int angle,fixed_t xcenter, fixed_t ycenter,int smapspot)
{
int xl, yl, xh, yh, x, y, mapspot;
fixed_t sz, sz2, floorz, ceilingz;
if (angle<NORTH || angle>SOUTH)
{
xl=xcenter>>FRACTILESHIFT;
xh=(xcenter+msprite->movesize) >> FRACTILESHIFT;
}
else if (angle>NORTH && angle<SOUTH)
{
xh=xcenter>>FRACTILESHIFT;
xl=(xcenter-msprite->movesize) >> FRACTILESHIFT;
}
else
{
xl=(xcenter-msprite->movesize) >> FRACTILESHIFT;
xh=(xcenter+msprite->movesize) >> FRACTILESHIFT;
}
if (angle>WEST)
{
yl=ycenter>>FRACTILESHIFT;
yh=(ycenter+msprite->movesize) >> FRACTILESHIFT;
}
else if (angle<WEST && angle!=EAST)
{
yl=(ycenter-msprite->movesize) >> FRACTILESHIFT;
yh=ycenter>>FRACTILESHIFT;
}
else
{
yl=(ycenter-msprite->movesize) >> FRACTILESHIFT;
yh=(ycenter+msprite->movesize) >> FRACTILESHIFT;
}
sz = msprite->z - msprite->zadj + (20<<FRACBITS);
sz2 = msprite->z - msprite->zadj;
for (y=yl;y<=yh;y++)
for (x=xl;x<=xh;x++)
{
mapspot=MAPCOLS*y+x;
if (mapspot==player.mapspot ||
(y>yl && northwall[mapspot] && !(northflags[mapspot] & F_NOCLIP)) ||
(x>xl && westwall[mapspot] && !(westflags[mapspot] & F_NOCLIP)))
return false; // wall hit
floorz=RF_GetFloorZ((x<<FRACTILESHIFT)+(32<<FRACBITS),(y<<FRACTILESHIFT)+(32<<FRACBITS));
if (floorz>sz)
return false;
if (msprite->nofalling && floorz+(5<<FRACBITS)<sz2)
return false;
ceilingz=RF_GetCeilingZ((x<<FRACTILESHIFT)+(32<<FRACBITS),(y<<FRACTILESHIFT)+(32<<FRACBITS));
if (ceilingz<msprite->z+msprite->height)
return false;
if (ceilingz-floorz<msprite->height)
return false;
if (mapspot!=smapspot && mapsprites[mapspot])
return false;
}
return true;
}
byte SP_ClipMove2(fixed_t xmove, fixed_t ymove)
{
fixed_t dx, dy;
int smapspot, angle2, ms;
if (msprite->type==S_CLONE) ms=SM_CLONE;
else ms=1;
dx=msprite->x+xmove;
dy=msprite->y+ymove;
smapspot=(msprite->y>>FRACTILESHIFT)*MAPCOLS+(msprite->x>>FRACTILESHIFT);
if (SP_TryMove2(msprite->angle,dx,dy,smapspot) && SP_TryDoor(dx,dy))
{
if (floorpic[(dy>>FRACTILESHIFT)*MAPCOLS+(dx>>FRACTILESHIFT)]==0) return 0;
mapsprites[smapspot]=0;
msprite->x+=xmove;
msprite->y+=ymove;
mapsprites[(msprite->y>>FRACTILESHIFT)*MAPCOLS+(msprite->x>>FRACTILESHIFT)]=ms;
return 1;
}
// the move goes into a wall, so try and move along one axis
if (xmove>0)
{
angle2=EAST;
dx=msprite->x+msprite->moveSpeed;
}
else
{
angle2=WEST;
dx=msprite->x-msprite->moveSpeed;
}
if (SP_TryMove2(angle2,dx,msprite->y,smapspot) && SP_TryDoor(dx,msprite->y))
{
if (floorpic[(msprite->y>>FRACTILESHIFT)*MAPCOLS+(dx>>FRACTILESHIFT)]==0) return 0;
mapsprites[smapspot]=0;
msprite->x+=xmove;
mapsprites[(msprite->y>>FRACTILESHIFT)*MAPCOLS+(msprite->x>>FRACTILESHIFT)]=ms;
return 2;
}
if (ymove>0)
{
angle2=SOUTH;
dy=msprite->y+msprite->moveSpeed;
}
else
{
angle2=NORTH;
dy=msprite->y-msprite->moveSpeed;
}
if (SP_TryMove2(angle2,msprite->x,dy,smapspot) && SP_TryDoor(msprite->x,dy))
{
if (floorpic[(dy>>FRACTILESHIFT)*MAPCOLS+(msprite->x>>FRACTILESHIFT)]==0) return 0;
mapsprites[smapspot]=0;
msprite->y+=ymove;
mapsprites[(msprite->y>>FRACTILESHIFT)*MAPCOLS+(msprite->x>>FRACTILESHIFT)]=ms;
return 3;
}
return 0;
}
byte SP_Thrust2()
{
fixed_t xmove, ymove;
msprite->angle&=ANGLES;
xmove=FIXEDMUL(msprite->moveSpeed,costable[msprite->angle]);
ymove=-FIXEDMUL(msprite->moveSpeed,sintable[msprite->angle]);
return SP_ClipMove2(xmove,ymove);
}
void ActivationSound(scaleobj_t *sp)
{
switch (sp->type)
{
case S_MONSTER1:
SoundEffect(SN_MON1_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER2:
SoundEffect(SN_MON2_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER3:
SoundEffect(SN_MON3_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER4:
SoundEffect(SN_MON4_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER5:
SoundEffect(SN_MON5_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER6:
SoundEffect(SN_MON6_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER7:
SoundEffect(SN_MON7_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER8:
SoundEffect(SN_MON8_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER9:
SoundEffect(SN_MON9_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER10:
SoundEffect(SN_MON10_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER11:
SoundEffect(SN_MON11_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER12:
SoundEffect(SN_MON12_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER13:
SoundEffect(SN_MON13_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER14:
SoundEffect(SN_MON14_WAKE,7,sp->x,sp->y);
break;
case S_MONSTER15:
SoundEffect(SN_MON15_WAKE,7,sp->x,sp->y);
break;
}
}
void ActivateSprites(int sx,int sy)
/* proximity activation (recursive chain reaction) */
{
scaleobj_t *sp;
int x, y;
for(sp=firstscaleobj.next;sp!=&lastscaleobj;sp=sp->next)
if (sp->active==false && sp->moveSpeed)
{
x=sp->x>>FRACTILESHIFT;
y=sp->y>>FRACTILESHIFT;
if (abs(x-sx)<5 && abs(y-sy)<5)
{
sp->active=true;
sp->actiontime=timecount+40;
ActivationSound(sp);
ActivationSound(sp);
ActivateSprites(x,y);
}
}
}
void ShowWallPuff()
{
int i;
switch (msprite->type)
{
case S_BULLET3:
case S_BULLET12:
case S_BULLET17:
case S_MONSTERBULLET2:
case S_MONSTERBULLET4:
case S_MONSTERBULLET6:
case S_MONSTERBULLET8:
case S_GRENADEBULLET:
i=S_SMALLEXPLODE;
break;
case S_BULLET4:
case S_MONSTERBULLET5:
case S_MONSTERBULLET11:
i=S_PLASMAWALLPUFF;
break;
case S_HANDBULLET:
case S_BLOODSPLAT:
case S_BULLET7:
case S_MONSTERBULLET7:
case S_MONSTERBULLET10:
case S_MONSTERBULLET12:
case S_MONSTERBULLET15:
case S_SOULBULLET:
return;
case S_BULLET9:
i=S_ARROWPUFF;
break;
case S_BULLET10:
case S_BULLET18:
i=S_GREENPUFF;
break;
case S_MINEBULLET:
i=S_MINEPUFF;
break;
default:
i=S_WALLPUFF;
}
SpawnSprite(i,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
ActivateSprites(msprite->x>>FRACTILESHIFT,msprite->y>>FRACTILESHIFT);
}
void HitSprite(scaleobj_t *sp)
{
switch (sp->type)
{
case S_CLONE:
if (!sp->active)
{
ActivateSprites((int)(sp->x>>FRACTILESHIFT),(int)(sp->y>>FRACTILESHIFT));
sp->active=true;
}
sp->modetime=timecount+8;
sp->basepic=sp->startpic+32;
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
if (msprite->type!=S_BULLET17)
{
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
}
break;
case S_MONSTER1:
case S_MONSTER2:
case S_MONSTER7:
case S_MONSTER9:
case S_MONSTER10:
case S_MONSTER12:
case S_MONSTER13:
case S_MONSTER14:
case S_MONSTER15:
if (!sp->active)
{
ActivateSprites((int)(sp->x>>FRACTILESHIFT),(int)(sp->y>>FRACTILESHIFT));
sp->active=true;
}
sp->modetime=timecount+8;
sp->basepic=sp->startpic+40;
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
if (msprite->type!=S_BULLET17)
{
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
}
break;
case S_MONSTER3:
case S_MONSTER4:
case S_MONSTER5:
case S_MONSTER6:
case S_MONSTER8:
case S_MONSTER11:
ShowWallPuff();
break;
}
}
boolean Int0(void)
/* control of bullets, explosions, and other objects (not monsters!!) */
{
scaleobj_t *hsprite, *sp;
int counter, mapspot, result, angle, angleinc, i, oldfall;
int oldangle, oldmovespeed;
boolean killed, blood;
counter=0;
killed=false;
if (msprite->type==S_GRENADE) msprite->angle2-=4;
else if ((msprite->type==S_BLOODSPLAT || msprite->type==S_METALPARTS) && (msprite->angle2<NORTH || msprite->angle2>SOUTH))
msprite->angle2-=32;
if (msprite->maxmove)
{
--msprite->maxmove;
if (msprite->maxmove<=0)
{
ShowWallPuff();
return true;
}
}
if (msprite->type==S_MONSTERBULLET4 || msprite->type==S_MONSTERBULLET6 || msprite->type==S_BULLET17)
SpawnSprite(S_WALLPUFF,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
blood=false;
while (counter++<msprite->moveSpeed)
{
result=SP_Thrust();
if (msprite->type==S_BULLET3)
msprite->z=RF_GetFloorZ(msprite->x,msprite->y)+(20<<FRACBITS);
if (result!=0)
{
if (msprite->type==S_BLOODSPLAT)
{
if (result==2) return true;
spritehit=false;
playerhit=false;
}
else if (msprite->type==S_METALPARTS && result==2)
{
playerhit=false;
return true;
}
if (spritehit)
{
if (mapsprites[spriteloc]==SM_NETPLAYER)
{
for(hsprite=firstscaleobj.next;hsprite!=&lastscaleobj;hsprite=hsprite->next)
if (hsprite!=msprite)
{
mapspot=(hsprite->y>>FRACTILESHIFT)*MAPCOLS+(hsprite->x>>FRACTILESHIFT);
if (mapspot==spriteloc)
{
if (msprite->z<hsprite->z || msprite->z>hsprite->z+hsprite->height || hsprite->type!=S_NETPLAYER) break;
{
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
// if (msprite->type!=S_BULLET17)
// {
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
SpawnSprite(S_BLOODSPLAT,msprite->x,msprite->y,msprite->z,msprite->zadj,0,0,false,0);
blood=true;
killed=true;
// }
}
}
}
}
else
for(hsprite=firstscaleobj.next;hsprite!=&lastscaleobj;hsprite=hsprite->next)
if (hsprite!=msprite)
{
mapspot=(hsprite->y>>FRACTILESHIFT)*MAPCOLS+(hsprite->x>>FRACTILESHIFT);
if (mapspot==spriteloc)
{
if (msprite->z<hsprite->z || msprite->z>hsprite->z+hsprite->height) continue;
if (hsprite->hitpoints)
{
if (hsprite->type!=S_MONSTER5)
hsprite->actiontime+=15;
else
hsprite->actiontime+=5;
hsprite->hitpoints-=msprite->damage;
if (msprite->spawnid==255) hsprite->enraged++;
if (msprite->type==S_SOULBULLET && msprite->spawnid==playernum)
{
heal(msprite->damage/2);
medpaks(msprite->damage/2);
}
killed=true;
if (hsprite->hitpoints<=0)
{
if (msprite->spawnid==playernum || msprite->spawnid-200==playernum)
{
++player.bodycount;
addscore(hsprite->score);
}
mapsprites[spriteloc]=0;
blood=true;
HitSprite(hsprite);
KillSprite(hsprite,msprite->type);
}
else if (msprite->damage)
{
oldangle=hsprite->angle;
oldmovespeed=hsprite->moveSpeed;
hsprite->angle=msprite->angle;
hsprite->moveSpeed=(msprite->damage>>2)<<FRACBITS;
sp=msprite;
msprite=hsprite;
oldfall=msprite->nofalling;
msprite->nofalling=0;
SP_Thrust2();
msprite->nofalling=oldfall;
msprite=sp;
hsprite->angle=oldangle;
hsprite->moveSpeed=oldmovespeed;
blood=true;
HitSprite(hsprite);
}
break;
}
}
}
}
else if (playerhit && msprite->z>player.z-player.height && msprite->z<player.z)
{
if (player.angst!=0) // don't keep hitting
{
hurt(msprite->damage);
if (player.angst==0 && netmode) NetDeath(msprite->spawnid);
}
Thrust(msprite->angle,msprite->damage<<(FRACBITS-3));
playerhit=false;
killed=true;
if (msprite->damage>50)
{
player.angle+=-15+(MS_RndT()&31);
player.angle&=ANGLES;
}
}
if (result==2)
killed=true;
if (killed)
{
if (!blood)
ShowWallPuff();
break;
}
}
}
if (killed && msprite->type==S_GRENADE)
{
angleinc=ANGLES/12;
angle=0;
for(i=0,angle=0;i<12;i++,angle+=angleinc)
{
sp=SpawnSprite(S_GRENADEBULLET,msprite->x,msprite->y,msprite->z,20<<FRACBITS,angle,0,true,msprite->spawnid);
sp->maxmove=3;
sp->startspot=-1;
}
angleinc=ANGLES/8;
angle=0;
for(i=0,angle=0;i<8;i++,angle+=angleinc)
{
sp=SpawnSprite(S_GRENADEBULLET,msprite->x,msprite->y,msprite->z,20<<FRACBITS,angle,64,true,msprite->spawnid);
sp->maxmove=2;
sp->startspot=-1;
}
angleinc=ANGLES/8;
angle=0;
for(i=0,angle=0;i<8;i++,angle+=angleinc)
{
sp=SpawnSprite(S_GRENADEBULLET,msprite->x,msprite->y,msprite->z,20<<FRACBITS,angle,-64,true,msprite->spawnid);
sp->maxmove=2;
sp->startspot=-1;
}
sp=SpawnSprite(S_EXPLODE,msprite->x,msprite->y,msprite->z,0,0,0,true,255);
SoundEffect(SN_EXPLODE1+(MS_RndT()&1),15,msprite->x,msprite->y);
}
else if (killed && msprite->type==S_BULLET17)
{
angleinc=ANGLES/8;
angle=0;
for(i=0,angle=0;i<8;i++,angle+=angleinc)
{
sp=SpawnSprite(S_GRENADEBULLET,msprite->x,msprite->y,msprite->z,20<<FRACBITS,angle,0,true,msprite->spawnid);
sp->maxmove=3;
sp->startspot=-1;
}
angleinc=ANGLES/6;
angle=0;
for(i=0,angle=0;i<6;i++,angle+=angleinc)
{
sp=SpawnSprite(S_GRENADEBULLET,msprite->x,msprite->y,msprite->z,20<<FRACBITS,angle,64,true,msprite->spawnid);
sp->maxmove=2;
sp->startspot=-1;
}
angleinc=ANGLES/6;
angle=0;
for(i=0,angle=0;i<6;i++,angle+=angleinc)
{
sp=SpawnSprite(S_GRENADEBULLET,msprite->x,msprite->y,msprite->z,20<<FRACBITS,angle,-64,true,msprite->spawnid);
sp->maxmove=2;
sp->startspot=-1;
}
sp=SpawnSprite(S_EXPLODE,msprite->x,msprite->y,msprite->z,0,0,0,true,255);
SoundEffect(SN_EXPLODE1+(MS_RndT()&1),15,msprite->x,msprite->y);
}
return killed;
}
/***************************************************************************/
int ScanX(int limit1, int x1, int y1, int x2, int y2,int *tx,int *ty)
/* check for the player along the x axis */
{
int mapspot, wall, x, limit, flags;
mapspot=y1*MAPCOLS+x1+1;
x=x1;
limit=limit1;
while (1)
{
if (mapsprites[mapspot]==SM_NETPLAYER || mapsprites[mapspot]==SM_CLONE || (x==x2 && y1==y2))
{
*tx=x+1;
return 2;
}
if (msprite->enraged>=6-player.difficulty && mapsprites[mapspot]==1)
{
*tx=x+1;
*ty=y1;
return 2;
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
wall=westwall[mapspot];
flags=westflags[mapspot];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
++mapspot;
++x;
--limit;
if (!limit) break;
}
limit=limit1;
mapspot=y1*MAPCOLS+x1-1;
x=x1;
while (1)
{
if (mapsprites[mapspot]==SM_NETPLAYER || mapsprites[mapspot]==SM_CLONE || (x==x2 && y1==y2))
{
*tx=x-1;
return 2;
}
if (msprite->enraged>=6-player.difficulty && mapsprites[mapspot]==1)
{
*tx=x-1;
*ty=y1;
return 2;
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) return 1;
wall=westwall[mapspot+1];
flags=westflags[mapspot+1];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) return 0;
--mapspot;
--x;
--limit;
if (!limit) break;
}
return 0;
}
int ScanY(int limit1, int x1, int y1, int x2, int y2,int *tx,int *ty)
/* check for the player along the y axis */
{
int mapspot, wall, y, limit, flags;
limit=limit1;
mapspot=y1*MAPCOLS+x1+MAPCOLS;
y=y1;
while (1)
{
if (mapsprites[mapspot]==SM_NETPLAYER || mapsprites[mapspot]==SM_CLONE || (y==y2 && x1==x2))
{
*ty=y+1;
return 2;
}
if (msprite->enraged>=6-player.difficulty && mapsprites[mapspot]==1)
{
*tx=x1;
*ty=y+1;
return 2;
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
wall=northwall[mapspot];
flags=northflags[mapspot];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
mapspot+=MAPCOLS;
++y;
--limit;
if (!limit) break;
}
limit=limit1;
mapspot=y1*MAPCOLS+x1-MAPCOLS;
y=y1;
while (1)
{
if (mapsprites[mapspot]==SM_NETPLAYER || mapsprites[mapspot]==SM_CLONE || (y==y2 && x1==x2))
{
*ty=y-1;
return 2;
}
if (msprite->enraged>=6-player.difficulty && mapsprites[mapspot]==1)
{
*tx=x1;
*ty=y-1;
return 2;
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
wall=northwall[mapspot+MAPCOLS];
flags=northflags[mapspot+MAPCOLS];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
mapspot-=MAPCOLS;
--y;
--limit;
if (!limit) break;
}
return 0;
}
int ScanAngle(int limit1, int x1, int y1, int x2, int y2,int *tx,int *ty)
/* scan for the player along a 45 degree angle
this is not very accurate!! approximate only */
{
int mapspot, wall, x, y, limit, flags;
limit=limit1;
mapspot=y1*MAPCOLS+x1+MAPCOLS+1;
y=y1;
x=x1;
while (1)
{
wall=northwall[mapspot-1];
flags=northflags[mapspot-1];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
wall=westwall[mapspot-MAPCOLS];
flags=westflags[mapspot-MAPCOLS];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) return 0;
if (mapsprites[mapspot]==SM_NETPLAYER || mapsprites[mapspot]==SM_CLONE || (y==y2 && x==x2))
{
*tx=x+1;
*ty=y+1;
return 2;
}
if (msprite->enraged>=6-player.difficulty && mapsprites[mapspot]==1)
{
*tx=x+1;
*ty=y+1;
return 2;
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
mapspot+=MAPCOLS+1;
++y;
++x;
--limit;
if (!limit) break;
}
limit=limit1;
mapspot=y1*MAPCOLS+x1+MAPCOLS-1;
y=y1;
x=x1;
while (1)
{
wall=northwall[mapspot+1];
flags=northflags[mapspot+1];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
wall=westwall[mapspot-MAPCOLS];
flags=westflags[mapspot-MAPCOLS];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) return 0;
if (mapsprites[mapspot]==SM_NETPLAYER || mapsprites[mapspot]==SM_CLONE || (y==y2 && x==x2))
{
*tx=x-1;
*ty=y+1;
return 2;
}
if (msprite->enraged>=6-player.difficulty && mapsprites[mapspot]==1)
{
*tx=x-1;
*ty=y+1;
return 2;
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
mapspot+=MAPCOLS-1;
++y;
--x;
--limit;
if (!limit) break;
}
limit=limit1;
mapspot=y1*MAPCOLS+x1-MAPCOLS+1;
y=y1;
x=x1;
while (1)
{
wall=northwall[mapspot-1+MAPCOLS];
flags=northflags[mapspot-1+MAPCOLS];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
wall=westwall[mapspot-MAPCOLS];
flags=westflags[mapspot-MAPCOLS];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) return 0;
if (mapsprites[mapspot]==SM_NETPLAYER || mapsprites[mapspot]==SM_CLONE || (y==y2 && x==x2))
{
*tx=x+1;
*ty=y-1;
return 2;
}
if (msprite->enraged>=6-player.difficulty && mapsprites[mapspot]==1)
{
*tx=x+1;
*ty=y-1;
return 2;
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
mapspot-=MAPCOLS+1;
--y;
++x;
--limit;
if (!limit) break;
}
limit=limit1;
mapspot=y1*MAPCOLS+x1-MAPCOLS-1;
y=y1;
x=x1;
while (1)
{
wall=northwall[mapspot+1+MAPCOLS];
flags=northflags[mapspot+1+MAPCOLS];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
wall=westwall[mapspot-MAPCOLS];
flags=westflags[mapspot-MAPCOLS];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) return 0;
if (mapsprites[mapspot]==SM_NETPLAYER || mapsprites[mapspot]==SM_CLONE || (y==y2 && x==x2))
{
*tx=x-1;
*ty=y-1;
return 2;
}
if (msprite->enraged>=6-player.difficulty && mapsprites[mapspot]==1)
{
*tx=x-1;
*ty=y-1;
return 2;
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
mapspot-=MAPCOLS-1;
--y;
--x;
--limit;
if (!limit) break;
}
return 0;
}
/***************************************************************************/
int GetFireAngle(fixed_t sz,int x1,int y1,fixed_t px,fixed_t py,fixed_t pz)
{
scaleobj_t *hsprite;
int x, y, z, d, spriteloc, mapspot;
boolean found;
sz+=msprite->z;
if (x1!=px>>FRACTILESHIFT || y1!=py>>FRACTILESHIFT)
{
spriteloc=y1*MAPCOLS+x1;
found=false;
for(hsprite=firstscaleobj.next;hsprite!=&lastscaleobj;hsprite=hsprite->next)
if (hsprite->hitpoints)
{
mapspot=(hsprite->y>>FRACTILESHIFT)*MAPCOLS+(hsprite->x>>FRACTILESHIFT);
if (mapspot==spriteloc)
{
found=true;
break;
}
}
if (found)
{
px=hsprite->x;
py=hsprite->y;
pz=hsprite->z+(32<<FRACBITS);
}
}
else pz+=20<<FRACBITS;
if (sz>pz)
{
z=(sz-pz)>>(FRACBITS+2);
if (z>=MAXAUTO) return 0;
x=(msprite->x-px)>>(FRACBITS+2);
y=(msprite->y-py)>>(FRACBITS+2);
d=sqrt(x*x + y*y);
if (d>=MAXAUTO || autoangle2[d][z]==-1) return 0;
return -autoangle2[d][z];
}
else if (sz<pz)
{
z=(pz-sz)>>(FRACBITS+2);
if (z>=MAXAUTO) return 0;
x=(msprite->x-px)>>(FRACBITS+2);
y=(msprite->y-py)>>(FRACBITS+2);
d=sqrt(x*x + y*y);
if (d>=MAXAUTO || autoangle2[d][z]==-1) return 0;
return autoangle2[d][z];
}
else return 0;
}
/***************************************************************************/
void Int5(void) // priests / viscount lords
{
int angle, sx, sy, px, py, tx, ty, pangle;
fixed_t floorz, oldspeed, fheight;
sx=msprite->x>>FRACTILESHIFT;
sy=msprite->y>>FRACTILESHIFT;
if (netmode) NetGetClosestPlayer(sx,sy);
else
{
if (specialeffect==SE_INVISIBILITY)
{
targx=0;
targy=0;
targz=0;
}
else
{
targx=player.x;
targy=player.y;
targz=player.z;
}
}
px=targx>>FRACTILESHIFT;
py=targy>>FRACTILESHIFT;
oldspeed=msprite->moveSpeed;
if (abs(px-sx)<6 && abs(py-sy)<6) msprite->moveSpeed=msprite->moveSpeed*2;
if (timecount>msprite->movetime)
{
if (px>sx) angle=EAST;
else if (px<sx) angle=WEST;
else angle=-1;
if (py<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (py>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
angle=angle - DEGREE45 + MS_RndT();
msprite->angle=angle&ANGLES;
msprite->movetime=timecount+140; // 350
}
if (timecount>msprite->firetime && timecount>msprite->scantime)
{
tx=px;
ty=py;
if (ScanX(10,sx,sy,px,py,&tx,&ty)>1 || ScanY(10,sx,sy,px,py,&tx,&ty)>1
|| ScanAngle(10,sx,sy,px,py,&tx,&ty)>1)
{
if (tx>sx) angle=EAST;
else if (tx<sx) angle=WEST;
else angle=-1;
if (ty<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (ty>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
msprite->angle=angle&ANGLES;
msprite->basepic=msprite->startpic+24;
msprite->movemode=4;
msprite->firetime=timecount+(40+5*player.difficulty);
msprite->actiontime=timecount+30;
msprite->modetime=timecount+15;
}
msprite->scantime=timecount+30;
}
if (timecount>msprite->modetime)
{
msprite->modetime=timecount+10;
switch (msprite->movemode)
{
case 0: // left
case 1: // mid
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
++msprite->movemode;
msprite->basepic=msprite->startpic+msprite->movemode*8;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 2: // right
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->basepic=msprite->startpic + 8; // midstep
++msprite->movemode;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 3: // mid #2
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->movemode=0;
msprite->basepic=msprite->startpic;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 4: // fire #1
tx=px;
ty=py;
if (ScanX(10,sx,sy,px,py,&tx,&ty)>1 || ScanY(10,sx,sy,px,py,&tx,&ty)>1
|| ScanAngle(10,sx,sy,px,py,&tx,&ty)>1)
{
if (tx>sx) angle=EAST;
else if (tx<sx) angle=WEST;
else angle=-1;
if (ty<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (ty>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
msprite->angle=angle&ANGLES;
msprite->movemode=5;
msprite->basepic=msprite->startpic+32;
if (msprite->type==S_MONSTER7) fheight=15<<FRACBITS;
else fheight=40<<FRACBITS;
pangle=GetFireAngle(fheight,tx,ty,targx,targy,targz)-15+(MS_RndT()&31);
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle-15+(MS_RndT()&31),pangle,true,255);
msprite->modetime+=8;
}
else
{
msprite->movemode=0;
msprite->basepic=msprite->startpic;
}
break;
case 5: // fire #2
msprite->movemode=0;
msprite->basepic=msprite->startpic;
break;
}
}
if (timecount>msprite->actiontime && SP_Thrust2()!=1)
{
angle=msprite->angle+DEGREE45;
msprite->angle=angle&ANGLES;
}
floorz=RF_GetFloorZ(msprite->x,msprite->y);
if (floorz+msprite->zadj<msprite->z)
msprite->z-=FRACUNIT<<4;
if (floorz+msprite->zadj>msprite->z)
msprite->z=floorz+msprite->zadj;
msprite->moveSpeed=oldspeed;
if (MS_RndT()>=255)
ActivationSound(msprite);
}
/***************************************************************************/
boolean Int6() // intelligence for mines
{
scaleobj_t *sp;
int i, j, angle,angleinc, x, y, sx, sy;
boolean activate;
if (timecount>msprite->actiontime) // now active
{
if (msprite->type==S_TIMEMINE)
{
angleinc=ANGLES/20;
angle=0;
for(i=0,angle=0;i<20;i++,angle+=angleinc)
sp=SpawnSprite(S_MINEBULLET,msprite->x,msprite->y,msprite->z,20<<FRACBITS,angle,0,true,msprite->spawnid);
sp=SpawnSprite(S_EXPLODE,msprite->x,msprite->y,msprite->z,0,0,0,true,255);
SoundEffect(SN_EXPLODE1+(MS_RndT()&1),15,msprite->x,msprite->y);
return true;
}
else if (msprite->type==S_PROXMINE)
{
if (MS_RndT()&1) msprite->angle+=8;
else msprite->angle-=8;
msprite->angle&=ANGLES;
x=msprite->x>>FRACTILESHIFT;
y=msprite->y>>FRACTILESHIFT;
activate=false;
if (abs(x-(player.x>>FRACTILESHIFT))<2 && abs(y-(player.y>>FRACTILESHIFT))<2) activate=true;
if (!activate)
for (sp=firstscaleobj.next;sp!=&lastscaleobj;sp=sp->next)
if (sp->hitpoints)
{
sx=sp->x>>FRACTILESHIFT;
sy=sp->y>>FRACTILESHIFT;
if (abs(x-sx)<2 && abs(y-sy)<2)
{
activate=true;
break;
}
}
for(i=-1;i<2;i++)
for(j=-1;j<2;j++)
if (mapsprites[(i+y)*MAPCOLS+j+x]==SM_NETPLAYER) activate=true;
if (activate)
{
angleinc=ANGLES/16;
angle=0;
for(i=0,angle=0;i<16;i++,angle+=angleinc)
sp=SpawnSprite(S_MINEBULLET,msprite->x,msprite->y,msprite->z,20<<FRACBITS,angle,0,true,msprite->spawnid);
sp=SpawnSprite(S_EXPLODE,msprite->x,msprite->y,msprite->z,0,0,0,true,255);
SoundEffect(SN_EXPLODE1+(MS_RndT()&1),15,msprite->x,msprite->y);
return true;
}
}
else if (msprite->type==S_INSTAWALL)
{
mapsprites[(msprite->y>>FRACTILESHIFT)*MAPCOLS+(msprite->x>>FRACTILESHIFT)]=0;
return true;
}
}
return false;
}
/***************************************************************************/
int CloneScanX(int x,int y,int *x2)
/* check for the target along the x axis */
{
int mapspot, wall, x1, limit, flags;
mapspot=y*MAPCOLS+x+1;
x1=x;
limit=10;
while (1)
{
if (mapsprites[mapspot]==SM_CLONE || mapsprites[mapspot]==1)
{
*x2=x1+1;
return 1+(MS_RndT()&1);
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
wall=westwall[mapspot];
flags=westflags[mapspot];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
++mapspot;
++x1;
--limit;
if (!limit) break;
}
limit=10;
mapspot=y*MAPCOLS+x-1;
x1=x;
while (1)
{
if (mapsprites[mapspot]==SM_CLONE || mapsprites[mapspot]==1)
{
*x2=x1-1;
return 1+(MS_RndT()&1);
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) return 1;
wall=westwall[mapspot+1];
flags=westflags[mapspot+1];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) return 0;
--mapspot;
--x1;
--limit;
if (!limit) break;
}
return 0;
}
int CloneScanY(int x,int y,int *y2)
/* check for the player along the y axis */
{
int mapspot, wall, y1, limit, flags;
limit=10;
mapspot=y*MAPCOLS+x+MAPCOLS;
y1=y;
while (1)
{
if (mapsprites[mapspot]==SM_CLONE || mapsprites[mapspot]==1)
{
*y2=y1+1;
return 1+(MS_RndT()&1);
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
wall=northwall[mapspot];
flags=northflags[mapspot];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
mapspot+=MAPCOLS;
++y1;
--limit;
if (!limit) break;
}
limit=10;
mapspot=y*MAPCOLS+x-MAPCOLS;
y1=y;
while (1)
{
if (mapsprites[mapspot]==SM_CLONE || mapsprites[mapspot]==1)
{
*y2=y1-1;
return 1+(MS_RndT()&1);
}
if (mapsprites[mapspot]>0 && mapsprites[mapspot]<128) break;
wall=northwall[mapspot+MAPCOLS];
flags=northflags[mapspot+MAPCOLS];
if (wall && !(flags & F_NOCLIP) && !(flags & F_NOBULLETCLIP)) break;
mapspot-=MAPCOLS;
--y1;
--limit;
if (!limit) break;
}
return 0;
}
void Int7(void) // clone ai
{
int angle, sx, sy, px, py, pangle, r;
fixed_t floorz, fheight;
sx=msprite->x>>FRACTILESHIFT;
sy=msprite->y>>FRACTILESHIFT;
if (timecount>msprite->movetime)
{
angle=msprite->angle - DEGREE45;
r=MS_RndT()%3;
if (r==1)
angle+=DEGREE45;
else if (r==2)
angle+=NORTH;
msprite->angle=angle&ANGLES;
msprite->movetime=timecount+250;
}
if (timecount>msprite->firetime && timecount>msprite->scantime)
{
px=sx;
py=sy;
if (CloneScanX(sx,sy,&px)>1)
{
if (px>sx) angle=EAST;
else if (px<sx) angle=WEST;
msprite->angle=angle&ANGLES;
msprite->movemode=4;
msprite->basepic=msprite->startpic+24;
fheight=40<<FRACBITS;
pangle=GetFireAngle(fheight,px,py,0,0,0);
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle,pangle,true,255);
msprite->modetime=timecount+8;
msprite->actiontime=timecount+30;
msprite->firetime=timecount+30;
}
else if (CloneScanY(sx,sy,&py)>1)
{
if (py>sy) angle=SOUTH;
else if (py<sy) angle=NORTH;
msprite->angle=angle&ANGLES;
msprite->movemode=4;
msprite->basepic=msprite->startpic+24;
fheight=40<<FRACBITS;
pangle=GetFireAngle(fheight,px,py,0,0,0);
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle,pangle,true,255);
msprite->modetime=timecount+8;
msprite->actiontime=timecount+30;
msprite->firetime=timecount+30;
}
msprite->scantime=timecount+20;
}
if (timecount>msprite->modetime)
{
msprite->modetime=timecount+10;
switch (msprite->movemode)
{
case 0: // left
case 1: // mid
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
++msprite->movemode;
msprite->basepic=msprite->startpic+msprite->movemode*8;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 2: // right
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->basepic=msprite->startpic + 8;
++msprite->movemode;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 3: // mid #2
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->movemode=0;
msprite->basepic=msprite->startpic;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 4: // fire
msprite->movemode=0;
msprite->basepic=msprite->startpic;
break;
}
}
if (timecount>msprite->actiontime && SP_Thrust2()!=1)
{
angle=msprite->angle+DEGREE45;
msprite->angle=angle&ANGLES;
}
floorz=RF_GetFloorZ(msprite->x,msprite->y);
if (floorz+msprite->zadj<msprite->z) msprite->z-=FRACUNIT<<4;
if (floorz+msprite->zadj>msprite->z) msprite->z=floorz+msprite->zadj;
}
/***************************************************************************/
void Int8(void) // prisoners
{
int angle, sx, sy, px, py, tx, ty, pangle;
fixed_t floorz, oldspeed, fheight;
sx=msprite->x>>FRACTILESHIFT;
sy=msprite->y>>FRACTILESHIFT;
if (netmode) NetGetClosestPlayer(sx,sy);
else
{
if (specialeffect==SE_INVISIBILITY)
{
targx=0;
targy=0;
targz=0;
}
else
{
targx=player.x;
targy=player.y;
targz=player.z;
}
}
px=targx>>FRACTILESHIFT;
py=targy>>FRACTILESHIFT;
oldspeed=msprite->moveSpeed;
if (abs(px-sx)<6 && abs(py-sy)<6) msprite->moveSpeed=msprite->moveSpeed*2;
if (timecount>msprite->movetime)
{
if (px>sx) angle=EAST;
else if (px<sx) angle=WEST;
else angle=-1;
if (py<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (py>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
angle=angle - DEGREE45 + MS_RndT();
msprite->angle=angle&ANGLES;
msprite->movetime=timecount+350;
}
if (timecount>msprite->firetime && timecount>msprite->scantime)
{
tx=px;
ty=py;
if (ScanX(7,sx,sy,px,py,&tx,&ty)>1 || ScanY(7,sx,sy,px,py,&tx,&ty)>1
|| ScanAngle(7,sx,sy,px,py,&tx,&ty)>1)
{
if (tx>sx) angle=EAST;
else if (tx<sx) angle=WEST;
else angle=-1;
if (ty<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (ty>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
msprite->angle=angle&ANGLES;
if (abs(tx-sx)>2 || abs(ty-sy)>2)
{
msprite->scantime=timecount+45;
goto endscan;
}
msprite->basepic=msprite->startpic+24;
msprite->movemode=4;
msprite->firetime=timecount+(80+5*player.difficulty);
msprite->actiontime=timecount+30;
msprite->modetime=timecount+15;
}
msprite->scantime=timecount+45;
}
endscan:
if (timecount>msprite->modetime)
{
msprite->modetime=timecount+10;
switch (msprite->movemode)
{
case 0: // left
case 1: // mid
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
++msprite->movemode;
msprite->basepic=msprite->startpic+msprite->movemode*8;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 2: // right
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->basepic=msprite->startpic + 8; // midstep
++msprite->movemode;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 3: // mid #2
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->movemode=0;
msprite->basepic=msprite->startpic;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 4: // fire #1
tx=px;
ty=py;
if (ScanX(7,sx,sy,px,py,&tx,&ty)>1 || ScanY(7,sx,sy,px,py,&tx,&ty)>1
|| ScanAngle(7,sx,sy,px,py,&tx,&ty)>1)
{
if (tx>sx) angle=EAST;
else if (tx<sx) angle=WEST;
else angle=-1;
if (ty<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (ty>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
msprite->angle=angle&ANGLES;
if (abs(tx-sx)>2 || abs(ty-sy)>2)
{
msprite->movemode=0;
msprite->basepic=msprite->startpic;
break;
}
msprite->movemode=5;
msprite->basepic=msprite->startpic+32;
fheight=40<<FRACBITS;
pangle=GetFireAngle(fheight,tx,ty,targx,targy,targz);
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle,pangle,true,255);
msprite->modetime+=8;
}
else
{
msprite->movemode=0;
msprite->basepic=msprite->startpic;
}
break;
case 5: // fire #2
msprite->movemode=0;
msprite->basepic=msprite->startpic;
break;
}
}
if (timecount>msprite->actiontime && SP_Thrust2()!=1)
{
angle=msprite->angle+DEGREE45;
msprite->angle=angle&ANGLES;
}
floorz=RF_GetFloorZ(msprite->x,msprite->y);
if (floorz+msprite->zadj<msprite->z)
msprite->z-=FRACUNIT<<4;
if (floorz+msprite->zadj>msprite->z)
msprite->z=floorz+msprite->zadj;
msprite->moveSpeed=oldspeed;
if (MS_RndT()>=255)
ActivationSound(msprite);
}
/***************************************************************************/
void Int9(void) // big guards only
{
int i, angleinc, angle, sx, sy, px, py, tx, ty, pangle;
fixed_t floorz, oldspeed, fheight;
if (msprite->hitpoints<1000)
msprite->hitpoints+=10;
msprite->enraged=0;
sx=msprite->x>>FRACTILESHIFT;
sy=msprite->y>>FRACTILESHIFT;
if (netmode) NetGetClosestPlayer(sx,sy);
else
{
if (specialeffect==SE_INVISIBILITY)
{
targx=0;
targy=0;
targz=0;
}
else
{
targx=player.x;
targy=player.y;
targz=player.z;
}
}
px=targx>>FRACTILESHIFT;
py=targy>>FRACTILESHIFT;
oldspeed=msprite->moveSpeed;
if (abs(px-sx)<6 && abs(py-sy)<6) msprite->moveSpeed=msprite->moveSpeed*2;
if (timecount>msprite->movetime)
{
if (px>sx) angle=EAST;
else if (px<sx) angle=WEST;
else angle=-1;
if (py<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (py>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
angle=angle - DEGREE45 + MS_RndT();
msprite->angle=angle&ANGLES;
msprite->movetime=timecount+200;
}
if (timecount>msprite->firetime && timecount>msprite->scantime)
{
SoundEffect(SN_MON11_WAKE,7,msprite->x,msprite->y);
tx=px;
ty=py;
if (ScanX(8,sx,sy,px,py,&tx,&ty)>1 || ScanY(8,sx,sy,px,py,&tx,&ty)>1
|| ScanAngle(8,sx,sy,px,py,&tx,&ty)>1)
{
if (tx>sx) angle=EAST;
else if (tx<sx) angle=WEST;
else angle=-1;
if (ty<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (ty>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
msprite->angle=angle&ANGLES;
msprite->basepic=msprite->startpic+24;
msprite->movemode=4;
msprite->firetime=timecount+(120+5*player.difficulty);
msprite->actiontime=timecount+30;
msprite->modetime=timecount+20;
}
msprite->scantime=timecount+45;
}
if (timecount>msprite->modetime)
{
msprite->modetime=timecount+20;
switch (msprite->movemode)
{
case 0: // left
case 1: // mid
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
++msprite->movemode;
msprite->basepic=msprite->startpic+msprite->movemode*8;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
if (MS_RndT()<32)
{
angle=0;
angleinc=ANGLES/16;
for (i=0;i<16;i++,angle+=angleinc)
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,32<<FRACBITS,angle,0,true,255);
SoundEffect(SN_MON11_FIRE,7,msprite->x,msprite->y);
}
break;
case 2: // right
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->basepic=msprite->startpic + 8; // midstep
++msprite->movemode;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
if (MS_RndT()<32)
{
angle=0;
angleinc=ANGLES/16;
for (i=0;i<16;i++,angle+=angleinc)
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,32<<FRACBITS,angle,0,true,255);
SoundEffect(SN_MON11_FIRE,7,msprite->x,msprite->y);
}
break;
case 3: // mid #2
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->movemode=0;
msprite->basepic=msprite->startpic;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
if (MS_RndT()<32)
{
angle=0;
angleinc=ANGLES/16;
for (i=0;i<16;i++,angle+=angleinc)
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,32<<FRACBITS,angle,0,true,255);
SoundEffect(SN_MON11_FIRE,7,msprite->x,msprite->y);
}
break;
case 4: // firing bullets
case 5:
case 6:
case 7:
tx=px;
ty=py;
if (ScanX(8,sx,sy,px,py,&tx,&ty)>1 || ScanY(8,sx,sy,px,py,&tx,&ty)>1
|| ScanAngle(8,sx,sy,px,py,&tx,&ty)>1)
{
if (tx>sx) angle=EAST;
else if (tx<sx) angle=WEST;
else angle=-1;
if (ty<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (ty>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
msprite->angle=angle&ANGLES;
++msprite->movemode;
msprite->basepic=msprite->startpic+32;
fheight=70<<FRACBITS;
if (msprite->movemode==5 && MS_RndT()<32)
{
SpawnSprite(S_GRENADE,msprite->x,msprite->y,msprite->z,fheight,msprite->angle-15+(MS_RndT()&31),0,true,255);
SpawnSprite(S_GRENADE,msprite->x,msprite->y,msprite->z,fheight,msprite->angle+15+(MS_RndT()&31),0,true,255);
SoundEffect(SN_GRENADE,0,msprite->x,msprite->y);
msprite->movemode=0;
msprite->basepic=msprite->startpic;
msprite->firetime=timecount+(120+5*player.difficulty);
msprite->actiontime=timecount+30;
}
else
{
pangle=GetFireAngle(fheight,tx,ty,targx,targy,targz)-15+(MS_RndT()&31);
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle-15+(MS_RndT()&31),pangle,true,255);
SoundEffect(SN_MON11_FIRE,7,msprite->x,msprite->y);
msprite->modetime=timecount+15;
}
}
else
{
msprite->movemode=0;
msprite->basepic=msprite->startpic;
msprite->firetime=timecount+(120+5*player.difficulty);
msprite->actiontime=timecount+30;
}
break;
case 8: // fire #2
msprite->movemode=0;
msprite->basepic=msprite->startpic;
msprite->firetime=timecount+(120+5*player.difficulty);
msprite->actiontime=timecount+30;
break;
}
}
if (timecount>msprite->actiontime && SP_Thrust2()!=1)
{
angle=msprite->angle+DEGREE45;
msprite->angle=angle&ANGLES;
}
floorz=RF_GetFloorZ(msprite->x,msprite->y);
if (floorz+msprite->zadj<msprite->z)
msprite->z-=FRACUNIT<<4;
if (floorz+msprite->zadj>msprite->z)
msprite->z=floorz+msprite->zadj;
msprite->moveSpeed=oldspeed;
if (MS_RndT()>=255)
ActivationSound(msprite);
}
/***************************************************************************/
void Int10(void)
{
int angle, sx, sy, px, py, tx, ty, pangle;
fixed_t floorz, oldspeed, fheight;
if (msprite->type==S_MONSTER5 && msprite->hitpoints<5000)
msprite->hitpoints+=4;
else if (msprite->type==S_MONSTER13 && msprite->hitpoints<300)
{
msprite->hitpoints+=25;
msprite->enraged=0;
}
else if (msprite->type==S_MONSTER15 && msprite->hitpoints<2000)
{
msprite->hitpoints+=6;
msprite->enraged=0;
}
else if (msprite->type==S_MONSTER14 && msprite->hitpoints<350)
msprite->hitpoints+=1;
sx=msprite->x>>FRACTILESHIFT;
sy=msprite->y>>FRACTILESHIFT;
if (netmode) NetGetClosestPlayer(sx,sy);
else
{
if (specialeffect==SE_INVISIBILITY)
{
targx=0;
targy=0;
targz=0;
}
else
{
targx=player.x;
targy=player.y;
targz=player.z;
}
}
px=targx>>FRACTILESHIFT;
py=targy>>FRACTILESHIFT;
oldspeed=msprite->moveSpeed;
if (abs(px-sx)<6 && abs(py-sy)<6) msprite->moveSpeed=msprite->moveSpeed*2;
if (timecount>msprite->movetime)
{
if (px>sx) angle=EAST;
else if (px<sx) angle=WEST;
else angle=-1;
if (py<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (py>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
angle=angle - DEGREE45 + MS_RndT();
msprite->angle=angle&ANGLES;
msprite->movetime=timecount+350;
}
if (timecount>msprite->firetime && timecount>msprite->scantime)
{
tx=px;
ty=py;
if (ScanX(10,sx,sy,px,py,&tx,&ty)>1 || ScanY(10,sx,sy,px,py,&tx,&ty)>1
|| ScanAngle(10,sx,sy,px,py,&tx,&ty)>1)
{
if (tx>sx) angle=EAST;
else if (tx<sx) angle=WEST;
else angle=-1;
if (ty<sy)
{
if (angle==EAST) angle+=DEGREE45;
else if (angle==WEST) angle-=DEGREE45;
else angle=NORTH;
}
else if (ty>sy)
{
if (angle==EAST) angle-=DEGREE45;
else if (angle==WEST) angle+=DEGREE45;
else angle=SOUTH;
}
msprite->angle=angle&ANGLES;
if (msprite->type==S_MONSTER7 && (abs(tx-sx)>2 || abs(ty-sy)>2))
{
msprite->scantime=timecount+30;
goto endscan;
}
if (msprite->type==S_MONSTER15 && (abs(tx-sx)>4 || abs(ty-sy)>4))
{
msprite->scantime=timecount+30;
goto endscan;
}
msprite->basepic=msprite->startpic+32;
msprite->movemode=6;
if (msprite->type==S_MONSTER5)
msprite->firetime=timecount+(10+3*player.difficulty);
else
msprite->firetime=timecount+(40+5*player.difficulty);
msprite->actiontime=timecount+30;
msprite->modetime=timecount+15;
if (msprite->type==S_MONSTER3)
fheight=3<<FRACBITS;
else if (msprite->type==S_MONSTER6)
fheight=100<<FRACBITS;
else
fheight=40<<FRACBITS;
pangle=GetFireAngle(fheight,tx,ty,targx,targy,targz)-15+(MS_RndT()&31);
if (msprite->type==S_MONSTER13 || msprite->type==S_MONSTER6 || msprite->type==S_MONSTER15 || msprite->type==S_MONSTER5)
{
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle-15+(MS_RndT()&31)+16,pangle,true,255);
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle-15+(MS_RndT()&31)-16,pangle,true,255);
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle-15+(MS_RndT()&31),pangle,true,255);
}
else if (msprite->type==S_MONSTER4)
{
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle-15+(MS_RndT()&31)+8,pangle,true,255);
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle-15+(MS_RndT()&31)-8,pangle,true,255);
}
else
SpawnSprite(msprite->bullet,msprite->x,msprite->y,msprite->z,fheight,msprite->angle-15+(MS_RndT()&31),pangle,true,255);
}
msprite->scantime=timecount+30;
}
endscan:
if (timecount>msprite->modetime)
{
msprite->modetime=timecount+8;
switch (msprite->movemode)
{
case 0: // 1
case 1: // 2
case 2: // 3
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
++msprite->movemode;
msprite->basepic=msprite->startpic+msprite->movemode*8;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 3: // 2
case 4: // 1
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->movemode++;
msprite->basepic=msprite->startpic+(6-msprite->movemode)*8;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 5:
if (msprite->lastx!=msprite->x || msprite->lasty!=msprite->y)
{
msprite->movemode=0;
msprite->basepic=msprite->startpic;
msprite->lasty=msprite->y;
msprite->lastx=msprite->x;
}
break;
case 6: // fire
msprite->movemode=0;
msprite->basepic=msprite->startpic;
break;
}
}
if (timecount>msprite->actiontime && SP_Thrust2()!=1)
{
angle=msprite->angle+DEGREE45;
msprite->angle=angle&ANGLES;
}
floorz=RF_GetFloorZ(msprite->x,msprite->y) + msprite->zadj;
if (floorz<msprite->z)
msprite->z-=FRACUNIT<<4;
if (floorz>msprite->z)
msprite->z=floorz;
msprite->moveSpeed=oldspeed;
if (MS_RndT()>=255)
ActivationSound(msprite);
}
/***************************************************************************/
void MoveSprites(void)
{
int mapspot, i, j, c, px, py, sx, sy;
boolean killed;
fixed_t floor;
if (!netmode)
{
targx=player.x;
targy=player.y;
px=targx>>FRACTILESHIFT;
py=targy>>FRACTILESHIFT;
}
for (msprite=firstscaleobj.next;msprite!=&lastscaleobj;msprite=msprite->next)
{
if (msprite->active)
{
if (msprite->moveSpeed)
switch (msprite->intelligence)
{
case 0:
killed=Int0();
if (killed)
{
if (msprite->type==S_BLOODSPLAT)
{
msprite->intelligence=128;
break;
}
else if (msprite->type==S_METALPARTS && !spritehit)
{
killed=false;
continue;
}
msprite=msprite->prev;
RF_RemoveSprite(msprite->next);
killed=false;
continue;
}
break;
case 5:
Int5();
break;
case 6:
killed=Int6();
if (killed)
{
msprite=msprite->prev;
RF_RemoveSprite(msprite->next);
killed=false;
continue;
}
break;
case 7:
Int7();
break;
case 8:
Int8();
break;
case 9:
Int9();
break;
case 10:
Int10();
break;
case 128:
floor=RF_GetFloorZ(msprite->x,msprite->y);
if (msprite->z>floor+FRACUNIT)
msprite->z-=FRACUNIT*2;
if (msprite->z<floor)
msprite->z=floor;
break;
}
if (!killed && msprite->heat)
{
mapspot=(msprite->y>>FRACTILESHIFT)*MAPCOLS+(msprite->x>>FRACTILESHIFT);
if (msprite->heat>256)
{
c=msprite->heat>>1;
for(i=-1;i<2;i++)
for(j=-1;j<2;j++)
reallight[mapspot+(i*MAPCOLS)+j]-=c;
reallight[mapspot]-=msprite->heat>>2;
}
else reallight[mapspot]-=msprite->heat;
}
killed=false;
}
else if (msprite->intelligence!=255)
{
if (msprite->moveSpeed)
{
sx=msprite->x>>FRACTILESHIFT;
sy=msprite->y>>FRACTILESHIFT;
if (netmode)
{
NetGetClosestPlayer(sx,sy);
px=targx>>FRACTILESHIFT;
py=targy>>FRACTILESHIFT;
}
if ((abs(px-sx)<6 && abs(py-sy)<6))
{
msprite->active=true;
ActivateSprites(sx,sy);
}
}
floor=RF_GetFloorZ(msprite->x,msprite->y)+msprite->zadj;
if (msprite->z>floor) msprite->z-=FRACUNIT<<4;
if (msprite->z<floor) msprite->z=floor;
if (msprite->heat)
{
mapspot=(msprite->y>>FRACTILESHIFT)*MAPCOLS+(msprite->x>>FRACTILESHIFT);
if (msprite->heat>256)
{
c=msprite->heat>>1;
for(i=-1;i<2;i++)
for(j=-1;j<2;j++)
reallight[mapspot+(i*MAPCOLS)+j]-=c;
reallight[mapspot]-=msprite->heat>>2;
msprite->heat-=64;
}
else reallight[mapspot]-=msprite->heat;
}
}
}
}