mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-30 07:23:05 +00:00
Player now moves out of the way if he's blocking an entrance when an NPC enters. Also changed errors in unimplemented NPC actions to warnings
svn-id: r22731
This commit is contained in:
parent
5d562eb3c5
commit
5fa3985bcb
@ -310,7 +310,7 @@ void Game::handleClick() {
|
||||
if (response != MENUITEM_NONE)
|
||||
handleMenuResponse(response);
|
||||
} else if ((room.cursorState() == CS_SEQUENCE) ||
|
||||
(room.cursorState() == CS_UNKNOWN)) {
|
||||
(room.cursorState() == CS_BUMPED)) {
|
||||
// No action necessary
|
||||
} else {
|
||||
if (mouse.lButton())
|
||||
|
@ -75,6 +75,8 @@ Hotspot::Hotspot(HotspotData *res): _pathFinder(this) {
|
||||
_actionCtr = 0;
|
||||
_blockedOffset = 0;
|
||||
_exitCtr = 0;
|
||||
_blockedState = BS_NONE;
|
||||
_unknownFlag = false;
|
||||
|
||||
if (_data->npcSchedule != 0) {
|
||||
CharacterScheduleEntry *entry = resources.charSchedules().getEntry(_data->npcSchedule);
|
||||
@ -96,6 +98,8 @@ Hotspot::Hotspot(Hotspot *character, uint16 objType): _pathFinder(this) {
|
||||
_destHotspotId = character->hotspotId();
|
||||
_blockedOffset = 0;
|
||||
_exitCtr = 0;
|
||||
_blockedState = BS_NONE;
|
||||
_unknownFlag = false;
|
||||
|
||||
switch (objType) {
|
||||
case VOICE_ANIM_ID:
|
||||
@ -389,6 +393,31 @@ void Hotspot::faceHotspot(HotspotData *hotspot) {
|
||||
}
|
||||
}
|
||||
|
||||
// Sets a character walking to a random destination position
|
||||
|
||||
void Hotspot::setRandomDest() {
|
||||
Resources &res = Resources::getReference();
|
||||
RoomData *roomData = res.getRoom(roomNumber());
|
||||
Common::Rect &rect = roomData->walkBounds;
|
||||
Common::RandomSource _rnd;
|
||||
int tryCtr = 0;
|
||||
int16 xp, yp;
|
||||
|
||||
if (_currentActions.isEmpty())
|
||||
_currentActions.addFront(START_WALKING, roomNumber());
|
||||
else
|
||||
_currentActions.top().setAction(START_WALKING);
|
||||
|
||||
while (tryCtr ++ <= 20) {
|
||||
xp = rect.left + _rnd.getRandomNumber(rect.right - rect.left);
|
||||
yp = rect.left + _rnd.getRandomNumber(rect.right - rect.left);
|
||||
setDestPosition(xp, yp);
|
||||
|
||||
if (!roomData->paths.isOccupied(xp, yp) && !roomData->paths.isOccupied(xp, yp))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Sets or clears the hotspot as occupying an area in its room's pathfinding data
|
||||
|
||||
void Hotspot::setOccupied(bool occupiedFlag) {
|
||||
@ -464,6 +493,30 @@ bool Hotspot::walkingStep() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void Hotspot::updateMovement() {
|
||||
assert(_data != NULL);
|
||||
if (_currentActions.action() == EXEC_HOTSPOT_SCRIPT) {
|
||||
if (_data->coveredFlag) {
|
||||
// Reset position and direction
|
||||
resetPosition();
|
||||
} else {
|
||||
// Make sure the cell occupied by character is covered
|
||||
_data->coveredFlag = true;
|
||||
setOccupied(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hotspot::updateMovement2(CharacterMode value) {
|
||||
setCharacterMode(value);
|
||||
updateMovement();
|
||||
}
|
||||
|
||||
void Hotspot::resetPosition() {
|
||||
setPosition(x() & 0xf8 | 5, y());
|
||||
setDirection(direction());
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
/* Hotspot action handling */
|
||||
/* */
|
||||
@ -1302,7 +1355,7 @@ void Hotspot::npcUnknown2(HotspotData *hotspot) {
|
||||
|
||||
void Hotspot::npcSetRandomDest(HotspotData *hotspot) {
|
||||
endAction();
|
||||
Support::setRandomDest(*this);
|
||||
setRandomDest();
|
||||
}
|
||||
|
||||
void Hotspot::npcWalkingCheck(HotspotData *hotspot) {
|
||||
@ -1373,19 +1426,23 @@ void Hotspot::npcDispatchAction(HotspotData *hotspot) {
|
||||
}
|
||||
|
||||
void Hotspot::npcUnknown3(HotspotData *hotspot) {
|
||||
error("npcUnknown3: Not yet implemented");
|
||||
warning("npcUnknown3: Not yet implemented");
|
||||
endAction();
|
||||
}
|
||||
|
||||
void Hotspot::npcUnknown4(HotspotData *hotspot) {
|
||||
error("npcUnknown4: Not yet implemented");
|
||||
warning("npcUnknown4: Not yet implemented");
|
||||
endAction();
|
||||
}
|
||||
|
||||
void Hotspot::npcStartTalking(HotspotData *hotspot) {
|
||||
error("npcStartTalking: Not yet implemented");
|
||||
warning("npcStartTalking: Not yet implemented");
|
||||
endAction();
|
||||
}
|
||||
|
||||
void Hotspot::npcJumpAddress(HotspotData *hotspot) {
|
||||
error("npcJumpAddress: Not yet implemented");
|
||||
warning("npcJumpAddress: Not yet implemented");
|
||||
endAction();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
@ -1460,7 +1517,7 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) {
|
||||
CurrentActionStack &actions = h.currentActions();
|
||||
uint16 impingingList[MAX_NUM_IMPINGING];
|
||||
int numImpinging;
|
||||
int index;
|
||||
bool bumpedPlayer;
|
||||
|
||||
// TODO: handle talk dialogs countdown if necessary
|
||||
|
||||
@ -1471,26 +1528,74 @@ void HotspotTickHandlers::standardCharacterAnimHandler(Hotspot &h) {
|
||||
}
|
||||
|
||||
numImpinging = Support::findIntersectingCharacters(h, impingingList);
|
||||
bumpedPlayer = (numImpinging == 0) ? false :
|
||||
Support::isCharacterInList(impingingList, numImpinging, PLAYER_ID);
|
||||
|
||||
// Check for character having just changed room
|
||||
if (h.skipFlag()) {
|
||||
if (numImpinging > 0) {
|
||||
index = 0;
|
||||
while ((index < numImpinging) && (impingingList[index] != PLAYER_ID))
|
||||
++index;
|
||||
|
||||
if (index != numImpinging) {
|
||||
// Character has bumped into player
|
||||
// TODO: Figure out handling code
|
||||
error("Unimplemented - character bumping into player");
|
||||
// Scan to check if the character has bumped into player
|
||||
Hotspot *player = res.getActiveHotspot(PLAYER_ID);
|
||||
|
||||
if (bumpedPlayer && (player->characterMode() == CHARMODE_IDLE)) {
|
||||
// Signal the player to move out of the way automatically
|
||||
player->setBlockedState(BS_INITIAL);
|
||||
player->setDestHotspot(0);
|
||||
|
||||
Room::getReference().setCursorState(CS_BUMPED);
|
||||
player->setRandomDest();
|
||||
} else {
|
||||
// Signal the character to pause briefly to allow bumped
|
||||
// character time to start moving out of the way
|
||||
h.setDelayCtr(10);
|
||||
h.setCharacterMode(CHARMODE_PAUSED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
h.setSkipFlag(false);
|
||||
}
|
||||
|
||||
// TODO: Handling of any set Tick Script Offset, as well as certain other
|
||||
// as of yet unknown hotspot flags
|
||||
|
||||
if (h.characterMode() != CHARMODE_NONE) {
|
||||
if (h.characterMode() == CHARMODE_6) {
|
||||
// TODO: Figure out what mode 6 is
|
||||
h.updateMovement();
|
||||
if (bumpedPlayer) return;
|
||||
|
||||
} else {
|
||||
// All other character modes
|
||||
if (h.delayCtr() > 0) {
|
||||
// There is some countdown left to do
|
||||
bool decrementFlag = true; //TODO: = HS[50h] == 0
|
||||
|
||||
if (!decrementFlag) {
|
||||
HotspotData *hotspot = res.getHotspot(0); // TODO: HS[50h]
|
||||
decrementFlag = (hotspot->roomNumber != h.roomNumber()) ? false :
|
||||
Support::charactersIntersecting(hotspot, h.resource());
|
||||
}
|
||||
|
||||
if (decrementFlag) {
|
||||
h.setDelayCtr(h.delayCtr() - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: HS[50h]=0
|
||||
CharacterMode currentMode = h.characterMode();
|
||||
h.setCharacterMode(CHARMODE_NONE);
|
||||
h.pathFinder().clear();
|
||||
|
||||
if ((currentMode == CHARMODE_4) || (currentMode == CHARMODE_7)) {
|
||||
// TODO: HS[33h]=0
|
||||
Dialog::showMessage(1, h.hotspotId());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentAction action = actions.action();
|
||||
|
||||
switch (action) {
|
||||
@ -1639,6 +1744,7 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) {
|
||||
case NO_ACTION:
|
||||
// Make sure there is no longer any destination
|
||||
h.setDestHotspot(0);
|
||||
h.updateMovement2(CHARMODE_IDLE);
|
||||
break;
|
||||
|
||||
case DISPATCH_ACTION:
|
||||
@ -1678,9 +1784,17 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) {
|
||||
// Deliberate fall through to processing walking path
|
||||
|
||||
case PROCESSING_PATH:
|
||||
h.setCharacterMode(CHARMODE_NONE);
|
||||
if (!pathFinder.process()) break;
|
||||
|
||||
// Pathfinding is now complete
|
||||
/*
|
||||
if ((pathFinder.result() != PF_OK) && (h.unknownFlag() ||
|
||||
(pathFinder.result() != PF_DEST_OCCUPIED))) {
|
||||
// TODO: occupiedFlag
|
||||
|
||||
}
|
||||
*/
|
||||
actions.pop();
|
||||
|
||||
if (pathFinder.isEmpty()) {
|
||||
@ -1709,6 +1823,9 @@ void HotspotTickHandlers::playerAnimHandler(Hotspot &h) {
|
||||
|
||||
if (h.walkingStep()) {
|
||||
// Walking done
|
||||
Room &room = Room::getReference();
|
||||
if (room.cursorState() == CS_BUMPED)
|
||||
room.setCursorState(CS_NONE);
|
||||
h.currentActions().pop();
|
||||
}
|
||||
|
||||
@ -2003,7 +2120,7 @@ void HotspotTickHandlers::npcRoomChange(Hotspot &h) {
|
||||
}
|
||||
|
||||
if (numCharacters >= 4) {
|
||||
error("npcChangeRoom - too many characters - yet to be tested");
|
||||
warning("XYZZY npcChangeRoom - too many characters - yet to be tested");
|
||||
uint16 dataId = res.getCharOffset(0);
|
||||
CharacterScheduleEntry *entry = res.charSchedules().getEntry(dataId);
|
||||
h.currentActions().addFront(DISPATCH_ACTION, entry, h.roomNumber());
|
||||
@ -2062,14 +2179,18 @@ PathFinder::PathFinder(Hotspot *h) {
|
||||
_stepCtr = 0;
|
||||
}
|
||||
|
||||
void PathFinder::reset(RoomPathsData &src) {
|
||||
void PathFinder::clear() {
|
||||
_stepCtr = 0;
|
||||
_list.clear();
|
||||
src.decompress(_layer, _hotspot->widthCopy());
|
||||
_inProgress = false;
|
||||
_countdownCtr = PATHFIND_COUNTDOWN;
|
||||
}
|
||||
|
||||
void PathFinder::reset(RoomPathsData &src) {
|
||||
clear();
|
||||
src.decompress(_layer, _hotspot->widthCopy());
|
||||
}
|
||||
|
||||
// Does the next stage of processing to figure out a path to take to a given
|
||||
// destination. Returns true if the path finding has been completed
|
||||
|
||||
@ -2439,6 +2560,7 @@ int Support::findIntersectingCharacters(Hotspot &h, uint16 *charList) {
|
||||
int numImpinging = 0;
|
||||
Resources &res = Resources::getReference();
|
||||
Rect r;
|
||||
uint16 hotspotY;
|
||||
|
||||
r.left = h.x();
|
||||
r.right = h.x() + h.widthCopy();
|
||||
@ -2456,12 +2578,13 @@ int Support::findIntersectingCharacters(Hotspot &h, uint16 *charList) {
|
||||
hotspot.skipFlag()) continue;
|
||||
// TODO: See why si+ANIM_HOTSPOT_OFFSET compared aganst di+ANIM_VOICE_CTR
|
||||
|
||||
hotspotY = hotspot.y() + hotspot.heightCopy();
|
||||
|
||||
if ((hotspot.x() > r.right) || (hotspot.x() + hotspot.widthCopy() <= r.left) ||
|
||||
(hotspot.y() + hotspot.heightCopy() + hotspot.charRectY() > r.bottom) ||
|
||||
(hotspot.y() + hotspot.heightCopy() - hotspot.charRectY()
|
||||
- hotspot.yCorrection() <= r.top))
|
||||
(hotspotY + hotspot.charRectY() < r.top) ||
|
||||
(hotspotY - hotspot.charRectY() - hotspot.yCorrection() >= r.bottom))
|
||||
continue;
|
||||
|
||||
|
||||
// Add hotspot Id to list
|
||||
if (numImpinging == MAX_NUM_IMPINGING)
|
||||
error("Exceeded maximum allowable number of impinging characters");
|
||||
@ -2534,26 +2657,6 @@ void Support::characterChangeRoom(Hotspot &h, uint16 roomNumber,
|
||||
}
|
||||
}
|
||||
|
||||
void Support::setRandomDest(Hotspot &h) {
|
||||
Resources &res = Resources::getReference();
|
||||
RoomData *roomData = res.getRoom(h.roomNumber());
|
||||
Common::Rect &rect = roomData->walkBounds;
|
||||
Common::RandomSource _rnd;
|
||||
int tryCtr = 0;
|
||||
int16 xp, yp;
|
||||
|
||||
h.currentActions().top().setAction(DISPATCH_ACTION);
|
||||
|
||||
while (tryCtr ++ <= 20) {
|
||||
xp = rect.left + _rnd.getRandomNumber(rect.right - rect.left);
|
||||
yp = rect.left + _rnd.getRandomNumber(rect.right - rect.left);
|
||||
h.setDestPosition(xp, yp);
|
||||
|
||||
if (!roomData->paths.isOccupied(xp, yp) && !roomData->paths.isOccupied(xp, yp))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool Support::charactersIntersecting(HotspotData *hotspot1, HotspotData *hotspot2) {
|
||||
return !((hotspot1->startX + hotspot1->widthCopy + 4 < hotspot2->startX) ||
|
||||
(hotspot2->startX + hotspot2->widthCopy + 4 < hotspot1->startX) ||
|
||||
@ -2563,4 +2666,10 @@ bool Support::charactersIntersecting(HotspotData *hotspot1, HotspotData *hotspot
|
||||
hotspot1->startY + hotspot1->heightCopy - hotspot1->yCorrection - 2));
|
||||
}
|
||||
|
||||
bool Support::isCharacterInList(uint16 *lst, int numEntries, uint16 charId) {
|
||||
while (numEntries-- > 0)
|
||||
if (*lst++ == charId) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // end of namespace Lure
|
||||
|
@ -41,8 +41,8 @@ public:
|
||||
static void checkRoomChange(Hotspot &h);
|
||||
static void characterChangeRoom(Hotspot &h, uint16 roomNumber,
|
||||
int16 newX, int16 newY, Direction dir);
|
||||
static void setRandomDest(Hotspot &h);
|
||||
static bool charactersIntersecting(HotspotData *hotspot1, HotspotData *hotspot2);
|
||||
static bool isCharacterInList(uint16 *lst, int numEntries, uint16 charId);
|
||||
};
|
||||
|
||||
typedef void(*HandlerMethodPtr)(Hotspot &h);
|
||||
@ -172,9 +172,9 @@ private:
|
||||
void addBack(Direction dir, int steps) {
|
||||
_list.push_back(new WalkingActionEntry(dir, steps));
|
||||
}
|
||||
void clear() { _list.clear(); }
|
||||
public:
|
||||
PathFinder(Hotspot *h);
|
||||
void clear();
|
||||
void reset(RoomPathsData &src);
|
||||
bool process();
|
||||
void list();
|
||||
@ -183,10 +183,13 @@ public:
|
||||
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;
|
||||
@ -224,6 +227,8 @@ private:
|
||||
uint16 _destHotspotId;
|
||||
uint16 _blockedOffset;
|
||||
uint8 _exitCtr;
|
||||
BlockedState _blockedState;
|
||||
bool _unknownFlag;
|
||||
|
||||
// Support methods
|
||||
void startTalk(HotspotData *charHotspot);
|
||||
@ -234,6 +239,7 @@ private:
|
||||
void actionPrecheck3(HotspotData *hotspot);
|
||||
bool characterWalkingCheck(HotspotData *hotspot);
|
||||
bool doorCloseCheck(uint16 doorId);
|
||||
void resetDirection();
|
||||
|
||||
// Action set
|
||||
void doNothing(HotspotData *hotspot);
|
||||
@ -295,6 +301,8 @@ public:
|
||||
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; }
|
||||
@ -320,14 +328,33 @@ public:
|
||||
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();
|
||||
@ -340,8 +367,12 @@ public:
|
||||
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();
|
||||
|
@ -291,6 +291,11 @@ HotspotData::HotspotData(HotspotResource *rec) {
|
||||
tickTimeout = READ_LE_UINT16(&rec->tickTimeout);
|
||||
tickSequenceOffset = READ_LE_UINT16(&rec->tickSequenceOffset);
|
||||
npcSchedule = READ_LE_UINT16(&rec->npcSchedule);
|
||||
|
||||
// Initialise dynamic fields
|
||||
delayCtr = 0;
|
||||
characterMode = CHARMODE_NONE;
|
||||
coveredFlag = false;
|
||||
}
|
||||
|
||||
// Hotspot override data
|
||||
|
@ -373,6 +373,9 @@ public:
|
||||
HotspotActionList *getActions(uint16 recordId);
|
||||
};
|
||||
|
||||
enum CharacterMode {CHARMODE_NONE, CHARMODE_1, CHARMODE_IDLE, CHARMODE_PAUSED,
|
||||
CHARMODE_4, CHARMODE_5, CHARMODE_6, CHARMODE_7};
|
||||
|
||||
class HotspotData {
|
||||
public:
|
||||
HotspotData(HotspotResource *rec);
|
||||
@ -405,7 +408,11 @@ public:
|
||||
uint16 tickProcOffset;
|
||||
uint16 tickTimeout;
|
||||
uint16 tickSequenceOffset;
|
||||
uint16 npcSchedule;
|
||||
uint16 npcSchedule;
|
||||
|
||||
uint16 delayCtr;
|
||||
CharacterMode characterMode;
|
||||
bool coveredFlag;
|
||||
|
||||
void enable() { flags |= 0x80; }
|
||||
void disable() { flags &= 0x7F; }
|
||||
|
@ -535,7 +535,7 @@ void Room::checkCursor() {
|
||||
newCursor = CURSOR_TALK;
|
||||
} else if (res.getTalkData()) {
|
||||
newCursor = CURSOR_ARROW;
|
||||
} else if (_cursorState == CS_UNKNOWN) {
|
||||
} else if (_cursorState == CS_BUMPED) {
|
||||
newCursor = CURSOR_CAMERA;
|
||||
} else if (_cursorState == CS_TALKING) {
|
||||
newCursor = CURSOR_ARROW;
|
||||
@ -547,7 +547,7 @@ void Room::checkCursor() {
|
||||
newCursor = CURSOR_MENUBAR;
|
||||
} else if (_cursorState != CS_NONE) {
|
||||
// Currently in a special mode
|
||||
// checkRoomHotspots();
|
||||
checkRoomHotspots();
|
||||
newCursor = CURSOR_CAMERA;
|
||||
} else {
|
||||
// Check for a highlighted hotspot
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum CursorState {CS_NONE, CS_ACTION, CS_SEQUENCE, CS_TALKING, CS_UNKNOWN};
|
||||
enum CursorState {CS_NONE, CS_ACTION, CS_SEQUENCE, CS_TALKING, CS_BUMPED};
|
||||
|
||||
class Room {
|
||||
private:
|
||||
|
Loading…
x
Reference in New Issue
Block a user