Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

1
engines/hdb/POTFILES Normal file
View File

@@ -0,0 +1 @@
engines/hdb/metaengine.cpp

3410
engines/hdb/ai-bots.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,896 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "hdb/hdb.h"
#include "hdb/ai.h"
#include "hdb/gfx.h"
#include "hdb/lua-script.h"
#include "hdb/map.h"
#include "hdb/sound.h"
#include "hdb/window.h"
namespace HDB {
static const char *cineTypeStr[] = {
"C_NO_COMMAND",
"C_STOPCINE",
"C_LOCKPLAYER",
"C_UNLOCKPLAYER",
"C_SETCAMERA",
"C_MOVECAMERA",
"C_WAIT",
"C_WAITUNTILDONE",
"C_MOVEENTITY",
"C_DIALOG",
"C_ANIMENTITY",
"C_RESETCAMERA",
"C_SETENTITY",
"C_STARTMAP",
"C_MOVEPIC",
"C_MOVEMASKEDPIC",
"C_DRAWPIC",
"C_DRAWMASKEDPIC",
"C_FADEIN",
"C_FADEOUT",
"C_SPAWNENTITY",
"C_PLAYSOUND",
"C_CLEAR_FG",
"C_SET_FG",
"C_SET_BG",
"C_FUNCTION",
"C_ENTITYFACE",
"C_USEENTITY",
"C_REMOVEENTITY",
"C_SETANIMFRAME",
"C_TEXTOUT",
"C_CENTERTEXTOUT",
"C_PLAYVOICE",
"C_ENDLIST"
};
void AI::processCines() {
if (!_cineActive)
return;
// Make sure Dialogs are timing out
g_hdb->_window->checkDialogClose(0, 0);
// Make sure Cine Pics are drawing
for (int i = 0; i < _numCineBlitList; i++) {
if (_cineBlitList[i]->masked == false)
_cineBlitList[i]->pic->draw(_cineBlitList[i]->x, _cineBlitList[i]->y);
else
_cineBlitList[i]->pic->drawMasked(_cineBlitList[i]->x, _cineBlitList[i]->y);
}
// Check for Game Pause
if (g_hdb->getPause())
return;
bool bailOut = false;
bool complete = false;
for (uint i = 0; i < _cine.size(); i++) {
debug(3, "processCines: [%d] %s now: %d start: %d delay: %d", i, cineTypeStr[_cine[i]->cmdType],
g_system->getMillis(), _cine[i]->start, _cine[i]->delay);
switch (_cine[i]->cmdType) {
case C_STOPCINE:
{
char func[64];
memset(func, 0, 64);
if (_cine[i]->title)
Common::strlcpy(func, _cine[i]->title, 64);
cineCleanup();
if (func[0])
g_hdb->_lua->callFunction(func, 0);
}
break;
case C_STARTMAP:
{
const char *title = _cine[i]->title;
// free all gfx alloc'ed during cine
cineFreeGfx();
_cineActive = false;
_playerLock = false;
_cameraLock = false;
g_hdb->_window->setInfobarDark(0);
g_hdb->_gfx->setPointerState(1);
_cine.resize(0);
_numCineFreeList = 0;
_numCineBlitList = 0;
// if cine is aborted and an abort function was specified, call it
if (_cineAborted && _cineAbortFunc)
g_hdb->_lua->callFunction(_cineAbortFunc, 0);
g_hdb->changeMap(title);
return;
}
break;
case C_LOCKPLAYER:
_playerLock = true;
complete = true;
if (_player)
stopEntity(_player);
clearWaypoints();
break;
case C_UNLOCKPLAYER:
_playerLock = false;
complete = true;
break;
case C_SETCAMERA:
_cameraX = _cine[i]->x;
_cameraY = _cine[i]->y;
g_hdb->_map->centerMapXY((int)_cameraX + 16, (int)_cameraY + 16);
_cameraLock = true;
complete = true;
break;
case C_RESETCAMERA:
{
_cameraLock = false;
int px, py;
g_hdb->_ai->getPlayerXY(&px, &py);
g_hdb->_map->centerMapXY(px + 16, py + 16);
complete = true;
}
break;
case C_MOVECAMERA:
_cameraLock = true;
if (!(_cine[i]->start)) {
debug(3, "C_MOVECAMERA: [%d] now: x: %f, y: %f, speed: %d", i, _cine[i]->x, _cine[i]->y, _cine[i]->speed);
_cine[i]->xv = (((double)_cine[i]->x) - _cameraX) / (double)_cine[i]->speed;
_cine[i]->yv = (((double)_cine[i]->y) - _cameraY) / (double)_cine[i]->speed;
_cine[i]->start = 1;
}
_cameraX += _cine[i]->xv;
_cameraY += _cine[i]->yv;
debug(3, "C_MOVECAMERA: _cine[%d]->xv: %f, _cine[%d]->yv: %f", i, _cine[i]->xv, i, _cine[i]->yv);
debug(3, "C_MOVECAMERA: abs(_cameraX - _cine[i]->x): %f, abs(_cameraY - _cine[i]->y): %f", fabs(_cameraX - _cine[i]->x), fabs(_cameraY - _cine[i]->y));
if (fabs(_cameraX - _cine[i]->x) <= 1 && fabs(_cameraY - _cine[i]->y) <= 1) {
_cameraX = _cine[i]->x;
_cameraY = _cine[i]->y;
complete = true;
}
g_hdb->_map->centerMapXY((int)_cameraX + 16, (int)_cameraY + 16);
break;
case C_WAIT:
if (!(_cine[i]->start)) {
_cine[i]->start = 1;
_cine[i]->delay = g_system->getMillis() + _cine[i]->delay * 1000;
} else if (_cine[i]->delay < g_system->getMillis())
complete = true;
else
bailOut = true;
break;
case C_WAITUNTILDONE:
if (!i)
complete = true;
else
bailOut = true;
break;
case C_SETENTITY:
_cine[i]->e = locateEntity(_cine[i]->string);
if (_cine[i]->e) {
_cine[i]->e->tileX = (int)_cine[i]->x / kTileWidth;
_cine[i]->e->x = (int)_cine[i]->x;
_cine[i]->e->tileY = (int)_cine[i]->y / kTileHeight;
_cine[i]->e->y = (int)_cine[i]->y;
_cine[i]->e->level = (int)_cine[i]->x2;
debug(2, "Found '%s' in setEntity", _cine[i]->string);
} else
warning("Can't locate '%s' in setEntity", _cine[i]->string);
complete = true;
break;
case C_MOVEENTITY:
if (!_cine[i]->start) {
AIEntity *e = locateEntity(_cine[i]->title);
if (e) {
_cine[i]->e = e;
_cine[i]->e->moveSpeed = _cine[i]->speed;
_cine[i]->e->level = (int)_cine[i]->x2;
setEntityGoal(_cine[i]->e, (int)_cine[i]->x, (int)_cine[i]->y);
_cine[i]->start = 1;
} else {
warning("Can't locate '%s' in moveEntity", _cine[i]->title);
// If the entity can't be found, we consider this cinematic command completed
complete = true;
}
} else {
// Fix for bug #16421
// Ensure that the entity _cine[i]->e still exists,
// because it could have been removed, eg. if Guy shoots the chicken in Map 10
AIEntity *e = locateEntity(_cine[i]->title);
if (e) {
_cine[i]->e = e;
debug(3, "C_MOVEENTITY: %d, %s tileX: %d, goalX: %d tileY %d, goalY: %d", i, AIType2Str(_cine[i]->e->type), _cine[i]->e->tileX, _cine[i]->e->goalX, _cine[i]->e->tileY, _cine[i]->e->goalY);
if (!_cine[i]->e->goalX)
complete = true;
} else {
warning("Can't locate '%s' in moveEntity (_cine[%d]->start=%d)", _cine[i]->title, i, _cine[i]->start);
// If the entity can't be found, we consider this cinematic command completed
complete = true;
}
}
break;
case C_ANIMENTITY:
if (!_cine[i]->start) {
AIEntity *e = locateEntity(_cine[i]->title);
if (e) {
_cine[i]->e = e;
e->state = (AIState)_cine[i]->speed;
_cine[i]->start = 1;
if (_cine[i]->end) // Loop ?
complete = true;
e->animFrame = 0;
e->animDelay = e->animCycle;
animEntFrames(e);
} else {
warning("Can't locate '%s' in animEntity", _cine[i]->title);
complete = true;
}
} else {
AIEntity *e = _cine[i]->e;
if (!e->animFrame && e->animDelay == e->animCycle) {
e->state = STATE_STANDDOWN;
e->animFrame = 0;
e->animDelay = e->animCycle;
complete = true;
}
}
break;
case C_SETANIMFRAME:
{
AIEntity *e = locateEntity(_cine[i]->title);
if (e) {
e->state = (AIState)_cine[i]->start;
e->animFrame = _cine[i]->end;
e->animDelay = e->animCycle;
animEntFrames(e);
e->state = STATE_NONE;
complete = true;
}
}
break;
case C_ENTITYFACE:
{
AIEntity *e = locateEntity(_cine[i]->title);
if (e) {
int d = (int)_cine[i]->x;
e->dir = (AIDir)d;
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;
default:
break;
}
} else
warning("Can't find %s to ENTITYFACE", _cine[i]->title);
complete = true;
}
break;
case C_DIALOG:
if (_cine[i]->start) {
g_hdb->_window->openDialog(_cine[i]->title, -1, _cine[i]->string, 0, nullptr);
g_hdb->_window->setDialogDelay(_cine[i]->delay);
_cine[i]->start = 0;
} else if (g_hdb->_window->getDialogDelay() < g_hdb->getTimeSlice())
complete = true;
break;
case C_TEXTOUT:
if (!_cine[i]->start) {
g_hdb->_window->textOut(_cine[i]->title, _cine[i]->x, _cine[i]->y, _cine[i]->end);
_cine[i]->start = 1;
} else if (!g_hdb->_window->textOutActive())
complete = true;
break;
case C_CENTERTEXTOUT:
if (!_cine[i]->start) {
g_hdb->_window->centerTextOut(_cine[i]->title, _cine[i]->y, _cine[i]->end);
_cine[i]->start = 1;
} else if (!g_hdb->_window->textOutActive())
complete = true;
break;
case C_DRAWPIC:
{
Picture *p = cineFindInBlitList(_cine[i]->id);
if (p == nullptr) {
p = g_hdb->_gfx->loadPic(_cine[i]->string);
cineAddToFreeList(p);
cineAddToBlitList(_cine[i]->id, p, (int)_cine[i]->x, (int)_cine[i]->y, false);
}
_cine[i]->pic = p;
_cine[i]->pic->draw((int)_cine[i]->x, (int)_cine[i]->y);
complete = true;
}
break;
case C_DRAWMASKEDPIC:
{
Picture *p = cineFindInBlitList(_cine[i]->id);
if (p == nullptr) {
p = g_hdb->_gfx->loadPic(_cine[i]->string);
cineAddToFreeList(p);
cineAddToBlitList(_cine[i]->id, p, (int)_cine[i]->x, (int)_cine[i]->y, true);
}
_cine[i]->pic = p;
_cine[i]->pic->drawMasked((int)_cine[i]->x, (int)_cine[i]->y);
complete = true;
}
break;
case C_MOVEPIC:
if (!_cine[i]->start) {
Picture *pic = cineFindInBlitList(_cine[i]->id);
if (!pic) {
pic = g_hdb->_gfx->loadPic(_cine[i]->string);
cineAddToFreeList(pic);
} else
cineRemoveFromBlitList(_cine[i]->id);
_cine[i]->pic = pic;
_cine[i]->start = 1;
}
cineRemoveFromBlitList(_cine[i]->id);
_cine[i]->x += _cine[i]->xv;
_cine[i]->y += _cine[i]->yv;
cineAddToBlitList(_cine[i]->id, _cine[i]->pic, (int)_cine[i]->x, (int)_cine[i]->y, false);
if (abs((int)(_cine[i]->x - _cine[i]->x2)) <= 1 && abs((int)(_cine[i]->y - _cine[i]->y2)) <= 1)
complete = true;
break;
case C_MOVEMASKEDPIC:
if (!_cine[i]->start) {
Picture *pic = cineFindInBlitList(_cine[i]->id);
if (!pic) {
pic = g_hdb->_gfx->loadPic(_cine[i]->string);
cineAddToFreeList(pic);
} else
cineRemoveFromBlitList(_cine[i]->id);
_cine[i]->pic = pic;
_cine[i]->start = 1;
}
cineRemoveFromBlitList(_cine[i]->id);
_cine[i]->x += _cine[i]->xv;
_cine[i]->y += _cine[i]->yv;
cineAddToBlitList(_cine[i]->id, _cine[i]->pic, (int)_cine[i]->x, (int)_cine[i]->y, true);
if (abs((int)(_cine[i]->x - _cine[i]->x2)) <= 1 && abs((int)(_cine[i]->y - _cine[i]->y2)) <= 1)
complete = true;
break;
case C_USEENTITY:
for (Common::Array<AIEntity *>::iterator it = _ents->begin(); it != _ents->end(); ++it) {
if (Common::matchString((*it)->entityName, _cine[i]->string, true))
g_hdb->useEntity((*it));
}
for (int k = 0; k < kMaxActions; k++) {
if (Common::matchString(_actions[k].entityName, _cine[i]->string, true)) {
checkActionList(&_dummyPlayer, _actions[k].x1, _actions[k].y1, false);
checkActionList(&_dummyPlayer, _actions[k].x2, _actions[k].y2, false);
}
}
for (int j = 0; j < kMaxAutoActions; j++) {
if (Common::matchString(_autoActions[j].entityName, _cine[i]->string, true) && !_autoActions[j].activated)
checkAutoList(&_dummyPlayer, _autoActions[j].x, _autoActions[j].y);
}
complete = true;
break;
case C_PLAYSOUND:
g_hdb->_sound->playSound((int)_cine[i]->start);
complete = true;
break;
case C_PLAYVOICE:
g_hdb->_sound->playVoice((int)_cine[i]->x, (int)_cine[i]->y);
complete = true;
break;
case C_FADEIN:
if (!_cine[i]->start) {
g_hdb->_gfx->setFade(true, (bool)_cine[i]->end, _cine[i]->speed);
_cine[i]->start = 1;
} else if (!g_hdb->_gfx->isFadeActive())
complete = true;
break;
case C_FADEOUT:
if (!_cine[i]->start) {
g_hdb->_gfx->setFade(false, (bool)_cine[i]->end, _cine[i]->speed);
_cine[i]->start = 1;
} else if (!g_hdb->_gfx->isFadeActive())
complete = true;
break;
case C_SPAWNENTITY:
{
int x2 = (int)_cine[i]->x2;
int y2 = (int)_cine[i]->y2;
spawn((AIType)x2, (AIDir)y2, (int)_cine[i]->x, (int)_cine[i]->y, _cine[i]->title, _cine[i]->string,
_cine[i]->id, (AIDir)_cine[i]->start, (int)_cine[i]->end, (int)_cine[i]->delay, (int)_cine[i]->speed, 1);
complete = true;
}
break;
case C_REMOVEENTITY:
{
AIEntity *e = locateEntity(_cine[i]->string);
if (e)
removeEntity(e);
complete = true;
}
break;
case C_CLEAR_FG:
g_hdb->_map->setMapFGTileIndex((int)_cine[i]->x, (int)_cine[i]->y, -1);
g_hdb->_map->removeFGTileAnimation((int)_cine[i]->x, (int)_cine[i]->y);
complete = true;
break;
case C_SET_BG:
g_hdb->_map->setMapBGTileIndex((int)_cine[i]->x, (int)_cine[i]->y, (int)_cine[i]->start);
g_hdb->_map->addBGTileAnimation((int)_cine[i]->x, (int)_cine[i]->y);
complete = true;
break;
case C_SET_FG:
g_hdb->_map->setMapFGTileIndex((int)_cine[i]->x, (int)_cine[i]->y, (int)_cine[i]->start);
g_hdb->_map->addFGTileAnimation((int)_cine[i]->x, (int)_cine[i]->y);
complete = true;
break;
case C_FUNCTION:
g_hdb->_lua->callFunction(_cine[i]->title, 0);
complete = true;
break;
default:
break;
}
if (bailOut)
return;
if (complete && _cine.size()) {
delete _cine[i];
_cine.remove_at(i);
i--;
complete = false;
}
}
}
void AI::cineCleanup() {
cineFreeGfx();
_cineActive = false;
// If aborted and abort function specified, call it
if (_cineAborted && _cineAbortFunc)
g_hdb->_lua->callFunction(_cineAbortFunc, 0);
_cameraLock = false;
_playerLock = false;
g_hdb->_window->setInfobarDark(0);
g_hdb->_gfx->setPointerState(1);
int px, py;
getPlayerXY(&px, &py);
g_hdb->_map->centerMapXY(px + 16, py + 16);
}
void AI::cineAbort() {
for (uint i = 0; i < _cine.size(); i++) {
if (_cine[i]->cmdType == C_STARTMAP || _cine[i]->cmdType == C_STOPCINE)
_cine[0] = _cine[i];
}
_cine.resize(1);
g_hdb->_window->closeAll();
if (_player)
stopEntity(_player);
_cineAborted = true;
}
void AI::cineAddToBlitList(const char *id, Picture *pic, int x, int y, bool masked) {
_cineBlitList[_numCineBlitList] = new CineBlit;
_cineBlitList[_numCineBlitList]->id = id;
_cineBlitList[_numCineBlitList]->pic = pic;
_cineBlitList[_numCineBlitList]->x = x;
_cineBlitList[_numCineBlitList]->y = y;
_cineBlitList[_numCineBlitList]->masked = masked;
_numCineBlitList++;
}
Picture *AI::cineFindInBlitList(const char *name) {
for (int i = 0; i < _numCineBlitList; i++) {
if (Common::matchString(_cineBlitList[i]->id, name, true))
return _cineBlitList[i]->pic;
}
return nullptr;
}
void AI::cineRemoveFromBlitList(const char *name) {
for (int i = 0; i < _numCineBlitList; i++) {
if (Common::matchString(_cineBlitList[i]->id, name, true)) {
delete _cineBlitList[i];
for (; i < _numCineBlitList - 1; i++)
_cineBlitList[i] = _cineBlitList[i + 1];
_numCineBlitList--;
_cineBlitList[_numCineBlitList] = nullptr;
return;
}
}
}
void AI::cineAddToFreeList(Picture *pic) {
if (_numCineFreeList >= kMaxCineGfx) {
warning("cineAddToFreeList: Too many gfx in Cinematic!");
return;
}
_cineFreeList[_numCineFreeList] = pic;
_numCineFreeList++;
}
void AI::cineFreeGfx() {
for (int i = 0; i < _numCineFreeList; i++)
delete _cineFreeList[i];
_numCineFreeList = 0;
}
void AI::cineStart(bool abortable, const char *abortFunc) {
_cineAbortable = abortable;
_cineAborted = false;
_cineAbortFunc = abortFunc;
_numCineBlitList = 0;
_numCineFreeList = 0;
_cineActive = true;
_playerLock = false;
_cameraLock = false;
_cine.clear();
}
void AI::cineStop(const char *funcNext) {
CineCommand *cmd = new CineCommand;
cmd->cmdType = C_STOPCINE;
cmd->title = funcNext;
_cine.push_back(cmd);
}
void AI::cineStartMap(const char *mapName) {
CineCommand *cmd = new CineCommand;
cmd->cmdType = C_STARTMAP;
cmd->title = mapName;
_cine.push_back(cmd);
}
void AI::cineLockPlayer() {
CineCommand *cmd = new CineCommand;
cmd->cmdType = C_LOCKPLAYER;
_cine.push_back(cmd);
}
void AI::cineUnlockPlayer() {
CineCommand *cmd = new CineCommand;
cmd->cmdType = C_UNLOCKPLAYER;
_cine.push_back(cmd);
}
void AI::cineSetCamera(int x, int y) {
CineCommand *cmd = new CineCommand;
cmd->x = x * kTileWidth;
cmd->y = y * kTileHeight;
cmd->cmdType = C_SETCAMERA;
_cine.push_back(cmd);
}
void AI::cineResetCamera() {
CineCommand *cmd = new CineCommand;
cmd->cmdType = C_RESETCAMERA;
_cine.push_back(cmd);
}
void AI::cineMoveCamera(int x, int y, int speed) {
CineCommand *cmd = new CineCommand;
cmd->start = 0;
cmd->x = x * kTileWidth;
cmd->y = y * kTileHeight;
cmd->speed = speed;
debug(2, "Setting up C_MOVECAMERA: x: %f, y: %f", cmd->x, cmd->y);
cmd->cmdType = C_MOVECAMERA;
_cine.push_back(cmd);
}
void AI::cineWait(int seconds) {
CineCommand *cmd = new CineCommand;
cmd->start = 0;
cmd->cmdType = C_WAIT;
cmd->delay = seconds;
_cine.push_back(cmd);
}
void AI::cineWaitUntilDone() {
CineCommand *cmd = new CineCommand;
cmd->cmdType = C_WAITUNTILDONE;
_cine.push_back(cmd);
}
void AI::cineSetEntity(const char *entName, int x, int y, int level) {
CineCommand *cmd = new CineCommand;
cmd->string = entName;
cmd->x = x * kTileWidth;
cmd->y = y * kTileHeight;
cmd->x2 = level;
cmd->cmdType = C_SETENTITY;
_cine.push_back(cmd);
}
void AI::cineMoveEntity(const char *entName, int x, int y, int level, int speed) {
CineCommand *cmd = new CineCommand;
cmd->x = x;
cmd->y = y;
cmd->x2 = level;
cmd->start = 0;
cmd->speed = speed;
cmd->title = entName;
cmd->cmdType = C_MOVEENTITY;
_cine.push_back(cmd);
}
void AI::cineAnimEntity(const char *entName, AIState state, int loop) {
CineCommand *cmd = new CineCommand;
cmd->start = 0;
cmd->title = entName;
cmd->speed = state;
cmd->end = loop;
cmd->cmdType = C_ANIMENTITY;
_cine.push_back(cmd);
}
void AI::cineSetAnimFrame(const char *entName, AIState state, int frame) {
CineCommand *cmd = new CineCommand;
cmd->start = state;
cmd->title = entName;
cmd->end = frame;
cmd->cmdType = C_SETANIMFRAME;
_cine.push_back(cmd);
}
void AI::cineEntityFace(const char *luaName, double dir) {
CineCommand *cmd = new CineCommand;
cmd->title = luaName;
cmd->x = dir;
cmd->cmdType = C_ENTITYFACE;
_cine.push_back(cmd);
}
void AI::cineSpawnEntity(AIType t, AIDir d, int x, int y, const char *func_init, const char *func_action,
const char *func_use, AIDir d2, int level, int value1, int value2) {
CineCommand *cmd = new CineCommand;
cmd->cmdType = C_SPAWNENTITY;
cmd->x2 = (double)t;
cmd->y2 = (double)d;
cmd->x = (double)x;
cmd->y = (double)y;
cmd->title = func_init;
cmd->string = func_action;
cmd->id = func_use;
cmd->start = (int)d2;
cmd->end = level;
cmd->delay = value1;
cmd->speed = value2;
_cine.push_back(cmd);
}
void AI::cineRemoveEntity(const char *entName) {
CineCommand *cmd = new CineCommand;
cmd->string = entName;
cmd->cmdType = C_REMOVEENTITY;
_cine.push_back(cmd);
}
void AI::cineDialog(const char *title, const char *string, int seconds) {
CineCommand *cmd = new CineCommand;
cmd->title = title;
cmd->string = string;
cmd->delay = seconds;
cmd->start = 1;
if (!title || !string)
warning("cineDialog: Missing Title or Text");
cmd->cmdType = C_DIALOG;
debug(6, "In cineDialog: C_DIALOG created. cmd->start: %d, cmd->title: %s", cmd->start, cmd->title);
_cine.push_back(cmd);
}
void AI::cineTextOut(const char *text, int x, int y, int timer) {
CineCommand *cmd = new CineCommand;
cmd->title = text;
cmd->x = x;
cmd->y = y;
cmd->end = timer;
cmd->start = 0;
cmd->cmdType = C_TEXTOUT;
_cine.push_back(cmd);
}
void AI::cineCenterTextOut(const char *text, int y, int timer) {
CineCommand *cmd = new CineCommand;
cmd->title = text;
cmd->y = y;
cmd->end = timer;
cmd->start = 0;
cmd->cmdType = C_CENTERTEXTOUT;
_cine.push_back(cmd);
}
void AI::cineDrawPic(const char *id, const char *pic, int x, int y) {
if (!pic || !id) {
warning("cineDrawPic: Missing ID or PIC");
return;
}
CineCommand *cmd = new CineCommand;
cmd->x = x;
cmd->y = y;
cmd->string = pic;
cmd->id = id;
cmd->cmdType = C_DRAWPIC;
_cine.push_back(cmd);
}
void AI::cineDrawMaskedPic(const char *id, const char *pic, int x, int y) {
if (!pic || !id) {
warning("cineDrawMaskedPic: Missing ID or PIC");
return;
}
CineCommand *cmd = new CineCommand;
cmd->x = x;
cmd->y = y;
cmd->string = pic;
cmd->id = id;
cmd->cmdType = C_DRAWMASKEDPIC;
_cine.push_back(cmd);
}
void AI::cineMovePic(const char *id, const char *pic, int x1, int y1, int x2, int y2, int speed) {
if (!pic || !id) {
warning("cineMovePic: Missing ID or PIC");
return;
}
CineCommand *cmd = new CineCommand;
cmd->x = x1;
cmd->y = y1;
cmd->x2 = x2;
cmd->y2 = y2;
cmd->speed = speed;
cmd->xv = ((double)(x2-x1)) / (double)speed;
cmd->yv = ((double)(y2-y1)) / (double)speed;
cmd->start = 0;
cmd->string = pic;
cmd->id = id;
cmd->cmdType = C_MOVEPIC;
_cine.push_back(cmd);
}
void AI::cineMoveMaskedPic(const char *id, const char *pic, int x1, int y1, int x2, int y2, int speed) {
if (!pic || !id) {
warning("cineMoveMaskedPic: Missing ID or PIC");
return;
}
CineCommand *cmd = new CineCommand;
cmd->x = x1;
cmd->y = y1;
cmd->x2 = x2;
cmd->y2 = y2;
cmd->speed = speed;
cmd->xv = ((double)(x2-x1)) / (double)speed;
cmd->yv = ((double)(y2-y1)) / (double)speed;
cmd->start = 0;
cmd->string = pic;
cmd->id = id;
cmd->cmdType = C_MOVEMASKEDPIC;
_cine.push_back(cmd);
}
void AI::cineUse(const char *entName) {
CineCommand *cmd = new CineCommand;
cmd->string = entName;
cmd->cmdType = C_USEENTITY;
_cine.push_back(cmd);
}
void AI::cinePlaySound(int index) {
CineCommand *cmd = new CineCommand;
cmd->start = index;
cmd->cmdType = C_PLAYSOUND;
_cine.push_back(cmd);
}
void AI::cinePlayVoice(int index, int actor) {
CineCommand *cmd = new CineCommand;
cmd->x = index;
cmd->y = actor;
cmd->cmdType = C_PLAYVOICE;
_cine.push_back(cmd);
}
void AI::cineFadeIn(bool isBlack, int steps) {
CineCommand *cmd = new CineCommand;
cmd->speed = steps;
cmd->end = (int)isBlack;
cmd->start = 0;
cmd->cmdType = C_FADEIN;
_cine.push_back(cmd);
}
void AI::cineFadeOut(bool isBlack, int steps) {
CineCommand *cmd = new CineCommand;
cmd->speed = steps;
cmd->end = (int)isBlack;
cmd->start = 0;
cmd->cmdType = C_FADEOUT;
_cine.push_back(cmd);
}
void AI::cineClearForeground(int x, int y) {
CineCommand *cmd = new CineCommand;
cmd->x = x;
cmd->y = y;
cmd->cmdType = C_CLEAR_FG;
_cine.push_back(cmd);
}
void AI::cineSetBackground(int x, int y, int index) {
CineCommand *cmd = new CineCommand;
cmd->x = x;
cmd->y = y;
cmd->start = index;
cmd->cmdType = C_SET_BG;
_cine.push_back(cmd);
}
void AI::cineSetForeground(int x, int y, int index) {
CineCommand *cmd = new CineCommand;
cmd->x = x;
cmd->y = y;
cmd->start = index;
cmd->cmdType = C_SET_FG;
_cine.push_back(cmd);
}
void AI::cineFunction(const char *func) {
CineCommand *cmd = new CineCommand;
cmd->title = func;
cmd->cmdType = C_FUNCTION;
_cine.push_back(cmd);
}
} // End of Namespace

