1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "engines/stark/movement/followpath.h"
24 
25 #include "engines/stark/services/global.h"
26 #include "engines/stark/services/services.h"
27 #include "engines/stark/services/stateprovider.h"
28 
29 #include "engines/stark/resources/anim.h"
30 #include "engines/stark/resources/floor.h"
31 #include "engines/stark/resources/item.h"
32 #include "engines/stark/resources/path.h"
33 
34 namespace Stark {
35 
FollowPath(Resources::ItemVisual * item)36 FollowPath::FollowPath(Resources::ItemVisual *item) :
37 		Movement(item),
38 		_path(nullptr),
39 		_speed(0.0),
40 		_position(0.0),
41 		_previouslyEnabled(true),
42 		_anim(nullptr) {
43 }
44 
~FollowPath()45 FollowPath::~FollowPath() {
46 }
47 
start()48 void FollowPath::start() {
49 	Movement::start();
50 
51 	_previouslyEnabled = _item->isEnabled();
52 	_item->setEnabled(true);
53 
54 	updateItemPosition(0, 0);
55 	changeItemAnim();
56 }
57 
stop()58 void FollowPath::stop() {
59 	Movement::stop();
60 
61 	changeItemAnim();
62 	_item->setEnabled(_previouslyEnabled);
63 }
64 
onGameLoop()65 void FollowPath::onGameLoop() {
66 	// Compute the new position on the path
67 	_position += _speed * StarkGlobal->getMillisecondsPerGameloop();
68 
69 	// Find the current path edge, and position on the path edge
70 	uint currentEdge = 0;
71 	float positionInEdge = _position;
72 	for (uint i = 0; i < _path->getEdgeCount(); i++) {
73 		float edgeLength = _path->getWeightedEdgeLength(i);
74 		if (positionInEdge < edgeLength) {
75 			break; // Found the current path edge
76 		}
77 
78 		positionInEdge -= edgeLength;
79 		currentEdge++;
80 	}
81 
82 	// Check if we went beyond the path's end
83 	if (currentEdge >= _path->getEdgeCount()) {
84 		stop();
85 		return;
86 	}
87 
88 	updateItemPosition(currentEdge, positionInEdge);
89 }
90 
updateItemPosition(uint currentEdge,float positionInEdge) const91 void FollowPath::updateItemPosition(uint currentEdge, float positionInEdge) const {// Get the new position for the item
92 	Math::Vector3d newPosition = _path->getWeightedPositionInEdge(currentEdge, positionInEdge);
93 
94 	// Update the item's properties in the scene
95 	if (is3D()) {
96 		Resources::FloorPositionedItem *item3D = Resources::Object::cast<Resources::FloorPositionedItem>(_item);
97 		Resources::Floor *floor = StarkGlobal->getCurrent()->getFloor();
98 
99 		int32 floorFaceIndex = floor->findFaceContainingPoint(newPosition);
100 		if (floorFaceIndex >= 0) {
101 			item3D->setFloorFaceIndex(floorFaceIndex);
102 		} else {
103 			item3D->overrideSortKey(_path->getSortKey());
104 		}
105 
106 		item3D->setPosition3D(newPosition);
107 
108 		Math::Vector3d direction = _path->getEdgeDirection(currentEdge);
109 		item3D->setDirection(computeAngleBetweenVectorsXYPlane(direction, Math::Vector3d(1.0, 0.0, 0.0)));
110 	} else {
111 		Common::Point position2D = Common::Point(newPosition.x(), newPosition.y());
112 		_item->setPosition2D(position2D);
113 	}
114 }
115 
changeItemAnim()116 void FollowPath::changeItemAnim() {
117 	if (_ended) {
118 		if (_anim) {
119 			_item->resetActionAnim();
120 		} else {
121 			_item->setAnimKind(Resources::Anim::kActorUsageIdle);
122 		}
123 	} else {
124 		if (_anim) {
125 			_item->playActionAnim(_anim);
126 		} else {
127 			_item->setAnimKind(Resources::Anim::kActorUsageWalk);
128 		}
129 	}
130 }
131 
setPath(Resources::Path * path)132 void FollowPath::setPath(Resources::Path *path) {
133 	_path = path;
134 }
135 
setSpeed(float speed)136 void FollowPath::setSpeed(float speed) {
137 	_speed = speed;
138 }
139 
is3D() const140 bool FollowPath::is3D() const {
141 	return _path->getSubType() == Resources::Path::kPath3D;
142 }
143 
setAnim(Resources::Anim * anim)144 void FollowPath::setAnim(Resources::Anim *anim) {
145 	_anim = anim;
146 }
147 
getType() const148 uint32 FollowPath::getType() const {
149 	return kTypeFollowPath;
150 }
151 
saveLoad(ResourceSerializer * serializer)152 void FollowPath::saveLoad(ResourceSerializer *serializer) {
153 	serializer->syncAsResourceReference(&_path);
154 	serializer->syncAsResourceReference(&_anim);
155 	serializer->syncAsFloat(_position);
156 	serializer->syncAsFloat(_speed);
157 	serializer->syncAsUint32LE(_previouslyEnabled);
158 }
159 
160 } // End of namespace Stark
161