Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,749 @@
/* 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/barbot.h"
#include "titanic/support/files_manager.h"
#include "titanic/titanic.h"
#include "titanic/translation.h"
namespace Titanic {
int CBarbot::_timesCalled;
BEGIN_MESSAGE_MAP(CBarbot, CTrueTalkNPC)
ON_MESSAGE(ActMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(TurnOn)
ON_MESSAGE(TurnOff)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(MovieEndMsg)
ON_MESSAGE(TrueTalkSelfQueueAnimSetMsg)
ON_MESSAGE(TrueTalkQueueUpAnimSetMsg)
ON_MESSAGE(TrueTalkGetStateValueMsg)
ON_MESSAGE(TrueTalkTriggerActionMsg)
ON_MESSAGE(FrameMsg)
ON_MESSAGE(LoadSuccessMsg)
ON_MESSAGE(MovieFrameMsg)
ON_MESSAGE(EnterRoomMsg)
ON_MESSAGE(TimerMsg)
END_MESSAGE_MAP()
CBarbot::FrameRanges::FrameRanges() : Common::Array<FrameRange>() {
resize(60);
Common::SeekableReadStream *stream = g_vm->_filesManager->getResource("FRAMES/BARBOT");
for (int idx = 0; idx < 60; ++idx) {
(*this)[idx]._startFrame = stream->readUint32LE();
(*this)[idx]._endFrame = stream->readUint32LE();
}
delete stream;
}
/*------------------------------------------------------------------------*/
CBarbot::CBarbot() : CTrueTalkNPC() {
_field108 = 0;
_field10C = 0;
_field110 = 0;
_addedLemon = false;
_addedTV = false;
_addedPuret = false;
_field120 = 0;
_field124 = 0;
_visCenterOnCounter = false;
_addedVodka = false;
_gottenDrunk = false;
_field134 = 0;
_field138 = 0;
_field13C = -1;
_volume = 30;
_frameNum = -1;
_field148 = -1;
_field14C = 0;
_field150 = 0;
_field154 = 0;
_glassContent = GG_DEFAULT;
_drunkFlag = false;
_field160 = 0;
}
void CBarbot::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_field108, indent);
file->writeNumberLine(_field10C, indent);
file->writeNumberLine(_field110, indent);
file->writeNumberLine(_addedLemon, indent);
file->writeNumberLine(_addedTV, indent);
file->writeNumberLine(_addedPuret, indent);
file->writeNumberLine(_field120, indent);
file->writeNumberLine(_field124, indent);
file->writeNumberLine(_visCenterOnCounter, indent);
file->writeNumberLine(_timesCalled, indent);
file->writeNumberLine(_addedVodka, indent);
file->writeNumberLine(_gottenDrunk, indent);
file->writeNumberLine(_field134, indent);
file->writeNumberLine(_field138, indent);
file->writeNumberLine(_field13C, indent);
file->writeNumberLine(_volume, indent);
file->writeNumberLine(_frameNum, indent);
file->writeNumberLine(_field148, indent);
file->writeNumberLine(_field14C, indent);
file->writeNumberLine(_field150, indent);
file->writeNumberLine(_field154, indent);
file->writeNumberLine(_glassContent, indent);
file->writeNumberLine(_drunkFlag, indent);
file->writeNumberLine(_field160, indent);
CTrueTalkNPC::save(file, indent);
}
void CBarbot::load(SimpleFile *file) {
file->readNumber();
_field108 = file->readNumber();
_field10C = file->readNumber();
_field110 = file->readNumber();
_addedLemon = file->readNumber();
_addedTV = file->readNumber();
_addedPuret = file->readNumber();
_field120 = file->readNumber();
_field124 = file->readNumber();
_visCenterOnCounter = file->readNumber();
_timesCalled = file->readNumber();
_addedVodka = file->readNumber();
_gottenDrunk = file->readNumber();
_field134 = file->readNumber();
_field138 = file->readNumber();
_field13C = file->readNumber();
_volume = file->readNumber();
_frameNum = file->readNumber();
_field148 = file->readNumber();
_field14C = file->readNumber();
_field150 = file->readNumber();
_field154 = file->readNumber();
_glassContent = (GlassGiven)file->readNumber();
_drunkFlag = file->readNumber();
_field160 = file->readNumber();
CTrueTalkNPC::load(file);
}
bool CBarbot::ActMsg(CActMsg *msg) {
if (msg->_action == "Vodka") {
if (!_addedVodka) {
playRange(_frames[47], MOVIE_NOTIFY_OBJECT);
playRange(_frames[46], MOVIE_NOTIFY_OBJECT);
playRange(_frames[40]);
playRange(_frames[7]);
playRange(_frames[13]);
playRange(_frames[8]);
playRange(_frames[40]);
playRange(_frames[7]);
playRange(_frames[13]);
playRange(_frames[8]);
playRange(_frames[7]);
playRange(_frames[40]);
playRange(_frames[13]);
playRange(_frames[40]);
playRange(_frames[7]);
playRange(_frames[8]);
playRange(_frames[13]);
playRange(_frames[40], MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
_frameNum = _frames[40]._endFrame;
}
} else if (msg->_action == "GiveBackVisCentre") {
if (_field134) {
playRange(_frames[27]);
_frameNum = _frames[27]._endFrame;
}
} else if (msg->_action == "Bird") {
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 2;
statusMsg.execute("PickUpGlass");
_glassContent = GG_BIRD;
playRange(_frames[32], MOVIE_NOTIFY_OBJECT);
movieEvent();
playRange(_frames[30], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[30]._endFrame;
if (areIngredientsMissing()) {
playRange(_frames[42], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[42]._endFrame;
}
CActMsg actMsg("InTitilator");
actMsg.execute("BeerGlass");
} else if (msg->_action == "None") {
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 2;
statusMsg.execute("PickUpGlass");
_glassContent = GG_EMPTY;
playRange(_frames[55], MOVIE_NOTIFY_OBJECT);
movieEvent();
playRange(_frames[54], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[54]._endFrame;
} else if (msg->_action == "Mustard" || msg->_action == "Tomato") {
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 2;
statusMsg.execute("PickUpGlass");
_glassContent = GG_CONDIMENT;
playRange(_frames[55], MOVIE_NOTIFY_OBJECT);
movieEvent();
playRange(_frames[54], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[54]._endFrame;
CActMsg actMsg("InTitilator");
actMsg.execute("BeerGlass");
} else if (msg->_action == "Fruit") {
if (!_addedLemon) {
CActMsg visibleMsg;
visibleMsg.execute("LemonOnBar");
startTalking(this, 250576);
_addedLemon = true;
playRange(_frames[36], MOVIE_NOTIFY_OBJECT);
movieEvent();
_frameNum = _frames[36]._endFrame;
if (areIngredientsMissing()) {
playRange(_frames[43], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[43]._endFrame;
}
CRemoveFromGameMsg removeMsg;
removeMsg.execute("Lemon");
}
} else if (msg->_action == "CrushedTV") {
if (!_addedTV) {
CVisibleMsg visibleMsg;
visibleMsg.execute("TVOnBar");
startTalking(this, 250584);
_field160 = 1;
_addedTV = true;
playSound(TRANSLATE("c#5.wav", "c#65.wav"), _volume);
playRange(_frames[35], MOVIE_NOTIFY_OBJECT);
movieEvent();
playRange(_frames[34]);
playRange(_frames[33], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[33]._endFrame;
if (areIngredientsMissing()) {
playRange(_frames[41], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[41]._endFrame;
}
CRemoveFromGameMsg removeMsg;
removeMsg.execute("CrushedTV");
}
} else if (msg->_action == "PlayerTakesGlass") {
playRange(_frames[53]);
_field124 = 0;
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 0;
statusMsg.execute("PickUpGlass");
} else if (msg->_action == "PlayerTakesVisCentre") {
_visCenterOnCounter = false;
loadFrame(0);
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 0;
statusMsg.execute("PickUpVisCentre");
} else if (msg->_action == "BellRing1") {
startTalking(this, 251105);
} else if (msg->_action == "BellRing2") {
startTalking(this, 251107);
} else if (msg->_action == "BellRing3") {
startTalking(this, 250285);
} else if (msg->_action == "GoRingBell") {
startTalking(this, 250285);
} else if (msg->_action == "ClickOnVision") {
startTalking(this, 251858);
}
return true;
}
bool CBarbot::EnterViewMsg(CEnterViewMsg *msg) {
// I think this is a remnant of early debugging code
if (getName() != "Barbot")
playMovie(MOVIE_REPEAT);
return true;
}
bool CBarbot::EnterRoomMsg(CEnterRoomMsg *msg) {
// I think this is a remnant of early debugging code
if (getName() != "Barbot")
addTimer(g_vm->getRandomNumber(20000));
return true;
}
bool CBarbot::TurnOn(CTurnOn *msg) {
if (!_fieldC4) {
_field13C = -1;
setVisible(true);
CGameObject *glass = findInRoom("BeerGlass");
if (!_gottenDrunk) {
CVisibleMsg visibleMsg(false);
visibleMsg.execute("BarShelfVisCentre");
}
if (glass && !_addedPuret) {
playRange(_frames[38], MOVIE_NOTIFY_OBJECT);
playRange(_frames[58], MOVIE_NOTIFY_OBJECT);
playRange(_frames[57], MOVIE_NOTIFY_OBJECT);
playRange(_frames[56], MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
_frameNum = _frames[56]._endFrame;
} else {
playRange(_frames[38]);
playRange(_frames[23], MOVIE_NOTIFY_OBJECT);
playRange(_frames[21], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[21]._endFrame;
switch (g_vm->getRandomNumber(2)) {
case 0:
playRange(_frames[10], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[10]._endFrame;
break;
case 1:
playRange(_frames[12], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[12]._endFrame;
break;
default:
break;
}
_field124 = 0;
}
_fieldC4 = 1;
++_timesCalled;
petSetArea(PET_CONVERSATION);
setTalking(this, true);
}
return true;
}
bool CBarbot::TurnOff(CTurnOff *msg) {
if (_fieldC4) {
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 0;
statusMsg.execute("PickUpGlass");
statusMsg.execute("PickUpVisCentre");
if (_field124) {
playRange(_frames[17], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[17]._endFrame;
_field124 = 0;
}
if (_visCenterOnCounter) {
// Barbot will put away the vision center
playRange(_frames[28], MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
_frameNum = _frames[28]._endFrame;
_visCenterOnCounter = false;
_field134 = 1;
}
playRange(_frames[29], MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
movieEvent(_frames[29]._startFrame);
_frameNum = _frames[29]._endFrame;
_fieldC4 = 0;
}
return true;
}
bool CBarbot::LeaveViewMsg(CLeaveViewMsg *msg) {
CTurnOff offMsg;
offMsg.execute(this);
return true;
}
bool CBarbot::MovieEndMsg(CMovieEndMsg *msg) {
if (msg->_endFrame == _frameNum) {
_frameNum = -1;
_field14C = getTicksCount();
}
if (msg->_endFrame == _field148) {
_field148 = -1;
_field150 = getTicksCount();
}
if (msg->_endFrame == _field13C) {
if (_field124)
playMovie(_frames[53]._startFrame, _frames[53]._startFrame, 0);
else if (_visCenterOnCounter)
playMovie(_frames[27]._endFrame, _frames[27]._endFrame, 0);
_field13C = -1;
return true;
}
if (msg->_endFrame == _frames[58]._endFrame || msg->_endFrame == _frames[21]._endFrame) {
if (!_gottenDrunk) {
CVisibleMsg visibleMsg(true);
visibleMsg.execute("BarShelfVisCentre");
}
}
if (msg->_endFrame == _frames[57]._endFrame) {
startTalking(this, 250575);
playSound(TRANSLATE("c#10.wav", "c#70.wav"), _volume);
return true;
}
if (msg->_endFrame == _frames[55]._endFrame) {
playSound(TRANSLATE("c#10.wav", "c#70.wav"), _volume);
return true;
}
if (msg->_endFrame == _frames[56]._endFrame
|| msg->_endFrame == _frames[54]._endFrame) {
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 1;
statusMsg.execute("PickUpGlass");
CMoveToStartPosMsg moveMsg;
moveMsg.execute("BeerGlass");
return true;
}
if (msg->_endFrame == _frames[30]._endFrame) {
_field124 = 0;
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 0;
statusMsg.execute("PickUpGlass");
}
if (msg->_endFrame == _frames[45]._endFrame) {
if (!_gottenDrunk) {
CVisibleMsg visibleMsg(false);
visibleMsg.execute("BarShelfVisCentre");
}
return true;
}
if (msg->_endFrame == _frames[44]._endFrame) {
_visCenterOnCounter = true;
_gottenDrunk = true;
startTalking(this, 250586);
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 1;
statusMsg.execute("PickUpVisCentre");
CPuzzleSolvedMsg solvedMsg;
solvedMsg.execute("VisionCentre");
}
if (msg->_endFrame == _frames[46]._endFrame) {
if (!_gottenDrunk && !areIngredientsMissing())
startTalking(this, 250571);
return true;
}
if (msg->_endFrame == _frames[43]._endFrame
|| msg->_endFrame == _frames[42]._endFrame
|| msg->_endFrame == _frames[41]._endFrame) {
if (_field124)
playMovie(_frames[53]._startFrame, _frames[53]._startFrame, 0);
return true;
}
if (msg->_endFrame == _frames[38]._endFrame || msg->_endFrame == _frames[23]._endFrame) {
playSound(TRANSLATE("c#3.wav", "c#63.wav"), _volume);
} else if (msg->_endFrame == _frames[36]._endFrame) {
playSound(TRANSLATE("c#6.wav", "c#66.wav"), _volume);
} else if (msg->_endFrame == _frames[35]._endFrame) {
playSound(TRANSLATE("c#8.wav", "c#68.wav"), _volume);
} else if (msg->_endFrame == _frames[33]._endFrame) {
playSound(TRANSLATE("c#4.wav", "c#64.wav"), _volume);
} else if (msg->_endFrame == _frames[32]._endFrame) {
startTalking(this, 145);
playSound(TRANSLATE("c#9.wav", "c#69.wav"), _volume);
} else if (msg->_endFrame == _frames[47]._endFrame) {
playSound(TRANSLATE("c#9.wav", "c#69.wav"), _volume);
_addedVodka = true;
_drunkFlag = true;
} else if (msg->_endFrame == _frames[30]._endFrame) {
playSound(TRANSLATE("c#4.wav", "c#64.wav"), 60);
} else if (msg->_endFrame == _frames[29]._endFrame) {
if (!_fieldC4) {
performAction(true, nullptr);
setVisible(false);
CActMsg actMsg("ResetCount");
actMsg.execute("BarBell");
}
} else if (msg->_endFrame == _frames[27]._endFrame) {
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 1;
statusMsg.execute("PickUpVisCentre");
_visCenterOnCounter = true;
_field134 = 0;
startTalking(this, 250586);
}
return true;
}
bool CBarbot::TrueTalkSelfQueueAnimSetMsg(CTrueTalkSelfQueueAnimSetMsg *msg) {
return true;
}
bool CBarbot::TrueTalkQueueUpAnimSetMsg(CTrueTalkQueueUpAnimSetMsg *msg) {
return true;
}
bool CBarbot::TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg) {
switch (msg->_stateNum) {
case 2:
if (!_gottenDrunk) {
if (_drunkFlag) {
msg->_stateVal = _field134 | 1;
return true;
}
}
msg->_stateVal = _field134;
break;
case 3:
msg->_stateVal = 0;
if (_addedLemon)
msg->_stateVal = 1;
if (_addedVodka)
msg->_stateVal |= 2;
if (_addedPuret)
msg->_stateVal |= 4;
if (_addedTV)
msg->_stateVal |= 8;
break;
case 9:
msg->_stateVal = _drunkFlag ? 1 : 0;
break;
default:
break;
}
return true;
}
bool CBarbot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
switch (msg->_action) {
case 6:
if (_field134) {
playRange(_frames[27], MOVIE_NOTIFY_OBJECT);
_frameNum = _frames[27]._endFrame;
} else if (!_gottenDrunk && _drunkFlag) {
playRange(_frames[45], MOVIE_NOTIFY_OBJECT);
playRange(_frames[44], MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
_frameNum = _frames[44]._endFrame;
}
break;
case 7: {
// "add vodka"
CActMsg actMsg("Vodka");
actMsg.execute(this);
break;
}
case 30:
// "starling puret"
_addedPuret = true;
break;
default:
break;
}
return true;
}
bool CBarbot::FrameMsg(CFrameMsg *msg) {
if (!_fieldC4 || _frameNum != -1 || _field148 != -1
|| (msg->_ticks - _field14C) <= 5000
|| (msg->_ticks - _field150) <= 1000)
return true;
if (!_drunkFlag) {
if (++_field154 > 2) {
playRange(_frames[0]);
playRange(_frames[1], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[1]._endFrame;
_field154 = 0;
return true;
}
switch (g_vm->getRandomNumber(5)) {
case 0:
playRange(_frames[4], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[4]._endFrame;
break;
case 1:
playRange(_frames[10], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[10]._endFrame;
break;
case 2:
playRange(_frames[7], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[7]._endFrame;
break;
case 3:
playRange(_frames[0]);
playRange(_frames[1], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[1]._endFrame;
break;
case 4:
playRange(_frames[3], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[3]._endFrame;
break;
case 5:
if (!_field160 && !_visCenterOnCounter) {
playRange(_frames[15], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[15]._endFrame;
}
break;
default:
break;
}
} else {
static const int CASES[23] = {
0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7
};
switch (CASES[g_vm->getRandomNumber(22)]) {
case 0:
playRange(_frames[13], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[13]._endFrame;
break;
case 1:
playRange(_frames[4], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[4]._endFrame;
break;
case 2:
playRange(_frames[8], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[8]._endFrame;
break;
case 3:
playRange(_frames[7], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[7]._endFrame;
break;
case 4:
playRange(_frames[10], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[10]._endFrame;
break;
case 5:
playRange(_frames[2], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[2]._endFrame;
break;
case 6:
playRange(_frames[6], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[6]._endFrame;
break;
default:
playRange(_frames[3], MOVIE_NOTIFY_OBJECT);
_field148 = _frames[3]._endFrame;
break;
}
}
return true;
}
bool CBarbot::LoadSuccessMsg(CLoadSuccessMsg *msg) {
_field14C = _field150 = getTicksCount();
_frameNum = -1;
_field148 = -1;
return true;
}
bool CBarbot::MovieFrameMsg(CMovieFrameMsg *msg) {
if (msg->_frameNumber == _frames[29]._startFrame) {
playSound(TRANSLATE("c#2.wav", "c#62.wav"), _volume);
} else if (msg->_frameNumber == _frames[55]._startFrame
|| msg->_frameNumber == _frames[32]._startFrame) {
// Finished giving the Barbot a glass
CStatusChangeMsg statusMsg;
statusMsg._newStatus = 0;
statusMsg.execute("PickUpGlass");
if (_glassContent == GG_EMPTY) {
// I'd rather see that full of Starling Puret
startTalking(this, 250574);
} else if (_glassContent > GG_EMPTY) {
// What's this?
startTalking(this, 250580);
petSetArea(PET_CONVERSATION);
}
_glassContent = GG_DEFAULT;
} else if (msg->_frameNumber == _frames[36]._startFrame) {
CVisibleMsg visibleMsg(false);
visibleMsg.execute("LemonOnBar");
} else if (msg->_frameNumber == _frames[35]._startFrame) {
CVisibleMsg visibleMsg(false);
visibleMsg.execute("TVOnBar");
}
return true;
}
bool CBarbot::TimerMsg(CTimerMsg *msg) {
if (!_fieldC4 && compareRoomNameTo("Bar")) {
CParrotSpeakMsg speakMsg("Barbot", "AskForDrink");
speakMsg.execute("PerchedParrot");
addTimer(10000 + getRandomNumber(20000));
}
return true;
}
void CBarbot::playRange(const FrameRange &range, uint flags) {
playMovie(range._startFrame, range._endFrame, flags);
}
} // End of namespace Titanic

View File

@@ -0,0 +1,116 @@
/* 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/>.
*
*/
#ifndef TITANIC_BARBOT_H
#define TITANIC_BARBOT_H
#include "titanic/npcs/true_talk_npc.h"
#include "titanic/messages/messages.h"
namespace Titanic {
enum GlassGiven { GG_DEFAULT = -1, GG_EMPTY = 0, GG_CONDIMENT = 1, GG_BIRD = 3 };
class CBarbot : public CTrueTalkNPC {
struct FrameRange {
int _startFrame;
int _endFrame;
FrameRange() : _startFrame(0), _endFrame(0) {}
};
class FrameRanges : public Common::Array<FrameRange> {
public:
FrameRanges();
};
DECLARE_MESSAGE_MAP;
bool ActMsg(CActMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool TurnOn(CTurnOn *msg);
bool TurnOff(CTurnOff *msg);
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool MovieEndMsg(CMovieEndMsg *msg);
bool TrueTalkSelfQueueAnimSetMsg(CTrueTalkSelfQueueAnimSetMsg *msg);
bool TrueTalkQueueUpAnimSetMsg(CTrueTalkQueueUpAnimSetMsg *msg);
bool TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg);
bool TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg);
bool FrameMsg(CFrameMsg *msg);
bool LoadSuccessMsg(CLoadSuccessMsg *msg);
bool MovieFrameMsg(CMovieFrameMsg *msg);
bool EnterRoomMsg(CEnterRoomMsg *msg);
bool TimerMsg(CTimerMsg *msg);
private:
static int _timesCalled;
private:
FrameRanges _frames;
int _field108;
int _field10C;
int _field110;
bool _addedLemon;
bool _addedTV;
bool _addedPuret;
int _field120;
int _field124;
bool _visCenterOnCounter;
bool _addedVodka;
bool _gottenDrunk;
int _field134;
int _field138;
int _field13C;
int _volume;
int _frameNum;
int _field148;
int _field14C;
int _field150;
int _field154;
GlassGiven _glassContent;
bool _drunkFlag;
int _field160;
private:
/**
* Plays a given range of movie frames
*/
void playRange(const FrameRange &range, uint flags = 0);
/**
* Returns true if one of the ingredients (with the exception of Vodka)
* is missing from the concoction
*/
bool areIngredientsMissing() const {
return !_addedPuret || !_addedLemon || !_addedVodka;
}
public:
CLASSDEF;
CBarbot();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_BARBOT_H */

View File

@@ -0,0 +1,301 @@
/* 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/bellbot.h"
#include "titanic/carry/carry.h"
#include "titanic/core/room_item.h"
#include "titanic/pet_control/pet_control.h"
#include "titanic/game_manager.h"
#include "titanic/translation.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CBellBot, CTrueTalkNPC)
ON_MESSAGE(OnSummonBotMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(MovieEndMsg)
ON_MESSAGE(Use)
ON_MESSAGE(DismissBotMsg)
ON_MESSAGE(TrueTalkTriggerActionMsg)
ON_MESSAGE(MovieFrameMsg)
ON_MESSAGE(PutBotBackInHisBoxMsg)
ON_MESSAGE(NPCPlayIdleAnimationMsg)
ON_MESSAGE(NPCPlayTalkingAnimationMsg)
ON_MESSAGE(TimerMsg)
ON_MESSAGE(TrueTalkGetStateValueMsg)
ON_MESSAGE(TrueTalkNotifySpeechEndedMsg)
END_MESSAGE_MAP()
CBellBot::CBellBot() : CTrueTalkNPC(), _field108(0) {
}
void CBellBot::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_field108, indent);
CTrueTalkNPC::save(file, indent);
}
void CBellBot::load(SimpleFile *file) {
file->readNumber();
_field108 = file->readNumber();
CTrueTalkNPC::load(file);
}
bool CBellBot::OnSummonBotMsg(COnSummonBotMsg *msg) {
if (msg->_value == 1) {
_npcFlags |= NPCFLAG_MOVE_LOOP;
} else {
struct RoomWave {
const char *_room;
const char *_enSound;
const char *_deSound;
};
static const RoomWave ROOM_WAVES[8] = {
{ "EmbLobby", "z#193.wav", "z#723.wav" },
{ "PromenadeDeck", "z#191.wav", "z#721.wav" },
{ "Arboretum", "z#195.wav", "z#725.wav" },
{ "Frozen Arboretum", "z#195.wav", "z#725.wav" },
{ "Bar", "z#194.wav", "z#724.wav" },
{ "MusicRoom", "z#192.wav", "z#722.wav" },
{ "MusicRoomLobby", "z#192.wav", "z#722.wav" },
{ "1stClassRestaurant", "z#190.wav", "z#720.wav" }
};
int idx;
for (idx = 0; idx < 8; ++idx) {
if (compareRoomNameTo(ROOM_WAVES[idx]._room)) {
playSound(TRANSLATE(ROOM_WAVES[idx]._enSound, ROOM_WAVES[idx]._deSound));
break;
}
}
if (idx == 8)
playSound(TRANSLATE("z#147.wav", "z#703.wav"));
sleep(2000);
_npcFlags &= ~NPCFLAG_MOVE_LOOP;
}
getGameManager()->_gameState.setMode(GSMODE_CUTSCENE);
playClip("Walk On", MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
movieEvent();
_npcFlags |= NPCFLAG_MOVING;
return true;
}
bool CBellBot::EnterViewMsg(CEnterViewMsg *msg) {
// WORKAROUND: Calling bot in front of doors and then going through them
// can leave it in the view. Detect this and properly remove him when
// the player returns to that view
if (!hasActiveMovie() && msg->_newView == getParent()
&& getPetControl()->canSummonBot("BellBot"))
petMoveToHiddenRoom();
return true;
}
bool CBellBot::LeaveViewMsg(CLeaveViewMsg *msg) {
if (_npcFlags & NPCFLAG_MOVING) {
performAction(true);
_npcFlags &= ~NPCFLAG_START_IDLING;
CDismissBotMsg dismissMsg;
dismissMsg.execute(this);
}
return true;
}
bool CBellBot::MovieEndMsg(CMovieEndMsg *msg) {
if (!(_npcFlags & NPCFLAG_MOVING)) {
CTrueTalkNPC::MovieEndMsg(msg);
} else if (clipExistsByEnd("Walk On", msg->_endFrame)) {
getGameManager()->_gameState.setMode(GSMODE_INTERACTIVE);
setPosition(Point(80, 10));
loadFrame(543);
_npcFlags |= NPCFLAG_START_IDLING;
if (_npcFlags & NPCFLAG_MOVE_LOOP) {
startTalking(this, 157);
_npcFlags &= ~NPCFLAG_MOVE_LOOP;
}
setTalking(this, true);
petSetArea(PET_CONVERSATION);
} else if (clipExistsByEnd("Walk Off", msg->_endFrame)) {
CPutBotBackInHisBoxMsg boxMsg;
boxMsg.execute(this);
if (_npcFlags & NPCFLAG_MOVE_START)
startAnimTimer("SummonDoorbot", 1500);
} else {
CTrueTalkNPC::MovieEndMsg(msg);
}
return true;
}
bool CBellBot::Use(CUse *msg) {
CCarry *item = dynamic_cast<CCarry *>(msg->_item);
assert(item);
item->_npcUse = "Bellbot";
return true;
}
bool CBellBot::DismissBotMsg(CDismissBotMsg *msg) {
if (_npcFlags & NPCFLAG_MOVING) {
playClip("Walk Off", MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
movieEvent();
if (_npcFlags & NPCFLAG_START_IDLING) {
_npcFlags &= ~NPCFLAG_START_IDLING;
performAction(true);
} else {
performAction(false);
}
CActMsg actMsg("BellbotDismissed");
actMsg.execute("BotIdleSummons");
}
return true;
}
bool CBellBot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
switch (msg->_action) {
case 1:
case 28: {
_npcFlags &= ~NPCFLAG_IDLING;
CDismissBotMsg dismissMsg;
dismissMsg.execute(this);
break;
}
case 5:
_npcFlags &= ~NPCFLAG_MOVE_START;
playClip("Walk Off", MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
movieEvent();
break;
case 17: {
CActMsg actMsg("ThrowTVDownWell");
actMsg.execute("ThrowTVDownWellControl");
break;
}
case 29: {
CActMsg actMsg("BellbotGetLight");
actMsg.execute("BellbotGetLightCutScene");
startTalking(this, 158);
break;
}
default:
break;
}
return true;
}
bool CBellBot::MovieFrameMsg(CMovieFrameMsg *msg) {
if (clipExistsByStart("Walk Off", msg->_frameNumber)
|| clipExistsByStart("Walk On", msg->_frameNumber)) {
setPosition(Point(20, 10));
}
return true;
}
bool CBellBot::PutBotBackInHisBoxMsg(CPutBotBackInHisBoxMsg *msg) {
petMoveToHiddenRoom();
_npcFlags &= ~NPCFLAG_START_IDLING;
return true;
}
bool CBellBot::NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg) {
static const char *const NAMES[] = {
"Sway Side To Side", "Hit Head", "Hands On Hips", "Sway",
"Hand Wave", "Slow Sway", "Lean Backwards",
"Sway Side To Side 2", "Bob Up And Down", nullptr
};
msg->_names = NAMES;
return true;
}
bool CBellBot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
static const char *const NAMES[] = {
"Hand On Hip Talking", "Hand On Hip Talking", "Hand On Hip Talking",
"Sway Side To Side", "Lean Forward", "Hit Head", "Confidential Talking",
"Hands On Hips", "Hands On Hips", "Hands On Hips", "Sway", "Laugh",
"Hand Wave", "Slow Sway", "Lean Backwards", "Sway Side To Side 2",
"Bob Up And Down", "Elbow In Hand", "Elbow In Hand", "Elbow In Hand",
nullptr
};
if (msg->_value2 == 2)
playClip("Mother Frame");
else
msg->_names = NAMES;
return true;
}
bool CBellBot::TimerMsg(CTimerMsg *msg) {
if (msg->_action == "SummonDoorbot") {
CRoomItem *room = getRoom();
if (room) {
CSummonBotMsg botMsg;
botMsg._npcName = "Doorbot";
botMsg._value = 2;
botMsg.execute(room);
}
_npcFlags &= ~NPCFLAG_MOVE_START;
} else {
CTrueTalkNPC::TimerMsg(msg);
}
return true;
}
bool CBellBot::TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg) {
CPetControl *pet = getPetControl();
bool isYourStateroom = pet ? pet->isFirstClassSuite() : false;
if (msg->_stateNum == 7)
msg->_stateVal = isYourStateroom ? 1 : 0;
return true;
}
bool CBellBot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) {
CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(msg);
if (msg->_dialogueId == TRANSLATE(20991, 20997)) {
petDismissBot("DoorBot");
getGameManager()->unlockInputHandler();
}
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,64 @@
/* 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/>.
*
*/
#ifndef TITANIC_BELLBOT_H
#define TITANIC_BELLBOT_H
#include "titanic/npcs/true_talk_npc.h"
namespace Titanic {
class CBellBot : public CTrueTalkNPC {
DECLARE_MESSAGE_MAP;
bool OnSummonBotMsg(COnSummonBotMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool MovieEndMsg(CMovieEndMsg *msg);
bool Use(CUse *msg);
bool DismissBotMsg(CDismissBotMsg *msg);
bool TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg);
bool MovieFrameMsg(CMovieFrameMsg *msg);
bool PutBotBackInHisBoxMsg(CPutBotBackInHisBoxMsg *msg);
bool NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg);
bool NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg);
bool TimerMsg(CTimerMsg *msg);
bool TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg);
bool TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg);
private:
int _field108;
public:
CLASSDEF;
CBellBot();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_BELLBOT_H */

View File

@@ -0,0 +1,468 @@
/* 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/bilge_succubus.h"
#include "titanic/carry/chicken.h"
#include "titanic/core/view_item.h"
#include "titanic/pet_control/pet_control.h"
#include "titanic/translation.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CBilgeSuccUBus, CSuccUBus)
ON_MESSAGE(FrameMsg)
ON_MESSAGE(PETReceiveMsg)
ON_MESSAGE(PETDeliverMsg)
ON_MESSAGE(MovieEndMsg)
ON_MESSAGE(MouseButtonDownMsg)
ON_MESSAGE(SubAcceptCCarryMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(TrueTalkGetStateValueMsg)
ON_MESSAGE(TurnOn)
ON_MESSAGE(TurnOff)
END_MESSAGE_MAP()
CBilgeSuccUBus::CBilgeSuccUBus() : CSuccUBus(),
_sneezing2StartFrame(-1), _sneezing2EndFrame(-1),
_sneezing1StartFrame(-1), _sneezing1EndFrame(-1) {
}
void CBilgeSuccUBus::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_sneezing2StartFrame, indent);
file->writeNumberLine(_sneezing2EndFrame, indent);
file->writeNumberLine(_sneezing1StartFrame, indent);
file->writeNumberLine(_sneezing1EndFrame, indent);
CSuccUBus::save(file, indent);
}
void CBilgeSuccUBus::load(SimpleFile *file) {
file->readNumber();
_sneezing2StartFrame = file->readNumber();
_sneezing2EndFrame = file->readNumber();
_sneezing1StartFrame = file->readNumber();
_sneezing1EndFrame = file->readNumber();
CSuccUBus::load(file);
}
bool CBilgeSuccUBus::FrameMsg(CFrameMsg *msg) {
return true;
}
bool CBilgeSuccUBus::PETReceiveMsg(CPETReceiveMsg *msg) {
CPetControl *pet = getPetControl();
if (_motherBlocked) {
// Mother hasn't yet been unblocked, so don't receive anything
if (_receiveStartFrame >= 0)
playMovie(_receiveStartFrame, _receiveEndFrame, MOVIE_WAIT_FOR_FINISH);
if (_afterReceiveStartFrame >= 0)
playMovie(_afterReceiveStartFrame, _afterReceiveEndFrame, MOVIE_WAIT_FOR_FINISH);
playSound(TRANSLATE("z#28.wav", "z#559.wav"), 70);
} else if (!_isOn) {
petDisplayMessage(2, SUCCUBUS_IS_IN_STANDBY);
return false;
} else if (!pet) {
return false;
} else {
uint roomFlags = pet->getRoomFlags();
CGameObject *mailObject = findMailByFlags(
_fuseboxOn && compareRoomNameTo("Titania") ? RFC_TITANIA : _flagsComparison,
roomFlags);
if (mailObject) {
startTalking(this, 230004);
_mailP = mailObject;
if (_receiveStartFrame >= 0)
playMovie(_receiveStartFrame, _receiveEndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
} else {
petDisplayMessage(2, NOTHING_TO_DELIVER);
}
}
return true;
}
bool CBilgeSuccUBus::PETDeliverMsg(CPETDeliverMsg *msg) {
CPetControl *pet = getPetControl();
if (!_isOn || !pet)
return true;
uint petRoomFlags = pet->getRoomFlags();
CGameObject *mailObject = findMail(petRoomFlags);
if (!mailObject) {
petDisplayMessage(2, NOTHING_IN_SUCCUBUS_TRAY);
return true;
}
_sendLost = false;
_mailP = mailObject;
uint roomFlags = _destRoomFlags;
if (!pet->isSuccUBusDest(roomFlags) || getPassengerClass() > pet->getMailDestClass(roomFlags)) {
roomFlags = pet->getSpecialRoomFlags("BilgeRoom");
_sendLost = true;
}
_isChicken = mailObject->getName() == "Chicken";
_isFeathers = mailObject->getName() == "Feathers";
_sendAction = SA_SENT;
if (_motherBlocked) {
if (_isFeathers) {
startTalking(this, 230022);
_sendAction = SA_FEATHERS;
if (_sendStartFrame >= 0)
playMovie(_sendStartFrame, _sendEndFrame, MOVIE_NOTIFY_OBJECT);
if (_sneezing2StartFrame >= 0) {
playMovie(_trayOutStartFrame, _trayOutEndFrame, MOVIE_WAIT_FOR_FINISH);
playMovie(_sneezing1StartFrame, _sneezing1EndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
playMovie(_sneezing2StartFrame, _sneezing2EndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
lockMouse();
}
} else {
startTalking(this, 230012);
_sendAction = SA_EATEN;
if (_sendStartFrame >= 0)
playMovie(_sendStartFrame, _sendEndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
if (_receiveStartFrame >= 0)
playMovie(_receiveStartFrame, _receiveEndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
if (_afterReceiveStartFrame >= 0)
playMovie(_afterReceiveStartFrame, _afterReceiveEndFrame, MOVIE_WAIT_FOR_FINISH);
}
} else {
if (_isFeathers) {
startTalking(this, 230022);
_sendAction = SA_BILGE_FEATHERS;
if (_sendStartFrame >= 0)
playMovie(_sendStartFrame, _sendEndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
if (_receiveStartFrame >= 0)
playMovie(_receiveStartFrame, _receiveEndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
if (_afterReceiveStartFrame >= 0)
playMovie(_afterReceiveStartFrame, _afterReceiveEndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
} else {
sendMail(petRoomFlags, roomFlags);
startTalking(this, 230012);
if (_sendStartFrame >= 0) {
_sendAction = SA_BILGE_SENT;
playMovie(_sendStartFrame, _sendEndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
}
}
}
return true;
}
bool CBilgeSuccUBus::MovieEndMsg(CMovieEndMsg *msg) {
CPetControl *pet = getPetControl();
if (msg->_endFrame == _trayOutEndFrame) {
if (_offStartFrame >= 0)
playSound(TRANSLATE("z#27.wav", "z#558.wav"));
} else if (msg->_endFrame == _offEndFrame) {
if (_endingStartFrame >= 0)
playSound(TRANSLATE("z#30.wav", "z#561.wav"));
} else {
if (msg->_endFrame == _onEndFrame && pet) {
if (_motherBlocked) {
startTalking(this, getRandomNumber(1) ? 230062 : 230063);
} else if (!findMail(pet->getRoomFlags())) {
switch (getRandomNumber(4)) {
case 0:
startTalking(this, 230001);
break;
case 1:
startTalking(this, 230002);
break;
case 2:
startTalking(this, 230003);
break;
default:
break;
}
}
} else if (msg->_endFrame == _sendEndFrame) {
switch (_sendAction) {
case SA_EATEN:
stopSound(_soundHandle, 1);
_soundHandle = playSound(TRANSLATE("z#3.wav", "z#539.wav"), 1);
break;
case SA_BILGE_FEATHERS:
stopSound(_soundHandle);
_soundHandle = playSound(TRANSLATE("z#12.wav", "z#532.wav"));
break;
case SA_BILGE_SENT:
if (_isChicken) {
startTalking(this, 230018);
_isChicken = false;
} else {
startTalking(this, 230013);
}
break;
case SA_BILGE_EATEN:
startTalking(this, 230017);
break;
default:
break;
}
CSUBTransition transMsg;
transMsg.execute(this);
} else if (msg->_endFrame == _receiveEndFrame) {
if (_mailP) {
_mailP->petAddToInventory();
CVisibleMsg visibleMsg(true);
visibleMsg.execute(_mailP);
_mailP = nullptr;
petSetArea(PET_INVENTORY);
CSUBTransition transMsg;
transMsg.execute(this);
}
} else if (msg->_endFrame == _sneezing1EndFrame) {
playSound(TRANSLATE("z#25.wav", "z#556.wav"), 70);
playSound(TRANSLATE("z#24.wav", "z#555.wav"), 70);
} else if (msg->_endFrame == _sneezing2EndFrame) {
changeView("BilgeRoomWith.Node 1.N", "");
_motherBlocked = false;
resetMail();
if (_mailP) {
_mailP->petAddToInventory();
CVisibleMsg visibleMsg(true);
visibleMsg.execute(_mailP);
_mailP = nullptr;
petSetArea(PET_INVENTORY);
}
startTalking(this, 150);
CBodyInBilgeRoomMsg bodyMsg;
bodyMsg.execute("Service Elevator Entity");
unlockMouse();
_sendAction = SA_SENT;
} else {
_sendAction = SA_SENT;
}
}
return true;
}
bool CBilgeSuccUBus::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
if (_isOn) {
switch (getRandomNumber(4)) {
case 0:
case 4: {
_isOn = false;
CTurnOff offMsg;
offMsg.execute(this);
break;
}
case 1:
startTalking(this, 230055);
break;
case 2:
startTalking(this, 230067);
break;
case 3:
startTalking(this, 230045);
break;
default:
break;
}
} else {
CTurnOn onMsg;
onMsg.execute(this);
_isOn = true;
}
return true;
}
bool CBilgeSuccUBus::SubAcceptCCarryMsg(CSubAcceptCCarryMsg *msg) {
CPetControl *pet = getPetControl();
if (!msg->_item)
return false;
CCarry *item = dynamic_cast<CCarry *>(msg->_item);
if (!_isOn || !pet || !item) {
item->petAddToInventory();
return true;
}
uint petRoomFlags = pet->getRoomFlags();
if (mailExists(petRoomFlags)) {
petDisplayMessage(2, SUCCUBUS_SINGLE_DELIVERY);
item->petAddToInventory();
return true;
}
petContainerRemove(item);
pet->phonographAction("");
item->setVisible(false);
playSound(TRANSLATE("z#23.wav", "z#554.wav"));
CChicken *chicken = dynamic_cast<CChicken *>(item);
bool chickenFlag = chicken ? chicken->_condiment == "None" : false;
if (chickenFlag) {
if (_okStartFrame >= 0) {
startTalking(this, 70219);
playMovie(_okStartFrame, _okEndFrame, 0);
}
if (_sendStartFrame >= 0) {
_sendAction = SA_BILGE_EATEN;
playMovie(_sendStartFrame, _sendEndFrame, MOVIE_NOTIFY_OBJECT);
}
CViewItem *view = parseView(item->_fullViewName);
if (view) {
item->setVisible(false);
setPosition(item->_origPos);
item->moveUnder(view);
CSUBTransition transMsg;
transMsg.execute(this);
} else {
return false;
}
} else {
item->addMail(petRoomFlags);
if (_okStartFrame >= 0)
playMovie(_okStartFrame, _okEndFrame, 0);
petSetArea(PET_REMOTE);
CSUBTransition transMsg;
transMsg.execute(this);
}
return true;
}
bool CBilgeSuccUBus::EnterViewMsg(CEnterViewMsg *msg) {
petSetRemoteTarget();
_mailP = nullptr;
if (_initialStartFrame >= 0)
loadFrame(_initialStartFrame);
return true;
}
bool CBilgeSuccUBus::LeaveViewMsg(CLeaveViewMsg *msg) {
petDisplayMessage(2, BLANK);
petClear();
if (_soundHandle != -1) {
stopSound(_soundHandle);
_soundHandle = -1;
}
if (_isOn) {
_isOn = false;
if (_offStartFrame >= 0)
playSound(TRANSLATE("z#27.wav", "z#558.wav"));
}
performAction(true);
CSUBTransition transMsg;
transMsg.execute(this);
return true;
}
bool CBilgeSuccUBus::TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg) {
if (msg->_stateNum == 1)
msg->_stateVal = _isOn;
return true;
}
bool CBilgeSuccUBus::TurnOn(CTurnOn *msg) {
CPetControl *pet = getPetControl();
if (pet) {
if (_onStartFrame >= 0) {
playMovie(_onStartFrame, _onEndFrame, MOVIE_NOTIFY_OBJECT);
playSound(TRANSLATE("z#26.wav", "z#557.wav"));
}
if (mailExists(pet->getRoomFlags()) && _okStartFrame >= 0)
playMovie(_okStartFrame, _okEndFrame, 0);
_isOn = true;
CSUBTransition transMsg;
transMsg.execute(this);
setTalking(this, true);
petSetArea(PET_REMOTE);
petHighlightGlyph(16);
}
return true;
}
bool CBilgeSuccUBus::TurnOff(CTurnOff *msg) {
CPetControl *pet = getPetControl();
if (pet && mailExists(pet->getRoomFlags()) && _trayOutStartFrame >= 0)
playMovie(_trayOutStartFrame, _trayOutEndFrame, MOVIE_NOTIFY_OBJECT);
else if (_trayOutEndFrame >= 0)
playMovie(_trayOutEndFrame, _trayOutEndFrame, MOVIE_NOTIFY_OBJECT);
if (_soundHandle != -1) {
stopSound(_soundHandle);
_soundHandle = -1;
}
if (_offStartFrame >= 0)
playMovie(_offStartFrame, _offEndFrame, MOVIE_NOTIFY_OBJECT);
_isOn = false;
performAction(true);
CSUBTransition transMsg;
transMsg.execute(this);
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,64 @@
/* 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/>.
*
*/
#ifndef TITANIC_BILGE_SUCCUBUS_H
#define TITANIC_BILGE_SUCCUBUS_H
#include "titanic/npcs/succubus.h"
namespace Titanic {
class CBilgeSuccUBus : public CSuccUBus {
DECLARE_MESSAGE_MAP;
bool FrameMsg(CFrameMsg *msg);
bool PETReceiveMsg(CPETReceiveMsg *msg);
bool PETDeliverMsg(CPETDeliverMsg *msg);
bool MovieEndMsg(CMovieEndMsg *msg);
bool MouseButtonDownMsg(CMouseButtonDownMsg *msg);
bool SubAcceptCCarryMsg(CSubAcceptCCarryMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg);
bool TurnOn(CTurnOn *msg);
bool TurnOff(CTurnOff *msg);
public:
int _sneezing2StartFrame;
int _sneezing2EndFrame;
int _sneezing1StartFrame;
int _sneezing1EndFrame;
public:
CLASSDEF;
CBilgeSuccUBus();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_BILGE_SUCCUBUS_H */

View File

@@ -0,0 +1,80 @@
/* 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/callbot.h"
#include "titanic/core/room_item.h"
#include "titanic/game_manager.h"
#include "titanic/titanic.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CCallBot, CGameObject)
ON_MESSAGE(TurnOn)
ON_MESSAGE(EnterViewMsg)
END_MESSAGE_MAP()
CCallBot::CCallBot() : CGameObject(), _enabled(false) {
}
void CCallBot::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeQuotedLine(_npcName, indent);
file->writeNumberLine(_enabled, indent);
CGameObject::save(file, indent);
}
void CCallBot::load(SimpleFile *file) {
file->readNumber();
_npcName = file->readString();
_enabled = file->readNumber();
CGameObject::load(file);
}
bool CCallBot::TurnOn(CTurnOn *msg) {
_enabled = true;
return true;
}
bool CCallBot::EnterViewMsg(CEnterViewMsg *msg) {
if (_enabled) {
CRoomItem *room = getRoom();
if (room) {
CGameState &gs = getGameManager()->_gameState;
gs.setMode(GSMODE_CUTSCENE);
CSummonBotQueryMsg queryMsg;
queryMsg._npcName = _npcName;
if (queryMsg.execute(room))
petOnSummonBot(_npcName, 0);
gs.setMode(GSMODE_INTERACTIVE);
}
_enabled = false;
}
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,53 @@
/* 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/>.
*
*/
#ifndef TITANIC_CALLBOT_H
#define TITANIC_CALLBOT_H
#include "titanic/core/game_object.h"
namespace Titanic {
class CCallBot : public CGameObject {
DECLARE_MESSAGE_MAP;
bool TurnOn(CTurnOn *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
protected:
CString _npcName;
bool _enabled;
public:
CLASSDEF;
CCallBot();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_CALLBOT_H */

View File

@@ -0,0 +1,78 @@
/* 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/character.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CCharacter, CGameObject)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(TurnOn)
ON_MESSAGE(TurnOff)
END_MESSAGE_MAP()
CCharacter::CCharacter() : CGameObject(), _startFrame(0), _endFrame(0), _fieldC4(1) {
}
void CCharacter::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_startFrame, indent);
file->writeNumberLine(_endFrame, indent);
file->writeNumberLine(_fieldC4, indent);
file->writeQuotedLine(_charName, indent);
CGameObject::save(file, indent);
}
void CCharacter::load(SimpleFile *file) {
file->readNumber();
_startFrame = file->readNumber();
_endFrame = file->readNumber();
_fieldC4 = file->readNumber();
_charName = file->readString();
CGameObject::load(file);
}
bool CCharacter::LeaveViewMsg(CLeaveViewMsg *msg) {
CTurnOff offMsg;
offMsg.execute(this);
return true;
}
bool CCharacter::TurnOn(CTurnOn *msg) {
if (!_fieldC4)
_fieldC4 = 1;
return true;
}
bool CCharacter::TurnOff(CTurnOff *msg) {
CString charName = getName();
if (charName == "Deskbot" || charName == "Barbot" || charName == "SuccUBus") {
_fieldC4 = 0;
}
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,56 @@
/* 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/>.
*
*/
#ifndef TITANIC_CHARACTER_H
#define TITANIC_CHARACTER_H
#include "titanic/core/game_object.h"
namespace Titanic {
class CCharacter : public CGameObject {
DECLARE_MESSAGE_MAP;
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool TurnOn(CTurnOn *msg);
bool TurnOff(CTurnOff *msg);
protected:
int _startFrame;
int _endFrame;
int _fieldC4;
CString _charName;
public:
CLASSDEF;
CCharacter();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_CHARACTER_H */

View File

@@ -0,0 +1,363 @@
/* 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/deskbot.h"
#include "titanic/pet_control/pet_control.h"
#include "titanic/game_manager.h"
#include "titanic/translation.h"
namespace Titanic {
static const char *const TALKING_NAMES[] = {
"NeutralTalking", "HandFidget1", "HandFidget2", "LookingAround",
"FriendlyTalking", "MoreRudeness", "HandUp", "TapFingers",
"WaveOn", "WaveArmsAround", "HandsOverEdge",
nullptr
};
static const char *const IDLE_NAMES[] = {
"WaveOn", "HandFidget1", "HandFidget2", "TapFingers", "HandsOverEdge",
nullptr
};
BEGIN_MESSAGE_MAP(CDeskbot, CTrueTalkNPC)
ON_MESSAGE(TurnOn)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(ActMsg)
ON_MESSAGE(MovieEndMsg)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(TrueTalkTriggerActionMsg)
ON_MESSAGE(NPCPlayTalkingAnimationMsg)
ON_MESSAGE(NPCPlayIdleAnimationMsg)
ON_MESSAGE(TrueTalkNotifySpeechStartedMsg)
ON_MESSAGE(TrueTalkNotifySpeechEndedMsg)
ON_MESSAGE(TurnOff)
END_MESSAGE_MAP()
int CDeskbot::_v1;
int CDeskbot::_v2;
CDeskbot::CDeskbot() : CTrueTalkNPC(), _deskbotActive(false),
_classNum(NO_CLASS) {
}
void CDeskbot::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_v1, indent);
file->writeNumberLine(_v2, indent);
file->writeNumberLine(_deskbotActive, indent);
file->writeNumberLine(_classNum, indent);
CTrueTalkNPC::save(file, indent);
}
void CDeskbot::load(SimpleFile *file) {
file->readNumber();
_v1 = file->readNumber();
_v2 = file->readNumber();
_deskbotActive = file->readNumber();
_classNum = (PassengerClass)file->readNumber();
CTrueTalkNPC::load(file);
}
bool CDeskbot::TurnOn(CTurnOn *msg) {
if (!_deskbotActive) {
setVisible(true);
playClip("BellRinging");
playClip("Opening", MOVIE_NOTIFY_OBJECT);
playSound(TRANSLATE("b#69.wav", "b#47.wav"));
petSetArea(PET_CONVERSATION);
_npcFlags |= NPCFLAG_MOVE_START;
_deskbotActive = true;
}
return true;
}
bool CDeskbot::EnterViewMsg(CEnterViewMsg *msg) {
setVisible(false);
_deskbotActive = false;
_fieldC4 = 0;
loadFrame(625);
// WORKAROUND: If loading directly from the launcher when Marcinta
// is active, reset the active NPC back to none at the same time
CPetControl *pet = getPetControl();
pet->resetActiveNPC();
return true;
}
bool CDeskbot::ActMsg(CActMsg *msg) {
if (msg->_action == "2ndClassUpgrade" && getPassengerClass() > 2) {
startTalking(this, 140, findView());
}
return true;
}
bool CDeskbot::MovieEndMsg(CMovieEndMsg *msg) {
bool flag = false;
if (_npcFlags & NPCFLAG_MOVING) {
if (_classNum) {
petSetArea(PET_ROOMS);
decTransitions();
unlockMouse();
playSound(TRANSLATE("z#47.wav", "z#578.wav"));
_classNum = NO_CLASS;
}
_npcFlags &= ~NPCFLAG_MOVING;
}
if (_npcFlags & NPCFLAG_MOVE_LOOP) {
_deskbotActive = false;
_npcFlags &= ~(NPCFLAG_MOVE_LOOP | NPCFLAG_MOVE_START);
if (_npcFlags & NPCFLAG_MOVE_FINISH) {
CTurnOn turnOn;
turnOn.execute("EmbBellbotTrigger");
unlockMouse();
getGameManager()->lockInputHandler();
changeView("EmbLobby.Node 4.N", "");
} else if (_npcFlags & NPCFLAG_MOVE_LEFT) {
CTurnOn turnOn;
turnOn.execute("EmbDoorBotTrigger");
unlockMouse();
changeView("EmbLobby.Node 4.N", "");
}
_npcFlags &= ~(NPCFLAG_MOVE_FINISH | NPCFLAG_MOVE_LEFT);
flag = true;
}
if (_npcFlags & NPCFLAG_MOVE_START) {
_npcFlags &= ~(NPCFLAG_MOVE_LOOP | NPCFLAG_MOVE_START);
setTalking(this, true, findView());
_npcFlags |= NPCFLAG_START_IDLING;
flag = true;
}
if (!flag)
CTrueTalkNPC::MovieEndMsg(msg);
return true;
}
bool CDeskbot::LeaveViewMsg(CLeaveViewMsg *msg) {
if (_deskbotActive) {
CTurnOff turnOff;
turnOff.execute(this);
}
return true;
}
bool CDeskbot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
switch (msg->_action) {
case 19:
incTransitions();
lockMouse();
petSetArea(PET_CONVERSATION);
playClip("ReprogramPETInHand", MOVIE_NOTIFY_OBJECT);
_npcFlags |= NPCFLAG_MOVING;
_classNum = (PassengerClass)msg->_param1;
switch (_classNum) {
case FIRST_CLASS:
petDisplayMessage(UPGRADED_TO_FIRST_CLASS);
setPassengerClass(_classNum);
petReassignRoom(_classNum);
break;
case SECOND_CLASS:
petDisplayMessage(UPGRADED_TO_SECOND_CLASS);
setPassengerClass(_classNum);
petReassignRoom(_classNum);
break;
case THIRD_CLASS:
setPassengerClass(THIRD_CLASS);
petReassignRoom(_classNum);
break;
default:
break;
}
break;
case 20:
if (getPassengerClass() == 1) {
CPetControl *petControl = getPetControl();
if (petControl)
petControl->changeLocationClass(UNCHECKED);
}
break;
case 21:
if (getPassengerClass() == FIRST_CLASS) {
CPetControl *petControl = getPetControl();
if (petControl)
petControl->changeLocationClass(THIRD_CLASS);
}
break;
case 22:
if (getPassengerClass() == FIRST_CLASS) {
CPetControl *petControl = getPetControl();
if (petControl)
petControl->changeLocationClass(SECOND_CLASS);
}
break;
case 23:
if (getPassengerClass() == FIRST_CLASS) {
CPetControl *petControl = getPetControl();
if (petControl)
petControl->changeLocationClass(FIRST_CLASS);
}
break;
case 26:
{
_npcFlags |= NPCFLAG_MOVE_FINISH;
CTurnOff turnOff;
turnOff.execute(this);
lockMouse();
}
break;
default:
break;
}
return true;
}
bool CDeskbot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
if (msg->_value2 != 2)
msg->_names = TALKING_NAMES;
return true;
}
bool CDeskbot::NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg) {
msg->_names = IDLE_NAMES;
return true;
}
bool CDeskbot::TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg) {
if (_npcFlags & NPCFLAG_MOVE_LOOP)
return true;
CTrueTalkNPC::TrueTalkNotifySpeechStartedMsg(msg);
if (g_language == Common::DE_DEU) {
switch (msg->_dialogueId) {
case 41701:
case 41703:
case 41804:
case 41805:
case 41806:
lockMouse();
break;
default:
break;
}
} else {
switch (msg->_dialogueId) {
case 41684:
case 41686:
case 41787:
case 41788:
case 41789:
lockMouse();
break;
default:
break;
}
}
return true;
}
bool CDeskbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) {
if (_npcFlags & NPCFLAG_MOVE_LOOP)
return true;
CTurnOff turnOff;
CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(msg);
if (g_language == Common::DE_DEU) {
switch (msg->_dialogueId) {
case 41701:
case 41804:
case 41805:
case 41806:
_npcFlags |= NPCFLAG_MOVE_FINISH;
turnOff.execute(this);
break;
case 41703:
_npcFlags |= NPCFLAG_MOVE_LEFT;
turnOff.execute(this);
break;
default:
break;
}
} else {
switch (msg->_dialogueId) {
case 41684:
case 41787:
case 41788:
case 41789:
_npcFlags |= NPCFLAG_MOVE_FINISH;
turnOff.execute(this);
break;
case 41686:
_npcFlags |= NPCFLAG_MOVE_LEFT;
turnOff.execute(this);
break;
default:
break;
}
}
return true;
}
bool CDeskbot::TurnOff(CTurnOff *msg) {
if (_deskbotActive) {
stopMovie();
performAction(1, findView());
_npcFlags = (_npcFlags & ~(NPCFLAG_SPEAKING | NPCFLAG_IDLING | NPCFLAG_START_IDLING)) | NPCFLAG_MOVE_LOOP;
playClip("Closing", MOVIE_WAIT_FOR_FINISH | MOVIE_NOTIFY_OBJECT);
}
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,65 @@
/* 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/>.
*
*/
#ifndef TITANIC_DESKBOT_H
#define TITANIC_DESKBOT_H
#include "titanic/npcs/true_talk_npc.h"
namespace Titanic {
class CDeskbot : public CTrueTalkNPC {
DECLARE_MESSAGE_MAP;
bool TurnOn(CTurnOn *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool ActMsg(CActMsg *msg);
bool MovieEndMsg(CMovieEndMsg *msg);
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg);
bool NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg);
bool NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg);
bool TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg);
bool TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg);
bool TurnOff(CTurnOff *msg);
private:
static int _v1;
static int _v2;
public:
bool _deskbotActive;
PassengerClass _classNum;
public:
CLASSDEF;
CDeskbot();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_DESKBOT_H */

View File

@@ -0,0 +1,609 @@
/* 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/doorbot.h"
#include "titanic/core/room_item.h"
#include "titanic/debugger.h"
#include "titanic/pet_control/pet_control.h"
#include "titanic/translation.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CDoorbot, CTrueTalkNPC)
ON_MESSAGE(MovieEndMsg)
ON_MESSAGE(OnSummonBotMsg)
ON_MESSAGE(TrueTalkTriggerActionMsg)
ON_MESSAGE(DoorbotNeededInHomeMsg)
ON_MESSAGE(DoorbotNeededInElevatorMsg)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(TimerMsg)
ON_MESSAGE(NPCPlayTalkingAnimationMsg)
ON_MESSAGE(NPCPlayIdleAnimationMsg)
ON_MESSAGE(PutBotBackInHisBoxMsg)
ON_MESSAGE(DismissBotMsg)
ON_MESSAGE(MovieFrameMsg)
ON_MESSAGE(TrueTalkNotifySpeechEndedMsg)
ON_MESSAGE(TextInputMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(ActMsg)
END_MESSAGE_MAP()
int CDoorbot::_v1;
int CDoorbot::_v2;
CDoorbot::CDoorbot() : CTrueTalkNPC() {
_introMovieNum = 0;
_timerId = 0;
_field110 = 0;
_field114 = 0;
}
void CDoorbot::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_v1, indent);
file->writeNumberLine(_v2, indent);
file->writeNumberLine(_introMovieNum, indent);
file->writeNumberLine(_timerId, indent);
file->writeNumberLine(_field110, indent);
file->writeNumberLine(_field114, indent);
CTrueTalkNPC::save(file, indent);
}
void CDoorbot::load(SimpleFile *file) {
file->readNumber();
_v1 = file->readNumber();
_v2 = file->readNumber();
_introMovieNum = file->readNumber();
_timerId = file->readNumber();
_field110 = file->readNumber();
_field114 = file->readNumber();
CTrueTalkNPC::load(file);
}
bool CDoorbot::MovieEndMsg(CMovieEndMsg *msg) {
debugC(DEBUG_DETAILED, kDebugScripts, "CDoorbot MovieEndMsg flags=%x v=%d, start=%d, end=%d",
_npcFlags, _introMovieNum, msg->_startFrame, msg->_endFrame);
if (_npcFlags & NPCFLAG_DOORBOT_INTRO) {
switch (_introMovieNum) {
case 3:
startTalking(this, 221482);
_introMovieNum = 4;
break;
case 6:
if (clipExistsByEnd("Cloak On", msg->_endFrame)) {
petShow();
petDecAreaLocks();
stateSetSoundMakerAllowed(true);
changeView("ServiceElevator.Node 1.S");
changeView("ServiceElevator.Node 1.N");
}
break;
case 7:
startTalking(this, 221467);
_introMovieNum = 8;
break;
case 9:
if (msg->_endFrame == 949)
startTalking(this, 221468);
break;
case 11:
changeView("ServiceElevator.Node 1.S");
changeView("MoonEmbLobby.Node 1.NE");
break;
default:
break;
}
CTrueTalkNPC::MovieEndMsg(msg);
} else if (_npcFlags & NPCFLAG_MOVE_LEFT) {
if (clipExistsByEnd("Cloak Off", msg->_endFrame)) {
_npcFlags = (_npcFlags & ~NPCFLAG_DOORBOT_IN_HOME) | NPCFLAG_START_IDLING;
setTalking(this, false);
startTalking(this, 221474);
_npcFlags |= NPCFLAG_DOORBOT_INTRO;
_introMovieNum = 0;
} else if (clipExistsByEnd("Cloak On", msg->_endFrame)) {
petShow();
stateSetSoundMakerAllowed(true);
changeView("ServiceElevator.Node 1.S");
} else {
CTrueTalkNPC::MovieEndMsg(msg);
}
} else if (_npcFlags & NPCFLAG_MOVE_END) {
if (clipExistsByEnd("Whizz On Left", msg->_endFrame)
|| clipExistsByEnd("Whizz On Right", msg->_endFrame)) {
setPosition(Point((600 - _bounds.width()) / 2 + 18, 42));
loadFrame(0);
setTalking(this, true);
_npcFlags |= NPCFLAG_START_IDLING;
petSetArea(PET_CONVERSATION);
} else if (clipExistsByEnd("Whizz Off Left", msg->_endFrame)
|| clipExistsByEnd("Whizz Off Right", msg->_endFrame)) {
CPutBotBackInHisBoxMsg boxMsg;
boxMsg.execute(this);
if (_npcFlags & NPCFLAG_SUMMON_BELLBOT)
startAnimTimer("SummonBellbot", 1500);
} else {
CTrueTalkNPC::MovieEndMsg(msg);
}
} else {
CTrueTalkNPC::MovieEndMsg(msg);
}
return true;
}
bool CDoorbot::OnSummonBotMsg(COnSummonBotMsg *msg) {
struct RoomWave {
const char *_room;
const char *_enSound;
const char *_deSound;
};
const RoomWave ROOM_WAVES[8] = {
{ "EmbLobby", "z#186.wav", "z#716.wav" },
{ "PromenadeDeck", "z#184.wav", "z#714.wav" },
{ "Arboretum", "z#188.wav", "z#718.wav" },
{ "Frozen Arboretum", "z#188.wav", "z#718.wav" },
{ "Bar", "z#187.wav", "z#717.wav" },
{ "MusicRoom", "z#185.wav", "z#715.wav" },
{ "MusicRoomLobby", "z#185.wav", "z#715.wav" },
{ "1stClassRestaurant", "z#183.wav", "z#713.wav" },
};
if (msg->_value != -1) {
int idx;
for (idx = 0; idx < 8; ++idx) {
if (compareRoomNameTo(ROOM_WAVES[idx]._room)) {
playSound(TRANSLATE(ROOM_WAVES[idx]._enSound, ROOM_WAVES[idx]._deSound));
break;
}
}
if (idx == 8)
playSound(TRANSLATE("z#146.wav", "z#702.wav"));
sleep(2000);
}
playClip(getRandomNumber(1) ? "Whizz On Left" : "Whizz On Right",
MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
movieEvent();
_npcFlags |= NPCFLAG_MOVE_END;
return true;
}
bool CDoorbot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
switch (msg->_action) {
case 3:
playClip("Cloak On", MOVIE_NOTIFY_OBJECT);
break;
case 4:
_npcFlags = (_npcFlags & ~NPCFLAG_IDLING) | NPCFLAG_SUMMON_BELLBOT;
playClip("Whizz Off Left", MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
break;
case 28: {
_npcFlags &= ~(NPCFLAG_IDLING | NPCFLAG_START_IDLING);
CDismissBotMsg dismissMsg;
dismissMsg.execute(this);
break;
}
default:
break;
}
return true;
}
bool CDoorbot::DoorbotNeededInHomeMsg(CDoorbotNeededInHomeMsg *msg) {
moveToView();
setPosition(Point(90, 42));
_npcFlags = NPCFLAG_MOVE_LEFT;
stopMovie();
playClip("Cloak Off", MOVIE_NOTIFY_OBJECT);
_npcFlags |= NPCFLAG_DOORBOT_IN_HOME;
return true;
}
bool CDoorbot::DoorbotNeededInElevatorMsg(CDoorbotNeededInElevatorMsg *msg) {
moveToView("ServiceElevator.Node 1.N");
setPosition(Point(100, 42));
if (_npcFlags & NPCFLAG_DOORBOT_INTRO) {
_introMovieNum = 7;
_npcFlags |= NPCFLAG_MOVE_RIGHT;
loadFrame(797);
} else {
_npcFlags = 0;
if (msg->_value)
setTalking(this, true);
}
return true;
}
bool CDoorbot::LeaveViewMsg(CLeaveViewMsg *msg) {
if (!(_npcFlags & NPCFLAG_DOORBOT_INTRO) && (_npcFlags & NPCFLAG_MOVE_END)) {
performAction(true);
_npcFlags &= ~NPCFLAG_START_IDLING;
}
return true;
}
bool CDoorbot::TimerMsg(CTimerMsg *msg) {
if (msg->_action == "NPCIdleAnim") {
return CTrueTalkNPC::TimerMsg(msg);
} else if (_npcFlags & NPCFLAG_DOORBOT_INTRO) {
_timerId = 0;
switch (msg->_actionVal) {
case 0:
startTalking(this, 221475);
break;
case 1:
startTalking(this, 221476);
break;
case 2:
startTalking(this, 221477);
break;
case 3:
playClip("DoubleTake Start");
playClip("DoubleTake End");
playClip("DoubleTake Start");
playClip("DoubleTake End", MOVIE_NOTIFY_OBJECT);
_introMovieNum = 3;
break;
case 4:
startTalking(this, 221483);
lockInputHandler();
_field114 = true;
break;
case 5:
lockInputHandler();
mouseDisableControl();
_field114 = true;
startTalking(this, 221485);
break;
case 6:
// Start dragging photograph to PET
CMouseButtonDownMsg::generate();
mouseSetPosition(Point(200, 430), 2500);
_timerId = addTimer(7, 2500, 0);
break;
case 7:
// Drop photograph in PET
CMouseButtonUpMsg::generate();
startTalking(this, 221486);
mouseEnableControl();
unlockInputHandler();
_field114 = false;
disableMouse();
break;
default:
break;
}
} else if (msg->_action == "SummonBellbot") {
CRoomItem *room = getRoom();
if (room) {
CSummonBotMsg botMsg;
botMsg._npcName = "Bellbot";
botMsg.execute(room);
}
_npcFlags &= ~NPCFLAG_SUMMON_BELLBOT;
}
return true;
}
bool CDoorbot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
static const char *const NAMES1[] = {
"Mutter Aside", "Rub Chin", "Drunken Eye Roll", "Drunken Head Move",
"Look down and mutter", "Look side to side", "Gesture forward and around",
"Arms behind back", "Look down", "Rolling around", "Hold face",
"Touch chin", "Cross hands in front", nullptr
};
static const char *const NAMES2[] = {
"SE Talking 1", "SE Talking 2", "SE Talking 3", "SE Talking 4",
nullptr
};
static const char *const NAMES3[] = {
"SE Ask For Help", nullptr
};
if (msg->_value2 != 2) {
if (_npcFlags & NPCFLAG_MOVE_RIGHT) {
switch (_introMovieNum) {
case 8:
case 10:
msg->_names = NAMES2;
break;
case 9:
msg->_names = NAMES3;
_introMovieNum = 10;
break;
default:
break;
}
} else if (_npcFlags & (NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_END)) {
msg->_names = NAMES1;
}
}
return true;
}
bool CDoorbot::NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg) {
static const char *const NAMES[] = {
"Hand swivel", "Prompt Push", "Eye Roll", "Say something", nullptr
};
if (!(_npcFlags & (NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT))
&& (_npcFlags & NPCFLAG_MOVE_END))
msg->_names = NAMES;
return true;
}
bool CDoorbot::PutBotBackInHisBoxMsg(CPutBotBackInHisBoxMsg *msg) {
petMoveToHiddenRoom();
_npcFlags &= ~(NPCFLAG_START_IDLING | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT | NPCFLAG_DOORBOT_INTRO);
if (msg->_value)
performAction(true);
return true;
}
bool CDoorbot::DismissBotMsg(CDismissBotMsg *msg) {
if (_npcFlags & NPCFLAG_MOVE_END) {
playClip(getRandomNumber(1) ? "Whizz Off Left" : "Whizz Off Right",
MOVIE_STOP_PREVIOUS | MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
movieEvent();
if (_npcFlags & NPCFLAG_START_IDLING) {
_npcFlags &= ~NPCFLAG_START_IDLING;
performAction(true);
} else {
performAction(false);
}
CActMsg actMsg("DoorbotDismissed");
actMsg.execute("BotIdleSummons");
}
return true;
}
bool CDoorbot::MovieFrameMsg(CMovieFrameMsg *msg) {
if (clipExistsByStart("Whizz Off Left", msg->_frameNumber)
|| clipExistsByStart("Whizz On Left", msg->_frameNumber)) {
setPosition(Point(20, 42));
} else if (clipExistsByStart("Whizz Off Right", msg->_frameNumber)
|| clipExistsByStart("Whizz On Right", msg->_frameNumber)) {
setPosition(Point(620 - _bounds.width(), 42));
}
return true;
}
bool CDoorbot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) {
CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(msg);
if (_npcFlags & NPCFLAG_DOORBOT_INTRO) {
// Initial speech by Doorbot in
switch (msg->_dialogueId - TRANSLATE(10552, 10563)) {
case 0:
playClip("SE Try Buttons", MOVIE_NOTIFY_OBJECT);
_introMovieNum = 9;
break;
case 1:
enableMouse();
break;
case 5:
playClip("SE Move To Right", MOVIE_NOTIFY_OBJECT);
_introMovieNum = 11;
break;
case 7:
stopAnimTimer(_timerId);
_timerId = addTimer(0, 2500, 0);
break;
case 8:
petShow();
petSetArea(PET_CONVERSATION);
petIncAreaLocks();
stopAnimTimer(_timerId);
_timerId = addTimer(1, 1000, 0);
break;
case 9:
enableMouse();
_introMovieNum = 1;
stopAnimTimer(_timerId);
_timerId = addTimer(2, 10000, 0);
break;
case 10:
if (_introMovieNum == 1) {
stopAnimTimer(_timerId);
_timerId = addTimer(2, getRandomNumber(5000) + 5000, 0);
}
break;
case 11:
case 12:
disableMouse();
startTalking(this, 221480);
break;
case 13:
startTalking(this, 221481);
break;
case 14:
stopAnimTimer(_timerId);
_timerId = 0;
if (_field110 == 2) {
playClip("Cloak On", MOVIE_NOTIFY_OBJECT);
_introMovieNum = 6;
} else {
_timerId = addTimer(3, 2000, 0);
}
break;
case 15: {
CActMsg actMsg("BecomeGettable");
actMsg.execute("Photograph");
enableMouse();
stopAnimTimer(_timerId);
_timerId = addTimer(4, 5000, 0);
break;
}
case 16:
// Start moving cursor to photograph
mouseDisableControl();
mouseSetPosition(Point(600, 250), 2500);
_timerId = addTimer(6, 2500, 0);
break;
case 17:
if (_field110 != 2) {
stopAnimTimer(_timerId);
_timerId = addTimer(5, 3000, 0);
}
break;
case 18:
mouseSetPosition(Point(200, 430), 2500);
_timerId = addTimer(7, 3000, 0);
break;
case 19:
playClip("Cloak On", MOVIE_NOTIFY_OBJECT);
_introMovieNum = 6;
break;
default:
break;
}
}
return true;
}
bool CDoorbot::TextInputMsg(CTextInputMsg *msg) {
if (!(_npcFlags & NPCFLAG_DOORBOT_INTRO))
return CTrueTalkNPC::TextInputMsg(msg);
if (_introMovieNum == 1) {
stopAnimTimer(_timerId);
_introMovieNum = 2;
_timerId = 0;
if (msg->_input == "yes" || msg->_input == "yeah"
|| msg->_input == "yea" || msg->_input == "yup"
|| msg->_input == "yep" || msg->_input == "sure"
|| msg->_input == "alright" || msg->_input == "all right"
|| msg->_input == "ok") {
startTalking(this, 221479);
} else {
startTalking(this, 221478);
}
}
return true;
}
bool CDoorbot::EnterViewMsg(CEnterViewMsg *msg) {
if ((_npcFlags & NPCFLAG_DOORBOT_INTRO) && _introMovieNum == 7)
playClip("SE Move And Turn", MOVIE_NOTIFY_OBJECT);
else if (!compareRoomNameTo("ServiceElevator") && msg->_newView == getParent() && getPetControl()->canSummonBot("DoorBot")) {
// WORKAROUND: Calling bot in front of doors and then going through them
// can leave it in the view. Detect this and properly remove him when
// the player returns to that view
petMoveToHiddenRoom();
}
return true;
}
bool CDoorbot::ActMsg(CActMsg *msg) {
debugC(DEBUG_DETAILED, kDebugScripts, "CDoorbot ActMsg action=%s v108=%d v110=%d v114=%d",
msg->_action.c_str(), _introMovieNum, _field110, _field114);
if (msg->_action == "DoorbotPlayerPressedTopButton") {
disableMouse();
startTalking(this, 221471);
} else if (msg->_action == "DoorbotPlayerPressedMiddleButton") {
startTalking(this, 221470);
} else if (msg->_action == "DoorbotPlayerPressedBottomButton") {
startTalking(this, 221469);
} else if (msg->_action == "DoorbotReachedEmbLobby") {
startTalking(this, 221472);
} else if (msg->_action == "PlayerPicksUpPhoto") {
_field110 = 1;
if (!_field114 && _introMovieNum == 4) {
stopAnimTimer(_timerId);
_timerId = 0;
_introMovieNum = 5;
startTalking(this, 221484);
}
} else if (msg->_action == "PlayerPutsPhotoInPet") {
_field110 = 2;
if (!_field114 && _introMovieNum == 5) {
stopAnimTimer(_timerId);
_timerId = 0;
startTalking(this, 221486);
disableMouse();
}
}
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,72 @@
/* 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/>.
*
*/
#ifndef TITANIC_DOORBOT_H
#define TITANIC_DOORBOT_H
#include "titanic/npcs/true_talk_npc.h"
namespace Titanic {
class CDoorbot : public CTrueTalkNPC {
DECLARE_MESSAGE_MAP;
bool MovieEndMsg(CMovieEndMsg *msg);
bool OnSummonBotMsg(COnSummonBotMsg *msg);
bool TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg);
bool DoorbotNeededInHomeMsg(CDoorbotNeededInHomeMsg *msg);
bool DoorbotNeededInElevatorMsg(CDoorbotNeededInElevatorMsg *msg);
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool TimerMsg(CTimerMsg *msg);
bool NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg);
bool NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg);
bool PutBotBackInHisBoxMsg(CPutBotBackInHisBoxMsg *msg);
bool DismissBotMsg(CDismissBotMsg *msg);
bool MovieFrameMsg(CMovieFrameMsg *msg);
bool TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg);
bool TextInputMsg(CTextInputMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool ActMsg(CActMsg *msg);
private:
static int _v1;
static int _v2;
private:
int _introMovieNum;
int _timerId;
int _field110;
int _field114;
public:
CLASSDEF;
CDoorbot();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_DOORBOT_H */

View File

@@ -0,0 +1,185 @@
/* 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/liftbot.h"
#include "titanic/pet_control/pet_control.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CLiftBot, CTrueTalkNPC)
ON_MESSAGE(TextInputMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(EnterRoomMsg)
ON_MESSAGE(TrueTalkTriggerActionMsg)
ON_MESSAGE(LeaveRoomMsg)
ON_MESSAGE(TurnOff)
ON_MESSAGE(TurnOn)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(TrueTalkGetStateValueMsg)
ON_MESSAGE(NPCPlayTalkingAnimationMsg)
ON_MESSAGE(ActMsg)
END_MESSAGE_MAP()
bool CLiftBot::_flag;
bool CLiftBot::_enabled;
CLiftBot::CLiftBot() : CTrueTalkNPC(), _field108(1) {
}
void CLiftBot::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_flag, indent);
file->writeNumberLine(_field108, indent);
file->writeNumberLine(_enabled, indent);
CTrueTalkNPC::save(file, indent);
}
void CLiftBot::load(SimpleFile *file) {
file->readNumber();
_flag = file->readNumber();
_field108 = file->readNumber();
_enabled = file->readNumber();
CTrueTalkNPC::load(file);
}
bool CLiftBot::TextInputMsg(CTextInputMsg *msg) {
CPetControl *pet = getPetControl();
if (_enabled || pet->getRoomsElevatorNum() != 4) {
if (getName() == "LiftBot") {
CViewItem *view = findView();
processInput(msg, view);
}
}
return true;
}
bool CLiftBot::EnterViewMsg(CEnterViewMsg *msg) {
CPetControl *pet = getPetControl();
if (!_enabled && pet->getRoomsElevatorNum() == 4) {
loadFrame(700);
} else if (!_flag && getName() == "LiftBot") {
// First time meeting the LiftBot
CViewItem *view = findView();
setTalking(this, true, view);
petSetArea(PET_CONVERSATION);
_flag = 1;
}
return true;
}
bool CLiftBot::EnterRoomMsg(CEnterRoomMsg *msg) {
_flag = 0;
changeView("Lift.Node 1.W", "");
return true;
}
bool CLiftBot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
if (msg->_action == 2 && msg->_param1 != _field108) {
CStatusChangeMsg statusMsg(_field108, msg->_param1, false);
statusMsg.execute("Well");
_field108 = msg->_param1;
}
return true;
}
bool CLiftBot::LeaveRoomMsg(CLeaveRoomMsg *msg) {
if (getName() == "LiftBot")
performAction(false);
return true;
}
bool CLiftBot::TurnOff(CTurnOff *msg) {
_enabled = false;
return true;
}
bool CLiftBot::TurnOn(CTurnOn *msg) {
_enabled = true;
if (!_flag) {
if (isEquals("LiftBotTalking")) {
setTalking(this, MOVIE_REPEAT, findView());
petSetArea(PET_CONVERSATION);
_flag = true;
}
}
return true;
}
bool CLiftBot::LeaveViewMsg(CLeaveViewMsg *msg) {
return true;
}
bool CLiftBot::TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg) {
if (msg->_stateNum == 4) {
CPetControl *pet = getPetControl();
if (pet)
msg->_stateVal = pet->getAssignedFloorNum();
} else if (msg->_stateNum == 5) {
msg->_stateVal = _field108;
} else if (msg->_stateNum == 6) {
CPetControl *pet = getPetControl();
if (pet)
msg->_stateVal = pet->getRoomsElevatorNum();
} else {
msg->_stateVal = _field108;
}
return true;
}
bool CLiftBot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
static const char *const NAMES[] = {
"Groaning", "Groaning 2", "Talking 1", "Talking 2", "Talking 3",
"Happy Talking", "Complaining", "Aggressive", "Explaining",
"Happy Talking 2", "Happy Talking 3", "Happy Talking 4",
"Confidential", nullptr
};
if (msg->_value2 == 2)
playClip("At Rest");
else
msg->_names = NAMES;
return true;
}
bool CLiftBot::ActMsg(CActMsg *msg) {
if (msg->_action == "ActivateLift") {
_enabled = true;
CViewItem *view = findView();
setTalking(this, true, view);
startTalking(this, 155, view);
} else if (msg->_action == "LiftArrive") {
CViewItem *view = findView();
startTalking(this, 156, view);
}
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,65 @@
/* 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/>.
*
*/
#ifndef TITANIC_LIFTBOT_H
#define TITANIC_LIFTBOT_H
#include "titanic/npcs/true_talk_npc.h"
#include "titanic/messages/messages.h"
namespace Titanic {
class CLiftBot : public CTrueTalkNPC {
DECLARE_MESSAGE_MAP;
bool TextInputMsg(CTextInputMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool EnterRoomMsg(CEnterRoomMsg *msg);
bool TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg);
bool LeaveRoomMsg(CLeaveRoomMsg *msg);
bool TurnOff(CTurnOff *msg);
bool TurnOn(CTurnOn *msg);
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg);
bool NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg);
bool ActMsg(CActMsg *msg);
private:
static bool _flag;
static bool _enabled;
private:
int _field108;
public:
CLASSDEF;
CLiftBot();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_LIFTBOT_H */

View File

@@ -0,0 +1,228 @@
/* 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/maitre_d.h"
#include "titanic/core/room_item.h"
#include "titanic/sound/music_room.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CMaitreD, CTrueTalkNPC)
ON_MESSAGE(RestaurantMusicChanged)
ON_MESSAGE(TrueTalkTriggerActionMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(NPCPlayTalkingAnimationMsg)
ON_MESSAGE(TimerMsg)
ON_MESSAGE(TrueTalkNotifySpeechStartedMsg)
ON_MESSAGE(TrueTalkNotifySpeechEndedMsg)
ON_MESSAGE(LoadSuccessMsg)
ON_MESSAGE(TextInputMsg)
ON_MESSAGE(TriggerNPCEvent)
END_MESSAGE_MAP()
CMaitreD::CMaitreD() : CTrueTalkNPC(),
_priorMusicName("z#40.wav"), _musicName("z#40.wav"), _unused5(0), _hasMusic(true),
_musicSet(false), _fightFlag(false), _unused6(true), _savedFightFlag(false),
_timerId(0), _defeated(false) {
}
void CMaitreD::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_unused5, indent);
file->writeQuotedLine(_priorMusicName, indent);
file->writeNumberLine(_hasMusic, indent);
file->writeNumberLine(_musicSet, indent);
file->writeQuotedLine(_musicName, indent);
file->writeNumberLine(_fightFlag, indent);
file->writeNumberLine(_unused6, indent);
file->writeNumberLine(_defeated, indent);
file->writeNumberLine(_savedFightFlag, indent);
file->writeNumberLine(_timerId, indent);
CTrueTalkNPC::save(file, indent);
}
void CMaitreD::load(SimpleFile *file) {
file->readNumber();
_unused5 = file->readNumber();
_priorMusicName = file->readString();
_hasMusic = file->readNumber();
_musicSet = file->readNumber();
_musicName = file->readString();
_fightFlag = file->readNumber();
_unused6 = file->readNumber();
_defeated = file->readNumber();
_savedFightFlag = file->readNumber();
_timerId = file->readNumber();
CTrueTalkNPC::load(file);
// WORKAROUND: The back view of the MaitreD from close to the table is dodgy
// in the original. And unneeded anyway, since he's also part of the background
if (_name == "MaitreLoop03")
_visible = false;
}
bool CMaitreD::RestaurantMusicChanged(CRestaurantMusicChanged *msg) {
if (msg->_value.empty()) {
_hasMusic = false;
} else {
_musicName = msg->_value;
_hasMusic = _musicSet = true;
}
return true;
}
bool CMaitreD::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
if (msg->_action == 8) {
_fightFlag = true;
stopAnimTimer(_timerId);
_timerId = startAnimTimer("MD Fight", 3500, 0);
} else if (msg->_action == 9) {
stopAnimTimer(_timerId);
_timerId = 0;
} else if (msg->_action == 10) {
_fightFlag = false;
_defeated = true;
stopAnimTimer(_timerId);
_timerId = 0;
CMaitreDDefeatedMsg defeatedMsg;
defeatedMsg.execute(findRoom());
}
return true;
}
bool CMaitreD::EnterViewMsg(CEnterViewMsg *msg) {
setTalking(this, true, findView());
_fightFlag = _savedFightFlag;
if (_musicName != "STMusic" && (!_musicSet || _priorMusicName == _musicName))
return true;
// WORKAROUND: It's possible in the original to not have a music handler set
// if you start and stop the phonograph, then save and restore the game
if (!CMusicRoom::_musicHandler)
return true;
if (_musicName.contains("nasty ambient"))
startTalking(this, 111, findView());
else if (!CMusicRoom::_musicHandler->checkInstrument(SNAKE))
startTalking(this, 114, findView());
else if (!CMusicRoom::_musicHandler->checkInstrument(BASS))
startTalking(this, 113, findView());
else if (!CMusicRoom::_musicHandler->checkInstrument(PIANO))
startTalking(this, 115, findView());
else {
startTalking(this, 110, findView());
CMaitreDHappyMsg happyMsg;
happyMsg.execute("MaitreD Left Arm");
happyMsg.execute("MaitreD Right Arm");
}
_priorMusicName = _musicName;
return true;
}
bool CMaitreD::LeaveViewMsg(CLeaveViewMsg *msg) {
_savedFightFlag = _fightFlag;
performAction(true);
stopAnimTimer(_timerId);
_timerId = 0;
_fightFlag = false;
return true;
}
bool CMaitreD::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
static const char *const NAMES[] = {
"Talking0", "Talking1", "Talking2", "Talking3", "Talking4",
"Talking5", "Talking6", "Talking7", nullptr
};
if (msg->_value2 != 2) {
msg->_names = NAMES;
CAnimateMaitreDMsg animMsg;
if (_fightFlag)
animMsg._value = 0;
animMsg.execute(this, nullptr, MSGFLAG_SCAN);
}
return true;
}
bool CMaitreD::TimerMsg(CTimerMsg *msg) {
if (msg->_action == "MD Fight") {
if (_fightFlag && compareViewNameTo("1stClassRestaurant.MaitreD Node.N")) {
startTalking(this, 131, findView());
}
} else {
CTrueTalkNPC::TimerMsg(msg);
}
return true;
}
bool CMaitreD::TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg) {
if (_fightFlag) {
stopAnimTimer(_timerId);
_timerId = 0;
}
CTrueTalkNPC::TrueTalkNotifySpeechStartedMsg(msg);
return true;
}
bool CMaitreD::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) {
if (_fightFlag) {
stopAnimTimer(_timerId);
_timerId = startAnimTimer("MD Fight", 3000 + getRandomNumber(3000));
}
CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(msg);
return true;
}
bool CMaitreD::LoadSuccessMsg(CLoadSuccessMsg *msg) {
if (_fightFlag) {
_timerId = startAnimTimer("MD Fight", 3000 + getRandomNumber(3000));
}
return true;
}
bool CMaitreD::TextInputMsg(CTextInputMsg *msg) {
CTrueTalkNPC::processInput(msg, findView());
return true;
}
bool CMaitreD::TriggerNPCEvent(CTriggerNPCEvent *msg) {
startTalking(this, msg->_value, findView());
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,70 @@
/* 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/>.
*
*/
#ifndef TITANIC_MAITRED_H
#define TITANIC_MAITRED_H
#include "titanic/npcs/true_talk_npc.h"
namespace Titanic {
class CMaitreD : public CTrueTalkNPC {
DECLARE_MESSAGE_MAP;
bool RestaurantMusicChanged(CRestaurantMusicChanged *msg);
bool TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg);
bool TimerMsg(CTimerMsg *msg);
bool TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg);
bool TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg);
bool LoadSuccessMsg(CLoadSuccessMsg *msg);
bool TextInputMsg(CTextInputMsg *msg);
bool TriggerNPCEvent(CTriggerNPCEvent *msg);
private:
int _unused5;
CString _priorMusicName;
bool _hasMusic;
bool _musicSet;
CString _musicName;
bool _fightFlag;
bool _unused6;
bool _savedFightFlag;
int _timerId;
bool _defeated;
public:
CLASSDEF;
CMaitreD();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_MAITRED_H */

View File

@@ -0,0 +1,47 @@
/* 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/mobile.h"
namespace Titanic {
EMPTY_MESSAGE_MAP(CMobile, CCharacter);
CMobile::CMobile() : CCharacter(), _fieldDC(0) {
}
void CMobile::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writePoint(_pos1, indent);
file->writeNumberLine(_fieldDC, indent);
CCharacter::save(file, indent);
}
void CMobile::load(SimpleFile *file) {
file->readNumber();
_pos1 = file->readPoint();
_fieldDC = file->readNumber();
CCharacter::load(file);
}
} // End of namespace Titanic

View File

@@ -0,0 +1,51 @@
/* 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/>.
*
*/
#ifndef TITANIC_MOBILE_H
#define TITANIC_MOBILE_H
#include "titanic/npcs/character.h"
namespace Titanic {
class CMobile : public CCharacter {
DECLARE_MESSAGE_MAP;
protected:
Point _pos1;
int _fieldDC;
public:
CLASSDEF;
CMobile();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_MOBILE_H */

View File

@@ -0,0 +1,759 @@
/* 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/parrot.h"
#include "titanic/core/project_item.h"
#include "titanic/carry/carry.h"
#include "titanic/carry/chicken.h"
#include "titanic/game_manager.h"
#include "titanic/translation.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CParrot, CTrueTalkNPC)
ON_MESSAGE(ActMsg)
ON_MESSAGE(MouseButtonDownMsg)
ON_MESSAGE(MovieEndMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(TrueTalkTriggerActionMsg)
ON_MESSAGE(MouseDragStartMsg)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(ParrotSpeakMsg)
ON_MESSAGE(NPCPlayTalkingAnimationMsg)
ON_MESSAGE(NPCPlayIdleAnimationMsg)
ON_MESSAGE(FrameMsg)
ON_MESSAGE(MovieFrameMsg)
ON_MESSAGE(PutParrotBackMsg)
ON_MESSAGE(PreEnterViewMsg)
ON_MESSAGE(PanningAwayFromParrotMsg)
ON_MESSAGE(LeaveRoomMsg)
ON_MESSAGE(TrueTalkNotifySpeechStartedMsg)
ON_MESSAGE(TrueTalkNotifySpeechEndedMsg)
END_MESSAGE_MAP()
bool CParrot::_eatingChicken;
bool CParrot::_takeOff;
bool CParrot::_unused;
ParrotState CParrot::_state;
bool CParrot::_coreReplaced;
CParrot::CParrot() : CTrueTalkNPC() {
_unused1 = 0;
_carryParrot = "CarryParrot";
_canDrag = true;
_unused2 = 25;
_lastSpeakTime = 0;
_newXp = 73;
_newXc = 58;
_triedEatChicken = false;
_eatOffsetX = 0;
_panTarget = nullptr;
_assetName = "z454.dlg";
_assetNumber = 0x13880;
}
void CParrot::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_assetNumber, indent);
file->writeQuotedLine(_assetName, indent);
file->writeNumberLine(_unused1, indent);
file->writeNumberLine(_eatingChicken, indent);
file->writeNumberLine(_takeOff, indent);
file->writeNumberLine(_unused, indent);
file->writeQuotedLine(_carryParrot, indent);
file->writeNumberLine(_canDrag, indent);
file->writeNumberLine(_unused2, indent);
file->writeNumberLine(_lastSpeakTime, indent);
file->writeNumberLine(_newXp, indent);
file->writeNumberLine(_newXc, indent);
file->writeNumberLine(_triedEatChicken, indent);
file->writeNumberLine(_eatOffsetX, indent);
file->writeNumberLine(_state, indent);
file->writeNumberLine(_coreReplaced, indent);
CTrueTalkNPC::save(file, indent);
}
void CParrot::load(SimpleFile *file) {
file->readNumber();
_assetNumber = file->readNumber();
_assetName = file->readString();
_unused1 = file->readNumber();
_eatingChicken = file->readNumber();
_takeOff = file->readNumber();
_unused = file->readNumber();
_carryParrot = file->readString();
_canDrag = file->readNumber();
_unused2 = file->readNumber();
_lastSpeakTime = file->readNumber();
_newXp = file->readNumber();
_newXc = file->readNumber();
_triedEatChicken = file->readNumber();
_eatOffsetX = file->readNumber();
_state = (ParrotState)file->readNumber();
_coreReplaced = file->readNumber();
CTrueTalkNPC::load(file);
}
bool CParrot::ActMsg(CActMsg *msg) {
if (msg->_action == "Chicken") {
// Nothing to do
} else if (msg->_action == "CarryParrotLeftView") {
if (!_takeOff)
setEatingChicken(false);
} else if (msg->_action == "StartChickenDrag") {
if (_state == PARROT_IN_CAGE) {
stopMovie();
startTalking(this, 280275, findView());
_triedEatChicken = false;
}
} else if (msg->_action == "EnteringFromTOW" &&
(_state == PARROT_IN_CAGE || _state == PARROT_ESCAPED)) {
if (_takeOff) {
_state = PARROT_ESCAPED;
} else {
setVisible(true);
CTreeItem *cageBar = getRoot()->findByName("CageBar");
detach();
attach(cageBar);
_state = PARROT_IN_CAGE;
CActMsg actMsg1("OpenNow");
actMsg1.execute("ParrotCage");
CActMsg actMsg2("GainParrot");
actMsg2.execute("ParrotLobbyController");
}
}
return true;
}
bool CParrot::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
if (!(_npcFlags & NPCFLAG_TAKE_OFF) && _speechCounter == 0) {
CTrueTalkTriggerActionMsg triggerMsg(280250, 280250, 1);
triggerMsg.execute(this);
}
return true;
}
bool CParrot::MovieEndMsg(CMovieEndMsg *msg) {
if ((_npcFlags & NPCFLAG_TAKE_OFF) && clipExistsByEnd("Take Off", msg->_endFrame)) {
setVisible(false);
moveUnder(findRoom());
stopMovie();
CActMsg actMsg1("LoseParrot");
actMsg1.execute("ParrotLobbyController");
if (_panTarget) {
CActMsg actMsg2("PanAwayFromParrot");
actMsg2.execute(_panTarget);
_panTarget = nullptr;
} else {
CActMsg actMsg2("Shut");
actMsg2.execute("ParrotCage");
}
_npcFlags &= ~NPCFLAG_TAKE_OFF;
_state = PARROT_ESCAPED;
} else if (_npcFlags & NPCFLAG_MOVING) {
if (_npcFlags & NPCFLAG_MOVE_START) {
// Parrot is about to loop
_npcFlags = (_npcFlags & ~NPCFLAG_MOVE_START) | NPCFLAG_MOVE_LOOP;
if (_npcFlags & NPCFLAG_MOVE_LEFT) {
playClip("Walk Left Loop", MOVIE_NOTIFY_OBJECT);
movieEvent(236);
} else {
playClip("Walk Right Loop", MOVIE_NOTIFY_OBJECT);
}
} else if (_npcFlags & NPCFLAG_MOVE_LOOP) {
// In progress movement loop
int xp = _bounds.left + _bounds.width() / 2;
if (_npcFlags & NPCFLAG_MOVE_LEFT) {
if ((xp - _newXc) > 32) {
setPosition(Point(_bounds.left - 40, _bounds.top));
playClip("Walk Left Loop", MOVIE_NOTIFY_OBJECT);
movieEvent(236);
} else {
setPosition(Point(_bounds.left - 10, _bounds.top));
playClip("Walk Left Outro", MOVIE_NOTIFY_OBJECT);
_npcFlags = (_npcFlags & ~NPCFLAG_MOVE_LOOP) | NPCFLAG_MOVE_FINISH;
}
} else {
if ((_newXc - xp) > 32) {
playClip("Walk Right Loop", MOVIE_NOTIFY_OBJECT);
movieEvent(244);
} else {
playClip("Walk Right Outro", MOVIE_NOTIFY_OBJECT);
_npcFlags = (_npcFlags & ~NPCFLAG_MOVE_LOOP) | NPCFLAG_MOVE_FINISH;
}
}
} else if (_npcFlags & NPCFLAG_MOVE_FINISH) {
// Finishing movement
loadFrame(0);
if (_npcFlags & NPCFLAG_MOVE_LEFT)
setPosition(Point(_bounds.left - 30, _bounds.top));
else
setPosition(Point(_bounds.left + 14, _bounds.top));
_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_FINISH | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT);
CTrueTalkNPC::MovieEndMsg(msg);
}
} else if (_npcFlags & NPCFLAG_CHICKEN_OUTSIDE_CAGE) {
Point pt = getMousePos();
if (pt.x > 70 || pt.y < 90 || pt.y > 280) {
stopMovie();
loadFrame(0);
_npcFlags &= ~NPCFLAG_CHICKEN_OUTSIDE_CAGE;
}
if (clipExistsByEnd("Walk Left Loop", msg->_endFrame)) {
playClip("Lean Over To Chicken", MOVIE_NOTIFY_OBJECT);
setPosition(Point(_bounds.left - 55, _bounds.top));
_eatOffsetX = (-100 - _bounds.left) / 5;
movieEvent(261);
movieEvent(262);
movieEvent(265);
movieEvent(268);
movieEvent(271);
return true;
} else if (clipExistsByEnd("Lean Over To Chicken", msg->_endFrame)) {
// WORKAROUND: Do what the original obviously intended but got
// wrong.. only flag chicken as eaten if it's still being dragged
CTreeItem *dragItem = getGameManager()->_dragItem;
CCarry *chicken = dynamic_cast<CCarry *>(dragItem);
if (chicken)
playClip("Eat Chicken");
playClip("Eat Chicken 2", MOVIE_NOTIFY_OBJECT);
if (chicken) {
setEatingChicken(true);
CTrueTalkTriggerActionMsg actionMsg;
actionMsg._action = 280266;
actionMsg._param2 = 1;
actionMsg.execute(this);
CActMsg actMsg("Eaten");
actMsg.execute(chicken);
}
_npcFlags &= ~NPCFLAG_CHICKEN_OUTSIDE_CAGE;
return true;
}
}
if (clipExistsByEnd("Eat Chicken 2", msg->_endFrame)) {
// Parrot has finished eating Chicken
setEatingChicken(false);
if (_takeOff) {
// Perch has been taken, so take off
loadMovie(TRANSLATE("z168.avi", "z191.avi"), false);
playClip("Take Off", MOVIE_NOTIFY_OBJECT);
setPosition(Point(20, 10));
_npcFlags |= NPCFLAG_TAKE_OFF;
} else {
// Resetting back to standing
_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP
| NPCFLAG_MOVE_FINISH | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT);
_npcFlags |= NPCFLAG_MOVE_END;
stopMovie();
loadFrame(0);
setPosition(Point(-90, _bounds.top));
}
} else {
return CTrueTalkNPC::MovieEndMsg(msg);
}
return true;
}
bool CParrot::EnterViewMsg(CEnterViewMsg *msg) {
static const char *const NAMES[] = {
"Talking0", "Talking1", "Talking2", "Talking3", "Talking4",
"Talking5", "Talking6", "Talking7", nullptr
};
if (_state == PARROT_IN_CAGE) {
setPosition(Point(_newXp, _bounds.top));
_canDrag = true;
_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP
| NPCFLAG_MOVE_FINISH | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT | NPCFLAG_MOVE_END);
loadFrame(0);
setTalking(this, true, findView());
if (_speechCounter > 0) {
playRandomClip(NAMES, MOVIE_NOTIFY_OBJECT);
} else {
startTalking(this, 280258, findView());
}
petSetArea(PET_CONVERSATION);
_triedEatChicken = false;
_npcFlags |= NPCFLAG_START_IDLING;
}
return true;
}
bool CParrot::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
if (_state != PARROT_MAILED) {
CViewItem *view = msg->_param2 ? findView() : nullptr;
startTalking(this, msg->_action, view);
}
return true;
}
bool CParrot::MouseDragStartMsg(CMouseDragStartMsg *msg) {
if (_canDrag && _state == PARROT_IN_CAGE && checkPoint(msg->_mousePos, false, true)) {
setVisible(false);
CRoomItem *room = findRoom();
moveUnder(room);
startTalking(this, 280129);
performAction(true);
CCarry *item = dynamic_cast<CCarry *>(getRoot()->findByName(_carryParrot));
if (item) {
item->_canTake = true;
CPassOnDragStartMsg passMsg;
passMsg._mousePos = msg->_mousePos;
passMsg.execute(item);
msg->_dragItem = item;
CActMsg actMsg("LoseParrot");
actMsg.execute("ParrotLobbyController");
return true;
}
}
return false;
}
bool CParrot::LeaveViewMsg(CLeaveViewMsg *msg) {
performAction(true);
_npcFlags &= ~NPCFLAG_START_IDLING;
return true;
}
bool CParrot::ParrotSpeakMsg(CParrotSpeakMsg *msg) {
static const char *const ROOM_NAMES[] = {
"SGTState", "SGTLittleLift", "SecClassLittleLift", "SecClassState",
"Lift", "ServiceElevator", "Dome", "Home", "MoonEmbLobby", nullptr
};
if (!stateGetParrotMet() || _state == PARROT_MAILED || compareViewNameTo("Titania.Node 18.N"))
return true;
// Check for rooms not to speak in
for (const char *const *s = &ROOM_NAMES[0]; *s; ++s) {
if (isEquals(*s))
return true;
}
// Don't have the parrot speak too often
if ((getTicksCount() - _lastSpeakTime) < 20000 || _speechCounter)
return true;
playSound(TRANSLATE("z#475.wav", "z#212.wav"), 50);
if (msg->_target == "Bomb") {
startTalking("PerchedParrot", 280236);
} else if (msg->_target == "Announcements") {
startTalking("PerchedParrot", 280263);
} else if (msg->_target == "Television") {
startTalking("PerchedParrot", 280264);
} else if (msg->_target == "Barbot") {
if (msg->_action == "AskForDrink")
startTalking("PerchedParrot", 280262);
} else if (msg->_target == "SuccUBus") {
if (msg->_action == "TurnOn")
startTalking("PerchedParrot", 80161);
else if (msg->_action == "EnterView")
startTalking("PerchedParrot", 80159);
} else if (msg->_target == "Cellpoints") {
if (getRandomNumber(2) == 0) {
switch (getRandomNumber(2)) {
case 0:
startTalking("PerchedParrot", 80193);
break;
case 1:
startTalking("PerchedParrot", 80197);
break;
case 2:
startTalking("PerchedParrot", 80198);
break;
default:
break;
}
} else if (msg->_action == "DoorBot") {
startTalking("PerchedParrot", 80195);
} else if (msg->_action == "DeskBot") {
startTalking("PerchedParrot", 80194);
} else if (msg->_action == "BarBot") {
startTalking("PerchedParrot", 80191);
} else if (msg->_action == "BellBot") {
startTalking("PerchedParrot", 80192);
} else if (msg->_action == "LiftBot") {
startTalking("PerchedParrot", 80196);
}
}
_lastSpeakTime = getTicksCount();
return true;
}
bool CParrot::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
static const char *const NAMES[] = {
"Talking0", "Talking1", "Talking2", "Talking3", "Talking4",
"Talking5", "Talking6", "Talking7", nullptr
};
if (!(_npcFlags & (NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP | NPCFLAG_MOVE_FINISH
| NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT | NPCFLAG_MOVE_END))
&& _visible && _state == PARROT_IN_CAGE) {
if (compareViewNameTo("ParrotLobby.Node 1.N"))
msg->_names = NAMES;
}
return true;
}
bool CParrot::NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg) {
static const char *const NAMES[] = {
"Idle0", "Idle1", "Peck At Feet", "Peck At Feet Left",
"Peck At Feet Right", nullptr
};
if (!(_npcFlags & (NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP | NPCFLAG_MOVE_FINISH
| NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT | NPCFLAG_MOVE_END))
&& _visible && _state == PARROT_IN_CAGE && compareViewNameTo("ParrotLobby.Node 1.N")) {
CGameObject *dragItem = getDraggingObject();
if (!dragItem || dragItem->getName() == "Chicken") {
if (!_coreReplaced || getRandomNumber(3) != 0) {
if (getRandomNumber(1)) {
startTalking(this, 280267, findView());
} else {
msg->_names = NAMES;
}
} else {
int id = -1;
switch (getParrotResponse()) {
case 0:
id = 280107;
break;
case 1:
id = 280106;
break;
case 2:
id = 280115;
break;
case 3:
id = 280114;
break;
case 4:
id = 280113;
break;
case 5:
id = 280112;
break;
case 6:
id = 280111;
break;
case 7:
id = 280110;
break;
case 8:
id = 280109;
break;
case 9:
id = 280108;
break;
case 10:
id = 280105;
break;
case 11:
id = 280000;
break;
default:
break;
}
if (id != -1)
startTalking(this, id, findView());
CActMsg actMsg("FlashCore");
actMsg.execute("PerchCoreHolder");
}
}
}
return true;
}
bool CParrot::FrameMsg(CFrameMsg *msg) {
if (!compareViewNameTo("ParrotLobby.Node 1.N"))
return false;
if (_state != PARROT_IN_CAGE)
return true;
Point pt = getMousePos();
CGameObject *dragObject = getDraggingObject();
int xp = _bounds.left + _bounds.width() / 2;
bool chickenFlag = false;
if ((_npcFlags & NPCFLAG_MOVE_END) && !hasActiveMovie()) {
_newXc = _newXp + _bounds.width() / 2;
int xDiff = ABS(xp - _newXc);
if (xDiff < 64) {
if (_panTarget) {
CActMsg actMsg("PanAwayFromParrot");
actMsg.execute(_panTarget);
_panTarget = nullptr;
}
_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_START | NPCFLAG_MOVE_LOOP
| NPCFLAG_MOVE_FINISH | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT | NPCFLAG_MOVE_END);
return true;
}
// WORKAROUND: Prevent panning away from stalling if Parrot was moving
_npcFlags &= ~NPCFLAG_MOVING;
} else {
if (dragObject)
chickenFlag = dragObject && dragObject->isEquals("Chicken");
if (_npcFlags & NPCFLAG_CHICKEN_OUTSIDE_CAGE) {
if (!chickenFlag || pt.x > 70 || pt.y < 90 || pt.y > 280) {
// A start of eating the chicken outside the cage has to be
// aborted because the chicken has been moved out of range
stopMovie();
loadFrame(0);
setPosition(Point(-90, _bounds.top));
_npcFlags &= ~NPCFLAG_CHICKEN_OUTSIDE_CAGE;
}
} else {
if (!chickenFlag)
return false;
}
_newXc = CLIP((int)pt.x, 230, 480);
}
if ((_npcFlags & NPCFLAG_MOVING) || hasActiveMovie())
return true;
if (ABS(_newXc - xp) > 64) {
_npcFlags |= NPCFLAG_MOVING | NPCFLAG_MOVE_START;
if (_newXc >= xp) {
// WORKAROUND: Original did not properly reset the eating chicken
// flag when the player turns away from the cage
setEatingChicken(false);
setPosition(Point(_bounds.left + 30, _bounds.top));
_npcFlags |= NPCFLAG_MOVE_RIGHT;
playClip("Walk Right Intro", MOVIE_NOTIFY_OBJECT);
} else {
_npcFlags |= NPCFLAG_MOVE_LEFT;
playClip("Walk Left Intro", MOVIE_NOTIFY_OBJECT);
}
} else if (chickenFlag && pt.y >= 90 && pt.y <= 280 && !_triedEatChicken) {
CParrotTriesChickenMsg triesMsg;
triesMsg.execute(dragObject);
CTrueTalkTriggerActionMsg triggerMsg;
int &action = triggerMsg._action;
switch (triesMsg._condiment) {
case 1:
action = triesMsg._isHot ? 280034 : 280056;
break;
case 2:
action = triesMsg._isHot ? 280033 : 280055;
break;
case 3:
action = triesMsg._isHot ? 280032 : 280054;
break;
default:
action = triesMsg._isHot ? 280266 : 280053;
break;
}
if (action == 280266) {
if (pt.x < 75) {
// Parrot needs to reach outside the cage
_npcFlags |= NPCFLAG_CHICKEN_OUTSIDE_CAGE;
playClip("Walk Left Intro", MOVIE_STOP_PREVIOUS);
playClip("Walk Left Loop", MOVIE_NOTIFY_OBJECT);
movieEvent(236);
chickenFlag = false;
} else if ((pt.x - xp) > 15) {
_npcFlags |= NPCFLAG_PECKING;
playClip("Peck At Feet Right", MOVIE_NOTIFY_OBJECT);
movieEvent(170);
} else if ((xp - pt.x) > 15) {
_npcFlags |= NPCFLAG_PECKING;
playClip("Peck At Feet Left", MOVIE_NOTIFY_OBJECT);
movieEvent(142);
} else {
_npcFlags |= NPCFLAG_PECKING;
playClip("Peck At Feet", MOVIE_NOTIFY_OBJECT);
movieEvent(157);
}
}
if (chickenFlag) {
triggerMsg._param2 = 1;
triggerMsg.execute(this);
_triedEatChicken = true;
}
}
return true;
}
bool CParrot::MovieFrameMsg(CMovieFrameMsg *msg) {
if (_npcFlags & NPCFLAG_PECKING) {
// Whoopsy, the Parrot got your chicken
CCarry *chicken = dynamic_cast<CCarry *>(findUnder(getRoot(), "Chicken"));
if (chicken) {
CActMsg actMsg("Eaten");
actMsg.execute(chicken);
}
_npcFlags &= ~NPCFLAG_PECKING;
}
switch (msg->_frameNumber) {
case 244:
setPosition(Point(_bounds.left + 45, _bounds.top));
break;
case 261:
case 262:
case 265:
case 268:
case 271:
setPosition(Point(_bounds.left + _eatOffsetX, _bounds.top));
break;
default:
break;
}
return true;
}
bool CParrot::PutParrotBackMsg(CPutParrotBackMsg *msg) {
const char *const NAMES[] = {
"Talking0", "Talking1", "Talking2", "Talking3", "Talking4",
"Talking5", "Talking6", "Talking7", nullptr
};
int xp = CLIP(msg->_value, 230, 480);
setVisible(true);
moveToView();
_state = PARROT_IN_CAGE;
setPosition(Point(xp - _bounds.width() / 2, _bounds.top));
playRandomClip(NAMES, MOVIE_NOTIFY_OBJECT);
CActMsg actMsg("GainParrot");
actMsg.execute("ParrotLobbyController");
return true;
}
bool CParrot::PreEnterViewMsg(CPreEnterViewMsg *msg) {
if (_state == PARROT_IN_CAGE) {
loadMovie(TRANSLATE("z167.avi", "z190.avi"), false);
loadFrame(0);
}
return true;
}
bool CParrot::PanningAwayFromParrotMsg(CPanningAwayFromParrotMsg *msg) {
if (_state != PARROT_IN_CAGE) {
CActMsg actMsg("PanAwayFromParrot");
actMsg.execute(msg->_target);
_panTarget = nullptr;
} else if (_takeOff) {
_panTarget = msg->_target;
loadMovie(TRANSLATE("z168.avi", "z191.avi"), false);
stopMovie();
playClip("Take Off", MOVIE_NOTIFY_OBJECT);
_npcFlags |= NPCFLAG_TAKE_OFF;
} else {
_npcFlags |= NPCFLAG_MOVE_END;
_panTarget = msg->_target;
stopMovie();
}
return true;
}
bool CParrot::LeaveRoomMsg(CLeaveRoomMsg *msg) {
if (_state == PARROT_IN_CAGE)
startTalking(this, 280259);
return true;
}
bool CParrot::TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg) {
// WORKAROUND: Fix parrot freezing up if you drag the chicken whilst
// he's still returning to the center from a prior chicken drag
if (_npcFlags & (NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT))
_npcFlags &= ~(NPCFLAG_MOVING | NPCFLAG_MOVE_LEFT | NPCFLAG_MOVE_RIGHT);
return CTrueTalkNPC::TrueTalkNotifySpeechStartedMsg(msg);
}
bool CParrot::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) {
if (msg->_dialogueId == 80022) {
// WORKAROUND: End of parrot speech after having fixed Titania
unlockMouse();
changeView("Titania.Node 18.N", "");
}
return CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(msg);
}
void CParrot::setEatingChicken(bool eating) {
_eatingChicken = eating;
CStatusChangeMsg statusMsg;
statusMsg._newStatus = eating ? 0 : 1;
statusMsg.execute("PerchCoreHolder");
}
} // End of namespace Titanic

View File

@@ -0,0 +1,94 @@
/* 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/>.
*
*/
#ifndef TITANIC_PARROT_H
#define TITANIC_PARROT_H
#include "titanic/npcs/true_talk_npc.h"
#include "titanic/moves/move_player_to.h"
namespace Titanic {
enum ParrotState {
PARROT_IN_CAGE = 0, PARROT_1 = 1, PARROT_ESCAPED = 2,
PARROT_MAILED = 3, PARROT_4 = 4
};
class CParrot : public CTrueTalkNPC {
DECLARE_MESSAGE_MAP;
bool ActMsg(CActMsg *msg);
bool MouseButtonDownMsg(CMouseButtonDownMsg *msg);
bool MovieEndMsg(CMovieEndMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg);
bool MouseDragStartMsg(CMouseDragStartMsg *msg);
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool ParrotSpeakMsg(CParrotSpeakMsg *msg);
bool NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg);
bool NPCPlayIdleAnimationMsg(CNPCPlayIdleAnimationMsg *msg);
bool FrameMsg(CFrameMsg *msg);
bool MovieFrameMsg(CMovieFrameMsg *msg);
bool PutParrotBackMsg(CPutParrotBackMsg *msg);
bool PreEnterViewMsg(CPreEnterViewMsg *msg);
bool PanningAwayFromParrotMsg(CPanningAwayFromParrotMsg *msg);
bool LeaveRoomMsg(CLeaveRoomMsg *msg);
bool TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg);
bool TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg);
public:
static bool _eatingChicken;
static bool _takeOff;
static bool _unused;
static ParrotState _state;
static bool _coreReplaced;
private:
int _unused1;
CString _carryParrot;
bool _canDrag;
int _unused2;
uint _lastSpeakTime;
int _newXp;
int _newXc;
bool _triedEatChicken;
int _eatOffsetX;
CMovePlayerTo *_panTarget;
private:
/**
* Called for the Parrot to start or finish eating
*/
void setEatingChicken(bool eating);
public:
CLASSDEF;
CParrot();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_PARROT_H */

View File

@@ -0,0 +1,152 @@
/* 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/parrot_succubus.h"
#include "titanic/pet_control/pet_control.h"
#include "titanic/carry/hose.h"
#include "titanic/translation.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CParrotSuccUBus, CSuccUBus)
ON_MESSAGE(HoseConnectedMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(MovieEndMsg)
ON_MESSAGE(MouseButtonDownMsg)
ON_MESSAGE(LeaveNodeMsg)
END_MESSAGE_MAP()
CParrotSuccUBus::CParrotSuccUBus() : CSuccUBus(), _hoseConnected(false),
_pumpingSound(0), _hoseRemovalStartFrame(376), _hoseRemovalEndFrame(393) {
}
void CParrotSuccUBus::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_hoseConnected, indent);
file->writeQuotedLine(_pumpingTarget, indent);
file->writeNumberLine(_pumpingSound, indent);
CSuccUBus::save(file, indent);
}
void CParrotSuccUBus::load(SimpleFile *file) {
file->readNumber();
_hoseConnected = file->readNumber();
_pumpingTarget = file->readString();
_pumpingSound = file->readNumber();
CSuccUBus::load(file);
}
bool CParrotSuccUBus::HoseConnectedMsg(CHoseConnectedMsg *msg) {
CPetControl *pet = getPetControl();
if (msg->_connected == _hoseConnected)
return true;
if (mailExists(pet->getRoomFlags()))
return false;
_hoseConnected = msg->_connected;
if (_hoseConnected) {
CGameObject *item = msg->_object;
_pumpingTarget = item->getName();
CHoseConnectedMsg hoseMsg(1, this);
hoseMsg.execute(msg->_object);
item->petMoveToHiddenRoom();
CPumpingMsg pumpingMsg(1, this);
pumpingMsg.execute(_pumpingTarget);
_hoseConnected = true;
if (_isOn) {
_isOn = false;
} else {
playMovie(_onStartFrame, _onEndFrame, 0);
playSound(TRANSLATE("z#26.wav", "z#557.wav"));
}
playMovie(_hoseStartFrame, _hoseEndFrame, MOVIE_NOTIFY_OBJECT);
} else {
stopMovie();
stopSound(_pumpingSound);
playMovie(_hoseRemovalStartFrame, _hoseRemovalEndFrame, MOVIE_NOTIFY_OBJECT);
CPumpingMsg pumpingMsg(0, this);
pumpingMsg.execute(_pumpingTarget);
CGameObject *obj = getHiddenObject(_pumpingTarget);
if (obj) {
obj->petAddToInventory();
obj->setVisible(true);
}
_isOn = true;
CTurnOff offMsg;
offMsg.execute(this);
}
return true;
}
bool CParrotSuccUBus::EnterViewMsg(CEnterViewMsg *msg) {
if (_hoseConnected) {
playMovie(_pumpingStartFrame, _pumpingEndFrame, MOVIE_REPEAT);
return true;
} else {
return CSuccUBus::EnterViewMsg(msg);
}
}
bool CParrotSuccUBus::MovieEndMsg(CMovieEndMsg *msg) {
if (msg->_endFrame == _hoseEndFrame) {
playMovie(_pumpingStartFrame, _pumpingEndFrame, MOVIE_REPEAT);
_pumpingSound = playSound(TRANSLATE("z#472.wav", "z#209.wav"));
return true;
} else {
return CSuccUBus::MovieEndMsg(msg);
}
}
bool CParrotSuccUBus::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
if (_hoseConnected) {
CHoseConnectedMsg hoseMsg;
hoseMsg._connected = false;
hoseMsg.execute(this);
return true;
} else {
return CSuccUBus::MouseButtonDownMsg(msg);
}
}
bool CParrotSuccUBus::LeaveNodeMsg(CLeaveNodeMsg *msg) {
if (_hoseConnected) {
getHiddenObject(_pumpingTarget);
if (CHose::_statics->_actionTarget.empty()) {
playSound(TRANSLATE("z#51.wav", "z#582.wav"));
CHoseConnectedMsg hoseMsg;
hoseMsg._connected = false;
hoseMsg.execute(this);
}
}
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,59 @@
/* 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/>.
*
*/
#ifndef TITANIC_PARROT_SUCCUBUS_H
#define TITANIC_PARROT_SUCCUBUS_H
#include "titanic/npcs/succubus.h"
namespace Titanic {
class CParrotSuccUBus : public CSuccUBus {
DECLARE_MESSAGE_MAP;
bool HoseConnectedMsg(CHoseConnectedMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool MovieEndMsg(CMovieEndMsg *msg);
bool MouseButtonDownMsg(CMouseButtonDownMsg *msg);
bool LeaveNodeMsg(CLeaveNodeMsg *msg);
public:
bool _hoseConnected;
CString _pumpingTarget;
int _pumpingSound;
int _hoseRemovalStartFrame;
int _hoseRemovalEndFrame;
public:
CLASSDEF;
CParrotSuccUBus();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_PARROT_SUCCUBUS_H */

View File

@@ -0,0 +1,59 @@
/* 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/robot_controller.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CRobotController, CGameObject)
ON_MESSAGE(SummonBotMsg)
ON_MESSAGE(SummonBotQueryMsg)
END_MESSAGE_MAP()
CRobotController::CRobotController() : CGameObject(), _robotName("BellBot") {
}
void CRobotController::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeQuotedLine(_robotName, indent);
CGameObject::save(file, indent);
}
void CRobotController::load(SimpleFile *file) {
file->readNumber();
_robotName = file->readString();
CGameObject::load(file);
}
bool CRobotController::SummonBotMsg(CSummonBotMsg *msg) {
if (!petDismissBot(msg->_npcName))
petOnSummonBot(msg->_npcName, msg->_value);
return true;
}
bool CRobotController::SummonBotQueryMsg(CSummonBotQueryMsg *msg) {
return _robotName == msg->_npcName;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,52 @@
/* 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/>.
*
*/
#ifndef TITANIC_ROBOT_CONTROLLER_H
#define TITANIC_ROBOT_CONTROLLER_H
#include "titanic/core/game_object.h"
namespace Titanic {
class CRobotController : public CGameObject {
DECLARE_MESSAGE_MAP;
bool SummonBotMsg(CSummonBotMsg *msg);
bool SummonBotQueryMsg(CSummonBotQueryMsg *msg);
protected:
CString _robotName;
public:
CLASSDEF;
CRobotController();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_ROBOT_CONTROLLER_H */

View File

@@ -0,0 +1,67 @@
/* 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/starlings.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CStarlings, CCharacter)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(StatusChangeMsg)
END_MESSAGE_MAP()
bool CStarlings::_dead;
CStarlings::CStarlings() : CCharacter() {
}
void CStarlings::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_dead, indent);
CCharacter::save(file, indent);
}
void CStarlings::load(SimpleFile *file) {
file->readNumber();
_dead = file->readNumber();
CCharacter::load(file);
}
bool CStarlings::EnterViewMsg(CEnterViewMsg *msg) {
if (_dead)
// Tis but a flesh wound
setVisible(false);
else
// Repeatedly play the starlings flying
playMovie(MOVIE_REPEAT);
return true;
}
bool CStarlings::StatusChangeMsg(CStatusChangeMsg *msg) {
// I'm not dead.. I'm getting better.
_dead = msg->_newStatus == 1;
setVisible(!_dead);
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,53 @@
/* 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/>.
*
*/
#ifndef TITANIC_STARLINGS_H
#define TITANIC_STARLINGS_H
#include "titanic/npcs/character.h"
namespace Titanic {
class CStarlings : public CCharacter {
DECLARE_MESSAGE_MAP;
bool EnterViewMsg(CEnterViewMsg *msg);
bool StatusChangeMsg(CStatusChangeMsg *msg);
private:
// This needs to be static to be shared across all starling instances
static bool _dead;
public:
CLASSDEF;
CStarlings();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_STARLING_H */

View File

@@ -0,0 +1,814 @@
/* 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/succubus.h"
#include "titanic/carry/carry.h"
#include "titanic/carry/chicken.h"
#include "titanic/core/view_item.h"
#include "titanic/pet_control/pet_control.h"
#include "titanic/translation.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CSuccUBus, CTrueTalkNPC)
ON_MESSAGE(MouseButtonDownMsg)
ON_MESSAGE(SubAcceptCCarryMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(LeaveViewMsg)
ON_MESSAGE(PETDeliverMsg)
ON_MESSAGE(PETReceiveMsg)
ON_MESSAGE(MovieEndMsg)
ON_MESSAGE(TrueTalkGetStateValueMsg)
ON_MESSAGE(SignalObject)
ON_MESSAGE(TurnOn)
ON_MESSAGE(TurnOff)
ON_MESSAGE(SUBTransition)
ON_MESSAGE(SetChevRoomBits)
ON_MESSAGE(ActMsg)
ON_MESSAGE(MouseDragStartMsg)
END_MESSAGE_MAP()
bool CSuccUBus::_isOn; // SuccUBus turned on
bool CSuccUBus::_motherBlocked; // Bilge SuccUBus is blocked
bool CSuccUBus::_fuseboxOn; // SuccUBus dial in fusebox is on
CSuccUBus::CSuccUBus() : CTrueTalkNPC() {
_initialStartFrame = -1;
_initialEndFrame = -1;
_endingStartFrame = -1;
_endingEndFrame = -1;
_sendStartFrame = 68;
_sendEndFrame = 168;
_receiveStartFrame = 168;
_receiveEndFrame = 248;
_onStartFrame = 0;
_onEndFrame = 0x0E;
_offStartFrame = 0x0E;
_offEndFrame = 27;
_okStartFrame = 40;
_okEndFrame = 68;
_flagsComparison = RFC_LOCATION;
_mailP = nullptr;
_afterReceiveStartFrame = 0;
_afterReceiveEndFrame = 0;
_trayOutStartFrame = 224;
_trayOutEndFrame = 248;
_sendAction = SA_SENT;
_signalFlag = false;
_signalTarget = "NULL";
_startFrame1 = 28;
_endFrame1 = 40;
_rect1 = Rect(82, 284, 148, 339);
_field184 = 15;
_mailPresent = false;
_rect2 = Rect(0, 0, 240, 340);
_sendLost = false;
_soundHandle = -1;
_isChicken = false;
_isFeathers = false;
_priorRandomVal1 = 0;
_priorRandomVal2 = 0;
_emptyStartFrame = 303;
_emptyEndFrame = 312;
_smokeStartFrame = 313;
_smokeEndFrame = 325;
_hoseStartFrame = 326;
_hoseEndFrame = 347;
_pumpingStartFrame = 348;
_pumpingEndFrame = 375;
_destRoomFlags = 1;
_inProgress = false;
}
void CSuccUBus::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_isOn, indent);
file->writeNumberLine(_initialStartFrame, indent);
file->writeNumberLine(_initialEndFrame, indent);
file->writeNumberLine(_endingStartFrame, indent);
file->writeNumberLine(_endingEndFrame, indent);
file->writeNumberLine(_sendStartFrame, indent);
file->writeNumberLine(_sendEndFrame, indent);
file->writeNumberLine(_receiveStartFrame, indent);
file->writeNumberLine(_receiveEndFrame, indent);
file->writeNumberLine(_onStartFrame, indent);
file->writeNumberLine(_onEndFrame, indent);
file->writeNumberLine(_offStartFrame, indent);
file->writeNumberLine(_offEndFrame, indent);
file->writeNumberLine(_okStartFrame, indent);
file->writeNumberLine(_okEndFrame, indent);
file->writeNumberLine(_flagsComparison, indent);
file->writeNumberLine(_motherBlocked, indent);
file->writeNumberLine(_afterReceiveStartFrame, indent);
file->writeNumberLine(_afterReceiveEndFrame, indent);
file->writeNumberLine(_trayOutStartFrame, indent);
file->writeNumberLine(_trayOutEndFrame, indent);
file->writeNumberLine(_sendAction, indent);
file->writeNumberLine(_signalFlag, indent);
file->writeQuotedLine(_signalTarget, indent);
file->writeNumberLine(_startFrame1, indent);
file->writeNumberLine(_endFrame1, indent);
file->writeNumberLine(_rect1.left, indent);
file->writeNumberLine(_rect1.top, indent);
file->writeNumberLine(_rect1.right, indent);
file->writeNumberLine(_rect1.bottom, indent);
file->writeNumberLine(_field184, indent);
file->writeNumberLine(_mailPresent, indent);
file->writeNumberLine(_rect2.left, indent);
file->writeNumberLine(_rect2.top, indent);
file->writeNumberLine(_rect2.right, indent);
file->writeNumberLine(_rect2.bottom, indent);
file->writeNumberLine(_sendLost, indent);
file->writeNumberLine(_soundHandle, indent);
file->writeNumberLine(_isChicken, indent);
file->writeNumberLine(_isFeathers, indent);
file->writeNumberLine(_priorRandomVal1, indent);
file->writeNumberLine(_priorRandomVal2, indent);
file->writeNumberLine(_emptyStartFrame, indent);
file->writeNumberLine(_emptyEndFrame, indent);
file->writeNumberLine(_smokeStartFrame, indent);
file->writeNumberLine(_smokeEndFrame, indent);
file->writeNumberLine(_hoseStartFrame, indent);
file->writeNumberLine(_hoseEndFrame, indent);
file->writeNumberLine(_pumpingStartFrame, indent);
file->writeNumberLine(_pumpingEndFrame, indent);
file->writeNumberLine(_destRoomFlags, indent);
file->writeNumberLine(_fuseboxOn, indent);
file->writeNumberLine(_inProgress, indent);
file->writeNumberLine(_field104, indent);
CTrueTalkNPC::save(file, indent);
}
void CSuccUBus::load(SimpleFile *file) {
file->readNumber();
_isOn = file->readNumber();
_initialStartFrame = file->readNumber();
_initialEndFrame = file->readNumber();
_endingStartFrame = file->readNumber();
_endingEndFrame = file->readNumber();
_sendStartFrame = file->readNumber();
_sendEndFrame = file->readNumber();
_receiveStartFrame = file->readNumber();
_receiveEndFrame = file->readNumber();
_onStartFrame = file->readNumber();
_onEndFrame = file->readNumber();
_offStartFrame = file->readNumber();
_offEndFrame = file->readNumber();
_okStartFrame = file->readNumber();
_okEndFrame = file->readNumber();
_flagsComparison = (RoomFlagsComparison)file->readNumber();
_motherBlocked = file->readNumber();
_afterReceiveStartFrame = file->readNumber();
_afterReceiveEndFrame = file->readNumber();
_trayOutStartFrame = file->readNumber();
_trayOutEndFrame = file->readNumber();
_sendAction = (SuccUBusAction)file->readNumber();
_signalFlag = file->readNumber();
_signalTarget = file->readString();
_startFrame1 = file->readNumber();
_endFrame1 = file->readNumber();
_rect1.left = file->readNumber();
_rect1.top = file->readNumber();
_rect1.right = file->readNumber();
_rect1.bottom = file->readNumber();
_field184 = file->readNumber();
_mailPresent = file->readNumber();
_rect2.left = file->readNumber();
_rect2.top = file->readNumber();
_rect2.right = file->readNumber();
_rect2.bottom = file->readNumber();
_sendLost = file->readNumber();
_soundHandle = file->readNumber();
_isChicken = file->readNumber();
_isFeathers = file->readNumber();
_priorRandomVal1 = file->readNumber();
_priorRandomVal2 = file->readNumber();
_emptyStartFrame = file->readNumber();
_emptyEndFrame = file->readNumber();
_smokeStartFrame = file->readNumber();
_smokeEndFrame = file->readNumber();
_hoseStartFrame = file->readNumber();
_hoseEndFrame = file->readNumber();
_pumpingStartFrame = file->readNumber();
_pumpingEndFrame = file->readNumber();
_destRoomFlags = file->readNumber();
_fuseboxOn = file->readNumber();
_inProgress = file->readNumber();
_field104 = file->readNumber();
CTrueTalkNPC::load(file);
}
bool CSuccUBus::MouseButtonDownMsg(CMouseButtonDownMsg *msg) {
if (_inProgress)
return true;
Rect tempRect = _rect1;
tempRect.translate(_bounds.left, _bounds.top);
if (!_isOn) {
CTurnOn onMsg;
onMsg.execute(this);
_isOn = true;
return true;
}
if (_mailPresent && tempRect.contains(msg->_mousePos))
return true;
if (getRandomNumber(256) < 130) {
_isOn = false;
CTurnOff offMsg;
offMsg.execute(this);
} else {
switch (getRandomNumber(2, &_priorRandomVal1)) {
case 0:
startTalking(this, 230055, findView());
break;
case 1:
startTalking(this, 230067, findView());
break;
case 2:
startTalking(this, 230045, findView());
break;
default:
break;
}
}
return true;
}
bool CSuccUBus::SubAcceptCCarryMsg(CSubAcceptCCarryMsg *msg) {
if (!msg->_item)
return false;
CPetControl *pet = getPetControl();
CCarry *item = dynamic_cast<CCarry *>(msg->_item);
Rect tempRect = _rect2;
tempRect.translate(_bounds.left, _bounds.top);
uint roomFlags = pet ? pet->getRoomFlags() : 0;
if (!_isOn || !pet || !item || !tempRect.contains(item->getControid())) {
item->petAddToInventory();
} else if (mailExists(roomFlags)) {
petDisplayMessage(SUCCUBUS_DESCRIPTION);
item->petAddToInventory();
} else {
petContainerRemove(item);
pet->phonographAction("");
CChicken *chicken = dynamic_cast<CChicken *>(item);
bool chickenFlag = chicken ? chicken->_condiment == "None" : false;
item->setVisible(false);
if (_startFrame1 >= 0) {
playSound(TRANSLATE("z#23.wav", "z#554.wav"));
playMovie(_startFrame1, _endFrame1, 0);
}
if (!chickenFlag) {
// Not chicken, or chicken with condiments
_mailPresent = true;
item->addMail(roomFlags);
petSetArea(PET_REMOTE);
petHighlightGlyph(16);
CSUBTransition transMsg;
transMsg.execute(this);
} else {
// Chicken without condiments was passed to SuccUBus, so it'll
// eat it immediately
if (_okStartFrame >= 0) {
startTalking(this, 70219, findView());
playMovie(_okStartFrame, _okEndFrame, 0);
}
if (_sendStartFrame >= 0) {
playMovie(_sendStartFrame, _sendEndFrame, MOVIE_NOTIFY_OBJECT);
_sendAction = SA_EATEN;
}
// WORKAROUND: The original had code below to return the chicken
// to the dispensor after eaten, but since _fullViewName isn't
// set, it didn't work. I've added code below in the else block
// that replicates what happens when the parrot eats the chicken
CViewItem *view = parseView(chicken->_fullViewName);
if (view) {
item->setPosition(item->_origPos);
item->moveUnder(view);
CSUBTransition transMsg;
transMsg.execute(this);
} else {
CActMsg actMsg("Eaten");
actMsg.execute(chicken);
return false;
}
}
}
return true;
}
bool CSuccUBus::EnterViewMsg(CEnterViewMsg *msg) {
if (getRandomNumber(4) == 0 && compareRoomNameTo("PromenadeDeck")) {
CParrotSpeakMsg speakMsg("SuccUBus", "EnterView");
speakMsg.execute("PerchedParrot");
}
petSetRemoteTarget();
_mailP = nullptr;
if (_initialStartFrame >= 0)
loadFrame(_initialStartFrame);
return true;
}
bool CSuccUBus::LeaveViewMsg(CLeaveViewMsg *msg) {
petDisplayMessage(2, BLANK);
if (_initialStartFrame >= 0)
loadFrame(_initialStartFrame);
else if (!_signalFlag && _onStartFrame >= 0)
loadFrame(_onStartFrame);
petClear();
if (_soundHandle != -1) {
stopSound(_soundHandle, 1);
_soundHandle = -1;
}
if (_isOn) {
_isOn = false;
if (_offStartFrame >= 0)
playSound(TRANSLATE("z#27.wav", "z#558.wav"), 100);
if (_signalFlag)
setVisible(false);
}
performAction(true, findView());
CSUBTransition transMsg;
transMsg.execute(this);
return true;
}
bool CSuccUBus::PETDeliverMsg(CPETDeliverMsg *msg) {
if (_inProgress)
return true;
if (!_isOn) {
petDisplayMessage(2, SUCCUBUS_IS_IN_STANDBY);
return true;
}
CPetControl *pet = getPetControl();
if (!pet)
return true;
uint srcRoomFlags = pet->getRoomFlags();
CGameObject *mailObject = findMail(srcRoomFlags);
if (!mailObject) {
// Nothing to send
switch (getRandomNumber(2)) {
case 0:
startTalking(this, 70111, findView());
break;
case 1:
startTalking(this, 70112, findView());
break;
case 2:
startTalking(this, 70113, findView());
break;
default:
break;
}
petDisplayMessage(2, NOTHING_IN_SUCCUBUS_TRAY);
} else {
_sendLost = false;
CRoomFlags roomFlags = _destRoomFlags;
if (!pet->isSuccUBusDest(roomFlags) || pet->getMailDestClass(roomFlags) < getPassengerClass()) {
roomFlags = pet->getSpecialRoomFlags("BilgeRoom");
_sendLost = true;
}
_isFeathers = mailObject->getName() == "Feathers";
_isChicken = mailObject->getName() == "Chicken";
_sendAction = SA_SENT;
_mailPresent = false;
_inProgress = true;
lockMouse();
if (_isFeathers) {
// The feather has special handling to be rejected by the SuccUBus
_sendLost = false;
sendMail(srcRoomFlags, roomFlags);
pet->phonographAction("");
if (_okStartFrame >= 0) {
playMovie(_okStartFrame, _okEndFrame, 0);
startTalking(this, 230022, findView());
}
_sendAction = SA_FEATHERS;
if (_sendStartFrame >= 0)
playMovie(_sendStartFrame, _sendEndFrame, 0);
if (_receiveStartFrame >= 0) {
_mailP = mailObject;
playMovie(_receiveStartFrame, _receiveEndFrame, MOVIE_NOTIFY_OBJECT);
}
if (_afterReceiveStartFrame >= 0) {
playMovie(_afterReceiveStartFrame, _afterReceiveEndFrame, 0);
}
} else {
// Send the mail to the destination
sendMail(pet->getRoomFlags(), roomFlags);
pet->phonographAction("");
if (_okStartFrame >= 0) {
playMovie(_okStartFrame, _okEndFrame, 0);
startTalking(this, 230012, findView());
}
if (_sendStartFrame >= 0)
playMovie(_sendStartFrame, _sendEndFrame, MOVIE_NOTIFY_OBJECT);
}
}
return true;
}
bool CSuccUBus::PETReceiveMsg(CPETReceiveMsg *msg) {
CPetControl *pet = getPetControl();
if (_inProgress || !pet)
return true;
if (!_isOn) {
petDisplayMessage(2, SUCCUBUS_IS_IN_STANDBY);
return true;
}
uint petRoomFlags = pet->getRoomFlags();
if (mailExists(petRoomFlags)) {
// There's already something to send in the tray, so you can't receive
switch (getRandomNumber(2)) {
case 0:
startTalking(this, 70080, findView());
break;
case 1:
startTalking(this, 70081, findView());
break;
case 2:
startTalking(this, 70082, findView());
break;
default:
break;
}
} else {
// When the SuccUBus dial in Titania's fusebox is on, then
// any mail can be received by the SuccUBus in the bomb room.
// Otherwise, only get mail sent to this specific SuccUBus
CGameObject *mailObject = findMailByFlags(
_fuseboxOn && compareRoomNameTo("Titania") ? RFC_TITANIA : _flagsComparison, petRoomFlags);
if (!mailObject) {
// No mail for this SuccUBus
if (getRandomNumber(1) == 0) {
startTalking(this, 70104, findView());
} else {
startTalking(this, 70105, findView());
}
playMovie(_emptyStartFrame, _emptyEndFrame, 0);
playMovie(_smokeStartFrame, _smokeEndFrame, 0);
petDisplayMessage(2, NOTHING_TO_DELIVER);
} else {
// Receive the mail addressed to this SuccUBus
_mailP = mailObject;
startTalking(this, 230004, findView());
if (_receiveStartFrame >= 0) {
_sendAction = SA_FEATHERS;
_inProgress = true;
lockMouse();
playMovie(_receiveStartFrame, _receiveEndFrame, MOVIE_NOTIFY_OBJECT);
}
}
}
return true;
}
bool CSuccUBus::MovieEndMsg(CMovieEndMsg *msg) {
CPetControl *pet = getPetControl();
uint petRoomFlags = pet ? pet->getRoomFlags() : 0;
if (msg->_endFrame == _offEndFrame) {
if (_endingStartFrame >= 0)
playSound(TRANSLATE("z#30.wav", "z#561.wav"), 100);
if (_signalFlag) {
_signalFlag = false;
setVisible(false);
CSignalObject signalMsg;
signalMsg._numValue = 1;
signalMsg.execute(_signalTarget);
}
}
if (msg->_endFrame == _onEndFrame) {
bool flag = false;
if (pet && !mailExists(petRoomFlags)) {
CGameObject *mailObject = _fuseboxOn && compareRoomNameTo("Titania") ?
findMailByFlags(RFC_TITANIA, petRoomFlags) :
findMailByFlags(_flagsComparison, petRoomFlags);
if (mailObject) {
switch (getRandomNumber(4)) {
case 0:
startTalking(this, 70094, findView());
break;
case 1:
startTalking(this, 70095, findView());
break;
case 2:
startTalking(this, 70096, findView());
break;
case 3:
startTalking(this, 70098, findView());
break;
case 4:
startTalking(this, 70099, findView());
break;
default:
break;
}
flag = true;
}
}
if (!_mailPresent && !flag) {
stopSound(_soundHandle);
_soundHandle = -1;
switch (getRandomNumber(_motherBlocked ? 7 : 5, &_priorRandomVal2)) {
case 2:
startTalking(this, 230001, findView());
break;
case 3:
startTalking(this, 230002, findView());
break;
case 4:
startTalking(this, 230003, findView());
break;
case 5:
startTalking(this, 230064, findView());
break;
case 6:
startTalking(this, 230062, findView());
break;
case 7:
startTalking(this, 230063, findView());
break;
default:
break;
}
}
}
if (msg->_endFrame == _sendEndFrame) {
if (_sendAction == SA_FEATHERS) {
startTalking(this, 230022, findView());
} else if (_sendAction == SA_EATEN) {
startTalking(this, 230017, findView());
} else if (_sendLost) {
startTalking(this, 230019, findView());
_sendLost = false;
} else if (_isChicken) {
startTalking(this, 230018, findView());
_isChicken = false;
} else {
startTalking(this, 230013, findView());
}
if (_inProgress) {
_inProgress = false;
unlockMouse();
}
CSUBTransition transMsg;
transMsg.execute(this);
}
if (msg->_endFrame == _receiveEndFrame) {
// SuccUBus disgorged mail
if (pet && _mailP) {
_mailP->setMailDest(petRoomFlags);
}
_mailPresent = true;
_mailP = nullptr;
if (_inProgress) {
_inProgress = false;
unlockMouse();
}
CSUBTransition transMsg;
transMsg.execute(this);
}
return true;
}
bool CSuccUBus::TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg) {
if (msg->_stateNum == 1)
msg->_stateVal = _isOn;
return true;
}
bool CSuccUBus::SignalObject(CSignalObject *msg) {
if (msg->_numValue == 1) {
_signalTarget = msg->_strValue;
_signalFlag = true;
setVisible(true);
CTurnOn onMsg;
onMsg.execute(this);
}
return true;
}
bool CSuccUBus::TurnOn(CTurnOn *msg) {
if (getRandomNumber(9) == 0) {
CParrotSpeakMsg speakMsg("SuccUBus", "TurnOn");
speakMsg.execute("PerchedParrot");
}
CPetControl *pet = getPetControl();
if (pet) {
if (!_signalFlag && _initialStartFrame >= 0) {
playMovie(_initialStartFrame, _initialEndFrame, 0);
playSound(TRANSLATE("z#30.wav", "z#561.wav"), 100);
}
if (_onStartFrame >= 0) {
playMovie(_onStartFrame, _onEndFrame, MOVIE_NOTIFY_OBJECT);
playSound(TRANSLATE("z#26.wav", "z#557.wav"), 100);
}
uint petRoomFlags = pet->getRoomFlags();
if (mailExists(petRoomFlags) && _endFrame1 >= 0)
// Mail canister present
playMovie(_endFrame1, _endFrame1, 0);
_isOn = true;
CSUBTransition transMsg;
transMsg.execute(this);
setTalking(this, true, findView());
petSetArea(PET_REMOTE);
petHighlightGlyph(16);
}
return true;
}
bool CSuccUBus::TurnOff(CTurnOff *msg) {
if (_soundHandle != -1) {
stopSound(_soundHandle);
_soundHandle = -1;
}
if (_offStartFrame >= 0) {
playSound(TRANSLATE("z#27.wav", "z#558.wav"), 100);
playMovie(_offStartFrame, _offEndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
}
if (!_signalFlag && _endingStartFrame >= 0)
playMovie(_endingStartFrame, _endingEndFrame, MOVIE_NOTIFY_OBJECT | MOVIE_WAIT_FOR_FINISH);
_isOn = false;
performAction(true);
CSUBTransition transMsg;
transMsg.execute(this);
return true;
}
bool CSuccUBus::SUBTransition(CSUBTransition *msg) {
CPetControl *pet = getPetControl();
if (pet) {
uint petRoomFlags = pet->getRoomFlags();
if (_isOn) {
CGameObject *mailObject = findMail(petRoomFlags);
if (mailObject)
pet->phonographAction("Send");
else
pet->phonographAction("Receive");
} else {
if (pet->isSuccUBusRoom(petRoomFlags))
pet->phonographAction("Record");
else
pet->phonographAction("");
}
}
return true;
}
bool CSuccUBus::SetChevRoomBits(CSetChevRoomBits *msg) {
if (_isOn) {
_destRoomFlags = msg->_roomFlags;
playSound(TRANSLATE("z#98.wav", "z#629.wav"), 100);
}
return true;
}
bool CSuccUBus::ActMsg(CActMsg *msg) {
if (msg->_action == "EnableObject")
// SuccUBus dial in fusebox was turned on
_fuseboxOn = true;
else if (msg->_action == "DisableObject")
// SuccUBus dial in fusebox was turned off
_fuseboxOn = false;
return true;
}
bool CSuccUBus::MouseDragStartMsg(CMouseDragStartMsg *msg) {
CPetControl *pet = getPetControl();
Rect tempRect = _rect1;
tempRect.translate(_bounds.left, _bounds.top);
if (_inProgress || !_isOn || !_mailPresent || !tempRect.contains(msg->_mousePos)
|| !pet)
return true;
uint petRoomFlags = pet->getRoomFlags();
CGameObject *mailObject = findMail(petRoomFlags);
if (!mailObject)
return true;
petAddToCarryParcel(mailObject);
CViewItem *view = getView();
if (!view)
return true;
mailObject->moveUnder(view);
mailObject->setPosition(Point(msg->_mousePos.x + mailObject->_bounds.width() / 2,
msg->_mousePos.y + mailObject->_bounds.height() / 2));
CVisibleMsg visibleMsg(true);
visibleMsg.execute(mailObject);
CPassOnDragStartMsg dragMsg;
dragMsg._mousePos = msg->_mousePos;
dragMsg._value3 = 1;
dragMsg.execute(mailObject);
if (!dragMsg._value4)
msg->_dragItem = mailObject;
loadFrame(_field184);
_mailPresent = false;
CSUBTransition transMsg;
transMsg.execute(this);
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,117 @@
/* 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/>.
*
*/
#ifndef TITANIC_SUCCUBUS_H
#define TITANIC_SUCCUBUS_H
#include "titanic/npcs/true_talk_npc.h"
#include "titanic/messages/pet_messages.h"
namespace Titanic {
enum SuccUBusAction { SA_SENT = 0, SA_FEATHERS = 1, SA_EATEN = 2,
SA_BILGE_FEATHERS = 3, SA_BILGE_SENT = 4, SA_BILGE_EATEN = 5 };
class CSuccUBus : public CTrueTalkNPC {
DECLARE_MESSAGE_MAP;
bool MouseButtonDownMsg(CMouseButtonDownMsg *msg);
bool SubAcceptCCarryMsg(CSubAcceptCCarryMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool LeaveViewMsg(CLeaveViewMsg *msg);
bool PETDeliverMsg(CPETDeliverMsg *msg);
bool PETReceiveMsg(CPETReceiveMsg *msg);
bool MovieEndMsg(CMovieEndMsg *msg);
bool TrueTalkGetStateValueMsg(CTrueTalkGetStateValueMsg *msg);
bool SignalObject(CSignalObject *msg);
bool TurnOn(CTurnOn *msg);
bool TurnOff(CTurnOff *msg);
bool SUBTransition(CSUBTransition *msg);
bool SetChevRoomBits(CSetChevRoomBits *msg);
bool ActMsg(CActMsg *msg);
bool MouseDragStartMsg(CMouseDragStartMsg *msg);
protected:
static bool _isOn;
static bool _motherBlocked;
static bool _fuseboxOn;
protected:
int _initialStartFrame;
int _initialEndFrame;
int _endingStartFrame;
int _endingEndFrame;
int _sendStartFrame;
int _sendEndFrame;
int _receiveStartFrame;
int _receiveEndFrame;
int _onStartFrame;
int _onEndFrame;
int _offStartFrame;
int _offEndFrame;
int _okStartFrame;
int _okEndFrame;
RoomFlagsComparison _flagsComparison;
CGameObject *_mailP;
int _afterReceiveStartFrame;
int _afterReceiveEndFrame;
int _trayOutStartFrame;
int _trayOutEndFrame;
SuccUBusAction _sendAction;
bool _signalFlag;
CString _signalTarget;
int _startFrame1;
int _endFrame1;
Rect _rect1;
int _field184;
bool _mailPresent;
Rect _rect2;
bool _sendLost;
int _soundHandle;
bool _isChicken;
bool _isFeathers;
int _priorRandomVal1;
int _priorRandomVal2;
int _emptyStartFrame;
int _emptyEndFrame;
int _smokeStartFrame;
int _smokeEndFrame;
int _hoseStartFrame;
int _hoseEndFrame;
int _pumpingStartFrame;
int _pumpingEndFrame;
uint _destRoomFlags;
bool _inProgress;
public:
CLASSDEF;
CSuccUBus();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_SUCCUBUS_H */

View File

@@ -0,0 +1,85 @@
/* 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/summon_bots.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CSummonBots, CRobotController)
ON_MESSAGE(SummonBotQueryMsg)
ON_MESSAGE(SummonBotMsg)
END_MESSAGE_MAP()
CSummonBots::CSummonBots() : CRobotController(), _validSummonLocations("NULL"),
_canSummonBellbot(false), _canSummonDoorbot(false) {
}
void CSummonBots::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_canSummonBellbot, indent);
file->writeNumberLine(_canSummonDoorbot, indent);
file->writeQuotedLine(_validSummonLocations, indent);
CRobotController::save(file, indent);
}
void CSummonBots::load(SimpleFile *file) {
file->readNumber();
_canSummonBellbot = file->readNumber();
_canSummonDoorbot = file->readNumber();
_validSummonLocations = file->readString();
CRobotController::load(file);
}
bool CSummonBots::SummonBotQueryMsg(CSummonBotQueryMsg *msg) {
if (msg->_npcName == "BellBot") {
if (_canSummonBellbot && !petCheckNode(_validSummonLocations))
return true;
} else if (msg->_npcName == "DoorBot") {
if (_canSummonDoorbot && !petCheckNode(_validSummonLocations))
return true;
}
return false;
}
bool CSummonBots::SummonBotMsg(CSummonBotMsg *msg) {
if (msg->_npcName == "BellBot") {
if (!_canSummonBellbot)
return false;
if (!petDismissBot("BellBot"))
petOnSummonBot("Bellbot", msg->_value);
} else if (msg->_npcName == "DoorBot") {
if (!_canSummonDoorbot)
return false;
if (!petDismissBot("Doorbot"))
petOnSummonBot("Doorbot", msg->_value);
} else {
return false;
}
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,54 @@
/* 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/>.
*
*/
#ifndef TITANIC_SUMMON_BOTS_H
#define TITANIC_SUMMON_BOTS_H
#include "titanic/npcs/robot_controller.h"
namespace Titanic {
class CSummonBots : public CRobotController {
DECLARE_MESSAGE_MAP;
bool SummonBotQueryMsg(CSummonBotQueryMsg *msg);
bool SummonBotMsg(CSummonBotMsg *msg);
protected:
CString _validSummonLocations;
bool _canSummonBellbot;
bool _canSummonDoorbot;
public:
CLASSDEF;
CSummonBots();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_SUMMON_BOTS_H */

View File

@@ -0,0 +1,234 @@
/* 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/titania.h"
#include "titanic/translation.h"
namespace Titanic {
BEGIN_MESSAGE_MAP(CTitania, CCharacter)
ON_MESSAGE(AddHeadPieceMsg)
ON_MESSAGE(TakeHeadPieceMsg)
ON_MESSAGE(ActMsg)
ON_MESSAGE(EnterViewMsg)
ON_MESSAGE(TimerMsg)
END_MESSAGE_MAP()
CTitania::CTitania() : CCharacter() {
_speechCentre = false;
_olfactoryCentre = false;
_centralCore = false;
_visionCentre = false;
_eye1 = false;
_eye2 = false;
_ear1 = false;
_ear2 = false;
_nose = false;
_mouth = false;
_showSpeech = true;
}
void CTitania::save(SimpleFile *file, int indent) {
file->writeNumberLine(1, indent);
file->writeNumberLine(_speechCentre, indent);
file->writeNumberLine(_olfactoryCentre, indent);
file->writeNumberLine(_auditoryCentre, indent);
file->writeNumberLine(_centralCore, indent);
file->writeNumberLine(_visionCentre, indent);
file->writeNumberLine(_eye1, indent);
file->writeNumberLine(_eye2, indent);
file->writeNumberLine(_ear1, indent);
file->writeNumberLine(_ear2, indent);
file->writeNumberLine(_nose, indent);
file->writeNumberLine(_mouth, indent);
file->writeNumberLine(_showSpeech, indent);
CCharacter::save(file, indent);
}
void CTitania::load(SimpleFile *file) {
file->readNumber();
_speechCentre = file->readNumber();
_olfactoryCentre = file->readNumber();
_auditoryCentre = file->readNumber();
_centralCore = file->readNumber();
_visionCentre = file->readNumber();
_eye1 = file->readNumber();
_eye2 = file->readNumber();
_ear1 = file->readNumber();
_ear2 = file->readNumber();
_nose = file->readNumber();
_mouth = file->readNumber();
_showSpeech = file->readNumber();
CCharacter::load(file);
}
bool CTitania::AddHeadPieceMsg(CAddHeadPieceMsg *msg) {
if (msg->_value == "VisionCentre") {
_visionCentre = true;
} else if (msg->_value == "AuditoryCentre") {
_auditoryCentre = true;
} else if (msg->_value == "OlfactoryCentre") {
_olfactoryCentre = true;
} else if (msg->_value == "SpeechCentre") {
_speechCentre = true;
} else if (msg->_value == "CentralCore") {
_centralCore = true;
} else if (msg->_value == "Eye1") {
_eye1 = true;
} else if (msg->_value == "Eye2") {
_eye2 = true;
} else if (msg->_value == "Ear1") {
_ear1 = true;
} else if (msg->_value == "Ear 2") {
_ear2 = true;
} else if (msg->_value == "Mouth") {
_mouth = true;
} else if (msg->_value == "Nose") {
_nose = true;
}
CActMsg actMsg("CheckHead");
actMsg.execute(this);
return true;
}
bool CTitania::TakeHeadPieceMsg(CTakeHeadPieceMsg *msg) {
if (msg->_value == "VisionCentre") {
_visionCentre = false;
} else if (msg->_value == "AuditoryCentre") {
_auditoryCentre = false;
} else if (msg->_value == "OlfactoryCentre") {
_olfactoryCentre = false;
} else if (msg->_value == "SpeechCentre") {
_speechCentre = false;
} else if (msg->_value == "CentralCore") {
_centralCore = false;
} else if (msg->_value == "Eye1") {
_eye1 = false;
} else if (msg->_value == "Eye2") {
_eye2 = false;
} else if (msg->_value == "Ear1") {
_ear1 = false;
} else if (msg->_value == "Ear 2") {
_ear2 = false;
} else if (msg->_value == "Mouth") {
_mouth = false;
} else if (msg->_value == "Nose") {
_nose = false;
}
CActMsg actMsg("CheckHead");
actMsg.execute(this);
return true;
}
bool CTitania::ActMsg(CActMsg *msg) {
if (msg->_action == "SleepTitania") {
setVisible(true);
playCutscene(52, 104);
playSound(TRANSLATE("z#47.wav", "z#578.wav"), 100);
changeView("Titania.Node 7.S", "");
// Re-enable control, and reset bomb's volume back to normal 60%
petShow();
enableMouse();
CSetFrameMsg frameMsg(60);
frameMsg.execute("Bomb");
} else if (msg->_action == "CheckHead") {
CSenseWorkingMsg workingMsg1("Not Working");
CSenseWorkingMsg workingMsg2("Not Working");
CSenseWorkingMsg workingMsg3("Not Working");
CSenseWorkingMsg workingMsg4("Not Working");
if (_eye1 && _eye2) {
workingMsg1._value = _visionCentre ? "Working" : "Random";
}
if (_ear1 && _ear2) {
workingMsg2._value = _auditoryCentre ? "Working" : "Random";
}
if (_nose) {
workingMsg4._value = _olfactoryCentre ? "Working" : "Random";
}
if (_mouth) {
workingMsg3._value = _speechCentre ? "Working" : "Random";
}
if (_centralCore && _eye1 && _eye2 && _ear1 && _ear2 && _nose
&& _mouth && _visionCentre && _speechCentre
&& _olfactoryCentre && _auditoryCentre) {
CProximity prox(Audio::Mixer::kSpeechSoundType);
playSound(TRANSLATE("z#47.wav", "z#578.wav"), prox);
CActMsg actMsg("Woken");
actMsg.execute("MouthSlot");
actMsg.execute("VisionCentreSlot");
setPassengerClass(UNCHECKED);
addTimer(1000);
} else {
workingMsg1.execute("Eye1Slot");
workingMsg1.execute("Eye2Slot");
workingMsg2.execute("Ear1Slot");
workingMsg2.execute("Ear2Slot");
workingMsg3.execute("MouthSlot");
workingMsg4.execute("NoseSlot");
}
}
return true;
}
bool CTitania::EnterViewMsg(CEnterViewMsg *msg) {
if (_showSpeech) {
_showSpeech = false;
disableMouse();
petHide();
// The Bomb uses the CSetFrameMsg as a hack for setting the volume.
// In case it's currently active, set it to a quieter 25% so that
// it won't obscure Titania's speech.
CSetFrameMsg frameMsg;
frameMsg._frameNumber = 25;
frameMsg.execute("Bomb");
playCutscene(0, 52);
setVisible(false);
CActMsg actMsg("TitaniaSpeech");
actMsg.execute("TitaniaSpeech");
}
return true;
}
bool CTitania::TimerMsg(CTimerMsg *msg) {
// WORKAROUND: The original uses the disc change dialog as a pause
// to allow the parrot speech to finish. I've rewritten it to instead
// use the standard TrueTalkNotifySpeechEndedMsg message instead
startTalking("PerchedParrot", 80022);
lockMouse();
return true;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,66 @@
/* 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/>.
*
*/
#ifndef TITANIC_TITANIA_H
#define TITANIC_TITANIA_H
#include "titanic/npcs/character.h"
namespace Titanic {
class CTitania : public CCharacter {
DECLARE_MESSAGE_MAP;
bool AddHeadPieceMsg(CAddHeadPieceMsg *msg);
bool TakeHeadPieceMsg(CTakeHeadPieceMsg *msg);
bool ActMsg(CActMsg *msg);
bool EnterViewMsg(CEnterViewMsg *msg);
bool TimerMsg(CTimerMsg *msg);
private:
bool _speechCentre;
bool _olfactoryCentre;
bool _auditoryCentre;
bool _centralCore;
bool _visionCentre;
bool _eye1;
bool _eye2;
bool _ear1;
bool _ear2;
bool _nose;
bool _mouth;
bool _showSpeech;
public:
CLASSDEF;
CTitania();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
} // End of namespace Titanic
#endif /* TITANIC_TITANIA_H */

View File

@@ -0,0 +1,262 @@
/* 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

View File

@@ -0,0 +1,101 @@
/* 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/>.
*
*/
#ifndef TITANIC_TRUE_TALK_NPC_H
#define TITANIC_TRUE_TALK_NPC_H
#include "titanic/npcs/character.h"
#include "titanic/messages/messages.h"
#include "titanic/true_talk/tt_talker.h"
namespace Titanic {
enum NpcFlag {
NPCFLAG_SPEAKING = 1, NPCFLAG_IDLING = 2, NPCFLAG_START_IDLING = 4,
NPCFLAG_DOORBOT_IN_HOME = 8, NPCFLAG_MOVING = 0x10000, NPCFLAG_MOVE_START = 0x20000,
NPCFLAG_MOVE_LOOP = 0x40000, NPCFLAG_MOVE_FINISH = 0x80000,
NPCFLAG_MOVE_LEFT = 0x100000, NPCFLAG_MOVE_RIGHT = 0x200000,
NPCFLAG_MOVE_END = 0x400000, NPCFLAG_PECKING = 0x800000,
NPCFLAG_CHICKEN_OUTSIDE_CAGE = 0x1000000, NPCFLAG_TAKE_OFF = 0x2000000,
NPCFLAG_SUMMON_BELLBOT = 0x4000000, NPCFLAG_DOORBOT_INTRO = 0x8000000
};
class CViewItem;
class CTrueTalkNPC : public CCharacter {
DECLARE_MESSAGE_MAP;
bool TextInputMsg(CTextInputMsg *msg);
bool TrueTalkGetAssetDetailsMsg(CTrueTalkGetAssetDetailsMsg *msg);
bool DismissBotMsg(CDismissBotMsg *msg);
bool TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg);
bool TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg);
bool MovieEndMsg(CMovieEndMsg *msg);
bool NPCQueueIdleAnimMsg(CNPCQueueIdleAnimMsg *msg);
bool TimerMsg(CTimerMsg *msg);
bool NPCPlayAnimationMsg(CNPCPlayAnimationMsg *msg);
protected:
int _assetNumber;
CString _assetName;
int _fieldE4;
uint _npcFlags;
uint _speechDuration;
uint _startTicks;
int _fieldF4;
int _fieldF8;
int _speechTimerId;
int _field104;
protected:
void processInput(CTextInputMsg *msg, CViewItem *view);
public:
int _speechCounter;
public:
CLASSDEF;
CTrueTalkNPC();
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
/**
* Set the view for the NPC
*/
void setView(CViewItem *view);
/**
* Start the talker in the given view
*/
void startTalker(CViewItem *view);
/**
* Perform an action
*/
void performAction(bool startTalking, CViewItem *view = nullptr);
};
} // End of namespace Titanic
#endif /* TITANIC_TRUE_TALK_NPC_H */