OAI_SEEK.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  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 : OAI_SEEK.CPP
  21. //Description: AI - action progressing functions
  22. #include <ALL.h>
  23. #include <OUNIT.h>
  24. #include <OF_MINE.h>
  25. #include <OF_FACT.h>
  26. #include <OF_HARB.h>
  27. #include <OTOWN.h>
  28. #include <OSITE.h>
  29. #include <ONATION.h>
  30. //--------- Begin of function Nation::seek_mine --------//
  31. //
  32. // <short&> xLoc, yLoc - reference vars for returning the building
  33. // location.
  34. // <short&> refXLoc, refYLoc - reference vars for returning the exact
  35. // location of the raw material.
  36. //
  37. // return: <int> >0 the raw id. of the site.
  38. // ==0 no suitable site found.
  39. //
  40. int Nation::seek_mine(short& xLoc, short& yLoc, short& refXLoc, short& refYLoc)
  41. {
  42. err_when( site_array.untapped_raw_count < 0 );
  43. if( site_array.untapped_raw_count==0 )
  44. return 0;
  45. int raw_kind_mined[MAX_RAW], i;
  46. Firm *firmPtr;
  47. FirmMine *minePtr;
  48. //-----------------------------------------------------------------//
  49. // count each kind of raw material that is being mined
  50. //-----------------------------------------------------------------//
  51. memset(raw_kind_mined, 0, sizeof(int)*MAX_RAW);
  52. for(i=0; i<ai_mine_count; i++)
  53. {
  54. firmPtr = firm_array[ai_mine_array[i]];
  55. minePtr = firmPtr->cast_to_FirmMine();
  56. if( minePtr->raw_id>=1 && minePtr->raw_id<=MAX_RAW )
  57. raw_kind_mined[minePtr->raw_id-1]++;
  58. }
  59. //-------------------- define parameters ----------------------//
  60. FirmInfo *firmInfo = firm_res[FIRM_MINE];
  61. Location *locPtr, *siteLocPtr;
  62. Site *sitePtr;
  63. Town *townPtr;
  64. int nearSite[MAX_RAW], minDist[MAX_RAW], townWithMine[MAX_RAW];
  65. short buildXLoc[MAX_RAW], buildYLoc[MAX_RAW];
  66. short dist;
  67. int canBuild, connected, allHave;
  68. int j, k, siteId;
  69. memset(townWithMine, 0, sizeof(int)*MAX_RAW);
  70. memset(nearSite, 0, sizeof(int)*MAX_RAW);
  71. memset(buildXLoc, 0, sizeof(short)*MAX_RAW);
  72. memset(buildYLoc, 0, sizeof(short)*MAX_RAW);
  73. for(i=0; i<MAX_RAW; i++)
  74. minDist[i] = 0x7FFFFF;
  75. //--------------------------------------------//
  76. // scan for the site array
  77. //--------------------------------------------//
  78. for(i=site_array.size(); i>0; i--)
  79. {
  80. if(site_array.is_deleted(i))
  81. continue;
  82. sitePtr = site_array[i];
  83. if( sitePtr->site_type != SITE_RAW )
  84. continue;
  85. siteLocPtr = world.get_loc(sitePtr->map_x_loc, sitePtr->map_y_loc);
  86. if(!siteLocPtr->can_build_firm())
  87. continue;
  88. siteId = sitePtr->object_id - 1;
  89. err_when(siteId<0 || siteId>MAX_RAW);
  90. if(townWithMine[siteId])
  91. continue; // a site connected to town is found before
  92. //--------------------------------------------//
  93. // continue if action to this site already exist
  94. //--------------------------------------------//
  95. if(is_action_exist(-1, -1, sitePtr->map_x_loc, sitePtr->map_y_loc, ACTION_AI_BUILD_FIRM, FIRM_MINE))
  96. continue;
  97. for(j=0; j<ai_town_count; j++)
  98. {
  99. townPtr = town_array[ai_town_array[j]];
  100. locPtr = world.get_loc(townPtr->loc_x1, townPtr->loc_y1);
  101. //-********* codes to move to other territory ***********-//
  102. if(siteLocPtr->region_id!=locPtr->region_id)
  103. continue; // not on the same territory
  104. dist = m.points_distance(sitePtr->map_x_loc, sitePtr->map_y_loc, townPtr->center_x, townPtr->center_y);
  105. //-------------------------------------------------------------------------//
  106. // check whether a mine is already connected to this town, if so, use it
  107. //-------------------------------------------------------------------------//
  108. for(connected=0, k=townPtr->linked_firm_count-1; k>=0; k--)
  109. {
  110. err_when(!townPtr->linked_firm_array[k] || firm_array.is_deleted(townPtr->linked_firm_array[k]));
  111. firmPtr = firm_array[townPtr->linked_firm_array[k]];
  112. if(firmPtr->nation_recno==nation_recno && firmPtr->firm_id==FIRM_MINE)
  113. {
  114. connected++;
  115. break;
  116. }
  117. }
  118. //-------------------------------------------------------------------------//
  119. // calculate the minimum distance from own towns
  120. //-------------------------------------------------------------------------//
  121. if(dist<minDist[siteId] || (connected && dist<=EFFECTIVE_FIRM_TOWN_DISTANCE))
  122. {
  123. //------ can build or not ----------//
  124. canBuild = 0;
  125. for(int ix=sitePtr->map_x_loc-firmInfo->loc_width+1; ix<=sitePtr->map_x_loc && !canBuild; ix++)
  126. {
  127. if(ix<0 || ix>=MAX_WORLD_X_LOC)
  128. continue;
  129. for(int iy=sitePtr->map_y_loc-firmInfo->loc_height+1; iy<=sitePtr->map_y_loc && !canBuild; iy++)
  130. {
  131. if(iy<0 || iy>=MAX_WORLD_Y_LOC)
  132. continue;
  133. if(world.can_build_firm(ix, iy, FIRM_MINE))
  134. {
  135. canBuild++;
  136. buildXLoc[siteId] = ix;
  137. buildYLoc[siteId] = iy;
  138. break;
  139. }
  140. }
  141. }
  142. if(canBuild)
  143. {
  144. nearSite[siteId] = i;
  145. minDist[siteId] = dist;
  146. if(connected && dist<=EFFECTIVE_FIRM_TOWN_DISTANCE)
  147. townWithMine[siteId]++;
  148. }
  149. }
  150. }
  151. for(allHave=1, j=0; j<MAX_RAW; j++)
  152. {
  153. if(!townWithMine[j])//if(!nearSite[j])
  154. {
  155. allHave = 0;
  156. break;
  157. }
  158. }
  159. if(allHave)
  160. break; // sites of each raw material have been found
  161. }
  162. //---------------------------------------------------------------------------//
  163. // determine which raw material is the best choice to build
  164. // Note: a better sorting algorithm should be used if there are many kind of
  165. // raw material
  166. //---------------------------------------------------------------------------//
  167. int weight, pos; // weight is the such kind of material mined, pos is the position in the array
  168. int siteRecno = 0; // siteRecno is the recno of site to build
  169. int withoutThisRaw = 0; // withoutThisRaw shows that this raw material is strongly recommended
  170. int closestDist=0x7FFFFF;
  171. for(pos=-1, weight=0x7FFFFF, j=0 ;j<MAX_RAW; j++)
  172. {
  173. if(!nearSite[j])
  174. continue; // no such kind of raw material
  175. if(!raw_kind_mined[j]) // no such kind of material and there is a possible site
  176. {
  177. if(withoutThisRaw)
  178. {
  179. if(minDist[j]<closestDist) // more than one kind of material we don't have
  180. {
  181. siteRecno = nearSite[j];
  182. closestDist = minDist[j];
  183. pos = j;
  184. }
  185. }
  186. else
  187. {
  188. siteRecno = nearSite[j];
  189. closestDist = minDist[j];
  190. withoutThisRaw++;
  191. pos = j;
  192. }
  193. }
  194. else if(!withoutThisRaw && weight>raw_kind_mined[j]) // scan for the kind of material with least num of this site
  195. {
  196. weight = raw_kind_mined[j];
  197. pos = j;
  198. }
  199. }
  200. if(!siteRecno && pos>=0)
  201. siteRecno = nearSite[pos];
  202. if(siteRecno)
  203. {
  204. sitePtr = site_array[siteRecno];
  205. xLoc = buildXLoc[pos];
  206. yLoc = buildYLoc[pos];
  207. refXLoc = sitePtr->map_x_loc;
  208. refYLoc = sitePtr->map_y_loc;
  209. err_when((xLoc-refXLoc)>=firm_res[FIRM_MINE]->loc_width || (yLoc-refYLoc)>=firm_res[FIRM_MINE]->loc_height);
  210. //--------------------------------------------------------------//
  211. // do some adjustment such that the firm will be built far away
  212. // from other firms by at least one step.
  213. //--------------------------------------------------------------//
  214. seek_best_build_mine_location(xLoc, yLoc, sitePtr->map_x_loc, sitePtr->map_y_loc);
  215. err_when((xLoc-refXLoc)>=firm_res[FIRM_MINE]->loc_width || (yLoc-refYLoc)>=firm_res[FIRM_MINE]->loc_height);
  216. return sitePtr->object_id; // the raw id.
  217. }
  218. return 0;
  219. }
  220. //---------- End of function Nation::seek_mine --------//
  221. //----- Begin of function Nation::seek_best_build_mine_location -----//
  222. //
  223. // <short&> xLoc - a possible x location to build the mine, the final location is also returned by this reference
  224. // <short&> yLoc - a possible y location to build the mine.
  225. //
  226. // <short> mapXLoc - the x location of the raw material
  227. // <short> mapYLoc - the y location of the raw material
  228. //
  229. void Nation::seek_best_build_mine_location(short& xLoc, short& yLoc, short mapXLoc, short mapYLoc)
  230. {
  231. //--------------- define parameters -----------------//
  232. FirmInfo *firmInfo = firm_res[FIRM_MINE];
  233. int weight = 0, maxWeight = 0;
  234. short xLeftLimit = mapXLoc-firmInfo->loc_width+1;
  235. short yLeftLimit = mapYLoc-firmInfo->loc_height+1;
  236. short resultXLoc = xLoc;
  237. short resultYLoc = yLoc;
  238. short ix, iy;
  239. for(ix=xLeftLimit; ix<=mapXLoc; ix++)
  240. {
  241. if(ix<0 || ix>=MAX_WORLD_X_LOC)
  242. continue;
  243. for(iy=yLeftLimit; iy<=mapYLoc; iy++)
  244. {
  245. if(iy<0 || iy>=MAX_WORLD_Y_LOC)
  246. continue;
  247. //---------------------------------------------------------------//
  248. // remove previous checked and useless locaton
  249. // Since all the possible location is checked from the top left
  250. // to the bottom right, the previous checked location should all
  251. // be impossible to build the mine.
  252. //---------------------------------------------------------------//
  253. if(ix<xLoc && iy<yLoc)
  254. continue;
  255. if(world.can_build_firm(ix, iy, FIRM_MINE))
  256. {
  257. //----------------------------------------//
  258. // calculate weight
  259. //----------------------------------------//
  260. weight = 0;
  261. cal_location_score(ix, iy, firmInfo->loc_width, firmInfo->loc_height, weight);
  262. if(weight>maxWeight)
  263. {
  264. resultXLoc = ix;
  265. resultYLoc = iy;
  266. if(weight == MAX_SCORE) // very good locaton, stop checking
  267. break;
  268. maxWeight = weight;
  269. }
  270. }
  271. }
  272. }
  273. xLoc = resultXLoc;
  274. yLoc = resultYLoc;
  275. }
  276. //---------- End of function Nation::seek_best_build_mine_location --------//
  277. //--------- Begin of function Nation::cal_location_score --------//
  278. // Called by seek_best_build_mine_location() to calculate a specifed
  279. // location score to build the mine.
  280. //
  281. // <short> x1 - the upper left corner x location of the firm
  282. // <short> y1 - the upper left corner y location of the firm
  283. // <short> width - the width of the firm
  284. // <short> height - the height of the firm
  285. // <short&> score - return the location score
  286. //
  287. void Nation::cal_location_score(short x1, short y1, short width, short height, int& score)
  288. {
  289. //-----------------------------------------------------------------//
  290. // the score is calculated as follows, for instance, the firm is
  291. // 2x2 in dimension
  292. //
  293. // LU U U RU L--left, R--right, U--upper, O--lower
  294. // L x x R
  295. // L x x R
  296. // LO O O RO
  297. //
  298. // if any L can build, score += 1, if all set of L can build the total
  299. // score of this edge is 100. For each corner, the score is 50 if
  300. // can build. Thus, the max. score == 600
  301. //
  302. //-----------------------------------------------------------------//
  303. short x, y, i, count;
  304. score = 0;
  305. //---------- left edge ---------//
  306. if((x=x1-1)>=0)
  307. {
  308. for(i=0, count=0; i<height; i++)
  309. {
  310. if(world.get_loc(x, y1+i)->can_build_firm())
  311. count++;
  312. }
  313. score += (count==height) ? 100 : count;
  314. }
  315. //---------- upper edge ---------//
  316. if((y=y1-1)>=0)
  317. {
  318. for(i=0, count=0; i<width; i++)
  319. {
  320. if(world.get_loc(x1+i, y)->can_build_firm())
  321. count++;
  322. }
  323. score += (count==width) ? 100 : count;
  324. }
  325. //---------- right edge ---------//
  326. if((x=x1+width)<MAX_WORLD_X_LOC)
  327. {
  328. for(i=0, count=0; i<height; i++)
  329. {
  330. if(world.get_loc(x, y1+i)->can_build_firm())
  331. count++;
  332. }
  333. score += (count==height) ? 100 : count;
  334. }
  335. //----------- lower edge -----------//
  336. if((y=y1+height)<MAX_WORLD_Y_LOC)
  337. {
  338. for(i=0, count=0; i<width; i++)
  339. {
  340. if(world.get_loc(x1+i, y)->can_build_firm())
  341. count++;
  342. }
  343. score += (count==width) ? 100 : count;
  344. }
  345. //------------------------------------------//
  346. // extra score
  347. //------------------------------------------//
  348. //------- upper left corner -------//
  349. if(x1>0 && y1>0 && world.get_loc(x1-1, y1-1)->can_build_firm())
  350. score += 50;
  351. //------- upper right corner ---------//
  352. if(x1<MAX_WORLD_X_LOC-1 && y1>0 && world.get_loc(x1+1, y1-1)->can_build_firm())
  353. score += 50;
  354. //----------- lower left corner ----------//
  355. if(x1>0 && y1<MAX_WORLD_Y_LOC-1 && world.get_loc(x1-1, y1+1)->can_build_firm())
  356. score += 50;
  357. //------- lower right corner ---------//
  358. if(x1<MAX_WORLD_X_LOC-1 && y1<MAX_WORLD_Y_LOC-1 && world.get_loc(x1+1, y1+1)->can_build_firm())
  359. score += 50;
  360. }
  361. //---------- End of function Nation::cal_location_score --------//
  362. //----------- Begin of function Nation::find_best_firm_loc ----------//
  363. //
  364. // Determine the location of a new firm. It's best to have the
  365. // new firm within the refective range of: towns, factories and
  366. // mines.
  367. //
  368. // <short> buildFirmId - id. of the firm to be built
  369. // <short> refXLoc, refYLoc - either the location of a town or a firm,
  370. // the market must be built next to it.
  371. // <short&> resultXLoc, resultYLoc - result location of the firm.
  372. //
  373. // return: <int> 1 - succeed, 0 - fail
  374. //
  375. int Nation::find_best_firm_loc(short buildFirmId, short refXLoc, short refYLoc, short& resultXLoc, short& resultYLoc)
  376. {
  377. Location *locPtr = world.get_loc(refXLoc, refYLoc);
  378. short centerX, centerY, refX1, refY1, refX2, refY2;
  379. //-------- get the refective area ---------//
  380. int originFirmRecno=0, originTownRecno=0;
  381. Firm* firmPtr;
  382. Town* townPtr;
  383. BYTE buildRegionId = locPtr->region_id;
  384. int buildIsPlateau = locPtr->is_plateau();
  385. if( locPtr->is_firm() )
  386. {
  387. originFirmRecno = locPtr->firm_recno();
  388. firmPtr = firm_array[originFirmRecno];
  389. centerX = firmPtr->center_x;
  390. centerY = firmPtr->center_y;
  391. refX1 = centerX - EFFECTIVE_FIRM_FIRM_DISTANCE;
  392. refY1 = centerY - EFFECTIVE_FIRM_FIRM_DISTANCE;
  393. refX2 = centerX + EFFECTIVE_FIRM_FIRM_DISTANCE;
  394. refY2 = centerY + EFFECTIVE_FIRM_FIRM_DISTANCE;
  395. if( firmPtr->firm_id == FIRM_HARBOR )
  396. {
  397. buildRegionId = ((FirmHarbor*)firmPtr)->land_region_id;
  398. buildIsPlateau = 0;
  399. }
  400. }
  401. else if( locPtr->is_town() )
  402. {
  403. originTownRecno = locPtr->town_recno();
  404. townPtr = town_array[originTownRecno];
  405. centerX = townPtr->center_x;
  406. centerY = townPtr->center_y;
  407. refX1 = centerX - EFFECTIVE_FIRM_TOWN_DISTANCE;
  408. refY1 = centerY - EFFECTIVE_FIRM_TOWN_DISTANCE;
  409. refX2 = centerX + EFFECTIVE_FIRM_TOWN_DISTANCE;
  410. refY2 = centerY + EFFECTIVE_FIRM_TOWN_DISTANCE;
  411. }
  412. else
  413. err_here();
  414. //------------------------------------------------------//
  415. FirmInfo* firmInfo = firm_res[buildFirmId];
  416. int firmLocWidth = firmInfo->loc_width;
  417. int firmLocHeight = firmInfo->loc_height;
  418. refX1 -= firmLocWidth/2; // since we use loc_x1 as the building reference, we need to shift it so it will match the use of center_x in effective distance
  419. refY1 -= firmLocHeight/2;
  420. refX1 = max(0, refX1);
  421. refY1 = max(0, refY1);
  422. if( refX2 - firmLocWidth/2 >= MAX_WORLD_X_LOC )
  423. refX2 = MAX_WORLD_X_LOC-1;
  424. else
  425. refX2 -= firmLocWidth/2;
  426. if( refY2 - firmLocHeight/2 >= MAX_WORLD_Y_LOC )
  427. refY2 = MAX_WORLD_Y_LOC-1;
  428. else
  429. refY2 -= firmLocHeight/2;
  430. err_when( refX2 >= MAX_WORLD_X_LOC );
  431. err_when( refY2 >= MAX_WORLD_Y_LOC );
  432. //-------- build a matrix on the refective area ---------//
  433. int refWidth=refX2-refX1+1, refHeight=refY2-refY1+1;
  434. short* refMatrix = (short*) mem_add( sizeof(short) * refWidth * refHeight );
  435. short* refMatrixPtr;
  436. //------ initialize the weights of the matrix ------//
  437. int xLoc, yLoc; // inner locations in the matrix receives more weights than outer locations do
  438. int t1, t2;
  439. for( yLoc=refY1 ; yLoc<=refY2 ; yLoc++ )
  440. {
  441. refMatrixPtr = refMatrix + (yLoc-refY1)*refWidth;
  442. locPtr = world.get_loc( refX1, yLoc );
  443. for( xLoc=refX1 ; xLoc<=refX2 ; xLoc++, refMatrixPtr++, locPtr++ )
  444. {
  445. t1 = abs(xLoc-centerX);
  446. t2 = abs(yLoc-centerY);
  447. if( locPtr->region_id != buildRegionId ||
  448. locPtr->is_plateau() != buildIsPlateau ||
  449. locPtr->is_power_off() )
  450. {
  451. *refMatrixPtr = -1000;
  452. }
  453. else
  454. {
  455. *refMatrixPtr = 10-max(t1, t2); // it's negative value, and the value is lower for the outer ones
  456. }
  457. }
  458. }
  459. //----- calculate weights of the locations in the matrix ----//
  460. int xLocB, yLocB, weightAdd, weightReduce;
  461. short refBX1, refBY1, refBX2, refBY2;
  462. short refCX1, refCY1, refCX2, refCY2;
  463. for( yLoc=refY1 ; yLoc<=refY2 ; yLoc++ )
  464. {
  465. locPtr = world.get_loc(refX1, yLoc);
  466. for( xLoc=refX1 ; xLoc<=refX2 ; xLoc++, locPtr++ )
  467. {
  468. if( locPtr->region_id != buildRegionId ||
  469. locPtr->is_plateau() != buildIsPlateau ||
  470. locPtr->is_power_off() )
  471. {
  472. continue;
  473. }
  474. //------- if there is a firm on the location ------//
  475. weightAdd = 0;
  476. weightReduce = 0;
  477. if( locPtr->is_firm() )
  478. {
  479. firmPtr = firm_array[locPtr->firm_recno()];
  480. if( buildFirmId==FIRM_MARKET || buildFirmId==FIRM_FACTORY ) // only factories & market places need building close to other firms
  481. {
  482. int rc = 1;
  483. if( firmPtr->nation_recno != nation_recno )
  484. rc = 0;
  485. //----- check if the firm is of the right type ----//
  486. if( buildFirmId==FIRM_MARKET ) // build a market place close to mines and factories
  487. {
  488. if( firmPtr->firm_id!=FIRM_MINE && firmPtr->firm_id!=FIRM_FACTORY ) // market places should be built close to factories and mines and they are the only two firms that influence the location of the market place
  489. rc = 0;
  490. }
  491. else if( buildFirmId==FIRM_FACTORY ) // build a factory close to mines and market places
  492. {
  493. if( firmPtr->firm_id!=FIRM_MINE && firmPtr->firm_id!=FIRM_MARKET ) // market places should be built close to factories and mines and they are the only two firms that influence the location of the market place
  494. rc = 0;
  495. }
  496. //------------------------------------------/
  497. if( rc )
  498. {
  499. refBX1 = firmPtr->center_x - EFFECTIVE_FIRM_FIRM_DISTANCE;
  500. refBY1 = firmPtr->center_y - EFFECTIVE_FIRM_FIRM_DISTANCE;
  501. refBX2 = firmPtr->center_x + EFFECTIVE_FIRM_FIRM_DISTANCE;
  502. refBY2 = firmPtr->center_y + EFFECTIVE_FIRM_FIRM_DISTANCE;
  503. weightAdd = 30;
  504. }
  505. }
  506. refCX1 = firmPtr->loc_x1-1; // add negative weights on space around this firm
  507. refCY1 = firmPtr->loc_y1-1; // so to prevent firms from building right next to the firm
  508. refCX2 = firmPtr->loc_x2+1; // and leave some space for walking path.
  509. refCY2 = firmPtr->loc_y2+1;
  510. weightReduce = 20;
  511. }
  512. //------- if there is a town on the location ------//
  513. else if( locPtr->is_town() )
  514. {
  515. townPtr = town_array[locPtr->town_recno()];
  516. refBX1 = townPtr->center_x - EFFECTIVE_FIRM_TOWN_DISTANCE;
  517. refBY1 = townPtr->center_y - EFFECTIVE_FIRM_TOWN_DISTANCE;
  518. refBX2 = townPtr->center_x + EFFECTIVE_FIRM_TOWN_DISTANCE;
  519. refBY2 = townPtr->center_y + EFFECTIVE_FIRM_TOWN_DISTANCE;
  520. weightAdd = townPtr->population*2;
  521. //----- if the town is not our own -----//
  522. if(townPtr->nation_recno != nation_recno)
  523. {
  524. if( townPtr->nation_recno==0 ) // it's an independent town
  525. weightAdd = weightAdd * (100-townPtr->average_resistance(nation_recno)) / 100;
  526. else // more friendly nations get higher weights
  527. {
  528. int relationStatus = get_relation_status(townPtr->nation_recno);
  529. if( relationStatus >= NATION_NEUTRAL )
  530. weightAdd = weightAdd * (relationStatus-NATION_NEUTRAL+1) / 4;
  531. }
  532. }
  533. refCX1 = townPtr->loc_x1-1; // add negative weights on space around this firm
  534. refCY1 = townPtr->loc_y1-1; // so to prevent firms from building right next to the firm
  535. refCX2 = townPtr->loc_x2+1; // and leave some space for walking path.
  536. refCY2 = townPtr->loc_y2+1;
  537. weightReduce = 100;
  538. }
  539. else
  540. continue;
  541. //------ add weights to the matrix ------//
  542. if( weightAdd )
  543. {
  544. for( yLocB=max(refY1,refBY1) ; yLocB<=min(refY2,refBY2) ; yLocB++ )
  545. {
  546. xLocB = max(refX1,refBX1);
  547. refMatrixPtr = refMatrix + (yLocB-refY1)*refWidth + (xLocB-refX1);
  548. for( ; xLocB<=min(refX2,refBX2) ; xLocB++ )
  549. {
  550. *refMatrixPtr++ += weightAdd;
  551. }
  552. }
  553. }
  554. //------ reduce weights from the matrix ------//
  555. if( weightReduce )
  556. {
  557. for( yLocB=max(refY1,refCY1) ; yLocB<=min(refY2,refCY2) ; yLocB++ )
  558. {
  559. xLocB = max(refX1,refCX1);
  560. refMatrixPtr = refMatrix + (yLocB-refY1)*refWidth + (xLocB-refX1);
  561. for( ; xLocB<=min(refX2,refCX2) ; xLocB++ )
  562. {
  563. *refMatrixPtr++ -= weightReduce;
  564. }
  565. }
  566. }
  567. }
  568. }
  569. //------ select the best building site in the matrix -------//
  570. resultXLoc = -1;
  571. resultYLoc = -1;
  572. short thisWeight, bestWeight=0;
  573. refX2 -= firmLocWidth-1; // do not scan beyond the border
  574. refY2 -= firmLocHeight-1;
  575. for( yLoc=refY1 ; yLoc<=refY2 ; yLoc++ )
  576. {
  577. for( xLoc=refX1 ; xLoc<=refX2 ; xLoc++ )
  578. {
  579. if( world.get_region_id(xLoc, yLoc) != buildRegionId ||
  580. !world.can_build_firm(xLoc, yLoc, buildFirmId) )
  581. {
  582. continue;
  583. }
  584. //---- calculate the average weight of a firm area ----//
  585. int totalWeight=0;
  586. refMatrixPtr = refMatrix + (yLoc-refY1)*refWidth + (xLoc-refX1);
  587. for( int yCount=0 ; yCount<firmLocHeight ; yCount++ )
  588. {
  589. for( int xCount=0 ; xCount<firmLocWidth ; xCount++ )
  590. {
  591. totalWeight += *refMatrixPtr++;
  592. }
  593. refMatrixPtr += refWidth-firmLocWidth;
  594. }
  595. //------- compare the weights --------//
  596. thisWeight = totalWeight / (firmLocWidth*firmLocHeight);
  597. if( thisWeight > bestWeight )
  598. {
  599. bestWeight = thisWeight;
  600. resultXLoc = xLoc;
  601. resultYLoc = yLoc;
  602. }
  603. }
  604. }
  605. //------ release the refective matrix -----//
  606. mem_del( refMatrix );
  607. return resultXLoc >= 0;
  608. }
  609. //-------- End of function Nation::find_best_firm_loc --------//