aboutsummaryrefslogtreecommitdiff
path: root/engines/cge/walk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/cge/walk.cpp')
-rw-r--r--engines/cge/walk.cpp267
1 files changed, 267 insertions, 0 deletions
diff --git a/engines/cge/walk.cpp b/engines/cge/walk.cpp
new file mode 100644
index 0000000000..31ea1909d8
--- /dev/null
+++ b/engines/cge/walk.cpp
@@ -0,0 +1,267 @@
+/* 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 {
+
+Cluster::Cluster(CGEEngine *vm, int16 a, int16 b) : _vm(vm) {
+ _pt = Common::Point(a, b);
+}
+
+Cluster::Cluster(CGEEngine *vm) : _vm(vm) {
+ _pt = Common::Point(-1, -1);
+}
+
+uint8 &Cluster::cell() {
+ return _vm->_clusterMap[_pt.y][_pt.x];
+}
+
+bool Cluster::isValid() const {
+ return (_pt.x >= 0) && (_pt.x < kMapXCnt) && (_pt.y >= 0) && (_pt.y < kMapZCnt);
+}
+
+Walk::Walk(CGEEngine *vm, BitmapPtr *shpl)
+ : Sprite(vm, shpl), _dir(kDirNone), _tracePtr(-1), _level(0), _target(-1, -1), _findLevel(-1), _here(vm), _vm(vm) {
+ for (int i = 0; i < kMaxFindLevel; i++) {
+ Cluster *tmpClust = new Cluster(_vm);
+ _trace.push_back(tmpClust);
+ }
+}
+
+Walk::~Walk() {
+ for (uint idx = 0; idx < _trace.size(); ++idx)
+ delete _trace[idx];
+}
+
+void Walk::tick() {
+ if (_flags._hide)
+ return;
+
+ _here = _vm->XZ(_x + _w / 2, _y + _h);
+
+ if (_dir != kDirNone) {
+ _vm->_sys->funTouch();
+ for (Sprite *spr = _vm->_vga->_showQ->first(); spr; spr = spr->_next) {
+ if (distance(spr) < 2) {
+ if (!spr->_flags._near) {
+ _vm->feedSnail(spr, kNear);
+ spr->_flags._near = true;
+ }
+ } else {
+ spr->_flags._near = false;
+ }
+ }
+ }
+
+ if (_flags._hold || _tracePtr < 0) {
+ park();
+ } else {
+ if (_here._pt == _trace[_tracePtr]->_pt) {
+ if (--_tracePtr < 0)
+ park();
+ } else {
+ Common::Point tmpPoint = _trace[_tracePtr]->_pt - _here._pt;
+ int16 dx = tmpPoint.x;
+ int16 dz = tmpPoint.y;
+ Dir d = (dx) ? ((dx > 0) ? kDirEast : kDirWest) : ((dz > 0) ? kDirSouth : kDirNorth);
+ turn(d);
+ }
+ }
+
+ step();
+
+ if ((_dir == kDirWest && _x <= 0) ||
+ (_dir == kDirEast && _x + _w >= kScrWidth) ||
+ (_dir == kDirSouth && _y + _w >= kWorldHeight - 2)) {
+ park();
+ } else {
+ // take current Z position
+ _z = _here._pt.y;
+ _vm->_commandHandlerTurbo->addCommand(kCmdZTrim, -1, 0, this); // update Hero's pos in show queue
+ }
+}
+
+int Walk::distance(Sprite *spr) {
+ int dx = spr->_x - (_x + _w - kWalkSide);
+ if (dx < 0)
+ dx = (_x + kWalkSide) - (spr->_x + spr->_w);
+
+ if (dx < 0)
+ dx = 0;
+
+ dx /= kMapGridX;
+ int dz = spr->_z - _z;
+ if (dz < 0)
+ dz = - dz;
+
+ dx = dx * dx + dz * dz;
+ for (dz = 1; dz * dz < dx; dz++)
+ ;
+
+ return dz - 1;
+}
+
+void Walk::turn(Dir d) {
+ Dir dir = (_dir == kDirNone) ? kDirSouth : _dir;
+ if (d != _dir) {
+ step((d == dir) ? (1 + dir + dir) : (9 + 4 * dir + d));
+ _dir = d;
+ }
+}
+
+void Walk::park() {
+ if (_time == 0)
+ _time++;
+
+ if (_dir != kDirNone) {
+ step(9 + 4 * _dir + _dir);
+ _dir = kDirNone;
+ _tracePtr = -1;
+ }
+}
+
+void Walk::findWay(Cluster c) {
+ if (c._pt == _here._pt)
+ return;
+
+ for (_findLevel = 1; _findLevel <= kMaxFindLevel; _findLevel++) {
+ _target = _here._pt;
+ int16 x = c._pt.x;
+ int16 z = c._pt.y;
+
+ if (find1Way(Cluster(_vm, x, z)))
+ break;
+ }
+
+ _tracePtr = (_findLevel > kMaxFindLevel) ? -1 : (_findLevel - 1);
+ if (_tracePtr < 0)
+ noWay();
+ _time = 1;
+}
+
+void Walk::findWay(Sprite *spr) {
+ 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(_vm, (x / kMapGridX),
+ ((z < kMapZCnt - kDistMax) ? (z + 1)
+ : (z - 1))));
+}
+
+bool Walk::lower(Sprite *spr) {
+ return (spr->_y > _y + (_h * 3) / 5);
+}
+
+void Walk::reach(Sprite *spr, int mode) {
+ if (spr) {
+ _vm->_hero->findWay(spr);
+ if (mode < 0) {
+ mode = spr->_flags._east;
+ if (lower(spr))
+ mode += 2;
+ }
+ }
+ // note: insert SNAIL commands in reverse order
+ _vm->_commandHandler->insertCommand(kCmdPause, -1, 64, NULL);
+ _vm->_commandHandler->insertCommand(kCmdSeq, -1, kTSeq + mode, this);
+ if (spr) {
+ _vm->_commandHandler->insertCommand(kCmdWait, -1, -1, _vm->_hero);
+ //SNINSERT(SNWALK, -1, -1, spr);
+ }
+ // sequence is not finished,
+ // now it is just at sprite appear (disappear) point
+}
+
+void Walk::noWay() {
+ _vm->trouble(kSeqNoWay, kNoWay);
+}
+
+bool Cluster::chkBar() const {
+ assert(_vm->_now <= kSceneMax);
+ return (_pt.x == _vm->_barriers[_vm->_now]._horz) || (_pt.y == _vm->_barriers[_vm->_now]._vert);
+}
+
+bool Walk::find1Way(Cluster c) {
+ const Cluster tab[4] = { Cluster(_vm, -1, 0), Cluster(_vm, 1, 0), Cluster(_vm, 0, -1), Cluster(_vm, 0, 1)};
+ const int tabLen = 4;
+
+ if (c._pt == _target)
+ // Found destination
+ return true;
+
+ if (_level >= _findLevel)
+ // Nesting limit
+ return false;
+
+ // Look for barriers
+ if (c.chkBar())
+ return false;
+
+ if (c.cell())
+ // Location is occupied
+ return false;
+
+ // Loop through each direction
+ Cluster start = c;
+ for (int i = 0; i < tabLen; i++) {
+ // Reset to starting position
+ c = start;
+
+ do {
+ c._pt += tab[i]._pt;
+ if (!c.isValid())
+ // Break to check next direction
+ break;
+
+ // Recursively check for further paths
+ ++_level;
+ ++start.cell();
+ bool foundPath = find1Way(c);
+ --start.cell();
+ --_level;
+
+ if (foundPath) {
+ // Set route point
+ _trace[_level]->_pt = start._pt;
+ return true;
+ }
+ } while (!c.chkBar() && !c.cell());
+ }
+
+ return false;
+}
+
+} // End of namespace CGE