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 "sludge/allfiles.h"
24 #include "sludge/backdrop.h"
25 #include "sludge/fonttext.h"
26 #include "sludge/freeze.h"
27 #include "sludge/graphics.h"
28 #include "sludge/moreio.h"
29 #include "sludge/newfatal.h"
30 #include "sludge/objtypes.h"
31 #include "sludge/people.h"
32 #include "sludge/region.h"
33 #include "sludge/sludge.h"
34 #include "sludge/sludger.h"
35 #include "sludge/sound.h"
36 #include "sludge/speech.h"
37 #include "sludge/sprbanks.h"
38 #include "sludge/sprites.h"
39
40 namespace Sludge {
41
init()42 void SpeechManager::init() {
43 _speechMode = 0;
44 _speechSpeed = 1;
45 _speech = new SpeechStruct;
46 if (checkNew(_speech)) {
47 _speech->currentTalker = NULL;
48 _speech->allSpeech.clear();
49 _speech->speechY = 0;
50 _speech->lastFile = -1;
51 }
52 }
53
kill()54 void SpeechManager::kill() {
55 if (!_speech)
56 return;
57
58 if (_speech->lastFile != -1) {
59 _vm->_soundMan->huntKillSound(_speech->lastFile);
60 _speech->lastFile = -1;
61 }
62
63 if (_speech->currentTalker) {
64 _speech->currentTalker->makeSilent();
65 _speech->currentTalker = nullptr;
66 }
67
68 for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
69 SpeechLine *killMe = *it;
70 delete killMe;
71 killMe = nullptr;
72 }
73 _speech->allSpeech.clear();
74 }
75
setObjFontColour(ObjectType * t)76 void SpeechManager::setObjFontColour(ObjectType *t) {
77 _speech->talkCol.setColor(t->r, t->g, t->b);
78 }
79
addSpeechLine(const Common::String & theLine,int x,int & offset)80 void SpeechManager::addSpeechLine(const Common::String &theLine, int x, int &offset) {
81 float cameraZoom = g_sludge->_gfxMan->getCamZoom();
82 int halfWidth = (g_sludge->_txtMan->stringWidth(theLine) >> 1) / cameraZoom;
83 int xx1 = x - (halfWidth);
84 int xx2 = x + (halfWidth);
85
86 // Create new speech line
87 SpeechLine *newLine = new SpeechLine;
88 checkNew(newLine);
89 newLine->textLine.clear();
90 newLine->textLine = theLine;
91 newLine->x = xx1;
92 _speech->allSpeech.push_front(newLine);
93
94 // Calculate offset
95 if ((xx1 < 5) && (offset < (5 - xx1))) {
96 offset = 5 - xx1;
97 } else if ((xx2 >= ((float) g_system->getWidth() / cameraZoom) - 5)
98 && (offset > (((float) g_system->getWidth() / cameraZoom) - 5 - xx2))) {
99 offset = ((float) g_system->getWidth() / cameraZoom) - 5 - xx2;
100 }
101 }
102
isThereAnySpeechGoingOn()103 int SpeechManager::isThereAnySpeechGoingOn() {
104 return _speech->allSpeech.empty() ? -1 : _speech->lookWhosTalking;
105 }
106
getLastSpeechSound()107 int SpeechManager::getLastSpeechSound() {
108 return _vm->_soundMan->findInSoundCache(_speech->lastFile);
109 }
110
wrapSpeechXY(const Common::String & theText,int x,int y,int wrap,int sampleFile)111 int SpeechManager::wrapSpeechXY(const Common::String &theText, int x, int y, int wrap, int sampleFile) {
112 float cameraZoom = g_sludge->_gfxMan->getCamZoom();
113 int fontHeight = g_sludge->_txtMan->getFontHeight();
114 int cameraY = g_sludge->_gfxMan->getCamY();
115
116 int a, offset = 0;
117
118 kill();
119
120 int speechTime = (theText.size() + 20) * _speechSpeed;
121 if (speechTime < 1)
122 speechTime = 1;
123 if (sampleFile != -1) {
124 if (_speechMode >= 1) {
125 if (g_sludge->_soundMan->startSound(sampleFile, false)) {
126 speechTime = -10;
127 _speech->lastFile = sampleFile;
128 if (_speechMode == 2) return -10;
129 }
130
131 }
132 }
133 _speech->speechY = y;
134
135 char *tmp, *txt;
136 tmp = txt = createCString(theText);
137 while ((int)strlen(txt) > wrap) {
138 a = wrap;
139 while (txt[a] != ' ') {
140 a--;
141 if (a == 0) {
142 a = wrap;
143 break;
144 }
145 }
146 txt[a] = 0;
147 addSpeechLine(txt, x, offset);
148 txt[a] = ' ';
149 txt += a + 1;
150 y -= fontHeight / cameraZoom;
151 }
152 addSpeechLine(txt, x, offset);
153 y -= fontHeight / cameraZoom;
154 delete []tmp;
155
156 if (y < 0)
157 _speech->speechY -= y;
158 else if (_speech->speechY > cameraY + (float) (g_system->getHeight() - fontHeight / 3) / cameraZoom)
159 _speech->speechY = cameraY
160 + (float) (g_system->getHeight() - fontHeight / 3) / cameraZoom;
161
162 if (offset) {
163 for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
164 (*it)->x += offset;
165 }
166 }
167 return speechTime;
168 }
169
wrapSpeechPerson(const Common::String & theText,OnScreenPerson & thePerson,int sampleFile,bool animPerson)170 int SpeechManager::wrapSpeechPerson(const Common::String &theText, OnScreenPerson &thePerson, int sampleFile, bool animPerson) {
171 int cameraX = g_sludge->_gfxMan->getCamX();
172 int cameraY = g_sludge->_gfxMan->getCamY();
173 int i = wrapSpeechXY(theText, thePerson.x - cameraX,
174 thePerson.y - cameraY
175 - (thePerson.scale * (thePerson.height - thePerson.floaty))
176 - thePerson.thisType->speechGap,
177 thePerson.thisType->wrapSpeech, sampleFile);
178 if (animPerson) {
179 thePerson.makeTalker();
180 _speech->currentTalker = &thePerson;
181 }
182 return i;
183 }
184
wrapSpeech(const Common::String & theText,int objT,int sampleFile,bool animPerson)185 int SpeechManager::wrapSpeech(const Common::String &theText, int objT, int sampleFile, bool animPerson) {
186 int i;
187 int cameraX = g_sludge->_gfxMan->getCamX();
188 int cameraY = g_sludge->_gfxMan->getCamY();
189
190 _speech->lookWhosTalking = objT;
191 OnScreenPerson *thisPerson = g_sludge->_peopleMan->findPerson(objT);
192 if (thisPerson) {
193 setObjFontColour(thisPerson->thisType);
194 i = wrapSpeechPerson(theText, *thisPerson, sampleFile, animPerson);
195 } else {
196 ScreenRegion *thisRegion = g_sludge->_regionMan->getRegionForObject(objT);
197 if (thisRegion) {
198 setObjFontColour(thisRegion->thisType);
199 i = wrapSpeechXY(theText,
200 ((thisRegion->x1 + thisRegion->x2) >> 1) - cameraX,
201 thisRegion->y1 - thisRegion->thisType->speechGap - cameraY,
202 thisRegion->thisType->wrapSpeech, sampleFile);
203 } else {
204 ObjectType *temp = g_sludge->_objMan->findObjectType(objT);
205 setObjFontColour(temp);
206 i = wrapSpeechXY(theText, g_system->getWidth() >> 1, 10, temp->wrapSpeech,
207 sampleFile);
208 }
209 }
210 return i;
211 }
212
display()213 void SpeechManager::display() {
214 float cameraZoom = g_sludge->_gfxMan->getCamZoom();
215 int fontHeight = g_sludge->_txtMan->getFontHeight();
216 int viewY = _speech->speechY;
217 for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
218 g_sludge->_txtMan->pasteString((*it)->textLine, (*it)->x, viewY, _speech->talkCol);
219 viewY -= fontHeight / cameraZoom;
220 }
221 }
222
save(Common::WriteStream * stream)223 void SpeechManager::save(Common::WriteStream *stream) {
224 stream->writeByte(_speechMode);
225 stream->writeByte(_speech->talkCol.originalRed);
226 stream->writeByte(_speech->talkCol.originalGreen);
227 stream->writeByte(_speech->talkCol.originalBlue);
228
229 stream->writeFloatLE(_speechSpeed);
230
231 // Write y co-ordinate
232 stream->writeUint16BE(_speech->speechY);
233
234 // Write which character's talking
235 stream->writeUint16BE(_speech->lookWhosTalking);
236 if (_speech->currentTalker) {
237 stream->writeByte(1);
238 stream->writeUint16BE(_speech->currentTalker->thisType->objectNum);
239 } else {
240 stream->writeByte(0);
241 }
242
243 // Write what's being said
244 for (SpeechLineList::iterator it = _speech->allSpeech.begin(); it != _speech->allSpeech.end(); ++it) {
245 stream->writeByte(1);
246 writeString((*it)->textLine, stream);
247 stream->writeUint16BE((*it)->x);
248 }
249 stream->writeByte(0);
250 }
251
load(Common::SeekableReadStream * stream)252 bool SpeechManager::load(Common::SeekableReadStream *stream) {
253 // read speech mode
254 _speechMode = stream->readByte();
255
256 _speech->currentTalker = nullptr;
257 kill();
258 byte r = stream->readByte();
259 byte g = stream->readByte();
260 byte b = stream->readByte();
261 _speech->talkCol.setColor(r, g, b);
262 _speechSpeed = stream->readFloatLE();
263
264 // Read y co-ordinate
265 _speech->speechY = stream->readUint16BE();
266
267 // Read which character's talking
268 _speech->lookWhosTalking = stream->readUint16BE();
269
270 if (stream->readByte()) {
271 _speech->currentTalker = g_sludge->_peopleMan->findPerson(stream->readUint16BE());
272 } else {
273 _speech->currentTalker = NULL;
274 }
275
276 // Read what's being said
277 _speech->lastFile = -1;
278 while (stream->readByte()) {
279 SpeechLine *newOne = new SpeechLine;
280 if (!checkNew(newOne))
281 return false;
282 newOne->textLine = readString(stream);
283 newOne->x = stream->readUint16BE();
284 _speech->allSpeech.push_back(newOne);
285 }
286 return true;
287 }
288
freeze(FrozenStuffStruct * frozenStuff)289 void SpeechManager::freeze(FrozenStuffStruct *frozenStuff) {
290 frozenStuff->speech = _speech;
291 init();
292 }
293
restore(FrozenStuffStruct * frozenStuff)294 void SpeechManager::restore(FrozenStuffStruct *frozenStuff) {
295 kill();
296 delete _speech;
297 _speech = frozenStuff->speech;
298 }
299
300 } // End of namespace Sludge
301