From c6b6a2e12587b15a95d371acf9f18586ff392736 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sat, 8 Jul 2006 08:36:32 +0000 Subject: Added new hotspot runtime fields, a list for handling the details of paused characters (who have bumped into each other), and loading of newly added default character states from lure.dat svn-id: r23410 --- engines/lure/res_struct.cpp | 168 +++++++++++++++++++++++++++++++++++++++++--- engines/lure/res_struct.h | 79 ++++++++++++++++++--- 2 files changed, 226 insertions(+), 21 deletions(-) diff --git a/engines/lure/res_struct.cpp b/engines/lure/res_struct.cpp index 7ecee018c1..dfa478ffce 100644 --- a/engines/lure/res_struct.cpp +++ b/engines/lure/res_struct.cpp @@ -128,6 +128,7 @@ bool RoomPathsData::isOccupied(int x, int y) { void RoomPathsData::setOccupied(int x, int y, int width) { if ((x < 0) || (y < 0) || (x >= ROOM_PATHS_WIDTH) || (y >= ROOM_PATHS_HEIGHT)) return; + byte *p = &_data[y * 5 + (x / 8)]; byte bitMask = 0x80 >> (x % 8); @@ -144,6 +145,7 @@ void RoomPathsData::setOccupied(int x, int y, int width) { void RoomPathsData::clearOccupied(int x, int y, int width) { if ((x < 0) || (y < 0) || (x >= ROOM_PATHS_WIDTH) || (y >= ROOM_PATHS_HEIGHT)) return; + byte *p = &_data[y * 5 + (x / 8)]; byte bitMask = 0x80 >> (x % 8); @@ -291,11 +293,20 @@ HotspotData::HotspotData(HotspotResource *rec) { tickTimeout = READ_LE_UINT16(&rec->tickTimeout); tickSequenceOffset = READ_LE_UINT16(&rec->tickSequenceOffset); npcSchedule = READ_LE_UINT16(&rec->npcSchedule); + characterMode = (CharacterMode) READ_LE_UINT16(&rec->characterMode); + delayCtr = READ_LE_UINT16(&rec->delayCtr); - // Initialise dynamic fields - delayCtr = 0; - characterMode = CHARMODE_NONE; + // Initialise runtime fields + actionCtr = 0; + blockedState = BS_NONE; coveredFlag = false; + talkMessageId = 0; + talkDestHotspot = 0; + talkCountdown = 0; + pauseCtr = 0; + useHotspotId = 0; + v2b = 0; + v50 = 0; } // Hotspot override data @@ -470,16 +481,18 @@ RoomExitCoordinateData &RoomExitCoordinates::getData(uint16 destRoomNumber) { // The following classes hold any sequence offsets that are being delayed -SequenceDelayData::SequenceDelayData(uint16 delay, uint16 seqOffset) { +SequenceDelayData::SequenceDelayData(uint16 delay, uint16 seqOffset, bool canClearFlag) { OSystem &system = System::getReference(); - _timeoutCtr = system.getMillis() + delay; - _sequenceOffset = seqOffset; + // The delay is in number of ticks (1/18th of a second) - convert to milliseconds + timeoutCtr = system.getMillis() + (delay * 1000 / 18); + sequenceOffset = seqOffset; + canClear = canClearFlag; } -void SequenceDelayList::addSequence(uint16 delay, uint16 seqOffset) { - SequenceDelayData *entry = new SequenceDelayData(delay, seqOffset); - push_back(entry); +void SequenceDelayList::add(uint16 delay, uint16 seqOffset, bool canClear) { + SequenceDelayData *entry = new SequenceDelayData(delay, seqOffset, canClear); + push_front(entry); } void SequenceDelayList::tick() { @@ -488,8 +501,9 @@ void SequenceDelayList::tick() { for (i = begin(); i != end(); i++) { SequenceDelayData *entry = *i; - if (entry->_timeoutCtr >= currTime) { - uint16 seqOffset = entry->_sequenceOffset; + if (currTime >= entry->timeoutCtr) { + // Timeout reached - delete entry from list and execute the sequence + uint16 seqOffset = entry->sequenceOffset; erase(i); Script::execute(seqOffset); return; @@ -497,6 +511,18 @@ void SequenceDelayList::tick() { } } +void SequenceDelayList::clear() { + SequenceDelayList::iterator i = begin(); + + while (i != end()) { + SequenceDelayData *entry = *i; + if (entry->canClear) + i = erase(i); + else + ++i; + } +} + // The following classes hold the NPC schedule classes CharacterScheduleEntry::CharacterScheduleEntry(Action theAction, ...) { @@ -652,6 +678,121 @@ uint16 RoomExitIndexedHotspotList::getHotspot(uint16 roomNumber, uint8 hotspotIn return 0xffff; } +// Paused character list methods + +PausedCharacter::PausedCharacter(uint16 SrcCharId, uint16 DestCharId) { + srcCharId = SrcCharId; + destCharId = DestCharId; + counter = IDLE_COUNTDOWN_SIZE; + charHotspot = Resources::getReference().getHotspot(SrcCharId); + assert(charHotspot); +} + +void PausedCharacterList::reset(uint16 hotspotId) { + iterator i; + for (i = begin(); i != end(); ++i) { + PausedCharacter *rec = *i; + + if (rec->srcCharId == hotspotId) { + rec->counter = 1; + if (rec->destCharId < START_EXIT_ID) + rec->charHotspot->pauseCtr = 1; + } + } +} + +void PausedCharacterList::countdown() { + iterator i = begin(); + + while (i != end()) { + PausedCharacter *rec = *i; + --rec->counter; + + // Handle reflecting counter to hotspot + if (rec->destCharId < START_EXIT_ID) + rec->charHotspot->pauseCtr = rec->counter + 1; + + // If counter has reached zero, remove entry from list + if (rec->counter == 0) + i = erase(i); + else + ++i; + } +} + +void PausedCharacterList::scan(Hotspot &h) { + iterator i; + + if (h.blockedState() != BS_NONE) { + + for (i = begin(); i != end(); ++i) { + PausedCharacter *rec = *i; + + if (rec->srcCharId == h.hotspotId()) { + rec->counter = IDLE_COUNTDOWN_SIZE; + + if (rec->destCharId < START_EXIT_ID) + rec->charHotspot->pauseCtr = IDLE_COUNTDOWN_SIZE; + } + } + } +} + +int PausedCharacterList::check(uint16 charId, int numImpinging, uint16 *impingingList) { + Resources &res = Resources::getReference(); + PausedCharacterList::iterator i; + int result = 0; + Hotspot *charHotspot = res.getActiveHotspot(charId); + assert(charHotspot); + + for (int index = 0; index < numImpinging; ++index) { + Hotspot *hotspot = res.getActiveHotspot(impingingList[index]); + if ((!hotspot) || (!hotspot->currentActions().isEmpty() && + (hotspot->currentActions().top().action() == EXEC_HOTSPOT_SCRIPT))) + // Entry is skipped if hotspot not present or is executing hotspot script + continue; + + // Scan through the pause list to see if there's a record for the + // calling character and the impinging list entry + for (i = res.pausedList().begin(); i != res.pausedList().end(); ++i) { + PausedCharacter *rec = *i; + if ((rec->srcCharId == charId) && + (rec->destCharId == hotspot->hotspotId())) + break; + } + + if (i != res.pausedList().end()) + // There was, so move to next impinging character entry + continue; + + if ((hotspot->hotspotId() == PLAYER_ID) && !hotspot->coveredFlag()) + return 1; + + // Add a new paused character entry + PausedCharacter *entry = new PausedCharacter(charId, hotspot->hotspotId()); + res.pausedList().push_back(entry); + charHotspot->setBlockedState(BS_INITIAL); + + if (hotspot->hotspotId() < START_EXIT_ID) { + if ((charHotspot->characterMode() == CHARMODE_PAUSED) || + ((charHotspot->pauseCtr() == 0) && + (charHotspot->characterMode() == CHARMODE_NONE))) { + hotspot->resource()->use2HotspotId = charId; + } else { + hotspot->setPauseCtr(IDLE_COUNTDOWN_SIZE); + } + } + + result = 2; + if (charHotspot->currentActions().isEmpty()) + charHotspot->currentActions().addFront(START_WALKING, charHotspot->roomNumber()); + else + charHotspot->currentActions().top().setAction(START_WALKING); + } + + return result; +} + // Field list and miscellaneous variables ValueTableData::ValueTableData() { @@ -659,6 +800,11 @@ ValueTableData::ValueTableData() { _playerNewPos.roomNumber = 0; _playerNewPos.position.x = 0; _playerNewPos.position.y = 0; + _playerPendingPos.pos.x = 0; + _playerPendingPos.pos.y = 0; + _playerPendingPos.isSet = false; + _flags = GAMEFLAG_4 | GAMEFLAG_1; + for (uint16 index = 0; index < NUM_VALUE_FIELDS; ++index) _fieldList[index] = 0; } diff --git a/engines/lure/res_struct.h b/engines/lure/res_struct.h index 177b83f986..ded24f61f9 100644 --- a/engines/lure/res_struct.h +++ b/engines/lure/res_struct.h @@ -84,6 +84,8 @@ struct HotspotResource { uint16 tickTimeout; uint16 tickSequenceOffset; uint16 npcSchedule; + uint16 characterMode; + uint16 delayCtr; } GCC_PACK; struct HotspotAnimResource { @@ -373,8 +375,10 @@ public: HotspotActionList *getActions(uint16 recordId); }; -enum CharacterMode {CHARMODE_NONE, CHARMODE_1, CHARMODE_IDLE, CHARMODE_PAUSED, - CHARMODE_4, CHARMODE_5, CHARMODE_6, CHARMODE_7}; +enum CharacterMode {CHARMODE_NONE, CHARMODE_HESITATE, CHARMODE_IDLE, CHARMODE_PAUSED, + CHARMODE_4, CHARMODE_CONVERSING, CHARMODE_6, CHARMODE_7, CHARMODE_8}; + +enum BlockedState {BS_NONE, BS_INITIAL, BS_FINAL}; class HotspotData { public: @@ -409,10 +413,21 @@ public: uint16 tickTimeout; uint16 tickSequenceOffset; uint16 npcSchedule; - - uint16 delayCtr; CharacterMode characterMode; + uint16 delayCtr; + + // Runtime fields + uint16 actionCtr; + BlockedState blockedState; bool coveredFlag; + uint16 talkMessageId; + uint16 talkDestHotspot; + uint16 talkCountdown; + uint16 pauseCtr; + uint16 useHotspotId; + uint16 use2HotspotId; + uint16 v2b; + uint16 v50; void enable() { flags |= 0x80; } void disable() { flags &= 0x7F; } @@ -543,18 +558,19 @@ public: // The following classes hold any sequence offsets that are being delayed class SequenceDelayData { - friend class SequenceDelayList; -private: - uint32 _timeoutCtr; - uint16 _sequenceOffset; public: - SequenceDelayData(uint16 delay, uint16 seqOffset); + SequenceDelayData(uint16 delay, uint16 seqOffset, bool canClearFlag); + + uint32 timeoutCtr; + uint16 sequenceOffset; + bool canClear; }; class SequenceDelayList: public ManagedList { public: - void addSequence(uint16 delay, uint16 seqOffset); + void add(uint16 delay, uint16 seqOffset, bool canClear); void tick(); + void clear(); }; // The following classes holds the data for NPC schedules @@ -599,6 +615,26 @@ public: typedef List CharacterScheduleOffsets; +class PausedCharacter { +public: + PausedCharacter(uint16 SrcCharId, uint16 DestCharId); + + uint16 srcCharId; + uint16 destCharId; + uint16 counter; + HotspotData *charHotspot; +}; + +class Hotspot; + +class PausedCharacterList: public ManagedList { +public: + void reset(uint16 hotspotId); + void countdown(); + void scan(Hotspot &h); + int check(uint16 charId, int numImpinging, uint16 *impingingList); +}; + // The following class holds the field list used by the script engine as // well as miscellaneous fields used by the game. @@ -611,6 +647,7 @@ enum FieldName { ACTIVE_HOTSPOT_ID = 3, SEQUENCE_RESULT = 4, GENERAL = 5, + GIVE_TALK_INDEX = 6, NEW_ROOM_NUMBER = 7, OLD_ROOM_NUMBER = 8, CELL_DOOR_STATE = 9, @@ -621,15 +658,33 @@ enum FieldName { SACK_CUT = 20 }; +enum GameFlags { + GAMEFLAG_1 = 1, + GAMEFLAG_2 = 2, + GAMEFLAG_4 = 4, + GAMEFLAG_8 = 8, + GAMEFLAG_10 = 0x10, + GAMEFLAG_20 = 0x20, + GAMEFLAG_40 = 0x40, + GAMEFLAG_FAST_TEXTSPEED = 0x80 +}; + struct PlayerNewPosition { Point position; uint16 roomNumber; }; +struct PlayerPendingPosition { + Point pos; + bool isSet; +}; + class ValueTableData { private: uint16 _numGroats; PlayerNewPosition _playerNewPos; + PlayerPendingPosition _playerPendingPos; + uint8 _flags; uint16 _fieldList[NUM_VALUE_FIELDS]; bool isKnownField(uint16 fieldIndex); @@ -640,8 +695,12 @@ public: void setField(uint16 fieldIndex, uint16 value); void setField(FieldName fieldName, uint16 value); + int size() { return NUM_VALUE_FIELDS; } + uint16 &numGroats() { return _numGroats; } + uint8 &flags() { return _flags; } PlayerNewPosition &playerNewPos() { return _playerNewPos; } + PlayerPendingPosition &playerPendingPos() { return _playerPendingPos; } }; } // End of namespace Lure -- cgit v1.2.3