1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
|
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "common/textconsole.h"
#include "common/util.h"
#include "sword1/objectman.h"
#include "sword1/sworddefs.h"
#include "sword1/swordres.h"
#include "sword1/sword1.h"
namespace Sword1 {
ObjectMan::ObjectMan(ResMan *pResourceMan) {
_resMan = pResourceMan;
}
void ObjectMan::initialize() {
uint16 cnt;
for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
_liveList[cnt] = 0; // we don't need to close the files here. When this routine is
// called, the memory was flushed() anyways, so these resources
// already *are* closed.
_liveList[128] = _liveList[129] = _liveList[130] = _liveList[131] = _liveList[133] =
_liveList[134] = _liveList[145] = _liveList[146] = _liveList[TEXT_sect] = 1;
for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++) {
if (_liveList[cnt])
_cptData[cnt] = (uint8 *)_resMan->cptResOpen(_objectList[cnt]) + sizeof(Header);
else
_cptData[cnt] = NULL;
}
}
ObjectMan::~ObjectMan() {
for (uint16 cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
if (_liveList[cnt])
_resMan->resClose(_objectList[cnt]);
}
bool ObjectMan::sectionAlive(uint16 section) {
return (_liveList[section] > 0);
}
void ObjectMan::megaEntering(uint16 section) {
_liveList[section]++;
if (_liveList[section] == 1)
_cptData[section] = ((uint8 *)_resMan->cptResOpen(_objectList[section])) + sizeof(Header);
}
void ObjectMan::megaLeaving(uint16 section, int id) {
if (_liveList[section] == 0)
error("mega %d is leaving empty section %d", id, section);
_liveList[section]--;
if ((_liveList[section] == 0) && (id != PLAYER)) {
_resMan->resClose(_objectList[section]);
_cptData[section] = NULL;
}
/* if the player is leaving the section then we have to close the resources after
mainloop ends, because the screen will still need the resources*/
}
uint8 ObjectMan::fnCheckForTextLine(uint32 textId) {
uint8 retVal = 0;
if (!_textList[textId / ITM_PER_SEC][0])
return 0; // section does not exist
uint8 lang = SwordEngine::_systemVars.language;
uint32 *textData = (uint32 *)((uint8 *)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]) + sizeof(Header));
if ((textId & ITM_ID) < _resMan->readUint32(textData)) {
textData++;
if (textData[textId & ITM_ID])
retVal = 1;
}
_resMan->resClose(_textList[textId / ITM_PER_SEC][lang]);
return retVal;
}
char *ObjectMan::lockText(uint32 textId) {
uint8 lang = SwordEngine::_systemVars.language;
char *text = lockText(textId, lang);
if (text == 0) {
if (lang != BS1_ENGLISH) {
text = lockText(textId, BS1_ENGLISH);
if (text != 0)
warning("Missing translation for textId %u (\"%s\")", textId, text);
unlockText(textId, BS1_ENGLISH);
}
return _missingSubTitleStr;
}
return text;
}
char *ObjectMan::lockText(uint32 textId, uint8 lang) {
char *addr = (char *)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]);
if (addr == 0)
return NULL;
addr += sizeof(Header);
if ((textId & ITM_ID) >= _resMan->readUint32(addr)) {
// Workaround for missing sentences in some languages in the demo.
switch(textId) {
case 8455194:
return const_cast<char *>(_translationId8455194[lang]);
case 8455195:
return const_cast<char *>(_translationId8455195[lang]);
case 8455196:
return const_cast<char *>(_translationId8455196[lang]);
case 8455197:
return const_cast<char *>(_translationId8455197[lang]);
case 8455198:
return const_cast<char *>(_translationId8455198[lang]);
case 8455199:
return const_cast<char *>(_translationId8455199[lang]);
case 8455200:
return const_cast<char *>(_translationId8455200[lang]);
case 8455201:
return const_cast<char *>(_translationId8455201[lang]);
case 8455202:
return const_cast<char *>(_translationId8455202[lang]);
case 8455203:
return const_cast<char *>(_translationId8455203[lang]);
case 8455204:
return const_cast<char *>(_translationId8455204[lang]);
case 8455205:
return const_cast<char *>(_translationId8455205[lang]);
case 6488080:
return const_cast<char *>(_translationId6488080[lang]);
case 6488081:
return const_cast<char *>(_translationId6488081[lang]);
case 6488082:
return const_cast<char *>(_translationId6488082[lang]);
case 6488083:
return const_cast<char *>(_translationId6488083[lang]);
}
warning("ObjectMan::lockText(%d): only %d texts in file", textId & ITM_ID, _resMan->readUint32(addr));
return NULL;
}
uint32 offset = _resMan->readUint32(addr + ((textId & ITM_ID) + 1) * 4);
if (offset == 0) {
// Workaround bug for missing sentence in some languages in Syria (see bug #1977094).
// We use the hardcoded text in this case.
if (textId == 2950145)
return const_cast<char *>(_translationId2950145[lang]);
warning("ObjectMan::lockText(%d): text number has no text lines", textId);
return NULL;
}
return addr + offset;
}
void ObjectMan::unlockText(uint32 textId) {
unlockText(textId, SwordEngine::_systemVars.language);
}
void ObjectMan::unlockText(uint32 textId, uint8 lang) {
_resMan->resClose(_textList[textId / ITM_PER_SEC][lang]);
}
uint32 ObjectMan::lastTextNumber(int section) {
uint8 *data = (uint8 *)_resMan->openFetchRes(_textList[section][SwordEngine::_systemVars.language]) + sizeof(Header);
uint32 result = _resMan->readUint32(data) - 1;
_resMan->resClose(_textList[section][SwordEngine::_systemVars.language]);
return result;
}
Object *ObjectMan::fetchObject(uint32 id) {
uint8 *addr = _cptData[id / ITM_PER_SEC];
if (!addr)
error("fetchObject: section %d is not open", id / ITM_PER_SEC);
id &= ITM_ID;
// DON'T do endian conversion here. it's already done.
return (Object *)(addr + * (uint32 *)(addr + (id + 1) * 4));
}
uint32 ObjectMan::fetchNoObjects(int section) {
if (_cptData[section] == NULL)
error("fetchNoObjects: section %d is not open", section);
return *(uint32 *)_cptData[section];
}
void ObjectMan::closeSection(uint32 screen) {
if (_liveList[screen] == 0) // close the section that PLAYER has just left, if it's empty now
_resMan->resClose(_objectList[screen]);
}
void ObjectMan::loadLiveList(uint16 *src) {
for (uint16 cnt = 0; cnt < TOTAL_SECTIONS; cnt++) {
if (_liveList[cnt]) {
_resMan->resClose(_objectList[cnt]);
_cptData[cnt] = NULL;
}
_liveList[cnt] = src[cnt];
if (_liveList[cnt])
_cptData[cnt] = ((uint8 *)_resMan->cptResOpen(_objectList[cnt])) + sizeof(Header);
}
}
void ObjectMan::saveLiveList(uint16 *dest) {
memcpy(dest, _liveList, TOTAL_SECTIONS * sizeof(uint16));
}
// String displayed when a subtitle sentence is missing in the cluster file.
// It happens with at least one sentence in Syria in some languages (see bug
// #1977094).
// Note: an empty string or a null pointer causes a crash.
char ObjectMan::_missingSubTitleStr[] = " ";
// Missing translation for textId 2950145 (see bug #1977094).
// Currently text is missing for Portuguese languages. (It's possible that it
// is not needed. The English version of the game does not include Portuguese
// so I cannot check.)
const char *const ObjectMan::_translationId2950145[7] = {
"Oh?", // English (not needed)
"Quoi?", // French
"Oh?", // German
"Eh?", // Italian
"\277Eh?", // Spanish
"Ano?", // Czech
NULL // Portuguese
};
// The translations for the next texts are missing in the demo but are present
// in the full game. The translations were therefore extracted from the full game.
// Missing translation for textId 8455194 (in the demo).
const char *const ObjectMan::_translationId8455194[7] = {
NULL, // "Who was the guy you were supposed to meet?", // English (not needed)
"Qui \351tait l'homme que vous deviez rencontrer?", // French
"Wer war der Typ, den Du treffen wolltest?", // German
"Chi dovevi incontrare?", // Italian
"\277Qui\351n era el hombre con el que ten\355as que encontrarte?", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455195 (in the demo).
const char *const ObjectMan::_translationId8455195[7] = {
NULL, // "His name was Plantard. I didn't know him, but he called me last night.", // English (not needed)
"Son nom \351tait Plantard. Je ne le connaissais pas, mais il m'avait t\351l\351phon\351 la veille.", // French
"Sein Name war Plantard. Ich kannte ihn nicht, aber er hat mich letzte Nacht angerufen.", // German
"Si chiamava Plantard. Mi ha chiamato ieri sera, ma non lo conoscevo.", // Italian
"Su nombre era Plantard. Yo no lo conoc\355a pero \351l me llam\363 ayer por la noche.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455196 (in the demo).
const char *const ObjectMan::_translationId8455196[7] = {
NULL, // "He said he had a story which would interest me.", // English (not needed)
"Il a dit qu'il avait une histoire qui devrait m'int\351resser.", // French
"Er sagte, er h\344tte eine Story, die mich interessieren w\374rde.", // German
"Mi disse che aveva una storia che mi poteva interessare.", // Italian
"Dijo que ten\355a una historia que me interesar\355a.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455197 (in the demo).
const char *const ObjectMan::_translationId8455197[7] = {
NULL, // "He asked me to meet him at the caf\351.", // English (not needed)
"Il m'a demand\351 de le rencontrer au caf\351.", // French
"Er fragte mich, ob wir uns im Caf\351 treffen k\366nnten.", // German
"Mi chiese di incontrarci al bar.", // Italian
"Me pidi\363 que nos encontr\341ramos en el caf\351.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455198 (in the demo).
const char *const ObjectMan::_translationId8455198[7] = {
NULL, // "I guess I'll never know what he wanted to tell me...", // English (not needed)
"Je suppose que je ne saurai jamais ce qu'il voulait me dire...", // French
"Ich werde wohl nie erfahren, was er mir sagen wollte...", // German
"Penso che non sapr\362 mai che cosa voleva dirmi...", // Italian
"Supongo que nunca sabr\351 qu\351 me quer\355a contar...", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455199 (in the demo).
const char *const ObjectMan::_translationId8455199[7] = {
NULL, // "Not unless you have Rosso's gift for psychic interrogation.", // English (not needed)
"Non, \340 moins d'avoir les dons de Rosso pour les interrogatoires psychiques.", // French
"Es sei denn, Du h\344ttest Rosso's Gabe der parapsychologischen Befragung.", // German
"A meno che tu non riesca a fare interrogatori telepatici come Rosso.", // Italian
"A no ser que tengas el don de Rosso para la interrogaci\363n ps\355quica.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455200 (in the demo).
const char *const ObjectMan::_translationId8455200[7] = {
NULL, // "How did Plantard get your name?", // English (not needed)
"Comment Plantard a-t-il obtenu votre nom?", // French
"Woher hat Plantard Deinen Namen?", // German
"Come ha fatto Plantard a sapere il tuo nome?", // Italian
"\277C\363mo consigui\363 Plantard tu nombre?", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455201 (in the demo).
const char *const ObjectMan::_translationId8455201[7] = {
NULL, // "Through the newspaper - La Libert\351.", // English (not needed)
"Par mon journal... La Libert\351.", // French
"\334ber die Zeitung - La Libert\351.", // German
"Tramite il giornale La Libert\351.", // Italian
"Por el peri\363dico - La Libert\351.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455202 (in the demo).
const char *const ObjectMan::_translationId8455202[7] = {
NULL, // "I'd written an article linking two unsolved murders, one in Italy, the other in Japan.", // English (not needed)
"J'ai \351crit un article o\371 je faisais le lien entre deux meurtres inexpliqu\351s, en Italie et au japon.", // French
"Ich habe einen Artikel geschrieben, in dem ich zwei ungel\366ste Morde miteinander in Verbindung bringe, einen in Italien, einen anderen in Japan.", // German
"Ho scritto un articolo che metteva in collegamento due omicidi insoluti in Italia e Giappone.", // Italian
"Yo hab\355a escrito un art\355culo conectando dos asesinatos sin resolver, uno en Italia, el otro en Jap\363n.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455203 (in the demo).
const char *const ObjectMan::_translationId8455203[7] = {
NULL, // "The cases were remarkably similar...", // English (not needed)
"Les affaires \351taient quasiment identiques...", // French
"Die F\344lle sind sich bemerkenswert \344hnlich...", // German
"I casi erano sorprendentemente uguali...", // Italian
"Los casos eran incre\355blemente parecidos...", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455204 (in the demo).
const char *const ObjectMan::_translationId8455204[7] = {
NULL, // "...a wealthy victim, no apparent motive, and a costumed killer.", // English (not needed)
"...une victime riche, pas de motif apparent, et un tueur d\351guis\351.", // French
"...ein wohlhabendes Opfer, kein offensichtliches Motiv, und ein verkleideter Killer.", // German
"...una vittima ricca, nessun motivo apparente e un assassino in costume.", // Italian
"...una v\355ctima rica, sin motivo aparente, y un asesino disfrazado.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 8455205 (in the demo).
const char *const ObjectMan::_translationId8455205[7] = {
NULL, // "Plantard said he could supply me with more information.", // English (not needed)
"Plantard m'a dit qu'il pourrait me fournir des renseignements.", // French
"Plantard sagte, er k\366nne mir weitere Informationen beschaffen.", // German
"Plantard mi disse che mi avrebbe fornito ulteriori informazioni.", // Italian
"Plantard dijo que \351l me pod\355a proporcionar m\341s informaci\363n.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 6488080 (in the demo).
const char *const ObjectMan::_translationId6488080[7] = {
NULL, // "I wasn't going to head off all over Paris until I'd investigated some more.", // English (not needed)
"Je ferais mieux d'enqu\351ter un peu par ici avant d'aller me promener ailleurs.", // French
"Ich durchquere nicht ganz Paris, bevor ich etwas mehr herausgefunden habe.", // German
"Non mi sarei incamminato per tutta Parigi prima di ulteriori indagini.", // Italian
"No iba a ponerme a recorrer Par\355s sin haber investigado un poco m\341s.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// The next three sentences are specific to the demo and only the english text is present.
// The translations were provided by:
// French: Thierry Crozat
// German: Simon Sawatzki
// Italian: Matteo Angelino
// Spanish: Tomás Maidagan
// Missing translation for textId 6488081 (in the demo).
const char *const ObjectMan::_translationId6488081[7] = {
NULL, // "I wasn't sure what I was going to do when I caught up with that clown...", // English (not needed)
"Je ne savais pas ce que je ferais quand je rattraperais le clown...", // French
"Ich wu\337te nicht, worauf ich mich einlie\337, als ich dem Clown nachjagte...", // German
"Non sapevo cosa avrei fatto una volta raggiunto quel clown...", // Italian
"No sab\355a muy bien qu\351 es lo que har\355a cuando alcanzara al payaso...", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 6488082 (in the demo).
const char *const ObjectMan::_translationId6488082[7] = {
NULL, // "...but before I knew it, I was drawn into a desperate race between two ruthless enemies.", // English (not needed)
"...mais avant de m'en rendre compte je me retrouvais happ\351 dans une course effr\351n\351e entre deux ennemis impitoyables.", // French
"... doch bevor ich mich versah, war ich inmitten eines Wettlaufs von zwei r\374cksichtslosen Feinden.", // German
"... ma prima che me ne rendessi conto, fui trascinato in una corsa disperata con due spietati nemici.", // Italian
"...pero sin darme cuenta, acab\351 en medio de una desesperada carrera entre dos despiadados enemigos.", // Spanish
NULL, // Czech
NULL // Portuguese
};
// Missing translation for textId 6488083 (in the demo).
const char *const ObjectMan::_translationId6488083[7] = {
NULL, // "The goal: the mysterious power of the Broken Sword.", // English (not needed)
"Le but: les pouvoirs myst\351rieux de l'\351p\351e bris\351e.", // French
"Das Ziel: die geheimnisvolle Macht des zerbrochenen Schwertes.", // German
"Obiettivo: il misterioso potere della Spada spezzata.", // Italian
"El objetivo: el misterioso poder de la Espada Rota.", // Spanish
NULL, // Czech
NULL // Portuguese
};
} // End of namespace Sword1
|