SHERLOCK: RT: Implement updateNPC

This commit is contained in:
Paul Gilbert 2015-06-17 21:41:05 -04:00
parent 8abce6b025
commit 65b794a750
2 changed files with 239 additions and 5 deletions

View File

@ -100,7 +100,8 @@ TattooPerson::TattooPerson() : Person() {
_savedNpcSequence = 0;
_savedNpcFrame = 0;
_updateNPCPath = true;
_npcPause = false;
_npcPause = 0;
_lookHolmes = false;
}
void TattooPerson::freeAltGraphics() {
@ -577,7 +578,221 @@ void TattooPerson::clearNPC() {
}
void TattooPerson::updateNPC() {
warning("TODO: updateNPC");
People &people = *_vm->_people;
Talk &talk = *_vm->_talk;
// If the NPC isn't on, or it's in Talk or Listen Mode, then return without doing anything
if (_type != CHARACTER || _sequenceNumber >= TALK_UPRIGHT)
return;
// If the NPC is paused, just decrement his pause counter and exit
if (_npcPause) {
// Decrement counter
--_npcPause;
// Now see if we need to update the NPC's frame sequence so that he faces Holmes
if (_lookHolmes) {
// See where Holmes is with respect to the NPC (x coordinate)
_npcFacing = (people[HOLMES]._position.x < _position.x) ? STOP_LEFT : STOP_RIGHT;
// See where Holmes is with respect to the NPC (y coordinate)
if (people[HOLMES]._position.y < (_position.y - 10 * FIXED_INT_MULTIPLIER)) {
// Holmes is above the NPC so reset the facing to a diagonal up
_npcFacing = (_npcFacing == STOP_RIGHT) ? STOP_UPRIGHT : STOP_UPLEFT;
} else if (people[HOLMES]._position.y > (_position.y + 10 * FIXED_INT_MULTIPLIER)) {
// Holmes is below the NPC so reset the facing to a diagonal down
_npcFacing = (_npcFacing == STOP_RIGHT) ? STOP_DOWNRIGHT : STOP_DOWNLEFT;
}
// See if we need to set the old_walk_sequence so the NPC will put his arms
// up if he turns another way
if (_sequenceNumber != _npcFacing)
_oldWalkSequence = _sequenceNumber;
gotoStand();
}
} else {
// Reset the look flag so the NPC won't face Holmes anymore
_lookHolmes = false;
// See if the NPC is stopped or not. Don't do anything if he's moving
if (!_walkCount) {
// If there is no new command, reset the path back to the beginning
if (!_npcPath[_npcIndex])
_npcIndex = 0;
// The NPC is stopped and any pause he was doing is done. We can now see what
// the next command in the NPC path is.
// Scan Past any NPC Path Labels since they do nothing except mark places for If's and Goto's
while (_npcPath[_npcIndex] == NPCPATH_PATH_LABEL)
_npcIndex += 2;
if (_npcPath[_npcIndex]) {
_npcFacing = -1;
switch (_npcPath[_npcIndex]) {
case NPCPATH_SET_DEST: {
// Set the NPC's new destination
int xp = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1;
if (xp > 16384)
xp = -1 * (xp - 16384);
_walkDest.x = xp;
_walkDest.y = (_npcPath[_npcIndex + 3] - 1) * 256 + _npcPath[_npcIndex + 4] - 1;
_npcFacing = _npcPath[_npcIndex + 5] - 1;
goAllTheWay();
_npcIndex += 6;
break;
}
case NPCPATH_PAUSE:
// Set the NPC to pause where he is
_npcPause = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1;
_npcIndex += 3;
break;
case NPCPATH_SET_TALK_FILE: {
// Set the NPC's Talk File to use if Holmes talks to them
++_npcIndex;
_npcName = "";
for (int idx = 0; idx < 8; ++idx) {
if (_npcPath[_npcIndex + idx] != '~')
_npcName += _npcPath[_npcIndex + idx];
else
break;
}
_npcIndex += 8;
break;
}
case NPCPATH_CALL_TALK_FILE: {
// Call a Talk File
++_npcIndex;
Common::String name;
for (int idx = 0; idx < 8; ++idx) {
if (_npcPath[_npcIndex + idx] != '~')
name += _npcPath[_npcIndex + idx];
else
break;
}
_npcIndex += 8;
talk.talkTo(name);
break;
}
case NPCPATH_TAKE_NOTES:
// Set the NPC to Pause where he is and set his frame sequences
// so he takes notes while he's paused
_npcPause = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1;
_npcIndex += 3;
break;
case NPCPATH_FACE_HOLMES:
// Set the NPC to Pause where he is and set his look flag so he will always face Holmes
// while he is paused
_npcPause = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1;
_lookHolmes = true;
_npcIndex += 3;
break;
//case NPCPATH_PATH_LABEL: // No implementation needed here
case NPCPATH_GOTO_LABEL: {
// Goto NPC Path Label
int label = _npcPath[_npcIndex + 1];
_npcIndex = 0;
// Scan through NPC path data to find the label
bool found = false;
while (!found) {
switch (_npcPath[_npcIndex]) {
case NPCPATH_SET_DEST:
_npcIndex += 6;
break;
case NPCPATH_PAUSE:
case NPCPATH_TAKE_NOTES:
case NPCPATH_FACE_HOLMES:
_npcIndex += 3;
break;
case NPCPATH_SET_TALK_FILE:
case NPCPATH_CALL_TALK_FILE:
_npcIndex += 8;
break;
case NPCPATH_PATH_LABEL:
if (_npcPath[_npcIndex + 1] == label)
found = true;
_npcIndex += 2;
break;
case NPCPATH_GOTO_LABEL:
_npcIndex += 2;
break;
case NPCPATH_IFFLAG_GOTO_LABEL:
_npcIndex += 4;
break;
}
}
break;
}
case NPCPATH_IFFLAG_GOTO_LABEL: {
// If FLAG then Goto Label
int flag = (_npcPath[_npcIndex + 1] - 1) * 256 + _npcPath[_npcIndex + 2] - 1 - (_npcPath[_npcIndex + 2] == 1 ? 1 : 0);
// Set the value the flag should be for the if statement to succeed
bool flagVal = flag < 16384;
int label = _npcPath[_npcIndex + 3];
_npcIndex += 4;
// If the flag is set Correctly, move the NPC Index to the given label
if (_vm->readFlags(flag & 16383) == flagVal) {
_npcIndex = 0;
bool found = false;
while (!found)
{
switch (_npcPath[_npcIndex])
{
case NPCPATH_SET_DEST:
_npcIndex += 6;
break;
case NPCPATH_PAUSE:
case NPCPATH_TAKE_NOTES:
case NPCPATH_FACE_HOLMES:
_npcIndex += 3;
break;
case NPCPATH_SET_TALK_FILE:
case NPCPATH_CALL_TALK_FILE:
_npcIndex += 8;
break;
case NPCPATH_PATH_LABEL:
if (_npcPath[_npcIndex + 1] == label)
found = true;
_npcIndex += 2;
break;
case NPCPATH_GOTO_LABEL:
_npcIndex += 2;
break;
case NPCPATH_IFFLAG_GOTO_LABEL:
_npcIndex += 4;
break;
}
}
}
break;
}
default:
break;
}
}
}
}
}
void TattooPerson::pushNPCPath() {

View File

@ -71,6 +71,18 @@ enum TattooSequences {
LISTEN_UPLEFT = 27
};
enum NpcPath {
NPCPATH_SET_DEST = 1,
NPCPATH_PAUSE = 2,
NPCPATH_SET_TALK_FILE = 3,
NPCPATH_CALL_TALK_FILE = 4,
NPCPATH_TAKE_NOTES = 5,
NPCPATH_FACE_HOLMES = 6,
NPCPATH_PATH_LABEL = 7,
NPCPATH_GOTO_LABEL = 8,
NPCPATH_IFFLAG_GOTO_LABEL = 9
};
class TattooPerson: public Person {
private:
Point32 _nextDest;
@ -89,7 +101,7 @@ protected:
public:
int _npcIndex;
int _npcStack;
bool _npcPause;
int _npcPause;
byte _npcPath[MAX_NPC_PATH];
Common::String _npcName;
bool _npcMoved;
@ -100,6 +112,7 @@ public:
int _tempX;
int _tempScaleVal;
bool _updateNPCPath;
bool _lookHolmes;
public:
TattooPerson();
virtual ~TattooPerson() {}
@ -110,12 +123,18 @@ public:
void clearNPC();
/**
* Update the NPC
* Called from doBgAnim to move NPCs along any set paths. If an NPC is paused in his path,
* he will remain paused until his pause timer runs out. If he is walking somewhere,
* he will continue walking there until he reaches the dest position. When an NPC stops moving,
* the next element of his path is processed.
*
* The path is an array of bytes with control codes followed by their parameters as needed.
*/
void updateNPC();
/**
* Push the NPC's path
* Push the NPC's path data onto the path stack for when a talk file moves the NPC that
* has some control codes.
*/
void pushNPCPath();