OW_PLANT.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  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 : OW_PLANT.CPP
  21. // Description: growth of plant
  22. // Ownership : Gilbert
  23. #include <OMATRIX.h>
  24. #include <OWORLD.h>
  25. #include <OWORLDMT.h>
  26. #include <OWEATHER.h>
  27. #include <OPLANT.h>
  28. #include <OTERRAIN.h>
  29. #include <ALL.h>
  30. #include <math.h>
  31. //------------ Define constant ---------------//
  32. static short opt_temp[3] = { 32, 25, 28 }; // tropical,temperate and both
  33. #define PLANT_ARRAY_SIZE 8
  34. //------------ Define inline function -------//
  35. inline int rand_inner_x()
  36. {
  37. // can use m.random(ZOOM_LOC_WIDTH) instead
  38. // return (ZOOM_LOC_WIDTH *3)/8 + m.random(ZOOM_LOC_WIDTH/4);
  39. return ZOOM_LOC_WIDTH / 4 + m.random(ZOOM_LOC_WIDTH/2);
  40. }
  41. inline int rand_inner_y()
  42. {
  43. return (ZOOM_LOC_HEIGHT * 3) / 8 + m.random(ZOOM_LOC_HEIGHT/4);
  44. }
  45. //----------- Begin of function World::plant_ops -----------//
  46. //
  47. void World::plant_ops()
  48. {
  49. plant_grow(40);
  50. plant_reprod(10);
  51. plant_death();
  52. plant_spread(50);
  53. }
  54. //----------- End of function World::plant_ops -----------//
  55. //------------ begin of function World::plant_grow ------------//
  56. //
  57. // pGrow = prabability of grow, range from 0 to 100
  58. // scanDensity = scan one square per scanDensity^2
  59. //
  60. void World::plant_grow(int pGrow, int scanDensity)
  61. {
  62. // scan part of the map for plant
  63. int yBase = m.random(scanDensity);
  64. int xBase = m.random(scanDensity);
  65. for( int y = yBase; y < max_y_loc; y += scanDensity)
  66. for( int x = xBase; x < max_x_loc; x += scanDensity)
  67. {
  68. Location *l = get_loc(x,y);
  69. short bitmapId, basePlantId;
  70. // is a plant and is not at maximum grade
  71. if( l->is_plant() && m.random(100) < pGrow &&
  72. (basePlantId = plant_res.plant_recno(bitmapId = l->plant_id())) != 0 &&
  73. bitmapId - plant_res[basePlantId]->first_bitmap < plant_res[basePlantId]->bitmap_count -1)
  74. {
  75. // increase the grade of plant
  76. l->grow_plant();
  77. }
  78. }
  79. }
  80. //------------ end of function World::plant_grow ------------//
  81. //------------ begin of function World::plant_reprod --------//
  82. //
  83. // pReprod = prabability of reproduction, range from 0 to 20
  84. // scanDensity = scan one square per scanDensity^2
  85. //
  86. void World::plant_reprod(int pReprod, int scanDensity)
  87. {
  88. if( plant_count > plant_limit )
  89. return;
  90. if( 5 * plant_count < 4 * plant_limit )
  91. pReprod++; // higher probability to grow
  92. // determine the rainful, temperature and sunlight
  93. short t = weather.temp_c();
  94. // scan the map for plant
  95. int yBase = m.random(scanDensity);
  96. int xBase = m.random(scanDensity);
  97. for( int y = yBase; y < max_y_loc; y += scanDensity)
  98. {
  99. for( int x = xBase; x < max_x_loc; x += scanDensity)
  100. {
  101. Location *l = get_loc(x,y);
  102. short bitmapId, basePlantId, plantGrade;
  103. // is a plant and grade > 3
  104. if( l->is_plant() && (basePlantId = plant_res.plant_recno(
  105. bitmapId = l->plant_id())) != 0 &&
  106. ((plantGrade = bitmapId - plant_res[basePlantId]->first_bitmap) >= 3 ||
  107. plantGrade == plant_res[basePlantId]->bitmap_count-1))
  108. {
  109. // find the optimal temperature for the plant
  110. short oTemp = opt_temp[plant_res[basePlantId]->climate_zone -1];
  111. short tempEffect = 5 - abs( oTemp - t);
  112. tempEffect = tempEffect > 0 ? tempEffect : 0;
  113. if( m.random(100) < tempEffect * pReprod)
  114. {
  115. // produce the same plant but grade 1,
  116. char trial = 2;
  117. Location *newl;
  118. while( trial --)
  119. {
  120. newl = NULL;
  121. switch(m.random(8))
  122. {
  123. case 0: // north square
  124. if( y > 0)
  125. newl = get_loc(x,y-1);
  126. break;
  127. case 1: // east square
  128. if( x < max_x_loc-1 )
  129. newl = get_loc(x+1,y);
  130. break;
  131. case 2: // south square
  132. if( y < max_y_loc-1 )
  133. newl = get_loc(x,y+1);
  134. break;
  135. case 3: // west square
  136. if( x > 0)
  137. newl = get_loc(x-1,y);
  138. break;
  139. case 4: // north west square
  140. if( y > 0 && x > 0)
  141. newl = get_loc(x-1,y-1);
  142. break;
  143. case 5: // north east square
  144. if( y > 0 && x < max_x_loc-1 )
  145. newl = get_loc(x+1,y-1);
  146. break;
  147. case 6: // south east square
  148. if( y < max_y_loc-1 && x < max_x_loc-1)
  149. newl = get_loc(x+1,y+1);
  150. break;
  151. case 7: // south west square
  152. if( y < max_y_loc-1 && x > 0)
  153. newl = get_loc(x-1,y+1);
  154. break;
  155. }
  156. char teraType;
  157. // #### begin Gilbert 6/3 #######//
  158. if( newl && newl->can_add_plant() &&
  159. (plant_res[basePlantId]->tera_type[0] ==
  160. (teraType = terrain_res[newl->terrain_id]->average_type) ||
  161. plant_res[basePlantId]->tera_type[1] == teraType ||
  162. plant_res[basePlantId]->tera_type[2] == teraType) )
  163. // #### end Gilbert 6/3 #######//
  164. {
  165. newl->set_plant(plant_res[basePlantId]->first_bitmap
  166. , rand_inner_x(), rand_inner_y() );
  167. // ------- set flammability ---------
  168. newl->set_fire_src(100);
  169. plant_count++;
  170. //### begin alex 24/6 ###//
  171. //newl->set_power_off();
  172. //newl->power_nation_recno = 0;
  173. //set_surr_power_off(x, y);
  174. //#### end alex 24/6 ####//
  175. break;
  176. }
  177. }
  178. }
  179. }
  180. }
  181. }
  182. }
  183. //------------ end of function World::plant_reprod --------//
  184. //------------ begin of function World::plant_spread ------------//
  185. //
  186. // pSpread = probability of spreading, range from 0 to 1000
  187. //
  188. void World::plant_spread(int pSpread)
  189. {
  190. if( plant_count > plant_limit)
  191. return;
  192. if( 5 * plant_count < 4 * plant_limit )
  193. pSpread += pSpread;
  194. if(m.random(1000) >= pSpread )
  195. return;
  196. // ------- determine temperature
  197. short t = weather.temp_c();
  198. // ------- randomly select a place to seed plant
  199. int y = 1+m.random(max_y_loc-2);
  200. int x = 1+m.random(max_x_loc-2);
  201. Location *l = get_loc(x,y);
  202. int build_flag = TRUE;
  203. char teraType = terrain_res[l->terrain_id]->average_type;
  204. // ------- all square around are the same terrain type and empty
  205. for( int y1 = y-1; y1 <= y+1; ++y1)
  206. for( int x1 = x-1; x1 <= x+1; ++x1)
  207. {
  208. l = get_loc(x1,y1);
  209. // #### begin Gilbert 6/3 #######//
  210. if( !l->can_add_plant() || terrain_res[l->terrain_id]->average_type != teraType)
  211. build_flag = FALSE;
  212. // #### end Gilbert 6/3 #######//
  213. }
  214. if( build_flag)
  215. {
  216. char climateZone = 0;
  217. short plantBitmap = 0;
  218. for( int retry=0; !climateZone && retry < 5; ++retry)
  219. {
  220. for( char j=0; j < 3; ++j)
  221. {
  222. if( m.random(5) > abs(t- opt_temp[j]) )
  223. {
  224. climateZone = j+1;
  225. plantBitmap = plant_res.scan( climateZone, teraType, 0);
  226. if( plantBitmap)
  227. {
  228. l = get_loc(x,y);
  229. l->set_plant( plantBitmap, rand_inner_x(), rand_inner_y() );
  230. l->set_fire_src(100);
  231. plant_count++;
  232. //### begin alex 24/6 ###//
  233. //l->set_power_off();
  234. //l->power_nation_recno = 0;
  235. //set_surr_power_off(x, y);
  236. //#### end alex 24/6 ####//
  237. }
  238. break;
  239. }
  240. }
  241. }
  242. }
  243. }
  244. //------------ end of function World::plant_spread ------------//
  245. //------------ begin of function World::plant_death ---------//
  246. //
  247. // a plant may death, if it is surrounded by many trees
  248. //
  249. void World::plant_death(int scanDensity)
  250. {
  251. int yBase = m.random(scanDensity);
  252. int xBase = m.random(scanDensity);
  253. for( int y = yBase; y < max_y_loc; y += scanDensity)
  254. {
  255. for( int x = xBase; x < max_x_loc; x += scanDensity)
  256. {
  257. Location *locPtr = get_loc(x,y);
  258. if( locPtr->is_plant() )
  259. {
  260. char neighbour =0;
  261. char totalSpace =0;
  262. // west
  263. if( x > 0)
  264. {
  265. totalSpace++;
  266. if( (locPtr-1)->is_plant() )
  267. neighbour++;
  268. }
  269. // east
  270. if( x < max_x_loc-1)
  271. {
  272. totalSpace++;
  273. if( (locPtr+1)->is_plant() )
  274. neighbour++;
  275. }
  276. if( y > 0)
  277. {
  278. locPtr = get_loc(x,y-1);
  279. // north square
  280. totalSpace++;
  281. if( locPtr->is_plant() )
  282. neighbour++;
  283. // north west
  284. if( x > 0)
  285. {
  286. totalSpace++;
  287. if( (locPtr-1)->is_plant() )
  288. neighbour++;
  289. }
  290. // north east
  291. if( x < max_x_loc-1)
  292. {
  293. totalSpace++;
  294. if( (locPtr+1)->is_plant() )
  295. neighbour++;
  296. }
  297. }
  298. if( y < max_x_loc-1)
  299. {
  300. locPtr = get_loc(x,y+1);
  301. // south square
  302. totalSpace++;
  303. if( locPtr->is_plant() )
  304. neighbour++;
  305. // south west
  306. if( x > 0)
  307. {
  308. totalSpace++;
  309. if( (locPtr-1)->is_plant() )
  310. neighbour++;
  311. }
  312. // south east
  313. if( x < max_x_loc-1)
  314. {
  315. totalSpace++;
  316. if( (locPtr+1)->is_plant() )
  317. neighbour++;
  318. }
  319. }
  320. // may remove plant if more than two third of the space is occupied
  321. if( m.random(totalSpace) + 2*totalSpace/3 <= neighbour )
  322. {
  323. locPtr = get_loc(x,y);
  324. get_loc(x,y)->remove_plant();
  325. if( locPtr->fire_src() > 50)
  326. locPtr->set_fire_src(50);
  327. plant_count--;
  328. //### begin alex 24/6 ###//
  329. //newl->set_power_off();
  330. //newl->power_nation_recno = 0;
  331. //set_surr_power_off(x, y);
  332. //#### end alex 24/6 ####//
  333. }
  334. }
  335. }
  336. }
  337. }
  338. //------------ end of function World::plant_death ---------//
  339. //------------ begin of function World::plant_init ------------//
  340. // randomly select a place and call plant_spray to enlarge the
  341. // forest
  342. //
  343. void World::plant_init()
  344. {
  345. plant_count = 0;
  346. int trial;
  347. for(trial = 50; trial > 0; --trial)
  348. {
  349. // ------- randomly select a place to seed plant
  350. int y = 1+m.random(max_y_loc-2);
  351. int x = 1+m.random(max_x_loc-2);
  352. Location *l = get_loc(x,y);
  353. int build_flag = TRUE;
  354. char teraType = terrain_res[l->terrain_id]->average_type;
  355. // ------- all square around are the same terrain type and empty
  356. for( int y1 = y-1; y1 <= y+1; ++y1)
  357. for( int x1 = x-1; x1 <= x+1; ++x1)
  358. {
  359. l = get_loc(x1,y1);
  360. // #### begin Gilbert 6/3 #######//
  361. if( !l->can_add_plant() || terrain_res[l->terrain_id]->average_type != teraType)
  362. build_flag = FALSE;
  363. // #### end Gilbert 6/3 #######//
  364. }
  365. if( build_flag )
  366. {
  367. short plantBitmap = plant_res.scan( 0, teraType, 0);
  368. short plantArray[PLANT_ARRAY_SIZE];
  369. for( int i = 0; i < PLANT_ARRAY_SIZE; ++i)
  370. {
  371. plantArray[i] = plant_res.plant_recno(plant_res.scan(0, teraType, 0));
  372. }
  373. if( plantArray[0] )
  374. {
  375. plant_spray(plantArray, 6+m.random(4), x, y);
  376. }
  377. }
  378. }
  379. plant_limit = plant_count * 3 / 2;
  380. // ------- kill some plant ----------//
  381. for(trial = 8; trial > 0; --trial)
  382. {
  383. plant_death(2);
  384. }
  385. }
  386. //------------ end of function World::plant_init ------------//
  387. //------------ begin of function World::plant_spray ------------//
  388. void World::plant_spray(short *plantArray, char strength, short x, short y)
  389. {
  390. if( strength <= 0)
  391. return;
  392. //---------- if the space is empty put a plant on it ----------//
  393. Location *newl = get_loc(x, y);
  394. short basePlantId = plantArray[m.random(PLANT_ARRAY_SIZE)];
  395. short plantSize = m.random(plant_res[basePlantId]->bitmap_count);
  396. if( plantSize > strength)
  397. plantSize = strength;
  398. char teraType;
  399. if( newl && newl->can_add_plant() &&
  400. (plant_res[basePlantId]->tera_type[0] ==
  401. (teraType = terrain_res[newl->terrain_id]->average_type) ||
  402. plant_res[basePlantId]->tera_type[1] == teraType ||
  403. plant_res[basePlantId]->tera_type[2] == teraType) )
  404. {
  405. newl->set_plant(plant_res[basePlantId]->first_bitmap +plantSize
  406. , rand_inner_x(), rand_inner_y() );
  407. newl->set_fire_src(100);
  408. plant_count++;
  409. //### begin alex 24/6 ###//
  410. //newl->set_power_off();
  411. //newl->power_nation_recno = 0;
  412. //set_surr_power_off(x, y);
  413. //#### end alex 24/6 ####//
  414. }
  415. else if( newl && newl->is_plant() &&
  416. // 1. same type, large override small
  417. // newl->plant_id() >= plant_res[basePlantId]->first_bitmap &&
  418. // newl->plant_id() < plant_res[basePlantId]->first_bitmap + plantSize)
  419. // 2. same type, small override large
  420. // newl->plant_id() > plant_res[basePlantId]->first_bitmap + plantSize &&
  421. // newl->plant_id() < plant_res[basePlantId]->first_bitmap + plant_res[basePlantId]->bitmap_count)
  422. // 3. all types, small override large
  423. (newl->plant_id() - plant_res[plant_res.plant_recno(newl->plant_id())]->first_bitmap) >
  424. plantSize )
  425. {
  426. // same kind of plant, but smaller, override by a smaller one
  427. newl->remove_plant();
  428. newl->set_plant(plant_res[basePlantId]->first_bitmap +plantSize
  429. , rand_inner_x(), rand_inner_y() );
  430. newl->set_fire_src(100);
  431. //### begin alex 24/6 ###//
  432. //newl->set_power_off();
  433. //newl->power_nation_recno = 0;
  434. //set_surr_power_off(x, y);
  435. //#### end alex 24/6 ####//
  436. }
  437. else
  438. {
  439. plantSize = -1;
  440. }
  441. if( plantSize >= 0 && strength)
  442. {
  443. char trial = 3;
  444. while( trial--)
  445. {
  446. switch(m.random(8))
  447. {
  448. case 0: // north square
  449. if( y > 0)
  450. plant_spray(plantArray, strength-1, x,y-1);
  451. break;
  452. case 1: // east square
  453. if( x < max_x_loc-1 )
  454. plant_spray(plantArray, strength-1, x+1,y);
  455. break;
  456. case 2: // south square
  457. if( y < max_y_loc-1 )
  458. plant_spray(plantArray, strength-1, x,y+1);
  459. break;
  460. case 3: // west square
  461. if( x > 0)
  462. plant_spray(plantArray, strength-1, x-1,y);
  463. break;
  464. case 4: // north west square
  465. if( y > 0 && x > 0)
  466. plant_spray(plantArray, strength-1, x-1,y-1);
  467. break;
  468. case 5: // north east square
  469. if( y > 0 && x < max_x_loc-1 )
  470. plant_spray(plantArray, strength-1, x+1,y-1);
  471. break;
  472. case 6: // south east square
  473. if( y < max_y_loc-1 && x < max_x_loc-1)
  474. plant_spray(plantArray, strength-1, x+1,y+1);
  475. break;
  476. case 7: // south west square
  477. if( y < max_y_loc-1 && x > 0)
  478. plant_spray(plantArray, strength-1, x-1,y+1);
  479. break;
  480. }
  481. }
  482. }
  483. }
  484. //------------ end of function World::plant_spray ------------//