2614
engines/hdb/ai-funcs.cpp Normal file

File diff suppressed because it is too large Load Diff

2285
engines/hdb/ai-init.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,317 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "hdb/hdb.h"
#include "hdb/ai.h"
#include "hdb/sound.h"
#include "hdb/window.h"
namespace HDB {
// Add entity to Player's Inventory
bool AI::addToInventory(AIEntity *e) {
switch (e->type) {
case ITEM_GEM_WHITE:
_numGems++;
removeEntity(e);
return true;
case ITEM_GEM_BLUE:
_numGems += 5;
removeEntity(e);
return true;
case ITEM_GEM_RED:
_numGems += 10;
removeEntity(e);
return true;
case ITEM_GEM_GREEN:
_numGems += 100;
removeEntity(e);
return true;
case ITEM_GOO_CUP:
_numGooCups++;
removeEntity(e);
return true;
case ITEM_MONKEYSTONE:
_numMonkeystones++;
removeEntity(e);
return true;
default:
break;
}
if (_numInventory >= kMaxInventory) {
g_hdb->_window->openMessageBar("Your inventory is full.", 5);
return false;
}
_inventory[_numInventory].ent = *e;
_numInventory++;
// If weapon, ready it
switch (e->type) {
case ITEM_CLUB:
case ITEM_ROBOSTUNNER:
case ITEM_SLUGSLINGER:
g_hdb->_window->chooseWeapon(e->type);
default:
break;
}
printYouGotMsg(e->printedName);
removeEntity(e);
return true;
}
void AI::purgeInventory() {
memset(&_inventory, 0, sizeof(InvEnt) * kMaxInventory);
_numInventory = 0;
}
// Clear out the Player inventory except Gems,
// Monkeystones and Goo Cups unless its marked
void AI::clearInventory() {
int keepslot = 0;
for (int i = 0; i < _numInventory; i++) {
if (!_inventory[i].keep) {
_inventory[i].reset();
} else {
if (i != keepslot) {
_inventory[keepslot] = _inventory[i];
_inventory[i].reset();
}
keepslot++;
}
}
_numInventory = keepslot;
}
AIEntity *AI::getInvItem(int which) {
if (which >= _numInventory)
return nullptr;
return &_inventory[which].ent;
}
int AI::queryInventory(const char *string) {
if (!scumm_stricmp(string, "monkeystone"))
return getMonkeystoneAmount();
if (!scumm_stricmp(string, "goo"))
return getGooCupAmount();
if (!scumm_stricmp(string, "gem"))
return getGemAmount();
if (!_numInventory)
return 0;
int count = 0;
for (int i = _numInventory - 1; i >= 0; i--)
if (strstr(_inventory[i].ent.entityName, string))
count++;
return count;
}
bool AI::removeInvItem(const char *string, int amount) {
// Check specially for Gems, Monkeystones and Goo Cups
if (!scumm_stricmp(string, "gem")) {
_numGems -= amount;
return true;
} else if (!scumm_stricmp(string, "monkeystone")) {
_numMonkeystones -= amount;
return true;
} else if (!scumm_stricmp(string, "goo")) {
_numGooCups -= amount;
return true;
}
if (!_numInventory)
return false;
bool found;
do {
found = false;
for (int i = _numInventory - 1; i >= 0; i--)
if (strstr(_inventory[i].ent.entityName, string)) {
int j = i;
_inventory[j].reset();
while (j < _numInventory - 1) {
_inventory[j] = _inventory[j + 1];
_inventory[j + 1].reset();
j++;
}
_numInventory--;
amount--;
found = true;
if (!amount)
break;
}
} while (found && amount);
// if we haven't removed them all, return false
if (amount)
return false;
return true;
}
int AI::queryInventoryType(AIType which) {
if (which == ITEM_MONKEYSTONE)
return getMonkeystoneAmount();
if (which == ITEM_GOO_CUP)
return getGooCupAmount();
if (which == ITEM_GEM_WHITE)
return getGemAmount();
if (!_numInventory)
return 0;
int count = 0;
for (int i = 0; i < _numInventory; i++) {
if (_inventory[i].ent.type == which)
count++;
}
return count;
}
int AI::queryInventoryTypeSlot(AIType which) {
if (!_numInventory)
return 0;
for (int i = 0; i < _numInventory; i++) {
if (_inventory[i].ent.type == which)
return i;
}
return -1;
}
bool AI::removeInvItemType(AIType which, int amount) {
// Check specially for Gems, Monkeystones and Goo Cups
if (which == ITEM_GEM_WHITE) {
_numGems -= amount;
return true;
} else if (which == ITEM_MONKEYSTONE) {
_numMonkeystones -= amount;
return true;
} else if (which == ITEM_GOO_CUP) {
_numGooCups -= amount;
return true;
}
if (!_numInventory)
return false;
bool found;
do {
found = false;
for (int i = 0; i < _numInventory; i++) {
if (_inventory[i].ent.type == which) {
int j = i;
_inventory[j].reset();
while (j < _numInventory - 1) {
_inventory[j] = _inventory[j + 1];
_inventory[j + 1].reset();
j++;
}
_numInventory--;
amount--;
found = true;
if (!amount)
break;
}
}
} while (found && amount);
// if we haven't removed them all, return false
if (amount)
return false;
return true;
}
bool AI::addItemToInventory(AIType type, int amount, const char *funcInit, const char *funcAction, const char *funcUse) {
for (int i = 0; i < amount; i++) {
spawn(type, DIR_UP, 0, 0, funcInit, funcAction, funcUse, DIR_UP, 1, 0, 0, 1);
AIEntity *e = findEntity(0, 0);
if (!e)
return false;
if (!addToInventory(e))
return false;
}
return true;
}
void AI::keepInvItem(AIType type) {
for (int i = 0; i < _numInventory; i++) {
if (_inventory[i].ent.type == type)
_inventory[i].keep = 1;
}
}
void AI::printYouGotMsg(const char *name) {
if (!name || !name[0])
return;
Common::String youGotString = Common::String::format("Got %s", name);
g_hdb->_window->textOut(youGotString.c_str(), kYouGotX, g_hdb->_ai->_youGotY, 120);
}
void AI::newDelivery(const char *itemTextName, const char *itemGfxName, const char *destTextName, const char *destGfxName, const char *id) {
int i = _numDeliveries;
if (i == kMaxDeliveries) {
g_hdb->_window->openMessageBar("You have too many deliveries already!", 3);
return;
}
if (itemTextName)
Common::strlcpy(_deliveries[i].itemTextName, itemTextName, sizeof(_deliveries[0].itemTextName));
if (itemGfxName)
Common::strlcpy(_deliveries[i].itemGfxName, itemGfxName, sizeof(_deliveries[0].itemGfxName));
if (destTextName)
Common::strlcpy(_deliveries[i].destTextName, destTextName, sizeof(_deliveries[0].destTextName));
if (destGfxName)
Common::strlcpy(_deliveries[i].destGfxName, destGfxName, sizeof(_deliveries[0].destGfxName));
Common::strlcpy(_deliveries[i].id, id, sizeof(_deliveries[0].id));
_numDeliveries++;
g_hdb->_window->openDeliveries(true);
}
bool AI::completeDelivery(const char *id) {
for (int i = 0; i < _numDeliveries; i++) {
if (!scumm_stricmp(_deliveries[i].id, id)) {
for (; i < _numDeliveries; i++)
_deliveries[i] = _deliveries[i + 1];
_numDeliveries--;
if (g_hdb->isPPC())
g_hdb->_sound->playSound(SND_QUEST_COMPLETE);
else
g_hdb->_sound->playVoice(GUY_COMPLETED, 1);
return true;
}
}
return false;
}
} // End of Namespace

864
engines/hdb/ai-lists.cpp Normal file
View File

