scummvm/engines/lure/hotspots.h

566 lines
17 KiB
C++

/* 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 LURE_HOTSPOTS_H
#define LURE_HOTSPOTS_H
#include "lure/luredefs.h"
#include "lure/screen.h"
#include "lure/disk.h"
#include "lure/res_struct.h"
namespace Lure {
#define MAX_NUM_IMPINGING 10
class Hotspot;
class Support {
private:
static bool changeRoomCheckBumped(Hotspot &h);
public:
static int findIntersectingCharacters(Hotspot &h, uint16 *charList);
static bool checkForIntersectingCharacter(Hotspot &h);
static bool checkRoomChange(Hotspot &h);
static void characterChangeRoom(Hotspot &h, uint16 roomNumber,
int16 newX, int16 newY, Direction dir);
static bool charactersIntersecting(HotspotData *hotspot1, HotspotData *hotspot2);
static bool isCharacterInList(uint16 *lst, int numEntries, uint16 charId);
};
typedef void(*HandlerMethodPtr)(Hotspot &h);
class HotspotTickHandlers {
private:
// Support methods
static void npcRoomChange(Hotspot &h);
// Handler methods
static void defaultHandler(Hotspot &h);
static void voiceBubbleAnimHandler(Hotspot &h);
static void standardAnimHandler(Hotspot &h);
static void standardAnimHandler2(Hotspot &h);
static void standardCharacterAnimHandler(Hotspot &h);
static void puzzledAnimHandler(Hotspot &h);
static void roomExitAnimHandler(Hotspot &h);
static void playerAnimHandler(Hotspot &h);
static void followerAnimHandler(Hotspot &h);
static void jailorAnimHandler(Hotspot &h);
static void sonicRatAnimHandler(Hotspot &h);
static void droppingTorchAnimHandler(Hotspot &h);
static void playerSewerExitAnimHandler(Hotspot &h);
static void fireAnimHandler(Hotspot &h);
static void sparkleAnimHandler(Hotspot &h);
static void teaAnimHandler(Hotspot &h);
static void goewinCaptiveAnimHandler(Hotspot &h);
static void prisonerAnimHandler(Hotspot &h);
static void catrionaAnimHandler(Hotspot &h);
static void morkusAnimHandler(Hotspot &h);
static void talkAnimHandler(Hotspot &h);
static void grubAnimHandler(Hotspot &h);
static void barmanAnimHandler(Hotspot &h);
static void skorlAnimHandler(Hotspot &h);
static void gargoyleAnimHandler(Hotspot &h);
static void goewinShopAnimHandler(Hotspot &h);
static void skullAnimHandler(Hotspot &h);
static void dragonFireAnimHandler(Hotspot &h);
static void castleSkorlAnimHandler(Hotspot &h);
static void rackSerfAnimHandler(Hotspot &h);
static void fighterAnimHandler(Hotspot &h);
static void playerFightAnimHandler(Hotspot &h);
public:
static HandlerMethodPtr getHandler(uint16 procOffset);
};
enum CurrentAction {NO_ACTION, START_WALKING, DISPATCH_ACTION, EXEC_HOTSPOT_SCRIPT,
PROCESSING_PATH, WALKING};
class CurrentActionEntry {
private:
CurrentAction _action;
CharacterScheduleEntry *_supportData;
uint16 _roomNumber;
bool _dynamicSupportData;
public:
CurrentActionEntry(CurrentAction newAction, uint16 roomNum);
CurrentActionEntry(CurrentAction newAction, CharacterScheduleEntry *data, uint16 roomNum);
CurrentActionEntry(Action newAction, uint16 roomNum, uint16 param1, uint16 param2);
virtual ~CurrentActionEntry() {
if (_dynamicSupportData) delete _supportData;
}
CurrentAction action() { return _action; }
CharacterScheduleEntry &supportData() {
if (!_supportData) error("Access made to non-defined action support record");
return *_supportData;
}
bool hasSupportData() { return _supportData != NULL; }
uint16 roomNumber() { return _roomNumber; }
void setAction(CurrentAction newAction) { _action = newAction; }
void setRoomNumber(uint16 roomNum) { _roomNumber = roomNum; }
void setSupportData(CharacterScheduleEntry *newRec) {
assert((newRec == NULL) || (newRec->parent() != NULL));
_supportData = newRec;
}
void setSupportData(uint16 entryId);
void saveToStream(WriteStream *stream);
static CurrentActionEntry *loadFromStream(ReadStream *stream);
};
class CurrentActionStack {
private:
ManagedList<CurrentActionEntry *> _actions;
void validateStack() {
if (_actions.size() > 20)
error("NPC character got an excessive number of pending actions");
}
public:
CurrentActionStack() { _actions.clear(); }
bool isEmpty() { return _actions.begin() == _actions.end(); }
void clear() { _actions.clear(); }
CurrentActionEntry &top() { return **_actions.begin(); }
CurrentAction action() { return isEmpty() ? NO_ACTION : top().action(); }
void pop() { _actions.erase(_actions.begin()); }
int size() { return _actions.size(); }
void list(char *buffer);
void list() { list(NULL); }
void addBack(CurrentAction newAction, uint16 roomNum) {
_actions.push_back(new CurrentActionEntry(newAction, roomNum));
validateStack();
}
void addBack(CurrentAction newAction, CharacterScheduleEntry *rec, uint16 roomNum) {
_actions.push_back(new CurrentActionEntry(newAction, rec, roomNum));
validateStack();
}
void addBack(Action newAction, uint16 roomNum, uint16 param1, uint16 param2) {
_actions.push_back(new CurrentActionEntry(newAction, roomNum, param1, param2));
validateStack();
}
void addFront(CurrentAction newAction, uint16 roomNum) {
_actions.push_front(new CurrentActionEntry(newAction, roomNum));
validateStack();
}
void addFront(CurrentAction newAction, CharacterScheduleEntry *rec, uint16 roomNum) {
_actions.push_front(new CurrentActionEntry(newAction, rec, roomNum));
validateStack();
}
void addFront(Action newAction, uint16 roomNum, uint16 param1, uint16 param2) {
_actions.push_front(new CurrentActionEntry(newAction, roomNum, param1, param2));
validateStack();
}
void saveToStream(WriteStream *stream);
void loadFromStream(ReadStream *stream);
};
class WalkingActionEntry {
private:
Direction _direction;
int _numSteps;
public:
WalkingActionEntry(Direction dir, int steps): _direction(dir), _numSteps(steps) {}
Direction direction() { return _direction; }
int &rawSteps() { return _numSteps; }
int numSteps();
};
enum PathFinderResult {PF_UNFINISHED, PF_OK, PF_DEST_OCCUPIED, PF_PART_PATH, PF_NO_WALK};
class PathFinder {
private:
Hotspot *_hotspot;
bool _inUse;
ManagedList<WalkingActionEntry *> _list;
RoomPathsDecompressedData _layer;
int _stepCtr;
bool _inProgress;
int _countdownCtr;
int16 _destX, _destY;
int16 _xPos, _yPos;
int16 _xCurrent, _yCurrent;
int16 _xDestPos, _yDestPos;
int16 _xDestCurrent, _yDestCurrent;
bool _destOccupied;
bool _cellPopulated;
uint16 *_pSrc, *_pDest;
int _xChangeInc, _xChangeStart;
int _yChangeInc, _yChangeStart;
int _xCtr, _yCtr;
void initVars();
void processCell(uint16 *p);
void scanLine(int numScans, int changeAmount, uint16 *&pEnd, int &v);
void add(Direction dir, int steps) {
_list.push_front(new WalkingActionEntry(dir, steps));
}
void addBack(Direction dir, int steps) {
_list.push_back(new WalkingActionEntry(dir, steps));
}
public:
PathFinder(Hotspot *h);
void clear();
void reset(RoomPathsData &src);
PathFinderResult process();
void list(char *buffer);
void list() { list(NULL); }
void pop() { _list.erase(_list.begin()); }
WalkingActionEntry &top() { return **_list.begin(); }
bool isEmpty() { return _list.empty(); }
int &stepCtr() { return _stepCtr; }
void saveToStream(Common::WriteStream *stream);
void loadFromStream(Common::ReadStream *stream);
};
enum HotspotPrecheckResult {PC_EXECUTE, PC_NOT_IN_ROOM, PC_FAILED, PC_WAIT, PC_EXCESS};
enum BarPlaceResult {BP_KEEP_TRYING, BP_GOT_THERE, BP_FAIL};
struct DestStructure {
uint8 counter;
Point position;
};
#define MAX_NUM_FRAMES 16
class Hotspot {
private:
HotspotData *_data;
uint16 _animId;
HotspotAnimData *_anim;
HandlerMethodPtr _tickHandler;
Surface *_frames;
uint16 _hotspotId;
uint16 _originalId;
uint16 _roomNumber;
int16 _startX, _startY;
uint16 _height, _width;
uint16 _heightCopy, _widthCopy;
uint16 _yCorrection;
uint16 _charRectY;
int8 _talkX, _talkY;
uint16 _numFrames;
uint16 _frameNumber;
Direction _direction;
uint8 _layer;
uint16 _hotspotScriptOffset;
uint16 _tickCtr;
uint8 _colourOffset;
bool _persistant;
HotspotOverrideData *_override;
bool _skipFlag;
CurrentActionStack _currentActions;
PathFinder _pathFinder;
uint16 _frameWidth;
bool _frameStartsUsed;
uint16 _frameStarts[MAX_NUM_FRAMES];
char _nameBuffer[MAX_HOTSPOT_NAME_SIZE];
DestStructure _tempDest;
// Runtime fields
uint16 _frameCtr;
uint8 _voiceCtr;
int16 _destX, _destY;
uint16 _destHotspotId;
uint16 _blockedOffset;
uint8 _exitCtr;
bool _walkFlag;
uint16 _startRoomNumber;
uint16 _supportValue;
// Support methods
uint16 getTalkId(HotspotData *charHotspot);
void startTalk(HotspotData *charHotspot, uint16 id);
void startTalkDialog();
// Action support methods
HotspotPrecheckResult actionPrecheck(HotspotData *hotspot);
BarPlaceResult getBarPlace();
bool findClearBarPlace();
bool characterWalkingCheck(HotspotData *hotspot);
bool doorCloseCheck(uint16 doorId);
void resetDirection();
// Action set
void doNothing(HotspotData *hotspot);
void doGet(HotspotData *hotspot);
void doOperate(HotspotData *hotspot);
void doOpen(HotspotData *hotspot);
void doClose(HotspotData *hotspot);
void doLockUnlock(HotspotData *hotspot);
void doUse(HotspotData *hotspot);
void doGive(HotspotData *hotspot);
void doTalkTo(HotspotData *hotspot);
void doTell(HotspotData *hotspot);
void doLook(HotspotData *hotspot);
void doLookAt(HotspotData *hotspot);
void doLookThrough(HotspotData *hotspot);
void doAsk(HotspotData *hotspot);
void doDrink(HotspotData *hotspot);
void doStatus(HotspotData *hotspot);
void doGoto(HotspotData *hotspot);
void doReturn(HotspotData *hotspot);
void doBribe(HotspotData *hotspot);
void doExamine(HotspotData *hotspot);
void npcSetRoomAndBlockedOffset(HotspotData *hotspot);
void npcHeySir(HotspotData *hotspot);
void npcExecScript(HotspotData *hotspot);
void npcResetPausedList(HotspotData *hotspot);
void npcSetRandomDest(HotspotData *hotspot);
void npcWalkingCheck(HotspotData *hotspot);
void npcSetSupportOffset(HotspotData *hotspot);
void npcSupportOffsetConditional(HotspotData *hotspot);
void npcDispatchAction(HotspotData *hotspot);
void npcTalkNpcToNpc(HotspotData *hotspot);
void npcPause(HotspotData *hotspot);
void npcStartTalking(HotspotData *hotspot);
void npcJumpAddress(HotspotData *hotspot);
// Auxillaries
void doLookAction(HotspotData *hotspot, Action action);
public:
Hotspot(HotspotData *res);
Hotspot(Hotspot *character, uint16 objType);
Hotspot();
~Hotspot();
void setAnimation(uint16 newAnimId);
void setAnimation(HotspotAnimData *newRecord);
uint16 hotspotId() { return _hotspotId; }
uint16 originalId() { return _originalId; }
Surface &frames() { return *_frames; }
HotspotAnimData &anim() { return *_anim; }
HotspotData *resource() { return _data; }
uint16 numFrames() { return _numFrames; }
uint16 frameNumber() { return _frameNumber; }
void setFrameNumber(uint16 frameNum) {
assert(frameNum < _numFrames);
_frameNumber = frameNum;
}
void incFrameNumber();
Direction direction() { return _direction; }
uint16 frameWidth() { return _width; }
int16 x() { return _startX; }
int16 y() { return _startY; }
int16 destX() { return _destX; }
int16 destY() { return _destY; }
int8 talkX() { return _talkX; }
int8 talkY() { return _talkY; }
uint16 destHotspotId() { return _destHotspotId; }
uint16 blockedOffset() { return _blockedOffset; }
uint8 exitCtr() { return _exitCtr; }
bool walkFlag() { return _walkFlag; }
uint16 startRoomNumber() { return _startRoomNumber; }
uint16 width() { return _width; }
uint16 height() { return _height; }
uint16 widthCopy() { return _widthCopy; }
uint16 heightCopy() { return _heightCopy; }
uint16 yCorrection() { return _yCorrection; }
uint16 charRectY() { return _charRectY; }
uint16 roomNumber() { return _roomNumber; }
uint16 talkScript() {
assert(_data);
return _data->talkScriptOffset;
}
uint16 hotspotScript() { return _hotspotScriptOffset; }
uint8 layer() { return _layer; }
uint16 tickCtr() { return _tickCtr; }
bool skipFlag() { return _skipFlag; }
void setTickCtr(uint16 newVal) { _tickCtr = newVal; }
void setTickProc(uint16 newVal);
bool persistant() { return _persistant; }
void setPersistant(bool value) { _persistant = value; }
uint8 colourOffset() { return _colourOffset; }
void setColourOffset(uint8 value) { _colourOffset = value; }
void setRoomNumber(uint16 roomNum) {
_roomNumber = roomNum;
if (_data) _data->roomNumber = roomNum;
}
uint16 nameId();
const char *getName();
bool isActiveAnimation();
void setPosition(int16 newX, int16 newY);
void setDestPosition(int16 newX, int16 newY) { _destX = newX; _destY = newY; }
void setDestHotspot(uint16 id) { _destHotspotId = id; }
void setExitCtr(uint8 value) { _exitCtr = value; }
BlockedState blockedState() {
assert(_data);
return _data->blockedState;
}
void setBlockedState(BlockedState newState) {
assert(_data);
_data->blockedState = newState;
}
bool blockedFlag() {
assert(_data);
return _data->blockedFlag;
}
void setBlockedFlag(bool newValue) {
assert(_data);
_data->blockedFlag = newValue;
}
void setWalkFlag(bool value) { _walkFlag = value; }
void setStartRoomNumber(uint16 value) { _startRoomNumber = value; }
void setSize(uint16 newWidth, uint16 newHeight);
void setWidth(uint16 newWidth) {
_width = newWidth;
_frameWidth = newWidth;
}
void setHeight(uint16 newHeight) {
_height = newHeight;
}
void setHotspotScript(uint16 offset) {
assert(_data != NULL);
_hotspotScriptOffset = offset;
_data->hotspotScriptOffset = offset;
}
void setLayer(uint8 newLayer) {
assert(_data != NULL);
_layer = newLayer;
_data->layer = newLayer;
}
void setActions(uint32 newActions) {
assert(_data);
_data->actions = newActions;
}
void setCharRectY(uint16 value) { _charRectY = value; }
void setSkipFlag(bool value) { _skipFlag = value; }
CharacterMode characterMode() {
assert(_data != NULL);
return _data->characterMode;
}
void setCharacterMode(CharacterMode value) {
assert(_data != NULL);
_data->characterMode = value;
}
uint16 delayCtr() {
assert(_data);
return _data->delayCtr;
}
void setDelayCtr(uint16 value) {
assert(_data);
_data->delayCtr = value;
}
uint16 pauseCtr() {
assert(_data);
return _data->pauseCtr;
}
void setPauseCtr(uint16 value) {
assert(_data);
_data->pauseCtr = value;
}
VariantBool coveredFlag() {
assert(_data);
return _data->coveredFlag;
}
void setCoveredFlag(VariantBool value) {
assert(_data);
_data->coveredFlag = value;
}
uint16 useHotspotId() {
assert(_data);
return _data->useHotspotId;
}
void setUseHotspotId(uint16 value) {
assert(_data);
_data->useHotspotId = value;
}
uint16 talkGate() {
assert(_data);
return _data->talkGate;
}
void setTalkGate(uint16 value) {
assert(_data);
_data->talkGate = value;
}
uint16 supportValue() { return _supportValue; }
void setSupportValue(uint16 value) { _supportValue = value; }
void copyTo(Surface *dest);
bool executeScript();
void tick();
bool isRoomExit(uint16 id);
// Walking
void walkTo(int16 endPosX, int16 endPosY, uint16 destHotspot = 0);
void stopWalking();
void endAction();
void setDirection(Direction dir);
void faceHotspot(HotspotData *hotspot);
void faceHotspot(uint16 hotspotId);
void setRandomDest();
void setOccupied(bool occupiedFlag);
bool walkingStep();
void updateMovement();
void updateMovement2(CharacterMode value);
void resetPosition();
void doAction();
void doAction(Action action, HotspotData *hotspot);
CurrentActionStack &currentActions() { return _currentActions; }
PathFinder &pathFinder() { return _pathFinder; }
DestStructure &tempDest() { return _tempDest; }
uint16 frameCtr() { return _frameCtr; }
void setFrameCtr(uint16 value) { _frameCtr = value; }
void decrFrameCtr() { if (_frameCtr > 0) --_frameCtr; }
uint8 actionCtr() {
assert(_data);
return _data->actionCtr;
}
void setActionCtr(uint8 v) {
assert(_data);
_data->actionCtr = v;
}
uint8 voiceCtr() { return _voiceCtr; }
void setVoiceCtr(uint8 v) { _voiceCtr = v; }
// Miscellaneous
void converse(uint16 destCharacterId, uint16 messageId, bool standStill);
void converse(uint16 destCharacterId, uint16 messageId) {
converse(destCharacterId, messageId, false);
}
void showMessage(uint16 messageId, uint16 destCharacterId = NOONE_ID);
void scheduleConverse(uint16 destHotspot, uint16 messageId);
void handleTalkDialog();
void saveToStream(Common::WriteStream *stream);
void loadFromStream(Common::ReadStream *stream);
};
class HotspotList: public ManagedList<Hotspot *> {
public:
void saveToStream(WriteStream *stream);
void loadFromStream(ReadStream *stream);
};
} // End of namespace Lure
#endif