OINFO.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  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 : OINFO.CPP
  21. //Description : Info class
  22. #include <time.h>
  23. #include <OVGA.h>
  24. #include <OIMGRES.h>
  25. #include <OSPY.h>
  26. #include <OSTR.h>
  27. #include <OBUTTON.h>
  28. #include <OMOUSE.h>
  29. #include <OFIRM.h>
  30. #include <OSTR.h>
  31. #include <ONEWS.h>
  32. #include <ONATION.h>
  33. #include <OFONT.h>
  34. #include <ODATE.h>
  35. #include <OTOWN.h>
  36. #include <ODATE.h>
  37. #include <OGAME.h>
  38. #include <OGFILE.h>
  39. #include <OPOWER.h>
  40. #include <OSITE.h>
  41. #include <OWALLRES.h>
  42. #include <OSYS.h>
  43. #include <OUNIT.h>
  44. #include <OCOLTBL.h>
  45. #include <OINFO.h>
  46. #include <OOPTMENU.h>
  47. //------------ Define static vars ----------------//
  48. static char* skill_name_array[] =
  49. {
  50. "Combat Skill",
  51. "Construction Skill",
  52. "Production Skill"
  53. };
  54. //------ define static vars --------//
  55. static char *save_buf_1 = NULL;
  56. static char *save_buf_1b = NULL;
  57. static char *save_buf_2 = NULL;
  58. static char *save_buf_3 = NULL;
  59. static char *save_buf_4 = NULL;
  60. //-------- Begin of function Info::Info --------//
  61. //
  62. Info::Info() : report_array(sizeof(short), 50),
  63. report_array2(sizeof(short), 50),
  64. talk_msg_disp_array(sizeof(TalkMsgDisp), 50)
  65. {
  66. info_background_bitmap = NULL;
  67. }
  68. //--------- End of function Info::Info ---------//
  69. //-------- Begin of function Info::~Info --------//
  70. //
  71. Info::~Info()
  72. {
  73. deinit();
  74. err_when( save_buf_1 );
  75. }
  76. //--------- End of function Info::~Info ---------//
  77. //-------- Begin of function Info::init --------//
  78. //
  79. void Info::init()
  80. {
  81. deinit();
  82. game_day = 1;
  83. game_month = 6;
  84. game_year = 1000;
  85. game_start_date = date.julian( game_year, game_month, game_day );
  86. game_date = game_start_date;
  87. year_day = date.day_year( game_year, game_month, game_day );
  88. year_passed= 0; // no. of years has been passed since the game begins
  89. goal_deadline = date.julian( date.year(info.game_start_date)+config.goal_year_limit,
  90. date.month(info.game_start_date),
  91. date.day(info.game_start_date) );
  92. goal_difficulty = 0;
  93. goal_score_bonus = 0;
  94. //------ reset report browsers recno -----//
  95. browse_nation_recno = 0;
  96. browse_race_recno = 0;
  97. browse_firm_recno = 0;
  98. browse_income_recno = 0;
  99. browse_expense_recno = 0;
  100. browse_troop_recno = 0;
  101. browse_unit_recno = 0;
  102. browse_tech_recno = 0;
  103. browse_god_recno = 0;
  104. browse_town_recno = 0;
  105. browse_spy_recno = 0;
  106. browse_caravan_recno = 0;
  107. browse_ship_recno = 0;
  108. browse_talk_msg_recno= 0;
  109. browse_news_recno = 0;
  110. browse_ai_action_recno = 0;
  111. browse_ai_attack_recno = 0;
  112. //------ vars of the nation report ------//
  113. nation_report_mode = NATION_REPORT_INFO;
  114. player_reply_mode = 0;
  115. chat_receiver_type = CHAT_RECEIVER_CURRENT;
  116. //----------------------------------//
  117. start_play_time = m.get_time(); // the time player start playing the game
  118. total_play_time = 0; // total time the player has played in all saved games
  119. // these will be updated during loading game and saving game
  120. err_when( MAX_REMOTE_CHAT_STR < DISP_NEWS_COUNT ); // it must not fewer then the maximum number of news that can be displayed on the screen at a time.
  121. }
  122. //--------- End of function Info::init ---------//
  123. //-------- Begin of function Info::deinit --------//
  124. //
  125. void Info::deinit()
  126. {
  127. if( info_background_bitmap )
  128. {
  129. mem_del( info_background_bitmap );
  130. info_background_bitmap = NULL;
  131. }
  132. }
  133. //--------- End of function Info::deinit ---------//
  134. //------- Begin of function Info::init_random_seed ------//
  135. //
  136. // [unsigned] randomSeed - if given, it will be the random seed of the game.
  137. // random seed. otherwise a random seed will be
  138. // picked.
  139. // (default:0)
  140. //
  141. void Info::init_random_seed(int randomSeed)
  142. {
  143. if( randomSeed )
  144. random_seed = randomSeed;
  145. else
  146. {
  147. randomSeed = time(NULL);
  148. randomSeed = (int) _rotr( randomSeed, 4 );
  149. if( randomSeed < 0 )
  150. randomSeed = ~randomSeed;
  151. if( randomSeed == 0 )
  152. randomSeed = 1;
  153. random_seed = randomSeed;
  154. }
  155. m.set_random_seed(random_seed);
  156. //------ write random seed --------//
  157. if( sys.testing_session )
  158. {
  159. File fileMapSeed;
  160. fileMapSeed.file_create( "MAP.RS" );
  161. String str(m.format(random_seed,1));
  162. fileMapSeed.file_write(str, str.len());
  163. }
  164. }
  165. //------- End of function Info::init_random_seed ------//
  166. //-------- Begin of function Info::next_day ---------//
  167. //
  168. void Info::next_day()
  169. {
  170. if( ++game_day > 30 )
  171. game_day = 30; // game_day is limited to 1-30 for
  172. // calculation of e.g. revenue_30days()
  173. game_date++;
  174. week_day=game_date%7;
  175. //-----------------------------------------//
  176. if( date.month(game_date) != game_month )
  177. {
  178. game_day = 1;
  179. game_month = date.month(game_date);
  180. firm_array.next_month();
  181. nation_array.next_month();
  182. }
  183. if( date.year(game_date) != game_year )
  184. {
  185. game_month = 1;
  186. game_year = date.year(game_date);
  187. year_passed++;
  188. firm_array.next_year();
  189. nation_array.next_year();
  190. }
  191. //-------- set year_day ----------//
  192. year_day = date.day_year( game_year, game_month, game_day );
  193. //--- if a spy is viewing secret reports of other nations ---//
  194. if( viewing_spy_recno )
  195. process_viewing_spy();
  196. //-------- deadline approaching message -------//
  197. if( !game.game_has_ended && config.goal_year_limit_flag )
  198. {
  199. int dayLeft = goal_deadline-game_date;
  200. int yearLeft = dayLeft/365;
  201. if( dayLeft%365==0 && yearLeft>=1 && yearLeft<=5 )
  202. news_array.goal_deadline( yearLeft, 0 );
  203. if( dayLeft==0 ) // deadline arrives, everybody loses the game
  204. game.game_end(0, 0);
  205. }
  206. }
  207. //---------- End of function Info::next_day --------//
  208. //-------- Begin of function Info::disp_panel --------//
  209. //
  210. void Info::disp_panel()
  211. {
  212. image_interface.put_to_buf( &vga_back, "MAINSCR" );
  213. //------ keep a copy of bitmap of the panel texture -----//
  214. if( !info_background_bitmap )
  215. info_background_bitmap = mem_add( 4 + (INFO_X2-INFO_X1+1)*(INFO_Y2-INFO_Y1+1) );
  216. vga_back.read_bitmap( INFO_X1, INFO_Y1, INFO_X2, INFO_Y2, info_background_bitmap );
  217. }
  218. //--------- End of function Info::disp_panel ---------//
  219. //-------- Begin of function Info::disp --------//
  220. //
  221. // Display the side info area.
  222. //
  223. void Info::disp()
  224. {
  225. // mouse.handle_flicking = 0; // since it will be called by Firm detect functions directly which may have set mouse.handle_flicking to 1 first, so we need to cancel it here
  226. if( !power.enable_flag )
  227. return;
  228. if( sys.signal_exit_flag )
  229. return;
  230. if( option_menu.is_active() )
  231. return;
  232. vga_back.put_bitmap( INFO_X1, INFO_Y1, info_background_bitmap );
  233. vga_front.put_bitmap( INFO_X1, INFO_Y1, info_background_bitmap );
  234. //------- use front buffer -------//
  235. int saveUseBackBuf = vga.use_back_buf;
  236. vga.use_front();
  237. //------ if units/firm selected, display info --------//
  238. if( firm_array.selected_recno )
  239. {
  240. firm_array[firm_array.selected_recno]->disp_info_both(INFO_REPAINT);
  241. }
  242. else if( town_array.selected_recno )
  243. {
  244. town_array[town_array.selected_recno]->disp_info(INFO_REPAINT);
  245. }
  246. else if( site_array.selected_recno )
  247. {
  248. site_array[site_array.selected_recno]->disp_info(INFO_REPAINT);
  249. }
  250. else if( unit_array.selected_recno )
  251. {
  252. unit_array[unit_array.selected_recno]->disp_info(INFO_REPAINT);
  253. }
  254. else if( wall_res.selected_x_loc >= 0 )
  255. {
  256. wall_res.disp_info(INFO_REPAINT);
  257. }
  258. //----- restore use back buffer if it was ----//
  259. if( saveUseBackBuf )
  260. vga.use_back();
  261. }
  262. //-------- End of function Info::disp --------//
  263. //-------- Begin of function Info::update --------//
  264. void Info::update()
  265. {
  266. if( !power.enable_flag )
  267. return;
  268. if( option_menu.is_active() )
  269. return;
  270. //-------------------------------------------//
  271. disp_heading();
  272. //------- use front buffer -------//
  273. int saveUseBackBuf = vga.use_back_buf;
  274. vga.use_front();
  275. //-------------------------------------------//
  276. if( firm_array.selected_recno )
  277. {
  278. firm_array[firm_array.selected_recno]->disp_info_both(INFO_UPDATE);
  279. }
  280. else if( town_array.selected_recno )
  281. {
  282. town_array[town_array.selected_recno]->disp_info(INFO_UPDATE);
  283. }
  284. else if( site_array.selected_recno )
  285. {
  286. site_array[site_array.selected_recno]->disp_info(INFO_UPDATE);
  287. }
  288. else if( unit_array.selected_recno )
  289. {
  290. unit_array[unit_array.selected_recno]->disp_info(INFO_UPDATE);
  291. }
  292. else if( wall_res.selected_x_loc >= 0 )
  293. {
  294. wall_res.disp_info(INFO_UPDATE);
  295. }
  296. //----- restore use back buffer if it was ----//
  297. if( saveUseBackBuf )
  298. vga.use_back();
  299. }
  300. //-------- End of function Info::update --------//
  301. //-------- Begin of function Info::disp_heading --------//
  302. void Info::disp_heading()
  303. {
  304. //---- display info on the top menu area ----//
  305. int x=TOP_MENU_X2-250;
  306. //---------- display date -----------//
  307. font_mid.use_max_height();
  308. font_mid.disp( 460, 10, date.date_str(game_date,1), 575);
  309. font_mid.use_std_height();
  310. if( !nation_array.player_recno ) // the player has lost the game
  311. {
  312. font_mid.disp( 307, 10, "", 445); // clear the display
  313. font_mid.disp( 305, 30, "", 445);
  314. // ##### begin Gilbert 4/11 #######//
  315. image_icon.put_front(447,26, "REPU_DW" );
  316. // ##### end Gilbert 4/11 #######//
  317. font_mid.disp( 476, 30, "", 575);
  318. return;
  319. }
  320. String str;
  321. Nation* nationPtr = ~nation_array;
  322. //------- display food and net food change --------//
  323. err_when( vga.use_back_buf );
  324. char* strPtr = nationPtr->food_str();
  325. font_mid.disp( 307, 10, strPtr, 445);
  326. //------- display cash and profit --------//
  327. strPtr = nationPtr->cash_str();
  328. font_mid.disp( 305, 30, strPtr, 445);
  329. //------- display reputation ---------//
  330. if( nationPtr->reputation >= 0 )
  331. {
  332. str = m.format( (int)nationPtr->reputation, 4 ); // format type 4 - no thousand separators
  333. }
  334. else
  335. {
  336. str = "-";
  337. str += m.format( (int)-nationPtr->reputation, 4 ); // format type 4 - no thousand separators
  338. }
  339. int reputationChange = (int) nationPtr->reputation_change_365days();
  340. if( reputationChange )
  341. {
  342. str += " (";
  343. if( reputationChange > 0 )
  344. str += "+";
  345. else
  346. str += "-";
  347. str += abs(reputationChange);
  348. str += ")";
  349. }
  350. image_icon.put_front(447,26, nationPtr->reputation_change_365days() >= (float)0.0 ? (char*)"REPU_UP" : (char*)"REPU_DW" );
  351. font_mid.disp( 476, 30, str, 575);
  352. }
  353. //-------- End of function Info::disp_heading --------//
  354. //-------- Begin of function Info::detect --------//
  355. int Info::detect()
  356. {
  357. //------------ detect objects ------------//
  358. if( firm_array.selected_recno )
  359. {
  360. firm_array[firm_array.selected_recno]->detect_info_both();
  361. }
  362. else if( town_array.selected_recno )
  363. {
  364. town_array[town_array.selected_recno]->detect_info();
  365. }
  366. else if( site_array.selected_recno )
  367. {
  368. site_array[site_array.selected_recno]->detect_info();
  369. }
  370. else if( unit_array.selected_recno )
  371. {
  372. unit_array[unit_array.selected_recno]->detect_info();
  373. }
  374. return 0;
  375. }
  376. //-------- End of function Info::detect --------//
  377. //-------- Begin of function Info::draw_selected --------//
  378. void Info::draw_selected()
  379. {
  380. if( firm_array.selected_recno )
  381. firm_array[firm_array.selected_recno]->draw_selected();
  382. else if( town_array.selected_recno )
  383. town_array[town_array.selected_recno]->draw_selected();
  384. else if( site_array.selected_recno )
  385. site_array[site_array.selected_recno]->draw_selected();
  386. else if( wall_res.selected_x_loc >= 0 )
  387. wall_res.draw_selected();
  388. }
  389. //-------- End of function Info::draw_selected --------//
  390. //-------- Begin of function Info::get_report_data --------//
  391. short Info::get_report_data(int recNo)
  392. {
  393. err_when( recNo<1 || recNo>report_array.size() );
  394. return *((short*)report_array.get(recNo));
  395. }
  396. //-------- End of function Info::get_report_data --------//
  397. //-------- Begin of function Info::get_report_data2 --------//
  398. short Info::get_report_data2(int recNo)
  399. {
  400. err_when( recNo<1 || recNo>report_array2.size() );
  401. return *((short*)report_array2.get(recNo));
  402. }
  403. //-------- End of function Info::get_report_data2 --------//
  404. //-------- Begin of function Info::process_viewing_spy --------//
  405. void Info::process_viewing_spy()
  406. {
  407. //---- check if the viewing spy is still valid ----//
  408. int isValid=1;
  409. if( spy_array.is_deleted(viewing_spy_recno) ) // the spy is dead
  410. {
  411. isValid = 0;
  412. }
  413. else
  414. {
  415. Spy* spyPtr = spy_array[viewing_spy_recno];
  416. //-- check if the spy still stay in the same place --//
  417. if( spyPtr->spy_place_nation_recno() != info.viewing_nation_recno )
  418. {
  419. isValid = 0;
  420. }
  421. else
  422. {
  423. /*
  424. //--- on average, a spy will get caught in 5 to 15 days when viewing the secret of its enemy ---//
  425. if( m2.random(5+spyPtr->spy_skill/5) ) // use m2 to avoid multiplayer sync problem
  426. {
  427. spyPtr->set_exposed(COMMAND_PLAYER);
  428. isValid = 0;
  429. }
  430. */
  431. }
  432. }
  433. if( !isValid ) //-- if not valid, set the mode back to normal viewing mode
  434. sys.set_view_mode(MODE_NORMAL);
  435. }
  436. //-------- End of function Info::process_viewing_spy --------//
  437. //------- Begin of function Info::play_time_str --------//
  438. //
  439. char* Info::play_time_str()
  440. {
  441. int totalMin = total_play_time / (60*1000);
  442. int playHour = totalMin / 60;
  443. int playMin = totalMin - playHour*60;
  444. static String str;
  445. str = "";
  446. if( playHour > 0 )
  447. {
  448. str += playHour;
  449. str += translate.process( playHour>1 ? (char*)" hours" : (char*)" hour" );
  450. str += translate.process( " and " );
  451. }
  452. str += playMin;
  453. str += translate.process( playMin>1 ? (char*)" minutes" : (char*)" minute" );
  454. return str;
  455. }
  456. //---------- End of function Info::play_time_str ---------//
  457. //------- Begin of function Info::game_duration_str --------//
  458. //
  459. char* Info::game_duration_str()
  460. {
  461. //------- get the true game start date --------//
  462. int gameStartDate;
  463. //-- For scenarios (whose goal_difficulty are > 0 ), the actual game start date is no info.game_start_date, we must calculate it
  464. if( info.goal_difficulty )
  465. {
  466. gameStartDate = date.julian( date.year(info.goal_deadline)-config.goal_year_limit,
  467. date.month(info.goal_deadline),
  468. date.day(info.goal_deadline) );
  469. }
  470. else
  471. {
  472. gameStartDate = info.game_start_date;
  473. }
  474. //---------------------------------------------//
  475. int totalDay = info.game_date - gameStartDate;
  476. int playYear = totalDay / 365;
  477. int playDay = totalDay - playYear*365;
  478. static String str;
  479. str = "";
  480. if( playYear > 0 )
  481. {
  482. str += playYear;
  483. str += translate.process( playYear>1 ? (char*)" years" : (char*)" year" );
  484. str += translate.process( (char*)" and " );
  485. }
  486. str += playDay;
  487. str += translate.process( playDay>1 ? (char*)" days" : (char*)" day" );
  488. return str;
  489. }
  490. //---------- End of function Info::game_duration_str ---------//
  491. //------- Begin of function Info::save_game_scr --------//
  492. //
  493. void Info::save_game_scr()
  494. {
  495. err_when( save_buf_1 );
  496. // top and buttom
  497. if( 0 < ZOOM_Y1 )
  498. {
  499. save_buf_1 = vga_front.save_area(0, 0, VGA_WIDTH-1, ZOOM_Y1-1);
  500. save_buf_1b = vga_back.save_area(0, 0, VGA_WIDTH-1, ZOOM_Y1-1); // save the back buffer also as the top area of the back buf is used for font display
  501. }
  502. if( ZOOM_Y2 < VGA_HEIGHT-1 )
  503. save_buf_2 = vga_front.save_area(0, ZOOM_Y2+1, VGA_WIDTH-1, VGA_HEIGHT-1);
  504. // left and right
  505. if( 0 < ZOOM_X1 )
  506. save_buf_3 = vga_front.save_area(0, ZOOM_Y1, ZOOM_X1-1, ZOOM_Y2);
  507. if( ZOOM_X2 < VGA_WIDTH-1 )
  508. save_buf_4 = vga_front.save_area(ZOOM_X2+1, ZOOM_Y1, VGA_WIDTH-1, ZOOM_Y2);
  509. }
  510. //---------- End of function Info::save_game_scr ---------//
  511. //------- Begin of function Info::rest_game_scr --------//
  512. //
  513. void Info::rest_game_scr()
  514. {
  515. // restore area outside front buffer
  516. if(save_buf_4)
  517. vga_front.rest_area(save_buf_4, 1);
  518. if(save_buf_3)
  519. vga_front.rest_area(save_buf_3, 1);
  520. if(save_buf_2)
  521. vga_front.rest_area(save_buf_2, 1);
  522. if(save_buf_1)
  523. vga_front.rest_area(save_buf_1, 1);
  524. if(save_buf_1b)
  525. vga_back.rest_area(save_buf_1b, 1);
  526. save_buf_1 = NULL;
  527. info.disp();
  528. sys.blt_virtual_buf(); // blt the virtual front buffer to the screen
  529. }
  530. //---------- End of function Info::rest_game_scr ---------//
  531. //------- Begin of function Info::free_game_scr --------//
  532. //
  533. void Info::free_game_scr()
  534. {
  535. if(save_buf_4)
  536. mem_del(save_buf_4);
  537. if(save_buf_3)
  538. mem_del(save_buf_3);
  539. if(save_buf_2)
  540. mem_del(save_buf_2);
  541. if(save_buf_1)
  542. mem_del(save_buf_1);
  543. if(save_buf_1b)
  544. mem_del(save_buf_1b);
  545. save_buf_1 = NULL;
  546. }
  547. //---------- End of function Info::free_game_scr ---------//
  548. //------- Begin of function Info::disp_loyalty --------//
  549. //
  550. // return: <int> x2 - the ending x position of the loyalty string.
  551. //
  552. int Info::disp_loyalty(int x, int y, int x2, int curLoyalty, int targetLoyalty, int nationRecno, int refreshFlag)
  553. {
  554. int endX;
  555. if( x != x2 ) // if x==x2, don't display the field name.
  556. {
  557. font_san.field( x, y, "Loyalty", x2, curLoyalty, 1, INFO_X2-2, refreshFlag);
  558. endX = x2 + 4 + font_san.text_width( m.format(curLoyalty) );
  559. }
  560. else
  561. {
  562. endX = font_san.put( x2+4, y+2, curLoyalty, 1 );
  563. }
  564. if( nation_array[nationRecno]->cash <= 0 ) // if the nation no longer has money to pay the unit
  565. targetLoyalty = 0;
  566. if( curLoyalty != targetLoyalty ) // only increase, no decrease. Decrease are caused by events. Increases are made gradually
  567. {
  568. int tx = x2+6+font_san.text_width( m.format(curLoyalty) );
  569. if( targetLoyalty > curLoyalty )
  570. image_icon.put_front( tx, y+2, "ARROWUP" );
  571. else if( targetLoyalty < curLoyalty )
  572. image_icon.put_front( tx, y+2, "ARROWDWN" );
  573. endX = font_san.put( tx+10, y+2, targetLoyalty, 1 );
  574. }
  575. return endX;
  576. }
  577. //---------- End of function Info::disp_loyalty ---------//