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