aboutsummaryrefslogtreecommitdiff
path: root/engines/draci/walking.h
blob: 7e4a3184f54f62499d3f387cb632c0f92e060f08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
/* 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 DRACI_WALKING_H
#define DRACI_WALKING_H

#include "common/array.h"
#include "common/rect.h"

namespace Draci {

class Sprite;

typedef Common::Array<Common::Point> WalkingPath;

class WalkingMap {
public:
	WalkingMap() : _realWidth(0), _realHeight(0), _deltaX(1), _deltaY(1),
		_mapWidth(0), _mapHeight(0), _byteWidth(0), _data(NULL) { }

	void load(const byte *data, uint length);

	bool getPixel(int x, int y) const;
	bool isWalkable(const Common::Point &p) const;

	Sprite *newOverlayFromMap(byte color) const;
	Common::Point findNearestWalkable(int x, int y) const;

	bool findShortestPath(Common::Point p1, Common::Point p2, WalkingPath *path) const;
	void obliquePath(const WalkingPath& path, WalkingPath *obliquedPath);
	Sprite *newOverlayFromPath(const WalkingPath &path, byte color) const;
	Common::Point getDelta() const { return Common::Point(_deltaX, _deltaY); }

	static int pointsBetween(const Common::Point &p1, const Common::Point &p2);
	static Common::Point interpolate(const Common::Point &p1, const Common::Point &p2, int i, int n);

private:
	int _realWidth, _realHeight;
	int _deltaX, _deltaY;
	int _mapWidth, _mapHeight;
	int _byteWidth;

	// We don't own the pointer.  It points to the BArchive cache for this room.
	const byte *_data;

	// 4 possible directions to walk from a pixel.
	static const int kDirections[][2];

	void drawOverlayRectangle(const Common::Point &p, byte color, byte *buf) const;
	bool lineIsCovered(const Common::Point &p1, const Common::Point &p2) const;

	// Returns true if the number of vertices on the path was decreased.
	bool managedToOblique(WalkingPath *path) const;
};

/*
 * Enumerates the directions the dragon can look into when arrived.
 */
enum SightDirection {
	kDirectionLast, kDirectionMouse, kDirectionUnknown,
	kDirectionRight, kDirectionLeft, kDirectionIntelligent
};

/**
  * Enumerates the animations for the dragon's movement.
  */
enum Movement {
	kMoveUndefined = -1,
	kMoveDown, kMoveUp, kMoveRight, kMoveLeft,

	kFirstTurning,
	kMoveRightDown = kFirstTurning, kMoveRightUp, kMoveLeftDown, kMoveLeftUp,
	kMoveDownRight, kMoveUpRight, kMoveDownLeft, kMoveUpLeft,
	kMoveLeftRight, kMoveRightLeft, kMoveUpStopLeft, kMoveUpStopRight,
	kLastTurning = kMoveUpStopRight,

	kSpeakRight, kSpeakLeft, kStopRight, kStopLeft,

	kFirstTemporaryAnimation
};

class DraciEngine;
struct GPL2Program;

class WalkingState {
public:
	explicit WalkingState(DraciEngine *vm) : _vm(vm) {
		_dir = kDirectionLast;
		_startingDirection = kMoveUndefined;
		_segment = 0;
		_lastAnimPhase = 0;
		_turningFinished = 0;
		_callbackOffset = 0;

		stopWalking(); 
	}

	~WalkingState() {}

	void stopWalking();
	void startWalking(const Common::Point &p1, const Common::Point &p2,
		const Common::Point &mouse, SightDirection dir,
		const Common::Point &delta, const WalkingPath& path);
	const WalkingPath& getPath() const { return _path; }

	void setCallback(const GPL2Program *program, uint16 offset);
	void callback();

	bool isActive() const { return _path.size() > 0; }

	// Advances the hero along the path and changes animation accordingly.
	// Walking MUST be active when calling this method.  When the hero has
	// arrived to the target, returns false, but leaves the callback
	// untouched (the caller must call it).
	// The second variant also clears the path when returning false.
	bool continueWalking();
	bool continueWalkingOrClearPath();

	// Called when the hero's turning animation has finished.
	void heroAnimationFinished();

	// Returns the hero's animation corresponding to looking into given
	// direction.  The direction can be smart and in that case this
	// function needs to know the whole last path, the current position of
	// the hero, or the mouse position.
	static Movement animationForSightDirection(SightDirection dir, const Common::Point &hero, const Common::Point &mouse, const WalkingPath &path, Movement startingDirection);

private:
	DraciEngine *_vm;

	WalkingPath _path;
	Common::Point _mouse;
	SightDirection _dir;
	Movement _startingDirection;

	uint _segment;		// Index of the path vertex we are currently going to / rotation on
	int _lastAnimPhase;
	bool _turningFinished;

	const GPL2Program *_callback;
	uint16 _callbackOffset;

	// Initiates turning of the dragon into the direction for the next
	// segment / after walking.  Returns false when there is nothing left
	// to do and walking is done.
	bool turnForTheNextSegment();

	// Starts walking on the next edge.  Returns false if we are already at
	// the final vertex and walking is done.
	bool walkOnNextEdge();

	// Return one of the 4 animations kMove{Down,Up,Right,Left}
	// corresponding to walking from here to there.
	static Movement animationForDirection(const Common::Point &here, const Common::Point &there);

	// Returns the desired facing direction to begin the next phase of the
	// walk.  It's either a direction for the given edge or the desired
	// final direction.
	Movement directionForNextPhase() const;

	// Returns either animation that needs to be played between given two
	// animations (e.g., kMoveRightDown after kMoveRight and before
	// kMoveDown), or kMoveUndefined if none animation is to be played.
	static Movement transitionBetweenAnimations(Movement previous, Movement next);

	static bool isTurningMovement(Movement m) {
		return m >= kFirstTurning && m <= kLastTurning;
	}

	// Projects hero to the given edge.  Returns true when hero has reached
	// at least p2.  prevHero is passed so that we can compute how much to
	// adjust in the other-than-walking direction.
	static bool alignHeroToEdge(const Common::Point &p1, const Common::Point &p2, const Common::Point &prevHero, Common::Point *hero);
};

} // End of namespace Draci

#endif // DRACI_WALKING_H