2011-07-13 11:04:44 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
|
|
|
*
|
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This code is based on original Soltys source code
|
|
|
|
* Copyright (c) 1994-1995 Janus B. Wisniewski and L.K. Avalon
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "cge/walk.h"
|
|
|
|
#include "cge/cge_main.h"
|
|
|
|
|
|
|
|
namespace CGE {
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
Walk *_hero;
|
2011-07-13 11:04:44 +00:00
|
|
|
|
2011-07-30 22:52:35 +00:00
|
|
|
uint8 Cluster::_map[kMapZCnt][kMapXCnt];
|
2011-07-15 10:43:29 +00:00
|
|
|
CGEEngine *Cluster::_vm;
|
2011-07-13 11:04:44 +00:00
|
|
|
|
2011-07-15 10:43:29 +00:00
|
|
|
void Cluster::init(CGEEngine *vm) {
|
|
|
|
_vm = vm;
|
|
|
|
}
|
2011-07-13 11:04:44 +00:00
|
|
|
|
|
|
|
uint8 &Cluster::cell() {
|
|
|
|
return _map[_b][_a];
|
|
|
|
}
|
|
|
|
|
2011-07-14 12:36:18 +00:00
|
|
|
bool Cluster::isValid() const {
|
2011-07-30 22:52:35 +00:00
|
|
|
return (_a >= 0) && (_a < kMapXCnt) && (_b >= 0) && (_b < kMapZCnt);
|
2011-07-14 12:36:18 +00:00
|
|
|
}
|
2011-07-13 11:04:44 +00:00
|
|
|
|
|
|
|
Cluster XZ(int x, int y) {
|
2011-07-30 22:52:35 +00:00
|
|
|
if (y < kMapTop)
|
|
|
|
y = kMapTop;
|
2011-07-13 11:04:44 +00:00
|
|
|
|
2011-07-30 22:52:35 +00:00
|
|
|
if (y > kMapTop + kMapHig - kMapGridZ)
|
|
|
|
y = kMapTop + kMapHig - kMapGridZ;
|
2011-07-13 11:04:44 +00:00
|
|
|
|
2011-07-30 22:52:35 +00:00
|
|
|
return Cluster(x / kMapGridX, (y - kMapTop) / kMapGridZ);
|
2011-07-13 11:04:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Cluster XZ(Couple xy) {
|
|
|
|
signed char x, y;
|
|
|
|
xy.split(x, y);
|
|
|
|
return XZ(x, y);
|
|
|
|
}
|
|
|
|
|
2011-07-30 22:52:35 +00:00
|
|
|
Walk::Walk(CGEEngine *vm, BitmapPtr *shpl)
|
2011-08-19 16:32:46 +00:00
|
|
|
: Sprite(vm, shpl), _dir(kDirNone), _tracePtr(-1), _level(0), _target(-1, -1), _findLevel(-1), _vm(vm) {
|
2011-07-13 11:04:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
void Walk::tick() {
|
2011-08-19 10:36:43 +00:00
|
|
|
if (_flags._hide)
|
2011-07-13 11:04:44 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
_here = XZ(_x + _w / 2, _y + _h);
|
|
|
|
|
2011-07-30 22:52:35 +00:00
|
|
|
if (_dir != kDirNone) {
|
2011-07-13 11:04:44 +00:00
|
|
|
Sprite *spr;
|
|
|
|
_sys->funTouch();
|
|
|
|
for (spr = _vga->_showQ->first(); spr; spr = spr->_next) {
|
|
|
|
if (distance(spr) < 2) {
|
2011-08-19 10:36:43 +00:00
|
|
|
if (!spr->_flags._near) {
|
2011-07-13 11:04:44 +00:00
|
|
|
_vm->feedSnail(spr, kNear);
|
2011-08-19 10:36:43 +00:00
|
|
|
spr->_flags._near = true;
|
2011-07-13 11:04:44 +00:00
|
|
|
}
|
|
|
|
} else {
|
2011-08-19 10:36:43 +00:00
|
|
|
spr->_flags._near = false;
|
2011-07-13 11:04:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-19 14:04:10 +00:00
|
|
|
if (_flags._hold || _tracePtr < 0) {
|
2011-07-13 11:04:44 +00:00
|
|
|
park();
|
2011-08-19 14:04:10 +00:00
|
|
|
} else {
|
2011-07-14 12:36:18 +00:00
|
|
|
if (_here == _trace[_tracePtr]) {
|
2011-07-13 11:04:44 +00:00
|
|
|
if (--_tracePtr < 0)
|
|
|
|
park();
|
|
|
|
} else {
|
|
|
|
signed char dx, dz;
|
2011-07-14 12:36:18 +00:00
|
|
|
(_trace[_tracePtr] - _here).split(dx, dz);
|
2011-07-30 22:52:35 +00:00
|
|
|
Dir d = (dx) ? ((dx > 0) ? kDirEast : kDirWest) : ((dz > 0) ? kDirSouth : kDirNorth);
|
2011-07-13 11:04:44 +00:00
|
|
|
turn(d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
step();
|
2011-07-30 22:52:35 +00:00
|
|
|
if ((_dir == kDirWest && _x <= 0) ||
|
|
|
|
(_dir == kDirEast && _x + _w >= kScrWidth) ||
|
2011-08-19 14:04:10 +00:00
|
|
|
(_dir == kDirSouth && _y + _w >= kWorldHeight - 2)) {
|
2011-07-13 11:04:44 +00:00
|
|
|
park();
|
2011-08-19 14:04:10 +00:00
|
|
|
} else {
|
2011-07-13 11:04:44 +00:00
|
|
|
signed char x; // dummy var
|
|
|
|
_here.split(x, _z); // take current Z position
|
2011-07-23 12:31:39 +00:00
|
|
|
_snail_->addCom(kSnZTrim, -1, 0, this); // update Hero's pos in show queue
|
2011-07-13 11:04:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
int Walk::distance(Sprite *spr) {
|
2011-08-19 14:04:10 +00:00
|
|
|
int dx = spr->_x - (_x + _w - kWalkSide);
|
2011-07-13 11:04:44 +00:00
|
|
|
if (dx < 0)
|
2011-07-20 23:56:40 +00:00
|
|
|
dx = (_x + kWalkSide) - (spr->_x + spr->_w);
|
2011-07-13 11:04:44 +00:00
|
|
|
|
|
|
|
if (dx < 0)
|
|
|
|
dx = 0;
|
|
|
|
|
2011-07-30 22:52:35 +00:00
|
|
|
dx /= kMapGridX;
|
2011-08-19 14:04:10 +00:00
|
|
|
int dz = spr->_z - _z;
|
2011-07-13 11:04:44 +00:00
|
|
|
if (dz < 0)
|
|
|
|
dz = - dz;
|
|
|
|
|
|
|
|
dx = dx * dx + dz * dz;
|
|
|
|
for (dz = 1; dz * dz < dx; dz++)
|
|
|
|
;
|
|
|
|
|
|
|
|
return dz - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-30 22:52:35 +00:00
|
|
|
void Walk::turn(Dir d) {
|
|
|
|
Dir dir = (_dir == kDirNone) ? kDirSouth : _dir;
|
|
|
|
if (d != _dir) {
|
2011-07-13 11:04:44 +00:00
|
|
|
step((d == dir) ? (1 + dir + dir) : (9 + 4 * dir + d));
|
2011-07-30 22:52:35 +00:00
|
|
|
_dir = d;
|
2011-07-13 11:04:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
void Walk::park() {
|
2011-07-13 11:04:44 +00:00
|
|
|
if (_time == 0)
|
2011-07-30 22:52:35 +00:00
|
|
|
_time++;
|
2011-07-13 11:04:44 +00:00
|
|
|
|
2011-07-30 22:52:35 +00:00
|
|
|
if (_dir != kDirNone) {
|
|
|
|
step(9 + 4 * _dir + _dir);
|
|
|
|
_dir = kDirNone;
|
2011-07-13 11:04:44 +00:00
|
|
|
_tracePtr = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
void Walk::findWay(Cluster c) {
|
2011-08-19 14:04:10 +00:00
|
|
|
if (c == _here)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (_findLevel = 1; _findLevel <= kMaxFindLevel; _findLevel++) {
|
|
|
|
signed char x, z;
|
|
|
|
_here.split(x, z);
|
|
|
|
_target = Couple(x, z);
|
|
|
|
c.split(x, z);
|
|
|
|
|
|
|
|
if (find1Way(Cluster(x, z)))
|
|
|
|
break;
|
2011-07-13 11:04:44 +00:00
|
|
|
}
|
2011-08-19 14:04:10 +00:00
|
|
|
_tracePtr = (_findLevel > kMaxFindLevel) ? -1 : (_findLevel - 1);
|
|
|
|
if (_tracePtr < 0)
|
|
|
|
noWay();
|
|
|
|
_time = 1;
|
2011-07-13 11:04:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
void Walk::findWay(Sprite *spr) {
|
2011-08-19 14:04:10 +00:00
|
|
|
if (!spr || spr == this)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int x = spr->_x;
|
|
|
|
int z = spr->_z;
|
|
|
|
if (spr->_flags._east)
|
|
|
|
x += spr->_w + _w / 2 - kWalkSide;
|
|
|
|
else
|
|
|
|
x -= _w / 2 - kWalkSide;
|
|
|
|
|
|
|
|
findWay(Cluster((x / kMapGridX),
|
|
|
|
((z < kMapZCnt - kDistMax) ? (z + 1)
|
|
|
|
: (z - 1))));
|
2011-07-13 11:04:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
bool Walk::lower(Sprite *spr) {
|
2011-07-13 11:04:44 +00:00
|
|
|
return (spr->_y > _y + (_h * 3) / 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
void Walk::reach(Sprite *spr, int mode) {
|
2011-07-13 11:04:44 +00:00
|
|
|
if (spr) {
|
|
|
|
_hero->findWay(spr);
|
|
|
|
if (mode < 0) {
|
2011-08-19 10:36:43 +00:00
|
|
|
mode = spr->_flags._east;
|
2011-07-13 11:04:44 +00:00
|
|
|
if (lower(spr))
|
|
|
|
mode += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// note: insert SNAIL commands in reverse order
|
2011-07-23 12:31:39 +00:00
|
|
|
_snail->insCom(kSnPause, -1, 64, NULL);
|
|
|
|
_snail->insCom(kSnSeq, -1, kTSeq + mode, this);
|
2011-07-13 11:04:44 +00:00
|
|
|
if (spr) {
|
2011-07-23 12:31:39 +00:00
|
|
|
_snail->insCom(kSnWait, -1, -1, _hero); /////--------$$$$$$$
|
2011-07-13 11:04:44 +00:00
|
|
|
//SNINSERT(SNWALK, -1, -1, spr);
|
|
|
|
}
|
|
|
|
// sequence is not finished,
|
|
|
|
// now it is just at sprite appear (disappear) point
|
|
|
|
}
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
void Walk::noWay() {
|
2011-07-22 09:54:46 +00:00
|
|
|
_vm->trouble(kSeqNoWay, kNoWay);
|
2011-07-14 12:36:18 +00:00
|
|
|
}
|
|
|
|
|
2011-08-19 22:03:44 +00:00
|
|
|
bool Cluster::chkBar() const {
|
|
|
|
assert(_vm->_now <= _vm->_caveMax);
|
|
|
|
return (_a == _vm->_barriers[_vm->_now]._horz) || (_b == _vm->_barriers[_vm->_now]._vert);
|
|
|
|
}
|
|
|
|
|
2011-07-24 21:42:03 +00:00
|
|
|
bool Walk::find1Way(Cluster c) {
|
2011-07-14 12:36:18 +00:00
|
|
|
Cluster start = c;
|
|
|
|
const Cluster tab[4] = { Cluster(-1, 0), Cluster(1, 0), Cluster(0, -1), Cluster(0, 1)};
|
|
|
|
const int tabLen = 4;
|
|
|
|
|
2011-07-15 10:43:29 +00:00
|
|
|
if (c == _target)
|
2011-07-14 12:36:18 +00:00
|
|
|
// Found destination
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (_level >= _findLevel)
|
|
|
|
// Nesting limit
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Look for barriers
|
2011-07-15 10:43:29 +00:00
|
|
|
if (c.chkBar())
|
2011-07-14 12:36:18 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (c.cell())
|
|
|
|
// Location is occupied
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Loop through each direction
|
2011-07-30 22:52:35 +00:00
|
|
|
for (int i = 0; i < tabLen; i++) {
|
2011-07-14 12:36:18 +00:00
|
|
|
// Reset to starting position
|
|
|
|
c = start;
|
|
|
|
|
|
|
|
do {
|
|
|
|
c += tab[i];
|
|
|
|
if (!c.isValid())
|
|
|
|
// Break to check next direction
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Recursively check for further paths
|
|
|
|
++_level;
|
2011-07-15 11:25:03 +00:00
|
|
|
++start.cell();
|
2011-07-14 12:36:18 +00:00
|
|
|
bool foundPath = find1Way(c);
|
2011-07-15 11:25:03 +00:00
|
|
|
--start.cell();
|
2011-07-14 12:36:18 +00:00
|
|
|
--_level;
|
|
|
|
|
|
|
|
if (foundPath) {
|
|
|
|
// Set route point
|
|
|
|
_trace[_level] = start;
|
|
|
|
return true;
|
|
|
|
}
|
2011-07-15 11:25:03 +00:00
|
|
|
} while (!c.chkBar() && !c.cell());
|
2011-07-14 12:36:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-07-13 11:04:44 +00:00
|
|
|
} // End of namespace CGE
|