diff options
author | Paul Gilbert | 2007-02-22 06:29:09 +0000 |
---|---|---|
committer | Paul Gilbert | 2007-02-22 06:29:09 +0000 |
commit | 7ac767a2bae0bcc97bd46a7a29ced6b21dbc12a3 (patch) | |
tree | 52916c859b0af3f822befcae83da5a26f1d6b7c1 | |
parent | 69255e9c14fceb7a6584a8bf52bfa9ab009dea16 (diff) | |
download | scummvm-rg350-7ac767a2bae0bcc97bd46a7a29ced6b21dbc12a3.tar.gz scummvm-rg350-7ac767a2bae0bcc97bd46a7a29ced6b21dbc12a3.tar.bz2 scummvm-rg350-7ac767a2bae0bcc97bd46a7a29ced6b21dbc12a3.zip |
Added proper support for the random actions your sidekick can do in each room
svn-id: r25780
-rw-r--r-- | engines/lure/hotspots.cpp | 80 | ||||
-rw-r--r-- | engines/lure/luredefs.h | 2 | ||||
-rw-r--r-- | engines/lure/res.cpp | 27 | ||||
-rw-r--r-- | engines/lure/res.h | 2 | ||||
-rw-r--r-- | engines/lure/res_struct.cpp | 54 | ||||
-rw-r--r-- | engines/lure/res_struct.h | 39 |
6 files changed, 193 insertions, 11 deletions
diff --git a/engines/lure/hotspots.cpp b/engines/lure/hotspots.cpp index e7c1b5020e..25684e2e4a 100644 --- a/engines/lure/hotspots.cpp +++ b/engines/lure/hotspots.cpp @@ -2581,17 +2581,13 @@ RoomTranslationRecord roomTranslations[] = { {0, 0}}; void HotspotTickHandlers::followerAnimHandler(Hotspot &h) { + static int countdownCtr = 0; Resources &res = Resources::getReference(); ValueTableData &fields = res.fieldList(); Hotspot *player = res.getActiveHotspot(PLAYER_ID); - if ((fields.getField(37) == 0) && h.currentActions().isEmpty()) { - - if (h.roomNumber() == player->roomNumber()) { - // In same room as player - set a random destination - h.setRandomDest(); - - } else { + if ((fields.getField(37) == 0) && (h.currentActions().size() <= 1)) { + if (h.roomNumber() != player->roomNumber()) { // Character in different room than player if (h.hotspotId() == GOEWIN_ID) h.currentActions().addFront(DISPATCH_ACTION, player->roomNumber()); @@ -2606,12 +2602,78 @@ void HotspotTickHandlers::followerAnimHandler(Hotspot &h) { } } - if (h.characterMode() == CHARMODE_IDLE) { - // TODO: Checks on ds:[4f8ah] to figure out + // If some action is in progress, do standard handling + if (h.characterMode() != CHARMODE_IDLE) { + standardCharacterAnimHandler(h); + return; + } + + if (fields.wanderingCharsLoaded()) { + // Start Ratpouch to sewer exit to meet player + fields.wanderingCharsLoaded() = false; + h.setBlockedFlag(false); + CharacterScheduleEntry *newEntry = res.charSchedules().getEntry(RETURN_SUPPORT_ID); + h.currentActions().addFront(DISPATCH_ACTION, newEntry, 7); + h.setActionCtr(0); + + standardCharacterAnimHandler(h); + return; + } + + // Handle any pause countdown + if (countdownCtr > 0) + { + --countdownCtr; standardCharacterAnimHandler(h); return; } + // Handle selecting a random action for the character to do + RandomActionSet *set = res.randomActions().getRoom(h.roomNumber()); + if (!set) return; + Common::RandomSource rnd; + RandomActionType actionType; + uint16 scheduleId; + int actionIndex = rnd.getRandomNumber(set->numActions() - 1); + set->getEntry(actionIndex, actionType, scheduleId); + + if (actionType == REPEAT_ONCE_DONE) + { + // Repeat once random action that's already done, so don't repeat it + standardCharacterAnimHandler(h); + return; + } + + // For repeat once actions, make sure the character is in the same room as the player + if (actionType == REPEAT_ONCE) + { + if (player->roomNumber() != h.roomNumber()) + { + // Not in the same room, so don't do the action + standardCharacterAnimHandler(h); + return; + } + + // Flag the action as having been done, so it won't be repeated + set->setDone(actionIndex); + } + + if (scheduleId == 0) + { + // No special schedule to perform, so simply set a random action + h.setRandomDest(); + } + else + { + // Prepare the follower to standard the specified schedule + CharacterScheduleEntry *newEntry = res.charSchedules().getEntry(scheduleId); + assert(newEntry); + h.currentActions().addFront(DISPATCH_ACTION, newEntry, h.roomNumber()); + + // Set a random delay before beginning the action + countdownCtr = rnd.getRandomNumber(32); + } + standardCharacterAnimHandler(h); } diff --git a/engines/lure/luredefs.h b/engines/lure/luredefs.h index e3b5f867fc..918e679dcb 100644 --- a/engines/lure/luredefs.h +++ b/engines/lure/luredefs.h @@ -31,7 +31,7 @@ namespace Lure { #define SUPPORT_FILENAME "lure.dat" #define LURE_DAT_MAJOR 1 -#define LURE_DAT_MINOR 13 +#define LURE_DAT_MINOR 14 #define LURE_DEBUG 1 diff --git a/engines/lure/res.cpp b/engines/lure/res.cpp index 2eb6aaee8f..6277dab4c9 100644 --- a/engines/lure/res.cpp +++ b/engines/lure/res.cpp @@ -55,6 +55,7 @@ void Resources::freeData() { _exitJoins.clear(); _delayList.clear(); _charSchedules.clear(); + _randomActions.clear(); _indexedRoomExitHospots.clear(); _pausedList.clear(); _stringList.clear(); @@ -283,6 +284,15 @@ void Resources::reloadData() { for (ctr = 0; ctr < numCharOffsets; ++ctr, ++offset) _charOffsets[ctr] = READ_LE_UINT16(offset); + // Next load up the list of random actions your follower can do in each room + + ++offset; + while (READ_LE_UINT16(offset) != 0xffff) + { + RandomActionSet *actionSet = new RandomActionSet(offset); + _randomActions.push_back(actionSet); + } + // Loop through loading the schedules ctr = 0; while ((startOffset = READ_LE_UINT16(++offset)) != 0xffff) { @@ -515,8 +525,25 @@ Hotspot *Resources::activateHotspot(uint16 hotspotId) { if (loadFlag) { Hotspot *hotspot = addHotspot(hotspotId); assert(hotspot); + + // Special post-load handling if (res->loadOffset == 0x7167) hotspot->setPersistant(true); if (res->loadOffset == 0x8617) hotspot->handleTalkDialog(); + + // TODO: Figure out why there's a room set in the animation decode for a range of characters, + // particularly since it doesn't seem to match what happens in-game + /* + if ((hotspot->hotspotId() >= RATPOUCH_ID) && + (hotspot->hotspotId() < FIRST_NONCHARACTER_ID) && + (hotspot->roomNumber() < 42)) + { + // Start wandering characters off in room 24 + hotspot->setRoomNumber(24); + hotspot->setPosition(64, 116); + _fieldList.wanderingCharsLoaded() = true; + } + */ + return hotspot; } } diff --git a/engines/lure/res.h b/engines/lure/res.h index 133fec120a..e42c24ca71 100644 --- a/engines/lure/res.h +++ b/engines/lure/res.h @@ -68,6 +68,7 @@ private: MemoryBlock *_talkDialogData; RoomExitCoordinatesList _coordinateList; CharacterScheduleList _charSchedules; + RandomActionList _randomActions; RoomExitIndexedHotspotList _indexedRoomExitHospots; PausedCharacterList _pausedList; StringList _stringList; @@ -122,6 +123,7 @@ public: MemoryBlock &getTalkDialogData() { return *_talkDialogData; } RoomExitCoordinatesList &coordinateList() { return _coordinateList; } CharacterScheduleList &charSchedules() { return _charSchedules; } + RandomActionList &randomActions() { return _randomActions; } RoomExitIndexedHotspotList &exitHotspots() { return _indexedRoomExitHospots; } PausedCharacterList &pausedList() { return _pausedList; } StringList &stringList() { return _stringList; } diff --git a/engines/lure/res_struct.cpp b/engines/lure/res_struct.cpp index 39d110f997..c1ff323f20 100644 --- a/engines/lure/res_struct.cpp +++ b/engines/lure/res_struct.cpp @@ -34,7 +34,7 @@ const Action sortedActions[] = {ASK, BRIBE, BUY, CLOSE, DRINK, EXAMINE, GET, GIV int actionNumParams[NPC_JUMP_ADDRESS+1] = {0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 0, 1, - 0, 1, 1, 1, 1, 0, 0, 2, 0, 1, 0, 0, 1, 1, 2, 2, 5, 2, 2, 1}; + 0, 1, 1, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1, 1, 2, 2, 5, 2, 2, 1}; // Room data holding class @@ -774,6 +774,55 @@ uint16 CharacterScheduleSet::getId(CharacterScheduleEntry *rec) { return result; } +// This classes is used to store a list of random action sets - one set per room + +RandomActionSet::RandomActionSet(uint16 *&offset) +{ + _roomNumber = READ_LE_UINT16(offset++); + uint16 actionDetails = READ_LE_UINT16(offset++); + _numActions = (actionDetails & 0xff); + assert(_numActions <= 8); + _types = new RandomActionType[_numActions]; + _ids = new uint16[_numActions]; + + for (int actionIndex = 0; actionIndex < _numActions; ++actionIndex) + { + _ids[actionIndex] = READ_LE_UINT16(offset++); + _types[actionIndex] = (actionDetails & (0x100 << actionIndex)) != 0 ? REPEATABLE : REPEAT_ONCE; + } +} + +RandomActionSet::~RandomActionSet() +{ + delete _types; + delete _ids; +} + +RandomActionSet *RandomActionList::getRoom(uint16 roomNumber) +{ + iterator i; + for (i = begin(); i != end(); ++i) + { + RandomActionSet *v = *i; + if (v->roomNumber() == roomNumber) + return v; + } + return NULL; +} + +void RandomActionList::saveToStream(Common::WriteStream *stream) +{ + +} + +void RandomActionList::loadFromStream(Common::ReadStream *stream) +{ + +} + + + + // This class handles an indexed hotspot entry - which is used by the NPC code to // determine whether exiting a room to another given room has an exit hotspot or not @@ -950,6 +999,7 @@ ValueTableData::ValueTableData() { _playerPendingPos.isSet = false; _flags = GAMEFLAG_4 | GAMEFLAG_1; _hdrFlagMask = 1; + _wanderingCharsLoaded = false; for (uint16 index = 0; index < NUM_VALUE_FIELDS; ++index) _fieldList[index] = 0; @@ -996,6 +1046,7 @@ void ValueTableData::saveToStream(Common::WriteStream *stream) stream->writeSint16LE(_playerPendingPos.pos.y); stream->writeByte(_flags); stream->writeByte(_hdrFlagMask); + stream->writeByte(_wanderingCharsLoaded); // Write out the special fields for (int index = 0; index < NUM_VALUE_FIELDS; ++index) @@ -1014,6 +1065,7 @@ void ValueTableData::loadFromStream(Common::ReadStream *stream) _playerPendingPos.pos.y = stream->readSint16LE(); _flags = stream->readByte(); _hdrFlagMask = stream->readByte(); + _wanderingCharsLoaded = stream->readByte() != 0; // Read in the field list for (int index = 0; index < NUM_VALUE_FIELDS; ++index) diff --git a/engines/lure/res_struct.h b/engines/lure/res_struct.h index c2d59eecc6..eb82a24a54 100644 --- a/engines/lure/res_struct.h +++ b/engines/lure/res_struct.h @@ -633,6 +633,43 @@ public: typedef List<uint16> CharacterScheduleOffsets; +// The follow classes are used to store the NPC schedule Ids for the random actions a follower can do in each room + +enum RandomActionType {REPEATABLE, REPEAT_ONCE, REPEAT_ONCE_DONE}; + +class RandomActionSet { +private: + uint16 _roomNumber; + int _numActions; + RandomActionType *_types; + uint16 *_ids; +public: + RandomActionSet(uint16 *&offset); + ~RandomActionSet(); + + uint16 roomNumber() { return _roomNumber; } + int numActions() { return _numActions; } + void getEntry(int index, RandomActionType &actionType, uint16 &id) + { + assert((index >= 0) && (index < _numActions)); + actionType = _types[index]; + id = _ids[index]; + } + void setDone(int index) + { + assert((index >= 0) && (index < _numActions)); + assert(_types[index] == REPEAT_ONCE); + _types[index] = REPEAT_ONCE_DONE; + } +}; + +class RandomActionList: public ManagedList<RandomActionSet *> { +public: + RandomActionSet *getRoom(uint16 roomNumber); + void saveToStream(Common::WriteStream *stream); + void loadFromStream(Common::ReadStream *stream); +}; + class PausedCharacter { public: PausedCharacter(uint16 SrcCharId, uint16 DestCharId); @@ -730,6 +767,7 @@ private: PlayerPendingPosition _playerPendingPos; uint8 _flags; uint8 _hdrFlagMask; + bool _wanderingCharsLoaded; uint16 _fieldList[NUM_VALUE_FIELDS]; bool isKnownField(uint16 fieldIndex); @@ -747,6 +785,7 @@ public: uint8 &hdrFlagMask() { return _hdrFlagMask; } PlayerNewPosition &playerNewPos() { return _playerNewPos; } PlayerPendingPosition &playerPendingPos() { return _playerPendingPos; } + bool &wanderingCharsLoaded() { return _wanderingCharsLoaded; } void saveToStream(Common::WriteStream *stream); void loadFromStream(Common::ReadStream *stream); |