aboutsummaryrefslogtreecommitdiff
path: root/engines/parallaction/walk.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/parallaction/walk.cpp')
-rw-r--r--engines/parallaction/walk.cpp471
1 files changed, 471 insertions, 0 deletions
diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp
new file mode 100644
index 0000000000..a44f16aeb5
--- /dev/null
+++ b/engines/parallaction/walk.cpp
@@ -0,0 +1,471 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "parallaction/defs.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/commands.h"
+#include "parallaction/graphics.h"
+#include "parallaction/zone.h"
+
+namespace Parallaction {
+
+uint16 walkFunc1(int16, int16, WalkNode *);
+uint16 queryPath(uint16 x, uint16 y);
+
+WalkNode _NULL_WALKNODE = { {NULL, NULL}, 0, 0 };
+
+static uint16 _doorData1 = 1000;
+static Zone *_zoneTrap = NULL;
+
+static uint16 walkData1 = 0;
+static uint16 walkData2 = 0; // next walk frame
+static int16 walkData3 = -1000; // unused
+
+
+int32 dotProduct(Point *p1, Point *p2) {
+ return p1->_x * p2->_x + p1->_y * p2->_y;
+}
+
+//
+// x, y: mouse click (foot) coordinates
+//
+WalkNode *buildWalkPath(uint16 x, uint16 y) {
+// printf("buildWalkPath(%i, %i)\n", x, y);
+
+ int16 to_x = x;
+ int16 to_y = y;
+
+ int16 left, bottom, right, top, close, closeY, closeX;
+
+ // looks for closest usable path Point
+ if (queryPath(to_x, to_y) == 0) {
+
+ right = left = to_x;
+
+ do {
+ right++;
+ } while ((queryPath(right, to_y) == 0) && (x < SCREEN_WIDTH));
+
+ do {
+ left--;
+ } while ((queryPath(left, to_y) == 0) && (left > 0));
+
+ right = (right == SCREEN_WIDTH) ? 1000 : right - to_x;
+ left = (left == 0) ? 1000 : to_x - left;
+
+ top = bottom = to_y;
+
+ do {
+ top--;
+ } while ((queryPath(to_x, top) == 0) && (top > 0));
+
+ do {
+ bottom++;
+ } while ((queryPath(to_x, bottom) == 0) && (bottom < SCREEN_HEIGHT));
+
+ top = (top == 0) ? 1000 : to_y - top;
+ bottom = (bottom == SCREEN_HEIGHT) ? 1000 : bottom - to_y;
+
+ closeX = (right >= left) ? left : right;
+ closeY = (top >= bottom) ? bottom : top;
+
+ close = (closeX >= closeY) ? closeY : closeX;
+
+ if (close == right) {
+ to_x += right;
+ walkData3 = (_yourself._cnv._count == 20) ? 7 : 9;
+ } else
+ if (close == left) {
+ to_x -= left;
+ walkData3 = 0;
+ } else
+ if (close == top) {
+ to_y -= top;
+ } else
+ if (close == bottom) {
+ to_y += bottom;
+ walkData3 = (_yourself._cnv._count == 20) ? 17 : 21;
+ }
+
+ }
+// printf("closest path Point: %i, %i\n", to_x, to_y);
+
+
+ WalkNode *v48 = (WalkNode*)memAlloc(sizeof(WalkNode));
+ WalkNode *v44 = (WalkNode*)memAlloc(sizeof(WalkNode));
+
+ v48->_x = to_x - _yourself._cnv._width / 2; // target top left coordinates
+ v48->_y = to_y - _yourself._cnv._height;
+ v48->_node._next = NULL;
+ memcpy(v44, v48, sizeof(WalkNode));
+
+ uint16 v38 = walkFunc1(to_x, to_y, v44);
+ if (v38 == 1) {
+ // destination directly reachable
+// printf("moving to destination (%i, %i)\n", to_x, to_y);
+ memFree(v44);
+ return v48;
+ }
+
+ // path is obstructed: find alternative
+
+ WalkNode v58;
+ memset(&v58, 0, sizeof(WalkNode));
+
+ int16 _si = v48->_x; // _si, _di: target top left coordinates
+ int16 _di = v48->_y;
+ addNode(&v58._node, &v48->_node);
+
+ WalkNode *_closest_node = NULL;
+
+ Point v20;
+ Point v8;
+
+ int32 v30, v34, v2C, v28;
+
+ byte _closest_node_found = 1;
+ bool emptyList = true;
+
+ do {
+
+ v48 = &v58;
+
+ v20._x = _yourself._zone.pos._position._x;
+ v20._y = _yourself._zone.pos._position._y;
+
+ v8._x = _si - _yourself._zone.pos._position._x;
+ v8._y = _di - _yourself._zone.pos._position._y;
+ v34 = v30 = dotProduct(&v8, &v8); // square distance from current position and target
+
+ while (_closest_node_found != 0) {
+
+ _closest_node_found = 0;
+ WalkNode *location_node = (WalkNode*)_locationWalkNodes._next;
+
+ // scans location path nodes searching for the nearest Node
+ // which can't be farther than the target position
+ // otherwise no _closest_node is selected
+ while (location_node != NULL) {
+ v8._x = location_node->_x - _si;
+ v8._y = location_node->_y - _di;
+ v2C = dotProduct(&v8, &v8); // square distance from Node to target position
+
+ v8._x = location_node->_x - v20._x;
+ v8._y = location_node->_y - v20._y;
+ v28 = dotProduct(&v8, &v8); // square distance from Node to current position
+
+ if (v2C < v34 && v28 < v30) {
+ _closest_node_found = 1;
+ v30 = v28;
+ _closest_node = location_node;
+ }
+
+ location_node = (WalkNode*)location_node->_node._next;
+ }
+
+ if (_closest_node_found == 0) break;
+
+ WalkNode *_newnode = (WalkNode*)memAlloc(sizeof(WalkNode));
+ memcpy( _newnode, _closest_node, sizeof(WalkNode));
+ v20._x = _newnode->_x;
+ v20._y = _newnode->_y;
+
+ v34 = v30 = (_si - v20._x) * (_si - v20._x) + (_di - v20._y) * (_di - v20._y);
+
+ addNode(&v48->_node, &_newnode->_node);
+ v48 = _newnode;
+ }
+
+ if (!emptyList) break;
+
+ if (v38 != 0 && v34 > v38) {
+ // no alternative path (gap?)
+ freeNodeList(v58._node._next);
+// printf("can't reach destination, moving to (%i, %i)\n", v44->_x, v44->_y);
+ return v44;
+ } else {
+ _si = ((WalkNode*)(v58._node._next))->_x;
+ _di = ((WalkNode*)(v58._node._next))->_y;
+ emptyList = false;
+ _closest_node_found = 1;
+ }
+
+ } while (true);
+
+ // alternative path exists
+ WalkNode *tmp = (WalkNode*)v58._node._next;
+// printf("moving along path ");
+ while (tmp) {
+// printf(" -> (%i, %i)", tmp->_x, tmp->_y);
+ tmp = (WalkNode*)tmp->_node._next;
+ }
+// printf("\n");
+
+ memFree(v44);
+ return (WalkNode*)v58._node._next;
+}
+
+
+uint16 queryPath(uint16 x, uint16 y) {
+ return _vm->_graphics->queryPath(x, y);
+}
+
+
+//
+// x,y : top left coordinates
+//
+// 0 : Point not reachable
+// 1 : Point reachable
+// other values: square distance to target (not reachable)
+//
+uint16 walkFunc1(int16 x, int16 y, WalkNode *Node) {
+
+ Point v4 = { 0, 0 };
+
+ Point foot = {
+ _yourself._zone.pos._position._x + _yourself._cnv._width/2,
+ _yourself._zone.pos._position._y + _yourself._cnv._height
+ };
+
+ Point v8 = {
+ foot._x,
+ foot._y
+ };
+
+ while (foot._x != x || foot._y != y) {
+
+ if (foot._x < x) {
+ if (queryPath(foot._x + 1, foot._y) != 0) foot._x++;
+ }
+ if (foot._x > x) {
+ if (queryPath(foot._x - 1, foot._y) != 0) foot._x--;
+ }
+ if (foot._y < y) {
+ if (queryPath(foot._x, foot._y + 1) != 0) foot._y++;
+ }
+ if (foot._y > y) {
+ if (queryPath(foot._x, foot._y - 1) != 0) foot._y--;
+ }
+
+ if ((foot._x == v8._x) && (foot._y == v8._y) && ((foot._x != x) || (foot._y != y))) {
+ // foot couldn't move and still away from target
+
+ v4._x = foot._x;
+ v4._y = foot._y;
+
+ while (foot._x != x || foot._y != y) {
+
+ if (foot._x < x) {
+ if (queryPath(foot._x + 1, foot._y) == 0) foot._x++;
+ }
+ if (foot._x > x) {
+ if (queryPath(foot._x - 1, foot._y) == 0) foot._x--;
+ }
+ if (foot._y < y) {
+ if (queryPath(foot._x, foot._y + 1) == 0) foot._y++;
+ }
+ if (foot._y > y) {
+ if (queryPath(foot._x, foot._y - 1) == 0) foot._y--;
+ }
+
+ if ((foot._x == v8._x) && (foot._y == v8._y) && (foot._x != x || foot._y != y))
+ return 0;
+
+ v8._x = foot._x;
+ v8._y = foot._y;
+ }
+
+ Node->_x = v4._x - _yourself._cnv._width / 2;
+ Node->_y = v4._y - _yourself._cnv._height;
+
+ return (x - v4._x) * (x - v4._x) + (y - v4._y) * (y - v4._y);
+ }
+
+ v8._x = foot._x;
+ v8._y = foot._y;
+
+ }
+
+ // there exists an unobstructed path
+ return 1;
+}
+
+
+void jobWalk(void *parm, Job *j) {
+
+ WalkNode *node = (WalkNode*)parm;
+
+ int16 _si = _yourself._zone.pos._position._x;
+ int16 _di = _yourself._zone.pos._position._y;
+
+ _yourself._zone.pos._oldposition._x = _si;
+ _yourself._zone.pos._oldposition._y = _di;
+
+ if ((node->_x == 0) && (node->_y == 0)) {
+ if (node->_node._next == NULL) {
+ j->_finished = 1;
+ checkDoor();
+ memFree(node);
+ return;
+ }
+
+ j->_parm = node->_node._next;
+ memFree(node);
+ node = (WalkNode*)node->_node._next;
+ }
+
+ Point dist = {
+ node->_x - _yourself._zone.pos._position._x,
+ node->_y - _yourself._zone.pos._position._y
+ };
+
+ if (dist._x < 0) dist._x = -dist._x;
+ if (dist._y < 0) dist._y = -dist._y;
+
+ walkData1++;
+
+ // walk frame selection
+ int16 v16;
+ if (_yourself._cnv._count == 20) {
+
+ if (dist._x > dist._y) {
+ walkData2 = (node->_x > _si) ? 0 : 7;
+ walkData1 %= 12;
+ v16 = walkData1 / 2;
+ } else {
+ walkData2 = (node->_y > _di) ? 14 : 17;
+ walkData1 %= 8;
+ v16 = walkData1 / 4;
+ }
+
+ } else {
+
+ if (dist._x > dist._y) {
+ walkData2 = (node->_x > _si) ? 0 : 9;
+ walkData1 %= 16;
+ v16 = walkData1 / 2;
+ } else {
+ walkData2 = (node->_y > _di) ? 18 : 21;
+ walkData1 %= 8;
+ v16 = walkData1 / 4;
+ }
+
+ }
+
+// StaticCnv v14;
+// v14._width = _yourself._cnv._width;
+// v14._height = _yourself._cnv._height;
+// v14._data0 = _yourself._cnv._array[_yourself._frame];
+// v14._data1 = _yourself._cnv.field_8[_yourself._frame];
+// v14._data2 = &_yourself.field_54;
+
+ if ((_si < node->_x) && (_si < SCREEN_WIDTH) && (queryPath(_yourself._cnv._width/2 + _si + 2, _yourself._cnv._height + _di) != 0)) {
+// printf("walk right\n");
+ _si = (_si + 2 < node->_x) ? _si + 2 : node->_x;
+ }
+
+ if ((_si > node->_x) && (_si > -20) && (queryPath(_yourself._cnv._width/2 + _si - 2, _yourself._cnv._height + _di) != 0)) {
+// printf("walk left\n");
+ _si = (_si - 2 > node->_x) ? _si - 2 :node->_x;
+ }
+
+ if ((_di < node->_y) && (_di < (SCREEN_HEIGHT - _yourself._cnv._height)) && (queryPath(_yourself._cnv._width/2 + _si, _yourself._cnv._height + _di + 2) != 0)) {
+// printf("walk down\n");
+ _di = (_di + 2 <= node->_y) ? _di + 2 : node->_y;
+ }
+
+ if ((_di > node->_y) && (_di > -20) && (queryPath(_yourself._cnv._width/2 + _si, _yourself._cnv._height + _di - 2) != 0)) {
+// printf("walk up\n");
+ _di = (_di - 2 >= node->_y) ? _di - 2 : node->_y;
+ }
+
+// printf("hitZone: %i, %i\n", _si, _di);
+ _yourself._zone.pos._position._x = _si;
+ _yourself._zone.pos._position._y = _di;
+
+ if ((_si == _yourself._zone.pos._oldposition._x) && (_di == _yourself._zone.pos._oldposition._y)) {
+
+ j->_finished = 1;
+ checkDoor();
+ freeNodeList(&node->_node);
+
+ } else {
+
+// printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
+ _yourself._frame = v16 + walkData2 + 1;
+
+ }
+
+ return;
+}
+
+
+uint16 checkDoor() {
+// printf("checkDoor()...");
+
+ if (_vm->_currentLocationIndex != _doorData1) {
+ _doorData1 = _vm->_currentLocationIndex;
+ _zoneTrap = NULL;
+ }
+
+ _engineFlags &= ~kEngineWalking;
+ Zone *z = hitZone(kZoneDoor, _yourself._zone.pos._position._x + _yourself._cnv._width / 2, _yourself._zone.pos._position._y + _yourself._cnv._height);
+
+ if (z != NULL) {
+
+ if ((z->_flags & kFlagsClosed) == 0) {
+ _firstPosition._x = z->u.door->_startPos._x;
+ _firstPosition._y = z->u.door->_startPos._y;
+ _firstFrame = z->u.door->_startFrame;
+ strcpy( _location, z->u.door->_location );
+
+ _engineFlags |= kEngineChangeLocation;
+ _zoneTrap = NULL;
+
+ } else {
+ runCommands(z->_commands, z);
+ }
+ }
+
+ z = hitZone(kZoneTrap, _yourself._zone.pos._position._x + _yourself._cnv._width / 2, _yourself._zone.pos._position._y + _yourself._cnv._height);
+
+ if (z != NULL) {
+ _localFlags[_vm->_currentLocationIndex] |= kFlagsEnter;
+ runCommands(z->_commands, z);
+ _localFlags[_vm->_currentLocationIndex] &= ~kFlagsEnter;
+ _zoneTrap = z;
+ } else
+ if (_zoneTrap != NULL) {
+ _localFlags[_vm->_currentLocationIndex] |= kFlagsExit;
+ runCommands(_zoneTrap->_commands, _zoneTrap);
+ _localFlags[_vm->_currentLocationIndex] &= ~kFlagsExit;
+ _zoneTrap = NULL;
+ }
+
+// printf("done\n");
+
+ _yourself._frame = walkData2;
+ return _yourself._frame;
+}
+
+} // namespace Parallaction
+