@@ -0,0 +1,864 @@
/* 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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "hdb/hdb.h"
#include "hdb/ai.h"
#include "hdb/ai-player.h"
#include "hdb/file-manager.h"
#include "hdb/gfx.h"
#include "hdb/lua-script.h"
#include "hdb/map.h"
#include "hdb/sound.h"
#include "hdb/window.h"
namespace HDB {
/*
Adds a tile to an animation list
*/
void AI::addAnimateTarget(int x, int y, int start, int end, AnimSpeed speed, bool killAuto, bool inMap, const char *tileName) {
AnimTarget *at = new AnimTarget;
at->x = x;
at->y = y;
at->start = start;
at->end = end;
at->killAuto = killAuto; // Doesn't actually kill it, deactivates it
// Set animCycle and animFrame as per speed
switch (speed) {
case ANIM_SLOW:
at->animCycle = 10;
at->animFrame = 10;
break;
case ANIM_NORMAL:
default:
at->animCycle = 6;
at->animFrame = 6;
break;
case ANIM_FAST:
at->animCycle = 2;
at->animFrame = 2;
break;
}
// Set +1/-1 for tile anim direction
if ((end - start) > 0)
at->vel = 1;
else
at->vel = -1;
// Set Info if this is not an inMap animation
at->inMap = inMap;
if (!inMap) {
char name[32];
for (int i = start; i <= end; i++) {
if (i < 10)
snprintf(name, 32, "%s0%d", tileName, i + 1);
else
snprintf(name, 32, "%s%d", tileName, i + 1);
uint32 size = g_hdb->_fileMan->getLength(name, TYPE_TILE32);
at->gfxList[i] = g_hdb->_gfx->getTileGfx(name, size);
}
}
// Insert in the beginning
_animTargets.insert_at(0, at);
}
/*
Animate _animTargets
Called every frame
*/
void AI::animateTargets() {
int mx, my;
g_hdb->_map->getMapXY(&mx, &my);
for (uint i = 0; i < _animTargets.size(); i++) {
AnimTarget *at = _animTargets[i];
debug(9, "AnimTarget #%i: at: at->x: %d, at->y: %d, at->start: %d, at->end: %d, at->vel: %d", i, at->x, at->y, at->start, at->end, at->vel);
// Draw Non-map stuff every frame
if (!at->inMap)
// FIXME: Out of bounds reference to gfxList
at->gfxList[at->start]->drawMasked(at->x - mx, at->y - my);
// Frame Timer
if (at->animFrame-- < 1) {
at->animFrame = at->animCycle;
if (at->inMap) {
// Animate Map Tiles
int layer = 0; // BG layer
if (!(at->start == g_hdb->_map->getMapBGTileIndex(at->x, at->y)))
layer = 1;
// Change Tile Anim
at->start += at->vel;
// Set it back in map
if (!layer)
g_hdb->_map->setMapBGTileIndex(at->x, at->y, at->start);
else
g_hdb->_map->setMapFGTileIndex(at->x, at->y, at->start);
} else {
// Animate non-map tiles
at->start++;
}
// Animation Finished ?
if (at->start == at->end) {
if (at->killAuto)
autoDeactivate(at->x, at->y);
delete _animTargets[i];
_animTargets.remove_at(i);
i--;
continue;
}
}
}
}
void AI::addBridgeExtend(int x, int y, int bridgeType) {
if (_numBridges >= kMaxBridges)
return;
if (bridgeType == _targetBridgeU)
_bridges[_numBridges].dir = DIR_UP;
else if (bridgeType == _targetBridgeD)
_bridges[_numBridges].dir = DIR_DOWN;
else if (bridgeType == _targetBridgeL)
_bridges[_numBridges].dir = DIR_LEFT;
else if (bridgeType == _targetBridgeR)
_bridges[_numBridges].dir = DIR_RIGHT;
_bridges[_numBridges].delay = 5;
_bridges[_numBridges].x = x;
_bridges[_numBridges].y = y;
_bridges[_numBridges].anim = 0;
if (g_hdb->_map->onScreen(_bridges[_numBridges].x, _bridges[_numBridges].y))
g_hdb->_sound->playSound(SND_BRIDGE_START);
_numBridges++;
}
void AI::animateBridges() {
// out quick!
if (!_numBridges)
return;
for (int i = 0; i < _numBridges; i++) {
if (_bridges[i].delay-- > 0)
continue;
_bridges[i].delay = 5;
bool done = false;
int xv = 0;
int yv = 0;
switch (_bridges[i].dir) {
case DIR_UP:
g_hdb->_map->setMapFGTileIndex(_bridges[i].x, _bridges[i].y, _targetBridgeU + _bridges[i].anim);
_bridges[i].anim++;
if (_bridges[i].anim > 2) {
g_hdb->_map->setMapFGTileIndex(_bridges[i].x, _bridges[i].y, _targetBridgeMidUD);
yv = -1;
done = true;
}
break;
case DIR_DOWN:
g_hdb->_map->setMapFGTileIndex(_bridges[i].x, _bridges[i].y, _targetBridgeD + _bridges[i].anim);
_bridges[i].anim++;
if (_bridges[i].anim > 2) {
g_hdb->_map->setMapFGTileIndex(_bridges[i].x, _bridges[i].y, _targetBridgeMidUD);
yv = 1;
done = true;
}
break;
case DIR_LEFT:
g_hdb->_map->setMapFGTileIndex(_bridges[i].x, _bridges[i].y, _targetBridgeL + _bridges[i].anim);
_bridges[i].anim++;
if (_bridges[i].anim > 2) {
g_hdb->_map->setMapFGTileIndex(_bridges[i].x, _bridges[i].y, _targetBridgeMidLR);
xv = -1;
done = true;
}
break;
case DIR_RIGHT:
g_hdb->_map->setMapFGTileIndex(_bridges[i].x, _bridges[i].y, _targetBridgeR + _bridges[i].anim);
_bridges[i].anim++;
if (_bridges[i].anim > 2) {
g_hdb->_map->setMapFGTileIndex(_bridges[i].x, _bridges[i].y, _targetBridgeMidLR);
xv = 1;
done = true;
}
break;
case DIR_NONE:
default:
break;
}
// is this bridge done extending one chunk?
if (done) {
if (g_hdb->_map->onScreen(_bridges[i].x, _bridges[i].y))
g_hdb->_sound->playSound(SND_BRIDGE_EXTEND);
_bridges[i].anim = 0;
_bridges[i].x += xv;
_bridges[i].y += yv;
int tileIndex = g_hdb->_map->getMapFGTileIndex(_bridges[i].x, _bridges[i].y);
uint32 flags = g_hdb->_map->getMapBGTileFlags(_bridges[i].x, _bridges[i].y);
if (!flags || (flags & kFlagMetal) || tileIndex >= 0 || (flags & kFlagSolid)) {
if (g_hdb->_map->onScreen(_bridges[i].x, _bridges[i].y))
g_hdb->_sound->playSound(SND_BRIDGE_END);
// TODO: CHECKME - Using i as an index looks very wrong as the for statement uses j.
// This results in copying multiple times the same data
for (int j = 0; j < _numBridges - 1; j++)
memcpy(&_bridges[i], &_bridges[i + 1], sizeof(Bridge));
_numBridges--;
}
}
}
}
void AI::addToFairystones(int index, int tileX, int tileY, int sourceOrDest) {
if (!sourceOrDest) {
_fairystones[index].srcX = tileX;
_fairystones[index].srcY = tileY;
} else {
_fairystones[index].destX = tileX;
_fairystones[index].destY = tileY;
}
}
int AI::checkFairystones(int tileX, int tileY) {
for (int i = 0; i < kMaxFairystones; i++) {
if (_fairystones[i].destX == tileX && _fairystones[i].destY == tileY)
return i;
}
return -1;
}
// Add an action location to the list of possible actions
// Each action must be paired with another of the same number
void AI::addToActionList(int actionIndex, int x, int y, char *luaFuncInit, char *luaFuncUse) {
if (!_actions[actionIndex].x1) {
_actions[actionIndex].x1 = x;
_actions[actionIndex].y1 = y;
if (luaFuncInit[0] != '*')
Common::strlcpy(_actions[actionIndex].luaFuncInit, luaFuncInit, 32);
if (luaFuncUse[0] != '*')
Common::strlcpy(_actions[actionIndex].luaFuncUse, luaFuncUse, 32);
if (_actions[actionIndex].luaFuncInit[0]) {
g_hdb->_lua->callFunction(_actions[actionIndex].luaFuncInit, 2);
Common::strlcpy(_actions[actionIndex].entityName, g_hdb->_lua->getStringOffStack(), 32);
Common::strlcpy(_actions[actionIndex].entityName, g_hdb->_lua->getStringOffStack(), 32);
}
return;
}
if (!_actions[actionIndex].x2) {
_actions[actionIndex].x2 = x;
_actions[actionIndex].y2 = y;
if (luaFuncInit[0] != '*')
Common::strlcpy(_actions[actionIndex].luaFuncInit, luaFuncInit, 32);
if (luaFuncUse[0] != '*')
Common::strlcpy(_actions[actionIndex].luaFuncUse, luaFuncUse, 32);
if (_actions[actionIndex].luaFuncInit[0]) {
g_hdb->_lua->callFunction(_actions[actionIndex].luaFuncInit, 2);
Common::strlcpy(_actions[actionIndex].entityName, g_hdb->_lua->getStringOffStack(), 32);
Common::strlcpy(_actions[actionIndex].entityName, g_hdb->_lua->getStringOffStack(), 32);
}
return;
}
warning("Adding a 3rd action to ACTION-%d is illegal", actionIndex);
}
// Checks if the location passed-in matches an action pair.
// If so, activate it if possible. Returns TRUE for finding pair.
bool AI::checkActionList(AIEntity *e, int x, int y, bool lookAndGrab) {
for (int i = 0; i < kMaxActions; i++) {
if ((_actions[i].x1 == x && _actions[i].y1 == y) || (_actions[i].x2 == x && _actions[i].y2 == y)) {
int targetX = _actions[i].x2;
int targetY = _actions[i].y2;
bool success;
// Choose target co-ordinates
if (x == targetX && y == targetY) {
targetX = _actions[i].x1;
targetY = _actions[i].y1;
}
// Is this an actual switch?
uint32 flags = g_hdb->_map->getMapFGTileFlags(x, y);
if (!flags)
flags = g_hdb->_map->getMapBGTileFlags(x, y);
if (!(flags & kFlagSolid) && (_player->tileX != x && _player->tileY != y))
return false;
// Closing on something?
if (findEntity(targetX, targetY))
return false;
success = activateAction(e, x, y, targetX, targetY);
// If successful, remove action from list
if (success) {
_actions[i].x1 = _actions[i].y1 = _actions[i].x2 = _actions[i].y2 = 0;
// Call Lua Use function if it exists
if (_actions[i].luaFuncUse[0]) {
g_hdb->_lua->callFunction(_actions[i].luaFuncUse, 0);
}
} else if (e == _player && !checkForTouchplate(x, y))
addWaypoint(e->tileX, e->tileY, x, y, e->level);
if (lookAndGrab && e == _player) {
lookAtXY(x, y);
animGrabbing();
}
return true;
}
}
return false;
}
void AI::addToHereList(const char *entName, int x, int y) {
HereT *h = new HereT;
Common::strlcpy(h->entName, entName, 32);
h->x = x;
h->y = y;
_hereList->push_back(h);
}
HereT *AI::findHere(int x, int y) {
for (Common::Array<HereT *>::iterator it = _hereList->begin(); it != _hereList->end(); ++it) {
if ((*it)->x == x && (*it)->y == y)
return *it;
}
return nullptr;
}
void AI::addToAutoList(int x, int y, const char *luaFuncInit, const char *luaFuncUse) {
for (int i = 0; i < kMaxAutoActions; i++) {
if (!_autoActions[i].x) {
_autoActions[i].x = x;
_autoActions[i].y = y;
_autoActions[i].activated = false;
if (luaFuncInit[0] != '*')
Common::strlcpy(&_autoActions[i].luaFuncInit[0], luaFuncInit, 32);
if (luaFuncUse[0] != '*')
Common::strlcpy(&_autoActions[i].luaFuncUse[0], luaFuncUse, 32);
if (_autoActions[i].luaFuncInit[0]) {
g_hdb->_lua->callFunction(_autoActions[i].luaFuncInit, 2);
const char *get = g_hdb->_lua->getStringOffStack();
if (!get)
return;
Common::strlcpy(&_autoActions[i].entityName[0], get, 32);
get = g_hdb->_lua->getStringOffStack();
if (!get)
return;
Common::strlcpy(&_autoActions[i].entityName[0], get, 32);
}
return;
}
}
}
void AI::autoDeactivate(int x, int y) {
for (int i = 0; i < kMaxAutoActions; i++) {
if (_autoActions[i].x == x && _autoActions[i].y == y) {
_autoActions[i].activated = false;
return;
}
}
}
bool AI::activateAction(AIEntity *e, int x, int y, int targetX, int targetY) {
bool success = false;
int tileIndex = g_hdb->_map->getMapFGTileIndex(x, y);
// If FG tile invisivle or grating, ignore if
int fgFlags = g_hdb->_map->getMapFGTileFlags(x, y);
if (fgFlags & (kFlagInvisible | kFlagGrating))
tileIndex = -1;
if (tileIndex < 0)
tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
// Check which tile is going to activate
if (tileIndex == _useSwitchOff || tileIndex == _useSwitchOff + 1)
success = useSwitch(e, x, y, targetX, targetY, _useSwitchOn);
else if (tileIndex == _useSwitchOn)
success = useSwitchOn(e, x, y, targetX, targetY, _useSwitchOff);
//-------------------------------------------------------------------
else if (tileIndex == _useHandswitchOff || tileIndex == _useHandswitchOff + 1)
success = useSwitch(e, x, y, targetX, targetY, _useHandswitchOn);
else if (tileIndex == _useHandswitchOn)
success = useSwitchOn(e, x, y, targetX, targetY, _useHandswitchOff);
//-------------------------------------------------------------------
else if (tileIndex == _kcHolderWhiteOff || tileIndex == _kcHolderWhiteOff + 1)
success = useLockedSwitch(e, x, y, targetX, targetY, _kcHolderWhiteOn, ITEM_KEYCARD_WHITE, "I need a White Keycard.");
else if (tileIndex == _kcHolderWhiteOn)
success = useLockedSwitchOn(e, x, y, targetX, targetY, _kcHolderWhiteOff, ITEM_KEYCARD_WHITE);
else if (tileIndex == _kcHolderBlueOff || tileIndex == _kcHolderBlueOff + 1)
success = useLockedSwitch(e, x, y, targetX, targetY, _kcHolderBlueOn, ITEM_KEYCARD_BLUE, "I need a Blue Keycard.");
else if (tileIndex == _kcHolderBlueOn)
success = useLockedSwitchOn(e, x, y, targetX, targetY, _kcHolderBlueOff, ITEM_KEYCARD_BLUE);
else if (tileIndex == _kcHolderRedOff || tileIndex == _kcHolderRedOff + 1)
success = useLockedSwitch(e, x, y, targetX, targetY, _kcHolderRedOn, ITEM_KEYCARD_RED, "I need a Red Keycard.");
else if (tileIndex == _kcHolderRedOn)
success = useLockedSwitchOn(e, x, y, targetX, targetY, _kcHolderRedOff, ITEM_KEYCARD_RED);
else if (tileIndex == _kcHolderGreenOff || tileIndex == _kcHolderGreenOff + 1)
success = useLockedSwitch(e, x, y, targetX, targetY, _kcHolderGreenOn, ITEM_KEYCARD_GREEN, "I need a Green Keycard.");
else if (tileIndex == _kcHolderGreenOn)
success = useLockedSwitchOn(e, x, y, targetX, targetY, _kcHolderGreenOff, ITEM_KEYCARD_GREEN);
else if (tileIndex == _kcHolderPurpleOff || tileIndex == _kcHolderPurpleOff + 1)
success = useLockedSwitch(e, x, y, targetX, targetY, _kcHolderPurpleOn, ITEM_KEYCARD_PURPLE, "I need a Purple Keycard.");
else if (tileIndex == _kcHolderPurpleOn)
success = useLockedSwitchOn(e, x, y, targetX, targetY, _kcHolderPurpleOff, ITEM_KEYCARD_PURPLE);
else if (tileIndex == _kcHolderBlackOff || tileIndex == _kcHolderBlackOff + 1)
success = useLockedSwitch(e, x, y, targetX, targetY, _kcHolderBlackOn, ITEM_KEYCARD_BLACK, "I need a Black Keycard.");
else if (tileIndex == _kcHolderBlackOn)
success = useLockedSwitchOn(e, x, y, targetX, targetY, _kcHolderBlackOff, ITEM_KEYCARD_BLACK);
//-------------------------------------------------------------------
else if (tileIndex == _useSwitch2Off || tileIndex == _useSwitch2Off + 1)
success = useSwitch2(e, x, y, targetX, targetY);
else if (tileIndex == _useHolderEmpty || tileIndex == _useHolderEmpty + 1)
success = useCellHolder(e, x, y, targetX, targetY);
//-------------------------------------------------------------------
else if (tileIndex == _targetDoorN || tileIndex == _targetDoorN + 3)
success = useAutoDoorOpenClose(e, x, y);
else if (tileIndex == _targetDoorP || tileIndex == _targetDoorP + 3)
success = useDoorOpenCloseBot(e, x, y);
else if (tileIndex == _targetDoorS || tileIndex == _targetDoorS + 3)
success = useDoorOpenCloseBot(e, x, y);
else if (tileIndex == _targetDoorNv || tileIndex == _targetDoorNv + 3)
success = useAutoDoorOpenClose(e, x, y);
else if (tileIndex == _targetDoorPv || tileIndex == _targetDoorPv + 3)
success = useDoorOpenCloseBot(e, x, y);
else if (tileIndex == _targetDoorSv || tileIndex == _targetDoorSv + 3)
success = useDoorOpenCloseBot(e, x, y);
//-------------------------------------------------------------------
else if (tileIndex == _targetDoorN || tileIndex == _targetDoor2N + 3)
success = useAutoDoorOpenClose(e, x, y);
else if (tileIndex == _targetDoorP || tileIndex == _targetDoor2P + 3)
success = useDoorOpenCloseBot(e, x, y);
else if (tileIndex == _targetDoorS || tileIndex == _targetDoor2S + 3)
success = useDoorOpenCloseBot(e, x, y);
else if (tileIndex == _targetDoorNv || tileIndex == _targetDoor2Nv + 3)
success = useAutoDoorOpenClose(e, x, y);
else if (tileIndex == _targetDoorPv || tileIndex == _targetDoor2Pv + 3)
success = useDoorOpenCloseBot(e, x, y);
else if (tileIndex == _targetDoorSv || tileIndex == _targetDoor2Sv + 3)
success = useDoorOpenCloseBot(e, x, y);
//-------------------------------------------------------------------
else if (tileIndex == _touchplateOff)
success = useTouchplate(e, x, y, targetX, targetY, _touchplateOn);
else if (tileIndex == _touchplateOn)
success = useTouchplateOn(e, x, y, targetX, targetY, _touchplateOff);
else if (tileIndex == _templeTouchpOff)
success = useTouchplate(e, x, y, targetX, targetY, _templeTouchpOn);
else if (tileIndex == _templeTouchpOn)
success = useTouchplateOn(e, x, y, targetX, targetY, _templeTouchpOff);
return success;
}
bool AI::checkAutoList(AIEntity *e, int x, int y) {
for (int i = 0; i < kMaxAutoActions; i++) {
if (_autoActions[i].x == x && _autoActions[i].y == y && !_autoActions[i].activated) {
debug(1, "Activating action for Entity: %s, x: %d, y: %d", e->entityName, x, y);
bool success = activateAction(e, x, y, 0, 0);
_autoActions[i].activated = true;
if (success && _autoActions[i].luaFuncUse[0])
g_hdb->_lua->callFunction(_autoActions[i].luaFuncUse, 0);
if (e == _player) {
lookAtXY(x, y);
animGrabbing();
}
return true;
}
}
return false;
}
bool AI::autoActive(int x, int y) {
for (int i = 0; i < kMaxAutoActions; i++) {
if (_autoActions[i].x == x && _autoActions[i].y == y) {
if (!_autoActions[i].activated)
return false;
return true;
}
}
return false;
}
CallbackDef allCallbacks[] = {
{NO_FUNCTION, nullptr},
{AI_BARREL_EXPLOSION_END, callbackAiBarrelExplosionEnd},
{CALLBACK_DOOR_OPEN_CLOSE, callbackDoorOpenClose},
{CALLBACK_AUTODOOR_OPEN_CLOSE, callbackAutoDoorOpenClose},
{CALLBACK_END, nullptr}
};
void AI::addCallback(CallbackType type, int x, int y, int delay) {
for (int i = kMaxCallbacks - 1; i >= 0; i--)
if (_callbacks[i].type == NO_FUNCTION) {
_callbacks[i].type = type;
_callbacks[i].x = x;
_callbacks[i].y = y;
_callbacks[i].delay = delay;
return;
}
}
void AI::processCallbackList() {
for (int i = 0; i < kMaxCallbacks; i++)
if (_callbacks[i].type != NO_FUNCTION) {
if (_callbacks[i].delay) {
_callbacks[i].delay--;
return;
}
allCallbacks[_callbacks[i].type].function(_callbacks[i].x, _callbacks[i].y);
_callbacks[i].type = NO_FUNCTION;
_callbacks[i].x = _callbacks[i].y = 0;
return;
}
}
void AI::addToLuaList(int x, int y, int value1, int value2, char *luaFuncInit, char *luaFuncAction, char *luaFuncUse) {
for (int i = 0; i < kMaxLuaEnts; i++) {
if (!_luaList[i].luaFuncInit[0] && !_luaList[i].luaFuncAction[0] && !_luaList[i].luaFuncUse[0]) {
_luaList[i].x = x;
_luaList[i].y = y;
_luaList[i].value1 = value1;
_luaList[i].value2 = value2;
Common::strlcpy(_luaList[i].luaFuncInit, luaFuncInit, 32);
if (luaFuncInit[0] == '*')
_luaList[i].luaFuncInit[0] = 0;
Common::strlcpy(_luaList[i].luaFuncAction, luaFuncAction, 32);
if (luaFuncAction[0] == '*')
_luaList[i].luaFuncAction[0] = 0;
Common::strlcpy(_luaList[i].luaFuncUse, luaFuncUse, 32);
if (luaFuncUse[0] == '*')
_luaList[i].luaFuncUse[0] = 0;
_numLuaList++;
if (_luaList[i].luaFuncInit[0])
g_hdb->_lua->invokeLuaFunction(luaFuncInit, x, y, value1, value2);
spawnBlocking(x, y, 1);
return;
}
}
}
bool AI::checkLuaList(AIEntity *e, int x, int y) {
for (int i = 0; i < _numLuaList; i++) {
if (_luaList[i].x == x && _luaList[i].y == y && _luaList[i].luaFuncUse[0]) {
if (e == _player) {
lookAtXY(x, y);
animGrabbing();
}
g_hdb->_lua->invokeLuaFunction(_luaList[i].luaFuncUse, _luaList[i].x, _luaList[i].y, _luaList[i].value1, _luaList[i].value2);
return true;
}
}
return false;
}
bool AI::luaExistAtXY(int x, int y) {
for (int i = 0; i < _numLuaList; i++) {
if (_luaList[i].x == x && _luaList[i].y == y && _luaList[i].luaFuncUse[0]) {
return true;
}
}
return false;
}
void AI::addToTeleportList(int teleIndex, int x, int y, int dir, int level, int anim, int usable, const char *luaFuncUse) {
if (!level)
level = 1;
if (!_teleporters[teleIndex].x1) {
_teleporters[teleIndex].x1 = x;
_teleporters[teleIndex].y1 = y;
_teleporters[teleIndex].dir1 = (AIDir)dir;
_teleporters[teleIndex].level1 = level;
_teleporters[teleIndex].anim1 = anim;
_teleporters[teleIndex].usable1 = usable;
Common::strlcpy(_teleporters[teleIndex].luaFuncUse1, luaFuncUse, 32);
if (_teleporters[teleIndex].luaFuncUse1[0] == '*')
_teleporters[teleIndex].luaFuncUse1[0] = 0;
_numTeleporters++;
return;
}
if (!_teleporters[teleIndex].x2) {
_teleporters[teleIndex].x2 = x;
_teleporters[teleIndex].y2 = y;
_teleporters[teleIndex].dir2 = (AIDir)dir;
_teleporters[teleIndex].level2 = level;
_teleporters[teleIndex].anim2 = anim;
_teleporters[teleIndex].usable2 = usable;
Common::strlcpy(_teleporters[teleIndex].luaFuncUse2, luaFuncUse, 32);
if (_teleporters[teleIndex].luaFuncUse2[0] == '*')
_teleporters[teleIndex].luaFuncUse2[0] = 0;
_numTeleporters++;
return;
}
warning("addToTeleporterList: Adding a 3rd teleporter is illegal");
}
bool AI::findTeleporterDest(int tileX, int tileY, SingleTele *info) {
for (int i = 0; i < _numTeleporters; i++) {
if ((_teleporters[i].x1 == tileX) && (_teleporters[i].y1 == tileY)) {
info->anim = _teleporters[i].anim2;
info->x = _teleporters[i].x2;
info->y = _teleporters[i].y2;
info->dir = _teleporters[i].dir2;
info->level = _teleporters[i].level2;
info->usable = _teleporters[i].usable2;
return true;
}
if ((_teleporters[i].x2 == tileX) && (_teleporters[i].y2 == tileY)) {
info->anim = _teleporters[i].anim1;
info->x = _teleporters[i].x1;
info->y = _teleporters[i].y1;
info->dir = _teleporters[i].dir1;
info->level = _teleporters[i].level1;
info->usable = _teleporters[i].usable1;
return true;
}
}
return false;
}
bool AI::checkTeleportList(AIEntity *e, int x, int y) {
for (int i = 0; i < kMaxTeleporters; i++) {
if ((_teleporters[i].x1 == x && _teleporters[i].y1 == y) || (_teleporters[i].x2 == x && _teleporters[i].y2 == y)) {
int targetX = _teleporters[i].x1;
int targetY = _teleporters[i].y1;
int targetX2 = _teleporters[i].x2;
int targetY2 = _teleporters[i].y2;
//AIDir dir1 = _teleporters[i].dir1;
AIDir dir2 = _teleporters[i].dir2;
//int level1 = _teleporters[i].level1;
int level2 = _teleporters[i].level2;
int usable1 = _teleporters[i].usable1;
//int usable2 = _teleporters[i].usable2;
int anim1 = _teleporters[i].anim1;
int anim2 = _teleporters[i].anim2;
//const char *luaFuncUse1 = _teleporters[i].luaFuncUse1;
const char *luaFuncUse2 = _teleporters[i].luaFuncUse2;
// Choose which set of co-ordinates is the target
if (x != targetX || y != targetY) {
targetX = _teleporters[i].x2;
targetY = _teleporters[i].y2;
targetX2 = _teleporters[i].x1;
targetY2 = _teleporters[i].y1;
//dir1 = _teleporters[i].dir2;
dir2 = _teleporters[i].dir1;
//level1 = _teleporters[i].level2;
level2 = _teleporters[i].level1;
usable1 = _teleporters[i].usable2;
//usable2 = _teleporters[i].usable1;
anim1 = _teleporters[i].anim2;
anim2 = _teleporters[i].anim1;
//luaFuncUse1 = _teleporters[i].luaFuncUse2;
luaFuncUse2 = _teleporters[i].luaFuncUse1;
}
// We must be exactly on the teleporter
if (abs(targetX*kTileWidth - e->x) > 2 || abs(targetY*kTileHeight - e->y) > 2)
return false;
// Can this teleporter be used?
if (usable1)
return false;
// Move Entity to new Spot, then walk forward one tile
e->tileX = targetX2;
e->tileY = targetY2;
e->x = targetX2 * kTileWidth;
e->y = targetY2 * kTileHeight;
e->xVel = e->yVel = 0;
e->goalX = e->goalY = 0;
e->animFrame = 0;
e->drawXOff = e->drawYOff = 0;
e->dir = dir2;
e->level = level2;
if (luaFuncUse2[0])
g_hdb->_lua->callFunction(luaFuncUse2, 0);
e->draw = e->standdownGfx[0];
if (e == _player) {
clearWaypoints();
}
switch (e->dir) {
case DIR_UP:
setEntityGoal(e, e->tileX, e->tileY - 1);
break;
case DIR_DOWN:
setEntityGoal(e, e->tileX, e->tileY + 1);
break;
case DIR_LEFT:
setEntityGoal(e, e->tileX - 1, e->tileY);
break;
case DIR_RIGHT:
setEntityGoal(e, e->tileX + 1, e->tileY);
break;
case DIR_NONE:
default:
break;
}
g_hdb->_map->centerMapXY(e->x + 16, e->y + 16);
// Start up Teleport flash animation only if value1 is set to 1
if (anim1 == 1 || anim2 == 2) {
addAnimateTarget(e->x, e->y, 0, 7, ANIM_NORMAL, false, false, "teleporter_flash_sit");
g_hdb->_sound->playSound(SND_TELEPORT);
}
// PANIC ZONE Teleports?
if (anim2 >= 2)
g_hdb->_window->startPanicZone();
else
g_hdb->_window->stopPanicZone();
// Is there an attack gem still floating around?
for (Common::Array<AIEntity *>::iterator it = _ents->begin(); it != _ents->end(); ++it) {
if ((*it)->type == AI_GEM_ATTACK) {
int amt = getGemAmount();
setGemAmount(amt + 1);
removeEntity(*it);
break;
}
}
_playerEmerging = true;
return true;
}
}
return false;
}
void AI::addToPathList(int x, int y, int type, AIDir dir) {
ArrowPath *arrowPath = new ArrowPath;
arrowPath->type = type;
arrowPath->tileX = x;
arrowPath->tileY = y;
arrowPath->dir = dir;
_arrowPaths->push_back(arrowPath);
}
ArrowPath *AI::findArrowPath(int x, int y) {
for (Common::Array<ArrowPath *>::iterator it = _arrowPaths->begin(); it != _arrowPaths->end(); ++it) {
if ((*it)->tileX == x && (*it)->tileY == y)
return *it;
}
return nullptr;
}
void AI::addToTriggerList(char *luaFuncInit, char *luaFuncUse, int x, int y, int value1, int value2, char *id) {
Trigger *t = new Trigger;
_triggerList->push_back(t);
Common::strlcpy(t->id, id, 32);
t->x = x;
t->y = y;
t->value1 = value1;
t->value2 = value2;
if (luaFuncInit[0] != '*')
Common::strlcpy(t->luaFuncInit, luaFuncInit, 32);
if (luaFuncUse[0] != '*')
Common::strlcpy(t->luaFuncUse, luaFuncUse, 32);
if (!t->luaFuncUse[0])
g_hdb->_window->openMessageBar("Trigger without USE!", 10);
if (t->luaFuncInit[0]) {
g_hdb->_lua->pushFunction(t->luaFuncInit);
g_hdb->_lua->pushInt(x);
g_hdb->_lua->pushInt(y);
g_hdb->_lua->pushInt(value1);
g_hdb->_lua->pushInt(value2);
g_hdb->_lua->call(4, 0);
}
}
bool AI::checkTriggerList(char *entName, int x, int y) {
for (Common::Array<Trigger *>::iterator it = _triggerList->begin(); it != _triggerList->end(); ++it) {
Trigger *t = *it;
if (t->x == x && t->y == y) {
if (!t->luaFuncUse[0])
return false;
g_hdb->_lua->pushFunction(t->luaFuncUse);
g_hdb->_lua->pushString(entName);
g_hdb->_lua->pushInt(t->x);
g_hdb->_lua->pushInt(t->y);
g_hdb->_lua->pushInt(t->value1);
g_hdb->_lua->pushInt(t->value2);
g_hdb->_lua->call(5, 0);
return true;
}
}
return false;
}
void AI::killTrigger(const char *id) {
for (uint i = 0; i < _triggerList->size(); i++) {
if (!scumm_stricmp(id, _triggerList->operator[](i)->id)) {
_triggerList->remove_at(i);
i--;
}
}
}
} // End of Namespace

1771
engines/hdb/ai-player.cpp Normal file

File diff suppressed because it is too large Load Diff

277
engines/hdb/ai-player.h Normal file
View File

