HDB: More cleanup in ai-bots

This commit is contained in:
Strangerke 2019-07-25 16:30:59 +02:00 committed by Eugene Sandulenko
parent 174b8c31cf
commit becfce8bfc

View File

@ -78,7 +78,7 @@ void aiOmniBotAction(AIEntity *e) {
// Shoot player ?
if (onEvenTile(e->x, e->y) && g_hdb->getActionMode()) {
int xv = 0, yv = 0, result;
int shoot = 0;
bool shoot = false;
// FIXME: Is reloading Player required here?
p = g_hdb->_ai->getPlayer();
@ -91,25 +91,25 @@ void aiOmniBotAction(AIEntity *e) {
switch (e->dir) {
case DIR_UP:
if (p->x == e->x && p->y < e->y) {
shoot = 1;
shoot = true;
yv = -1;
}
break;
case DIR_DOWN:
if (p->x == e->x && p->y > e->y) {
shoot = 1;
shoot = true;
yv = 1;
}
break;
case DIR_LEFT:
if (p->x < e->x && p->y == e->y) {
shoot = 1;
shoot = true;
xv = -1;
}
break;
case DIR_RIGHT:
if (p->x > e->x && p->y == e->y) {
shoot = 1;
shoot = true;
xv = 1;
}
break;
@ -118,10 +118,10 @@ void aiOmniBotAction(AIEntity *e) {
break;
}
// If shoot = 1, take the shot
// If shoot = true, take the shot
// (1) Check we're not shooting into a solid tile
// (2) Check we're not shooting into an Entity unless it's the player
AIEntity *hit = g_hdb->_ai->legalMoveOverWater(e->tileX+xv, e->tileY + yv, e->level, &result);
AIEntity *hit = g_hdb->_ai->legalMoveOverWater(e->tileX + xv, e->tileY + yv, e->level, &result);
if (shoot && !hit && result) {
AIEntity *omni = g_hdb->_ai->spawn(AI_OMNIBOT_MISSILE, e->dir, e->tileX + xv, e->tileY + yv, NULL, NULL, NULL, DIR_NONE, e->level, 0, 0, 1);
omni->xVel = xv * kPlayerMoveSpeed * 2;
@ -298,17 +298,16 @@ void aiShockBotAction(AIEntity *e) {
}
void aiShockBotShock(AIEntity *e, int mx, int my) {
int offX[8] = { -1, 0, 1, 1, 1, 0, -1, -1 };
int offY[8] = { -1, -1, -1, 0, 1, 1, 1, 0 };
static const int offX[8] = { -1, 0, 1, 1, 1, 0, -1, -1 };
static const int offY[8] = { -1, -1, -1, 0, 1, 1, 1, 0 };
// Only on a exact tile boundary do we change the shocked tiles
// Start at top left and go around
if (g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY) & kFlagMetal)
e->special1Gfx[e->animFrame]->drawMasked(e->tileX * kTileWidth - mx, e->tileY * kTileHeight - my);
uint32 flags;
for (int i = 0; i < 8; i++) {
flags = g_hdb->_map->getMapBGTileFlags(e->tileX + offX[i], e->tileY + offY[i]);
uint32 flags = g_hdb->_map->getMapBGTileFlags(e->tileX + offX[i], e->tileY + offY[i]);
if (flags & kFlagMetal) {
// Is the shocking tile onScreen?
if (g_hdb->_map->checkXYOnScreen((e->tileX + offX[i]) * kTileWidth, (e->tileY + offY[i]) * kTileHeight)) {
@ -465,10 +464,26 @@ void aiRightBotFindGoal(AIEntity *e) {
}
} else {
switch (e->dir) {
case DIR_UP: e->dir = DIR_DOWN; yv = 1; xv = 0; break;
case DIR_DOWN: e->dir = DIR_UP; yv = -1; xv = 0; break;
case DIR_LEFT: e->dir = DIR_RIGHT; yv = 0; xv = 1; break;
case DIR_RIGHT: e->dir = DIR_LEFT; yv = 0; xv = -1; break;
case DIR_UP:
e->dir = DIR_DOWN;
yv = 1;
xv = 0;
break;
case DIR_DOWN:
e->dir = DIR_UP;
yv = -1;
xv = 0;
break;
case DIR_LEFT:
e->dir = DIR_RIGHT;
yv = 0;
xv = 1;
break;
case DIR_RIGHT:
e->dir = DIR_LEFT;
yv = 0;
xv = -1;
break;
case DIR_NONE:
warning("aiRightBotFindGoal: DIR_NONE found");
}
@ -593,10 +608,18 @@ void aiPushBotAction(AIEntity *e) {
e1->moveSpeed = e->moveSpeed;
g_hdb->_ai->setEntityGoal(e1, nx2, ny2);
switch (e1->type) {
case AI_CRATE: g_hdb->_sound->playSound(SND_CRATE_SLIDE); break;
case AI_HEAVYBARREL: case AI_BOOMBARREL: g_hdb->_sound->playSound(SND_HEAVY_SLIDE); break;
case AI_LIGHTBARREL: g_hdb->_sound->playSound(SND_LIGHT_SLIDE); break;
default: break;
case AI_CRATE:
g_hdb->_sound->playSound(SND_CRATE_SLIDE);
break;
case AI_HEAVYBARREL:
case AI_BOOMBARREL:
g_hdb->_sound->playSound(SND_HEAVY_SLIDE);
break;
case AI_LIGHTBARREL:
g_hdb->_sound->playSound(SND_LIGHT_SLIDE);
break;
default:
break;
}
} else {
if (e->onScreen)
@ -715,12 +738,10 @@ void aiRailRiderOnUse(AIEntity *e) {
g_hdb->_ai->setEntityGoal(p, p->tileX, p->tileY - 1);
else
g_hdb->_ai->setEntityGoal(p, p->tileX, p->tileY + 1);
} else {
if (p->tileX > e->tileX)
g_hdb->_ai->setEntityGoal(p, p->tileX - 1, p->tileY);
else
g_hdb->_ai->setEntityGoal(p, p->tileX + 1, p->tileY);
}
} else if (p->tileX > e->tileX)
g_hdb->_ai->setEntityGoal(p, p->tileX - 1, p->tileY);
else
g_hdb->_ai->setEntityGoal(p, p->tileX + 1, p->tileY);
e->sequence = -1; // Waiting for player to board
}
@ -901,6 +922,9 @@ void aiMaintBotAction(AIEntity *e) {
static const int xvAhead[5] = {9, 0, 0,-1, 1};
static const int yvAhead[5] = {9,-1, 1, 0, 0};
static const int whistles[3] = {SND_MBOT_WHISTLE1, SND_MBOT_WHISTLE2, SND_MBOT_WHISTLE3};
static const AIDir lookRight[5] = {DIR_NONE, DIR_RIGHT, DIR_LEFT, DIR_UP, DIR_DOWN};
static const AIDir lookLeft[5] = {DIR_NONE, DIR_LEFT, DIR_RIGHT, DIR_DOWN, DIR_UP};
static const AIDir dirList[5] = {DIR_NONE, DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT};
// Waiting at an arrow (or hit by player)?
if (e->sequence) {
@ -967,9 +991,6 @@ void aiMaintBotAction(AIEntity *e) {
}
// Deciding where to go at 4-way
else {
AIDir lookRight[5] = {DIR_NONE, DIR_RIGHT, DIR_LEFT, DIR_UP, DIR_DOWN};
AIDir lookLeft[5] = {DIR_NONE, DIR_LEFT, DIR_RIGHT, DIR_DOWN, DIR_UP};
AIDir dirList[5] = {DIR_NONE, DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT};
switch (e->sequence) {
// HMM
case 50:
@ -1057,10 +1078,10 @@ void aiFourFirerInit2(AIEntity *e) {
}
void aiFourFirerAction(AIEntity *e) {
AIEntity *p = g_hdb->_ai->getPlayer();
AIState state[5] = {STATE_NONE, STATE_STANDUP, STATE_STANDDOWN, STATE_STANDLEFT, STATE_STANDRIGHT};
AIDir turn[5] = {DIR_NONE, DIR_RIGHT, DIR_LEFT, DIR_UP, DIR_DOWN};
static const AIState state[5] = {STATE_NONE, STATE_STANDUP, STATE_STANDDOWN, STATE_STANDLEFT, STATE_STANDRIGHT};
static const AIDir turn[5] = {DIR_NONE, DIR_RIGHT, DIR_LEFT, DIR_UP, DIR_DOWN};
AIEntity *p = g_hdb->_ai->getPlayer();
// Time to turn right?
if (!e->value1) {
e->dir = turn[e->dir];
@ -1089,11 +1110,32 @@ void aiFourFirerAction(AIEntity *e) {
int yv = 0;
switch (e->dir) {
case DIR_UP: if (p->x == e->x && p->y < e->y) { shoot = true; yv = -1; } break;
case DIR_DOWN: if (p->x == e->x && p->y > e->y) { shoot = true; yv = 1; } break;
case DIR_LEFT: if (p->y == e->y && p->x < e->x) { shoot = true; xv = -1; } break;
case DIR_RIGHT: if (p->y == e->y && p->x > e->x) { shoot = true; xv = 1; } break;
case DIR_NONE: warning("aiFourFirerAction: DIR_NONE found"); break;
case DIR_UP:
if (p->x == e->x && p->y < e->y) {
shoot = true;
yv = -1; }
break;
case DIR_DOWN:
if (p->x == e->x && p->y > e->y) {
shoot = true;
yv = 1;
}
break;
case DIR_LEFT:
if (p->y == e->y && p->x < e->x) {
shoot = true;
xv = -1;
}
break;
case DIR_RIGHT:
if (p->y == e->y && p->x > e->x) {
shoot = true;
xv = 1;
}
break;
case DIR_NONE:
warning("aiFourFirerAction: DIR_NONE found");
break;
}
// Shoot if needed
@ -1142,9 +1184,7 @@ void aiDeadEyeInit2(AIEntity *e) {
}
void aiDeadEyeWalkInPlace(AIEntity *e) {
AIState state[5] = {STATE_NONE, STATE_MOVEUP, STATE_MOVEDOWN, STATE_MOVELEFT, STATE_MOVERIGHT};
AIDir dir;
AIState s;
static const AIState state[5] = {STATE_NONE, STATE_MOVEUP, STATE_MOVEDOWN, STATE_MOVELEFT, STATE_MOVERIGHT};
e->sequence--;
@ -1154,15 +1194,16 @@ void aiDeadEyeWalkInPlace(AIEntity *e) {
case 30:
case 20:
case 10:
dir = (AIDir)(g_hdb->_rnd->getRandomNumber(3) + 1);
s = state[dir];
e->dir = dir;
e->state = s;
if (e->onScreen) {
if (e->sequence == 50)
g_hdb->_sound->playSound(SND_DEADEYE_AMB01);
else if (e->sequence == 10)
g_hdb->_sound->playSound(SND_DEADEYE_AMB02);
{
int rnd = g_hdb->_rnd->getRandomNumber(3) + 1;
e->dir = (AIDir)rnd;
e->state = state[rnd];
if (e->onScreen) {
if (e->sequence == 50)
g_hdb->_sound->playSound(SND_DEADEYE_AMB01);
else if (e->sequence == 10)
g_hdb->_sound->playSound(SND_DEADEYE_AMB02);
}
}
break;
case 0:
@ -1172,12 +1213,9 @@ void aiDeadEyeWalkInPlace(AIEntity *e) {
}
void aiDeadEyeAction(AIEntity *e) {
AIState state[5] = {STATE_NONE, STATE_MOVEUP, STATE_MOVEDOWN, STATE_MOVELEFT, STATE_MOVERIGHT};
int xvAhead[5] = {9, 0, 0, -1, 1}, yvAhead[5] = {9, -1, 1, 0, 0};
int result;
AIEntity *hit;
AIDir dir;
AIState s;
static const AIState state[5] = {STATE_NONE, STATE_MOVEUP, STATE_MOVEDOWN, STATE_MOVELEFT, STATE_MOVERIGHT};
static const int xvAhead[5] = {9, 0, 0, -1, 1};
static const int yvAhead[5] = {9, -1, 1, 0, 0};
if (e->sequence) {
e->sequence--;
@ -1188,42 +1226,56 @@ void aiDeadEyeAction(AIEntity *e) {
// Is player visible to us?
AIEntity *p = g_hdb->_ai->getPlayer();
if (e->onScreen && p->level == e->level && !e->blinkFrames) {
int nuts = 0;
bool nuts = false;
switch (e->dir) {
case DIR_UP: if (p->tileX == e->tileX && p->tileY < e->tileY) nuts = 1; break;
case DIR_DOWN: if (p->tileX == e->tileX && p->tileY > e->tileY) nuts = 1; break;
case DIR_LEFT: if (p->tileY == e->tileY && p->tileX < e->tileX) nuts = 1; break;
case DIR_RIGHT: if (p->tileY == e->tileY && p->tileX > e->tileX) nuts = 1; break;
case DIR_NONE: warning("aiDeadEyeAction: DIR_NONE found"); break;
case DIR_UP:
if (p->tileX == e->tileX && p->tileY < e->tileY)
nuts = true;
break;
case DIR_DOWN:
if (p->tileX == e->tileX && p->tileY > e->tileY)
nuts = true;
break;
case DIR_LEFT:
if (p->tileY == e->tileY && p->tileX < e->tileX)
nuts = true;
break;
case DIR_RIGHT:
if (p->tileY == e->tileY && p->tileX > e->tileX)
nuts = true;
break;
case DIR_NONE:
warning("aiDeadEyeAction: DIR_NONE found");
break;
}
// Did we see the player (and we're done moving)?
if (nuts && e->aiAction != aiDeadEyeWalkInPlace) {
int newX, newY, xv, yv, done, okToMove;
e->sequence = 0;
e->blinkFrames = 20;
xv = xvAhead[e->dir];
yv = yvAhead[e->dir];
newX = e->tileX + xv;
newY = e->tileY + yv;
int xv = xvAhead[e->dir];
int yv = yvAhead[e->dir];
int newX = e->tileX + xv;
int newY = e->tileY + yv;
okToMove = done = 0;
bool okToMove = false;
bool done = false;
do {
hit = g_hdb->_ai->legalMove(newX, newY, e->level, &result);
int result;
AIEntity *hit = g_hdb->_ai->legalMove(newX, newY, e->level, &result);
if (hit && hit->type == AI_GUY)
hit = NULL;
hit = nullptr;
if (result && !hit) {
okToMove = 1;
okToMove = true;
newX += xv;
newY += yv;
if (newX == p->tileX && newY == p->tileY)
done = 1;
done = true;
} else {
newX -= xv;
newY -= yv;
done = 1;
done = true;
}
} while (!done);
@ -1245,34 +1297,34 @@ void aiDeadEyeAction(AIEntity *e) {
case 30:
case 20:
case 10:
dir = (AIDir)(g_hdb->_rnd->getRandomNumber(3)+1);
s = state[dir];
e->dir = dir;
e->state = s;
{
int dir = g_hdb->_rnd->getRandomNumber(3) + 1;
e->dir = (AIDir)dir;
e->state = state[dir];
if (e->onScreen) {
if (e->sequence == 50)
g_hdb->_sound->playSound(SND_DEADEYE_AMB01);
else if (e->sequence == 10)
g_hdb->_sound->playSound(SND_DEADEYE_AMB02);
if (e->onScreen) {
if (e->sequence == 50)
g_hdb->_sound->playSound(SND_DEADEYE_AMB01);
else if (e->sequence == 10)
g_hdb->_sound->playSound(SND_DEADEYE_AMB02);
}
}
break;
case 0:
// Pick a random direction and random number of tiles in that direction
dir = (AIDir)(g_hdb->_rnd->getRandomNumber(3) + 1);
int dir = g_hdb->_rnd->getRandomNumber(3) + 1;
int walk = g_hdb->_rnd->getRandomNumber(4) + 1;
int xv, yv;
e->dir = dir;
e->dir = (AIDir)dir;
e->state = state[dir];
xv = xvAhead[dir] * walk;
int xv = xvAhead[dir] * walk;
if (e->tileX + xv < 1)
xv = 1 - e->tileX;
if (e->tileX + xv > g_hdb->_map->_width)
xv = g_hdb->_map->_width - e->tileX - 1;
yv = yvAhead[dir] * walk;
int yv = yvAhead[dir] * walk;
if (e->tileY + yv < 1)
yv = 1 - e->tileY;
if (e->tileY + yv > g_hdb->_map->_height)
@ -1281,9 +1333,10 @@ void aiDeadEyeAction(AIEntity *e) {
e->value1 = xvAhead[dir];
e->value2 = yvAhead[dir];
e->moveSpeed = kPlayerMoveSpeed;
hit = g_hdb->_ai->legalMove(e->tileX + xvAhead[e->dir], e->tileY + yvAhead[e->dir], e->level, &result);
int result;
AIEntity *hit = g_hdb->_ai->legalMove(e->tileX + xvAhead[e->dir], e->tileY + yvAhead[e->dir], e->level, &result);
if (hit && hit->type == AI_GUY)
hit = NULL;
hit = nullptr;
if (!hit && result)
g_hdb->_ai->setEntityGoal(e, e->tileX + xv, e->tileY + yv);
@ -1303,9 +1356,10 @@ void aiDeadEyeAction(AIEntity *e) {
// Did we run into a wall, entity, water, slime etc?
// If so, Pick new direction
if (onEvenTile(e->x, e->y)) {
hit = g_hdb->_ai->legalMove(e->tileX + e->value1, e->tileY + e->value2, e->level, &result);
int result;
AIEntity *hit = g_hdb->_ai->legalMove(e->tileX + e->value1, e->tileY + e->value2, e->level, &result);
if (hit && hit->type == AI_GUY)
hit = NULL;
hit = nullptr;
if (!result || hit) {
g_hdb->_ai->stopEntity(e);
e->state = STATE_MOVEDOWN;
@ -1327,15 +1381,15 @@ void aiDeadEyeAction(AIEntity *e) {
void aiLaserInit(AIEntity *e) {
e->aiDraw = aiLaserDraw;
e->value1 = e->value2 = 0; // start & end of laser beam
// start & end of laser beam
e->value1 = e->value2 = 0;
}
void aiLaserInit2(AIEntity *e) {
e->draw = g_hdb->_ai->getStandFrameDir(e);
if (!g_hdb->_ai->_gfxLaserbeamUD[0]) {
char name[64];
int i;
for (i = 0; i < 4; i++) {
for (int i = 0; i < 4; i++) {
sprintf(name, FORCEFIELD_UD"0%d", i + 1);
g_hdb->_ai->_gfxLaserbeamUD[i] = g_hdb->_gfx->loadTile(name);
sprintf(name, FORCESPLASH_TOP"0%d", i + 1);
@ -1353,46 +1407,63 @@ void aiLaserInit2(AIEntity *e) {
}
void aiLaserAction(AIEntity *e) {
int xva[] = {9,0,0,-1,1}, yva[] = {9,-1,1,0,0};
int nx, ny, moveOK;
AIEntity *hit;
static const int xva[] = {9, 0, 0,-1, 1};
static const int yva[] = {9,-1, 1, 0, 0};
hit = e;
AIEntity *hit = e;
int moveOK = 0;
do {
int nx = hit->tileX;
int ny = hit->tileY;
if (hit->type != AI_DIVERTER) {
hit->int1 = xva[hit->dir];
hit->int2 = yva[hit->dir];
nx = hit->tileX;
ny = hit->tileY;
if (hit->dir == DIR_UP || hit->dir == DIR_DOWN)
hit->value1 = ny;
else
hit->value1 = nx;
} else {
nx = hit->tileX;
ny = hit->tileY;
// diverter is on y-plane?
if (hit->tileX == e->tileX) {
hit->value1 = nx;
hit->int2 = 0;
switch (hit->dir2) {
case DIR_UP: hit->int1 = 1; break;
case DIR_DOWN: hit->int1 = -1; break;
case DIR_LEFT: hit->int1 = -1; break;
case DIR_RIGHT: hit->int1 = 1; break;
case DIR_NONE: break;
case DIR_UP:
hit->int1 = 1;
break;
case DIR_DOWN:
hit->int1 = -1;
break;
case DIR_LEFT:
hit->int1 = -1;
break;
case DIR_RIGHT:
hit->int1 = 1;
break;
case DIR_NONE:
break;
}
} else {
// diverter is on x-plane
hit->value1 = ny;
hit->int1 = 0;
switch (hit->dir2) {
case DIR_UP: hit->int2 = 1; break;
case DIR_DOWN: hit->int2 = 1; break;
case DIR_LEFT: hit->int2 = -1; break;
case DIR_RIGHT: hit->int2 = -1; break;
case DIR_NONE: break;
case DIR_UP:
hit->int2 = 1;
break;
case DIR_DOWN:
hit->int2 = 1;
break;
case DIR_LEFT:
hit->int2 = -1;
break;
case DIR_RIGHT:
hit->int2 = -1;
break;
case DIR_NONE:
break;
}
}
}
@ -1414,7 +1485,6 @@ void aiLaserAction(AIEntity *e) {
g_hdb->_ai->killPlayer(DEATH_FRIED);
else if (hit->type == AI_BOOMBARREL && hit->state != STATE_EXPLODING && onEvenTile(hit->x, hit->y)) {
// hit BOOM BARREL = explodes
aiBarrelExplode(hit);
aiBarrelBlowup(hit, nx, ny);
} else if (hit->type == AI_LIGHTBARREL || hit->type == AI_HEAVYBARREL || hit->type == AI_CRATE) {
@ -1425,7 +1495,8 @@ void aiLaserAction(AIEntity *e) {
moveOK = 0;
} else if (onEvenTile(hit->x, hit->y) && hit != g_hdb->_ai->getPlayer()) {
switch (hit->type) {
case AI_VORTEXIAN: // cannot kill Vortexians!
// cannot kill Vortexians!
case AI_VORTEXIAN:
continue;
case AI_BOOMBARREL:
@ -1435,7 +1506,6 @@ void aiLaserAction(AIEntity *e) {
case AI_LASER:
g_hdb->_ai->_laserRescan = true;
break;
case ITEM_KEYCARD_WHITE:
case ITEM_KEYCARD_BLUE:
case ITEM_KEYCARD_RED:
@ -1563,11 +1633,24 @@ void aiDiverterInit2(AIEntity *e) {
if (e->dir2 == DIR_NONE)
d = e->dir;
switch (d) {
case DIR_DOWN: e->state = STATE_DIVERTER_BL; e->draw = e->standdownGfx[0]; break;
case DIR_UP: e->state = STATE_DIVERTER_BR; e->draw = e->standupGfx[0]; break;
case DIR_LEFT: e->state = STATE_DIVERTER_TL; e->draw = e->standleftGfx[0]; break;
case DIR_RIGHT: e->state = STATE_DIVERTER_TR; e->draw = e->standrightGfx[0]; break;
case DIR_NONE: break;
case DIR_DOWN:
e->state = STATE_DIVERTER_BL;
e->draw = e->standdownGfx[0];
break;
case DIR_UP:
e->state = STATE_DIVERTER_BR;
e->draw = e->standupGfx[0];
break;
case DIR_LEFT:
e->state = STATE_DIVERTER_TL;
e->draw = e->standleftGfx[0];
break;
case DIR_RIGHT:
e->state = STATE_DIVERTER_TR;
e->draw = e->standrightGfx[0];
break;
case DIR_NONE:
break;
}
g_hdb->_ai->_laserRescan = true;
@ -1580,22 +1663,35 @@ void aiDiverterAction(AIEntity *e) {
// have to reset the state because we might have been moved...
switch (e->dir2) {
case DIR_DOWN: e->state = STATE_DIVERTER_BL; e->draw = e->standdownGfx[0]; break;
case DIR_UP: e->state = STATE_DIVERTER_BR; e->draw = e->standupGfx[0]; break;
case DIR_LEFT: e->state = STATE_DIVERTER_TL; e->draw = e->standleftGfx[0]; break;
case DIR_RIGHT: e->state = STATE_DIVERTER_TR; e->draw = e->standrightGfx[0]; break;
case DIR_NONE: break;
case DIR_DOWN:
e->state = STATE_DIVERTER_BL;
e->draw = e->standdownGfx[0];
break;
case DIR_UP:
e->state = STATE_DIVERTER_BR;
e->draw = e->standupGfx[0];
break;
case DIR_LEFT:
e->state = STATE_DIVERTER_TL;
e->draw = e->standleftGfx[0];
break;
case DIR_RIGHT:
e->state = STATE_DIVERTER_TR;
e->draw = e->standrightGfx[0];
break;
case DIR_NONE:
break;
}
}
}
void aiDiverterDraw(AIEntity *e, int mx, int my) {
int i;
if (!e->value1 && !e->value2)
return;
int frame = e->movedownFrames & 3;
int onScreen = 0;
int i;
switch (e->dir2) {
case DIR_UP:
if (e->tileY == e->value1 && e->int2) { // going down or right?
@ -1721,6 +1817,9 @@ void aiMeerkatDraw(AIEntity *e, int mx, int my) {
}
void aiMeerkatAction(AIEntity *e) {
static const int gem_xv[] = { 0, 0,-2,-3,-4,-4,-3,-2,-2,-2,-2,-1,-1, 100};
static const int gem_yv[] = {-6,-5,-4,-3,-2,-1, 0, 0, 1, 2, 3, 4, 5, 100};
AIEntity *p = g_hdb->_ai->getPlayer();
switch (e->sequence) {
@ -1787,7 +1886,7 @@ void aiMeerkatAction(AIEntity *e) {
case 5:
g_hdb->_ai->animateEntity(e);
if (!e->animFrame && e->animDelay == e->animCycle) {
e->sequence = 0;;
e->sequence = 0;
e->state = STATE_NONE;
e->draw = NULL;
}
@ -1849,9 +1948,6 @@ void aiMeerkatAction(AIEntity *e) {
// blasting a gem outta Guy?
if (e->value1) {
int gem_xv[] = {0, 0,-2,-3,-4,-4,-3,-2,-2,-2,-2,-1,-1, 100};
int gem_yv[] = {-6,-5,-4,-3,-2,-1, 0, 0, 1, 2, 3, 4, 5, 100};
if (gem_xv[e->blinkFrames] == 100) {
e->value1 = 0;
e->aiDraw = NULL;
@ -2225,9 +2321,10 @@ void aiGoodFairyInit2(AIEntity *e) {
}
void aiGoodFairyAction(AIEntity *e) {
AIState state[5] = {STATE_NONE, STATE_MOVEUP, STATE_MOVEDOWN, STATE_MOVELEFT, STATE_MOVERIGHT};
int xvAhead[5] = {9, 0, 0,-1, 1}, yvAhead[5] = {9,-1, 1, 0, 0};
int xv, yv;
static const AIState state[5] = {STATE_NONE, STATE_MOVEUP, STATE_MOVEDOWN, STATE_MOVELEFT, STATE_MOVERIGHT};
static const int xvAhead[5] = {9, 0, 0,-1, 1};
static const int yvAhead[5] = {9,-1, 1, 0, 0};
int result;
AIEntity *hit;
@ -2243,12 +2340,10 @@ void aiGoodFairyAction(AIEntity *e) {
{
// Create a GEM?
if (g_hdb->_rnd->getRandomNumber(99) > 98) {
int spawnOK;
// spawn a gem in a random direction
int d = g_hdb->_rnd->getRandomNumber(3) + 1;
xv = xvAhead[d];
yv = yvAhead[d];
int xv = xvAhead[d];
int yv = yvAhead[d];
e->sequence = 30;
e->state = STATE_MOVEDOWN;
@ -2256,6 +2351,7 @@ void aiGoodFairyAction(AIEntity *e) {
if ((g_hdb->_ai->findEntityType(AI_CRATE, e->tileX + xv, e->tileY + yv) != NULL) ||
(g_hdb->_ai->findEntityType(AI_LIGHTBARREL, e->tileX + xv, e->tileY + yv) != NULL))
return;
int spawnOK;
hit = g_hdb->_ai->legalMove(e->tileX + xv, e->tileY + yv, e->level, &spawnOK);
uint32 bg_flags = g_hdb->_map->getMapBGTileFlags(e->tileX + xv, e->tileY + yv);
if (hit || !spawnOK || (bg_flags & kFlagSpecial))
@ -2273,9 +2369,8 @@ void aiGoodFairyAction(AIEntity *e) {
int tries = 4;
do {
// pick a random direction, then a random # of tiles in that direction
int rnd = g_hdb->_rnd->getRandomNumber(3) + 1;
AIDir d = (AIDir)rnd;
int walk = g_hdb->_rnd->getRandomNumber(4) + 1;
AIDir d = (AIDir)(g_hdb->_rnd->getRandomNumber(3) + 1);
int walk = g_hdb->_rnd->getRandomNumber(4) + 1;
AIEntity *p = g_hdb->_ai->getPlayer();
// if player is within 3 tiles, move closer
@ -2317,14 +2412,15 @@ void aiGoodFairyAction(AIEntity *e) {
}
e->dir = d;
e->state = state[d];
xv = xvAhead[d] * walk;
int tmpDir = (int)d;
e->state = state[tmpDir];
int xv = xvAhead[tmpDir] * walk;
if (e->tileX + xv < 1)
xv = -e->tileX + 1;
if (e->tileX + xv > g_hdb->_map->_width)
xv = g_hdb->_map->_width - e->tileX - 1;
yv = yvAhead[d] * walk;
int yv = yvAhead[d] * walk;
if (e->tileY + yv < 1)
yv = -e->tileY + 1;
if (e->tileY + yv > g_hdb->_map->_height)
@ -2425,9 +2521,10 @@ void aiBadFairyInit2(AIEntity *e) {
}
void aiBadFairyAction(AIEntity *e) {
AIState state[5] = {STATE_NONE, STATE_MOVEUP, STATE_MOVEDOWN, STATE_MOVELEFT, STATE_MOVERIGHT};
int xvAhead[5] = {9, 0, 0,-1, 1}, yvAhead[5] = {9,-1, 1, 0, 0};
int result;
static const AIState state[5] = {STATE_NONE, STATE_MOVEUP, STATE_MOVEDOWN, STATE_MOVELEFT, STATE_MOVERIGHT};
static const AIDir opposite[5] = {DIR_NONE, DIR_DOWN, DIR_UP, DIR_RIGHT, DIR_LEFT};
static const int xvAhead[5] = {9, 0, 0,-1, 1};
static const int yvAhead[5] = {9,-1, 1, 0, 0};
if (e->sequence) {
e->sequence--;
@ -2441,8 +2538,6 @@ void aiBadFairyAction(AIEntity *e) {
{
// Create a GATE PUDDLE?
if (e->onScreen && (g_hdb->_rnd->getRandomNumber(99) > 90) && g_hdb->getActionMode() && (g_hdb->_ai->getGatePuddles() < kMaxGatePuddles)) {
AIDir opposite[] = {DIR_NONE, DIR_DOWN, DIR_UP, DIR_RIGHT, DIR_LEFT};
if (e->onScreen)
g_hdb->_sound->playSound(SND_BADFAIRY_SPELL);
@ -2457,14 +2552,14 @@ void aiBadFairyAction(AIEntity *e) {
}
int tries = 4;
int result;
do {
// pick a random direction, then a random # of tiles in that direction
int rnd = g_hdb->_rnd->getRandomNumber(3) + 1;
AIDir d = (AIDir)rnd;
int d = g_hdb->_rnd->getRandomNumber(3) + 1;
int walk = g_hdb->_rnd->getRandomNumber(4) + 1;
AIEntity *p = g_hdb->_ai->getPlayer();
e->dir = d;
e->dir = (AIDir)d;
e->state = state[d];
int xv = xvAhead[d] * walk;
if (e->tileX + xv < 1)
@ -2524,6 +2619,7 @@ void aiBadFairyAction(AIEntity *e) {
// did we run into a wall, entity, water, slime etc?
// if so, pick a new direction!
if (onEvenTile(e->x, e->y)) {
int result;
AIEntity *hit = g_hdb->_ai->legalMoveOverWater(e->tileX + e->value1, e->tileY + e->value2, e->level, &result);
uint32 bg_flags = g_hdb->_map->getMapBGTileFlags(e->tileX + e->value1, e->tileY + e->value2);
if (!result || (hit && hit->type != AI_GUY) || (bg_flags & kFlagSpecial)) {
@ -2562,8 +2658,7 @@ void aiGatePuddleAction(AIEntity *e) {
if (e->goalX) {
g_hdb->_ai->animateEntity(e);
if (hitPlayer(e->x, e->y)) {
int i;
for (i = 0; i < kMaxTeleporters; i++) {
for (int i = 0; i < kMaxTeleporters; i++) {
if (g_hdb->_ai->_teleporters[i].anim1 == 2) { // PANIC ZONE?
p->tileX = g_hdb->_ai->_teleporters[i].x1;
p->tileY = g_hdb->_ai->_teleporters[i].y1;
@ -2637,11 +2732,11 @@ void aiGatePuddleAction(AIEntity *e) {
}
} else {
int rnd = g_hdb->_rnd->getRandomNumber(3) + 1;
int move_ok = 0, nx, ny;
e->dir = (AIDir)rnd;
nx = e->tileX + xva[e->dir];
ny = e->tileY + yva[e->dir];
int nx = e->tileX + xva[rnd];
int ny = e->tileY + yva[rnd];
int move_ok;
AIEntity *hit = g_hdb->_ai->legalMoveOverWater(nx, ny, e->level, &move_ok);
if (hit == p)
hit = NULL;
@ -2706,12 +2801,10 @@ void aiIcePuffSnowballInit(AIEntity *e) {
}
void aiIcePuffSnowballAction(AIEntity *e) {
int result, speed;
AIEntity *hit = NULL;
// check for hit BEFORE moving so snowball is closer to object
// NOTE: Need to do logic in this draw routine just in case the ICEPUFF gets stunned!
hit = g_hdb->_ai->legalMoveOverWater(e->value1 / kTileWidth, e->value2 / kTileHeight, e->level, &result);
int result;
AIEntity *hit = g_hdb->_ai->legalMoveOverWater(e->value1 / kTileWidth, e->value2 / kTileHeight, e->level, &result);
if (hit && hit->type == AI_GUY && !g_hdb->_ai->playerDead()) {
g_hdb->_ai->killPlayer(DEATH_NORMAL);
g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_WATER_SPLASH_SIT);
@ -2725,15 +2818,22 @@ void aiIcePuffSnowballAction(AIEntity *e) {
return;
}
speed = kPlayerMoveSpeed;
int speed = kPlayerMoveSpeed;
if (!g_hdb->getActionMode())
speed >>= 1;
switch (e->dir2) {
case DIR_DOWN: e->value2 += speed; break;
case DIR_LEFT: e->value1 -= speed; break;
case DIR_RIGHT: e->value1 += speed; break;
default: break;
case DIR_DOWN:
e->value2 += speed;
break;
case DIR_LEFT:
e->value1 -= speed;
break;
case DIR_RIGHT:
e->value1 += speed;
break;
default:
break;
}
}
@ -2826,10 +2926,20 @@ void aiIcePuffAction(AIEntity *e) {
if (e->animFrame == e->standupFrames) {
e->animFrame = 0;
switch (e->dir) {
case DIR_DOWN: e->state = STATE_ICEP_THROWDOWN; g_hdb->_sound->playSound(SND_ICEPUFF_THROW); break;
case DIR_LEFT: e->state = STATE_ICEP_THROWLEFT;g_hdb->_sound->playSound(SND_ICEPUFF_THROW); break;
case DIR_RIGHT: e->state = STATE_ICEP_THROWRIGHT; g_hdb->_sound->playSound(SND_ICEPUFF_THROW); break;
default: break;
case DIR_DOWN:
e->state = STATE_ICEP_THROWDOWN;
g_hdb->_sound->playSound(SND_ICEPUFF_THROW);
break;
case DIR_LEFT:
e->state = STATE_ICEP_THROWLEFT;
g_hdb->_sound->playSound(SND_ICEPUFF_THROW);
break;
case DIR_RIGHT:
e->state = STATE_ICEP_THROWRIGHT;
g_hdb->_sound->playSound(SND_ICEPUFF_THROW);
break;
default:
break;
}
}
break;
@ -2919,9 +3029,8 @@ void aiBuzzflyInit(AIEntity *e) {
}
void aiBuzzflyInit2(AIEntity *e) {
int i;
e->draw = g_hdb->_ai->getStandFrameDir(e);
for (i = 0; i < e->movedownFrames; i++)
for (int i = 0; i < e->movedownFrames; i++)
{
e->standdownGfx[i] = e->movedownGfx[i];
e->standupGfx[i] = e->moveupGfx[i];
@ -2979,8 +3088,6 @@ void aiBuzzflyAction(AIEntity *e) {
//-------------------------------------------------------------------
void aiDragonInit(AIEntity *e) {
AIEntity *block;
e->state = STATE_STANDDOWN;
e->sequence = 0; // 0 = sleeping
e->aiAction = aiDragonAction;
@ -2988,7 +3095,7 @@ void aiDragonInit(AIEntity *e) {
e->animCycle = 10; // time between flaps
// need to save the dragon's coords and type in the blocking entity for gem-hit-blocking detection
block = spawnBlocking(e->tileX - 1, e->tileY, e->level);
AIEntity *block = spawnBlocking(e->tileX - 1, e->tileY, e->level);
block->value1 = (int)AI_DRAGON;
sprintf(block->luaFuncUse, "%03d%03d", e->tileX, e->tileY);
block = spawnBlocking(e->tileX + 1, e->tileY, e->level);