2020-10-02 20:22:46 +00:00
|
|
|
#include "ns.h"
|
|
|
|
#include "wh.h"
|
|
|
|
|
|
|
|
BEGIN_WH_NS
|
|
|
|
|
|
|
|
static void checkexpl(PLAYER& plr, short i);
|
|
|
|
|
|
|
|
|
|
|
|
static void chase(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
spr.lotag -= TICSPERFRAME;
|
|
|
|
if (spr.lotag < 0)
|
|
|
|
spr.lotag = 250;
|
|
|
|
|
|
|
|
short osectnum = spr.sectnum;
|
2020-10-02 20:26:24 +00:00
|
|
|
if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tileHeight(spr.picnum) << 7),
|
2020-10-02 20:22:46 +00:00
|
|
|
spr.sectnum) && plr.invisibletime < 0) {
|
|
|
|
if (checkdist(plr, i)) {
|
|
|
|
if (plr.shadowtime > 0) {
|
|
|
|
spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047);
|
|
|
|
newstatus(i, FLEE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
newstatus(i, ATTACK);
|
|
|
|
}
|
|
|
|
else if (krand() % 63 > 60) {
|
|
|
|
spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047);
|
|
|
|
newstatus(i, FLEE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int movestat = aimove(i);
|
|
|
|
|
|
|
|
if ((movestat & kHitTypeMask) == kHitSprite) {
|
|
|
|
if ((movestat & kHitIndexMask) != plr.spritenum) {
|
|
|
|
short daang = (short)((spr.ang - 256) & 2047);
|
|
|
|
spr.ang = daang;
|
|
|
|
if (plr.shadowtime > 0) {
|
|
|
|
spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047);
|
|
|
|
newstatus(i, FLEE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
newstatus(i, SKIRMISH);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047);
|
|
|
|
newstatus(i, SKIRMISH);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047);
|
|
|
|
newstatus(i, FLEE);
|
|
|
|
}
|
|
|
|
|
|
|
|
getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0);
|
|
|
|
if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10))
|
|
|
|
warpsprite(i);
|
|
|
|
|
|
|
|
if (checksector6(i))
|
|
|
|
return;
|
|
|
|
|
|
|
|
processfluid(i, zr_florhit, false);
|
|
|
|
|
|
|
|
if (sector[osectnum].lotag == KILLSECTOR) {
|
|
|
|
spr.hitag--;
|
|
|
|
if (spr.hitag < 0)
|
|
|
|
newstatus(i, DIE);
|
|
|
|
}
|
|
|
|
|
|
|
|
setsprite(i, spr.x, spr.y, spr.z);
|
|
|
|
|
|
|
|
if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA
|
|
|
|
|| sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) {
|
|
|
|
spr.hitag--;
|
|
|
|
if (spr.hitag < 0)
|
|
|
|
newstatus(i, DIE);
|
|
|
|
}
|
|
|
|
|
|
|
|
checkexpl(plr, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void skirmish(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
|
|
|
|
spr.lotag -= TICSPERFRAME;
|
|
|
|
|
|
|
|
if (spr.lotag < 0)
|
|
|
|
newstatus(i, FACE);
|
|
|
|
short osectnum = spr.sectnum;
|
|
|
|
if (aimove(i) != 0) {
|
|
|
|
spr.ang = getangle(plr.x - spr.x, plr.y - spr.y);
|
|
|
|
newstatus(i, FACE);
|
|
|
|
}
|
|
|
|
if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10))
|
|
|
|
warpsprite(i);
|
|
|
|
|
|
|
|
processfluid(i, zr_florhit, false);
|
|
|
|
|
|
|
|
setsprite(i, spr.x, spr.y, spr.z);
|
|
|
|
|
|
|
|
if (checksector6(i))
|
|
|
|
return;
|
|
|
|
|
|
|
|
checkexpl(plr, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void die(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
spr.lotag -= TICSPERFRAME;
|
|
|
|
|
|
|
|
if (spr.lotag <= 0) {
|
|
|
|
spr.picnum++;
|
|
|
|
spr.lotag = 20;
|
|
|
|
|
|
|
|
if (spr.picnum == FREDDEAD) {
|
|
|
|
if (difficulty == 4)
|
|
|
|
newstatus(i, RESURECT);
|
|
|
|
else {
|
|
|
|
kills++;
|
|
|
|
newstatus(i, DEAD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void search(PLAYER& plr, short i) {
|
|
|
|
aisearch(plr, i, false);
|
|
|
|
if (!checksector6(i))
|
|
|
|
checkexpl(plr, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void frozen(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
|
|
|
|
spr.lotag -= TICSPERFRAME;
|
|
|
|
if (spr.lotag < 0) {
|
|
|
|
spr.pal = 0;
|
|
|
|
spr.picnum = FRED;
|
|
|
|
newstatus(i, FACE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void face(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
|
|
|
|
|
2020-10-02 20:26:24 +00:00
|
|
|
boolean cansee = ::cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tileHeight(spr.picnum) << 7),
|
2020-10-02 20:22:46 +00:00
|
|
|
spr.sectnum);
|
|
|
|
|
|
|
|
if (cansee && plr.invisibletime < 0) {
|
|
|
|
spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047);
|
|
|
|
|
|
|
|
if (plr.shadowtime > 0) {
|
|
|
|
spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047);
|
|
|
|
newstatus(i, FLEE);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
spr.owner = plr.spritenum;
|
|
|
|
newstatus(i, CHASE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { // get off the wall
|
|
|
|
if (spr.owner == plr.spritenum) {
|
|
|
|
spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047);
|
|
|
|
newstatus(i, FINDME);
|
|
|
|
}
|
|
|
|
else if (cansee) newstatus(i, FLEE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (checkdist(plr, i))
|
|
|
|
newstatus(i, ATTACK);
|
|
|
|
|
|
|
|
checkexpl(plr, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void attack(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
|
|
|
|
getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0);
|
|
|
|
spr.z = zr_florz;
|
|
|
|
|
|
|
|
switch (checkfluid(i, zr_florhit)) {
|
|
|
|
case TYPELAVA:
|
|
|
|
sprite[i].hitag--;
|
|
|
|
if (sprite[i].hitag < 0)
|
|
|
|
newstatus(i, DIE);
|
|
|
|
case TYPEWATER:
|
2020-10-02 20:26:24 +00:00
|
|
|
spr.z += tileHeight(spr.picnum) << 5;
|
2020-10-02 20:22:46 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
setsprite(i, spr.x, spr.y, spr.z);
|
|
|
|
|
|
|
|
if (spr.lotag >= 64) {
|
|
|
|
if (checksight(plr, i))
|
|
|
|
if (checkdist(plr, i)) {
|
|
|
|
spr.ang = (short)checksight_ang;
|
|
|
|
attack(plr, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (spr.lotag < 0) {
|
|
|
|
if (plr.shadowtime > 0) {
|
|
|
|
spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW
|
|
|
|
newstatus(i, FLEE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
newstatus(i, CHASE);
|
|
|
|
}
|
|
|
|
spr.lotag -= TICSPERFRAME;
|
|
|
|
|
|
|
|
checksector6(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void flee(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
spr.lotag -= TICSPERFRAME;
|
|
|
|
short osectnum = spr.sectnum;
|
|
|
|
|
|
|
|
int movestat = aimove(i);
|
|
|
|
|
|
|
|
if (movestat != 0) {
|
|
|
|
if ((movestat & kHitTypeMask) == kHitWall) {
|
|
|
|
int nWall = movestat & kHitIndexMask;
|
|
|
|
int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4;
|
|
|
|
int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4;
|
|
|
|
spr.ang = getangle(nx, ny);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
spr.ang = getangle(plr.x - spr.x, plr.y - spr.y);
|
|
|
|
newstatus(i, FACE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (spr.lotag < 0)
|
|
|
|
newstatus(i, FACE);
|
|
|
|
|
|
|
|
if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10))
|
|
|
|
warpsprite(i);
|
|
|
|
|
|
|
|
if (checksector6(i))
|
|
|
|
return;
|
|
|
|
|
|
|
|
processfluid(i, zr_florhit, false);
|
|
|
|
|
|
|
|
setsprite(i, spr.x, spr.y, spr.z);
|
|
|
|
|
|
|
|
checkexpl(plr, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pain(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
spr.lotag -= TICSPERFRAME;
|
|
|
|
if (spr.lotag < 0) {
|
|
|
|
spr.picnum = FRED;
|
|
|
|
spr.ang = (short)plr.ang;
|
|
|
|
newstatus(i, FLEE);
|
|
|
|
}
|
|
|
|
|
|
|
|
aimove(i);
|
|
|
|
processfluid(i, zr_florhit, false);
|
|
|
|
setsprite(i, spr.x, spr.y, spr.z);
|
|
|
|
|
|
|
|
checkexpl(plr, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void resurect(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
|
|
|
|
spr.lotag -= TICSPERFRAME;
|
|
|
|
if (spr.lotag < 0) {
|
|
|
|
newstatus(i, FACE);
|
|
|
|
spr.picnum = FRED;
|
|
|
|
spr.hitag = (short)adjusthp(40);
|
|
|
|
spr.lotag = 100;
|
|
|
|
spr.cstat |= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void checkexpl(PLAYER& plr, short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
short j = headspritesect[spr.sectnum];
|
|
|
|
while (j != -1) {
|
|
|
|
short nextj = nextspritesect[j];
|
2020-10-02 20:26:24 +00:00
|
|
|
int dx = abs(spr.x - sprite[j].x); // x distance to sprite
|
|
|
|
int dy = abs(spr.y - sprite[j].y); // y distance to sprite
|
|
|
|
int dz = abs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite
|
|
|
|
int dh = tileHeight(sprite[j].picnum) >> 1; // height of sprite
|
2020-10-02 20:22:46 +00:00
|
|
|
if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) {
|
|
|
|
if (sprite[j].picnum == EXPLO2
|
|
|
|
|| sprite[j].picnum == SMOKEFX
|
|
|
|
|| sprite[j].picnum == MONSTERBALL) {
|
|
|
|
spr.hitag -= TICSPERFRAME << 2;
|
|
|
|
if (spr.hitag < 0) {
|
|
|
|
newstatus(i, DIE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
j = nextj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void createFredAI() {
|
|
|
|
auto &e = enemy[FREDTYPE];
|
|
|
|
e.info.Init(48, 48, 1024 + 256, 120, 0, 64, false, 40, 0);
|
|
|
|
e.chase = chase;
|
|
|
|
e.skirmish = skirmish;
|
|
|
|
e.die = die;
|
|
|
|
e.search = search;
|
|
|
|
e.frozen = frozen;
|
|
|
|
e.face = face;
|
|
|
|
e.attack = attack;
|
|
|
|
e.flee = flee;
|
|
|
|
e.pain = pain;
|
|
|
|
e.resurect = resurect;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void premapFred(short i) {
|
|
|
|
SPRITE& spr = sprite[i];
|
|
|
|
if (spr.picnum == FRED && spr.pal == 1) {
|
|
|
|
deletesprite(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
spr.detail = FREDTYPE;
|
|
|
|
changespritestat(i, FACE);
|
|
|
|
enemy[FREDTYPE].info.set(spr);
|
|
|
|
|
|
|
|
if (krand() % 100 > 50)
|
|
|
|
spr.extra = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
END_WH_NS
|