@@ -0,0 +1,277 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_AI_PLAYER_H
#define HDB_AI_PLAYER_H
namespace HDB {
void aiPlayerInit(AIEntity *e, int mx, int my);
void aiPlayerInit2(AIEntity *e, int mx, int my);
void aiPlayerAction(AIEntity *e, int mx, int my);
void aiPlayerDraw(AIEntity *e, int mx, int my);
void aiGemAttackInit(AIEntity *e, int mx, int my);
void aiGemAttackInit2(AIEntity *e, int mx, int my);
void aiGemAttackAction(AIEntity *e, int mx, int my);
void aiChickenAction(AIEntity *e, int mx, int my);
void aiChickenUse(AIEntity *e, int mx, int my);
void aiChickenInit(AIEntity *e, int mx, int my);
void aiChickenInit2(AIEntity *e, int mx, int my);
void aiDollyInit(AIEntity *e, int mx, int my);
void aiDollyInit2(AIEntity *e, int mx, int my);
void aiSergeantInit(AIEntity *e, int mx, int my);
void aiSergeantInit2(AIEntity *e, int mx, int my);
void aiSergeantAction(AIEntity *e, int mx, int my);
void aiSpacedudeInit(AIEntity *e, int mx, int my);
void aiSpacedudeInit2(AIEntity *e, int mx, int my);
void aiCrateAction(AIEntity *e, int mx, int my);
void aiCrateInit2(AIEntity *e, int mx, int my);
void aiCrateInit(AIEntity *e, int mx, int my);
void aiBarrelLightAction(AIEntity *e, int mx, int my);
void aiBarrelLightInit2(AIEntity *e, int mx, int my);
void aiBarrelLightInit(AIEntity *e, int mx, int my);
void aiBarrelHeavyAction(AIEntity *e, int mx, int my);
void aiBarrelHeavyInit(AIEntity *e, int mx, int my);
void aiBarrelHeavyInit2(AIEntity *e, int mx, int my);
void aiBarrelExplode(AIEntity *e, int mx, int my);
void aiBarrelExplodeInit(AIEntity *e, int mx, int my);
void aiBarrelExplodeInit2(AIEntity *e, int mx, int my);
void aiBarrelExplodeAction(AIEntity *e, int mx, int my);
void aiBarrelExplodeSpread(AIEntity *e, int mx, int my);
void aiBarrelBlowup(AIEntity *e, int x, int y);
void aiMaintBotInit(AIEntity *e, int mx, int my);
void aiMaintBotInit2(AIEntity *e, int mx, int my);
void aiMaintBotAction(AIEntity *e, int mx, int my);
void aiShockBotAction(AIEntity *e, int mx, int my);
void aiShockBotShock(AIEntity *e, int mx, int my);
void aiShockBotInit(AIEntity *e, int mx, int my);
void aiShockBotInit2(AIEntity *e, int mx, int my);
void aiScientistInit(AIEntity *e, int mx, int my);
void aiScientistInit2(AIEntity *e, int mx, int my);
void aiFourFirerInit(AIEntity *e, int mx, int my);
void aiFourFirerInit2(AIEntity *e, int mx, int my);
void aiFourFirerAction(AIEntity *e, int mx, int my);
void aiRailRiderInit(AIEntity *e, int mx, int my);
void aiRailRiderInit2(AIEntity *e, int mx, int my);
void aiRailRiderAction(AIEntity *e, int mx, int my);
void aiRailRiderUse(AIEntity *e, int mx, int my);
void aiRailRiderOnUse(AIEntity *e, int mx, int my);
void aiRailRiderOnAction(AIEntity *e, int mx, int my);
void aiOmniBotMissileAction(AIEntity *e, int mx, int my);
void aiOmniBotMissileInit(AIEntity *e, int mx, int my);
void aiOmniBotMissileInit2(AIEntity *e, int mx, int my);
void aiSlugAttackAction(AIEntity *e, int mx, int my);
void aiSlugAttackDraw(AIEntity *e, int mx, int my);
void aiSlugAttackInit(AIEntity *e, int mx, int my);
void aiSlugAttackInit2(AIEntity *e, int mx, int my);
void aiDeadWorkerInit(AIEntity *e, int mx, int my);
void aiDeadWorkerInit2(AIEntity *e, int mx, int my);
void aiWorkerInit(AIEntity *e, int mx, int my);
void aiWorkerInit2(AIEntity *e, int mx, int my);
void aiAccountantInit(AIEntity *e, int mx, int my);
void aiAccountantInit2(AIEntity *e, int mx, int my);
void aiFrogStatueInit(AIEntity *e, int mx, int my);
void aiFrogStatueInit2(AIEntity *e, int mx, int my);
void aiFrogStatueAction(AIEntity *e, int mx, int my);
void aiRoboStunnerAction(AIEntity *e, int mx, int my);
void aiRoboStunnerInit(AIEntity *e, int mx, int my);
void aiRoboStunnerInit2(AIEntity *e, int mx, int my);
void aiClubInit(AIEntity *e, int mx, int my);
void aiClubInit2(AIEntity *e, int mx, int my);
void aiSlugSlingerInit(AIEntity *e, int mx, int my);
void aiSlugSlingerInit2(AIEntity *e, int mx, int my);
void aiTurnBotAction(AIEntity *e, int mx, int my);
void aiPushBotAction(AIEntity *e, int mx, int my);
void aiOmniBotAction(AIEntity *e, int mx, int my);
void aiOmniBotMove(AIEntity *e, int mx, int my);
void aiLaserAction(AIEntity *e, int mx, int my);
void aiLaserDraw(AIEntity *e, int mx, int my);
void aiDiverterAction(AIEntity *e, int mx, int my);
void aiDiverterDraw(AIEntity *e, int mx, int my);
void aiRightBotAction(AIEntity *e, int mx, int my);
void aiDeadEyeAction(AIEntity *e, int mx, int my);
void aiMeerkatDraw(AIEntity *e, int mx, int my);
void aiMeerkatAction(AIEntity *e, int mx, int my);
void aiMeerkatLookAround(AIEntity *e, int mx, int my);
void aiDeadEyeWalkInPlace(AIEntity *e, int mx, int my);
void aiFatFrogAction(AIEntity *e, int mx, int my);
void aiFatFrogTongueDraw(AIEntity *e, int mx, int my);
void aiGoodFairyAction(AIEntity *e, int mx, int my);
void aiBadFairyAction(AIEntity *e, int mx, int my);
void aiGatePuddleAction(AIEntity *e, int mx, int my);
void aiIcePuffSnowballAction(AIEntity *e, int mx, int my);
void aiIcePuffSnowballDraw(AIEntity *e, int mx, int my);
void aiIcePuffAction(AIEntity *e, int mx, int my);
void aiBuzzflyAction(AIEntity *e, int mx, int my);
void aiDragonAction(AIEntity *e, int mx, int my);
void aiDragonDraw(AIEntity *e, int mx, int my);
void aiTurnBotInit(AIEntity *e, int mx, int my);
void aiTurnBotInit2(AIEntity *e, int mx, int my);
void aiOmniBotInit(AIEntity *e, int mx, int my);
void aiOmniBotInit2(AIEntity *e, int mx, int my);
void aiLaserInit(AIEntity *e, int mx, int my);
void aiLaserInit2(AIEntity *e, int mx, int my);
void aiDiverterInit(AIEntity *e, int mx, int my);
void aiDiverterInit2(AIEntity *e, int mx, int my);
void aiRightBotInit(AIEntity *e, int mx, int my);
void aiRightBotInit2(AIEntity *e, int mx, int my);
void aiPushBotInit(AIEntity *e, int mx, int my);
void aiPushBotInit2(AIEntity *e, int mx, int my);
void aiDeadEyeInit(AIEntity *e, int mx, int my);
void aiDeadEyeInit2(AIEntity *e, int mx, int my);
void aiMeerkatInit(AIEntity *e, int mx, int my);
void aiMeerkatInit2(AIEntity *e, int mx, int my);
void aiFatFrogInit(AIEntity *e, int mx, int my);
void aiFatFrogInit2(AIEntity *e, int mx, int my);
void aiGoodFairyInit(AIEntity *e, int mx, int my);
void aiGoodFairyInit2(AIEntity *e, int mx, int my);
void aiBadFairyInit(AIEntity *e, int mx, int my);
void aiBadFairyInit2(AIEntity *e, int mx, int my);
void aiGatePuddleInit(AIEntity *e, int mx, int my);
void aiGatePuddleInit2(AIEntity *e, int mx, int my);
void aiIcePuffInit(AIEntity *e, int mx, int my);
void aiIcePuffInit2(AIEntity *e, int mx, int my);
void aiBuzzflyInit(AIEntity *e, int mx, int my);
void aiBuzzflyInit2(AIEntity *e, int mx, int my);
void aiDragonInit(AIEntity *e, int mx, int my);
void aiDragonInit2(AIEntity *e, int mx, int my);
void aiDragonWake(AIEntity *e, int mx, int my);
void aiDragonUse(AIEntity *e, int mx, int my);
void aiEnvelopeGreenInit(AIEntity *e, int mx, int my);
void aiEnvelopeGreenInit2(AIEntity *e, int mx, int my);
void aiGemBlueInit(AIEntity *e, int mx, int my);
void aiGemBlueInit2(AIEntity *e, int mx, int my);
void aiGemRedInit(AIEntity *e, int mx, int my);
void aiGemRedInit2(AIEntity *e, int mx, int my);
void aiGemGreenInit(AIEntity *e, int mx, int my);
void aiGemGreenInit2(AIEntity *e, int mx, int my);
void aiTeaCupInit(AIEntity *e, int mx, int my);
void aiTeaCupInit2(AIEntity *e, int mx, int my);
void aiCookieInit(AIEntity *e, int mx, int my);
void aiCookieInit2(AIEntity *e, int mx, int my);
void aiBurgerInit(AIEntity *e, int mx, int my);
void aiBurgerInit2(AIEntity *e, int mx, int my);
void aiBookInit(AIEntity *e, int mx, int my);
void aiBookInit2(AIEntity *e, int mx, int my);
void aiClipboardInit(AIEntity *e, int mx, int my);
void aiClipboardInit2(AIEntity *e, int mx, int my);
void aiNoteInit(AIEntity *e, int mx, int my);
void aiNoteInit2(AIEntity *e, int mx, int my);
void aiKeycardWhiteInit(AIEntity *e, int mx, int my);
void aiKeycardWhiteInit2(AIEntity *e, int mx, int my);
void aiKeycardBlueInit(AIEntity *e, int mx, int my);
void aiKeycardBlueInit2(AIEntity *e, int mx, int my);
void aiKeycardRedInit(AIEntity *e, int mx, int my);
void aiKeycardRedInit2(AIEntity *e, int mx, int my);
void aiKeycardGreenInit(AIEntity *e, int mx, int my);
void aiKeycardGreenInit2(AIEntity *e, int mx, int my);
void aiKeycardPurpleInit(AIEntity *e, int mx, int my);
void aiKeycardPurpleInit2(AIEntity *e, int mx, int my);
void aiKeycardBlackInit(AIEntity *e, int mx, int my);
void aiKeycardBlackInit2(AIEntity *e, int mx, int my);
void aiSeedInit(AIEntity *e, int mx, int my);
void aiSeedInit2(AIEntity *e, int mx, int my);
void aiSodaInit(AIEntity *e, int mx, int my);
void aiSodaInit2(AIEntity *e, int mx, int my);
void aiDollyTool1Init(AIEntity *e, int mx, int my);
void aiDollyTool1Init2(AIEntity *e, int mx, int my);
void aiDollyTool2Init(AIEntity *e, int mx, int my);
void aiDollyTool2Init2(AIEntity *e, int mx, int my);
void aiDollyTool3Init(AIEntity *e, int mx, int my);
void aiDollyTool3Init2(AIEntity *e, int mx, int my);
void aiDollyTool4Init(AIEntity *e, int mx, int my);
void aiDollyTool4Init2(AIEntity *e, int mx, int my);
void aiRouterInit(AIEntity *e, int mx, int my);
void aiRouterInit2(AIEntity *e, int mx, int my);
void aiSlicerInit(AIEntity *e, int mx, int my);
void aiSlicerInit2(AIEntity *e, int mx, int my);
void aiPackageInit(AIEntity *e, int mx, int my);
void aiPackageInit2(AIEntity *e, int mx, int my);
void aiMagicEggAction(AIEntity *e, int mx, int my);
void aiMagicEggInit(AIEntity *e, int mx, int my);
void aiMagicEggInit2(AIEntity *e, int mx, int my);
void aiMagicEggUse(AIEntity *e, int mx, int my);
void aiIceBlockAction(AIEntity *e, int mx, int my);
void aiIceBlockInit(AIEntity *e, int mx, int my);
void aiIceBlockInit2(AIEntity *e, int mx, int my);
void aiCabKeyInit(AIEntity *e, int mx, int my);
void aiCabKeyInit2(AIEntity *e, int mx, int my);
void aiItemChickenInit(AIEntity *e, int mx, int my);
void aiItemChickenInit2(AIEntity *e, int mx, int my);
void aiPdaInit(AIEntity *e, int mx, int my);
void aiPdaInit2(AIEntity *e, int mx, int my);
#if 0
void aiCellUse(AIEntity *e, int mx, int my);
#endif
void aiCellInit2(AIEntity *e, int mx, int my);
void aiCellInit(AIEntity *e, int mx, int my);
void aiEnvelopeWhiteInit(AIEntity *e, int mx, int my);
void aiEnvelopeWhiteInit2(AIEntity *e, int mx, int my);
void aiEnvelopeBlueInit(AIEntity *e, int mx, int my);
void aiEnvelopeBlueInit2(AIEntity *e, int mx, int my);
void aiEnvelopeRedInit(AIEntity *e, int mx, int my);
void aiEnvelopeRedInit2(AIEntity *e, int mx, int my);
void aiTransceiverInit(AIEntity *e, int mx, int my);
void aiTransceiverInit2(AIEntity *e, int mx, int my);
void aiTransceiverAction(AIEntity *e, int mx, int my);
#if 0
void aiTransceiverUse(AIEntity *e, int mx, int my);
#endif
void aiMonkeystoneInit(AIEntity *e, int mx, int my);
void aiMonkeystoneAction(AIEntity *e, int mx, int my);
void aiMonkeystoneInit2(AIEntity *e, int mx, int my);
void aiMonkeystoneUse(AIEntity *e, int mx, int my);
void aiGemAction(AIEntity *e, int mx, int my);
void aiGemWhiteInit(AIEntity *e, int mx, int my);
void aiGemWhiteInit2(AIEntity *e, int mx, int my);
void aiGooCupUse(AIEntity *e, int mx, int my);
void aiGooCupInit(AIEntity *e, int mx, int my);
void aiGooCupInit2(AIEntity *e, int mx, int my);
void aiVortexianAction(AIEntity *e, int mx, int my);
void aiVortexianUse(AIEntity *e, int mx, int my);
void aiVortexianInit(AIEntity *e, int mx, int my);
void aiVortexianInit2(AIEntity *e, int mx, int my);
void aiNoneInit(AIEntity *e, int mx, int my);
void aiNoneInit2(AIEntity *e, int mx, int my);
void callbackDoorOpenClose(int x, int y);
void callbackAutoDoorOpenClose(int x, int y);
void callbackAiBarrelExplosionEnd(int x, int y);
// Utility Functions
void aiAnimateStanddown(AIEntity *e, int speed);
void aiGenericAction(AIEntity *e, int mx, int my);
void aiGetItemAction(AIEntity *e, int mx, int my);
} // End of Namespace
#endif // !HDB_AI_PLAYER_H

307
engines/hdb/ai-use.cpp Normal file
View File

@@ -0,0 +1,307 @@
/* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be AI::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, see <http://www.gnu.org/licenses/>.
*
*/
#include "hdb/hdb.h"
#include "hdb/ai.h"
#include "hdb/map.h"
#include "hdb/sound.h"
#include "hdb/window.h"
namespace HDB {
bool AI::isClosedDoor(int x, int y) {
int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
if ((tileIndex == _targetDoorN + 3) || // locked SILVER door?
(tileIndex == _targetDoorNv + 3) ||
(tileIndex == _targetDoorP + 3) || // locked BLUE door?
(tileIndex == _targetDoorPv + 3) ||
(tileIndex == _targetDoorS + 3) || // locked RED door?
(tileIndex == _targetDoorSv + 3) ||
(tileIndex == _targetDoor2N + 3) || // locked SILVER door?
(tileIndex == _targetDoor2Nv + 3) ||
(tileIndex == _targetDoor2P + 3) || // locked BLUE door?
(tileIndex == _targetDoor2Pv + 3) ||
(tileIndex == _targetDoor2S + 3) || // locked RED door?
(tileIndex == _targetDoor2Sv + 3) ||
(tileIndex == _target2DoorN + 3) || // locked SILVER door?
(tileIndex == _target2DoorNv + 3) ||
(tileIndex == _target2DoorP + 3) || // locked BLUE door?
(tileIndex == _target2DoorPv + 3) ||
(tileIndex == _target2DoorS + 3) || // locked RED door?
(tileIndex == _target2DoorSv + 3) ||
(tileIndex == _target3DoorN + 3) || // locked SILVER door?
(tileIndex == _target3DoorNv + 3) ||
(tileIndex == _target3DoorP + 3) || // locked BLUE door?
(tileIndex == _target3DoorPv + 3) ||
(tileIndex == _target3DoorS + 3) || // locked RED door?
(tileIndex == _target3DoorSv + 3) ||
(tileIndex == _blockpole + 3)) // blockpole UP?
return true;
return false;
}
bool AI::isOpenDoor(int x, int y) {
int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
if ((tileIndex == _targetDoorN) || // open SILVER door?
(tileIndex == _targetDoorNv) ||
(tileIndex == _targetDoorP) || // open BLUE door?
(tileIndex == _targetDoorPv) ||
(tileIndex == _targetDoorS) || // open RED door?
(tileIndex == _targetDoorSv) ||
(tileIndex == _targetDoor2N) || // open SILVER door?
(tileIndex == _targetDoor2Nv) ||
(tileIndex == _targetDoor2P) || // open BLUE door?
(tileIndex == _targetDoor2Pv) ||
(tileIndex == _targetDoor2S) || // open RED door?
(tileIndex == _targetDoor2Sv) ||
(tileIndex == _target2DoorN) || // open SILVER door?
(tileIndex == _target2DoorNv) ||
(tileIndex == _target2DoorP) || // open BLUE door?
(tileIndex == _target2DoorPv) ||
(tileIndex == _target2DoorS) || // open RED door?
(tileIndex == _target2DoorSv) ||
(tileIndex == _target3DoorN) || // open SILVER door?
(tileIndex == _target3DoorNv) ||
(tileIndex == _target3DoorP) || // open BLUE door?
(tileIndex == _target3DoorPv) ||
(tileIndex == _target3DoorS) || // open RED door?
(tileIndex == _target3DoorSv) ||
(tileIndex == _blockpole)) // blockpole DOWN?
return true;
return false;
}
bool AI::useTarget(int x, int y, int targetX, int targetY, int newTile, int *worked) {
// open a locked door?
if (isClosedDoor(targetX, targetY)) {
int tileIndex = g_hdb->_map->getMapBGTileIndex(targetX, targetY);
addAnimateTarget(targetX, targetY, tileIndex, tileIndex - 3, ANIM_SLOW, false, true, nullptr);
g_hdb->_map->setMapBGTileIndex(x, y, newTile);
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
*worked = 1;
return false; // return FALSE because we need to be able to do it some more
}
// close an open door?
if (isOpenDoor(targetX, targetY)) {
int tileIndex = g_hdb->_map->getMapBGTileIndex(targetX, targetY);
addAnimateTarget(targetX, targetY, tileIndex, tileIndex + 3, ANIM_SLOW, false, true, nullptr);
g_hdb->_map->setMapBGTileIndex(x, y, newTile);
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
*worked = 1;
return false; // return FALSE because we need to be able to do it some more
}
// open up a bridge?
int tileIndex = g_hdb->_map->getMapFGTileIndex(targetX, targetY);
if (tileIndex == _targetBridgeU ||
tileIndex == _targetBridgeD ||
tileIndex == _targetBridgeL ||
tileIndex == _targetBridgeR) {
addBridgeExtend(targetX, targetY, tileIndex);
g_hdb->_map->setMapBGTileIndex(x, y, newTile);
*worked = 1;
return true; // return TRUE because we can't open it again
}
*worked = 0;
return false;
}
// Black Door Switch
bool AI::useSwitch(AIEntity *e, int x, int y, int targetX, int targetY, int onTile) {
int worked;
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_SWITCH_USE);
return useTarget(x, y, targetX, targetY, onTile, &worked);
}
bool AI::useSwitchOn(AIEntity *e, int x, int y, int targetX, int targetY, int offTile) {
int worked;
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_SWITCH_USE);
return useTarget(x, y, targetX, targetY, offTile, &worked);
}
bool AI::useSwitch2(AIEntity *e, int x, int y, int targetX, int targetY) {
// int i = 10; // unused
return true;
}
// Colored Keycard Switch
bool AI::useLockedSwitch(AIEntity *e, int x, int y, int targetX, int targetY, int onTile, AIType item, const char *keyerror) {
// is the PLAYER next to this thing? No other entities are allowed to unlock anything!
if (abs(x - _player->tileX) > 1 || abs(y - _player->tileY) > 1)
return false;
int amount = queryInventoryType(item);
if (amount) {
int worked;
bool rtn = useTarget(x, y, targetX, targetY, onTile, &worked);
if (worked) {
removeInvItemType(item, 1);
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_SWITCH_USE);
}
return rtn;
} else {
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_CELLHOLDER_USE_REJECT);
g_hdb->_window->openMessageBar(keyerror, 3);
}
return false;
}
bool AI::useLockedSwitchOn(AIEntity *e, int x, int y, int targetX, int targetY, int offTile, AIType item) {
// is the PLAYER next to this thing? No other entities are allowed to unlock anything!
if (abs(x - _player->tileX) > 1 || abs(y - _player->tileY) > 1)
return false;
if (getInvAmount() == 10)
return false;
int worked;
bool rtn = useTarget(x, y, targetX, targetY, offTile, &worked);
if (worked) {
addItemToInventory(item, 1, nullptr, nullptr, nullptr);
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_SWITCH_USE);
}
return rtn;
}
// Purple Cell Holder Switch
bool AI::useCellHolder(AIEntity *e, int x, int y, int targetX, int targetY) {
// is the PLAYER next to this thing? No other entities are allowed to unlock anything!
if (abs(x - _player->tileX) > 1 || abs(y - _player->tileY) > 1)
return false;
int amount = queryInventoryType(ITEM_CELL);
if (amount) {
int worked;
bool rtn = useTarget(x, y, targetX, targetY, _useHolderFull, &worked);
if (worked) {
removeInvItemType(ITEM_CELL, 1);
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_SWITCH_USE);
}
return rtn;
} else {
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_CELLHOLDER_USE_REJECT);
}
g_hdb->_window->openDialog("Locked!", -1, "I can't use that unless I have an Energy Cell.", 0, nullptr);
g_hdb->_sound->playVoice(GUY_ENERGY_CELL, 0);
return false;
}
// Touchplate
bool AI::useTouchplate(AIEntity *e, int x, int y, int targetX, int targetY, int type) {
int worked;
g_hdb->_sound->playSound(SND_TOUCHPLATE_CLICK);
return useTarget(x, y, targetX, targetY, type, &worked);
}
bool AI::useTouchplateOn(AIEntity *e, int x, int y, int targetX, int targetY, int type) {
int worked;
g_hdb->_sound->playSound(SND_TOUCHPLATE_CLICK);
return useTarget(x, y, targetX, targetY, type, &worked);
}
void callbackDoorOpenClose(int x, int y) {
int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
// is the door gonna close on something? if so, wait again
if (!g_hdb->_ai->findEntity(x, y)) {
g_hdb->_ai->addCallback(CALLBACK_DOOR_OPEN_CLOSE, x, y, kDelay5Seconds);
return;
}
g_hdb->_ai->addAnimateTarget(x, y, tileIndex, tileIndex + 3, ANIM_SLOW, false, true, nullptr);
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
return;
}
// Normal Door
bool AI::useDoorOpenClose(AIEntity *e, int x, int y) {
int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
addAnimateTarget(x, y, tileIndex, tileIndex - 3, ANIM_SLOW, false, true, nullptr);
addCallback(CALLBACK_DOOR_OPEN_CLOSE, x, y, kDelay5Seconds);
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
return true;
}
void callbackAutoDoorOpenClose(int x, int y) {
int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
// Is the door going to close on something?
if (g_hdb->_ai->findEntity(x, y)) {
g_hdb->_ai->addCallback(CALLBACK_AUTODOOR_OPEN_CLOSE, x, y, kDelay5Seconds);
return;
}
g_hdb->_ai->addAnimateTarget(x, y, tileIndex, tileIndex + 3, ANIM_SLOW, true, true, nullptr);
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
return;
}
bool AI::useAutoDoorOpenClose(AIEntity *e, int x, int y) {
int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
if (autoActive(x, y))
return false;
addAnimateTarget(x, y, tileIndex, tileIndex - 3, ANIM_SLOW, false, true, nullptr);
addCallback(CALLBACK_AUTODOOR_OPEN_CLOSE, x, y, kDelay5Seconds);
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
return false;
}
// Any Type Door
bool AI::useDoorOpenCloseBot(AIEntity *e, int x, int y) {
int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
if (e == _player || e->type == AI_SLUG_ATTACK || e->type == AI_GEM_ATTACK) {
if (isClosedDoor(x, y))
g_hdb->_sound->playSound(SND_GUY_UHUH);
return false;
}
addAnimateTarget(x, y, tileIndex, tileIndex - 3, ANIM_SLOW, false, true, nullptr);
// AddCallback( CALLBACK_DOOR_OPEN_CLOSE, x, y, DELAY_5SECONDS / fs );
if (g_hdb->_map->onScreen(x, y))
g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
return true;
}
} // End of Namespace

463
engines/hdb/ai-waypoint.cpp Normal file
View File

