/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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 "common/random.h" #include "hdb/hdb.h" #include "hdb/ai.h" #include "hdb/ai-player.h" #include "hdb/file-manager.h" #include "hdb/gfx.h" #include "hdb/sound.h" #include "hdb/menu.h" #include "hdb/lua-script.h" #include "hdb/map.h" #include "hdb/mpc.h" #include "hdb/window.h" namespace HDB { void aiPlayerInit(AIEntity *e) { g_hdb->_ai->clearInventory(); e->aiAction = aiPlayerAction; e->draw = g_hdb->_ai->getStandFrameDir(e); switch (e->dir) { case DIR_UP: e->state = STATE_STANDUP; break; case DIR_DOWN: e->state = STATE_STANDDOWN; break; case DIR_LEFT: e->state = STATE_STANDLEFT; break; case DIR_RIGHT: e->state = STATE_STANDRIGHT; break; case DIR_NONE: default: break; } e->moveSpeed = kPlayerMoveSpeed; strcpy(e->entityName, "player"); g_hdb->_ai->assignPlayer(e); } void aiPlayerInit2(AIEntity *e) { if (!g_hdb->_ai->_clubUpGfx[0]) { g_hdb->_ai->_weaponSelGfx = g_hdb->_gfx->loadTile(TILE_WEAPON_EQUIPPED); g_hdb->_ai->_clubUpGfx[0] = g_hdb->_gfx->getPicGfx(CLUBUP1, -1); g_hdb->_ai->_clubUpGfx[1] = g_hdb->_gfx->getPicGfx(CLUBUP2, -1); g_hdb->_ai->_clubUpGfx[2] = g_hdb->_gfx->getPicGfx(CLUBUP3, -1); g_hdb->_ai->_clubUpGfx[3] = g_hdb->_gfx->getPicGfx(CLUBUP3, -1); g_hdb->_ai->_clubDownGfx[0] = g_hdb->_gfx->getPicGfx(CLUBDOWN1, -1); g_hdb->_ai->_clubDownGfx[1] = g_hdb->_gfx->getPicGfx(CLUBDOWN2, -1); g_hdb->_ai->_clubDownGfx[2] = g_hdb->_gfx->getPicGfx(CLUBDOWN3, -1); g_hdb->_ai->_clubDownGfx[3] = g_hdb->_gfx->getPicGfx(CLUBDOWN3, -1); g_hdb->_ai->_clubLeftGfx[0] = g_hdb->_gfx->getPicGfx(CLUBLEFT1, -1); g_hdb->_ai->_clubLeftGfx[1] = g_hdb->_gfx->getPicGfx(CLUBLEFT2, -1); g_hdb->_ai->_clubLeftGfx[2] = g_hdb->_gfx->getPicGfx(CLUBLEFT3, -1); g_hdb->_ai->_clubLeftGfx[3] = g_hdb->_gfx->getPicGfx(CLUBLEFT3, -1); g_hdb->_ai->_clubRightGfx[0] = g_hdb->_gfx->getPicGfx(CLUBRIGHT1, -1); g_hdb->_ai->_clubRightGfx[1] = g_hdb->_gfx->getPicGfx(CLUBRIGHT2, -1); g_hdb->_ai->_clubRightGfx[2] = g_hdb->_gfx->getPicGfx(CLUBRIGHT3, -1); g_hdb->_ai->_clubRightGfx[3] = g_hdb->_gfx->getPicGfx(CLUBRIGHT3, -1); g_hdb->_ai->_clubUpFrames = g_hdb->_ai->_clubDownFrames = g_hdb->_ai->_clubLeftFrames = g_hdb->_ai->_clubRightFrames = 4; g_hdb->_ai->_slugAttackGfx[0] = g_hdb->_gfx->loadPic(SLUG_SHOT1); g_hdb->_ai->_slugAttackGfx[1] = g_hdb->_gfx->loadPic(SLUG_SHOT2); g_hdb->_ai->_slugAttackGfx[2] = g_hdb->_gfx->loadPic(SLUG_SHOT3); g_hdb->_ai->_slugAttackGfx[3] = g_hdb->_gfx->loadPic(SLUG_SHOT4); int32 size = g_hdb->_fileMan->getLength("shock_spark_sit01", TYPE_TILE32); g_hdb->_ai->_stunLightningGfx[0] = g_hdb->_gfx->getTileGfx("shock_spark_sit01", size); size = g_hdb->_fileMan->getLength("shock_spark_sit02", TYPE_TILE32); g_hdb->_ai->_stunLightningGfx[1] = g_hdb->_gfx->getTileGfx("shock_spark_sit02", size); size = g_hdb->_fileMan->getLength("shock_spark_sit03", TYPE_TILE32); g_hdb->_ai->_stunLightningGfx[2] = g_hdb->_gfx->getTileGfx("shock_spark_sit03", size); size = g_hdb->_fileMan->getLength("shock_spark_sit04", TYPE_TILE32); g_hdb->_ai->_stunLightningGfx[3] = g_hdb->_gfx->getTileGfx("shock_spark_sit04", size); size = g_hdb->_fileMan->getLength("starstun_sit01", TYPE_TILE32); g_hdb->_ai->_stunnedGfx[0] = g_hdb->_gfx->getTileGfx("starstun_sit01", size); size = g_hdb->_fileMan->getLength("starstun_sit02", TYPE_TILE32); g_hdb->_ai->_stunnedGfx[1] = g_hdb->_gfx->getTileGfx("starstun_sit02", size); size = g_hdb->_fileMan->getLength("starstun_sit03", TYPE_TILE32); g_hdb->_ai->_stunnedGfx[2] = g_hdb->_gfx->getTileGfx("starstun_sit03", size); size = g_hdb->_fileMan->getLength("starstun_sit04", TYPE_TILE32); g_hdb->_ai->_stunnedGfx[3] = g_hdb->_gfx->getTileGfx("starstun_sit04", size); } e->draw = g_hdb->_ai->getStandFrameDir(e); } void aiPlayerAction(AIEntity *e) { static const AIState stand[5] = {STATE_NONE, STATE_STANDUP, STATE_STANDDOWN, STATE_STANDLEFT, STATE_STANDRIGHT}; static const int xvAhead[5] = {9, 0, 0, -1, 1}; static const int yvAhead[5] = {9, -1, 1, 0, 0}; AIEntity *hit = NULL; // Draw the STUN lightning if it exists if (e->sequence) { e->aiDraw = aiPlayerDraw; g_hdb->_sound->playSound(SND_STUNNER_FIRE); hit = g_hdb->_ai->findEntity(e->tileX + xvAhead[e->dir], e->tileY + yvAhead[e->dir]); if (hit) switch (hit->type) { case AI_MEERKAT: if (hit->sequence > 2) g_hdb->_ai->stunEnemy(hit, 8); break; case AI_ICEPUFF: if (hit->state == STATE_ICEP_APPEAR || hit->state == STATE_ICEP_THROWDOWN || hit->state == STATE_ICEP_THROWLEFT || hit->state == STATE_ICEP_THROWRIGHT) { g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT); g_hdb->_ai->stunEnemy(hit, 8); } break; case AI_BADFAIRY: case AI_GOODFAIRY: case AI_CHICKEN: case AI_OMNIBOT: case AI_TURNBOT: case AI_PUSHBOT: case AI_DEADEYE: case AI_FATFROG: case AI_BUZZFLY: case AI_MAINTBOT: case AI_RIGHTBOT: case AI_GATEPUDDLE: g_hdb->_ai->stunEnemy(hit, 8); break; default: break; } hit = g_hdb->_ai->findEntity(e->tileX + (xvAhead[e->dir] << 1), e->tileY + (yvAhead[e->dir] << 1)); if (hit) switch (hit->type) { case AI_MEERKAT: if (hit->sequence > 2) g_hdb->_ai->stunEnemy(hit, 8); break; case AI_ICEPUFF: if (hit->state == STATE_ICEP_APPEAR || hit->state == STATE_ICEP_THROWDOWN || hit->state == STATE_ICEP_THROWLEFT || hit->state == STATE_ICEP_THROWRIGHT) { g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT); g_hdb->_ai->stunEnemy(hit, 8); } break; case AI_BADFAIRY: case AI_GOODFAIRY: case AI_CHICKEN: case AI_OMNIBOT: case AI_TURNBOT: case AI_PUSHBOT: case AI_DEADEYE: case AI_FATFROG: case AI_BUZZFLY: case AI_MAINTBOT: case AI_RIGHTBOT: case AI_GATEPUDDLE: g_hdb->_ai->stunEnemy(hit, 8); break; default: break; } } int xOff[] = {0, 0, -8,-16}; int yOff[] = {-8,-24,-16,-16}; // If the player is supposed to animate for abit, check for it here switch (e->state) { case STATE_GRABUP: case STATE_GRABDOWN: case STATE_GRABLEFT: case STATE_GRABRIGHT: if (!e->animFrame--) { // Done with the Grabbing Animation, switch to standing switch (e->state) { case STATE_GRABUP: e->draw = e->standupGfx[0]; e->state = STATE_STANDUP; break; case STATE_GRABDOWN: e->draw = e->standdownGfx[0]; e->state = STATE_STANDDOWN; break; case STATE_GRABLEFT: e->draw = e->standleftGfx[0]; e->state = STATE_STANDLEFT; break; case STATE_GRABRIGHT: e->draw = e->standrightGfx[0]; e->state = STATE_STANDRIGHT; break; default: break; } e->animDelay = 1; e->animCycle = 1; } break; case STATE_ATK_CLUB_UP: case STATE_ATK_CLUB_DOWN: case STATE_ATK_CLUB_LEFT: case STATE_ATK_CLUB_RIGHT: g_hdb->_ai->setPlayerInvisible(true); e->aiDraw = aiPlayerDraw; e->drawXOff = xOff[e->state - STATE_ATK_CLUB_UP]; e->drawYOff = yOff[e->state - STATE_ATK_CLUB_UP]; switch (e->state) { case STATE_ATK_CLUB_UP: cycleFrames(e, g_hdb->_ai->_clubUpFrames); break; case STATE_ATK_CLUB_DOWN: cycleFrames(e, g_hdb->_ai->_clubDownFrames); break; case STATE_ATK_CLUB_LEFT: cycleFrames(e, g_hdb->_ai->_clubLeftFrames); break; case STATE_ATK_CLUB_RIGHT: cycleFrames(e, g_hdb->_ai->_clubRightFrames); break; default: break; } // Whack! if ((e->animFrame >= 1) && (e->animDelay == e->animCycle)) { switch (e->dir) { case DIR_UP: hit = g_hdb->_ai->playerCollision(32, 0, 16, 16); break; case DIR_DOWN: hit = g_hdb->_ai->playerCollision(0, 32, 16, 16); break; case DIR_LEFT: hit = g_hdb->_ai->playerCollision(16, 16, 32, 0); break; case DIR_RIGHT: hit = g_hdb->_ai->playerCollision(16, 16, 0, 32); break; default: break; } if (hit && hit->level == e->level && !hit->stunnedWait) { switch (hit->type) { case AI_MEERKAT: if (hit->sequence > 2) // out of the ground? g_hdb->_ai->stunEnemy(hit, 2); break; case AI_ICEPUFF: if (hit->state == STATE_ICEP_APPEAR || hit->state == STATE_ICEP_THROWDOWN || hit->state == STATE_ICEP_THROWLEFT || hit->state == STATE_ICEP_THROWRIGHT) g_hdb->_ai->stunEnemy(hit, 2); break; case AI_CHICKEN: g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT); g_hdb->_ai->removeEntity(hit); break; case AI_BADFAIRY: case AI_GOODFAIRY: case AI_OMNIBOT: case AI_TURNBOT: case AI_PUSHBOT: case AI_DEADEYE: case AI_FATFROG: case AI_BUZZFLY: case AI_MAINTBOT: case AI_RIGHTBOT: case AI_SHOCKBOT: case AI_GATEPUDDLE: g_hdb->_ai->stunEnemy(hit, 2); g_hdb->_sound->playSound(g_hdb->_ai->metalOrFleshSND(hit)); break; default: break; } } } if ((!e->animFrame) && (e->animDelay == e->animCycle)) { e->state = stand[e->dir]; e->aiDraw = NULL; switch (e->state) { case STATE_ATK_CLUB_UP: e->draw = e->standupGfx[0]; break; case STATE_ATK_CLUB_DOWN: e->draw = e->standdownGfx[0]; break; case STATE_ATK_CLUB_LEFT: e->draw = e->standleftGfx[0]; break; case STATE_ATK_CLUB_RIGHT: e->draw = e->standrightGfx[0]; break; default: break; } g_hdb->_ai->setPlayerInvisible(false); e->drawXOff = e->drawYOff = 0; } return; case STATE_ATK_STUN_UP: e->draw = g_hdb->_ai->_stunUpGfx[e->animFrame]; cycleFrames(e, g_hdb->_ai->_stunUpFrames); if (!e->animFrame && e->animDelay == e->animCycle) { e->state = stand[e->dir]; e->aiDraw = NULL; e->sequence = 0; } return; case STATE_ATK_STUN_DOWN: e->draw = g_hdb->_ai->_stunDownGfx[e->animFrame]; cycleFrames(e, g_hdb->_ai->_stunDownFrames); if (!e->animFrame && e->animDelay == e->animCycle) { e->state = stand[e->dir]; e->aiDraw = NULL; e->sequence = 0; } return; case STATE_ATK_STUN_LEFT: e->draw = g_hdb->_ai->_stunLeftGfx[e->animFrame]; cycleFrames(e, g_hdb->_ai->_stunLeftFrames); if (!e->animFrame && e->animDelay == e->animCycle) { e->state = stand[e->dir]; e->aiDraw = NULL; e->sequence = 0; } return; case STATE_ATK_STUN_RIGHT: e->draw = g_hdb->_ai->_stunRightGfx[e->animFrame]; cycleFrames(e, g_hdb->_ai->_stunRightFrames); if (!e->animFrame && e->animDelay == e->animCycle) { e->state = stand[e->dir]; e->aiDraw = NULL; e->sequence = 0; } return; case STATE_ATK_SLUG_UP: e->draw = g_hdb->_ai->_slugUpGfx[e->animFrame]; cycleFrames(e, g_hdb->_ai->_slugUpFrames); if (!e->animFrame && e->animDelay == e->animCycle) { e->state = stand[e->dir]; e->sequence = 0; } return; case STATE_ATK_SLUG_DOWN: e->draw = g_hdb->_ai->_slugDownGfx[e->animFrame]; cycleFrames(e, g_hdb->_ai->_slugDownFrames); if (!e->animFrame && e->animDelay == e->animCycle) { e->state = stand[e->dir]; e->sequence = 0; } return; case STATE_ATK_SLUG_LEFT: e->draw = g_hdb->_ai->_slugLeftGfx[e->animFrame]; cycleFrames(e, g_hdb->_ai->_slugLeftFrames); if (!e->animFrame && e->animDelay == e->animCycle) { e->state = stand[e->dir]; e->sequence = 0; } return; case STATE_ATK_SLUG_RIGHT: e->draw = g_hdb->_ai->_slugRightGfx[e->animFrame]; cycleFrames(e, g_hdb->_ai->_slugRightFrames); if (!e->animFrame && e->animDelay == e->animCycle) { e->state = stand[e->dir]; e->sequence = 0; } return; default: break; } // If the touchplate wait is on, keep it timing if (e->touchpWait) { e->touchpWait--; if (!e->touchpWait) e->touchpTile = -e->touchpTile; } else if (e->touchpTile < 0 && (e->touchpX != e->tileX || e->touchpY != e->tileY)) { g_hdb->_ai->checkActionList(e, e->touchpX, e->touchpY, false); g_hdb->_map->setMapBGTileIndex(e->touchpX, e->touchpY, -e->touchpTile); e->touchpX = e->touchpY = e->touchpTile = 0; } // If the player is moving somewhere, animate him int bgFlags, fgFlags; if (e->goalX) { if (onEvenTile(e->x, e->y)) { g_hdb->_ai->playerOnIce() ? g_hdb->_sound->playSound(SND_STEPS_ICE) : g_hdb->_sound->playSound(SND_FOOTSTEPS); // Did we just fall down a PLUMMET? bgFlags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY); fgFlags = g_hdb->_map->getMapFGTileFlags(e->tileX, e->tileY); if ((bgFlags & kFlagPlummet) && !(fgFlags & kFlagGrating) && !g_hdb->_ai->playerDead()) { g_hdb->_ai->killPlayer(DEATH_PLUMMET); g_hdb->_ai->animEntFrames(e); return; } } g_hdb->_ai->animateEntity(e); } else { // Sometimes the fading stays black if (!g_hdb->_ai->cinematicsActive() && g_hdb->_gfx->isFadeStaying()) g_hdb->_gfx->turnOffFade(); // Did we just fall down a PLUMMET? bgFlags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY); fgFlags = g_hdb->_map->getMapFGTileFlags(e->tileX, e->tileY); if ((bgFlags & kFlagPlummet) && !(fgFlags & kFlagGrating) && !g_hdb->_ai->playerDead()) { g_hdb->_ai->killPlayer(DEATH_PLUMMET); g_hdb->_ai->animEntFrames(e); return; } // Standing on a TouchPlate will activate something WHILE standing on it int bgTile = g_hdb->_ai->checkForTouchplate(e->tileX, e->tileY); if (bgTile && !e->touchpWait && !e->touchpTile) { if (g_hdb->_ai->checkActionList(e, e->tileX, e->tileY, false)) { e->touchpTile = bgTile; e->touchpX = e->tileX; e->touchpY = e->tileY; e->touchpWait = kPlayerTouchPWait; g_hdb->_ai->stopEntity(e); } } g_hdb->_ai->animEntFrames(e); } } void aiPlayerDraw(AIEntity *e, int mx, int my) { switch (e->state) { case STATE_ATK_CLUB_UP: g_hdb->_ai->_clubUpGfx[e->animFrame]->drawMasked(e->x + e->drawXOff - mx, e->y + e->drawYOff - my); break; case STATE_ATK_CLUB_DOWN: g_hdb->_ai->_clubDownGfx[e->animFrame]->drawMasked(e->x + e->drawXOff - mx, e->y + e->drawYOff - my); break; case STATE_ATK_CLUB_LEFT: g_hdb->_ai->_clubLeftGfx[e->animFrame]->drawMasked(e->x + e->drawXOff - mx, e->y + e->drawYOff - my); break; case STATE_ATK_CLUB_RIGHT: g_hdb->_ai->_clubRightGfx[e->animFrame]->drawMasked(e->x + e->drawXOff - mx, e->y + e->drawYOff - my); break; default: break; } if (e->sequence) { static int frame = 0; switch (e->dir) { case DIR_UP: g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - mx, e->y - 32 - my); g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - mx, e->y - 64 - my); break; case DIR_DOWN: g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - mx, e->y + 32 - my); g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - mx, e->y + 64 - my); break; case DIR_LEFT: g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - 32 - mx, e->y - my); g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x - 64 - mx, e->y - my); break; case DIR_RIGHT: g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x + 32 - mx, e->y - my); g_hdb->_ai->_stunLightningGfx[frame]->drawMasked(e->x + 64 - mx, e->y - my); break; case DIR_NONE: default: break; } frame = (frame + 1) & 3; } } void aiGemAttackInit(AIEntity *e) { static const int xv[5] = {9, 0, 0, -1, 1}; static const int yv[5] = {9, -1, 1, 0, 0}; e->moveSpeed = kPlayerMoveSpeed << 1; g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]); e->state = STATE_MOVEDOWN; // so it will draw & animate e->sequence = 0; // flying out at something e->aiAction = aiGemAttackAction; e->draw = e->movedownGfx[0]; g_hdb->_sound->playSound(SND_GEM_THROW); } void aiGemAttackAction(AIEntity *e) { static const int xv[5] = {9, 0, 0, -1, 1}; static const int yv[5] = {9, -1, 1, 0, 0}; switch (e->sequence) { // flying out at something case 0: if (e->goalX) g_hdb->_ai->animateEntity(e); else { g_hdb->_ai->checkActionList(e, e->tileX, e->tileY, false); g_hdb->_ai->checkAutoList(e, e->tileX, e->tileY); AIEntity *hit = g_hdb->_ai->findEntityIgnore(e->tileX, e->tileY, e); uint32 bgFlags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY); uint32 fgFlags = g_hdb->_map->getMapFGTileFlags(e->tileX, e->tileY); int result = (e->level == 1 ? (bgFlags & (kFlagSolid)) : !(fgFlags & kFlagGrating) && (bgFlags & (kFlagSolid))); if (hit) { switch (hit->type) { case AI_CHICKEN: g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT); g_hdb->_ai->removeEntity(hit); g_hdb->_sound->playSound(SND_CHICKEN_BAGAWK); break; case AI_BADFAIRY: g_hdb->_ai->stunEnemy(hit, 2); g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH); break; case AI_NONE: if (hit->value1 == (int)AI_DRAGON) { // pull dragon's coords out of "lua_func_use" string. char num1[4], num2[4]; memset(num1, 0, 4); memset(num2, 0, 4); memcpy(num1, hit->luaFuncUse, 3); memcpy(num2, hit->luaFuncUse + 3, 3); g_hdb->_sound->playSound(SND_CLUB_HIT_FLESH); AIEntity *found = g_hdb->_ai->findEntity(atoi(num1), atoi(num2)); if (found) aiDragonWake(found); } g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH); g_hdb->_sound->playSound(SND_INV_SELECT); break; case AI_DRAGON: g_hdb->_sound->playSound(SND_CLUB_HIT_FLESH); aiDragonWake(hit); // fallthrough default: g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH); g_hdb->_sound->playSound(SND_CLUB_HIT_FLESH); } if (e->value1) e->sequence = 1; else g_hdb->_ai->removeEntity(e); // bye bye! return; } else if (result) { // hit a wall g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH); g_hdb->_sound->playSound(SND_INV_SELECT); // come back to daddy? if (e->value1) e->sequence = 1; else { g_hdb->_ai->removeEntity(e); return; } } else { g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]); e->state = STATE_MOVEDOWN; // so it will draw & animate } g_hdb->_ai->animateEntity(e); } break; // coming back to daddy? case 1: { AIEntity *p = g_hdb->_ai->getPlayer(); if (e->x < p->x) e->x++; else e->x--; if (e->y < p->y) e->y++; else e->y--; if (abs(e->x - p->x) < 4 && abs(e->y - p->y) < 4) { int amt = g_hdb->_ai->getGemAmount(); g_hdb->_ai->setGemAmount(amt + 1); g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH); g_hdb->_ai->removeEntity(e); g_hdb->_sound->playSound(SND_GET_GEM); } } break; default: break; } } void aiChickenAction(AIEntity *e) { static int delay = 64; if (g_hdb->_map->checkEntOnScreen(e) && !delay) { g_hdb->_sound->playSound(SND_CHICKEN_AMBIENT); delay = g_hdb->_rnd->getRandomNumber(127) + 160; aiChickenUse(e); } if (delay) delay--; if (e->goalX) g_hdb->_ai->animateEntity(e); else g_hdb->_ai->animEntFrames(e); } void aiChickenUse(AIEntity *e) { g_hdb->_sound->playSound(SND_CHICKEN_BAGAWK); } void aiChickenInit(AIEntity *e) { e->aiUse = aiChickenUse; e->aiAction = aiChickenAction; } void aiChickenInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiDollyInit(AIEntity *e) { e->moveSpeed = kPlayerMoveSpeed >> 1; e->aiAction = aiGenericAction; } void aiDollyInit2(AIEntity *e) { e->draw = e->movedownGfx[0]; } void aiSergeantInit(AIEntity *e) { e->moveSpeed = kPlayerMoveSpeed >> 1; if (e->value1) e->aiAction = aiSergeantAction; } void aiSergeantInit2(AIEntity *e) { e->draw = g_hdb->_ai->getStandFrameDir(e); } void aiSergeantAction(AIEntity *e) { if (e->goalX) { g_hdb->_sound->playSound(SND_FOOTSTEPS); g_hdb->_ai->animateEntity(e); } else g_hdb->_ai->animEntFrames(e); } void aiSpacedudeInit(AIEntity *e) { e->moveSpeed = kPlayerMoveSpeed >> 1; if (e->value1) e->aiAction = aiGenericAction; } void aiSpacedudeInit2(AIEntity *e) { e->standdownFrames = 1; e->standdownGfx[0] = e->movedownGfx[0]; e->standupFrames = 1; e->standupGfx[0] = e->moveupGfx[0]; e->standleftFrames = 1; e->standleftGfx[0] = e->moveleftGfx[0]; e->standrightFrames = 1; e->standrightGfx[0] = e->moverightGfx[0]; e->draw = g_hdb->_ai->getStandFrameDir(e); } void aiCrateAction(AIEntity *e) { // if crate isn't moving somewhere, don't move it if (!e->goalX) { // crate is stopped in the water... should it continue downstream? // not if it's marked by the Number of the Beast! if (e->state == STATE_FLOATING) { if (e->value1 != 0x666) { int flags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY); if (flags & (kFlagPushRight | kFlagPushLeft | kFlagPushUp | kFlagPushDown)) { g_hdb->_ai->setEntityGoal(e, e->tileX, e->tileY); g_hdb->_ai->animateEntity(e); } else g_hdb->_ai->animEntFrames(e); } else g_hdb->_ai->animEntFrames(e); } return; } g_hdb->_ai->animateEntity(e); } void aiCrateInit2(AIEntity *e) { // point all crate move frames to the standing one e->movedownFrames = e->moveleftFrames = e->moverightFrames = e->moveupFrames = 1; e->movedownGfx[0] = e->moveupGfx[0] = e->moveleftGfx[0] = e->moverightGfx[0] = e->standdownGfx[0]; e->draw = e->standdownGfx[0]; // standing frame - doesn't move } void aiCrateInit(AIEntity *e) { e->moveSpeed = kPushMoveSpeed; e->aiAction = aiCrateAction; e->value1 = 0; } void aiBarrelLightAction(AIEntity *e) { if (!e->goalX) { if (e->state == STATE_FLOATING) g_hdb->_ai->animEntFrames(e); return; } g_hdb->_ai->animateEntity(e); } void aiBarrelLightInit2(AIEntity *e) { // point all light barrel move frames to the standing one e->movedownFrames = e->moveleftFrames = e->moverightFrames = e->moveupFrames = 1; e->movedownGfx[0] = e->moveupGfx[0] = e->moveleftGfx[0] = e->moverightGfx[0] = e->standdownGfx[0]; e->draw = e->standdownGfx[0]; // standing frame - doesn't move } void aiBarrelLightInit(AIEntity *e) { e->moveSpeed = kPushMoveSpeed; e->aiAction = aiBarrelLightAction; } void aiBarrelHeavyAction(AIEntity *e) { if (!e->goalX) { if (e->state == STATE_FLOATING) g_hdb->_ai->animEntFrames(e); return; } g_hdb->_ai->animateEntity(e); } void aiBarrelHeavyInit2(AIEntity *e) { // point all heavy barrel move frames to the standing one e->movedownFrames = e->moveleftFrames = e->moverightFrames = e->moveupFrames = 1; e->movedownGfx[0] = e->moveupGfx[0] = e->moveleftGfx[0] = e->moverightGfx[0] = e->standdownGfx[0]; e->draw = e->standdownGfx[0]; // standing frame - doesn't move } void aiBarrelHeavyInit(AIEntity *e) { e->moveSpeed = kPushMoveSpeed; e->aiAction = aiBarrelHeavyAction; } void aiBarrelExplode(AIEntity *e) { e->state = STATE_EXPLODING; e->animDelay = e->animCycle; e->animFrame = 0; if (!g_hdb->isDemo()) g_hdb->_sound->playSound(SND_BARREL_EXPLODE); g_hdb->_map->setBoomBarrel(e->tileX, e->tileY, 0); } void aiBarrelExplodeInit(AIEntity *e) { e->moveSpeed = kPushMoveSpeed; e->aiAction = aiBarrelExplodeAction; g_hdb->_map->setBoomBarrel(e->tileX, e->tileY, 1); } void aiBarrelExplodeInit2(AIEntity *e) { // point all exploding barrel MOVE frames to the standing one e->blinkFrames = e->movedownFrames = e->moveleftFrames = e->moverightFrames = e->moveupFrames = 1; e->blinkGfx[0] = e->movedownGfx[0] = e->moveupGfx[0] = e->moveleftGfx[0] = e->moverightGfx[0] = e->standdownGfx[0]; e->draw = e->standdownGfx[0]; // standing frame - doesn't move } void aiBarrelExplodeAction(AIEntity *e) { if (e->goalX) g_hdb->_ai->animateEntity(e); else if (e->state == STATE_EXPLODING) g_hdb->_ai->animEntFrames(e); } void aiBarrelExplodeSpread(AIEntity *e) { static const int xv1[4] = {-1, 1, -1, 0}; static const int yv1[4] = {-1, -1, 0, -1}; static const int xv2[4] = {1, 0, 1, -1}; static const int yv2[4] = {0, 1, 1, 1}; int x = e->tileX; int y = e->tileY; int index = e->animFrame; // are we just starting an explosion ring? if (e->animDelay != e->animCycle) return; // the animation frame is the index into which set of 2 explosions to spawn int xv = xv1[index]; int yv = yv1[index]; // explosion 1: check to see if we can explode (non-solid tile) // if so, spawn it and mark it in the explosion matrix if (!(g_hdb->_map->getMapBGTileFlags(x + xv, y + yv) & kFlagSolid) && !g_hdb->_map->explosionExist(x + xv, y + yv)) { aiBarrelBlowup(e, x + xv, y + yv); // are we blowing up on another BOOMBARREL? if so, start it exploding. AIEntity *e2 = g_hdb->_ai->findEntity(x + xv, y + yv); if (e2 && e2->state != STATE_EXPLODING) { switch (e2->type) { case AI_GUY: g_hdb->_ai->killPlayer(DEATH_FRIED); break; case AI_BOOMBARREL: aiBarrelExplode(e2); break; case AI_OMNIBOT: case AI_TURNBOT: case AI_SHOCKBOT: case AI_RIGHTBOT: case AI_PUSHBOT: case AI_RAILRIDER: case AI_MAINTBOT: case AI_DEADEYE: case AI_FATFROG: case AI_ICEPUFF: case AI_MEERKAT: case AI_BUZZFLY: case AI_GOODFAIRY: case AI_GATEPUDDLE: case AI_BADFAIRY: g_hdb->_ai->addAnimateTarget(x * kTileWidth, y * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT); if (e2->type != AI_LASERBEAM) g_hdb->_ai->removeEntity(e2); break; default: break; } } } xv = xv2[index]; yv = yv2[index]; // explosion 2: check to see if we can explode (non-solid tile) // if so, spawn it and mark it in the explosion matrix if (!(g_hdb->_map->getMapBGTileFlags(x + xv, y + yv) & kFlagSolid) && !g_hdb->_map->explosionExist(x + xv, y + yv)) { aiBarrelBlowup(e, x + xv, y + yv); // are we blowing up on another BOOMBARREL? if so, start it exploding. AIEntity *e2 = g_hdb->_ai->findEntity(x + xv, y + yv); if (e2 && e2->state != STATE_EXPLODING) { switch (e2->type) { case AI_GUY: g_hdb->_ai->killPlayer(DEATH_FRIED); break; case AI_BOOMBARREL: aiBarrelExplode(e2); break; case AI_OMNIBOT: case AI_TURNBOT: case AI_SHOCKBOT: case AI_RIGHTBOT: case AI_PUSHBOT: case AI_RAILRIDER: case AI_MAINTBOT: case AI_DEADEYE: case AI_FATFROG: case AI_ICEPUFF: case AI_MEERKAT: case AI_BUZZFLY: case AI_GOODFAIRY: case AI_GATEPUDDLE: case AI_BADFAIRY: g_hdb->_ai->addAnimateTarget(x * kTileWidth, y * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT); if (e2->type != AI_LASERBEAM) g_hdb->_ai->removeEntity(e2); break; default: break; } } } } void aiBarrelExplosionEnd(int x, int y) { g_hdb->_map->setExplosion(x, y, 0); } void aiBarrelBlowup(AIEntity *e, int x, int y) { g_hdb->_ai->addAnimateTarget(x * kTileWidth, y * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT); g_hdb->_map->setExplosion(x, y, 1); g_hdb->_ai->addCallback(AI_BARREL_EXPLOSION_END, x, y, e->animCycle * 4); } void aiScientistInit(AIEntity *e) { e->moveSpeed = kPlayerMoveSpeed >> 1; if (g_hdb->_ai->findPath(e)) e->aiAction = aiGenericAction; else if (e->value1) e->aiAction = aiGenericAction; } void aiScientistInit2(AIEntity *e) { e->draw = g_hdb->_ai->getStandFrameDir(e); } void aiSlugAttackAction(AIEntity *e) { static const int xv[5] = {9, 0, 0, -1, 1}; static const int yv[5] = {9, -1, 1, 0, 0}; if (e->goalX) g_hdb->_ai->animateEntity(e); g_hdb->_ai->checkActionList(e, e->tileX, e->tileY, false); g_hdb->_ai->checkAutoList(e, e->tileX, e->tileY); AIEntity *hit = g_hdb->_ai->findEntityIgnore(e->tileX, e->tileY, e); if (hit && hit->type == AI_GUY) hit = NULL; // don't hit anything you can walk through... if (hit && true == g_hdb->_ai->getTableEnt(hit->type)) hit = NULL; // don't hit floating stuff if (hit && hit->state == STATE_FLOATING) hit = NULL; uint32 bg_flags = g_hdb->_map->getMapBGTileFlags(e->tileX, e->tileY); uint32 fg_flags = g_hdb->_map->getMapFGTileFlags(e->tileX, e->tileY); int result = (e->level == 1 ? (bg_flags & (kFlagSolid)) : !(fg_flags & kFlagGrating) && (bg_flags & (kFlagSolid))); if (hit) { g_hdb->_sound->playSound(SND_SLUG_HIT); g_hdb->_sound->playSound(g_hdb->_ai->metalOrFleshSND(hit)); switch (hit->type) { case AI_MEERKAT: if (hit->sequence > 2) { // out of the ground? g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT); g_hdb->_ai->stunEnemy(hit, 8); } else { g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]); e->state = STATE_MOVEDOWN; // so it will draw & animate g_hdb->_ai->animateEntity(e); return; } break; case AI_ICEPUFF: if (hit->state == STATE_ICEP_APPEAR || hit->state == STATE_ICEP_THROWDOWN || hit->state == STATE_ICEP_THROWLEFT || hit->state == STATE_ICEP_THROWRIGHT) { g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT); g_hdb->_ai->stunEnemy(hit, 8); } else { g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]); e->state = STATE_MOVEDOWN; // so it will draw & animate g_hdb->_ai->animateEntity(e); return; } break; case AI_OMNIBOT: case AI_TURNBOT: case AI_SHOCKBOT: case AI_RIGHTBOT: case AI_PUSHBOT: case AI_LISTENBOT: case AI_MAINTBOT: case AI_FATFROG: case AI_BADFAIRY: case AI_BUZZFLY: g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT); g_hdb->_ai->stunEnemy(hit, 8); break; case AI_CHICKEN: g_hdb->_ai->addAnimateTarget(hit->x, hit->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT); g_hdb->_ai->removeEntity(hit); break; case AI_BOOMBARREL: g_hdb->_sound->playSound(SND_CLUB_HIT_METAL); aiBarrelExplode(hit); aiBarrelBlowup(hit, hit->tileX, hit->tileY); break; // ACTION MODE entities go away - except the FOURFIRER case AI_GATEPUDDLE: g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 7, ANIM_NORMAL, false, false, TELEPORT_FLASH); g_hdb->_ai->removeEntity(hit); g_hdb->_sound->playSound(SND_TELEPORT); break; case AI_DEADEYE: g_hdb->_ai->addAnimateTarget(e->tileX * kTileWidth, e->tileY * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT); g_hdb->_ai->removeEntity(hit); g_hdb->_sound->playSound(SND_BARREL_EXPLODE); break; case AI_NONE: if (hit->value1 == (int)AI_DRAGON) { // pull dragon's coords out of "lua_func_use" string. char num1[4], num2[4]; memset(num1, 0, 4); memset(num2, 0, 4); memcpy(num1, hit->luaFuncUse, 3); memcpy(num2, hit->luaFuncUse + 3, 3); g_hdb->_sound->playSound(SND_CLUB_HIT_FLESH); AIEntity *found = g_hdb->_ai->findEntity(atoi(num1), atoi(num2)); if (found) aiDragonWake(found); g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH); } break; case AI_DRAGON: aiDragonWake(hit); break; default: break; } g_hdb->_ai->removeEntity(e); // bye bye! return; } else if (result) { // hit a wall g_hdb->_sound->playSound(SND_SLUG_HIT); g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GROUP_STEAM_PUFF_SIT); g_hdb->_ai->removeEntity(e); } else { g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]); e->state = STATE_MOVEDOWN; // so it will draw & animate g_hdb->_ai->animateEntity(e); } } void aiSlugAttackDraw(AIEntity *e, int mx, int my) { g_hdb->_ai->_slugAttackGfx[e->animFrame]->drawMasked(e->x - mx + 8, e->y - my + 8); } void aiSlugAttackInit(AIEntity *e) { static const int xv[5] = {9, 0, 0, -1, 1}; static const int yv[5] = {9, -1, 1, 0, 0}; if (g_hdb->isDemo()) return; e->moveSpeed = kPlayerMoveSpeed << 1; g_hdb->_ai->setEntityGoal(e, e->tileX + xv[e->dir], e->tileY + yv[e->dir]); e->draw = NULL; // use custom draw function e->aiDraw = aiSlugAttackDraw; e->state = STATE_MOVEDOWN; // so it will draw & animate e->aiAction = aiSlugAttackAction; g_hdb->_sound->playSound(SND_SLUG_FIRE); } void aiSlugAttackInit2(AIEntity *e) { e->movedownFrames = 4; } void aiDeadWorkerInit(AIEntity *e) { } void aiDeadWorkerInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiWorkerInit(AIEntity *e) { if (e->value1) e->aiAction = aiGenericAction; e->moveSpeed = kPlayerMoveSpeed >> 1; } void aiWorkerInit2(AIEntity *e) { e->draw = g_hdb->_ai->getStandFrameDir(e); } void aiAccountantInit(AIEntity *e) { } void aiAccountantInit2(AIEntity *e) { e->draw = g_hdb->_ai->getStandFrameDir(e); } void aiFrogStatueInit(AIEntity *e) { e->moveSpeed = kPushMoveSpeed; e->aiAction = aiFrogStatueAction; } void aiFrogStatueInit2(AIEntity *e) { // point all frog statue MOVE frames to the standing one e->blinkFrames = e->movedownFrames = e->moveleftFrames = e->moverightFrames = e->moveupFrames = 1; e->blinkGfx[0] = e->movedownGfx[0] = e->moveupGfx[0] = e->moveleftGfx[0] = e->moverightGfx[0] = e->standdownGfx[0]; e->draw = e->standdownGfx[0]; // standing frame - doesn't move } void aiFrogStatueAction(AIEntity *e) { // if frog statue isn't moving somewhere, don't move it if (!e->goalX) return; g_hdb->_ai->animateEntity(e); } void aiRoboStunnerAction(AIEntity *e) { aiAnimateStanddown(e, 1); aiGetItemAction(e); } void aiRoboStunnerInit(AIEntity *e) { e->aiAction = aiRoboStunnerAction; strcpy(e->printedName, "Robostunner"); } void aiRoboStunnerInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiClubInit(AIEntity *e) { strcpy(e->printedName, "Creature Clubber"); e->aiAction = aiGetItemAction; } void aiClubInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiSlugSlingerInit(AIEntity *e) { strcpy(e->printedName, "Slugslinger"); e->aiAction = aiGetItemAction; } void aiSlugSlingerInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiEnvelopeGreenInit(AIEntity *e) { strcpy(e->printedName, "Green envelope"); e->aiAction = aiGetItemAction; } void aiEnvelopeGreenInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiGemBlueInit(AIEntity *e) { e->aiAction = aiGemAction; } void aiGemBlueInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiGemRedInit(AIEntity *e) { e->aiAction = aiGemAction; } void aiGemRedInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiGemGreenInit(AIEntity *e) { e->aiAction = aiGemAction; } void aiGemGreenInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiTeaCupInit(AIEntity *e) { strcpy(e->printedName, "a Teacup"); e->aiAction = aiGetItemAction; } void aiTeaCupInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiCookieInit(AIEntity *e) { strcpy(e->printedName, "a Cookie"); e->aiAction = aiGetItemAction; } void aiCookieInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiBurgerInit(AIEntity *e) { strcpy(e->printedName, "a Burger"); e->aiAction = aiGetItemAction; } void aiBurgerInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiBookInit(AIEntity *e) { strcpy(e->printedName, "a Book"); e->aiAction = aiGetItemAction; } void aiBookInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiClipboardInit(AIEntity *e) { strcpy(e->printedName, "a Clipboard"); e->aiAction = aiGetItemAction; } void aiClipboardInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiNoteInit(AIEntity *e) { strcpy(e->printedName, "a Note"); e->aiAction = aiGetItemAction; } void aiNoteInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiKeycardWhiteInit(AIEntity *e) { strcpy(e->printedName, "a White keycard"); e->aiAction = aiGetItemAction; } void aiKeycardWhiteInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiKeycardBlueInit(AIEntity *e) { strcpy(e->printedName, "a Blue keycard"); e->aiAction = aiGetItemAction; } void aiKeycardBlueInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiKeycardRedInit(AIEntity *e) { strcpy(e->printedName, "a Red keycard"); e->aiAction = aiGetItemAction; } void aiKeycardRedInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiKeycardGreenInit(AIEntity *e) { strcpy(e->printedName, "a Green keycard"); e->aiAction = aiGetItemAction; } void aiKeycardGreenInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiKeycardPurpleInit(AIEntity *e) { strcpy(e->printedName, "a Purple keycard"); e->aiAction = aiGetItemAction; } void aiKeycardPurpleInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiKeycardBlackInit(AIEntity *e) { strcpy(e->printedName, "a Black keycard"); e->aiAction = aiGetItemAction; } void aiKeycardBlackInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiSeedInit(AIEntity *e) { strcpy(e->printedName, "some Henscratch"); e->aiAction = aiGetItemAction; } void aiSeedInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiSodaInit(AIEntity *e) { strcpy(e->printedName, "a Dr. Frostee"); e->aiAction = aiGetItemAction; } void aiSodaInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiDollyTool1Init(AIEntity *e) { strcpy(e->printedName, "Dolly's Wrench"); e->aiAction = aiGetItemAction; } void aiDollyTool1Init2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiDollyTool2Init(AIEntity *e) { strcpy(e->printedName, "Dolly's Torch"); e->aiAction = aiGetItemAction; } void aiDollyTool2Init2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiDollyTool3Init(AIEntity *e) { strcpy(e->printedName, "Dolly's EMF Resonator"); e->aiAction = aiGetItemAction; } void aiDollyTool3Init2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiDollyTool4Init(AIEntity *e) { strcpy(e->printedName, "Dolly's Toolbox"); e->aiAction = aiGetItemAction; } void aiDollyTool4Init2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiRouterInit(AIEntity *e) { strcpy(e->printedName, "a Computer Router"); e->aiAction = aiGetItemAction; } void aiRouterInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiSlicerInit(AIEntity *e) { strcpy(e->printedName, "a Pizza Slicer"); e->aiAction = aiGetItemAction; } void aiSlicerInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiPackageInit(AIEntity *e) { strcpy(e->printedName, "a Package"); e->aiAction = aiGetItemAction; } void aiPackageInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiMagicEggAction(AIEntity *e) { // if magic egg isn't moving somewhere, don't move it if (!e->goalX) return; g_hdb->_ai->animateEntity(e); } void aiMagicEggInit(AIEntity *e) { e->moveSpeed = kPushMoveSpeed; e->aiAction = aiMagicEggAction; } void aiMagicEggInit2(AIEntity *e) { // point all magic egg move frames to the standing one e->movedownFrames = e->moveleftFrames = e->moverightFrames = e->moveupFrames = 1; e->movedownGfx[0] = e->moveupGfx[0] = e->moveleftGfx[0] = e->moverightGfx[0] = e->standdownGfx[0]; e->draw = e->standdownGfx[0]; // standing frame - doesn't move } void aiMagicEggUse(AIEntity *e) { if (!scumm_strnicmp(e->luaFuncAction, "ai_", 3) || !scumm_strnicmp(e->luaFuncAction, "item_", 5)) { AIEntity *spawned = NULL; for (int i = 0; aiEntList[i].type != END_AI_TYPES; ++i) { if (!scumm_stricmp(aiEntList[i].luaName, e->luaFuncAction)) { spawned = g_hdb->_ai->spawn(aiEntList[i].type, e->dir, e->tileX, e->tileY, NULL, NULL, NULL, DIR_NONE, e->level, 0, 0, 1); break; } } if (spawned) { g_hdb->_ai->addAnimateTarget(e->tileX * kTileWidth, e->tileY * kTileHeight, 0, 3, ANIM_NORMAL, false, false, GROUP_EXPLOSION_BOOM_SIT); if (!g_hdb->isDemo()) g_hdb->_sound->playSound(SND_BARREL_EXPLODE); g_hdb->_ai->removeEntity(e); } } } void aiIceBlockAction(AIEntity *e) { // if ice block isn't moving somewhere, don't move it if (!e->goalX) return; g_hdb->_ai->animateEntity(e); } void aiIceBlockInit(AIEntity *e) { e->moveSpeed = kPushMoveSpeed; e->aiAction = aiIceBlockAction; } void aiIceBlockInit2(AIEntity *e) { // point all ice block move frames to the standing one e->movedownFrames = e->moveleftFrames = e->moverightFrames = e->moveupFrames = 1; e->movedownGfx[0] = e->moveupGfx[0] = e->moveleftGfx[0] = e->moverightGfx[0] = e->standdownGfx[0]; e->draw = e->standdownGfx[0]; // standing frame - doesn't move } void aiCabKeyInit(AIEntity *e) { strcpy(e->printedName, "a Cabinet key"); } void aiCabKeyInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiItemChickenInit(AIEntity *e) { strcpy(e->printedName, "Cooper's chicken"); } void aiItemChickenInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiPdaInit(AIEntity *e) { strcpy(e->printedName, "a P.D.A."); e->aiAction = aiGetItemAction; } void aiPdaInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } #if 0 void aiCellUse(AIEntity *e) { g_hdb->_window->openMessageBar("You got the Energy Cell!", kMsgDelay); } #endif void aiCellInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiCellInit(AIEntity *e) { strcpy(e->printedName, "Energy Cell"); e->aiAction = aiGetItemAction; } void aiEnvelopeWhiteInit(AIEntity *e) { strcpy(e->printedName, "White envelope"); e->aiAction = aiGetItemAction; } void aiEnvelopeWhiteInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiEnvelopeBlueInit(AIEntity *e) { strcpy(e->printedName, "Blue envelope"); e->aiAction = aiGetItemAction; } void aiEnvelopeBlueInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiEnvelopeRedInit(AIEntity *e) { strcpy(e->printedName, "Red envelope"); e->aiAction = aiGetItemAction; } void aiEnvelopeRedInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiTransceiverInit(AIEntity *e) { e->aiAction = aiTransceiverAction; strcpy(e->printedName, "Transceiver"); } void aiTransceiverInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiTransceiverAction(AIEntity *e) { aiAnimateStanddown(e, 5); if (e->onScreen) aiGetItemAction(e); } #if 0 void aiTransceiverUse(AIEntity *e) { g_hdb->_window->openMessageBar("You got the Transceiver!", kMsgDelay); } #endif void aiMonkeystoneInit(AIEntity *e) { e->aiUse = aiMonkeystoneUse; e->aiAction = aiMonkeystoneAction; } void aiMonkeystoneAction(AIEntity *e) { if (!e->onScreen) return; AIEntity *p = g_hdb->_ai->getPlayer(); if (abs(p->x - e->x) < 16 && abs(p->y - e->y) < 16 && e->level == p->level) { if (e->luaFuncUse[0]) g_hdb->_lua->callFunction(e->luaFuncUse, 0); g_hdb->_ai->addToInventory(e); aiMonkeystoneUse(NULL); } } void aiMonkeystoneInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiMonkeystoneUse(AIEntity *e) { int val = g_hdb->_ai->getMonkeystoneAmount(); Common::String monkString = Common::String::format("You have %d Monkeystone%s!", val, (val > 1) ? "s" : ""); g_hdb->_sound->playSound(SND_GET_MONKEYSTONE); g_hdb->_window->openMessageBar(monkString.c_str(), kMsgDelay); // have we unlocked a secret star(tm)??? if (val == 7) { g_hdb->_window->openMessageBar("Red Star is Ready!", kMsgDelay * 2); g_hdb->setStarsMonkeystone7(STARS_MONKEYSTONE_7); g_hdb->_menu->writeConfig(); g_hdb->_gfx->turnOnBonusStars(0); } if (val == 14) { g_hdb->_window->openMessageBar("Green Star is GO!", kMsgDelay * 2); g_hdb->setStarsMonkeystone14(STARS_MONKEYSTONE_14); g_hdb->_menu->writeConfig(); g_hdb->_gfx->turnOnBonusStars(1); } if (val == 21) { g_hdb->_window->openMessageBar("Blue Star is Born!", kMsgDelay * 2); g_hdb->setStarsMonkeystone21(STARS_MONKEYSTONE_21); g_hdb->_menu->writeConfig(); g_hdb->_gfx->turnOnBonusStars(2); } } void aiGemAction(AIEntity *e) { e->animFrame++; if (e->animFrame >= e->standdownFrames) { e->animFrame = 0; // every 4th frame, check for player collision & // add to inventory if it happens AIEntity *p = g_hdb->_ai->getPlayer(); int tolerance = 16; if (g_hdb->_ai->playerRunning()) tolerance = 24; if (e->onScreen && abs(p->x - e->x) < tolerance && abs(p->y - e->y) < tolerance && e->level == p->level) { g_hdb->_ai->addAnimateTarget(e->x, e->y, 0, 3, ANIM_NORMAL, false, false, GEM_FLASH); g_hdb->_ai->addToInventory(e); g_hdb->_sound->playSound(SND_GET_GEM); return; } } e->draw = e->standdownGfx[e->animFrame]; } void aiGemWhiteInit(AIEntity *e) { e->aiAction = aiGemAction; } void aiGemWhiteInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiGooCupUse(AIEntity *e) { g_hdb->_window->openMessageBar("Got a... cup of goo.", kMsgDelay); } void aiGooCupInit(AIEntity *e) { e->aiUse = aiGooCupUse; e->aiAction = aiGetItemAction; } void aiGooCupInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiVortexianAction(AIEntity *e) { // anim the alpha blending : down to 32, up to 180, back down... e->value2 += e->value1; if ((e->value2 & 0xff) > 128) { e->value2 = (e->value2 & 0xff00) | 128; e->value1 = -e->value1; } else if ((e->value2 & 0xff) < 32) { e->value2 = (e->value2 & 0xff00) | 32; e->value1 = -e->value1; } // anim the shape e->animFrame++; if (e->animFrame >= e->standdownFrames) { e->animFrame = 0; // every 4th frame, check for player collision & // do an autosave AIEntity *p = g_hdb->_ai->getPlayer(); if (abs(p->x - e->x) < 4 && abs(p->y - e->y) < 4) { if (!(e->value2 & 0xff00)) { // let's make sure we don't autosave every frikken second! e->value2 |= 0xff00; g_hdb->saveWhenReady(kAutoSaveSlot); g_hdb->_window->openMessageBar("Saving progress at Vortexian...", 1); } } else e->value2 &= 0x00ff; } e->draw = e->standdownGfx[e->animFrame]; } void aiVortexianUse(AIEntity *e) { } void aiVortexianInit(AIEntity *e) { e->aiUse = aiVortexianUse; e->aiAction = aiVortexianAction; e->value1 = 5; e->value2 = 128; } void aiVortexianInit2(AIEntity *e) { e->draw = e->standdownGfx[0]; } void aiNoneInit(AIEntity *e) { } // Utility Functions void aiAnimateStanddown(AIEntity *e, int speed) { if (e->value2-- > 0) return; e->value2 = speed; if (e->type == AI_GUY && e->animFrame > 0) e->value2 = 0; e->draw = e->standdownGfx[e->animFrame]; e->animFrame++; if (e->animFrame >= e->standdownFrames) e->animFrame = 0; } void aiGenericAction(AIEntity *e) { if (!e->goalX) g_hdb->_ai->findPath(e); else if (onEvenTile(e->x, e->y)) g_hdb->_sound->playSound(SND_FOOTSTEPS); g_hdb->_ai->animateEntity(e); } void aiGetItemAction(AIEntity *e) { if (!e->onScreen) return; AIEntity *p = g_hdb->_ai->getPlayer(); if (abs(p->x - e->x) < 16 && abs(p->y - e->y) < 16 && e->level == p->level) { if (e->aiUse) e->aiUse(e); if (e->luaFuncUse[0]) g_hdb->_lua->callFunction(e->luaFuncUse, 0); g_hdb->_ai->getItemSound(e->type); g_hdb->_ai->addToInventory(e); } } } // End of Namespace