OTERRAIN.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  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 : OTERRAIN.CPP
  21. //Description : Terrain resource object
  22. //Ownership : Gilbert
  23. #include <OIMGRES.h>
  24. #include <COLOR.h>
  25. #include <OSYS.h>
  26. #include <OGAMESET.h>
  27. #include <OWORLD.h>
  28. #include <OTERRAIN.h>
  29. #include <OCONFIG.h>
  30. //---------- #define constant ------------//
  31. //#define TERRAIN_DB "TERRAIN"
  32. //#define TERRAIN_SUB_DB "TERSUB"
  33. //#define TERRAIN_ANIM_DB "TERANM"
  34. #define MAX_TERRAIN_ANIM_FRAME 16
  35. //-------- define base terrain colors --------//
  36. //
  37. // Base terrain types:
  38. //
  39. // -Ocean
  40. // -Dark Grass
  41. // -Light Grass
  42. // -Dark Dirt
  43. // -Light Dirt
  44. //
  45. //--------------------------------------------//
  46. static int terrain_type_color_array[TOTAL_TERRAIN_TYPE] = // the color of each terrain type on the small map
  47. {
  48. 0x20,
  49. 0x0A,
  50. 0x0D,
  51. 0x2D,
  52. };
  53. static char* map_tile_name_array[TOTAL_TERRAIN_TYPE] = // the color of each terrain type on the small map
  54. {
  55. "TERA_S",
  56. "TERA_DG",
  57. "TERA_LG",
  58. "TERA_D",
  59. };
  60. static char* map_tile_ptr_array[TOTAL_TERRAIN_TYPE];
  61. static int terrain_type_min_height_array[TOTAL_TERRAIN_TYPE][3] = // the color of each terrain type on the small map
  62. {
  63. // { 0, 5, 55 }, // S-, S0, S+
  64. // { 60, 65, 125 }, // G-, G0, G+
  65. // { 130, 135, 195 }, // F-, F0, F+
  66. // { 200, 205, 250 }, // D-, D0, D+
  67. { 0, 20, 40 }, // S-, S0, S+
  68. { 60, 80, 110 }, // G-, G0, G+
  69. { 130, 150, 180 }, // F-, F0, F+
  70. { 200, 215, 240 }, // D-, D0, D+
  71. };
  72. // ------ Begin of function TerrainInfo::get_bitmap -------//
  73. char *TerrainInfo::get_bitmap(unsigned frameNo)
  74. {
  75. return frameNo && anim_frames ? anim_bitmap_ptr[frameNo%(unsigned)anim_frames] : NULL;
  76. }
  77. // ------ end of function TerrainRes::terrain_code -------//
  78. // ------ Begin of function TerrainRes::terrain_code -------//
  79. TerrainTypeCode TerrainRes::terrain_code(char tcCode)
  80. {
  81. switch(tcCode)
  82. {
  83. case 'S':
  84. return TERRAIN_OCEAN;
  85. case 'G':
  86. return TERRAIN_DARK_GRASS;
  87. case 'F':
  88. return TERRAIN_LIGHT_GRASS;
  89. case 'D':
  90. return TERRAIN_DARK_DIRT;
  91. default:
  92. err_here();
  93. return TERRAIN_OCEAN;
  94. }
  95. }
  96. // ------ End of static function TerrainRes::terrain_code -------//
  97. // ------ Begin of static function TerrainRes::terrain_mask -------//
  98. SubTerrainMask TerrainRes::terrain_mask(char subtc)
  99. {
  100. switch(subtc)
  101. {
  102. case '0':
  103. return MIDDLE_MASK;
  104. case '+':
  105. return TOP_MASK;
  106. case '-':
  107. return BOTTOM_MASK;
  108. case 'A':
  109. return NOT_BOTTOM_MASK;
  110. case 'B':
  111. return NOT_TOP_MASK;
  112. case '*':
  113. return ALL_MASK;
  114. default:
  115. err_here();
  116. return MIDDLE_MASK;
  117. }
  118. }
  119. // ------ End of function TerrainRes::terrain_mask -------//
  120. // ------ Begin of function TerrainRes::terrain_height -------//
  121. int TerrainRes::terrain_height(int height, int *subPtr)
  122. {
  123. char tc, subtc;
  124. for( tc = TOTAL_TERRAIN_TYPE -1; tc >= 0; --tc)
  125. {
  126. if( height >= terrain_type_min_height_array[tc][0])
  127. {
  128. for( subtc = 2; subPtr && subtc >= 0; --subtc)
  129. {
  130. if(height >= terrain_type_min_height_array[tc][subtc])
  131. {
  132. *subPtr = 1 << subtc;
  133. break;
  134. }
  135. }
  136. err_when(subtc < 0);
  137. return tc+1;
  138. }
  139. }
  140. err_here();
  141. return 0;
  142. }
  143. // ------ End of function TerrainRes::terrain_height -------//
  144. // ------ Begin of function TerrainRes::min_height ------//
  145. short TerrainRes::min_height(TerrainTypeCode tc, SubTerrainMask subtc)
  146. {
  147. int s, j;
  148. for(s=0,j=1 ; s < 3 && !(subtc & j); ++s, j+=j);
  149. return terrain_type_min_height_array[tc-1][s];
  150. }
  151. // ------ End of function TerrainRes::min_height ------//
  152. // ------ Begin of function TerrainRes::max_height ------//
  153. short TerrainRes::max_height(TerrainTypeCode tc, SubTerrainMask subtc)
  154. {
  155. if( subtc & TOP_MASK )
  156. {
  157. if( tc < TOTAL_TERRAIN_TYPE )
  158. return terrain_type_min_height_array[tc-1+1][0]-1;
  159. else
  160. return 255;
  161. }
  162. int s, j;
  163. for(s=2,j=2 ; s >= 0 && !(subtc & j); --s, j>>=1);
  164. return terrain_type_min_height_array[tc-1][s]-1;
  165. }
  166. // ------ End of function TerrainRes::max_height ------//
  167. //------- Begin of function TerrainRes::TerrainRes -----------//
  168. TerrainRes::TerrainRes()
  169. {
  170. init_flag=0;
  171. }
  172. //--------- End of function TerrainRes::TerrainRes -----------//
  173. //---------- Begin of function TerrainRes::init -----------//
  174. //
  175. // This function must be called after a map is generated.
  176. //
  177. void TerrainRes::init()
  178. {
  179. deinit();
  180. //----- open firm material bitmap resource file -------//
  181. String str;
  182. str = DIR_RES;
  183. // str += "I_TERAIN.RES";
  184. str += "I_TERN";
  185. str += config.terrain_set;
  186. str += ".RES";
  187. res_bitmap.init_imported(str,1); // 1-read all into buffer
  188. //------- load database information --------//
  189. load_info();
  190. load_sub_info();
  191. str = DIR_RES;
  192. // str += "I_TERANM.RES";
  193. str += "I_TERA";
  194. str += config.terrain_set;
  195. str += ".RES";
  196. anm_bitmap.init_imported(str,1);
  197. load_anim_info();
  198. //-------- init map_tile_ptr_array --------//
  199. int i, terrainId;
  200. for( i=0 ; i<TOTAL_TERRAIN_TYPE ; i++ )
  201. {
  202. if( map_tile_name_array[i] )
  203. // ###### begin Gilbert 9/9 ########//
  204. // map_tile_ptr_array[i] = image_spict.get_ptr(map_tile_name_array[i]) + sizeof(short)*2;
  205. map_tile_ptr_array[i] = image_tpict.get_ptr(map_tile_name_array[i]) + sizeof(short)*2;
  206. // ###### end Gilbert 9/9 ########//
  207. }
  208. //-------- init terrain_type_array ---------//
  209. for( i=1 ; i<=TOTAL_TERRAIN_TYPE ; i++ )
  210. {
  211. terrainId = scan( i, ALL_MASK, i, ALL_MASK, i, ALL_MASK, i, ALL_MASK, 1 ); // scan for terrain of all four types. 1-take the first instance of the terrain bitmap that matches the given terrain types
  212. if(terrainId)
  213. {
  214. terrain_type_array[i-1].first_terrain_id = terrainId;
  215. terrain_type_array[i-1].last_terrain_id = terrainId + terrain_res[terrainId]->alternative_count_with_extra;
  216. terrain_type_array[i-1].min_height = terrain_type_min_height_array[i-1][0];
  217. }
  218. else
  219. {
  220. // BUGHERE: should not reach this point after all terrain type are complete
  221. terrain_type_array[i-1].first_terrain_id = 0;
  222. terrain_type_array[i-1].last_terrain_id = 0;
  223. terrain_type_array[i-1].min_height = terrain_type_min_height_array[i-1][0];
  224. }
  225. }
  226. init_flag=1;
  227. }
  228. //---------- End of function TerrainRes::init -----------//
  229. //---------- Begin of function TerrainRes::deinit -----------//
  230. void TerrainRes::deinit()
  231. {
  232. if( init_flag )
  233. {
  234. for( int i = terrain_count-1; i >= 0; --i)
  235. {
  236. if( terrain_info_array[i].anim_frames > 0 )
  237. mem_del(terrain_info_array[i].anim_bitmap_ptr);
  238. }
  239. mem_del(terrain_info_array);
  240. mem_del(ter_sub_array);
  241. mem_del(ter_sub_index);
  242. init_flag=0;
  243. }
  244. }
  245. //---------- End of function TerrainRes::deinit -----------//
  246. //------- Begin of function TerrainRes::load_info -------//
  247. //
  248. // Read in information of TERRAIN.DBF into memory array
  249. //
  250. void TerrainRes::load_info()
  251. {
  252. TerrainRec *terrainRec;
  253. TerrainInfo *terrainInfo = NULL;
  254. int i;
  255. long bitmapOffset;
  256. //---- read in terrain count and initialize terrain info array ----//
  257. // Database *dbTerrain = game_set.open_db(TERRAIN_DB);
  258. String terrainDbName;
  259. terrainDbName = DIR_RES;
  260. terrainDbName += "TERRAIN";
  261. terrainDbName += config.terrain_set;
  262. terrainDbName += ".RES";
  263. Database terrainDbObj(terrainDbName, 1);
  264. Database *dbTerrain = &terrainDbObj;
  265. terrain_count = (short) dbTerrain->rec_count();
  266. terrain_info_array = (TerrainInfo*) mem_add( sizeof(TerrainInfo)*terrain_count );
  267. memset( terrain_info_array, 0, sizeof(TerrainInfo) * terrain_count );
  268. file_name_array = (char *) mem_add(terrainRec->FILE_NAME_LEN*terrain_count);
  269. // ------ initial nw_type_index -------//
  270. for(i = 0; i < TOTAL_TERRAIN_TYPE; ++i)
  271. {
  272. nw_type_min[i] = 0;
  273. nw_type_max[i] = 0;
  274. }
  275. //---------- read in TERRAIN.DBF ---------//
  276. char firstNw=0, firstNe, firstSw, firstSe;
  277. char firstNwSub=0, firstNeSub, firstSwSub, firstSeSub, firstSpFlag;
  278. int firstId;
  279. for( i=0 ; i<terrain_count ; i++ )
  280. {
  281. terrainRec = (TerrainRec*) dbTerrain->read(i+1);
  282. terrainInfo = terrain_info_array+i;
  283. memcpy(&file_name_array[i*terrainRec->FILE_NAME_LEN], terrainRec->file_name,
  284. terrainRec->FILE_NAME_LEN);
  285. terrainInfo->nw_type = terrain_code(terrainRec->nw_type_code[0]);
  286. terrainInfo->nw_subtype = terrain_mask(terrainRec->nw_type_code[1]);
  287. terrainInfo->ne_type = terrain_code(terrainRec->ne_type_code[0]);
  288. terrainInfo->ne_subtype = terrain_mask(terrainRec->ne_type_code[1]);
  289. terrainInfo->sw_type = terrain_code(terrainRec->sw_type_code[0]);
  290. terrainInfo->sw_subtype = terrain_mask(terrainRec->sw_type_code[1]);
  291. terrainInfo->se_type = terrain_code(terrainRec->se_type_code[0]);
  292. terrainInfo->se_subtype = terrain_mask(terrainRec->se_type_code[1]);
  293. terrainInfo->average_type = terrain_code(terrainRec->represent_type);
  294. // ######## begin Gilbert 12/2 #######//
  295. switch(terrainRec->extra_flag)
  296. {
  297. case 0: // fall through
  298. case ' ': // fall through
  299. case 'N': // fall through
  300. case 'n':
  301. terrainInfo->extra_flag = 0;
  302. break;
  303. default:
  304. terrainInfo->extra_flag = 1;
  305. }
  306. terrainInfo->special_flag = terrainRec->special_flag==' ' ? 0 : terrainRec->special_flag;
  307. // ######## end Gilbert 12/2 #######//
  308. terrainInfo->secondary_type = terrain_code(terrainRec->secondary_type);
  309. terrainInfo->pattern_id = m.atoi(terrainRec->pattern_id, terrainRec->PATTERN_ID_LEN);
  310. //------ set alternative_count ---------//
  311. if( firstNw == terrainInfo->nw_type &&
  312. firstNwSub == terrainInfo->nw_subtype &&
  313. firstNe == terrainInfo->ne_type &&
  314. firstNeSub == terrainInfo->ne_subtype &&
  315. firstSw == terrainInfo->sw_type &&
  316. firstSwSub == terrainInfo->sw_subtype &&
  317. firstSe == terrainInfo->se_type &&
  318. firstSeSub == terrainInfo->se_subtype &&
  319. firstSpFlag == terrainInfo->special_flag )
  320. {
  321. terrain_info_array[firstId-1].alternative_count_with_extra++;
  322. if( !terrainInfo->extra_flag )
  323. terrain_info_array[firstId-1].alternative_count_without_extra++;
  324. // ----- record firstId - terrain_id -------//
  325. terrainInfo->alternative_count_with_extra = firstId -1 -i;
  326. terrainInfo->alternative_count_without_extra = firstId -1 -i;
  327. }
  328. else
  329. {
  330. // build index on nw_type
  331. if( firstNw != terrainInfo->nw_type)
  332. {
  333. // --------- mark end of previous nw_type group ---------//
  334. if(firstNw > 0)
  335. nw_type_max[firstNw-1] = i;
  336. // --------- mark start of new nw_type group -----------//
  337. nw_type_min[terrainInfo->nw_type-1] = i+1;
  338. }
  339. firstNw = terrainInfo->nw_type;
  340. firstNe = terrainInfo->ne_type;
  341. firstSw = terrainInfo->sw_type;
  342. firstSe = terrainInfo->se_type;
  343. firstNwSub = terrainInfo->nw_subtype;
  344. firstNeSub = terrainInfo->ne_subtype;
  345. firstSwSub = terrainInfo->sw_subtype;
  346. firstSeSub = terrainInfo->se_subtype;
  347. firstSpFlag = terrainInfo->special_flag;
  348. firstId = i+1;
  349. }
  350. //---- get the bitmap pointer of the terrain icon in res_icon ----//
  351. memcpy( &bitmapOffset, terrainRec->bitmap_ptr, sizeof(long) );
  352. terrainInfo->bitmap_ptr = res_bitmap.read_imported(bitmapOffset);
  353. terrainInfo->anim_frames = 0;
  354. terrainInfo->anim_bitmap_ptr = NULL;
  355. terrainInfo->flags = 0;
  356. if( terrainInfo->average_type != TERRAIN_OCEAN &&
  357. terrainInfo->secondary_type != TERRAIN_OCEAN)
  358. {
  359. terrainInfo->flags |= TERRAIN_FLAG_SNOW;
  360. }
  361. }
  362. // ------- mark end of last nw_type group -------//
  363. if(terrainInfo && terrainInfo->nw_type > 0)
  364. nw_type_max[terrainInfo->nw_type-1] = i;
  365. }
  366. //--------- End of function TerrainRes::load_info ---------//
  367. //---- Begin of function TerrainRes::scan ------//
  368. //
  369. // Scan for a terrain with the specific base terrain types.
  370. //
  371. // <int> nwType, neType, swType, seType - the base terrain types to look for
  372. // <int> nwSubType, neSubType, swSubType, seSubType - subTerrainMask
  373. // [int] firstInstance - whether return the first instance of the terrain instead of a random instance
  374. // (default: 0)
  375. // [int] includeExtra - whether include extra terrain type in the scanning
  376. // (default: 0)
  377. // [int] special - whether search special_flag
  378. // (default: 0)
  379. //
  380. // return : <int> >0 - the id. of the terrain
  381. // ==0 - no terrain of the specific base types found
  382. //
  383. int TerrainRes::scan(int nwType, int nwSubType, int neType, int neSubType,
  384. int swType, int swSubType, int seType, int seSubType,
  385. int firstInstance, int includeExtra, int special)
  386. {
  387. int terrainId = nw_type_min[nwType-1];
  388. int terrainIdMax = nw_type_max[nwType-1];
  389. if(terrainId <= 0 || terrainIdMax <= 0)
  390. return 0;
  391. TerrainInfo* terrainInfo = terrain_info_array+terrainId-1;
  392. // int firstTerrainId=0, instanceCount=0;
  393. for( ; terrainId<=terrainIdMax; terrainId++, terrainInfo++ )
  394. {
  395. if( terrainInfo->nw_type == nwType &&
  396. terrainInfo->nw_subtype & nwSubType &&
  397. terrainInfo->ne_type == neType &&
  398. terrainInfo->ne_subtype & neSubType &&
  399. terrainInfo->sw_type == swType &&
  400. terrainInfo->sw_subtype & swSubType &&
  401. terrainInfo->se_type == seType &&
  402. terrainInfo->se_subtype & seSubType &&
  403. terrainInfo->special_flag == special)
  404. {
  405. if( firstInstance )
  406. return terrainId;
  407. else
  408. {
  409. if( includeExtra )
  410. {
  411. err_when(terrainInfo->alternative_count_with_extra < 0);
  412. return terrainId + m.random(terrainInfo->alternative_count_with_extra+1);
  413. }
  414. else
  415. {
  416. err_when(terrainInfo->alternative_count_without_extra < 0);
  417. return terrainId + m.random(terrainInfo->alternative_count_without_extra+1);
  418. }
  419. }
  420. }
  421. else
  422. {
  423. //------ skip tiles of the same type and special_flag
  424. err_when(terrainInfo->alternative_count_with_extra < 0);
  425. terrainId += terrainInfo->alternative_count_with_extra;
  426. terrainInfo += terrainInfo->alternative_count_with_extra;
  427. }
  428. }
  429. return 0;
  430. }
  431. //------ End of function TerrainRes::scan ------//
  432. //---- Begin of function TerrainRes::scan ------//
  433. //
  434. // Scan for a terrain with the specific base terrain types.
  435. //
  436. // <int> primaryType - TerrainTypeCode
  437. // <int> secondaryType - TerrainTypeCode
  438. // <int> patternId - pattern_id in TerrainInfo
  439. // [int] firstInstance - whether return the first instance of the terrain instead of a random instance
  440. // (default: 0)
  441. // [int] includeExtra - whether include extra terrain type in the scanning
  442. // (default: 0)
  443. // [int] special - whether search special_flag
  444. // (default: 0)
  445. //
  446. // return : <int> >0 - the id. of the terrain
  447. // ==0 - no terrain of the specific base types found
  448. //
  449. int TerrainRes::scan(int primaryType, int secondaryType, int patternId,
  450. int firstInstance, int includeExtra, int special)
  451. {
  452. // if patternId is zero, that means it requires a pure terrain
  453. if( patternId == 0)
  454. secondaryType = primaryType;
  455. // ----------- search 1, search the lower type -------//
  456. int terrainId = nw_type_min[min(primaryType, secondaryType)-1];
  457. int terrainIdMax = nw_type_max[min(primaryType, secondaryType)-1];
  458. TerrainInfo* terrainInfo = terrain_info_array+terrainId-1;
  459. // int firstTerrainId=0, instanceCount=0;
  460. for( ; terrainId<=terrainIdMax; terrainId++, terrainInfo++ )
  461. {
  462. if( ( (terrainInfo->average_type == primaryType &&
  463. terrainInfo->secondary_type == secondaryType) ||
  464. (terrainInfo->average_type == secondaryType &&
  465. terrainInfo->secondary_type == primaryType)) &&
  466. terrainInfo->pattern_id == patternId &&
  467. terrainInfo->special_flag == special)
  468. {
  469. if( firstInstance )
  470. return terrainId;
  471. else
  472. {
  473. if( includeExtra )
  474. {
  475. err_when(terrainInfo->alternative_count_with_extra < 0);
  476. return terrainId + m.random(terrainInfo->alternative_count_with_extra+1);
  477. }
  478. else
  479. {
  480. err_when(terrainInfo->alternative_count_without_extra < 0);
  481. return terrainId + m.random(terrainInfo->alternative_count_without_extra+1);
  482. }
  483. }
  484. }
  485. else
  486. {
  487. //------ skip tiles of the same type and special_flag
  488. err_when(terrainInfo->alternative_count_with_extra < 0);
  489. terrainId += terrainInfo->alternative_count_with_extra;
  490. terrainInfo += terrainInfo->alternative_count_with_extra;
  491. }
  492. }
  493. // ----------- search 2, search the higher type ---------//
  494. if( primaryType != secondaryType)
  495. {
  496. terrainId = nw_type_min[max(primaryType, secondaryType)-1];
  497. terrainIdMax = nw_type_max[max(primaryType, secondaryType)-1];
  498. terrainInfo = terrain_info_array+terrainId-1;
  499. // int firstTerrainId=0, instanceCount=0;
  500. for( ; terrainId<=terrainIdMax; terrainId++, terrainInfo++ )
  501. {
  502. if( ( (terrainInfo->average_type == primaryType &&
  503. terrainInfo->secondary_type == secondaryType) ||
  504. (terrainInfo->average_type == secondaryType &&
  505. terrainInfo->secondary_type == primaryType)) &&
  506. terrainInfo->pattern_id == patternId &&
  507. terrainInfo->special_flag == special)
  508. {
  509. if( firstInstance )
  510. return terrainId;
  511. else
  512. {
  513. if( includeExtra )
  514. {
  515. err_when(terrainInfo->alternative_count_with_extra < 0);
  516. return terrainId + m.random(terrainInfo->alternative_count_with_extra+1);
  517. }
  518. else
  519. {
  520. err_when(terrainInfo->alternative_count_without_extra < 0);
  521. return terrainId + m.random(terrainInfo->alternative_count_without_extra+1);
  522. }
  523. }
  524. }
  525. else
  526. {
  527. //------ skip tiles of the same type and special_flag
  528. err_when(terrainInfo->alternative_count_with_extra < 0);
  529. terrainId += terrainInfo->alternative_count_with_extra;
  530. terrainInfo += terrainInfo->alternative_count_with_extra;
  531. }
  532. }
  533. }
  534. return 0;
  535. }
  536. //------ End of function TerrainRes::scan ------//
  537. //------------ Begin of function TerrainRes::search_pattern -----------//
  538. //
  539. // search first (northwest pattern id) to match a set of
  540. // substitution pattern, to be stored in resultArray
  541. // return the no. of matches
  542. //
  543. // <int> nwPatternId pattern_id of a terrain,
  544. // obtained by terrain_res[terrain_id]->pattern_id
  545. // <TerrainSubInfo *> resultArray an array to be filled with matches
  546. // <int> maxResult the no. of elements of the resultArray
  547. // <int> return no. of matches
  548. //
  549. int TerrainRes::search_pattern(int nwPatternId, TerrainSubInfo **resultArray,
  550. int maxResult)
  551. {
  552. err_when(!init_flag);
  553. if(!resultArray || !maxResult)
  554. return 0;
  555. int occur = 0;
  556. for( int i = 0; i < ter_sub_index_count; ++i)
  557. {
  558. if( ter_sub_index[i] && nwPatternId == ter_sub_index[i]->old_pattern_id)
  559. {
  560. resultArray[occur++] = ter_sub_index[i];
  561. if( occur >= maxResult)
  562. break;
  563. }
  564. }
  565. return occur;
  566. }
  567. //------------ End of function TerrainRes::search_pattern -----------//
  568. //------------ Begin of function TerrainRes::load_sub_info -----------//
  569. void TerrainRes::load_sub_info()
  570. {
  571. TerrainSubRec *terrainSubRec;
  572. TerrainSubInfo *terrainSubInfo = NULL;
  573. int i;
  574. //---- read in terrain count and initialize terrain info array ----//
  575. Database terSubDbObj(DIR_RES"TERSUB.RES", 1);
  576. //Database *dbTerrain = game_set.open_db(TERRAIN_SUB_DB);
  577. Database *dbTerrain = &terSubDbObj;
  578. ter_sub_rec_count = (short) dbTerrain->rec_count();
  579. ter_sub_array = (TerrainSubInfo*) mem_add( sizeof(TerrainSubInfo)*ter_sub_rec_count );
  580. memset( ter_sub_array, 0, sizeof(TerrainSubInfo) * ter_sub_rec_count );
  581. //---------- read in TERSUB.DBF ---------//
  582. short maxSubNo = 0;
  583. for( i=0 ; i < ter_sub_rec_count ; i++ )
  584. {
  585. terrainSubRec = (TerrainSubRec*) dbTerrain->read(i+1);
  586. terrainSubInfo = ter_sub_array+i;
  587. terrainSubInfo->sub_no = m.atoi(terrainSubRec->sub_no, terrainSubRec->SUB_NO_LEN);
  588. terrainSubInfo->step_id = m.atoi(terrainSubRec->step_id, terrainSubRec->STEP_ID_LEN);
  589. terrainSubInfo->old_pattern_id = m.atoi(terrainSubRec->old_pattern_id, terrainSubRec->PATTERN_ID_LEN);
  590. terrainSubInfo->new_pattern_id = m.atoi(terrainSubRec->new_pattern_id, terrainSubRec->PATTERN_ID_LEN);
  591. // sec_adj is useful when a pure type is changing to boundary type.
  592. // eg. a GG square can be changed to SG or GS sqare
  593. terrainSubInfo->sec_adj = m.atoi(terrainSubRec->sec_adj, terrainSubRec->SEC_ADJ_LEN);
  594. switch(terrainSubRec->post_move[0])
  595. {
  596. case 'N':
  597. switch(terrainSubRec->post_move[1])
  598. {
  599. case 'E':
  600. terrainSubInfo->post_move = 2;
  601. break;
  602. case 'W':
  603. terrainSubInfo->post_move = 8;
  604. break;
  605. default:
  606. terrainSubInfo->post_move = 1;
  607. }
  608. break;
  609. case 'S':
  610. switch(terrainSubRec->post_move[1])
  611. {
  612. case 'E':
  613. terrainSubInfo->post_move = 4;
  614. break;
  615. case 'W':
  616. terrainSubInfo->post_move = 6;
  617. break;
  618. default:
  619. terrainSubInfo->post_move = 5;
  620. }
  621. break;
  622. case 'E':
  623. terrainSubInfo->post_move = 3;
  624. break;
  625. case 'W':
  626. terrainSubInfo->post_move = 7;
  627. break;
  628. case 'X':
  629. terrainSubInfo->post_move = 0;
  630. break;
  631. default:
  632. err_here();
  633. }
  634. terrainSubInfo->next_step = NULL;
  635. if( terrainSubInfo->sub_no > maxSubNo )
  636. maxSubNo = terrainSubInfo->sub_no;
  637. }
  638. // ------- build ter_sub_index ------//
  639. ter_sub_index_count = maxSubNo;
  640. ter_sub_index = (TerrainSubInfo **) mem_add(sizeof(TerrainSubInfo *) * ter_sub_index_count);
  641. memset(ter_sub_index, 0, sizeof(TerrainSubInfo *) * ter_sub_index_count);
  642. TerrainSubInfo *lastTerrainSubInfo;
  643. for( i=0 ; i < ter_sub_rec_count ; i++ )
  644. {
  645. terrainSubInfo = ter_sub_array+i;
  646. if( terrainSubInfo->step_id == 1)
  647. {
  648. err_when(ter_sub_index[terrainSubInfo->sub_no-1] != NULL);
  649. ter_sub_index[terrainSubInfo->sub_no-1] = terrainSubInfo;
  650. }
  651. else
  652. {
  653. // link from the next_step pointer of previous step
  654. // search the previous record first
  655. if( lastTerrainSubInfo && lastTerrainSubInfo->sub_no == terrainSubInfo->sub_no
  656. && lastTerrainSubInfo->step_id == terrainSubInfo->step_id -1)
  657. {
  658. lastTerrainSubInfo->next_step = terrainSubInfo;
  659. }
  660. else
  661. {
  662. // search from the array
  663. int j;
  664. for(j = 0; j < ter_sub_rec_count; j++)
  665. {
  666. if(ter_sub_array[j].sub_no == terrainSubInfo->sub_no &&
  667. ter_sub_array[j].step_id == terrainSubInfo->step_id-1)
  668. {
  669. ter_sub_array[j].next_step = terrainSubInfo;
  670. break;
  671. }
  672. }
  673. err_when(j >= ter_sub_rec_count); // not found
  674. }
  675. }
  676. lastTerrainSubInfo = terrainSubInfo;
  677. }
  678. }
  679. //------------ End of function TerrainRes::load_sub_info -----------//
  680. //------------ Begin of function TerrainRes::load_anim_info -------//
  681. void TerrainRes::load_anim_info()
  682. {
  683. TerrainAnimRec terrainAnimRec, lastAnimRec;
  684. int i;
  685. long bitmapOffset;
  686. String terAnimDbName(DIR_RES);
  687. terAnimDbName += "TERANM";
  688. terAnimDbName += config.terrain_set;
  689. terAnimDbName += ".RES";
  690. Database terAnimDbObj(terAnimDbName, 1);
  691. // Database *dbTerAnim = game_set.open_db(TERRAIN_ANIM_DB);
  692. Database *dbTerAnim = &terAnimDbObj;
  693. int count = dbTerAnim->rec_count();
  694. int animFrameCount = 0;
  695. char *animFrameBitmap[MAX_TERRAIN_ANIM_FRAME];
  696. memset(lastAnimRec.filename, ' ', lastAnimRec.FILE_NAME_LEN);
  697. //---------- read in TERANM.DBF -------//
  698. // int j,k,l;
  699. int l;
  700. for( i = 0; i < count; i++)
  701. {
  702. char* bitmapPtr;
  703. terrainAnimRec = *(TerrainAnimRec *)(dbTerAnim->read(i+1));
  704. memcpy( &bitmapOffset, terrainAnimRec.bitmap_ptr, sizeof(long) );
  705. bitmapPtr = anm_bitmap.read_imported(bitmapOffset);
  706. if( memcmp(terrainAnimRec.base_file, lastAnimRec.base_file, terrainAnimRec.FILE_NAME_LEN))
  707. {
  708. // string not equal
  709. if( lastAnimRec.filename[0] != ' ' && animFrameCount > 0)
  710. {
  711. // replace terrainInfo->anim_frames and anim_frame_ptr
  712. // where the bitmap filename are the same
  713. int replaceCount = 0;
  714. for(l = 0; l < terrain_count; ++l)
  715. {
  716. if( memcmp(&file_name_array[terrainAnimRec.FILE_NAME_LEN *l],
  717. lastAnimRec.base_file, terrainAnimRec.FILE_NAME_LEN) == 0)
  718. {
  719. TerrainInfo *terrainInfo = terrain_info_array+l;
  720. err_when(terrainInfo->anim_frames > 0);
  721. terrainInfo->anim_frames = animFrameCount;
  722. terrainInfo->anim_bitmap_ptr = (char **) mem_add(
  723. sizeof(char *)*animFrameCount);
  724. memcpy(terrainInfo->anim_bitmap_ptr, animFrameBitmap,
  725. sizeof(char *)*animFrameCount);
  726. replaceCount++;
  727. }
  728. }
  729. /*
  730. for(int special = 0; special <= 1; ++special)
  731. {
  732. j = scan( terrain_code(lastAnimRec.average_type),
  733. terrain_code(lastAnimRec.secondary_type),
  734. m.atoi(lastAnimRec.pattern_id, lastAnimRec.PATTERN_ID_LEN), 1,0,special);
  735. if( j > 0)
  736. {
  737. k = terrain_info_array[j-1].alternative_count_with_extra;
  738. for(l = j; l <= j+k; ++l)
  739. {
  740. if( memcmp(&file_name_array[terrainAnimRec.FILE_NAME_LEN *(l-1)],
  741. lastAnimRec.base_file, terrainAnimRec.FILE_NAME_LEN) == 0)
  742. {
  743. TerrainInfo *terrainInfo = terrain_info_array+j-1;
  744. err_when(terrainInfo->anim_frames > 0);
  745. terrainInfo->anim_frames = animFrameCount;
  746. terrainInfo->anim_bitmap_ptr = (char **) mem_add(
  747. sizeof(char *)*animFrameCount);
  748. memcpy(terrainInfo->anim_bitmap_ptr, animFrameBitmap,
  749. sizeof(char *)*animFrameCount);
  750. replaceCount++;
  751. }
  752. }
  753. }
  754. }
  755. */
  756. err_when( replaceCount == 0);
  757. }
  758. lastAnimRec = terrainAnimRec;
  759. animFrameCount = 0;
  760. memset(animFrameBitmap, 0, sizeof(animFrameBitmap));
  761. }
  762. animFrameCount++;
  763. animFrameBitmap[m.atoi(terrainAnimRec.frame_no, terrainAnimRec.FRAME_NO_LEN)-1]
  764. = bitmapPtr;
  765. }
  766. if( lastAnimRec.filename[0] != ' ' && animFrameCount > 0)
  767. {
  768. // replace terrainInfo->anim_frames and anim_frame_ptr
  769. // where the bitmap filename are the same
  770. int replaceCount = 0;
  771. for(l = 0; l < terrain_count; ++l)
  772. {
  773. if( memcmp(&file_name_array[terrainAnimRec.FILE_NAME_LEN *(l-1)],
  774. lastAnimRec.base_file, terrainAnimRec.FILE_NAME_LEN) == 0)
  775. {
  776. TerrainInfo *terrainInfo = terrain_info_array+l-1;
  777. err_when(terrainInfo->anim_frames > 0);
  778. terrainInfo->anim_frames = animFrameCount;
  779. terrainInfo->anim_bitmap_ptr = (char **) mem_add(
  780. sizeof(char *)*animFrameCount);
  781. memcpy(terrainInfo->anim_bitmap_ptr, animFrameBitmap,
  782. sizeof(char *)*animFrameCount);
  783. replaceCount++;
  784. }
  785. }
  786. /*
  787. for(int special = 0; special <= 1; ++special)
  788. {
  789. j = scan( terrain_code(lastAnimRec.average_type),
  790. terrain_code(lastAnimRec.secondary_type),
  791. m.atoi(lastAnimRec.pattern_id, lastAnimRec.PATTERN_ID_LEN), 1,0,special);
  792. if( j > 0)
  793. {
  794. k = terrain_info_array[j-1].alternative_count_with_extra;
  795. for(l = j; l <= j+k; ++l)
  796. {
  797. if( memcmp(&file_name_array[terrainAnimRec.FILE_NAME_LEN *(l-1)],
  798. lastAnimRec.base_file, terrainAnimRec.FILE_NAME_LEN) == 0)
  799. {
  800. TerrainInfo *terrainInfo = terrain_info_array+j-1;
  801. err_when(terrainInfo->anim_frames > 0);
  802. terrainInfo->anim_frames = animFrameCount;
  803. terrainInfo->anim_bitmap_ptr = (char **) mem_add(
  804. sizeof(char *)*animFrameCount);
  805. memcpy(terrainInfo->anim_bitmap_ptr, animFrameBitmap,
  806. sizeof(char *)*animFrameCount);
  807. replaceCount++;
  808. }
  809. }
  810. }
  811. }
  812. */
  813. err_when( replaceCount == 0);
  814. }
  815. mem_del(file_name_array);
  816. file_name_array = NULL;
  817. }
  818. //------------ End of function TerrainRes::load_anim_info -------//
  819. //----- Begin of function TerrainRes::get_tera_type_id ------//
  820. int TerrainRes::get_tera_type_id(char* teraTypeCode)
  821. {
  822. return terrain_code(teraTypeCode[0]);
  823. }
  824. //----- End of function TerrainRes::get_tera_type_id ------//
  825. //----- Begin of function TerrainRes::get_map_tile ------//
  826. char* TerrainRes::get_map_tile(int terrainId)
  827. {
  828. return map_tile_ptr_array[terrain_res[terrainId]->average_type-1];
  829. }
  830. //----- End of function TerrainRes::get_map_tile ------//
  831. #ifdef DEBUG
  832. //---------- Begin of function TerrainRes::operator[] -----------//
  833. TerrainInfo* TerrainRes::operator[](int terrainId)
  834. {
  835. err_if( terrainId<1 || terrainId>terrain_count )
  836. err_now( "TerrainRes::operator[]" );
  837. return terrain_info_array+terrainId-1;
  838. }
  839. //------------ End of function TerrainRes::operator[] -----------//
  840. #endif