@@ -0,0 +1,463 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "hdb/hdb.h"
#include "hdb/ai.h"
#include "hdb/gfx.h"
#include "hdb/map.h"
#include "hdb/sound.h"
namespace HDB {
void AI::addWaypoint(int px, int py, int x, int y, int level) {
// at the max yet?
if (_numWaypoints >= kMaxWaypoints || (playerOnIce() && _player->goalX))
return;
// first, let's see if this is a duplicate waypoint
int i;
for (i = 0; i < _numWaypoints; i++)
if (_waypoints[i].x == x && _waypoints[i].y == y)
return;
// check to make sure the path is clear...
// if it's not, don't add to waypoint list!
// The destination x,y might be modified, so
// we'll pass in the address to them...
int nx = x;
int ny = y;
if (!_numWaypoints) {
// if player is already moving and this is the first waypoint, forget it.
// player is using the keyboard and must be fully stopped before laying
// the first waypoint
if (_player->goalX)
return;
// trace from player to new spot
// return value of 0 only means a diagonal was selected!
if (!traceStraightPath(px, py, &nx, &ny, &level)) {
int tx, ty, tx2, ty2;
// it didn't work, so player is probably trying some diagonal movement.
// let's break it down into two waypoints: one horz, one vert
tx = nx;
ty = py;
tx2 = nx;
ty2 = ny;
int lvl1, lvl2;
lvl1 = lvl2 = level;
if (traceStraightPath(px, py, &tx, &ty, &lvl1)) {
if (tx != nx || ty != py)
goto newpath;
traceStraightPath(tx, ty, &tx2, &ty2, &lvl2);
if (tx2 != nx || ty2 != ny)
goto newpath;
_waypoints[_numWaypoints].x = tx;
_waypoints[_numWaypoints].y = ty;
_waypoints[_numWaypoints].level = lvl1;
_numWaypoints++;
_waypoints[_numWaypoints].x = nx;
_waypoints[_numWaypoints].y = ny;
_waypoints[_numWaypoints].level = lvl2;
_numWaypoints++;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
if (onEvenTile(_player->x, _player->y))
setEntityGoal(_player, tx, ty);
} else {
newpath:
tx = px;
ty = ny;
tx2 = nx;
ty2 = ny;
lvl1 = lvl2 = level;
if (traceStraightPath(px, py, &tx, &ty, &lvl1)) {
if (tx != px || ty != ny)
return;
traceStraightPath(tx, ty, &nx, &ny, &lvl2);
if (tx2 != nx || ty2 != ny)
return;
_waypoints[_numWaypoints].x = tx;
_waypoints[_numWaypoints].y = ty;
_waypoints[_numWaypoints].level = lvl1;
_numWaypoints++;
_waypoints[_numWaypoints].x = nx;
_waypoints[_numWaypoints].y = ny;
_waypoints[_numWaypoints].level = lvl2;
_numWaypoints++;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
if (onEvenTile(_player->x, _player->y))
setEntityGoal(_player, tx, ty);
}
}
return;
}
// create a waypoint @ the player x,y? NO!
if ((nx != px || ny != py) && onEvenTile(_player->x, _player->y))
setEntityGoal(_player, nx, ny);
else
return;
} else {
// trace from last waypoint to new spot
level = _waypoints[_numWaypoints - 1].level;
if (!traceStraightPath(_waypoints[_numWaypoints - 1].x, _waypoints[_numWaypoints - 1].y, &nx, &ny, &level)) {
int tx, ty, tx2, ty2;
// it didn't work, so player is probably trying some diagonal movement.
// let's break it down into two waypoints: one horz, one vert
px = _waypoints[_numWaypoints - 1].x;
py = _waypoints[_numWaypoints - 1].y;
level = _waypoints[_numWaypoints - 1].level;
tx = nx;
ty = py;
tx2 = nx;
ty2 = ny;
int lvl1, lvl2;
lvl1 = lvl2 = level;
if (traceStraightPath(px, py, &tx, &ty, &lvl1)) {
if (tx != nx || ty != py)
goto newpath2;
traceStraightPath(tx, ty, &tx2, &ty2, &lvl2);
if (tx2 != nx || ty2 != ny)
goto newpath2;
if (_numWaypoints < kMaxWaypoints) {
_waypoints[_numWaypoints].x = tx;
_waypoints[_numWaypoints].y = ty;
_waypoints[_numWaypoints].level = lvl1;
_numWaypoints++;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
}
if (_numWaypoints < kMaxWaypoints) {
_waypoints[_numWaypoints].x = nx;
_waypoints[_numWaypoints].y = ny;
_waypoints[_numWaypoints].level = lvl2;
_numWaypoints++;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
}
} else {
newpath2:
tx = px;
ty = ny;
tx2 = nx;
ty2 = ny;
lvl1 = lvl2 = level;
if (traceStraightPath(px, py, &tx, &ty, &lvl1)) {
if (tx != px || ty != ny)
return;
traceStraightPath(tx, ty, &nx, &ny, &lvl2);
if (tx2 != nx || ty2 != ny)
return;
if (_numWaypoints < kMaxWaypoints) {
_waypoints[_numWaypoints].x = tx;
_waypoints[_numWaypoints].y = ty;
_waypoints[_numWaypoints].level = lvl1;
_numWaypoints++;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
}
if (_numWaypoints < kMaxWaypoints) {
_waypoints[_numWaypoints].x = nx;
_waypoints[_numWaypoints].y = ny;
_waypoints[_numWaypoints].level = lvl2;
_numWaypoints++;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
}
}
}
return;
}
// create a waypoint @ the player x,y? NO!
if (nx == px && ny == py)
return;
// make sure potential waypoint isn't on other waypoints!
for (i = 0; i < _numWaypoints; i++)
if (_waypoints[i].x == nx && _waypoints[i].y == ny)
return;
}
if (_numWaypoints < kMaxWaypoints) {
_waypoints[_numWaypoints].x = nx;
_waypoints[_numWaypoints].y = ny;
_waypoints[_numWaypoints].level = level;
_numWaypoints++;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
}
}
void AI::removeFirstWaypoint() {
if (!_numWaypoints)
return;
int i;
for (i = 0; i < _numWaypoints; i++) {
_waypoints[i] = _waypoints[i + 1];
}
_waypoints[i].x = 0;
_waypoints[i].y = 0;
_waypoints[i].level = 0;
_numWaypoints--;
}
void AI::clearWaypoints() {
for (uint8 i = 0; i < ARRAYSIZE(_waypoints); i++) {
_waypoints[i].reset();
}
_numWaypoints = 0;
}
bool AI::traceStraightPath(int x1, int y1, int *x2, int *y2, int *level) {
// this checks to make sure we're only going vert or horz
if (x1 != *x2 && y1 != *y2)
return false;
// this sets a -1, 0, or 1 step value
int xVel = *x2 - x1;
if (xVel < 0)
xVel = -1;
if (xVel > 0)
xVel = 1;
int yVel = *y2 - y1;
if (yVel < 0)
yVel = -1;
if (yVel > 0)
yVel = 1;
AIEntity *e;
while (1) {
// clear tile ahead?
bool entOK = false;
bool ok = false;
uint32 flags = g_hdb->_map->getMapBGTileFlags(x1, y1);
if (flags & kFlagStairTop)
*level = 2;
else if (flags & kFlagStairBot)
*level = 1;
// Floor level 1
if (*level < 2) {
ok = !(flags & (kFlagPlayerBlock | kFlagMonsterBlock));
// if it's blocking, is it rad or plasma? (might be melted stuff on it)
if (!ok) {
ok = ((flags & kFlagPlasmaFloor) == kFlagPlasmaFloor) +
((flags & kFlagRadFloor) == kFlagRadFloor);
e = findEntity(x1, y1);
if (e && g_hdb->_ai->walkThroughEnt(e->type))
entOK = true;
else if (ok && e && (e->state == STATE_FLOATING || e->state == STATE_MELTED || e == _player))
entOK = ok = true;
else
ok = false;
} else if (ok &&
((flags & kFlagWater) == kFlagWater ||
(flags & kFlagSlime) == kFlagSlime)) {
// if it's non-blocking, is there water or slime?
e = findEntity(x1, y1);
if (e && g_hdb->_ai->walkThroughEnt(e->type))
entOK = true;
else
if (e && (e->state == STATE_FLOATING || e->state == STATE_MELTED || e == _player))
entOK = ok = true;
else
ok = false;
}
} else {
// Floor level 2
if (g_hdb->_map->getMapFGTileIndex(x1, y1) >= 0) // is there a foregnd tile? its flags take precedence on Level 2
ok = !(g_hdb->_map->getMapFGTileFlags(x1, y1) & (kFlagPlayerBlock | kFlagMonsterBlock));
else {
flags = g_hdb->_map->getMapBGTileFlags(x1, y1);
ok = !(flags & (kFlagPlayerBlock | kFlagMonsterBlock));
// if it's blocking, is it rad or plasma? (might be melted stuff on it)
if (!ok) {
ok = ((flags & kFlagPlasmaFloor) == kFlagPlasmaFloor) +
((flags & kFlagRadFloor) == kFlagRadFloor);
e = findEntity(x1, y1);
if (e && g_hdb->_ai->walkThroughEnt(e->type))
entOK = true;
else if (ok && e && (e->state == STATE_FLOATING || e->state == STATE_MELTED || e == _player))
entOK = ok = true;
else
ok = false;
} else if (ok &&
((flags & kFlagWater) == kFlagWater ||
(flags & kFlagSlime) == kFlagSlime)) {
// if it's non-blocking, is there water or slime?
e = findEntity(x1, y1);
if (e && g_hdb->_ai->walkThroughEnt(e->type))
entOK = true;
else
if (e && (e->state == STATE_FLOATING || e->state == STATE_MELTED || e == _player))
entOK = ok = true;
else
ok = false;
}
}
}
if (ok) {
e = findEntity(x1, y1);
if (e == _player)
e = nullptr;
else if (g_hdb->_map->laserBeamExist(x1, y1)) {
*x2 = x1 - xVel;
*y2 = y1 - yVel;
return true;
} else if (e && (e->level != _player->level) && (g_hdb->_map->getMapFGTileFlags(e->tileX, e->tileY) & kFlagGrating)) {
// on the same level????
entOK = 1;
}
if (e && !entOK) {
if (g_hdb->_ai->walkThroughEnt(e->type)) {
// yes! are we at desired location?
if (x1 == *x2 && y1 == *y2)
return true;
} else {
// solid tile! back up one and return!
*x2 = x1 - xVel;
*y2 = y1 - yVel;
return true;
}
} else if (x1 == *x2 && y1 == *y2) {
// yes! are we at desired location?
return true;
}
} else {
// solid tile! back up one and return!
*x2 = x1 - xVel;
*y2 = y1 - yVel;
return true;
}
x1 += xVel;
y1 += yVel;
}
return true;
}
Tile *AI::getStandFrameDir(AIEntity *e) {
switch (e->dir) {
case DIR_DOWN:
if (e->standdownFrames)
return e->standdownGfx[0];
else if (e->movedownFrames)
return e->movedownGfx[0];
break;
case DIR_UP:
if (e->standupFrames)
return e->standupGfx[0];
else if (e->moveupFrames)
return e->moveupGfx[0];
break;
case DIR_LEFT:
if (e->standleftFrames)
return e->standleftGfx[0];
else if (e->moveleftFrames)
return e->moveleftGfx[0];
break;
case DIR_RIGHT:
if (e->standrightFrames)
return e->standrightGfx[0];
else if (e->moverightFrames)
return e->moverightGfx[0];
break;
case DIR_NONE:
default:
break;
}
return e->standdownGfx[0];
}
void AI::drawWayPoints() {
static int anim = 0;
static uint32 delay = g_hdb->getTimeSlice();
static int alpha = 255;
static int aVel = -4;
int mapX, mapY;
g_hdb->_map->getMapXY(&mapX, &mapY);
for (int i = 0; i < _numWaypoints; i++) {
int x = _waypoints[i].x * kTileWidth;
int y = _waypoints[i].y * kTileHeight;
if (x > mapX - 32 && (x < (mapX + g_hdb->_screenWidth)) &&
y > mapY - 32 && (y < (mapY + g_hdb->_screenHeight)))
_waypointGfx[anim]->drawMasked(x - mapX, y - mapY, alpha);
}
// vary the alpha blending
alpha = (alpha + aVel);
if (alpha < 64) {
alpha = 64;
aVel = -aVel;
}
if (alpha > 200) {
alpha = 200;
aVel = -aVel;
}
// don't animate every single game frame...
if (delay > g_hdb->getTimeSlice())
return;
delay = g_hdb->getTimeSlice() + 100;
// cycle the waypoint gfx animation
anim++;
if (anim == 4)
anim = 0;
}
} // End of Namespace

1448
engines/hdb/ai.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
# This file is included from the main "configure" script
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
add_engine hdb "Hyperspace Delivery Boy!" yes "" "" "16bit highres lua" ""

4
engines/hdb/credits.pl Normal file
View File

@@ -0,0 +1,4 @@
begin_section("HDB");
add_person("Eugene Sandulenko", "sev", "");
add_person("Nipun Garg", "nipung", "GSoC student");
end_section();

134
engines/hdb/detection.cpp Normal file
View File

@@ -0,0 +1,134 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "base/plugins.h"
#include "engines/advancedDetector.h"
#include "hdb/detection.h"
static const PlainGameDescriptor hdbGames[] = {
{"hdb", "Hyperspace Delivery Boy!"},
{nullptr, nullptr}
};
namespace HDB {
static const ADGameDescription gameDescriptions[] = {
{
"hdb",
"",
AD_ENTRY1s("hyperspace.mpc", "ff8e51d0872736bc6afe87cfcb846b70", 50339161),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_NO_FLAGS,
GUIO2(GUIO_NOMIDI,GAMEOPTION_CHEATMODE)
},
{
"hdb",
"",
AD_ENTRY1s("hyperspace.mpc", "39d3c9dbc9614f370ad9430307c043f9", 45645305),
Common::EN_ANY,
Common::kPlatformLinux,
ADGF_NO_FLAGS,
GUIO2(GUIO_NOMIDI,GAMEOPTION_CHEATMODE)
},
// PocketPC Arm
{
"hdb",
"",
AD_ENTRY1s("hyperspace.msd", "a62468904beb3efe16d4d64f3955a32e", 6825555),
Common::EN_ANY,
Common::kPlatformPocketPC,
ADGF_NO_FLAGS,
GUIO2(GUIO_NOMIDI,GAMEOPTION_CHEATMODE)
},
// Demos
{
"hdb",
"Demo",
AD_ENTRY1s("hyperdemo.mpc", "d8743b3b8be56486bcfb1398b2f2aad4", 13816461),
Common::EN_ANY,
Common::kPlatformLinux,
ADGF_DEMO,
GUIO2(GUIO_NOMIDI,GAMEOPTION_CHEATMODE)
},
{
"hdb",
"Demo",
AD_ENTRY1s("hyperdemo.mpc", "f3bc878e179f00b8666a9846f3d9f9f5", 5236568),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_DEMO,
GUIO2(GUIO_NOMIDI,GAMEOPTION_CHEATMODE)
},
// provided by sev
{
"hdb",
"Demo",
AD_ENTRY1s("hyperdemo.mpc", "7bc533e8f1866931c884f1bc09353744", 13906865),
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_DEMO,
GUIO2(GUIO_NOMIDI,GAMEOPTION_CHEATMODE)
},
{
"hdb",
"Demo",
AD_ENTRY1s("hyperdemo.msd", "312525298ca9f5ac904883d1ce19dc0f", 3088651),
Common::EN_ANY,
Common::kPlatformPocketPC,
ADGF_DEMO,
GUIO2(GUIO_NOMIDI,GAMEOPTION_CHEATMODE)
},
{
"hdb",
"Handango Demo",
AD_ENTRY1s("hyperdemo.msd", "2d4457b284a940b7058b36e5706b9951", 3094241),
Common::EN_ANY,
Common::kPlatformPocketPC,
(ADGF_DEMO | GF_HANDANGO),
GUIO2(GUIO_NOMIDI,GAMEOPTION_CHEATMODE)
},
AD_TABLE_END_MARKER
};
} // End of namespace HDB
class HDBMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
public:
HDBMetaEngineDetection() : AdvancedMetaEngineDetection(HDB::gameDescriptions, hdbGames) {
}
const char *getName() const override {
return "hdb";
}
const char *getEngineName() const override {
return "Hyperspace Delivery Boy!";
}
const char *getOriginalCopyright() const override {
return "Hyperspace Delivery Boy! (C) 2001 Monkeystone Games";
}
};
REGISTER_PLUGIN_STATIC(HDB_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, HDBMetaEngineDetection);

35
engines/hdb/detection.h Normal file
View File

@@ -0,0 +1,35 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_DETECTION_H
#define HDB_DETECTION_H
namespace HDB {
enum HDBGameFeatures {
GF_HANDANGO = (1 << 0)
};
#define GAMEOPTION_CHEATMODE GUIO_GAMEOPTIONS1
} // End of namespace HDB
#endif // HDB_DETECTION_H

View File

@@ -0,0 +1,210 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/debug.h"
#include "common/file.h"
#include "common/memstream.h"
#include "common/compression/deflate.h"
#include "hdb/hdb.h"
#include "hdb/file-manager.h"
namespace HDB {
FileMan::FileMan() {
_mpcFile = new Common::File;
_dataHeader.id = 0;
_dataHeader.dirSize = 0;
}
FileMan::~FileMan() {
delete _mpcFile;
for (uint i = 0; i < _dir.size(); i++)
delete _dir[i];
}
void FileMan::openMPC(const Common::Path &filename) {
if (!_mpcFile->open(filename))
error("FileMan::openMPC(): Error reading the MSD/MPC file %s", filename.toString().c_str());
_dataHeader.id = _mpcFile->readUint32BE();
if (_dataHeader.id == MKTAG('M', 'P', 'C', 'C'))
error("FileMan::openMPC: Compressed MPC File");
else if (_dataHeader.id == MKTAG('M', 'S', 'D', 'U'))
error("FileMan::openMPC: Uncompressed MSD File");
else if (_dataHeader.id != MKTAG('M', 'P', 'C', 'U') && _dataHeader.id != MKTAG('M', 'S', 'D', 'C'))
error("FileMan::openMPC: Invalid MPC/MSD File.");
// read the directory
uint32 offset = _mpcFile->readUint32LE();
_mpcFile->seek((int32)offset);
// Note: The MPC archive format assumes the offset to be uint32,
// but Common::File::seek() takes the offset as int32.
_dataHeader.dirSize = _mpcFile->readUint32LE();
debug(8, "MPCU: Read %d entries", _dataHeader.dirSize);
for (uint32 fileIndex = 0; fileIndex < _dataHeader.dirSize; fileIndex++) {
MPCEntry *dirEntry = new MPCEntry();
for (int i = 0; i < 64; i++)
dirEntry->filename[i] = tolower(_mpcFile->readByte());
dirEntry->offset = _mpcFile->readUint32LE();
dirEntry->length = _mpcFile->readUint32LE();
dirEntry->ulength = _mpcFile->readUint32LE();
dirEntry->type = (DataType)_mpcFile->readUint32LE();
debug(9, "%d: %s off:%d len:%d ulen: %d type: %d", fileIndex, dirEntry->filename, dirEntry->offset, dirEntry->length, dirEntry->ulength, dirEntry->type);
_dir.push_back(dirEntry);
}
}
void FileMan::closeMPC() {
_dir.clear();
_mpcFile->close();
}
void FileMan::seek(int32 offset, int flag) {
_mpcFile->seek(offset, flag);
}
Common::SeekableReadStream *FileMan::findFirstData(const char *string, DataType type, int *length) {
Common::String fileString;
MPCEntry *file = nullptr;
char fname[128];
Common::strlcpy(fname, string, 128);
char *pDest = strrchr(fname, '.');
if (pDest)
*pDest = '_';
debug(8, "Looking for Data: '%s' <- '%s'", fname, string);
Common::String fnameS(fname);
fnameS.toLowercase();
// Find MPC Entry
for (MPCIterator it = _dir.begin(); it != _dir.end(); it++) {
fileString = (*it)->filename;
if (fileString.equals(fnameS)) {
if ((*it)->type == type) {
file = *it;
break;
} else {
debug(4, "Found Data but type mismatch: '%s', target: %d, found: %d", fnameS.c_str(), type, (*it)->type);
}
}
}
if (file == nullptr) {
debug(4, "Couldn't find Data: '%s'", fnameS.c_str());
return nullptr;
}
// Load corresponding file into a buffer
_mpcFile->seek(file->offset);
byte *buffer = (byte *)malloc(file->length);
_mpcFile->read(buffer, file->length);
if (length)
*length = file->ulength;
// Return buffer wrapped in a MemoryReadStream, automatically
// uncompressed if it is zlib-compressed
return Common::wrapCompressedReadStream(new Common::MemoryReadStream(buffer, file->length, DisposeAfterUse::YES), DisposeAfterUse::YES, file->length);
}
int32 FileMan::getLength(const char *string, DataType type) {
Common::String fileString;
MPCEntry *file = nullptr;
char fname[128];
Common::strlcpy(fname, string, 128);
char *pDest = strrchr(fname, '.');
if (pDest)
*pDest = '_';
Common::String fnameS(fname);
fnameS.toLowercase();
// Find MPC Entry
for (MPCIterator it = _dir.begin(); it != _dir.end(); it++) {
fileString = (*it)->filename;
if (fileString.contains(fnameS)) {
if ((*it)->type == type) {
file = *it;
break;
}
}
}
if (file == nullptr) {
return 0;
}
return file->ulength;
}
int FileMan::getCount(const char *subString, DataType type) {
int count = 0;
Common::String fileString;
Common::String fnameS(subString);
fnameS.toLowercase();
for (MPCIterator it = _dir.begin(); it != _dir.end(); it++) {
fileString = (*it)->filename;
if (fileString.contains(fnameS)) {
if ((*it)->type == type) {
count++;
}
}
}
return count;
}
Common::Array<const char *> *FileMan::findFiles(const char *string, DataType type) {
Common::Array<const char *> *result = new Common::Array<const char *>;
Common::String fileString;
Common::String fnameS(string);
fnameS.toLowercase();
// Find MPC Entry
for (MPCIterator it = _dir.begin(); it != _dir.end(); it++) {
fileString = (*it)->filename;
if (fileString.contains(fnameS)) {
if ((*it)->type == type) {
result->push_back((*it)->filename);
}
}
}
return result;
}
} // End of Namespace HDB

View File

@@ -0,0 +1,83 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_FILE_MANAGER_H
#define HDB_FILE_MANAGER_H
namespace Common {
class File;
}
#define MPCIterator Common::Array<MPCEntry *>::iterator
namespace HDB {
// Each entry in a MSD file is of the following types
enum DataType {
TYPE_ERROR,
TYPE_BINARY,
TYPE_TILE32,
TYPE_FONT,
TYPE_ICON32,
TYPE_PIC,
ENDOFTYPES
};
struct MPCEntry {
char filename[64]; // filename
int32 offset; // offset in MSD file of data
int32 length; // compressed length of data
int32 ulength; // uncompressed length
DataType type; // type of data
};
class FileMan {
private:
Common::File *_mpcFile;
Common::Array<MPCEntry *> _dir;
public:
FileMan();
~FileMan();
struct {
uint32 id;
uint32 dirSize;
} _dataHeader;
void openMPC(const Common::Path &filename);
void closeMPC();
void seek(int32 offset, int flag);
Common::SeekableReadStream *findFirstData(const char *string, DataType type, int *length = nullptr);
int32 getLength(const char *string, DataType type);
int getCount(const char *subString, DataType type);
Common::Array<const char *> *findFiles(const char *string, DataType type);
};
} // End of Namespace HDB
#endif // !HDB_FILE_MANAGER_H

1462
engines/hdb/gfx.cpp Normal file

File diff suppressed because it is too large Load Diff

277
engines/hdb/gfx.h Normal file
View File

