00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <sstream>
00021 #include <fstream>
00022 #include <stdexcept>
00023
00024 #include "player.h"
00025
00026 #include "renderer.h"
00027 #include "channel.h"
00028 #include "chunck_type.h"
00029 #include "rect.h"
00030 #include "blitter.h"
00031 #include "endian.h"
00032
00033 #ifdef DEBUG
00034 #include <iomanip>
00035 #include <iostream>
00036 #endif
00037
00038 const int WAIT = 100;
00039
00040 using namespace std;
00041
00049 class string_resource {
00050 private:
00051 map<int, string> _strings;
00052 public:
00060 bool init(char * buffer, int length) throw(exception) {
00061 string str(buffer, length);
00062 string::size_type i = str.find('#');
00063 while(i != string::npos) {
00064 string::size_type j = str.find('\n', i) + 1;
00065 assert(j != string::npos);
00066 string::size_type m = j - 2;
00067 while((str[m] == '\r') || (str[m] == '\n') || (str[m] == ' ') || (str[m] == '\t')) m--;
00068
00069 string::size_type k = str.rfind(' ', m);
00070 string::size_type l = str.rfind('\t', m);
00071 if(l != string::npos && k < l) k = l;
00072 assert(k != string::npos);
00073 m++; k++;
00074
00075 istringstream iss(string(str, k, m-k));
00076 int id;
00077 iss >> id;
00078 k = str.find('\n', j) - 1;
00079 if(str[j] == '/') j += 2;
00080 string value = string(str, j, k-j);
00081 #ifdef DEBUG
00082 cout << "Inserting " << id << " == \"" << value << "\"" << endl;
00083 #endif
00084 _strings.insert(make_pair(id, value));
00085 i = str.find('#', k);
00086 }
00087 return true;
00088 }
00095 const string & get(int id) const throw(exception) {
00096 map<int, string>::const_iterator i = _strings.find(id);
00097 if(i == _strings.end())
00098 throw(runtime_error("invalid string id"));
00099 return i->second;
00100 }
00101 };
00102
00103 void player::show(const std::string & p) {
00104 if(p == "subtitles")
00105 _subtitles = true;
00106 else if(p == "bgmusic")
00107 _bgmusic = true;
00108 else if(p == "voices")
00109 _voices = true;
00110 else {
00111 istringstream iss(p);
00112 int id = -1;
00113 iss >> id;
00114 if(id < 0 || id > 36) throw runtime_error("invalid parameter to show");
00115 _skips.insert(make_pair(id, true));
00116 }
00117 }
00118
00119 void player::hide(const std::string & p) {
00120 if(p == "subtitles")
00121 _subtitles = false;
00122 else if(p == "bgmusic")
00123 _bgmusic = false;
00124 else if(p == "voices")
00125 _voices = false;
00126 else {
00127 istringstream iss(p);
00128 int id = -1;
00129 iss >> id;
00130 if(id < 0 || id > 36) throw runtime_error("invalid parameter to show");
00131 _skips.insert(make_pair(id, false));
00132 }
00133 }
00134
00135
00136 player::player(renderer * renderer, bool wait, bool sound) throw() :
00137 _version(-1),
00138 _secondary_version(0),
00139 _sound_frequency(0),
00140 _nbframes(0),
00141 _renderer(renderer),
00142 _strings(0),
00143 _frame_size(-1, -1),
00144 _frame(0),
00145 _output_sound(sound),
00146 _wait(wait),
00147 _already_init(false),
00148 _codec37_called(false),
00149 _skipnext(false),
00150 _subtitles(true),
00151 _bgmusic(true),
00152 _voices(true)
00153 {
00154 _fr[0] = _fr[1] = _fr[2] = _fr[3] = 0;
00155 assert(_renderer != 0);
00156 }
00157
00158 player::~player() throw() {
00159 clean();
00160 }
00161
00162 void player::update_palette(void) {
00163 _renderer->set_palette(_pal);
00164 }
00165
00166 void player::clean() throw() {
00167 if(_strings) delete _strings;
00168 if(_fr[0]) delete _fr[0];
00169 if(_fr[1]) delete _fr[1];
00170 if(_fr[2]) delete _fr[2];
00171 if(_fr[3]) delete _fr[3];
00172 }
00173
00174 void player::checkBlock(const chunck & b, chunck::type type_expected, unsigned int min_size) {
00175 #ifdef DEBUG
00176
00177 #endif
00178 if(type_expected != b.get_type()) {
00179 ostringstream oss;
00180 oss << "chunck type is different from expected : " << b.get_type() << " != " << type_expected;
00181 throw runtime_error(oss.str());
00182 }
00183 if(min_size > b.get_size()) {
00184 ostringstream oss;
00185 oss << "chunck size is inferior than minimum required size : " << b.get_size() << " < " << min_size;
00186 throw runtime_error(oss.str());
00187 }
00188 }
00189
00190 void player::handleSoundBuffer(int track_id, int index, int max_frames, int flags, int vol, int bal, chunck & b, int size) throw(exception) {
00191 if(!_voices && (flags & 128) == 128) return;
00192 if(!_bgmusic && (flags & 64) == 64) return;
00193 channel * c = _mixer.find_channel(track_id);
00194 if(c == 0) {
00195 c = new saud_channel(track_id, _mixer.get_frequency());
00196 _mixer.add_channel(track_id, c);
00197 }
00198 if(index == 0)
00199 c->set_parameters(max_frames, flags, vol, bal);
00200 else
00201 c->check_parameters(index, max_frames, flags, vol, bal);
00202 c->append_data(b, size);
00203 }
00204
00205 void player::handleSoundFrame(chunck & b) throw(exception) {
00206 #ifdef DEBUG
00207 cout << "handleSoundFrame()" << endl;
00208 #endif
00209 checkBlock(b, TYPE_PSAD);
00210 if(!_output_sound) return;
00211 int track_id = b.get_word();
00212 int index = b.get_word();
00213 int max_frames = b.get_word();
00214 int flags = b.get_word();
00215 int vol = b.get_byte();
00216 int bal = b.get_char();
00217 #ifdef DEBUG
00218
00219 if(index == 0) {
00220 cout << "track_id == " << track_id << ", max_frames == " << max_frames << ", " << flags << ", " << vol << ", " << bal << endl;
00221 }
00222 #endif
00223 int size = b.get_size() - 10;
00224 handleSoundBuffer(track_id, index, max_frames, flags, vol, bal, b, size);
00225 }
00226
00227 void player::handleSkip(chunck & b) throw(exception) {
00228 checkBlock(b, TYPE_SKIP, 4);
00229 int code = b.get_dword();
00230 #ifdef DEBUG
00231 cout << "handleSkip(" << code << ")" << endl;
00232 #endif
00233 map<int, bool>::iterator i = _skips.find(code);
00234 if(i != _skips.end())
00235 _skipnext = i->second;
00236 else
00237 _skipnext =true;
00238 }
00239
00240 void player::handleStore(chunck & b) throw(exception) {
00241 #ifdef DEBUG
00242 cerr << "handleStore()" << endl;
00243
00244
00245
00246
00247
00248
00249 #endif
00250 checkBlock(b, TYPE_STOR, 4);
00251
00252 }
00253
00254 void player::handleFetch(chunck & b) throw(exception) {
00255 #ifdef DEBUG
00256 cerr << "handleFetch()" << endl;
00257
00258
00259
00260
00261
00262
00263 #endif
00264 checkBlock(b, TYPE_FTCH, 6);
00265 }
00266
00267 void player::handleImuseBuffer(int track_id, int index, int nbframes, int size, int unk1, int unk2, chunck & b, int bsize) throw(exception) {
00268 channel * c = _mixer.find_channel(track_id);
00269 if(c == 0) {
00270 c = new imuse_channel(track_id, _mixer.get_frequency());
00271 _mixer.add_channel(track_id, c);
00272 }
00273 if(index == 0)
00274 c->set_parameters(nbframes, size, unk1, unk2);
00275 else
00276 c->check_parameters(index, nbframes, size, unk1, unk2);
00277 c->append_data(b, bsize);
00278 }
00279
00280 void player::handleImuseAction8(chunck & b, int flags, int unknown, int track_id) throw(exception) {
00281 assert(flags == 46 && unknown == 0);
00282 int unknown2 = b.get_word();
00283 track_id |= unknown2 << 16;
00284 int index = b.get_word();
00285 int nbframes = b.get_word();
00286 int size = b.get_dword();
00287 #ifdef DEBUG
00288 cout << "handleImuseAction8() : " << unknown2 << ", " << index << "/" << nbframes << " == " << size << endl;
00289 #endif
00290 int bsize = b.get_size() - 18;
00291 handleImuseBuffer(track_id, index, nbframes, size, unknown, unknown2, b, bsize);
00292 }
00293
00294 void player::handleImuseAction(chunck & b) throw(exception) {
00295 checkBlock(b, TYPE_IACT, 8);
00296 if(!_output_sound) return;
00297 int code = b.get_word();
00298 int flags = b.get_word();
00299 int unknown = b.get_short();
00300 int track_id = b.get_word();
00301 #ifdef DEBUG
00302 cout << "handleImuseAction(" << code << "," << flags << "," << unknown << "," << track_id << ")" << endl;
00303 #endif
00304 switch(code) {
00305 case 8:
00306 handleImuseAction8(b, flags, unknown, track_id);
00307 break;
00308 #ifdef DEBUG
00309 default:
00310
00311
00312 {
00313 cerr << setw(5) << track_id << " " << code << " " << setw(8) << flags << " " << setw(4) << unknown << " : ";
00314 int i = 1;
00315 while(!b.eof()) {
00316 int value = b.get_byte();
00317 cerr << setw(3) << value << " ";
00318 if(i++ == 80) { i = 0; cerr << endl; }
00319 }
00320 if(i) cerr << endl;
00321 }
00322 #endif
00323 }
00324 }
00325
00326
00327
00328 void player::handleTextResource(chunck & b) throw(exception) {
00329 #ifdef DEBUG
00330 cout << "handleTextResource()" << endl;
00331 #endif
00332 checkBlock(b, TYPE_TRES, 18);
00333 assert(_strings);
00334 int pos_x = b.get_short();
00335 int pos_y = b.get_short();
00336 int flags = b.get_short();
00337 int left = b.get_short();
00338 int top = b.get_short();
00339 int width = b.get_short();
00340 int height = b.get_short();
00341 int unk2 = b.get_word();
00342 int string_id = b.get_word();
00343 string str = _strings->get(string_id);
00344 #ifdef DEBUG
00345
00346 #else
00347 height = height;
00348 unk2 = unk2;
00349 #endif
00350 if((!_subtitles) && ((flags & 8) == 8)) return;
00351 font_renderer * fr = _fr[0];
00352 int color = 15;
00353 while(str[0] == '^') {
00354 switch(str[1]) {
00355 case 'f':
00356 {
00357 istringstream iss(string(str, 2, 2));
00358 int id = 0;
00359 iss >> id;
00360 str = string(str, 4);
00361 fr = _fr[id];
00362 } break;
00363 case 'c':
00364 {
00365 istringstream iss(string(str, 2, 3));
00366 iss >> color;
00367 str = string(str, 5);
00368 } break;
00369 default:
00370 throw runtime_error("invalid escape code in text string");
00371 }
00372 }
00373 fr->set_color(color);
00374
00375 if(!_cur_buffer) { _cur_buffer = _renderer->lock_frame(_frame); }
00376 if(flags == 0 || flags == 4)
00377 fr->draw_string_absolute(str, _cur_buffer, _frame_size, pos_x, pos_y);
00378 else
00379 fr->draw_string_centered(str, _cur_buffer, _frame_size, max(pos_y, top), left, width, pos_x);
00380 }
00381
00382 void player::readPalette(palette & out, chunck & in) throw(exception) {
00383 unsigned char buffer[768];
00384 in.read(buffer, 768);
00385 out = palette(buffer);
00386 }
00387
00388 void player::handleDeltaPalette(chunck & b) throw(exception) {
00389 #ifdef DEBUG_DELTA_PALETTE
00390 cout << "handleDeltaPalette()" << endl;
00391 #endif
00392 checkBlock(b, TYPE_XPAL);
00393 if(b.get_size() == 768*3+4) {
00394 int unk1, num;
00395 unk1 = b.get_word();
00396 num = b.get_word();
00397 for(int i = 0; i < 768; i++)
00398 {
00399 _delta_pal[i] = b.get_word();
00400 }
00401 readPalette(_pal, b);
00402 update_palette();
00403 #ifdef DEBUG_DELTA_PALETTE
00404 cout << "DELTA PALETTE : unk1 == " << unk1 << ", num == " << num << endl;
00405 for(int i = 0; i < 256; i++)
00406 {
00407 cout << "deltapal[" << i << "] == " << _delta_pal[3*i] << ", " << _delta_pal[3*i+1] << ", " << _delta_pal[3*i+2] << endl;
00408 }
00409 cout << "palette == " << _pal << endl;
00410 #endif
00411 } else if(b.get_size() == 6) {
00412 int unk1, num, unk2;
00413 unk1 = b.get_word();
00414 num = b.get_word();
00415 unk2 = b.get_word();
00416 #ifdef DEBUG_DELTA_PALETTE
00417 cout << "DELTA PALETTE : unk1 == " << unk1 << ", num == " << num << ", unk2 == " << unk2 << endl;
00418 #endif
00419 for(int i = 0; i < 256; i++)
00420 {
00421 _pal[i].delta(_delta_pal+3*i);
00422 }
00423 update_palette();
00424 } else {
00425 throw runtime_error("wrong size for DeltaPalette");
00426 }
00427 }
00428
00429 void player::handleNewPalette(chunck & b) throw(exception) {
00430 #ifdef DEBUG
00431 cout << "handleNewPalette()" << endl;
00432 #endif
00433 checkBlock(b, TYPE_NPAL, 768);
00434 readPalette(_pal, b);
00435 update_palette();
00436 }
00437
00438 void player::decodeCodec(chunck & b, const rect & r, decoder & codec) throw(exception) {
00439 assert(_cur_buffer);
00440 try {
00441 blitter blit(_cur_buffer, _frame_size, r);
00442 codec.decode(blit, b);
00443 } catch(const exception & e) {
00444 #ifdef DEBUG
00445 cerr << "Exception occured during decodeCodec : " << e.what() << endl;
00446 #endif
00447 }
00448 }
00449
00450 void player::init_size(const rect & r, bool always, bool transparent) throw(exception)
00451 {
00452 if(_codec37_called) _already_init = true;
00453
00454 if(!_already_init || _frame_size.get_x() < r.right() || _frame_size.get_y() < r.bottom() || always) {
00455 if(_cur_buffer) { _renderer->unlock_frame(); _cur_buffer = 0; }
00456 _frame_size = r.bottomright();
00457 _renderer->init_frame(_frame_size);
00458 }
00459 if(_cur_buffer) { _renderer->unlock_frame(); _cur_buffer = 0; }
00460 _cur_buffer = _renderer->lock_frame(_frame);
00461 if(!_already_init && transparent) {
00462 #ifdef DEBUG
00463 cout << "clearing buffer" << endl;
00464 #endif
00465 memset(_cur_buffer, 0, _frame_size.get_x()*_frame_size.get_y());
00466 }
00467 _codec1.init_size(_frame_size, r);
00468 _codec37.init_size(_frame_size, r);
00469 _codec44.init_size(_frame_size, r);
00470 _already_init = true;
00471 }
00472
00473 void player::handleFrameObject(chunck & b) throw(exception) {
00474 #ifdef DEBUG
00475 cout << "handleFrameObject()" << endl;
00476 #endif
00477 checkBlock(b, TYPE_FOBJ, 14);
00478 if(_skipnext) {
00479 _skipnext = false;
00480 return;
00481 }
00482 int codec = b.get_word();
00483 unsigned short left = b.get_word();
00484 unsigned short top = b.get_word();
00485 unsigned short width = b.get_word();
00486 unsigned short height = b.get_word();
00487 rect r(left, top, left+width, top+height);
00488 unsigned short data[2];
00489 data[1] = b.get_word();
00490 data[0] = b.get_word();
00491 #ifdef DEBUG
00492 cout << "Frame pos : " << left << ", " << top << endl;
00493 cout << "Frame size : " << width << "x" << height << endl;
00494 cout << "Codec : " << codec << endl;
00495 for(int i = 0; i < 2; i++)
00496 if(data[i] != 0) {
00497 cout << "FRAMEOBJECT:data[" << i << "] == " << data[i] << endl;
00498 cerr << "FRAMEOBJECT:data[" << i << "] == " << data[i] << endl;
00499 }
00500 #endif
00501 switch (codec) {
00502 case 3:
00503 case 1:
00504 init_size(r, false, true);
00505 decodeCodec(b, r, _codec1);
00506 break;
00507 case 37:
00508 assert(left == 0 && top == 0);
00509 init_size(r, true, false);
00510 decodeCodec(b, r, _codec37);
00511 _codec37_called = true;
00512 break;
00513 case 21:
00514 case 44:
00515 init_size(r, true, true);
00516 decodeCodec(b, r, _codec44);
00517 break;
00518 default:
00519 ostringstream oss;
00520 oss << "Invalid codec for frame object : " << static_cast<int>(codec);
00521 throw runtime_error(oss.str());
00522 }
00523
00524 }
00525
00526
00527 void player::handleFrame(chunck & b) throw(exception) {
00528 #ifdef DEBUG
00529 cout << "handleFrame(" << _frame << ")" << endl;
00530 #endif
00531 checkBlock(b, TYPE_FRME);
00532 _already_init = false;
00533 _skipnext = false;
00534
00535 while(!b.eof()) {
00536 chunck * sub = b.sub_block();
00537 if(sub->get_size() & 1) b.seek(1);
00538 switch(sub->get_type()) {
00539 case TYPE_NPAL:
00540 handleNewPalette(*sub);
00541 break;
00542 case TYPE_FOBJ:
00543 handleFrameObject(*sub);
00544 break;
00545 case TYPE_PSAD:
00546 handleSoundFrame(*sub);
00547 break;
00548 case TYPE_TRES:
00549 handleTextResource(*sub);
00550 break;
00551 case TYPE_XPAL:
00552 handleDeltaPalette(*sub);
00553 break;
00554 case TYPE_IACT:
00555 handleImuseAction(*sub);
00556 break;
00557 case TYPE_STOR:
00558 handleStore(*sub);
00559 break;
00560 case TYPE_FTCH:
00561 handleFetch(*sub);
00562 break;
00563 case TYPE_SKIP:
00564 handleSkip(*sub);
00565 break;
00566 default:
00567 ostringstream oss;
00568 oss << "Unknown frame subchunck found : " << chunck::chunck_string(sub->get_type()) << ", " << sub->get_size();
00569 throw runtime_error(oss.str());
00570 }
00571 delete sub;
00572 }
00573 if(_cur_buffer) { _renderer->unlock_frame(); _cur_buffer = 0; }
00574 if(_output_sound) _mixer.handle_frame();
00575 #ifdef DEBUG
00576
00577 cout << "=========================================================" << endl;
00578 #endif
00579 _renderer->flip_frame();
00580 if(_wait) _renderer->wait(WAIT);
00581 _frame++;
00582 }
00583
00584 void player::handleAnimHeader(chunck & b) throw(exception) {
00585 #ifdef DEBUG
00586 cout << "handleAnimHeader()" << endl;
00587 #endif
00588 checkBlock(b, TYPE_AHDR, 774);
00589 _version = b.get_word();
00590 _nbframes = b.get_word();
00591 int unknown = b.get_word();
00592 #ifdef DEBUG
00593 cout << "HEADER : version == " << _version << ", nbframes == " << _nbframes << ", unknown == " << unknown << endl;
00594 #else
00595 unknown = unknown;
00596 #endif
00597 _renderer->start_decode(_fname, _version, _nbframes);
00598 readPalette(_pal, b);
00599 update_palette();
00600 if(_version == 1) {
00601 _sound_frequency = 22050;
00602 }
00603 if(_version == 2) {
00604 _secondary_version = b.get_dword();
00605 int unknown2 = b.get_dword();
00606 _sound_frequency = b.get_dword();
00607 #ifdef DEBUG
00608 cout << "HEADER : secondary version == " << _secondary_version << ", unknown2 == " << unknown2 << ", sound frequency == " << _sound_frequency << endl;
00609 int i = 0, c;
00610 while(!b.eof()) {
00611 c = b.get_byte();
00612
00613 if(c) cerr << "HEADER : remaining bytes : " << i << " == " << c << endl;
00614 i++;
00615 }
00616 #else
00617 unknown2 = unknown2;
00618 #endif
00619 if(_secondary_version != 10 && _secondary_version != 0 && _secondary_version != 12 && _secondary_version != 15 && _secondary_version != 14)
00620 throw runtime_error("Wrong secondary version number for SMUSH animation");
00621 if(_sound_frequency != 0 && _sound_frequency != 11025 && _sound_frequency != 22050)
00622 throw runtime_error("Wrong _sound_frequency number for SMUSH animation");
00623 }else if(_version > 2) {
00624 throw runtime_error("Wrong primary version number for SMUSH animation");
00625 }
00626 if(_output_sound && _sound_frequency) {
00627 if(_sound_frequency != 22050) _sound_frequency = 22050;
00628 sound_renderer * sr = _renderer->get_sound_renderer();
00629 if(sr) {
00630 _mixer.init(sr, _sound_frequency, 1000 / WAIT);
00631 } else {
00632 _output_sound = false;
00633 }
00634 }
00635 }
00636
00637 string_resource * get_strings(const string & file, bool is_encoded) {
00638 ifstream is;
00639 is.exceptions(ifstream::badbit);
00640 is.open (file.c_str(), ios::binary);
00641 if(is.fail()) return 0;
00642 is.seekg (0, ios::end);
00643 ifstream::pos_type length = is.tellg();
00644 is.seekg (0, ios::beg);
00645 char * filebuffer = new char [length];
00646 assert(filebuffer);
00647 is.read (filebuffer,length);
00648 is.close();
00649 if(is_encoded) {
00650 chunck::type type = from_big_endian(*reinterpret_cast<unsigned int *>(filebuffer));
00651 if(type != TYPE_ETRS) throw runtime_error("invalid type for file");
00652 char * old = filebuffer;
00653 filebuffer = new char[static_cast<int>(length) - 8];
00654 for(int i = 8; i < length; i++)
00655 filebuffer[i-8] = old[i] ^ 0xCC;
00656 delete []old;
00657 length -= 8;
00658 }
00659 string_resource * sr = new string_resource;
00660 assert(sr);
00661 try {
00662 sr->init(filebuffer, length);
00663 } catch(exception & e) {
00664 delete sr;
00665 sr = 0;
00666 }
00667 delete []filebuffer;
00668 return sr;
00669 }
00670
00671 bool player::read_string(const string & file) throw(exception) {
00672 #ifdef DEBUG
00673 cout << "player::read_string(" << file << ")" << endl;
00674 #endif
00675 string::size_type i = file.rfind('.');
00676 if(i == string::npos) throw(runtime_error("invalid filename"));
00677 string fname = string(file, 0, i) + ".TRS";
00678 if((_strings = get_strings(fname, false)) != 0)
00679 return true;
00680 i = file.rfind('\\');
00681 if(i == string::npos) i = file.rfind('/');
00682 if(i == string::npos) throw(runtime_error("invalid filename"));
00683 fname = string(file, 0, i+1) + "MINEROAD.TRS";
00684 if((_strings = get_strings(fname, false)) != 0)
00685 return true;
00686 fname = string(file, 0, i+1) + "DIGTXT.TRS";
00687 if((_strings = get_strings(fname, true)) != 0)
00688 return false;
00689 return true;
00690 }
00691
00692 namespace {
00693 font_renderer * load_font(const string & file, bool original = false) {
00694 #ifdef DEBUG
00695 cout << "loading font from \"" << file << "\"" << endl;
00696 #endif
00697 font_renderer * fr = new font_renderer(original);
00698 player p(fr, false, false);
00699 p.play(file.c_str());
00700 return fr;
00701 }
00702 }
00703
00704 bool player::play(const string & file) throw(exception) {
00705 string::size_type i = file.rfind('\\');
00706 if(i == string::npos)
00707 {
00708 i = file.rfind('/');
00709 } else {
00710 string::size_type j = file.rfind('/', i);
00711 if(j != string::npos)
00712 i = j;
00713 }
00714 string directory;
00715 if(i != string::npos) {
00716 directory = string(file, 0, i);
00717 _fname = string(file, i+1);
00718 } else {
00719 directory = "";
00720 _fname = string(file);
00721 }
00722 clean();
00723
00724 bool is_fullthrottle = true;
00725 try {
00726 is_fullthrottle = read_string(file);
00727 } catch(exception & e) {
00728 #ifdef DEBUG
00729 cerr << "read_string() returned an exception : " << e.what();
00730 #endif
00731 }
00732 if(_strings) {
00733 if(is_fullthrottle) {
00734 if(directory == "") {
00735 directory == "../DATA/";
00736 } else {
00737 string::size_type i = directory.rfind('\\');
00738 if(i == string::npos) i = directory.rfind('/');
00739 if(i == string::npos) {
00740 directory = "DATA/";
00741 } else {
00742 directory = string(directory, 0, i) + "/DATA/";
00743 }
00744 }
00745 _fr[0] = load_font(directory + "SCUMMFNT.NUT", true);
00746 _fr[2] = load_font(directory + "TITLFNT.NUT", true);
00747 } else {
00748 for(int i = 0; i < 4; i++) {
00749 ostringstream oss;
00750 oss << directory << "/FONT" << i << ".NUT";
00751 _fr[i] = load_font(oss.str());
00752 }
00753 }
00754 }
00755
00756 file_chunck base = file_chunck(file);
00757
00758 checkBlock(base, TYPE_ANIM);
00759
00760 while(!base.eof()) {
00761 chunck * sub = base.sub_block();
00762 switch(sub->get_type()) {
00763 case TYPE_AHDR:
00764 handleAnimHeader(*sub);
00765 break;
00766 case TYPE_FRME:
00767 handleFrame(*sub);
00768 break;
00769 default:
00770 ostringstream oss;
00771 oss << "Unknown chunck found : " << sub->get_type() << ", " << sub->get_size();
00772 throw runtime_error(oss.str());
00773 }
00774 delete sub;
00775 }
00776 if(_output_sound) {
00777 _mixer.stop();
00778 }
00779 return true;
00780 }