aboutsummaryrefslogtreecommitdiff
path: root/engines/draci/walking.h
blob: 180c3cf855424857a789702698d7cc922048d84d (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
/* 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.
 *
 * $URL$
 * $Id$
 *
 */

#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(int x, int y) const;

	Sprite *newOverlayFromMap(byte colour) const;
	Common::Point findNearestWalkable(int x, int y, Common::Rect searchRect) 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 colour) 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 int kDirections[][2];

	void drawOverlayRectangle(const Common::Point &p, byte colour, 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
};

class DraciEngine;
struct GPL2Program;

class WalkingState {
public:
	explicit WalkingState(DraciEngine *vm) : _vm(vm) { 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, clears the path and returns false, but leaves
	// the callback untouched (the caller must call it).
	bool continueWalking();

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

	// Returns the hero's animation corresponding to looking into given direction.
	Movement animationForSightDirection(SightDirection dir) const;

private:
	DraciEngine *_vm;

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

	int _segment;
	int _position, _length;
	int _lastAnimPhase;

	const GPL2Program *_callback;
	uint16 _callbackOffset;

	// Initiates turning of the dragon into the direction for the next segment / after walking.
	void turnForTheNextSegment();

	// Return one of the 4 animations kMove{Down,Up,Right,Left}
	// corresponding to the 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;
	}
};

} // End of namespace Draci

#endif // DRACI_WALKING_H