@@ -0,0 +1,277 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_GFX_H
#define HDB_GFX_H
#include "graphics/managed_surface.h"
namespace Math {
class SineTable;
class CosineTable;
}
namespace HDB {
#define HDB_FONT "normalprop"
struct TileLookup {
const char *filename;
Tile *tData;
uint16 skyIndex;
uint16 animIndex;
TileLookup() : filename(nullptr), tData(nullptr), skyIndex(0), animIndex(0) {}
};
struct GfxCache {
char name[32];
bool status; // false = tileGfx, true = picGfx
union {
Tile *tileGfx;
Picture *picGfx;
};
uint32 size;
int16 loaded;
GfxCache() : status(false), tileGfx(nullptr), size(0), loaded(0) { name[0] = 0; }
};
struct FontInfo {
int type; // 0 = mono, 1 = proportional
int numChars; // how many characters in font
int height; // height of entire font
int kerning; // space between chars
int leading; // space between lines
};
struct CharInfo {
int16 width; // Character width in pixels
int32 offset; // From the start of the font charInfo chunk
};
class Gfx {
public:
Gfx();
~Gfx();
Graphics::ManagedSurface _globalSurface;
void init();
void save(Common::OutSaveFile *out);
void loadSaveFile(Common::InSaveFile *in);
void fillScreen(uint32 color);
void updateVideo();
void setPointerState(int value);
void drawPointer();
void showPointer(bool status) {
_showCursor = status;
}
bool getPointer() {
return _showCursor;
}
void setFade(bool fadeIn, bool black, int steps);
void updateFade();
bool isFadeActive() { return _fadeInfo.active; }
bool isFadeStaying() { return _fadeInfo.stayFaded; }
void turnOffFade() { _fadeInfo.active = _fadeInfo.stayFaded = false; }
void turnOnSnow();
void turnOffSnow() { _snowInfo.active = false; }
Picture *loadPic(const char *picName);
Tile *loadTile(const char *tileName);
Tile *loadIcon(const char *tileName);
void setPixel(int x, int y, uint16 color);
Tile *getTile(int index);
void cacheTileSequence(int index, int count);
int getTileIndex(const char *name);
Picture *getPicture(const char *name);
void emptyGfxCaches();
void markTileCacheFreeable();
void markGfxCacheFreeable();
// Returns: true->Tile, false->Pic
bool selectGfxType(const char *name);
Tile *getTileGfx(const char *name, int32 size);
Picture *getPicGfx(const char *name, int32 size);
int isSky(int skyIndex);
void setSky(int skyIndex);
void setup3DStars();
void setup3DStarsLeft();
void draw3DStars();
void draw3DStarsLeft();
void drawSky();
void drawSnow();
int animateTile(int tileIndex);
// Font Functions
bool loadFont(const char *string);
void drawText(const char *string);
void getDimensions(const char *string, int *pixelsWide, int *lines);
int stringLength(const char *string);
void centerPrint(const char *string);
void setTextEdges(int left, int right, int top, int bottom);
void getTextEdges(int *left, int *right, int *top, int *bottom);
void setKernLead(int kern, int lead);
void getKernLead(int *kern, int *lead);
void setCursor(int x, int y);
void getCursor(int *x, int *y);
// Trig Functions
double getSin(int index);
double getCos(int index);
// Bonus star functions
void turnOnBonusStars(int which);
void drawBonusStars();
void drawDebugInfo(Tile *_debugLogo, int fps);
private:
int _numTiles;
TileLookup *_tLookupArray;
uint16 _skyTiles[kMaxSkies];
Graphics::ManagedSurface _fadeBuffer1, _fadeBuffer2;
Common::Array<GfxCache *> *_gfxCache;
int _currentSky; // 0 if no Sky, 1+ for which Sky to use
struct {
bool active;
bool stayFaded;
bool isBlack;
int speed;
bool isFadeIn;
int curStep;
} _fadeInfo;
#define MAX_SNOW 50 // how many snowflakes onscreen
#define MAX_SNOW_XV 12
struct {
bool active;
double x[MAX_SNOW];
double y[MAX_SNOW];
double yv[MAX_SNOW];
int xvindex[MAX_SNOW];
} _snowInfo;
struct {
int x, y, speed;
uint16 color;
} _stars3D[kNum3DStars];
struct {
double x, y, speed;
uint16 color;
} _stars3DSlow[kNum3DStars];
int _tileSkyStars; // Index of sky_stars tile
int _tileSkyStarsLeft; // Left-scrolling stars, slow
int _tileSkyClouds; // Index of sky_stars tile
Picture *_starField[4];
Picture *_snowflake;
Picture *_skyClouds;
struct {
bool active;
int starAngle[10];
Picture *gfx[2];
uint32 timer;
int anim, radius;
double angleSpeed;
uint32 totalTime;
} _starsInfo;
// Cursor
int _cursorX, _cursorY;
Picture *_mousePointer[8]; // Gfx for screen pointer (4 Animations)
int _pointerDisplayable;
bool _showCursor;
// Font Data
FontInfo _fontHeader;
Common::Array<CharInfo *> _charInfoBlocks;
Graphics::Surface _fontSurfaces[256];
uint16 _fontGfx;
int _eLeft, _eRight, _eTop, _eBottom;
bool _systemInit;
Math::SineTable *_sines;
Math::CosineTable *_cosines;
};
class Picture {
public:
Picture();
~Picture();
Graphics::Surface load(Common::SeekableReadStream *stream);
int draw(int x, int y);
int drawMasked(int x, int y, int alpha = 0xff);
int _width, _height;
char *getName() { return _name; }
Graphics::ManagedSurface *getSurface() { return &_surface; }
private:
char _name[64];
Graphics::ManagedSurface _surface;
};
class Tile {
public:
Tile();
~Tile();
Graphics::Surface load(Common::SeekableReadStream *stream);
int draw(int x, int y);
int drawMasked(int x, int y, int alpha = 0xff);
uint32 _flags;
char *getName() { return _name; }
private:
char _name[64];
Graphics::ManagedSurface _surface;
};
} // End of Namespace HDB
#endif // !HDB_GFX_H

1135
engines/hdb/hdb.cpp Normal file

File diff suppressed because it is too large Load Diff

384
engines/hdb/hdb.h Normal file
View File

@@ -0,0 +1,384 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_HDB_H
#define HDB_HDB_H
#include "common/scummsys.h"
#include "common/system.h"
#include "common/savefile.h"
#include "common/fs.h"
#include "engines/engine.h"
namespace Common {
class RandomSource;
}
namespace HDB {
class AI;
struct AIEntity;
class FileMan;
class Gfx;
class Input;
class LuaScript;
class Map;
class Menu;
class Tile;
class Picture;
class Sound;
class Window;
#define CONFIG_MUSICVOL "music_volume"
#define CONFIG_SFXVOL "sfx_volume"
#define CONFIG_SPEECHVOL "speech_volume"
#define CONFIG_MSTONE7 "hdb_memory_heap"
#define CONFIG_MSTONE14 "lua_stack_offset"
#define CONFIG_MSTONE21 "fmod_mix_timer"
#define CONFIG_SOUNDCACHE "sound_cache_max" // Unused
#define CONFIG_GFXCACHE "gfx_cache_max" // Unused
#define CONFIG_CHEAT "hypercheat"
#define CONFIG_NOSPEECH "speech_mute"
#define CONFIG_MUTEALL "mute"
enum {
kTileWidth = 32,
kTileHeight = 32,
kMaxSkies = 10,
kNum3DStars = 300,
kFontSpace = 5,
kFontIncrement = 1,
kGameFPS = 60,
kAnimFrameDelay = kGameFPS / 30,
kAnimSlowFrames = kAnimFrameDelay * 10,
kAnimMediumFrames = kAnimFrameDelay * 6,
kAnimFastFrames = kAnimFrameDelay * 2
};
}
struct ADGameDescription;
namespace HDB {
enum GameState {
GAME_TITLE,
GAME_MENU,
GAME_PLAY,
GAME_LOADING
};
enum Flag {
kFlagOK = 0x0,
kFlagPlayerBlock = 0x1,
kFlagMonsterBlock = 0x2,
kFlagSolid = 0x3,
kFlagItemDie = 0x4,
kFlagPlayerDie = 0x8,
kFlagMonsterDie = 0x10,
kFlagInvisible = 0x20,
kFlagMetal = 0x40,
kFlagForeground = 0x80,
kFlagMonsterHurt = 0x100,
kFlagPushUp = 0x200,
kFlagPushRight = 0x400,
kFlagPushDown = 0x800,
kFlagPushLeft = 0x1000,
kFlagLightSink = 0x2000,
kFlagSlime = 0x201C,
kFlagHeavySink = 0x4000,
kFlagWater = 0x401C,
kFlagLightMelt = 0x8000,
kFlagHeavyMelt = 0x10000,
kFlagSlide = 0x20000,
kFlagEnergyFloor = 0x40000,
kFlagPlasmaFloor = 0x6000D,
kFlagRadFloor = 0x6800D,
kFlagTeleport = 0x80000,
kFlagSpecial = 0x100000,
kFlagIce = 0x120000,
kFlagStairBot = 0x200000,
kFlagStairTop = 0x400000,
kFlagAnimSlow = 0x800000,
kFlagAnimMedium = 0x1000000,
kFlagAnimFast = 0x1800000,
kFlagMasked = 0x2000000,
kFlagGrating = 0x4000000,
kFlagPlummet = 0x8000000
};
struct Save {
char saveID[12];
int fileSlot;
char mapName[32];
uint32 seconds;
Save() : fileSlot(0), seconds(0) {
saveID[0] = 0;
mapName[0] = 0;
}
};
class HDBGame : public Engine {
public:
HDBGame(OSystem *syst, const ADGameDescription *gameDesc);
~HDBGame() override;
bool hasFeature(Engine::EngineFeature f) const override;
void initializePath(const Common::FSNode &gamePath) override;
Common::Error run() override;
void syncSoundSettings() override;
// Detection related members;
const ADGameDescription *_gameDescription;
const char *getGameId() const;
const char *getGameFile() const;
uint32 getGameFlags() const;
Common::Platform getPlatform() const;
bool isDemo() const;
bool isPPC() const;
bool isHandango() const;
// Platform-Specific Constants
int _screenWidth;
int _screenHeight;
int _screenDrawWidth; // visible pixels wide
int _screenDrawHeight;
int _progressY;
/*
Game System Pointers
*/
FileMan *_fileMan;
Gfx *_gfx;
LuaScript *_lua;
Map *_map;
AI *_ai;
Input *_input;
Menu *_menu;
Sound *_sound;
Window *_window;
// Random Source
Common::RandomSource *_rnd;
// Game related members;
bool init();
void save(Common::OutSaveFile *out);
void loadSaveFile(Common::InSaveFile *in);
void start();
bool restartMap();
bool startMap(const char *name);
void changeMap(const char *name) {
Common::strlcpy(_changeMapname, name, 64);
_changeLevel = true;
}
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
Common::Error loadGameState(int slot) override;
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override;
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override;
void saveGame(Common::OutSaveFile *out);
void loadGame(Common::InSaveFile *in);
Common::String genSaveFileName(uint slot, bool lua);
void saveWhenReady(int slot) {
_saveInfo.active = true;
_saveInfo.slot = slot;
}
void loadWhenReady(int slot) {
_loadInfo.active = true;
_loadInfo.slot = slot;
}
void setGameState(GameState gs) {
_gameState = gs;
}
GameState getGameState() {
return _gameState;
}
void changeGameState();
void paint();
void moveMap(int x, int y); // Get Stylus Coords and Scroll
void startMoveMap(int x, int y); // Start Dragging Map
void setTargetXY(int x, int y);
void useEntity(AIEntity *e);
void setupProgressBar(int maxCount);
void drawProgressBar();
void makeProgress() {
_progressCurrent++;
drawProgressBar();
}
void checkProgress();
void stopProgress() {
_progressActive = false;
}
void drawLoadingScreen();
int getActionMode() {
return _actionMode;
}
void setActionMode(int status) {
_actionMode = status;
}
void togglePause() {
_pauseFlag ^= true;
}
bool getPause() {
return _pauseFlag;
}
void resetTimer() {
_timePlayed = _timeSeconds = 0;
}
uint32 getTime() {
return _timePlayed / 1000;
}
uint32 getTimeSlice() {
return _timeSlice;
}
uint32 getTimeSliceDelta() {
return _timeSlice - _prevTimeSlice;
}
const Common::String *getTargetName() {
return &_targetName;
}
int getDebug() { return _debugFlag; }
void setDebug(int flag) { _debugFlag = flag; }
bool isVoiceless() {
/*
FIXME: Add hyperspace-nv.mpc to gameDescriptions[]
in detection.cpp, and add a flag check for it.
Until then, the voiceless version is unsupported.
*/
return false;
}
char *lastMapName() { return _lastMapname; }
char *currentMapName() { return _currentMapname; }
char *getInMapName() { return _inMapName; }
void setInMapName(const char *name);
void changeLevel(const char *name) {
Common::strlcpy(_changeMapname, name, 64);
_changeLevel = true;
}
//
// monkeystone secret stars
//
int32 getStarsMonkeystone7() { return _monkeystone7; }
int32 getStarsMonkeystone14() { return _monkeystone14; }
int32 getStarsMonkeystone21() { return _monkeystone21; }
void setStarsMonkeystone7(int32 value) { _monkeystone7 = value; }
void setStarsMonkeystone14(int32 value) { _monkeystone14 = value; }
void setStarsMonkeystone21(int32 value) { _monkeystone21 = value; }
void setCheatingOn() {
_cheating = true;
}
bool getCheatingOn() {
return _cheating;
}
Save _saveHeader;
bool _gameShutdown;
Graphics::PixelFormat _format;
Picture *_progressGfx, *_progressMarkGfx;
Picture *_loadingScreenGfx, *_logoGfx;
bool _progressActive;
int _progressCurrent, _progressXOffset, _progressMax;
// FPS Variables
Common::Array<uint32> _frames;
Common::OutSaveFile *_currentOutSaveFile;
Common::InSaveFile *_currentInSaveFile;
private:
uint32 _timePlayed;
uint32 _timeSlice, _prevTimeSlice;
uint32 _timeSeconds;
uint32 _tiempo;
// Game Variables
bool _systemInit;
GameState _gameState;
int _actionMode; // 0 or 1
// Misc Variables
bool _pauseFlag;
bool _cheating;
int _debugFlag;
Tile *_debugLogo;
int _dx, _dy; // DEBUG : for dragging map
char _currentMapname[64];
char _lastMapname[64];
char _currentLuaName[64];
char _lastLuaName[64];
char _inMapName[32]; // Name Inside Map file
int32 _monkeystone7;
int32 _monkeystone14;
int32 _monkeystone21;
bool _changeLevel;
char _changeMapname[64];
struct {
bool active;
int slot;
} _saveInfo, _loadInfo;
bool _noMusicDriver; // If "Music Device" is set to "No Music" from Audio tab
};
extern HDBGame *g_hdb;
}// End of namespace HDB
#endif

550
engines/hdb/input.cpp Normal file
View File

@@ -0,0 +1,550 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "hdb/hdb.h"
#include "hdb/ai.h"
#include "hdb/gfx.h"
#include "hdb/input.h"
#include "hdb/map.h"
#include "hdb/sound.h"
#include "hdb/menu.h"
#include "hdb/window.h"
namespace HDB {
void Input::init() {
_stylusDown = false;
_buttons = 0;
_mouseX = g_hdb->_screenWidth / 2;
_mouseY = g_hdb->_screenHeight / 2;
}
void Input::setButtons(uint16 b) {
_buttons = b;
if (!b)
return;
// Change Game State
if ((_buttons & kButtonA) && (g_hdb->getGameState() != GAME_MENU)) {
if (g_hdb->_ai->cinematicsActive() && g_hdb->_ai->cineAbortable()) {
g_hdb->_ai->cineAbort();
g_hdb->_sound->playSound(SND_POP);
return;
}
if (g_hdb->getGameState() == GAME_TITLE)
g_hdb->_menu->changeToMenu();
g_hdb->_sound->playSound(SND_MENU_BACKOUT);
g_hdb->changeGameState();
}
if (g_hdb->isPPC()) {
if (_buttons & kButtonD) {
if (g_hdb->_window->inventoryActive()) {
g_hdb->_window->closeInv();
g_hdb->_window->openDeliveries(false);
} else if (g_hdb->_window->deliveriesActive()) {
g_hdb->_window->closeDlvs();
} else {
g_hdb->_window->openInventory();
}
return;
}
}
// Debug Mode Cycling
if ((_buttons & kButtonExit) && g_hdb->getCheatingOn()) {
int debugFlag = g_hdb->getDebug();
debugFlag++;
if (debugFlag > 2)
debugFlag = 0;
g_hdb->setDebug(debugFlag);
if (debugFlag == 2)
g_hdb->_ai->clearWaypoints();
if (!debugFlag && g_hdb->getGameState() == GAME_PLAY) {
int x, y;
g_hdb->_ai->getPlayerXY(&x, &y);
g_hdb->_map->centerMapXY(x + 16, y + 16); // point to center of player
}
}
if (g_hdb->getGameState() == GAME_PLAY) {
// Is Player Dead? Click on TRY AGAIN
if (g_hdb->_ai->playerDead()) {
// TRY AGAIN is onscreen...
if (_buttons & kButtonB) {
if (g_hdb->loadGameState(kAutoSaveSlot).getCode() == Common::kNoError) {
g_hdb->_window->clearTryAgain();
g_hdb->setGameState(GAME_PLAY);
}
}
return;
}
if (g_hdb->isPPC()) {
// Deliveries screen?
if (g_hdb->_window->deliveriesActive() && !g_hdb->_window->animatingDelivery()) {
if (_buttons & kButtonLeft) {
int amount = g_hdb->_ai->getDeliveriesAmount();
int current = g_hdb->_window->getSelectedDelivery();
if (!current)
current = amount - 1;
else
current--;
g_hdb->_window->setSelectedDelivery(current);
} else if (_buttons & kButtonRight) {
int amount = g_hdb->_ai->getDeliveriesAmount();
int current = g_hdb->_window->getSelectedDelivery();
current++;
if (current == amount)
current = 0;
g_hdb->_window->setSelectedDelivery(current);
} else if (_buttons & kButtonB)
g_hdb->_window->closeDlvs();
return;
}
//
// Resources screen? Move select cursor around
//
if (g_hdb->_window->inventoryActive()) {
// select weapon?
if (_buttons & kButtonB) {
static AIType lastWeaponSelected = AI_NONE;
if (!g_hdb->getActionMode()) {
g_hdb->_window->closeInv();
return;
}
AIType t = g_hdb->_ai->getInvItemType(g_hdb->_window->getInvSelect());
Tile *gfx = g_hdb->_ai->getInvItemGfx(g_hdb->_window->getInvSelect());
switch (t) {
case ITEM_CLUB:
case ITEM_ROBOSTUNNER:
case ITEM_SLUGSLINGER:
g_hdb->_ai->setPlayerWeapon(t, gfx);
if (t == lastWeaponSelected) {
g_hdb->_window->closeInv();
return;
}
lastWeaponSelected = t;
g_hdb->_sound->playSound(SND_MENU_ACCEPT);
return;
default:
break;
}
g_hdb->_sound->playSound(SND_CELLHOLDER_USE_REJECT);
return;
}
if (_buttons & kButtonLeft) {
int amount = g_hdb->_ai->getInvMax();
int current = g_hdb->_window->getInvSelect();
if (!amount)
return;
if (current == 5)
current = amount - 1;
else if (!current && amount > 5)
current = 4;
else if (!current)
current = amount - 1;
else
current--;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
g_hdb->_window->setInvSelect(current);
} else if (_buttons & kButtonRight) {
int amount = g_hdb->_ai->getInvMax();
int current = g_hdb->_window->getInvSelect();
if (!amount)
return;
if (amount > 5) {
if (current == amount - 1)
current = 5;
else if (current == 4)
current = 0;
else
current++;
} else if (current == amount - 1)
current = 0;
else
current++;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
g_hdb->_window->setInvSelect(current);
} else if (_buttons & kButtonUp) {
int amount = g_hdb->_ai->getInvMax();
int current = g_hdb->_window->getInvSelect();
if (amount < 6)
return;
if (current - 5 >= 0)
current -= 5;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
g_hdb->_window->setInvSelect(current);
} else if (_buttons & kButtonDown) {
int amount = g_hdb->_ai->getInvMax();
int current = g_hdb->_window->getInvSelect();
if (amount < 6)
return;
if (current + 5 < amount)
current += 5;
else if (current < 5)
current = amount - 1;
g_hdb->_sound->playSound(SND_MENU_SLIDER);
g_hdb->_window->setInvSelect(current);
}
return;
}
}
// Choose from DialogChoice
if (g_hdb->_window->dialogChoiceActive()) {
if (_buttons & kButtonUp)
g_hdb->_window->dialogChoiceMoveup();
else if (_buttons & kButtonDown)
g_hdb->_window->dialogChoiceMovedown();
else if (_buttons & kButtonB)
g_hdb->_window->closeDialogChoice();
return;
}
// Try to move the player
if (!g_hdb->_ai->playerDead())
g_hdb->_ai->movePlayer(_buttons);
}
}
uint16 Input::getButtons() {
return _buttons;
}
void Input::stylusDown(int x, int y) {
static uint32 delay = 0, time;
// Don't let the screen get clicked too fast
time = g_system->getMillis();
if (time - delay < 100)
return;
time = delay;
GameState gs = g_hdb->getGameState();
switch (gs) {
case GAME_TITLE:
g_hdb->_menu->changeToMenu();
g_hdb->changeGameState();
break;
case GAME_MENU:
g_hdb->_menu->processInput(x, y);
break;
case GAME_PLAY:
{
// Is Player Dead? Click on TRY AGAIN
if (g_hdb->_ai->playerDead()) {
if (y >= g_hdb->_window->_tryRestartY && y <= g_hdb->_window->_tryRestartY + 24) {
if (g_hdb->loadGameState(kAutoSaveSlot).getCode() == Common::kNoError) {
g_hdb->_window->clearTryAgain();
g_hdb->setGameState(GAME_PLAY);
}
}
return;
}
if (g_hdb->isPPC()) {
// is Deliveries active?
if (g_hdb->_window->deliveriesActive()) {
if (!g_hdb->_window->checkDlvsClose(x, y))
return;
if (!g_hdb->_ai->cinematicsActive())
return;
}
// is Inventory active?
if (g_hdb->_window->inventoryActive()) {
if (!g_hdb->_window->checkInvClose(x, y))
return;
if (!g_hdb->_ai->cinematicsActive())
return;
}
}
// Is Dialog Active?
if (g_hdb->_window->dialogActive()) {
g_hdb->_window->closeDialog();
if (!g_hdb->_ai->cinematicsActive())
return;
}
// Is a Choice Dialog Active?
if (g_hdb->_window->dialogChoiceActive()) {
if (!g_hdb->_window->checkDialogChoiceClose(x, y))
return;
if (!g_hdb->_ai->cinematicsActive())
return;
}
// Is MessageBar active?
if (g_hdb->_window->msgBarActive()) {
if (g_hdb->_window->checkMsgClose(x, y))
return;
}
// In a cinematic?
if (g_hdb->_ai->playerLocked())
return;
// Check for map dragging in debug Mode and place player there
if ((GAME_PLAY == g_hdb->getGameState()) && g_hdb->getDebug() == 2) {
int mx, my;
g_hdb->_map->getMapXY(&mx, &my);
mx = ((mx + x) / kTileWidth) * kTileWidth;
my = ((my + y) / kTileHeight) * kTileHeight;
g_hdb->_ai->setPlayerXY(mx, my);
g_hdb->startMoveMap(x, y);
return;
}
// Clicked in the world
int worldX, worldY;
g_hdb->_map->getMapXY(&worldX, &worldY);
worldX = ((worldX + x) / kTileWidth) * kTileWidth;
worldY = ((worldY + y) / kTileHeight) * kTileHeight;
if (!g_hdb->isPPC()) {
// Don't allow a click into INV/DELIVERIES area to go into the world
if (x >= (g_hdb->_screenWidth - 32 * 5))
return;
}
// Double-Clicking on the player to open inventory?
int nx, ny;
g_hdb->_ai->getPlayerXY(&nx, &ny);
if (g_hdb->isPPC()) {
if (nx == worldX && ny == worldY) {
static uint32 dblClickTimer = 0;
if (dblClickTimer && ((int)(g_system->getMillis() - dblClickTimer) < (int)(kGameFPS * 1000 / 60))) {
g_hdb->_window->openInventory();
dblClickTimer = 0;
g_hdb->_ai->togglePlayerRunning();
if (g_hdb->_ai->playerRunning())
g_hdb->_window->centerTextOut("Running Speed", g_hdb->_screenHeight - 32, kRunToggleDelay * kGameFPS);
else
g_hdb->_window->centerTextOut("Walking Speed", g_hdb->_screenHeight - 32, kRunToggleDelay * kGameFPS);
g_hdb->_sound->playSound(SND_SWITCH_USE);
return;
} else
dblClickTimer = g_system->getMillis();
}
}
// Toggle Walk Speed if we clicked Player
static uint32 lastRunning = g_system->getMillis();
if (nx == worldX && ny == worldY) {
if (lastRunning > g_system->getMillis())
return;
lastRunning = g_system->getMillis() + 1000 * kRunToggleDelay;
g_hdb->_ai->togglePlayerRunning();
if (g_hdb->_ai->playerRunning())
g_hdb->_window->centerTextOut("Running Speed", g_hdb->_screenHeight - 32, kRunToggleDelay * kGameFPS);
else
g_hdb->_window->centerTextOut("Walking Speed", g_hdb->_screenHeight - 32, kRunToggleDelay * kGameFPS);
g_hdb->_sound->playSound(SND_SWITCH_USE);
}
g_hdb->setTargetXY(worldX, worldY);
break;
}
case GAME_LOADING:
break;
default:
break;
}
}
void Input::stylusMove(int x, int y) {
// In a cinematic?
if (g_hdb->_ai->playerLocked() || g_hdb->_ai->playerDead())
return;
switch (g_hdb->getGameState()) {
case GAME_PLAY:
if (g_hdb->getDebug() == 2)
g_hdb->moveMap(x, y);
break;
case GAME_MENU:
g_hdb->_menu->processInput(x, y);
break;
default:
break;
}
}
void Input::updateMouse(int newX, int newY) {
_mouseX = CLIP(newX, 0, g_hdb->_screenWidth - 1);
_mouseY = CLIP(newY, 0, g_hdb->_screenHeight - 1);
// Turn Cursor back on?
if (!g_hdb->_gfx->getPointer())
g_hdb->_gfx->showPointer(true);
// Check if LButton is being dragged
if (_stylusDown)
stylusMove(_mouseX, _mouseY);
}
void Input::updateMouseButtons(bool isDown) {
_stylusDown = isDown;
// Check if LButton has been pressed
// Check if LButton has been lifted
if (isDown) {
if (g_hdb->isPPC()) {
stylusDown(_mouseX, _mouseY);
return;
}
if (_mouseX > (g_hdb->_screenWidth - 32 * 5) && _mouseY < 240) {
g_hdb->_window->checkInvSelect(_mouseX, _mouseY);
} else if (_mouseX > (g_hdb->_screenWidth - 32 * 5) && _mouseY >= 240) {
g_hdb->_window->checkDlvSelect(_mouseX, _mouseY);
} else {
if (g_hdb->getPause() && g_hdb->getGameState() == GAME_PLAY) {
g_hdb->_window->checkPause(_mouseX, _mouseY);
return;
}
stylusDown(_mouseX, _mouseY);
}
}
}
void Input::updateActions(Common::Event event, bool keyDown, bool fromMouse) {
static bool current = false, last = false;
if (keyDown && event.customType == kHDBActionQuit) {
g_hdb->quitGame();
return;
}
uint16 buttons = getButtons();
// PAUSE key pressed?
last = current;
if (keyDown && event.customType == kHDBActionPause && g_hdb->getGameState() == GAME_PLAY) {
current = true;
if (!last) {
g_hdb->togglePause();
g_hdb->_sound->playSound(SND_POP);
}
} else
current = false;
if (!g_hdb->getPause()) {
if (event.customType == kHDBActionUp) {
if (keyDown) {
buttons |= kButtonUp;
if (g_hdb->_gfx->getPointer() && !fromMouse)
g_hdb->_gfx->showPointer(false);
} else {
buttons &= ~kButtonUp;
}
} else if (event.customType == kHDBActionDown) {
if (keyDown) {
buttons |= kButtonDown;
if (g_hdb->_gfx->getPointer() && !fromMouse)
g_hdb->_gfx->showPointer(false);
} else {
buttons &= ~kButtonDown;
}
} else if (event.customType == kHDBActionLeft) {
if (keyDown) {
buttons |= kButtonLeft;
if (g_hdb->_gfx->getPointer() && !fromMouse)
g_hdb->_gfx->showPointer(false);
} else {
buttons &= ~kButtonLeft;
}
} else if (event.customType == kHDBActionRight) {
if (keyDown) {
buttons |= kButtonRight;
if (g_hdb->_gfx->getPointer() && !fromMouse)
g_hdb->_gfx->showPointer(false);
} else {
buttons &= ~kButtonRight;
}
} else if (event.customType == kHDBActionUse) {
if (keyDown) {
buttons |= kButtonB;
if (g_hdb->_gfx->getPointer() && !fromMouse)
g_hdb->_gfx->showPointer(false);
} else {
buttons &= ~kButtonB;
}
} else if (event.customType == kHDBActionClearWaypoints) {
if (keyDown) {
g_hdb->_ai->clearWaypoints();
g_hdb->_sound->playSound(SND_POP);
}
}
// TODO: Inventory key
}
if (event.customType == kHDBActionMenu) {
if (keyDown) {
buttons |= kButtonA;
g_hdb->_gfx->showPointer(true);
g_hdb->_menu->setMenuKey(1);
} else {
buttons &= ~kButtonA;
g_hdb->_menu->setMenuKey(0);
}
} else if (event.customType == kHDBActionDebug) {
if (keyDown)
buttons |= kButtonExit;
else
buttons &= ~kButtonExit;
}
setButtons(buttons);
}
} // End of Namespace

