[Scummvm-git-logs] scummvm master -> 2d0b4bf9fab6d39916fcd754fb49c8121547e8ea

whiterandrek whiterandrek at gmail.com
Wed Sep 30 18:03:17 UTC 2020


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
2d0b4bf9fa PETKA: Walk system implementation


Commit: 2d0b4bf9fab6d39916fcd754fb49c8121547e8ea
    https://github.com/scummvm/scummvm/commit/2d0b4bf9fab6d39916fcd754fb49c8121547e8ea
Author: Andrei Prykhodko (whiterandrek at gmail.com)
Date: 2020-09-30T21:01:32+03:00

Commit Message:
PETKA: Walk system implementation

Changed paths:
  A engines/petka/walk.cpp
  A engines/petka/walk.h
    engines/petka/interfaces/main.cpp
    engines/petka/module.mk
    engines/petka/objects/heroes.cpp
    engines/petka/objects/heroes.h
    engines/petka/q_system.cpp


diff --git a/engines/petka/interfaces/main.cpp b/engines/petka/interfaces/main.cpp
index ad9a655267..94f43f0a1f 100644
--- a/engines/petka/interfaces/main.cpp
+++ b/engines/petka/interfaces/main.cpp
@@ -38,6 +38,7 @@
 #include "petka/objects/object_case.h"
 #include "petka/objects/heroes.h"
 #include "petka/objects/text.h"
