mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-17 07:07:10 +00:00
302 lines
6.1 KiB
C++
302 lines
6.1 KiB
C++
/* 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 "common/scummsys.h"
|
|
#include "cge/walk.h"
|
|
#include "cge/cge.h"
|
|
#include "cge/sound.h"
|
|
#include "cge/startup.h"
|
|
#include "cge/config.h"
|
|
#include "cge/vga13h.h"
|
|
#include "cge/snail.h"
|
|
#include "cge/text.h"
|
|
#include "cge/game.h"
|
|
#include "cge/events.h"
|
|
#include "cge/cfile.h"
|
|
#include "cge/vol.h"
|
|
#include "cge/talk.h"
|
|
#include "cge/vmenu.h"
|
|
#include "cge/gettext.h"
|
|
#include "cge/mixer.h"
|
|
#include "cge/cge_main.h"
|
|
#include "cge/cge.h"
|
|
#include "common/str.h"
|
|
|
|
namespace CGE {
|
|
|
|
extern Bar _barriers[];
|
|
|
|
WALK *_hero;
|
|
|
|
uint8 Cluster::_map[MAP_ZCNT][MAP_XCNT];
|
|
CGEEngine *Cluster::_vm;
|
|
|
|
void Cluster::init(CGEEngine *vm) {
|
|
_vm = vm;
|
|
}
|
|
|
|
uint8 &Cluster::cell() {
|
|
return _map[_b][_a];
|
|
}
|
|
|
|
bool Cluster::isValid() const {
|
|
return (_a >= 0) && (_a < MAP_XCNT) && (_b >= 0) && (_b < MAP_ZCNT);
|
|
}
|
|
|
|
bool Cluster::chkBar() const {
|
|
assert(_vm->_now <= CAVE_MAX);
|
|
return (_a == _barriers[_vm->_now]._horz) && (_b == _barriers[_vm->_now]._vert);
|
|
}
|
|
|
|
Cluster XZ(int x, int y) {
|
|
if (y < MAP_TOP)
|
|
y = MAP_TOP;
|
|
|
|
if (y > MAP_TOP + MAP_HIG - MAP_ZGRID)
|
|
y = MAP_TOP + MAP_HIG - MAP_ZGRID;
|
|
|
|
return Cluster(x / MAP_XGRID, (y - MAP_TOP) / MAP_ZGRID);
|
|
}
|
|
|
|
|
|
Cluster XZ(Couple xy) {
|
|
signed char x, y;
|
|
xy.split(x, y);
|
|
return XZ(x, y);
|
|
}
|
|
|
|
WALK::WALK(CGEEngine *vm, BMP_PTR *shpl)
|
|
: Sprite(vm, shpl), Dir(NO_DIR), _tracePtr(-1), _level(0), _vm(vm) {
|
|
}
|
|
|
|
|
|
void WALK::tick() {
|
|
if (_flags._hide)
|
|
return;
|
|
|
|
_here = XZ(_x + _w / 2, _y + _h);
|
|
|
|
if (Dir != NO_DIR) {
|
|
Sprite *spr;
|
|
_sys->funTouch();
|
|
for (spr = _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 == _trace[_tracePtr]) {
|
|
if (--_tracePtr < 0)
|
|
park();
|
|
} else {
|
|
signed char dx, dz;
|
|
(_trace[_tracePtr] - _here).split(dx, dz);
|
|
DIR d = (dx) ? ((dx > 0) ? EE : WW) : ((dz > 0) ? SS : NN);
|
|
turn(d);
|
|
}
|
|
}
|
|
step();
|
|
if ((Dir == WW && _x <= 0) ||
|
|
(Dir == EE && _x + _w >= SCR_WID) ||
|
|
(Dir == SS && _y + _w >= WORLD_HIG - 2))
|
|
park();
|
|
else {
|
|
signed char x; // dummy var
|
|
_here.split(x, _z); // take current Z position
|
|
SNPOST_(SNZTRIM, -1, 0, this); // update Hero's pos in show queue
|
|
}
|
|
}
|
|
|
|
|
|
int WALK::distance(Sprite *spr) {
|
|
int dx, dz;
|
|
dx = spr->_x - (_x + _w - WALKSIDE);
|
|
if (dx < 0)
|
|
dx = (_x + WALKSIDE) - (spr->_x + spr->_w);
|
|
|
|
if (dx < 0)
|
|
dx = 0;
|
|
|
|
dx /= MAP_XGRID;
|
|
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 == NO_DIR) ? SS : 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 != NO_DIR) {
|
|
step(9 + 4 * Dir + Dir);
|
|
Dir = NO_DIR;
|
|
_tracePtr = -1;
|
|
}
|
|
}
|
|
|
|
|
|
void WALK::findWay(Cluster c) {
|
|
if (c != _here) {
|
|
for (_findLevel = 1; _findLevel <= MAX_FIND_LEVEL; _findLevel++) {
|
|
signed char x, z;
|
|
_here.split(x, z);
|
|
_target = Couple(x, z);
|
|
c.split(x, z);
|
|
|
|
if (find1Way(Cluster(x, z)))
|
|
break;
|
|
}
|
|
_tracePtr = (_findLevel > MAX_FIND_LEVEL) ? -1 : (_findLevel - 1);
|
|
if (_tracePtr < 0)
|
|
noWay();
|
|
_time = 1;
|
|
}
|
|
}
|
|
|
|
|
|
void WALK::findWay(Sprite *spr) {
|
|
if (spr && spr != this) {
|
|
int x = spr->_x;
|
|
int z = spr->_z;
|
|
if (spr->_flags._east)
|
|
x += spr->_w + _w / 2 - WALKSIDE;
|
|
else
|
|
x -= _w / 2 - WALKSIDE;
|
|
findWay(Cluster((x / MAP_XGRID),
|
|
((z < MAP_ZCNT - MAX_DISTANCE) ? (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) {
|
|
_hero->findWay(spr);
|
|
if (mode < 0) {
|
|
mode = spr->_flags._east;
|
|
if (lower(spr))
|
|
mode += 2;
|
|
}
|
|
}
|
|
// note: insert SNAIL commands in reverse order
|
|
SNINSERT(SNPAUSE, -1, 64, NULL);
|
|
SNINSERT(SNSEQ, -1, TSEQ + mode, this);
|
|
if (spr) {
|
|
SNINSERT(SNWAIT, -1, -1, _hero); /////--------$$$$$$$
|
|
//SNINSERT(SNWALK, -1, -1, spr);
|
|
}
|
|
// sequence is not finished,
|
|
// now it is just at sprite appear (disappear) point
|
|
}
|
|
|
|
void WALK::noWay() {
|
|
_vm->trouble(NO_WAY, NO_WAY_TEXT);
|
|
}
|
|
|
|
bool WALK::find1Way(Cluster c) {
|
|
Cluster start = c;
|
|
const Cluster tab[4] = { Cluster(-1, 0), Cluster(1, 0), Cluster(0, -1), Cluster(0, 1)};
|
|
const int tabLen = 4;
|
|
|
|
if (c == _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
|
|
for (int i = 0; i < tabLen; ++i) {
|
|
// 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;
|
|
++start.cell();
|
|
bool foundPath = find1Way(c);
|
|
--start.cell();
|
|
--_level;
|
|
|
|
if (foundPath) {
|
|
// Set route point
|
|
_trace[_level] = start;
|
|
return true;
|
|
}
|
|
} while (!c.chkBar() && !c.cell());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
} // End of namespace CGE
|