1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "titanic/npcs/maitre_d.h"
24 #include "titanic/core/room_item.h"
25 #include "titanic/sound/music_room.h"
26
27 namespace Titanic {
28
BEGIN_MESSAGE_MAP(CMaitreD,CTrueTalkNPC)29 BEGIN_MESSAGE_MAP(CMaitreD, CTrueTalkNPC)
30 ON_MESSAGE(RestaurantMusicChanged)
31 ON_MESSAGE(TrueTalkTriggerActionMsg)
32 ON_MESSAGE(EnterViewMsg)
33 ON_MESSAGE(LeaveViewMsg)
34 ON_MESSAGE(NPCPlayTalkingAnimationMsg)
35 ON_MESSAGE(TimerMsg)
36 ON_MESSAGE(TrueTalkNotifySpeechStartedMsg)
37 ON_MESSAGE(TrueTalkNotifySpeechEndedMsg)
38 ON_MESSAGE(LoadSuccessMsg)
39 ON_MESSAGE(TextInputMsg)
40 ON_MESSAGE(TriggerNPCEvent)
41 END_MESSAGE_MAP()
42
43 CMaitreD::CMaitreD() : CTrueTalkNPC(),
44 _priorMusicName("z#40.wav"), _musicName("z#40.wav"), _unused5(0), _hasMusic(true),
45 _musicSet(false), _fightFlag(false), _unused6(true), _savedFightFlag(false),
46 _timerId(0), _defeated(false) {
47 }
48
save(SimpleFile * file,int indent)49 void CMaitreD::save(SimpleFile *file, int indent) {
50 file->writeNumberLine(1, indent);
51 file->writeNumberLine(_unused5, indent);
52 file->writeQuotedLine(_priorMusicName, indent);
53 file->writeNumberLine(_hasMusic, indent);
54 file->writeNumberLine(_musicSet, indent);
55 file->writeQuotedLine(_musicName, indent);
56 file->writeNumberLine(_fightFlag, indent);
57 file->writeNumberLine(_unused6, indent);
58
59 file->writeNumberLine(_defeated, indent);
60 file->writeNumberLine(_savedFightFlag, indent);
61 file->writeNumberLine(_timerId, indent);
62
63 CTrueTalkNPC::save(file, indent);
64 }
65
load(SimpleFile * file)66 void CMaitreD::load(SimpleFile *file) {
67 file->readNumber();
68 _unused5 = file->readNumber();
69 _priorMusicName = file->readString();
70 _hasMusic = file->readNumber();
71 _musicSet = file->readNumber();
72 _musicName = file->readString();
73 _fightFlag = file->readNumber();
74 _unused6 = file->readNumber();
75
76 _defeated = file->readNumber();
77 _savedFightFlag = file->readNumber();
78 _timerId = file->readNumber();
79
80 CTrueTalkNPC::load(file);
81
82 // WORKAROUND: The back view of the MaitreD from close to the table is dodgy
83 // in the original. And unneeded anyway, since he's also part of the background
84 if (_name == "MaitreLoop03")
85 _visible = false;
86 }
87
RestaurantMusicChanged(CRestaurantMusicChanged * msg)88 bool CMaitreD::RestaurantMusicChanged(CRestaurantMusicChanged *msg) {
89 if (msg->_value.empty()) {
90 _hasMusic = false;
91 } else {
92 _musicName = msg->_value;
93 _hasMusic = _musicSet = true;
94 }
95
96 return true;
97 }
98
TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg * msg)99 bool CMaitreD::TrueTalkTriggerActionMsg(CTrueTalkTriggerActionMsg *msg) {
100 if (msg->_action == 8) {
101 _fightFlag = true;
102 stopAnimTimer(_timerId);
103 _timerId = startAnimTimer("MD Fight", 3500, 0);
104 } else if (msg->_action == 9) {
105 stopAnimTimer(_timerId);
106 _timerId = 0;
107 } else if (msg->_action == 10) {
108 _fightFlag = false;
109 _defeated = true;
110 stopAnimTimer(_timerId);
111 _timerId = 0;
112
113 CMaitreDDefeatedMsg defeatedMsg;
114 defeatedMsg.execute(findRoom());
115 }
116
117 return true;
118 }
119
EnterViewMsg(CEnterViewMsg * msg)120 bool CMaitreD::EnterViewMsg(CEnterViewMsg *msg) {
121 setTalking(this, true, findView());
122 _fightFlag = _savedFightFlag;
123
124 if (_musicName != "STMusic" && (!_musicSet || _priorMusicName == _musicName))
125 return true;
126
127 // WORKAROUND: It's possible in the original to not have a music handler set
128 // if you start and stop the phonograph, then save and restore the game
129 if (!CMusicRoom::_musicHandler)
130 return true;
131
132 if (_musicName.contains("nasty ambient"))
133 startTalking(this, 111, findView());
134 else if (!CMusicRoom::_musicHandler->checkInstrument(SNAKE))
135 startTalking(this, 114, findView());
136 else if (!CMusicRoom::_musicHandler->checkInstrument(BASS))
137 startTalking(this, 113, findView());
138 else if (!CMusicRoom::_musicHandler->checkInstrument(PIANO))
139 startTalking(this, 115, findView());
140 else {
141 startTalking(this, 110, findView());
142 CMaitreDHappyMsg happyMsg;
143 happyMsg.execute("MaitreD Left Arm");
144 happyMsg.execute("MaitreD Right Arm");
145 }
146
147 _priorMusicName = _musicName;
148 return true;
149 }
150
LeaveViewMsg(CLeaveViewMsg * msg)151 bool CMaitreD::LeaveViewMsg(CLeaveViewMsg *msg) {
152 _savedFightFlag = _fightFlag;
153 performAction(true);
154 stopAnimTimer(_timerId);
155 _timerId = 0;
156
157 _fightFlag = false;
158 return true;
159 }
160
NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg * msg)161 bool CMaitreD::NPCPlayTalkingAnimationMsg(CNPCPlayTalkingAnimationMsg *msg) {
162 static const char *const NAMES[] = {
163 "Talking0", "Talking1", "Talking2", "Talking3", "Talking4",
164 "Talking5", "Talking6", "Talking7", nullptr
165 };
166
167 if (msg->_value2 != 2) {
168 msg->_names = NAMES;
169
170 CAnimateMaitreDMsg animMsg;
171 if (_fightFlag)
172 animMsg._value = 0;
173 animMsg.execute(this, nullptr, MSGFLAG_SCAN);
174 }
175
176 return true;
177 }
178
TimerMsg(CTimerMsg * msg)179 bool CMaitreD::TimerMsg(CTimerMsg *msg) {
180 if (msg->_action == "MD Fight") {
181 if (_fightFlag && compareViewNameTo("1stClassRestaurant.MaitreD Node.N")) {
182 startTalking(this, 131, findView());
183 }
184 } else {
185 CTrueTalkNPC::TimerMsg(msg);
186 }
187
188 return true;
189 }
190
TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg * msg)191 bool CMaitreD::TrueTalkNotifySpeechStartedMsg(CTrueTalkNotifySpeechStartedMsg *msg) {
192 if (_fightFlag) {
193 stopAnimTimer(_timerId);
194 _timerId = 0;
195 }
196
197 CTrueTalkNPC::TrueTalkNotifySpeechStartedMsg(msg);
198 return true;
199 }
200
TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg * msg)201 bool CMaitreD::TrueTalkNotifySpeechEndedMsg(CTrueTalkNotifySpeechEndedMsg *msg) {
202 if (_fightFlag) {
203 stopAnimTimer(_timerId);
204 _timerId = startAnimTimer("MD Fight", 3000 + getRandomNumber(3000));
205 }
206
207 CTrueTalkNPC::TrueTalkNotifySpeechEndedMsg(msg);
208 return true;
209 }
210
LoadSuccessMsg(CLoadSuccessMsg * msg)211 bool CMaitreD::LoadSuccessMsg(CLoadSuccessMsg *msg) {
212 if (_fightFlag) {
213 _timerId = startAnimTimer("MD Fight", 3000 + getRandomNumber(3000));
214 }
215
216 return true;
217 }
218
TextInputMsg(CTextInputMsg * msg)219 bool CMaitreD::TextInputMsg(CTextInputMsg *msg) {
220 CTrueTalkNPC::processInput(msg, findView());
221 return true;
222 }
223
TriggerNPCEvent(CTriggerNPCEvent * msg)224 bool CMaitreD::TriggerNPCEvent(CTriggerNPCEvent *msg) {
225 startTalking(this, msg->_value, findView());
226 return true;
227 }
228
229 } // End of namespace Titanic
230