OTUTOR.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /*
  2. * Seven Kingdoms: Ancient Adversaries
  3. *
  4. * Copyright 1997,1998 Enlight Software Ltd.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. *
  19. */
  20. //Filename : OTUTOR.CPP
  21. //Description : Class Tutor
  22. #include <OVGA.h>
  23. #include <OSYS.h>
  24. #include <OAUDIO.h>
  25. #include <OBATTLE.h>
  26. #include <OFONT.h>
  27. #include <OF_MONS.h>
  28. #include <OMONSRES.h>
  29. #include <OIMGRES.h>
  30. #include <OBUTTON.h>
  31. #include <OBUTT3D.h>
  32. #include <OGFILE.h>
  33. #include <OGAME.h>
  34. #include <OGAMESET.h>
  35. #include <OWORLD.h>
  36. #include <OFILETXT.h>
  37. #include <OTUTOR.h>
  38. //---------- define constant ------------//
  39. #define TUTOR_DB "TUT_LIST.RES"
  40. #define TUTOR_TEXT_RES "TUT_TEXT.RES"
  41. #define TUTOR_INTRO_RES "TUT_INTR.RES"
  42. //---------- define coordinations ------------//
  43. enum { TUTOR_X1 = ZOOM_X1,
  44. TUTOR_Y1 = ZOOM_Y1,
  45. TUTOR_X2 = ZOOM_X2,
  46. TUTOR_Y2 = TUTOR_Y1+120
  47. };
  48. enum { TUTOR_BUTTON_X1 = TUTOR_X2-66,
  49. TUTOR_BUTTON_Y1 = TUTOR_Y1+20
  50. };
  51. //-------- Define static vars ----------//
  52. static Button button_new_tutor, button_quit_tutor;
  53. static Button button_restart, button_prev, button_next;
  54. static Button3D button_sample;
  55. //------- Begin of function Tutor::Tutor -----------//
  56. Tutor::Tutor()
  57. {
  58. memset( this, 0, sizeof(Tutor) );
  59. }
  60. //--------- End of function Tutor::Tutor -----------//
  61. //------- Begin of function Tutor::~Tutor -----------//
  62. Tutor::~Tutor()
  63. {
  64. deinit();
  65. }
  66. //--------- End of function Tutor::~Tutor -----------//
  67. //---------- Begin of function Tutor::init -----------//
  68. //
  69. // This function must be called after a map is generated.
  70. //
  71. void Tutor::init()
  72. {
  73. deinit();
  74. //------- allocate text_block_array ----------//
  75. text_block_array = (TutorTextBlock*) mem_add( sizeof(TutorTextBlock) * MAX_TUTOR_TEXT_BLOCK );
  76. //----- open tutorial text resource file -------//
  77. String str;
  78. str = DIR_RES;
  79. str += TUTOR_TEXT_RES;
  80. res_tutor_text.init(str, 0); // 0-don't read all into buffer
  81. //----- open tutorial introduction resource file -------//
  82. str = DIR_RES;
  83. str += TUTOR_INTRO_RES;
  84. res_tutor_intro.init(str, 0); // 0-don't read all into buffer
  85. //------- load database information --------//
  86. load_tutor_info();
  87. init_flag=1;
  88. }
  89. //---------- End of function Tutor::init -----------//
  90. //---------- Begin of function Tutor::deinit -----------//
  91. void Tutor::deinit()
  92. {
  93. if( init_flag )
  94. {
  95. mem_del(tutor_info_array);
  96. tutor_info_array = NULL;
  97. mem_del(text_block_array);
  98. text_block_array = NULL;
  99. if( tutor_text_buf )
  100. {
  101. mem_del(tutor_text_buf);
  102. tutor_text_buf = NULL;
  103. }
  104. if( tutor_intro_buf )
  105. {
  106. mem_del(tutor_intro_buf);
  107. tutor_intro_buf = NULL;
  108. }
  109. res_tutor_text.deinit();
  110. res_tutor_intro.deinit();
  111. init_flag=0;
  112. }
  113. }
  114. //---------- End of function Tutor::deinit -----------//
  115. //------- Begin of function Tutor::load_tutor_info -------//
  116. //
  117. // Read in information of GOD.DBF into memory array
  118. //
  119. void Tutor::load_tutor_info()
  120. {
  121. TutorRec *tutorRec;
  122. TutorInfo *tutorInfo;
  123. String str;
  124. str = DIR_RES;
  125. str += TUTOR_DB;
  126. Database dbTutor(str, 1);
  127. tutor_count = (short) dbTutor.rec_count();
  128. tutor_info_array = (TutorInfo*) mem_add( sizeof(TutorInfo)*tutor_count );
  129. //------ read in tutor information array -------//
  130. memset( tutor_info_array, 0, sizeof(TutorInfo) * tutor_count );
  131. for( int i=0 ; i<tutor_count ; i++ )
  132. {
  133. tutorRec = (TutorRec*) dbTutor.read(i+1);
  134. tutorInfo = tutor_info_array+i;
  135. m.rtrim_fld( tutorInfo->code, tutorRec->code, tutorRec->CODE_LEN );
  136. m.rtrim_fld( tutorInfo->des , tutorRec->des , tutorRec->DES_LEN );
  137. #if(defined(GERMAN) || defined(FRENCH) || defined(SPANISH))
  138. translate.multi_to_win(tutorInfo->des, tutorInfo->DES_LEN);
  139. #endif
  140. }
  141. //--- exclude the Fryhtan and Seat of Power tutorials in the demo ---//
  142. #ifdef DEMO
  143. tutor_count -= 2;
  144. #endif
  145. }
  146. //--------- End of function Tutor::load_tutor_info ---------//
  147. //------------ Begin of function Tutor::load -------------//
  148. //
  149. // <int> tutorId - id. of the tutorial
  150. //
  151. void Tutor::load(int tutorId)
  152. {
  153. cur_tutor_id = tutorId;
  154. //------- get the tutor msgs from the resource file -------//
  155. int dataSize;
  156. File* filePtr = res_tutor_text.get_file( tutor[tutorId]->code, dataSize);
  157. if( !filePtr ) // if error getting the tutor resource
  158. {
  159. err_here();
  160. return;
  161. }
  162. //------ Open the file and allocate buffer -----//
  163. FileTxt fileTxt( filePtr, dataSize ); // initialize fileTxt with an existing file stream
  164. if( dataSize > tutor_text_buf_size )
  165. {
  166. tutor_text_buf = mem_resize( tutor_text_buf, dataSize ); // allocate a buffer larger than we need for the largest size possible
  167. tutor_text_buf_size = dataSize;
  168. }
  169. //-------- read in tutor info one by one --------//
  170. TutorTextBlock* tutorTextBlock = text_block_array;
  171. char* textPtr = tutor_text_buf;
  172. int readLen, totalReadLen=0; // total length of text read into the tutor_text_buf
  173. int loopCount=0;
  174. char* tokenStr;
  175. text_block_count=0;
  176. fileTxt.next_line(); // by pass the first two lines of file description
  177. fileTxt.next_line();
  178. while( !fileTxt.is_eof() )
  179. {
  180. err_when( loopCount++ > 10000 );
  181. tokenStr = fileTxt.get_token(0); // don't advance the pointer
  182. if( !tokenStr )
  183. break;
  184. //------ read in the display button code of the tutorial segment -------//
  185. if( strcmpi( tokenStr, "Button" ) == 0 )
  186. {
  187. fileTxt.get_token(1); // advance the pointer
  188. tokenStr = fileTxt.get_token(1);
  189. strncpy( tutorTextBlock->button_code, tokenStr, tutorTextBlock->BUTTON_CODE_LEN );
  190. tutorTextBlock->button_code[tutorTextBlock->BUTTON_CODE_LEN] = NULL;
  191. }
  192. else
  193. {
  194. tutorTextBlock->button_code[0] = NULL;
  195. }
  196. //------- read in the tutorial text -------//
  197. readLen = fileTxt.read_paragraph(textPtr, tutor_text_buf_size-totalReadLen);
  198. tutorTextBlock->text_ptr = textPtr;
  199. tutorTextBlock->text_len = readLen;
  200. textPtr += readLen;
  201. totalReadLen += readLen;
  202. err_when( totalReadLen>tutor_text_buf_size );
  203. //----------- next tutor block -------------//
  204. fileTxt.next_line(); // pass the page break line
  205. text_block_count++;
  206. tutorTextBlock++;
  207. err_when( text_block_count >= MAX_TUTOR_TEXT_BLOCK );
  208. }
  209. cur_text_block_id = 1;
  210. last_text_block_id = 0;
  211. }
  212. //------------- End of function Tutor::load -------------//
  213. //------------ Begin of function Tutor::get_intro -------------//
  214. //
  215. // <int> tutorId - id. of the tutorial
  216. //
  217. // return: <char*> return the introduction text of the tutorial.
  218. //
  219. char* Tutor::get_intro(int tutorId)
  220. {
  221. //------- get the tutor msgs from the resource file -------//
  222. int dataSize;
  223. File* filePtr = res_tutor_intro.get_file( tutor[tutorId]->code, dataSize);
  224. if( !filePtr ) // if error getting the tutor resource
  225. {
  226. err_here();
  227. return NULL;
  228. }
  229. //------ Open the file and allocate buffer -----//
  230. FileTxt fileTxt( filePtr, dataSize ); // initialize fileTxt with an existing file stream
  231. if( dataSize > tutor_intro_buf_size )
  232. {
  233. tutor_intro_buf = mem_resize( tutor_intro_buf, dataSize ); // allocate a buffer larger than we need for the largest size possible
  234. tutor_intro_buf_size = dataSize;
  235. }
  236. // #### begin Gilbert 23/9 #######//
  237. fileTxt.read_paragraph(tutor_intro_buf, tutor_intro_buf_size);
  238. // #### end Gilbert 23/9 #######//
  239. return tutor_intro_buf;
  240. }
  241. //------------- End of function Tutor::get_intro -------------//
  242. //-------- Begin of function Tutor::select_run_tutor --------//
  243. //
  244. // <int> inGameCall - whether it's called from the main menu or from in-game tutorial.
  245. //
  246. void Tutor::select_run_tutor(int inGameCall)
  247. {
  248. if( inGameCall )
  249. select_tutor(-2);
  250. int tutorId = select_tutor(1);
  251. if( tutorId > 0 )
  252. run(tutorId, inGameCall);
  253. if( inGameCall )
  254. select_tutor(-1);
  255. }
  256. //--------- End of function Tutor::select_run_tutor ---------//
  257. //---------- Begin of function Tutor::run -----------//
  258. void Tutor::run(int tutorId, int inGameCall)
  259. {
  260. //--- don't load pre-saved game when selecting a new tutorial in the game ---//
  261. if( !inGameCall )
  262. {
  263. String str;
  264. str = DIR_TUTORIAL;
  265. str += tutor[tutorId]->code;
  266. str += ".TUT";
  267. if( m.is_file_exist(str) )
  268. {
  269. game_file.load_game(str);
  270. }
  271. else
  272. {
  273. str = "TUTORIAL\\STANDARD.TUT";
  274. if( m.is_file_exist(str) )
  275. game_file.load_game(str);
  276. }
  277. //------ fix firm_build_id problem -----//
  278. Firm* firmPtr;
  279. for( int i=firm_array.size() ; i>0 ; i-- )
  280. {
  281. if( firm_array.is_deleted(i) )
  282. continue;
  283. firmPtr = firm_array[i];
  284. if( firmPtr->firm_id != FIRM_MONSTER )
  285. continue;
  286. int monsterId = ((FirmMonster*)firmPtr)->monster_id;
  287. firmPtr->firm_build_id = firm_res[FIRM_MONSTER]->get_build_id( monster_res[monsterId]->firm_build_code );
  288. }
  289. //----- set the gaming speed to normal -----//
  290. sys.set_speed(9, COMMAND_AUTO);
  291. }
  292. //--------- load the tutorial text ------------//
  293. tutor.load(tutorId);
  294. game.game_mode = GAME_TUTORIAL;
  295. //------------------------------------------//
  296. if( !inGameCall )
  297. {
  298. battle.run_loaded();
  299. game.deinit();
  300. }
  301. }
  302. //----------- End of function Tutor::run ------------//
  303. //------------ Begin of function Tutor::disp ------------//
  304. void Tutor::disp()
  305. {
  306. vga.use_back();
  307. Vga::opaque_flag = config.opaque_report;
  308. vga.d3_panel_down( TUTOR_X1, TUTOR_Y1, TUTOR_X2, TUTOR_Y2 );
  309. Vga::opaque_flag = 0;
  310. TutorTextBlock* tutorTextBlock = text_block_array+cur_text_block_id-1;
  311. //------- display button bitmap ------//
  312. int textX2 = TUTOR_X2-10;
  313. if( tutorTextBlock->button_code[0] )
  314. {
  315. button_sample.paint( TUTOR_BUTTON_X1, TUTOR_BUTTON_Y1, 'A', tutorTextBlock->button_code );
  316. textX2 = TUTOR_BUTTON_X1-16;
  317. }
  318. //-------- display tutorial text --------//
  319. font_san.put_paragraph( TUTOR_X1+10, TUTOR_Y1+10, textX2, TUTOR_Y2-10,
  320. tutorTextBlock->text_ptr, 4 );
  321. //--------- display controls ---------//
  322. int x=TUTOR_X1+10, y=TUTOR_Y2-22;
  323. #ifdef GERMAN
  324. button_new_tutor.paint_text( x, y, "Next Training" );
  325. button_quit_tutor.paint_text( x+120, y, "Quit Training" );
  326. #else
  327. button_new_tutor.paint_text( x, y, "Next Training" );
  328. button_quit_tutor.paint_text( x+100, y, "Quit Training" );
  329. #endif
  330. //---- display current text block position ----//
  331. x += 360;
  332. String str;
  333. str = cur_text_block_id;
  334. str += " / ";
  335. str += text_block_count;
  336. font_san.put( x, y+3, str );
  337. x += 60;
  338. //------- display other controls --------//
  339. button_restart.paint_text( x, y, "|<<" );
  340. if( cur_text_block_id > 1 )
  341. button_prev.paint_text( x+45, y, " < " );
  342. if( cur_text_block_id < text_block_count )
  343. button_next.paint_text( x+88, y, " > " );
  344. vga.use_front();
  345. //------ play speech of the tutorial -------//
  346. if( last_text_block_id != cur_text_block_id )
  347. {
  348. last_text_block_id = cur_text_block_id;
  349. play_speech();
  350. }
  351. }
  352. //------------ End of function Tutor::disp ------------//
  353. //----------- Begin of function Tutor::play_speech ------------//
  354. void Tutor::play_speech()
  355. {
  356. if( !sys.dir_tutorial[0] )
  357. return;
  358. if( cur_speech_wav_id )
  359. stop_speech();
  360. //---------------------------------//
  361. String str;
  362. str = sys.dir_tutorial;
  363. str += tutor[cur_tutor_id]->code;
  364. str += "\\TUT";
  365. if( cur_text_block_id < 10 ) // Add a zero. e.g. "TUT01"
  366. str += "0";
  367. str += cur_text_block_id;
  368. if( !m.is_file_exist(str) )
  369. return;
  370. // ##### begin Gilbert 25/9 ######//
  371. cur_speech_wav_id = audio.play_long_wav(str, DEF_REL_VOLUME); // cur_speech_wav_id is the WAV id that is needed for stopping playing of the WAV file
  372. // ##### end Gilbert 25/9 ######//
  373. }
  374. //------------ End of function Tutor::play_speech ------------//
  375. //----------- Begin of function Tutor::stop_speech ------------//
  376. void Tutor::stop_speech()
  377. {
  378. audio.stop_long_wav(cur_speech_wav_id);
  379. cur_speech_wav_id = 0;
  380. }
  381. //------------ End of function Tutor::stop_speech ------------//
  382. //---------- Begin of function Tutor::detect ----------//
  383. int Tutor::detect()
  384. {
  385. if( button_new_tutor.detect() )
  386. {
  387. stop_speech();
  388. select_run_tutor(1); // select and run tutorial, 1-called from in-game, not from the main menu
  389. return 1;
  390. }
  391. if( button_quit_tutor.detect() )
  392. {
  393. stop_speech();
  394. game.game_mode = GAME_SINGLE_PLAYER;
  395. return 1;
  396. }
  397. if( button_restart.detect() )
  398. {
  399. cur_text_block_id = 1;
  400. return 1;
  401. }
  402. if( cur_text_block_id > 1 && button_prev.detect() )
  403. {
  404. prev_text_block();
  405. return 1;
  406. }
  407. if( cur_text_block_id < text_block_count && button_next.detect() )
  408. {
  409. next_text_block();
  410. return 1;
  411. }
  412. return 0;
  413. }
  414. //----------- End of function Tutor::detect ------------//
  415. //---------- Begin of function Tutor::prev_text_block ----------//
  416. void Tutor::prev_text_block()
  417. {
  418. if( cur_text_block_id > 1 )
  419. cur_text_block_id--;
  420. }
  421. //----------- End of function Tutor::prev_text_block ------------//
  422. //---------- Begin of function Tutor::next_text_block ----------//
  423. void Tutor::next_text_block()
  424. {
  425. if( cur_text_block_id < text_block_count )
  426. cur_text_block_id++;
  427. }
  428. //----------- End of function Tutor::next_text_block ------------//
  429. //---------- Begin of function Tutor::operator[] -----------//
  430. TutorInfo* Tutor::operator[](int recNo)
  431. {
  432. err_when( recNo < 1 || recNo > tutor_count );
  433. return tutor_info_array + recNo - 1;
  434. }
  435. //----------- End of function Tutor::operator[] ------------//