+#include "petka/walk.h"
 
 namespace Petka {
 
@@ -98,6 +99,10 @@ void InterfaceMain::loadRoom(int id, bool fromSave) {
 			g_vm->resMgr()->loadFlic(obj->_resourceId);
 		_objs.push_back(obj);
 	}
+
+	sys->getPetka()->_walk->setBackground(g_vm->resMgr()->findResourceName(room->_resourceId));
+	sys->getChapay()->_walk->setBackground(g_vm->resMgr()->findResourceName(room->_resourceId));
+
 	playSound(room->_musicId, Audio::Mixer::kMusicSoundType);
 	playSound(room->_fxId, Audio::Mixer::kSFXSoundType);
 	if (!fromSave)
diff --git a/engines/petka/module.mk b/engines/petka/module.mk
index 74e64e1a58..29723ffa8d 100644
--- a/engines/petka/module.mk
+++ b/engines/petka/module.mk
@@ -11,6 +11,7 @@ MODULE_OBJS = \
     q_system.o \
     sound.o \
     video.o \
+    walk.o \
     interfaces/dialog_interface.o \
     interfaces/interface.o \
     interfaces/main.o \
diff --git a/engines/petka/objects/heroes.cpp b/engines/petka/objects/heroes.cpp
index 4fa6d5ba05..8f777a2d3a 100644
--- a/engines/petka/objects/heroes.cpp
+++ b/engines/petka/objects/heroes.cpp
@@ -29,6 +29,7 @@
 #include "petka/video.h"
 #include "petka/sound.h"
 #include "petka/objects/heroes.h"
+#include "petka/walk.h"
 
 namespace Petka {
 
@@ -46,6 +47,7 @@ QObjectPetka::QObjectPetka() {
 	_surfH = 0;
 	_surfW = 0;
 	_k = 1.0;
+	_walk = nullptr;
 }
 
 void QObjectPetka::processMessage(const QMessage &arg) {
@@ -53,11 +55,13 @@ void QObjectPetka::processMessage(const QMessage &arg) {
 	if (msg.opcode == kImage) {
 		msg.opcode = kSet;
 		_imageId = msg.arg1;
-		// delete _walkObj;
-		// _walkObj = new Walk(_imageId + 10);
-		// int backgroundId = g_vm->resMgr()->findResourceName(g_vm->getQSystem()->_room->_resourceId)
-		// _walkObj->setBackground(backgroundId);
 
+		delete _walk;
+		_walk = new Walk(_imageId + 10);
+
+		QObjectBG *room = g_vm->getQSystem()->_room;
+		if (room)
+			_walk->setBackground(g_vm->resMgr()->findResourceName(room->_resourceId));
 	}
 	if (msg.opcode == kSaid || msg.opcode == kStand) {
 		msg.opcode = kSet;
@@ -100,17 +104,18 @@ void QObjectPetka::walk(int x, int y) {
 	if (_isShown) {
 		Common::Point currPos;
 		if (_isWalking) {
-			// currPos = _walkObj->currPos();
+			currPos = _walk->currPos();
 		} else {
 			currPos.x = _x_;
 			currPos.y = _y_;
 		}
 
-		//if (currPos.sqrDist(walkPos) >= 25 * 25) {
-			//_walkObj->init(currPos, walkPos);
+
+		if (currPos.sqrDist(walkPos) >= 25 * 25) {
+			_walk->init(currPos, walkPos);
 			_destX = x;
 			_destY = y;
-			_resourceId = _imageId + 10; // + _walkObj->getResId() + 10;
+			_resourceId = _imageId + _walk->getSpriteId() + 10;
 			_isWalking = true;
 			_animate = true;
 
@@ -118,12 +123,14 @@ void QObjectPetka::walk(int x, int y) {
 			FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
 			flc->setFrame(1);
 
+			sub_408940();
+
 			g_vm->videoSystem()->makeAllDirty();
 
 			_field7C = 0;
 			_time = 0;
 			_holdMessages = true;
-		//}
+		}
 	} else {
 		setPos(Common::Point(x, y), false);
 	}
@@ -193,16 +200,22 @@ double QObjectPetka::calcPerspective(int y) {
 }
 
 void QObjectPetka::updateWalk() {
-	if (_isWalking) {
+	if (!_isWalking)
+		return;
+
+	int v = _walk->sub_423350();
+
+	switch (v) {
+	case 0: {
 		_isWalking = false;
-		setPos(Common::Point(_destX, _destY), false);
+		setPos(Common::Point(_walk->destX, _walk->destY), false);
 
-		QMessage msg(_id, kSet, (uint16)_imageId, 1, 0, nullptr, 0);
+		QMessage msg(_id, kSet, (uint16) _imageId, 1, 0, nullptr, 0);
 		if (_heroReaction) {
 			uint i;
 			for (i = 0; i < _heroReaction->messages.size(); ++i) {
 				if (_heroReaction->messages[i].opcode == kGoTo || _heroReaction->messages[i].opcode == kSetSeq) {
-					_resourceId = _imageId; // + _walkObj->getResOffset() + 10;
+					_resourceId = _imageId + _walk->getSpriteId() + 10;
 
 					FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
 					flc->setFrame(1);
@@ -223,6 +236,25 @@ void QObjectPetka::updateWalk() {
 		}
 		_holdMessages = false;
 		g_vm->videoSystem()->makeAllDirty();
+		break;
+	}
+	case 1:
+		sub_408940();
+		break;
+	case 2: {
+		_resourceId = _walk->getSpriteId() + _imageId + 10;
+
+		FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+		flc->setFrame(1);
+
+		_time = flc->getDelay();
+
+		initSurface();
+		g_vm->videoSystem()->makeAllDirty();
+		break;
+	}
+	default:
+		break;
 	}
 }
 
@@ -262,6 +294,11 @@ void QObjectPetka::stopWalk() {
 	_heroReaction = nullptr;
 
 	if (!_field7C) {
+		Common::Point p = _walk->sub_4234B0();
+
+		_x = p.x;
+		_y = p.y;
+
 		QMessage msg(_id, kSet, (uint16)_imageId, 1, 0, nullptr, 0);
 		processMessage(msg);
 	}
@@ -285,8 +322,8 @@ void QObjectPetka::update(int time) {
 				g_vm->getQSystem()->addMessage(_id, kHalf, _resourceId, 0, 0, 0, 0);
 			}
 
-			//if (_field7C && flc->getCurFrame() == 0)
-			//	_time = -10000;
+			if (_field7C && flc->getCurFrame() == 0)
+				_time = -10000;
 
 			updateWalk();
 			flc = g_vm->resMgr()->loadFlic(_resourceId);
@@ -320,13 +357,36 @@ void QObjectPetka::updateZ() {
 	if (_animate && _isShown && _updateZ) {
 		FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
 		if (_isWalking) {
-			// _z = _walkObj->currPos().y
+			_z = _walk->currPos().y;
 		} else {
 			_z = _y + flc->getHeight() * _k;
 		}
 	}
 }
 
+void QObjectPetka::sub_408940() {
+	FlicDecoder *flc = g_vm->resMgr()->loadFlic(_resourceId);
+	QSystem *sys = g_vm->getQSystem();
+
+	Common::Rect dirty(_x - sys->_xOffset, _y, _surfW + _x - sys->_xOffset, _surfH + _y);
+	g_vm->videoSystem()->addDirtyRect(dirty);
+
+	Common::Point currPos = _walk->currPos();
+	_k = calcPerspective(currPos.y);
+	_surfW = flc->getWidth() * _k;
+	_surfH = flc->getHeight() * _k;
+
+	Common::Point p = _walk->sub_4234B0();
+	_x = p.x;
+	_y = p.y;
+
+	Common::Point curr = _walk->currPos();
+	_x_ = curr.x;
+	_y_ = curr.y;
+
+	// todo
+}
+
 QObjectChapayev::QObjectChapayev() {
 	_x = 477;
 	_y = 350;
diff --git a/engines/petka/objects/heroes.h b/engines/petka/objects/heroes.h
index 8a2e8d41fe..6d1cf3b381 100644
--- a/engines/petka/objects/heroes.h
+++ b/engines/petka/objects/heroes.h
@@ -27,6 +27,8 @@
 
 namespace Petka {
 
+class Walk;
+
 class QObjectPetka : public QObject {
 public:
 	QObjectPetka();
@@ -47,6 +49,8 @@ public:
 
 	void updateZ() override;
 
+	void sub_408940();
+
 public:
 	int _field7C;
 	int _surfW;
@@ -56,7 +60,7 @@ public:
 	// int _surfId;
 	int _imageId;
 	double _k;
-	// walkObj
+	Walk *_walk;
 	int _destX;
 	int _destY;
 	bool _isWalking;
diff --git a/engines/petka/q_system.cpp b/engines/petka/q_system.cpp
index 11e8eb1541..8b286801ad 100644
--- a/engines/petka/q_system.cpp
+++ b/engines/petka/q_system.cpp
@@ -43,7 +43,7 @@ namespace Petka {
 
 QSystem::QSystem(PetkaEngine &vm)
 	: _vm(vm), _mainInterface(nullptr), _currInterface(nullptr), _prevInterface(nullptr),
-	_totalInit(false), _sceneWidth(640) {}
+	_totalInit(false), _sceneWidth(640), _room(nullptr) {}
 
 QSystem::~QSystem() {
 	for (uint i = 0; i < _allObjects.size(); ++i) {
diff --git a/engines/petka/walk.cpp b/engines/petka/walk.cpp
new file mode 100644
index 0000000000..45bc041d01
--- /dev/null
+++ b/engines/petka/walk.cpp
@@ -0,0 +1,803 @@
+/* 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.
+ *
+ */
+
+#include "common/math.h"
+
+#include "petka/walk.h"
+#include "petka/petka.h"
+#include "petka/q_manager.h"
+#include "petka/q_system.h"
+#include "petka/objects/heroes.h"
+
+namespace Petka {
+
+const char *const wayPrefixes[] = {"-w-n.", "-w-ne.", "-w-e.", "-w-se.", "-w-s.", "-w-sw.", "-w-w.", "-w-nw."};
+
+const double kPI = 3.14159265;
+const double k2PI = kPI + kPI;
+const double kHalfPI = kPI / 2;
+
+const double kPiArray[] = {kPI * 0.5, kPI * 0.25, 0.0, kPI * -0.25, kPI * -0.5, kPI * -0.75, kPI, kPI * 0.75};
+
+Walk::Walk(int id) { // CHECKED
+	QManager *mgr = g_vm->resMgr();
+
+	Common::String res = mgr->findResourceName(id);
+	res.toLowercase();
+	res = res.substr(0, res.find(wayPrefixes[0]));
+	for (int i = 0; i < 8; ++i) {
+		waysSizes[i] = readWayFile(res + Common::String(wayPrefixes[i]) + "off", &_off1[i], &_off2[i]);
+		readWayFile(res + Common::String(wayPrefixes[i]) + "leg", &_leg1[i], &_leg2[i]);
+	}
+
+	for (int i = 0; i < 8; ++i) {
+		_offleg1[i] = new int[waysSizes[i] + 1];
+		_offleg2[i] = new int[waysSizes[i] + 1];
+		for (int j = 1; j <= waysSizes[i]; ++j) {
+			_offleg1[i][j] = _leg1[i][j] + _off1[i][j] - _leg1[i][j - 1];
+			_offleg2[i][j] = _leg2[i][j] + _off2[i][j] - _leg2[i][j - 1];
+		}
+		_offleg1[i][0] = _offleg1[i][waysSizes[i]];
+		_offleg2[i][0] = _offleg2[i][waysSizes[i]];
+	}
+	for (int i = 0; i < 8; ++i) {
+		int v16 = 0;
+		int v18 = 0;
+		int idx = 1;
+		for (int j = 0; j < 150; ++j) {
+			v16 += _offleg1[i][idx];
+			v18 += _offleg2[i][idx];
+			idx = (idx + 1) % waysSizes[i];
+		}
+		field_D0[i] = (double)v18 / v16;
+	}
+
+	currX = 0.0;
+	currY = 0.0;
+	_bkg3Count = 0;
+	_bkg2Count = 0;
+	field_134 = 0;
+	_bkg1Count = 0;
+	_bkg3_1 = nullptr;
+	_bkg3_2 = nullptr;
+	_bkg2 = nullptr;
+	_bkg3_3 = nullptr;
+	_bkg3_4 = nullptr;
+	_bkg3_5 = nullptr;
+	_bkg1 = nullptr;
+	field_190 = 0;
+	resId = 0;
+}
+
+Walk::~Walk() { // CHECKED
+	clearBackground();
+	reset();
+	for (int i = 0; i < 8; ++i) {
+		free(_leg1[i]);
+		free(_leg2[i]);
+		free(_off1[i]);
+		free(_off2[i]);
+		free(_offleg1[i]);
+		free(_offleg2[i]);
+
+		_leg1[i] = nullptr;
+		_leg2[i] = nullptr;
+		_off1[i] = nullptr;
+		_off2[i] = nullptr;
+		_offleg1[i] = nullptr;
+		_offleg2[i] = nullptr;
+
+		waysSizes[i] = 0;
+	}
+}
+
+void Walk::init(Point start, Point end) {
+	reset();
+	field_134 = 1;
+
+	int v5 = sub_424230(&end) ? moveInside(&end) : sub_423600(end);
+	_bkg3_4[0] = sub_424230(&start) ? moveInside(&start) : sub_423600(start);
+
+
+	destX = end.x;
+	destY = end.y;
+
+	currX = end.x;
+	currY = end.y;
+
+	if (start == end)
+		return;
+
+	if (sub_424160(&start, &end) || v5 != _bkg3_4[0]) {
+		for (int i = 0; i < _bkg3Count; ++i)
+			_bkg3_5[i] = -1;
+
+		field_134 = 1;
+		if (_bkg3_4[0] != v5) {
+			do {
+				_bkg3_4[field_134] = sub_423970(_bkg3_4[field_134 - 1], _bkg3_5[field_134 - 1]);
+				if (_bkg3_4[field_134] >= 0) {
+					_bkg3_5[field_134 - 1] = _bkg3_4[field_134];
+					if (field_134 <= 1 || _bkg3_4[field_134 - 2] != _bkg3_4[field_134])
+						field_134++;
+				} else {
+					field_134--;
+					_bkg3_4[field_134] = -1;
+					_bkg3_5[field_134] = -1;
+				}
+
+			} while (_bkg3_4[field_134 - 1] != v5);
+		}
+
+		int v20 = 1;
+		int v21 = 4;
+		int v22 = 1;
+		int a2 = 4;
+		_bkg3_3[0] = start;
+		if (field_134 > 1) {
+			do {
+				int v23 = sub_423A30(_bkg3_4[(v21 - 4) / 4], _bkg3_4[v21 / 4]);
+				_bkg3_3[v22].x = (_bkg1[_bkg2[v23].x].x + _bkg1[_bkg2[v23].y].x) / 2;
+				_bkg3_3[v22].y = (_bkg1[_bkg2[v23].x].y + _bkg1[_bkg2[v23].y].y) / 2;
+
+				if (v22 > 1 && !sub_424160(&_bkg3_3[v22 - 2], &_bkg3_3[v22])) {
+					v20--;
+
+					_bkg3_3[v22 - 1] = _bkg3_3[v22];
+
+					v22--;
+					field_134--;
+				}
+
+				v21 = a2 + 4;
+				v20++;
+				v22++;
+				a2 += 4;
+			} while (v20 < field_134);
+		}
+
+		_bkg3_3[v20] = end;
+		if (v20 > 1 && !sub_424160(_bkg3_3 + v20 - 2, _bkg3_3 + v20)) {
+			_bkg3_3[v20 - 1] = _bkg3_3[v20];
+			field_134--;
+		}
+		field_134++;
+	} else {
+		_bkg3_3[0] = start;
+		_bkg3_3[1] = end;
+		field_134 = 2;
+	}
+
+	sub_422EA0(_bkg3_3[0], _bkg3_3[1]);
+	field_14C = 1;
+}
+
+void Walk::clearBackground() { // CHECKED
+	delete[] _bkg1;
+	_bkg1 = nullptr;
+	_bkg1Count = 0;
+
+
+	if (_bkg3_1) {
+		if (_bkg3_2) {
+			for (int i = 0; i < _bkg3Count; ++i) {
+				delete[] _bkg3_2[i];
+				_bkg3_2[i] = nullptr;
+			}
+			delete[] _bkg3_2;
+			_bkg3_2 = nullptr;
+		}
+		delete[] _bkg3_1;
+		_bkg3_1 = nullptr;
+		_bkg3Count = 0;
+	}
+
+	delete[] _bkg2;
+	_bkg2 = nullptr;
+	_bkg2Count = 0;
+
+	delete[] _bkg3_3;
+	_bkg3_3 = nullptr;
+
+	delete[] _bkg3_4;
+	_bkg3_4 = nullptr;
+
+	delete[] _bkg3_5;
+	_bkg3_5 = nullptr;
+}
+
+void Walk::setBackground(Common::String name) { // CHECKED
+	clearBackground();
+
+	name.toLowercase();
+	name.replace(name.size() - 3, 3, "cvx");
+
+	Common::SeekableReadStream *stream = g_vm->openFile(name, false);
+	if (!stream)
+		return;
+
+	_bkg1Count = stream->readUint32LE();
+	_bkg1 = new Point[_bkg1Count];
+
+	for (int i = 0; i < _bkg1Count; ++i) {
+		_bkg1[i].x = stream->readUint32LE();
+		_bkg1[i].y = stream->readUint32LE();
+	}
+
+	_bkg2Count = stream->readUint32LE();
+	_bkg2 = new Point[_bkg2Count];
+
+	for (int i = 0; i < _bkg2Count; ++i) {
+		_bkg2[i].x = stream->readUint32LE();
+		_bkg2[i].y = stream->readUint32LE();
+	}
+
+	_bkg3Count = stream->readUint32LE();
+	_bkg3_1 = new int[_bkg3Count];
+
+	stream->read(_bkg3_1, 4 * _bkg3Count);
+
+	_bkg3_2 = new int*[_bkg3Count];
+
+	for (int i = 0; i < _bkg3Count; ++i) {
+		_bkg3_2[i] = new int[_bkg3_1[i]];
+		stream->read(_bkg3_2[i], 4 * _bkg3_1[i]);
+	}
+
+	delete stream;
+	_bkg3_3 = new Point[_bkg3Count + 1];
+	_bkg3_4 = new int[_bkg3Count + 1];
+	_bkg3_5 = new int[_bkg3Count + 1];
+
+}
+
+void Walk::reset() { // CHECKED
+	field_140 = 0.0;
+	field_138 = 0.0;
+	currX = 0;
+	currY = 0;
+	resId = 0;
+	field_14C = 0;
+	field_190 = 0;
+	field_194 = 0;
+}
+
+Common::Point Walk::currPos() { // CHECKED
+	return Common::Point(currX, currY);
+}
+
+int Walk::getSpriteId() { // CHECKED
+	return resId;
+}
+
+int Walk::commonPoint(int idx1, int idx2) { // CHECKED
+	if (_bkg2[idx1].x == _bkg2[idx2].x || _bkg2[idx1].x == _bkg2[idx2].y)
+		return _bkg2[idx1].x;
+
+	if (_bkg2[idx1].y != _bkg2[idx2].x && _bkg2[idx1].y != _bkg2[idx2].y)
+		return 0;
+
+	return _bkg2[idx1].y;
+}
+
+int Walk::readWayFile(const Common::String &name, int **p1, int **p2) { // CHECKED
+	Common::SeekableReadStream *stream = g_vm->openFile(name, false);
+	if (!stream) {
+		p1 = nullptr;
+		p2 = nullptr;
+		return 0;
+	}
+
+	const uint items = (uint)stream->size() / 8;
+
+	*p1 = new int[items];
+	*p2 = new int[items];
+
+	stream->skip(4);
+	for (uint i = 0; i < items; ++i) {
+		stream->read(&(*p1)[i], 4);
+		stream->read(&(*p2)[i], 4);
+	}
+
+	delete stream;
+	return items;
+}
+
+int Walk::sub_422EA0(Point p1, Point p2) {
+	if (p1 == p2)
+		return 0;
+
+	Point p = p1;
+	p.x += 150;
+
+	double v5 = angle(p1, p, p2);
+	double v6;
+	if (v5 >= 0.0)
+		v6 = k2PI - v5;
+	else
+		v6 = v5 + k2PI;
+
+	double v30 = 4.0;
+	for (uint i = 0; i < ARRAYSIZE(kPiArray); ++i) {
+		double v9 = v5 - kPiArray[i];
+		if (v9 < 0.0)
+			v9 = -v9;
+		if (v9 < v30) {
+			v30 = v9;
+			resId = i;
+		}
+
+		double v10 = v6 - kPiArray[i];
+		if (v10 < 0.0)
+			v10 = -v10;
+		if (v10 < v30) {
+			v30 = v10;
+			resId = i;
+		}
+	}
+
+	double v28 = p2.x - p1.x;
+	double v26 = p2.y - p1.y;
+	double v12 = Common::hypotenuse(p2.x - p1.x, p2.y - p1.y);
+
+	double v39 = 1.0 / sqrt(field_D0[resId] * field_D0[resId] - -1.0);
+	if (v39 == 0.0)
+		field_140 = v28 / v12;
+	else
+		field_140 =  (field_D0[resId] - -1.0 / (v26 / v28)) * (v26 / v12) * v39;
+
+	DBLPoint a1;
+	DBLPoint a2;
+	DBLPoint a3;
+
+	a1.x = p2.x;
+	a1.y = p2.y;
+
+	a2.x = p2.x;
+	a2.y = p2.y;
+
+	a3.x = p2.x;
+	a3.y = field_D0[resId] * v28 + p1.y;
+
+	double v13 = angle(a1, a2, a3);
+	field_140 = cos(v13);
+	field_138 = sin(v13);
+
+	double v16 = v13;
+	if (v13 < -kHalfPI)
+		v16 = v13 + kPI;
+	if (v13 > kHalfPI)
+		v16 = v13 - kPI;
+
+	field_140 = cos(v16);
+	field_138 = sin(v16);
+
+	int v32 = 1;
+	double v34 = 0.0;
+	double v35 = 0.0;
+	double v36 = p1.y;
+	v39 = v28 * v28 + v26 * v26 - -1.0;
+
+	int j = 0;
+	for (int i = 0; i < 10;) {
+		double k = g_vm->getQSystem()->getPetka()->calcPerspective(v36);
+
+		v34 += _offleg1[resId][v32] * k;
+		v35 += _offleg2[resId][v32] * k;
+
+		j++;
+
+		v32 = (v32 + 1) % waysSizes[resId];
+
+		v36 = v35 * field_140 + v34 * field_138 + p1.y;
+
+		double v22 = v34 * field_140 - v35 * field_138 + p1.x - p2.x;
+		double v38 = v36 - p2.y;
+
+		double v23 = v22 * v22 + v38 * v38;
+		if (v23 >= v39) {
+			i++;
+		} else {
+			v39 = v23;
+			field_194 = j;
+			i = 0;
+		}
+	}
+
+	field_170 = 0;
+	field_178 = 0;
+
+	currX = p1.x;
+	currY = p1.y;
+
+	field_150 = p1.x;
+	field_158 = p1.y;
+
+	field_190 = 0;
+	field_198 = g_vm->getQSystem()->getPetka()->calcPerspective(p1.y);
+	return resId;
+}
+
+int Walk::sub_423350() { // CHECKED
+	field_190 = (field_190 + 1) % waysSizes[resId];
+
+	--field_194;
+	if (field_194 < 0) {
+		field_14C++;
+		if (field_14C < field_134) {
+			int t = field_190;
+			int id = resId;
+			if (id == sub_422EA0(_bkg3_3[field_14C - 1], _bkg3_3[field_14C])) {
+				field_190 = t;
+				return 1;
+			}
+			return 2;
+		}
+		return 0;
+	}
+
+	field_198 = g_vm->getQSystem()->getPetka()->calcPerspective(currY);
+	field_170 = _offleg1[resId][field_190] * field_198 + field_170;
+	field_178 = _offleg2[resId][field_190] * field_198 + field_178;
+
+	currX = field_140 * field_170 - field_178 * field_138 + field_150;
+	currY = field_140 * field_178 + field_138 * field_170 + field_158;
+
+	return 1;
+}
+
+Common::Point Walk::sub_4234B0() { // CHECKED
+	Common::Point p;
+	field_198 = g_vm->getQSystem()->getPetka()->calcPerspective(currY);
+	p.x = currX - _leg1[resId][field_190] * field_198;
+	p.y = currY - _leg2[resId][field_190] * field_198;
+	return p;
+}
+
+bool Walk::sub_423570(int i1, int i2) { // CHECKED
+	if (i1 == i2)
+		return false;
+
+	if (_bkg2[i1].x == _bkg2[i2].x || _bkg2[i1].x == _bkg2[i2].y)
+		return true;
+
+	return !(_bkg2[i1].y != _bkg2[i2].x && _bkg2[i1].y != _bkg2[i2].y);
+}
+
+int Walk::sub_423600(Point p) {
+	int j = 0;
+	for (int i = 0; i < _bkg3Count; ++i, ++j) {
+		int *v4 = new int[_bkg3_1[j]];
+		v4[0] = _bkg3_2[j][0];
+
+		for (int k = 0; k < _bkg3_1[j]; ++k) {
+			if (sub_423570(v4[0], _bkg3_2[j][k])) {
+				v4[1] = _bkg3_2[j][k];
+				break;
+			}
+		}
+
+		for (int k = 2; k < _bkg3_1[j]; ++k) {
+			for (int l = 0; l < _bkg3_1[j]; ++l) {
+				if (sub_423570(v4[k - 1], _bkg3_2[j][l]) || v4[k - 2] == _bkg3_2[j][l]) {
+					v4[k] = _bkg3_2[j][l];
+					break;
+				}
+			}
+		}
+
+		int v11 = commonPoint(v4[_bkg3_1[j] - 1], v4[0]);
+		int v31 = commonPoint(v4[0], v4[1]);
+
+		double v12 = angle(p, _bkg1[v11], _bkg1[v31]);
+		if (p == _bkg1[v11] || p == _bkg1[v31]) {
+			free(v4);
+			return i;
+		}
+
+
+		int k;
+		for (k = 1; k < _bkg3_1[j] - 1; ++k) {
+			int v16 = commonPoint(v4[k - 1], v4[k]);
+			int v32 = commonPoint(v4[k], v4[k + 1]);
+
+			v12 += angle(p, _bkg1[v16], _bkg1[v32]);
+			if (p == _bkg1[v16] || p == _bkg1[v32]) {
+				free(v4);
+				return i;
+			}
+		}
+
+		int v19 = commonPoint(v4[k - 1], v4[k]);
+		int v20 = commonPoint(v4[k], v4[0]);
+
+		free(v4);
+
+		double v23 = angle(p, _bkg1[v19], _bkg2[v20]);
+		v12 += v23;
+
+		if (p == _bkg1[v19] || p == _bkg1[v20])
+			return i;
+
+		if (v12 < 0.0)
+			v12 = -v12;
+
+		if (v12 > kPI)
+			return i;
+	}
+
+	return 0;
+}
+
+int Walk::sub_423970(int a1, int a2) { // CHECKED
+	int index = 0;
+	if (a2 >= 0) {
+		int v5 = sub_423A30(a1, a2);
+		for (int i = 0; i < _bkg3_1[a1]; ++i) {
+			if (_bkg3_2[a1][i] == v5) {
+				index = i + 1;
+				break;
+			}
+		}
+	}
+
+	for (int i = index; i < _bkg3_1[a1]; ++i) {
+		for (int j = 0; j < _bkg3Count; ++j) {
+			if (j == a1)
+				continue;
+
+			for (int k = 0; k < _bkg3_1[j]; ++k) {
+				if (_bkg3_2[j][k] == _bkg3_2[a1][i]) {
+					return j;
+				}
+			}
+		}
+	}
+	return -1;
+}
+
+int Walk::sub_423A30(int idx1, int idx2) { // CHECKED
+	for (int i = 0; i < _bkg3_1[idx1]; ++i) {
+		for (int j = 0; j < _bkg3_1[idx2]; ++j) {
+			if (_bkg3_2[idx1][i] == _bkg3_2[idx2][j])
+				return _bkg3_2[idx1][i];
+		}
+	}
+	return 0;
+}
+
+double Walk::angle(Point p1, Point p2, Point p3) { // CHECKED
+	return angle(DBLPoint(p1), DBLPoint(p2), DBLPoint(p3));
+}
+
+double Walk::angle(DBLPoint p1, DBLPoint p2, DBLPoint p3) { // CHECKED
+	if (p1 == p2 || p1 == p3)
+		return 0.0;
+
+	double xv1 = p2.x - p1.x;
+	double xv2 = p3.x - p1.x;
+
+	double yv1 = p2.y - p1.y;
+	double yv2 = p3.y - p1.y;
+
+	double mv1 = Common::hypotenuse(xv1, yv1);
+	double mv2 = Common::hypotenuse(xv2, yv2);
+	double v13 = (xv1 * xv2 + yv1 * yv2) / (mv1 * mv2);
+	if ((xv2 / mv2 * (yv1 / mv1) - yv2 / mv2 * (xv1 / mv1)) < 0.0) // Not sure
+		return -acos(v13);
+	return acos(v13);
+}
+
+int Walk::sub_423E00(Point p1, Point p2, Point p3, Point p4, Point &p5) {
+	if (p1.x > p2.x) {
+		SWAP(p2, p1);
+	}
+
+	if (p3.x > p4.x) {
+		SWAP(p3, p4);
+	}
+
+	double v11 = (p2.y - p1.y) * (p4.x - p3.x);
+	double v12 = (p2.x - p1.x) * (p4.y - p3.y);
+	if (v11 == v12)
+		return 0;
+
+	double v30;
+	if (p2.x - p1.x) {
+		if (p4.x - p3.x) {
+			v30 = ((double)(p3.y - p1.y) * (p4.x - p3.x) * (p2.x - p1.x) + (v11 * p1.x) - (v12 * p3.x)) / (v11 - v12);
+			if (v30 < p1.x || p3.x > v30 || p2.x < v30 || p4.x < v30)
+				return 0;
+		} else {
+			v30 = p3.x;
+			if (p3.x < p1.x || p2.x < p3.x)
+				return 0;
+		}
+	} else {
+		v30 = p1.x;
+		if (p1.x < p3.x)
+			return 0;
+		if (p4.x < p1.x)
+			return 0;
+	}
+
+	if (p1.y > p2.y) {
+		SWAP(p1, p2);
+	}
+
+	if (p3.y > p4.y) {
+		SWAP(p3, p4);
+	}
+
+	if (p2.y - p1.y) {
+		if (p4.y - p3.y) {
+			double v21;
+			if (p2.x - p1.x) {
+				v21 = (v30 - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
+			} else {
+				v21 = (v30 - p3.x) * (p4.y - p3.y) / (p4.x - p3.x) + p3.y;
+			}
+
+			if (v21 >= p1.y && v21 >= p3.y && v21 <= p2.y && v21 <= p4.y) {
+				p5.x = v30;
+				p5.y = v21;
+				return 1;
+			}
+
+		} else {
+			if (p3.y >= p1.y) {
+				if (p3.y > p2.y)
+					return 0;
+				p5.x = v30;
+				p5.y = p3.y;
+				return 1;
+			}
+		}
+	} else {
+		if (p1.y >= p3.y) {
+			if (p1.y <= p4.y) {
+				p5.x = v30;
+				p5.y = p1.y;
+				return 1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+bool Walk::sub_424160(Point *p1, Point *p2) { // CHECKED
+	if (*p1 == *p2)
+		return false;
+
+	Point p;
+	int v = 1;
+	if (_bkg1Count <= 1)
+		return sub_423E00(_bkg1[v - 1], _bkg1[0], *p1, *p2, p) != 0;
+
+	while (!sub_423E00(_bkg1[v - 1], _bkg1[v], *p1, *p2, p)) {
+		if (++v >= _bkg1Count)
+			return sub_423E00(_bkg1[v - 1], _bkg1[0], *p1, *p2, p) != 0;
+	}
+	return true;
+}
+
+bool Walk::sub_424230(Point *p1) { // CHECKED
+	Point p(0, 0);
+	int v = sub_424320(p1, &p);
+
+	p.y = p1->y;
+	v = (sub_424320(p1, &p) & 1) + (v & 1);
+
+	p.y = 480;
+	v = (sub_424320(p1, &p) & 1) + v;
+	v = (sub_424320(p1, &p) & 1) + v;
+
+	p.x = 640;
+	v = (sub_424320(p1, &p) & 1) + v;
+
+	p.y = p1->y;
+	v = (sub_424320(p1, &p) & 1) + v;
+
+	p.y = 0;
+	v = (sub_424320(p1, &p) & 1) + v;
+
+	p.x = p1->x;
+	return (sub_424320(p1, &p) & 1) + v < 4;
+}
+
+int Walk::sub_424320(Point *p1, Point *p2) { // CHECKED
+	if (*p1 == *p2)
+		return 0;
+
+	int ret = 0;
+
+	Point p;
+
+	int i;
+	for (i = 1; i < _bkg1Count; ++i) {
+		if (sub_423E00(_bkg1[i - 1], _bkg1[i], *p1, *p2, p) && *p1 != p && *p2 != p) {
+			ret++;
+		}
+	}
+
+	if (sub_423E00(_bkg1[i - 1], _bkg1[0], *p1, *p2, p) && *p1 != p && *p2 != p) {
+		ret++;
+	}
+
+	return ret;
+}
+
+int Walk::moveInside(Point *p) { // CHECKED
+	DBLPoint dp = sub_424610(_bkg1[_bkg2->x], _bkg1[_bkg2->y].x, _bkg1[_bkg2->y].y, *p);
+
+	int v7 = 0;
+	int v23 = 0;
+
+	double min = (dp.y - p->y) * (dp.y - p->y) + (dp.x - p->x) * (dp.x - p->x);
+	for (int i = 1; i < _bkg1Count; ++i) {
+		DBLPoint dp1 = sub_424610(_bkg1[_bkg2[i].x], _bkg1[_bkg2[i].y].x, _bkg1[_bkg2[i].y].y, *p);
+		double curr = (dp1.y - p->y) * (dp1.y - p->y) + (dp1.x - p->x) * (dp1.x - p->x);
+		if (curr >= min) {
+			v7 = v23;
+		} else {
+			dp = dp1;
+			min = curr;
+			v7 = i;
+			v23 = i;
+		}
+
+	}
+
+	p->x = dp.x;
+	p->y = dp.y;
+
+
+	for (int i = 0; i < _bkg1Count; ++i) {
+		for (int j = 0; j < _bkg3_1[i]; ++j) {
+			if (_bkg3_2[i][j] == v7)
+				return i;
+		}
+	}
+
+	return 0;
+}
+
+DBLPoint Walk::sub_424610(Point p1, int x, int y, Point p2) { // CHECKED
+	DBLPoint p;
+	double v13;
+	double v14;
+	if (p1.x == x) {
+		v13 = p1.x;
+		v14 = p2.y;
+	} else {
+		double v6 = (double)(y - p1.y) / (x - p1.x);
+		double v7 = p1.y - v6 * p1.x;
+		v13 = ((p2.y - v7) * v6 + p2.x) / (v6 * v6 - -1.0);
+		v14 = v13 * v6 + v7;
+	}
+	p.x = CLIP<double>(v13, MIN<int>(x, p1.x), MAX<int>(x, p1.x));
+	p.y = CLIP<double>(v14, MIN<int>(y, p1.y), MAX<int>(y, p1.y));
+	return p;
+}
+
+} // End of namespace Petka
diff --git a/engines/petka/walk.h b/engines/petka/walk.h
new file mode 100644
index 0000000000..8139177aec
--- /dev/null
+++ b/engines/petka/walk.h
@@ -0,0 +1,156 @@
+/* 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.
+ *
+ */
+
+#ifndef PETKA_WALK_H
+#define PETKA_WALK_H
+
+#include "common/rect.h"
+
+namespace Petka {
+
+struct Point {
+	int x;
+	int y;
+
+	Point() : x(0), y(0) {}
+	Point(int x_, int y_) : x(x_), y(y_) {}
+	Point(Common::Point p) : x(p.x), y(p.y) {}
+	bool operator==(const Point &p) { return x == p.x && y == p.y; }
+	bool operator!=(const Point &p) { return !(*this == p); }
+};
+
+struct DBLPoint {
+	double x;
+	double y;
+
+	DBLPoint() : x(0.0), y(0.0) {}
+	DBLPoint(double x1, double y1) : x(x1), y(y1) {}
+	DBLPoint(Point p) : x(p.x), y(p.y) {}
+
+	bool operator==(const DBLPoint &p) { return x == p.x && y == p.y; }
+};
+
+class Walk {
+public:
+	Walk(int id);
+	~Walk();
+
+	void init(Point start, Point end);
+
+	void clearBackground();
+	void setBackground(Common::String name);
+
+	void reset();
+
+	Common::Point currPos();
+
+	int getSpriteId();
+
+	int commonPoint(int, int);
+
+	int readWayFile(const Common::String &name, int **, int **);
+
+	int sub_422EA0(Point p1, Point p2);
+	int sub_423350();
+	Common::Point sub_4234B0();
+	bool sub_423570(int, int);
+
+	int sub_423600(Point p);
+	int sub_423970(int, int);
+	int sub_423A30(int, int);
+
+	static double angle(Point p1, Point p2, Point p3);
+	static double angle(DBLPoint p1, DBLPoint p2, DBLPoint p3);
+
+	static int sub_423E00(Point p1, Point p2, Point p3, Point p4, Point &p5);
+
+	bool sub_424160(Point *p1, Point *p2);
+	bool sub_424230(Point *p1);
+	int sub_424320(Point *p1, Point *p2);
+
+	int moveInside(Point *p);
+	DBLPoint sub_424610(Point p1, int x, int y, Point p4);
+
+public:
+	char field_4;
+	char field_5;
+	char field_6;
+	char field_7;
+	int *_leg1[8];
+	int *_leg2[8];
+	int *_off1[8];
+	int *_off2[8];
+	int *_offleg1[8];
+	int *_offleg2[8];
+	int *_bkg3_4;
+	int *_bkg3_5;
+	double field_D0[8];
+	int waysSizes[8];
+	Point *_bkg3_3;
+	int field_134;
+	double field_138;
+	double field_140;
+	int resId;
+	int field_14C;
+	double field_150;
+	double field_158;
+	double currX;
+	double currY;
+	double field_170;
+	double field_178;
+	char field_180;
+	char field_181;
+	char field_182;
+	char field_183;
+	char field_184;
+	char field_185;
+	char field_186;
+	char field_187;
+	char field_188;
+	char field_189;
+	char field_18A;
+	char field_18B;
+	char field_18C;
+	char field_18D;
+	char field_18E;
+	char field_18F;
+	int field_190;
+	int field_194;
+	double field_198;
+	int destX;
+	int destY;
+	int _bkg1Count;
+	Point *_bkg1;
+	int _bkg2Count;
+	int _bkg3Count;
+	int *_bkg3_1;
+	int **_bkg3_2;
+	Point *_bkg2;
+	char field_1C4;
+	char field_1C5;
+	char field_1C6;
+	char field_1C7;
+};
+
+} // End of namespace Petka
+
+#endif
\ No newline at end of file




More information about the Scummvm-git-logs mailing list