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