scummvm/engines/titanic/npcs/true_talk_npc.cpp
2021-12-26 18:48:43 +01:00

262 lines
7.2 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/npcs/true_talk_npc.h"
#include "titanic/core/view_item.h"
#include "titanic/debugger.h"
#include "titanic/game_manager.h"
#include "titanic/pet_control/pet_control.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CTrueTalkNPC, CCharacter)
ON_MESSAGE(TextInputMsg)
ON_MESSAGE(TrueTalkGetAssetDetailsMsg)
ON_MESSAGE(DismissBotMsg)
ON_MESSAGE(TrueTalkNotifySpeechStartedMsg)
ON_MESSAGE(TrueTalkNotifySpeechEndedMsg)
ON_MESSAGE(MovieEndMsg)
ON_MESSAGE(NPCQueueIdleAnimMsg)
ON_MESSAGE(TimerMsg)
ON_MESSAGE(NPCPlayAnimationMsg)
END_MESSAGE_MAP()
CTrueTalkNPC::CTrueTalkNPC() : _assetName("z451.dlg"),
_assetNumber(0x11170), _fieldE4(0), _npcFlags(0), _speechDuration(0), _startTicks(0),
_fieldF4(0), _fieldF8(0), _speechTimerId(0), _speechCounter(0), _field104(0) {
}
void CTrueTalkNPC::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_assetNumber, indent);
file->writeQuotedLine(_assetName, indent);
file->writeNumberLine(_fieldE4, indent);
file->writeNumberLine(_npcFlags, indent);
file->writeNumberLine(_speechDuration, indent);
file->writeNumberLine(_startTicks, indent);
file->writeNumberLine(_fieldF4, indent);
file->writeNumberLine(_fieldF8, indent);
file->writeNumberLine(_speechTimerId, indent);
file->writeNumberLine(_speechCounter, indent);
file->writeNumberLine(_field104, indent);
CCharacter::save(file, indent);
}
void CTrueTalkNPC::load(SimpleFile *file) {
file->readNumber();
_assetNumber = file->readNumber();
_assetName = file->readString();
_fieldE4 = file->readNumber();
_npcFlags = file->readNumber();
_speechDuration = file->readNumber();
_startTicks = file->readNumber();
_fieldF4 = file->readNumber();
_fieldF8 = file->readNumber();
_speechTimerId = file->readNumber();
_speechCounter = file->readNumber();
_field104 = file->readNumber();
CCharacter::load(file);
}
bool CTrueTalkNPC::TextInputMsg(CTextInputMsg *msg) {
processInput(msg, _field104 ? findView() : nullptr);
return true;
}
bool CTrueTalkNPC::TrueTalkGetAssetDetailsMsg(CTrueTalkGetAssetDetailsMsg *msg) {
msg->_filename = _assetName;
msg->_numValue = _assetNumber;
return true;
}
bool CTrueTalkNPC::DismissBotMsg(CDismissBotMsg *msg) {
performAction(1, 0);
return true;
}
bool CTrueTalkNPC::TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg) {
debugC(DEBUG_DETAILED, kDebugScripts, "%s TrueTalkNotifySpeechStartedMsg flags=%x dialogueId=%d",
getName().c_str(), _npcFlags, msg->_dialogueId);
_npcFlags |= NPCFLAG_SPEAKING;
++_speechCounter;
if (!(_npcFlags & NPCFLAG_DOORBOT_IN_HOME)) {
// Stop any previous animation
if (_speechTimerId)
stopAnimTimer(_speechTimerId);
_speechTimerId = 0;
_speechDuration = msg->_speechDuration;
_startTicks = getTicksCount();
if (!hasActiveMovie() || (_npcFlags & NPCFLAG_IDLING)) {
_npcFlags &= ~NPCFLAG_IDLING;
stopMovie();
CNPCPlayTalkingAnimationMsg msg1(_speechDuration, 0, nullptr);
msg1.execute(this);
if (msg1._names) {
CNPCPlayAnimationMsg msg2(msg1._names, msg1._speechDuration);
msg2.execute(this);
}
}
}
return true;
}
bool CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) {
debugC(DEBUG_DETAILED, kDebugScripts, "%s TrueTalkNotifySpeechEndedMsg flags=%x dialogueId=%d", getName().c_str(), _npcFlags, msg->_dialogueId);
if (!getGameManager())
return false;
_npcFlags &= ~NPCFLAG_SPEAKING;
--_speechCounter;
_speechDuration = 0;
if (!(_npcFlags & NPCFLAG_DOORBOT_IN_HOME)) {
CNPCPlayTalkingAnimationMsg msg1(0, 2, nullptr);
msg1.execute(this);
CNPCQueueIdleAnimMsg msg2;
msg2.execute(this);
}
return true;
}
bool CTrueTalkNPC::MovieEndMsg(CMovieEndMsg *msg) {
if (_npcFlags & NPCFLAG_IDLING) {
_npcFlags &= ~NPCFLAG_IDLING;
CNPCQueueIdleAnimMsg idleMsg;
idleMsg.execute(this);
return true;
} else if (!(_npcFlags & NPCFLAG_SPEAKING)) {
return false;
}
int diff = getTicksCount() - _startTicks;
int ticks = MAX((int)_speechDuration - diff, 0);
CNPCPlayTalkingAnimationMsg msg1(ticks, ticks > 1000 ? 1 : 2, 0);
msg1.execute(this);
if (msg1._names) {
CNPCPlayAnimationMsg msg2(msg1._names, ticks);
msg2.execute(this);
}
return true;
}
bool CTrueTalkNPC::NPCQueueIdleAnimMsg(CNPCQueueIdleAnimMsg *msg) {
int rndVal = getRandomNumber(_fieldF8 - 1) - (_fieldF8 / 2);
_speechTimerId = startAnimTimer("NPCIdleAnim", _fieldF4 + rndVal, 0);
return true;
}
bool CTrueTalkNPC::TimerMsg(CTimerMsg *msg) {
if (_npcFlags & NPCFLAG_START_IDLING) {
if (_speechCounter > 0)
return false;
CNPCPlayIdleAnimationMsg idleMsg;
if (idleMsg.execute(this)) {
if (idleMsg._names) {
CNPCPlayAnimationMsg animMsg(idleMsg._names, 0);
animMsg.execute(this);
}
_npcFlags |= NPCFLAG_IDLING;
}
}
_speechTimerId = 0;
return true;
}
bool CTrueTalkNPC::NPCPlayAnimationMsg(CNPCPlayAnimationMsg *msg) {
// const char *const *nameP = msg->_names;
int count;
for (count = 0; msg->_names[count]; ++count)
;
if (msg->_maxDuration) {
// Randomly pick a clip that's less than the allowed maximum
int tries = 10, index;
do {
index = getRandomNumber(count - 1);
} while (getClipDuration(msg->_names[index]) > msg->_maxDuration && --tries);
if (!tries) {
// Sequentially go through the clips to find any below the maximum
index = 0;
for (int idx = 0; idx < count; ++idx) {
if (getClipDuration(msg->_names[idx]) < msg->_maxDuration) {
index = idx;
break;
}
}
}
playClip(msg->_names[index], MOVIE_NOTIFY_OBJECT);
} else {
playClip(msg->_names[getRandomNumber(count - 1)], MOVIE_NOTIFY_OBJECT);
}
return true;
}
void CTrueTalkNPC::processInput(CTextInputMsg *msg, CViewItem *view) {
CTrueTalkManager *talkManager = getGameManager()->getTalkManager();
if (talkManager)
talkManager->processInput(this, msg, view);
}
void CTrueTalkNPC::setView(CViewItem *view) {
CTrueTalkManager *talkManager = getGameManager()->getTalkManager();
if (talkManager)
talkManager->start3(this, view);
}
void CTrueTalkNPC::startTalker(CViewItem *view) {
CGameManager *gameManager = getGameManager();
if (gameManager)
gameManager->getTalkManager()->start4(this, view);
}
void CTrueTalkNPC::performAction(bool startTalkingFlag, CViewItem *destView) {
CPetControl *pet = getPetControl();
if (pet)
pet->resetActiveNPC();
if (startTalkingFlag)
startTalker(destView);
if (pet)
pet->convResetNPC();
}
} // End of namespace Titanic