/* ScummVM - Scumm Interpreter * Copyright (C) 2005-2006 The ScummVM project * * 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 { public: static int findIntersectingCharacters(Hotspot &h, uint16 *charList); static bool checkForIntersectingCharacter(Hotspot &h); static void 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 standardAnimHandler(Hotspot &h); static void standardCharacterAnimHandler(Hotspot &h); static void roomExitAnimHandler(Hotspot &h); static void playerAnimHandler(Hotspot &h); static void skorlAnimHandler(Hotspot &h); static void droppingTorchAnimHandler(Hotspot &h); static void fireAnimHandler(Hotspot &h); static void talkAnimHandler(Hotspot &h); static void headAnimationHandler(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; public: CurrentActionEntry(CurrentAction newAction, uint16 roomNum) { _action = newAction; _supportData = NULL; _roomNumber = roomNum; } CurrentActionEntry(CurrentAction newAction, CharacterScheduleEntry *data, uint16 roomNum) { _action = newAction; _supportData = data; _roomNumber = roomNum; } 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) { _supportData = newRec; } }; class CurrentActionStack { private: ManagedList _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(); void addBack(CurrentAction newAction, uint16 roomNum) { _actions.push_back(new CurrentActionEntry(newAction, roomNum)); } void addBack(CurrentAction newAction, CharacterScheduleEntry *rec, uint16 roomNum) { _actions.push_back(new CurrentActionEntry(newAction, rec, roomNum)); } void addFront(CurrentAction newAction, uint16 roomNum) { _actions.push_front(new CurrentActionEntry(newAction, roomNum)); } void addFront(CurrentAction newAction, CharacterScheduleEntry *rec, uint16 roomNum) { _actions.push_front(new CurrentActionEntry(newAction, rec, roomNum)); } }; 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_OK, PF_DEST_OCCUPIED, PF_NO_PATH, PF_NO_WALK}; class PathFinder { private: Hotspot *_hotspot; ManagedList _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; PathFinderResult _result; 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); bool process(); void list(); void pop() { _list.erase(_list.begin()); } WalkingActionEntry &top() { return **_list.begin(); } bool isEmpty() { return _list.empty(); } int &stepCtr() { return _stepCtr; } PathFinderResult result() { return _result; } }; enum HotspotPrecheckResult {PC_EXECUTE, PC_NOT_IN_ROOM, PC_UNKNOWN, PC_INITIAL, PC_EXCESS}; enum BlockedState {BS_NONE, BS_INITIAL, BS_UNKNOWN}; class Hotspot { private: HotspotData *_data; HotspotAnimData *_anim; public: HandlerMethodPtr _tickHandler; private: Surface *_frames; uint16 _hotspotId; 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 _sequenceOffset; uint16 _tickCtr; uint32 _actions; uint8 _colourOffset; bool _persistant; HotspotOverrideData *_override; bool _skipFlag; CurrentActionStack _currentActions; CharacterScheduleEntry _npcSupportData; PathFinder _pathFinder; uint16 _frameCtr; uint8 _actionCtr; int16 _destX, _destY; uint16 _destHotspotId; uint16 _blockedOffset; uint8 _exitCtr; BlockedState _blockedState; bool _unknownFlag; // Support methods void startTalk(HotspotData *charHotspot); // Action support methods HotspotPrecheckResult actionPrecheck(HotspotData *hotspot); HotspotPrecheckResult actionPrecheck2(HotspotData *hotspot); void actionPrecheck3(HotspotData *hotspot); 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 npcUnknown1(HotspotData *hotspot); void npcExecScript(HotspotData *hotspot); void npcUnknown2(HotspotData *hotspot); void npcSetRandomDest(HotspotData *hotspot); void npcWalkingCheck(HotspotData *hotspot); void npcSetSupportOffset(HotspotData *hotspot); void npcSupportOffsetConditional(HotspotData *hotspot); void npcDispatchAction(HotspotData *hotspot); void npcUnknown3(HotspotData *hotspot); void npcUnknown4(HotspotData *hotspot); void npcStartTalking(HotspotData *hotspot); void npcJumpAddress(HotspotData *hotspot); public: Hotspot(HotspotData *res); Hotspot(Hotspot *character, uint16 objType); ~Hotspot(); void setAnimation(uint16 newAnimId); void setAnimation(HotspotAnimData *newRecord); uint16 hotspotId() { return _hotspotId; } Surface &frames() { return *_frames; } HotspotAnimData &anim() { return *_anim; } HotspotData *resource() { return _data; } uint16 numFrames() { return _numFrames; } uint16 frameNumber() { return _frameNumber; } void setFrameNumber(uint16 v) { _frameNumber = v; } 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; } BlockedState blockedState() { return _blockedState; } bool unknownFlag() { return _unknownFlag; } 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 script() { return _sequenceOffset; } 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; } void setRoomNumber(uint16 roomNum) { _roomNumber = roomNum; if (_data) _data->roomNumber = roomNum; } uint16 nameId(); 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; } void setBlockedState(BlockedState newState) { _blockedState = newState; } void setUnknownFlag(bool value) { _unknownFlag = value; } void setSize(uint16 newWidth, uint16 newHeight); void setScript(uint16 offset) { assert(_data != NULL); _sequenceOffset = offset; _data->sequenceOffset = offset; } void setActions(uint32 newActions) { _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 != NULL); return _data->delayCtr; } void setDelayCtr(uint16 value) { assert(_data != NULL); _data->delayCtr = 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 setRandomDest(); void setOccupied(bool occupiedFlag); bool walkingStep(); void updateMovement(); void updateMovement2(CharacterMode value); void resetPosition(); // Actions void doAction(); void doAction(Action action, HotspotData *hotspot); CurrentActionStack ¤tActions() { return _currentActions; } CharacterScheduleEntry &npcSupportData() { return _npcSupportData; } PathFinder &pathFinder() { return _pathFinder; } uint16 frameCtr() { return _frameCtr; } void setFrameCtr(uint16 value) { _frameCtr = value; } void decrFrameCtr() { if (_frameCtr > 0) --_frameCtr; } uint8 actionCtr() { return _actionCtr; } void setActionCtr(uint8 v) { _actionCtr = v; } }; typedef ManagedList HotspotList; } // End of namespace Lure #endif