87
engines/hdb/input.h Normal file
View File

@@ -0,0 +1,87 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_INPUT_H
#define HDB_INPUT_H
#include "common/events.h"
namespace HDB {
enum Button {
kButtonUp = 2 << 0,
kButtonDown = 2 << 1,
kButtonLeft = 2 << 2,
kButtonRight = 2 << 3,
kButtonA = 2 << 4,
kButtonB = 2 << 5,
kButtonC = 2 << 6,
kButtonD = 2 << 7,
kButtonExit = 2 << 8
};
enum HDBAction {
kHDBActionNone,
kHDBActionUp,
kHDBActionDown,
kHDBActionLeft,
kHDBActionRight,
kHDBActionUse,
kHDBActionClearWaypoints,
kHDBActionInventory,
kHDBActionMenu,
kHDBActionPause,
kHDBActionDebug,
kHDBActionQuit
};
class Input {
public:
void init();
void setButtons(uint16 b);
uint16 getButtons();
void stylusDown(int x, int y);
void stylusUp(int x, int y);
void stylusMove(int x, int y);
void updateMouse(int newX, int newY);
void updateMouseButtons(bool isDown);
void updateActions(Common::Event event, bool keyDown, bool fromMouse);
int getMouseX() {
return _mouseX;
}
int getMouseY() {
return _mouseY;
}
private:
uint16 _buttons; // Flags for buttons
bool _stylusDown;
int _mouseX, _mouseY;
};
} // End of Namespace
#endif // !HDB_INPUT_H

2118
engines/hdb/lua-script.cpp Normal file

File diff suppressed because it is too large Load Diff

99
engines/hdb/lua-script.h Normal file
View File

@@ -0,0 +1,99 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_LUA_SCRIPT_H
#define HDB_LUA_SCRIPT_H
struct lua_State;
namespace HDB {
struct Global {
char global[32]; // name of global variable
int valueOrString; // value = 0, string = 1
double value; // value
char string[32]; // string
Global() : valueOrString(0), value(0) {
global[0] = 0;
string[0] = 0;
}
};
class LuaScript {
public:
LuaScript();
~LuaScript();
bool loadLua(const char *name);
void saveGlobalNumber(const char *global, double value);
void saveGlobalString(const char *global, const char *string);
void loadGlobal(const char *global);
void purgeGlobals();
void save(Common::OutSaveFile *out);
void loadSaveFile(Common::InSaveFile *in);
void init();
bool initScript(Common::SeekableReadStream *stream, const char *scriptName, int32 length);
void pushInt(int value);
void pushString(char *string);
void pushFunction(char *func);
void call(int args, int returns);
bool callFunction(const char *name, int returns);
void invokeLuaFunction(char *luaFunc, int x, int y, int value1, int value2);
bool executeMPC(Common::SeekableReadStream *stream, const char *name, const char *scriptName, int32 length);
bool executeFile(const Common::String &filename);
bool executeChunk(Common::String &chunk, const Common::String &chunkName) const;
void checkParameters(const char *func, int params);
const char *getStringOffStack();
void setLuaGlobalValue(const char *name, int value);
bool isValid() {
return _systemInit;
}
// Platform-specific Constants
int _cameraXOff;
int _cameraYOff;
private:
lua_State *_state;
int _pcallErrorhandlerRegistryIndex;
Common::SeekableReadStream* _globalLuaStream;
int32 _globalLuaLength;
bool _systemInit;
bool registerExtensions();
void stripComments(char *chunk);
void addPatches(Common::String &chunk, const char *scriptName);
Common::Array<Global *> _globals;
};
void lua_printstack(lua_State *L);
}
#endif // !HDB_LUA_SCRIPT_H

1235
engines/hdb/map.cpp Normal file

File diff suppressed because it is too large Load Diff

184
engines/hdb/map.h Normal file
View File

@@ -0,0 +1,184 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_MAP_H
#define HDB_MAP_H
namespace HDB {
enum {
kMaxGratings = 250,
kMaxForegrounds = 250
};
struct MSMIcon {
uint16 icon; // index into icon list
uint16 x;
uint16 y;
char funcInit[32]; // Lua init function for this entity
char funcAction[32];
char funcUse[32];
uint16 dir; // direction entity is facing
uint16 level; // which floor level entity is on
uint16 value1, value2;
MSMIcon(): icon(0), x(0), y(0), dir(0), level(0), value1(0), value2(0) {
funcInit[0] = 0;
funcAction[0] = 0;
funcUse[0] = 0;
}
};
struct Foreground {
uint16 x;
uint16 y;
uint16 tile;
Foreground() : x(0), y(0), tile(0) {}
};
struct SeeThroughTile {
uint16 x;
uint16 y;
uint16 tile;
SeeThroughTile() : x(0), y(0), tile(0) {}
};
class Map {
public:
Map();
~Map();
void save(Common::OutSaveFile *out);
void loadSaveFile(Common::InSaveFile *in);
void restartSystem();
int loadTiles();
bool load(Common::SeekableReadStream *stream);
bool loadMap(char *name);
void draw();
void drawEnts();
void drawGratings();
void drawForegrounds();
bool isLoaded() {
return _mapLoaded;
}
bool onScreen(int x, int y);
int mapPixelWidth() {
return _width * kTileWidth;
}
int mapPixelHeight() {
return _height * kTileHeight;
}
uint32 getMapBGTileFlags(int x, int y);
uint32 getMapFGTileFlags(int x, int y);
int16 getMapBGTileIndex(int x, int y);
int16 getMapFGTileIndex(int x, int y);
void setMapBGTileIndex(int x, int y, int index);
void setMapFGTileIndex(int x, int y, int index);
void addBGTileAnimation(int x, int y);
void addFGTileAnimation(int x, int y);
void removeBGTileAnimation(int x, int y);
void removeFGTileAnimation(int x, int y);
void getMapXY(int *x, int *y);
void setMapXY(int x, int y);
void centerMapXY(int x, int y);
bool checkEntOnScreen(AIEntity *);
bool checkXYOnScreen(int x, int y);
// Check if one of the tiles in a range exists in the map on either layer
bool checkOneTileExistInRange(int tileIndex, int count);
bool explosionExist(int x, int y) {
return _mapExplosions[y * _width + x];
}
void setExplosion(int x, int y, int value) {
_mapExplosions[y * _width + x] = value;
}
bool boomBarrelExist(int x, int y) {
return _mapExpBarrels[y * _width + x];
}
void setBoomBarrel(int x, int y, int value) {
_mapExpBarrels[y * _width + x] = value;
}
bool laserBeamExist(int x, int y) {
return _mapLaserBeams[y * _width + x];
}
void setLaserBeam(int x, int y, int value) {
_mapLaserBeams[y * _width + x] = value;
}
void clearLaserBeams() {
uint size = _width * _height;
memset(_mapLaserBeams, 0, size);
}
// Platform-specific Constants;
int _screenXTiles;
int _screenYTiles;
int _screenTileWidth;
int _screenTileHeight;
uint16 _width, _height;
int _mapX, _mapY; // Coordinates of Map
int _mapTileX, _mapTileY; // Tile Coordinates of Map
int _mapTileXOff, _mapTileYOff; // Tile Coordinates Offset (0-31)
Foreground _gratings[kMaxGratings], _foregrounds[kMaxForegrounds];
int _numGratings, _numForegrounds;
int _animCycle; // Tile Animation Counter
Common::Array<uint32> _listBGAnimSlow;
Common::Array<uint32> _listBGAnimMedium;
Common::Array<uint32> _listBGAnimFast;
Common::Array<uint32> _listFGAnimSlow;
Common::Array<uint32> _listFGAnimMedium;
Common::Array<uint32> _listFGAnimFast;
private:
char _name[32];
uint32 _backgroundOffset;
uint32 _foregroundOffset;
uint16 _iconNum;
uint32 _iconListOffset;
uint16 _infoNum;
uint32 _infoListOffset;
int16 *_background;
int16 *_foreground;
MSMIcon *_iconList;
byte *_mapExplosions;
byte *_mapExpBarrels;
byte *_mapLaserBeams;
bool _mapLoaded;
};
}
#endif // !HDB_MAP_H

1774
engines/hdb/menu.cpp Normal file

File diff suppressed because it is too large Load Diff

220
engines/hdb/menu.h Normal file
View File

@@ -0,0 +1,220 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_MENU_H
#define HDB_MENU_H
#include "common/events.h"
#include "hdb/ai.h"
#include "hdb/sound.h"
namespace HDB {
#define TITLE_DELAY1 2 // time to wait before OOH OOH
#define TITLE_DELAY2 0.5 // time to spend doing OOH OOH
#define TITLE_DELAY3 1 // time to wait before ending title
#define centerPic(x) (g_hdb->_screenWidth / 2 - x->_width / 2)
enum {
kStarRedX = 70,
kStarRedY = 20,
kStarGreenX = 70,
kStarGreenY = 100,
kStarBlueX = 70,
kStarBlueY = 180,
kOptionSPC = 16,
kOptionLineSPC = 32,
kScreenFade = 512,
kNebulaCount = 7,
kMaxStars = 10
};
enum OptionsScreens {
kOptionsScreenMain = 1, // The main Options screen; Sound Settings and Modify Controls button
kOptionsScreenModifyControls = 2 // The controls screen, for viewing and remapping controls (currently not implemented)
};
enum MenuScreens {
kMenuOptions = 0,
kMenuLoadGame = 1,
kMenuNewGame = 2
};
struct Star {
int x, y, speed, anim, delay;
Star() : x(0), y(0), speed(0), anim(0), delay(0) {}
};
class Menu {
public:
Menu();
~Menu();
bool init();
void readConfig();
void writeConfig();
bool startTitle();
void drawTitle();
void startMenu();
void changeToMenu(); // Changing from Intro to Menu
void drawMenu();
void freeMenu();
void processInput(int x, int y); // this is where the items are clicked!
void controlsInput(int x, int y, int xit); // take mouse input and pass through to menu
void controlsDraw();
void drawNebula();
void drawRocketAndSelections(); // draw the background stuff
void drawSlider(int x, int y, int offset);
void drawToggle(int x, int y, bool flag);
void drawWarpScreen();
void saveSong(SoundType song) {
_resumeSong = song;
}
void fillSavegameSlots();
void setMenuKey(int status) {
_menuKey = status;
}
int getMenuKey() {
return _menuKey;
}
// Platform-specific Constants
int _menuX, _menuY;
int _menuItemWidth;
int _menuItemHeight;
int _mResumeY;
int _mQuitY;
int _mOptionsY;
int _mLoadY;
int _mControlsY;
int _menuExitXLeft;
int _menuExitY;
int _menuExitYTop;
int _menuVortSaveY;
int _menuVortSaveX;
int _mRocketX;
int _mRocketY;
int _mRocketYBottom;
int _mRocketEXHX;
int _mRocketEXHX2;
int _mTitleY;
int _oohOhhX;
int _oohOhhY;
int _newGameX;
int _newGameX2;
int _modePuzzleY;
int _modeActionY;
int _optionsX;
int _optionsY;
int _vortSaveX;
int _vortSaveTextX;
int _vortSaveY;
int _saveSlotX;
int _saveSlotY;
int _quitX;
int _quitY;
int _quitYesX1;
int _quitYesX2;
int _quitYesY1;
int _quitYesY2;
int _quitNoX1;
int _quitNoX2;
int _quitNoY1;
int _quitNoY2;
int _controlX;
int _controlY;
int _controlUpX;
int _controlUpY;
int _controlDownX;
int _controlDownY;
int _controlLeftX;
int _controlLeftY;
int _controlRightX;
int _controlRightY;
int _controlUseX;
int _controlUseY;
int _controlWidth;
int _controlHeight;
int _assignX;
int _assignY;
int _backoutX;
int _backoutY;
int _warpBackoutX;
int _warpBackoutY;
int _warpX;
int _warpY;
Save _saveGames[kNumSaveSlots + 1];
int _starWarp;
int _titleCycle;
uint32 _titleDelay;
bool _titleActive;
SoundType _resumeSong; // the song that was playing before entering the Options screen
Picture *_oohOohGfx;
Picture *_titleScreen, *_titleLogo, *_hdbLogoScreen, *_menuBackoutGfx, *_controlButtonGfx, *_controlsGfx, *_menuBackspaceGfx;
int _rocketY, _rocketYVel, _rocketEx; // Rocket Vars
Picture *_rocketEx1, *_rocketEx2, *_rocketMain, *_rocketSecond;
int _rocketX;
int _nebulaX, _nebulaY, _nebulaYVel, _nebulaWhich;
Picture *_nebulaGfx[kNebulaCount];
Picture *_newGfx, *_loadGfx, *_optionsGfx, *_quitGfx, *_resumeGfx, *_slotGfx;
Picture *_modePuzzleGfx, *_modeActionGfx, *_modeLoadGfx, *_modeSaveGfx, *_quitScreen;
Tile *_vortexian[3];
Picture *_star[3], *_warpGfx;
uint32 _quitTimer;
Picture *_starRedGfx[2], *_starGreenGfx[2], *_starBlueGfx[2], *_versionGfx;
Picture *_screenshots1gfx, *_screenshots1agfx, *_screenshots2gfx, *_demoPlaqueGfx, *_handangoGfx;
bool _menuActive, _optionsScrolling, _newgameActive, _sayHDB, _warpActive, _gamefilesActive, _optionsActive, _quitActive;
int _clickDelay, _saveSlot, _optionsScreenId, _quitCounter, _warpMapId;
int _optionsScrollX, _optionsXV, _oBannerY;
int _nextScreen;
Picture *_contArrowUp, *_contArrowDown, *_contArrowLeft, *_contArrowRight, *_contAssign, *_warpPlaque;
Picture *_sliderLeft, *_sliderMid, *_sliderRight, *_sliderKnob;
Picture *_gCheckEmpty, *_gCheckOn, *_gCheckOff, *_gCheckLeft, *_gCheckRight;
SoundType _introSong, _titleSong;
Star _fStars[kMaxStars];
int _menuKey;
};
} // End of Namespace
#endif // !HDB_SOUND_H

292
engines/hdb/metaengine.cpp Normal file
View File

@@ -0,0 +1,292 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "base/plugins.h"
#include "common/debug.h"
#include "common/translation.h"
#include "backends/keymapper/action.h"
#include "backends/keymapper/keymapper.h"
#include "backends/keymapper/standard-actions.h"
#include "engines/advancedDetector.h"
#include "graphics/thumbnail.h"
#include "hdb/hdb.h"
#include "hdb/input.h"
#include "hdb/detection.h"
namespace HDB {
static const ADExtraGuiOptionsMap optionsList[] = {
{
GAMEOPTION_CHEATMODE,
{
_s("Enable cheat mode"),
_s("Debug info and level selection becomes available"),
"hypercheat",
false,
0,
0
}
},
AD_EXTRA_GUI_OPTIONS_TERMINATOR
};
const char *HDBGame::getGameId() const { return _gameDescription->gameId; }
Common::Platform HDBGame::getPlatform() const { return _gameDescription->platform; }
const char *HDBGame::getGameFile() const {
return _gameDescription->filesDescriptions[0].fileName;
}
uint32 HDBGame::getGameFlags() const {
return _gameDescription->flags;
}
bool HDBGame::isDemo() const {
return (getGameFlags() & ADGF_DEMO);
}
bool HDBGame::isPPC() const {
return (getPlatform() == Common::kPlatformPocketPC);
}
bool HDBGame::isHandango() const {
return (getGameFlags() & GF_HANDANGO);
}
} // End of namespace HDB
class HDBMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
public:
const char *getName() const override {
return "hdb";
}
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
return HDB::optionsList;
}
bool hasFeature(MetaEngineFeature f) const override;
int getMaximumSaveSlot() const override;
bool removeSaveState(const char *target, int slot) const override;
SaveStateList listSaves(const char *target) const override;
SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const override;
Common::KeymapArray initKeymaps(const char *target) const override;
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
};
bool HDBMetaEngine::hasFeature(MetaEngineFeature f) const {
return
(f == kSupportsLoadingDuringStartup) ||
(f == kSupportsListSaves) ||
(f == kSupportsDeleteSave) ||
(f == kSavesSupportMetaInfo) ||
(f == kSavesSupportThumbnail) ||
(f == kSimpleSavesNames) ||
(f == kSavesSupportPlayTime);
}
bool HDB::HDBGame::hasFeature(Engine::EngineFeature f) const {
return (f == kSupportsReturnToLauncher) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
bool HDBMetaEngine::removeSaveState(const char *target, int slot) const {
Common::String fileName = Common::String::format("%s.%03d", target, slot);
return g_system->getSavefileManager()->removeSavefile(fileName);
}
int HDBMetaEngine::getMaximumSaveSlot() const { return 99; }
SaveStateList HDBMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String pattern = target;
pattern += ".###";
filenames = saveFileMan->listSavefiles(pattern);
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
// Obtain the last 2 digits of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 2);
if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) {
Common::ScopedPtr<Common::InSaveFile> in(saveFileMan->openForLoading(*file));
if (in) {
SaveStateDescriptor desc;
char mapName[32];
Graphics::Surface *thumbnail;
if (!Graphics::loadThumbnail(*in, thumbnail)) {
warning("Error loading thumbnail for %s", file->c_str());
}
desc.setThumbnail(thumbnail);
uint32 timeSeconds = in->readUint32LE();
in->read(mapName, 32);
debug(1, "mapName: %s playtime: %d", mapName, timeSeconds);
desc.setSaveSlot(slotNum);
desc.setPlayTime(timeSeconds * 1000);
if (slotNum < 8)
desc.setDescription(Common::String::format("Auto: %s", mapName));
else
desc.setDescription(mapName);
saveList.push_back(desc);
}
}
}
// Sort saves based on slot number.
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
}
SaveStateDescriptor HDBMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
Common::ScopedPtr<Common::InSaveFile> in(g_system->getSavefileManager()->openForLoading(Common::String::format("%s.%03d", target, slot)));
if (in) {
SaveStateDescriptor desc;
char mapName[32];
Graphics::Surface *thumbnail;
if (!Graphics::loadThumbnail(*in, thumbnail)) {
warning("Error loading thumbnail");
}
desc.setThumbnail(thumbnail);
uint32 timeSeconds = in->readUint32LE();
in->read(mapName, 32);
desc.setSaveSlot(slot);
desc.setPlayTime(timeSeconds * 1000);
desc.setDescription(mapName);
return desc;
}
return SaveStateDescriptor();
}
Common::KeymapArray HDBMetaEngine::initKeymaps(const char *target) const {
using namespace Common;
using namespace HDB;
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "hdb", "Hyperspace Delivery Boy!");
Action *act;
act = new Action(kStandardActionLeftClick, _("Left click"));
act->setLeftClickEvent();
act->addDefaultInputMapping("MOUSE_LEFT");
act->addDefaultInputMapping("JOY_A");
engineKeyMap->addAction(act);
act = new Action(kStandardActionMoveUp, _("Move up"));
act->setCustomEngineActionEvent(kHDBActionUp);
act->addDefaultInputMapping("UP");
act->addDefaultInputMapping("JOY_UP");
engineKeyMap->addAction(act);
act = new Action(kStandardActionMoveDown, _("Move down"));
act->setCustomEngineActionEvent(kHDBActionDown);
act->addDefaultInputMapping("DOWN");
act->addDefaultInputMapping("JOY_DOWN");
engineKeyMap->addAction(act);
act = new Action(kStandardActionMoveLeft, _("Move left"));
act->setCustomEngineActionEvent(kHDBActionLeft);
act->addDefaultInputMapping("LEFT");
act->addDefaultInputMapping("JOY_LEFT");
engineKeyMap->addAction(act);
act = new Action(kStandardActionMoveRight, _("Move right"));
act->setCustomEngineActionEvent(kHDBActionRight);
act->addDefaultInputMapping("RIGHT");
act->addDefaultInputMapping("JOY_RIGHT");
engineKeyMap->addAction(act);
act = new Action("USE", _("Use"));
act->setCustomEngineActionEvent(kHDBActionUse);
act->addDefaultInputMapping("RETURN");
act->addDefaultInputMapping("MOUSE_RIGHT");
act->addDefaultInputMapping("JOY_B");
engineKeyMap->addAction(act);
act = new Action("CLEAR", _("Clear waypoints"));
act->setCustomEngineActionEvent(kHDBActionClearWaypoints);
act->addDefaultInputMapping("MOUSE_MIDDLE");
act->addDefaultInputMapping("JOY_X");
engineKeyMap->addAction(act);
#if 0
act = new Action("INV", _("Inventory"));
act->setCustomEngineActionEvent(kHDBActionInventory);
act->addDefaultInputMapping("SPACE");
act->addDefaultInputMapping("JOY_Y");
engineKeyMap->addAction(act);
#endif
act = new Action(kStandardActionPause, _("Pause"));
act->setCustomEngineActionEvent(kHDBActionPause);
act->addDefaultInputMapping("p");
act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
engineKeyMap->addAction(act);
act = new Action(kStandardActionOpenMainMenu, _("Menu"));
act->setCustomEngineActionEvent(kHDBActionMenu);
act->addDefaultInputMapping("ESCAPE");
act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
engineKeyMap->addAction(act);
act = new Action("DEBUG", _("Debug"));
act->setCustomEngineActionEvent(kHDBActionDebug);
act->addDefaultInputMapping("F1");
engineKeyMap->addAction(act);
act = new Action("QUIT", _("Quit"));
act->setCustomEngineActionEvent(kHDBActionQuit);
act->addDefaultInputMapping("F10");
engineKeyMap->addAction(act);
return Keymap::arrayOf(engineKeyMap);
}
Common::Error HDBMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
*engine = new HDB::HDBGame(syst, desc);
return Common::kNoError;
}
#if PLUGIN_ENABLED_DYNAMIC(HDB)
REGISTER_PLUGIN_DYNAMIC(HDB, PLUGIN_TYPE_ENGINE, HDBMetaEngine);
#else
REGISTER_PLUGIN_STATIC(HDB, PLUGIN_TYPE_ENGINE, HDBMetaEngine);
#endif

