aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2007-02-22 06:29:09 +0000
committerPaul Gilbert2007-02-22 06:29:09 +0000
commit7ac767a2bae0bcc97bd46a7a29ced6b21dbc12a3 (patch)
tree52916c859b0af3f822befcae83da5a26f1d6b7c1
parent69255e9c14fceb7a6584a8bf52bfa9ab009dea16 (diff)
downloadscummvm-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.cpp80
-rw-r--r--engines/lure/luredefs.h2
-rw-r--r--engines/lure/res.cpp27
-rw-r--r--engines/lure/res.h2
-rw-r--r--engines/lure/res_struct.cpp54
-rw-r--r--engines/lure/res_struct.h39
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);