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 198 199 200 201 202
|
/* 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;
_callbackOffsetLast = 0;
_callbackLast = 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();
void callbackLast();
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;
const GPL2Program *_callbackLast;
uint16 _callbackOffset;
uint16 _callbackOffsetLast;
// 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
|