37
engines/hdb/module.mk Normal file
View File

@@ -0,0 +1,37 @@
MODULE := engines/hdb
MODULE_OBJS := \
ai-bots.o \
ai-cinematic.o \
ai-funcs.o \
ai-init.o \
ai-inventory.o \
ai-lists.o \
ai-player.o \
ai-use.o \
ai-waypoint.o \
file-manager.o \
gfx.o \
hdb.o \
input.o \
lua-script.o \
map.o \
menu.o \
metaengine.o \
sound.o \
saveload.o \
window.o
MODULE_DIRS += \
engines/hdb
# This module can be built as a plugin
ifeq ($(ENABLE_HDB), DYNAMIC_PLUGIN)
PLUGIN := 1
endif
# Include common rules
include $(srcdir)/rules.mk
# Detection objects
DETECT_OBJS += $(MODULE)/detection.o

2241
engines/hdb/mpc.h Normal file

File diff suppressed because it is too large Load Diff

389
engines/hdb/saveload.cpp Normal file
View File

@@ -0,0 +1,389 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "graphics/thumbnail.h"
#include "hdb/hdb.h"
#include "hdb/ai.h"
#include "hdb/gfx.h"
#include "hdb/lua-script.h"
#include "hdb/map.h"
#include "hdb/sound.h"
#include "hdb/window.h"
namespace HDB {
bool HDBGame::canSaveGameStateCurrently(Common::U32String *msg) {
return (_gameState == GAME_PLAY && !_ai->cinematicsActive());
}
Common::Error HDBGame::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
// If no map is loaded, don't try to save
if (!g_hdb->_map->isLoaded())
return Common::kCreatingFileFailed;
// If it is autosave, push down all saves
if (slot == 0) {
Common::String nameFrom;
Common::String nameTo;
for (int i = kNumSaveSlots - 2; i >= 0; i--) {
nameFrom = genSaveFileName(i, false);
nameTo = genSaveFileName(i + 1, false);
_saveFileMan->renameSavefile(nameFrom, nameTo);
nameFrom = genSaveFileName(i, true);
nameTo = genSaveFileName(i + 1, true);
_saveFileMan->renameSavefile(nameFrom, nameTo);
}
}
Common::OutSaveFile *out;
Common::String saveFileName = genSaveFileName(slot, false);
if (!(out = _saveFileMan->openForSaving(saveFileName)))
error("Unable to open save file");
Graphics::saveThumbnail(*out);
_saveHeader.fileSlot = 0;
Common::strlcpy(_saveHeader.saveID, saveFileName.c_str(), sizeof(_saveHeader.saveID));
_saveHeader.seconds = _timeSeconds + (_timePlayed / 1000);
Common::strlcpy(_saveHeader.mapName, _inMapName, sizeof(_saveHeader.mapName));
// Actual Save Data
saveGame(out);
_lua->save(out);
out->finalize();
if (out->err())
warning("Can't write file '%s'. (Disk full?)", saveFileName.c_str());
delete out;
return Common::kNoError;
}
bool HDBGame::canLoadGameStateCurrently(Common::U32String *msg) {
return _gameState == GAME_PLAY;
}
Common::Error HDBGame::loadGameState(int slot) {
Common::InSaveFile *in;
Common::String saveFileName = genSaveFileName(slot, false);
if (!(in = _saveFileMan->openForLoading(saveFileName))) {
warning("missing savegame file %s", saveFileName.c_str());
if (g_hdb->_map->isLoaded())
g_hdb->setGameState(GAME_PLAY);
return Common::kReadingFailed;
}
_window->closeAll();
Graphics::skipThumbnail(*in);
// Actual Save Data
loadGame(in);
_lua->loadLua(_currentLuaName); // load the Lua code FIRST! (if no file, it's ok)
_lua->loadSaveFile(in);
delete in;
// center the player on the screen
int x, y;
_ai->getPlayerXY(&x, &y);
_map->centerMapXY(x + 16, y + 16);
if (!_ai->cinematicsActive())
_gfx->turnOffFade();
debug(7, "Action List Info:");
for (int k = 0; k < 20; k++) {
debug(7, "Action %d: entityName: %s", k, _ai->_actions[k].entityName);
debug(7, "Action %d: x1: %d, y1: %d", k, _ai->_actions[k].x1, _ai->_actions[k].y1);
debug(7, "Action %d: x2: %d, y2: %d", k, _ai->_actions[k].x2, _ai->_actions[k].y2);
debug(7, "Action %d: luaFuncInit: %s, luaFuncUse: %s", k, _ai->_actions[k].luaFuncInit, _ai->_actions[k].luaFuncUse);
}
return Common::kNoError;
}
void HDBGame::saveGame(Common::OutSaveFile *out) {
debug(1, "HDBGame::saveGame: start at %u", (uint32)out->pos());
// Save Map Name and Time
out->writeUint32LE(_saveHeader.seconds);
out->write(_inMapName, 32);
debug(1, "HDBGame::saveGame: map at %u", (uint32)out->pos());
// Save Map Object Data
_map->save(out);
// Save Window Object Data
debug(1, "HDBGame::saveGame: window at %u", (uint32)out->pos());
_window->save(out);
// Save Gfx Object Data
debug(1, "HDBGame::saveGame: gfx at %u", (uint32)out->pos());
_gfx->save(out);
// Save Sound Object Data
debug(1, "HDBGame::saveGame: sound at %u", (uint32)out->pos());
_sound->save(out);
// Save Game Object Data
debug(1, "HDBGame::saveGame: game object at %u", (uint32)out->pos());
save(out);
// Save AI Object Data
debug(1, "HDBGame::saveGame: ai at %u", (uint32)out->pos());
_ai->save(out);
debug(1, "HDBGame::saveGame: end at %u", (uint32)out->pos());
}
void HDBGame::loadGame(Common::InSaveFile *in) {
debug(1, "HDBGame::loadGame: start at %u", (uint32)in->pos());
// Load Map Name and Time
_timeSeconds = in->readUint32LE();
_timePlayed = 0;
in->read(_inMapName, 32);
g_hdb->_sound->stopMusic();
_saveHeader.seconds = _timeSeconds;
Common::strlcpy(_saveHeader.mapName, _inMapName, sizeof(_saveHeader.mapName));
// Load Map Object Data
debug(1, "HDBGame::loadGame: map at %u", (uint32)in->pos());
_map->loadSaveFile(in);
// Load Window Object Data
debug(1, "HDBGame::loadGame: window at %u", (uint32)in->pos());
_window->loadSaveFile(in);
// Load Gfx Object Data
debug(1, "HDBGame::loadGame: gfx at %u", (uint32)in->pos());
_gfx->loadSaveFile(in);
// Load Sound Object Data
debug(1, "HDBGame::loadGame: sound at %u", (uint32)in->pos());
_sound->loadSaveFile(in);
// Load Game Object Data
debug(1, "HDBGame::loadGame: game object at %u", (uint32)in->pos());
loadSaveFile(in);
// Load AI Object Data
debug(1, "HDBGame::loadGame: ai at %u", (uint32)in->pos());
_ai->loadSaveFile(in);
debug(1, "HDBGame::loadGame: end at %u", (uint32)in->pos());
_gfx->turnOffFade();
}
void HDBGame::save(Common::OutSaveFile *out) {
out->write(_currentMapname, 64);
out->write(_lastMapname, 64);
out->write(_currentLuaName, 64);
out->writeSint32LE(_actionMode);
out->writeByte(_changeLevel);
out->write(_changeMapname, 64);
out->write(_inMapName, 32);
}
void HDBGame::loadSaveFile(Common::InSaveFile *in) {
in->read(_currentMapname, 64);
debug(0, "Loading map %s", _currentMapname);
in->read(_lastMapname, 64);
in->read(_currentLuaName, 64);
_actionMode = in->readSint32LE();
_changeLevel = in->readByte();
in->read(_changeMapname, 64);
in->read(_inMapName, 32);
}
void AIEntity::save(Common::OutSaveFile *out) {
char funcString[32];
const char *lookUp;
// Write out 32-char names for the function ptrs we have in the entity struct
lookUp = g_hdb->_ai->funcLookUp(aiAction);
memset(&funcString, 0, 32);
if (!lookUp && aiAction)
error("AIEntity::save: No matching ACTION function for func-string for %s entity", AIType2Str(type));
if (lookUp)
strncpy(funcString, lookUp, 31);
out->write(funcString, 32);
lookUp = g_hdb->_ai->funcLookUp(aiUse);
memset(&funcString, 0, 32);
if (!lookUp && aiUse)
error("AIEntity::save: No matching USE function for func-string for %s entity", AIType2Str(type));
if (lookUp)
strncpy(funcString, lookUp, 31);
out->write(funcString, 32);
lookUp = g_hdb->_ai->funcLookUp(aiInit);
memset(&funcString, 0, 32);
if (!lookUp && aiInit)
error("AIEntity::save: No matching INIT function for func-string for %s entity", AIType2Str(type));
if (lookUp)
strncpy(funcString, lookUp, 31);
out->write(funcString, 32);
lookUp = g_hdb->_ai->funcLookUp(aiInit2);
memset(&funcString, 0, 32);
if (!lookUp && aiInit2)
error("AIEntity::save: No matching INIT2 function for func-string for %s entity", AIType2Str(type));
if (lookUp)
strncpy(funcString, lookUp, 31);
out->write(funcString, 32);
lookUp = g_hdb->_ai->funcLookUp(aiDraw);
memset(&funcString, 0, 32);
if (!lookUp && aiDraw)
error("AIEntity::save: No matching DRAW function for func-string for %s entity", AIType2Str(type));
if (lookUp)
strncpy(funcString, lookUp, 31);
out->write(funcString, 32);
// Save AIEntity
out->writeSint32LE((int)type);
out->writeSint32LE((int)state);
out->writeSint32LE((int)dir);
out->write(luaFuncInit, 32);
out->write(luaFuncAction, 32);
out->write(luaFuncUse, 32);
out->writeUint16LE(level);
out->writeUint16LE(value1);
out->writeUint16LE(value2);
out->writeSint32LE((int)dir2);
out->writeUint16LE(x);
out->writeUint16LE(y);
out->writeSint16LE(drawXOff);
out->writeSint16LE(drawYOff);
out->writeUint16LE(onScreen);
out->writeUint16LE(moveSpeed);
out->writeSint16LE(xVel);
out->writeSint16LE(yVel);
out->writeUint16LE(tileX);
out->writeUint16LE(tileY);
out->writeUint16LE(goalX);
out->writeUint16LE(goalY);
out->writeUint16LE(touchpX);
out->writeUint16LE(touchpY);
out->writeUint16LE(touchpTile);
out->writeUint16LE(touchpWait);
out->writeUint16LE(stunnedWait);
out->writeSint16LE(sequence);
out->write(entityName, 32);
out->write(printedName, 32);
out->writeUint16LE(animFrame);
out->writeUint16LE(animDelay);
out->writeUint16LE(animCycle);
}
void AIEntity::load(Common::InSaveFile *in) {
char funcString[32];
FuncPtr init, init2, use, action, drawf;
action = init = init2 = use = drawf = nullptr;
// Read 32-char names for the function ptrs we have in entity struct
in->read(funcString, 32);
if (funcString[0])
action = g_hdb->_ai->funcLookUp(funcString);
in->read(funcString, 32);
if (funcString[0])
use = g_hdb->_ai->funcLookUp(funcString);
in->read(funcString, 32);
if (funcString[0])
init = g_hdb->_ai->funcLookUp(funcString);
in->read(funcString, 32);
if (funcString[0])
init2 = g_hdb->_ai->funcLookUp(funcString);
in->read(funcString, 32);
if (funcString[0])
drawf = g_hdb->_ai->funcLookUp(funcString);
// Load AIEntity
type = (AIType)in->readSint32LE();
state = (AIState)in->readSint32LE();
dir = (AIDir)in->readSint32LE();
in->read(luaFuncInit, 32);
in->read(luaFuncAction, 32);
in->read(luaFuncUse, 32);
level = in->readUint16LE();
value1 = in->readUint16LE();
value2 = in->readUint16LE();
dir2 = (AIDir)in->readSint32LE();
x = in->readUint16LE();
y = in->readUint16LE();
drawXOff = in->readSint16LE();
drawYOff = in->readSint16LE();
onScreen = in->readUint16LE();
moveSpeed = in->readUint16LE();
xVel = in->readSint16LE();
yVel = in->readSint16LE();
tileX = in->readUint16LE();
tileY = in->readUint16LE();
goalX = in->readUint16LE();
goalY = in->readUint16LE();
touchpX = in->readUint16LE();
touchpY = in->readUint16LE();
touchpTile = in->readUint16LE();
touchpWait = in->readUint16LE();
stunnedWait = in->readUint16LE();
sequence = in->readSint16LE();
in->read(entityName, 32);
in->read(printedName, 32);
animFrame = in->readUint16LE();
animDelay = in->readUint16LE();
animCycle = in->readUint16LE();
aiAction = action;
aiInit = init;
aiInit2 = init2;
aiUse = use;
aiDraw = drawf;
}
Common::String HDBGame::genSaveFileName(uint slot, bool lua) {
if (!lua)
return Common::String::format("%s.%03d", _targetName.c_str(), slot);
return Common::String::format("%s.l.%03d", _targetName.c_str(), slot);
}
} // End of Namespace

1929
engines/hdb/sound.cpp Normal file

File diff suppressed because it is too large Load Diff

1576
engines/hdb/sound.h Normal file

File diff suppressed because it is too large Load Diff

1939
engines/hdb/window.cpp Normal file

File diff suppressed because it is too large Load Diff

351
engines/hdb/window.h Normal file
View File

@@ -0,0 +1,351 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HDB_WINDOW_H
#define HDB_WINDOW_H
namespace HDB {
enum {
kMaxMsgQueue = 10,
kPanicZoneFaceY = 5,
kNumCrazy = 37
};
enum PZValue {
PANICZONE_TIMER,
PANICZONE_START,
PANICZONE_TITLESTOP,
PANICZONE_BLASTOFF,
PANICZONE_COUNTDOWN,
PANICZONE_END
};
struct DialogInfo {
char title[64]; // TITLE string
int tileIndex; // this is for a character picture
char string[160]; // actual text in the dialog
bool active; // is it drawing or not?
int x, y; // where to draw dialog
int width, height; // size of the dialog itself
int titleWidth;
Picture *gfx; // character tile (picture)
int more; // whether we want to draw the MORE icon or not
int el, er, et, eb; // saves the text edges
char luaMore[64]; // the name of the function to call after clicking the MORE button
DialogInfo() : tileIndex(0), active(false), x(0), y(0),
width(0), height(0), titleWidth(0), gfx(nullptr), more(0), el(0), er(0), et(0),
eb(0) {
title[0] = 0;
string[0] = 0;
luaMore[0] = 0;
}
};
struct DialogChoiceInfo {
char title[64]; // TITLE string
char text[160]; // actual text in the dialog
char func[64]; // function to call with result
bool active; // is it drawing or not?
int x, y; // where to draw dialog
int width, height; // size of the dialog itself
int textHeight; // height of everything above choices
int titleWidth;
int el, er, et, eb; // saves the text edges
uint32 timeout; // timeout value!
int selection; // which choice we've made
int numChoices; // how many choices possible
char choices[10][64]; // ptrs to choice text
DialogChoiceInfo() : active(false), x(0), y(0),
width(0), height(0), textHeight(0), titleWidth(0), el(0), er(0), et(0),
eb(0), timeout(0), selection(0), numChoices(0) {
title[0] = 0;
text[0] = 0;
func[0] = 0;
for (int i = 0; i < 10; i++)
choices[i][0] = 0;
}
};
struct MessageInfo {
bool active;
char title[128];
int timer;
int x, y;
int width, height;
MessageInfo() : active(false), timer(0), x(0), y(0), width(0), height(0) {
title[0] = 0;
}
};
struct InvWinInfo {
int x, y;
int width, height;
int selection;
bool active;
InvWinInfo() : x(0), y(0), width(0), height(0), selection(0), active(false) {}
};
struct DlvsInfo {
int x, y;
int width, height;
bool active;
int selected;
bool animate;
uint32 delay1, delay2, delay3;
bool go1, go2, go3;
DlvsInfo() : x(0), y(0), width(0), height(0), active(false), selected(0),
animate(false), delay1(0), delay2(0), delay3(0), go1(false), go2(false), go3(false) {}
};
struct PanicZone {
bool active;
int sequence;
int timer;
int x1, y1;
int x2, y2;
int xv, yv; // for both
int numberTime;
int numberTimeMaster;
int numberValue;
Picture *gfxPanic, *gfxZone;
Picture *gfxFace[2];
Picture *gfxNumber[10];
PanicZone() : active(false), sequence(0), timer(0), x1(0), y1(0), x2(0), y2(0), xv(0), yv(0),
numberTime(0), numberTimeMaster(0), numberValue(0), gfxPanic(nullptr), gfxZone(nullptr) {
memset(&gfxFace, 0, sizeof(gfxFace));
memset(&gfxNumber, 0, sizeof(gfxNumber));
}
};
struct TryAgainInfo {
double y1, y2;
double yv1, yv2;
double yv1v, yv2v;
double x1, x2;
TryAgainInfo() : y1(0), y2(0), yv1(0), yv2(0), yv1v(0), yv2v(0), x1(0), x2(0) {}
};
struct TOut {
char text[128];
int x, y;
uint32 timer;
TOut() : x(0), y(0), timer(0) {
text[0] = 0;
}
};
class Window {
public:
Window();
~Window();
void init();
void save(Common::OutSaveFile *out);
void loadSaveFile(Common::InSaveFile *in);
void restartSystem();
void setInfobarDark(int value);
void closeAll();
// Pause Functions
void drawPause();
void checkPause(int x, int y);
// Weapon Functions
void drawWeapon();
void chooseWeapon(AIType wType);
// Dialog Functions
void openDialog(const char *title, int tileIndex, const char *string, int more, const char *luaMore);
void drawDialog();
void closeDialog();
bool checkDialogClose(int x, int y);
void drawBorder(int x, int y, int width, int height, bool guyTalking);
void setDialogDelay(int delay);
uint32 getDialogDelay() {
return _dialogDelay;
}
bool dialogActive() {
return _dialogInfo.active;
}
// Dialog Choice Functions
void openDialogChoice(const char *title, const char *text, const char *func, int numChoices, const char *choices[10]);
void drawDialogChoice();
void closeDialogChoice();
bool checkDialogChoiceClose(int x, int y);
void dialogChoiceMoveup();
void dialogChoiceMovedown();
bool dialogChoiceActive() {
return _dialogChoiceInfo.active;
}
// MessageBar Functions
void openMessageBar(const char *title, int time);
void drawMessageBar();
bool checkMsgClose(int x, int y);
void nextMsgQueued();
void closeMsg();
bool msgBarActive() {
return _msgInfo.active;
}
// Inventory Functions
void drawInventory();
void setInvSelect(int status) {
_invWinInfo.selection = status;
}
int getInvSelect() {
return _invWinInfo.selection;
}
void checkInvSelect(int x, int y);
bool inventoryActive() {
return _invWinInfo.active;
}
// PPC Inventory
void openInventory();
bool checkInvClose(int x, int y);
void closeInv();
// Deliveries Functions
void openDeliveries(bool animate);
void drawDeliveries();
void setSelectedDelivery(int which);
int getSelectedDelivery() {
return _dlvsInfo.selected;
}
bool animatingDelivery() {
return _dlvsInfo.animate;
}
void checkDlvSelect(int x, int y);
// PPC Deliveries
bool checkDlvsClose(int x, int y);
void closeDlvs();
bool deliveriesActive() {
return _dlvsInfo.active;
}
// Try Again Functions
void drawTryAgain();
void clearTryAgain();
// Panic Zone Functions
void loadPanicZoneGfx();
void drawPanicZone();
void startPanicZone();
void stopPanicZone();
bool inPanicZone() {
return _pzInfo.active;
}
// TextOut functions
void textOut(const char *text, int x, int y, int timer);
void centerTextOut(const char *text, int y, int timer);
void drawTextOut();
int textOutActive() {
return (_textOutList.size());
}
void closeTextOut();
// Platform-specific Constants
int _weaponX, _weaponY;
int _invItemSpace, _invItemSpaceX, _invItemSpaceY;
int _invItemPerLine;
int _dlvItemSpaceX;
int _dlvItemSpaceY;
int _dlvItemPerLine;
int _dlvItemTextY;
int _dialogTextLeft;
int _dialogTextRight;
int _openDialogTextLeft;
int _openDialogTextRight;
int _textOutCenterX;
int _pauseY;
int _tryY1; // TRY
int _tryY2; // AGAIN
int _tryRestartY; // (ok)
int _panicXStop;
int _panicZoneFaceX;
Tile *getGemGfx() {
return _gemGfx;
}
PanicZone _pzInfo, _tempPzInfo;
private:
DialogInfo _dialogInfo;
uint32 _dialogDelay; // Used for Cinematics
DialogChoiceInfo _dialogChoiceInfo;
MessageInfo _msgInfo;
InvWinInfo _invWinInfo;
Common::Array<TOut *> _textOutList;
DlvsInfo _dlvsInfo;
TryAgainInfo _tryAgainInfo;
char _msgQueueStr[kMaxMsgQueue][128];
int _msgQueueWait[kMaxMsgQueue];
int _numMsgQueue;
// Windows GFX
Picture *_gfxTL, *_gfxTM, *_gfxTR;
Picture *_gfxL, *_gfxM, *_gfxR;
Picture *_gfxBL, *_gfxBM, *_gfxBR;
Picture *_gfxTitleL, *_gfxTitleM, *_gfxTitleR;
Picture *_gGfxTL, *_gGfxTM, *_gGfxTR;
Picture *_gGfxL, *_gGfxM, *_gGfxR;
Picture *_gGfxBL, *_gGfxBM, *_gGfxBR;
Picture *_gGfxTitleL, *_gGfxTitleM, *_gGfxTitleR;
Picture *_gfxIndent, *_gfxArrowTo, *_gfxHandright;
Picture *_gfxTry, *_gfxAgain, *_gfxInvSelect;
Picture *_gfxLevelRestart, *_gfxPausePlaque;
Tile *_gemGfx;
Picture *_mstoneGfx;
// Info Bar
Picture *_gfxResources, *_gfxDeliveries;
Picture *_gfxInfobar, *_gfxDarken;
int _infobarDimmed;
};
} // End of Namespace
#endif // !HDB_WINDOW_H