OWORLD.cpp 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402
  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 : OWORLD.CPP
  21. //Description : Object World
  22. #include <OSYS.h>
  23. #include <OGAME.h>
  24. #include <OVGA.h>
  25. #include <OFONT.h>
  26. #include <OMOUSE.h>
  27. #include <OMOUSECR.h>
  28. #include <OFIRMRES.h>
  29. #include <OPLANT.h>
  30. #include <OPOWER.h>
  31. #include <OSITE.h>
  32. #include <OINFO.h>
  33. #include <OTOWN.h>
  34. #include <ONATION.h>
  35. #include <OWEATHER.h>
  36. #include <OTERRAIN.h>
  37. #include <OWORLD.h>
  38. #include <OANLINE.h>
  39. #include <OTORNADO.h>
  40. #include <OU_VEHI.h>
  41. #include <OSERES.h>
  42. #include <OREMOTE.h>
  43. #include <ONEWS.h>
  44. //------------ Define static class variables ------------//
  45. short World::view_top_x, World::view_top_y;
  46. int World::max_x_loc=200, World::max_y_loc=200;
  47. //----------- Begin of function World::World ----------//
  48. World::World()
  49. {
  50. memset( this, 0, sizeof(World) );
  51. //------- initialize matrix objects -------//
  52. map_matrix = new MapMatrix;
  53. zoom_matrix = new ZoomMatrix;
  54. }
  55. //------------- End of function World::World -----------//
  56. //----------- Begin of function World::~World ----------//
  57. World::~World()
  58. {
  59. if( map_matrix )
  60. {
  61. delete map_matrix;
  62. map_matrix = NULL;
  63. }
  64. if( zoom_matrix )
  65. {
  66. delete zoom_matrix;
  67. zoom_matrix = NULL;
  68. }
  69. deinit();
  70. }
  71. //------------- End of function World::~World -----------//
  72. //----------- Begin of function World::init ----------//
  73. void World::init()
  74. {
  75. //----------- initialize vars -------------//
  76. scan_fire_x = 0;
  77. scan_fire_y = 0;
  78. lightning_signal = 0;
  79. map_matrix->init_para();
  80. zoom_matrix->init_para();
  81. }
  82. //------------- End of function World::init -----------//
  83. //----------- Begin of function World::deinit ----------//
  84. void World::deinit()
  85. {
  86. if( loc_matrix )
  87. {
  88. mem_del( loc_matrix );
  89. loc_matrix = NULL;
  90. }
  91. }
  92. //------------- End of function World::deinit -----------//
  93. //--------- Begin of function World::assign_map ----------//
  94. //
  95. // After a map is loaded, assign_map() need to be called to
  96. // initial map_matrix and zoom_matrix
  97. //
  98. void World::assign_map()
  99. {
  100. //------------- assign map -------------//
  101. map_matrix-> assign_map(loc_matrix, max_x_loc, max_y_loc );
  102. zoom_matrix->assign_map(loc_matrix, max_x_loc, max_y_loc );
  103. //-------- set the zoom area box on map matrix ------//
  104. map_matrix->cur_x_loc = 0;
  105. map_matrix->cur_y_loc = 0;
  106. map_matrix->cur_cargo_width = zoom_matrix->disp_x_loc;
  107. map_matrix->cur_cargo_height = zoom_matrix->disp_y_loc;
  108. }
  109. //----------- End of function World::assign_map ----------//
  110. //----------- Begin of function World::paint ------------//
  111. //
  112. // Paint world window and scroll bars
  113. //
  114. void World::paint()
  115. {
  116. map_matrix->paint();
  117. zoom_matrix->paint();
  118. }
  119. //----------- End of function World::paint ------------//
  120. //----------- Begin of function World::refresh ------------//
  121. //
  122. void World::refresh()
  123. {
  124. map_matrix->refresh();
  125. zoom_matrix->refresh();
  126. }
  127. //----------- End of function World::refresh ------------//
  128. //----------- Begin of function World::process ------------//
  129. //
  130. // Called every frame
  131. //
  132. void World::process()
  133. {
  134. //-------- process wall ----------//
  135. form_world_wall();
  136. //-------- process fire -----------//
  137. // BUGHERE : set Location::flammability for every change in cargo
  138. world.spread_fire(weather);
  139. // ------- process visibility --------//
  140. process_visibility();
  141. //-------- process lightning ------//
  142. // ###### begin Gilbert 11/8 ########//
  143. if(lightning_signal== 0 && weather.is_lightning())
  144. {
  145. // ------- create new lightning ----------//
  146. lightning_signal = 110;
  147. }
  148. if( lightning_signal == 106 && config.weather_effect)
  149. {
  150. lightning_strike(m.random(MAX_MAP_WIDTH), m.random(MAX_MAP_HEIGHT), 1);
  151. }
  152. if(lightning_signal == 100)
  153. lightning_signal = 5 + m.random(10);
  154. else if( lightning_signal)
  155. lightning_signal--;
  156. // ###### end Gilbert 11/8 ########//
  157. //---------- process ambient sound ---------//
  158. if( sys.frame_count%10 == 0 ) // process once per ten frames
  159. process_ambient_sound();
  160. // --------- update scan fire x y ----------//
  161. if(++scan_fire_x >= SCAN_FIRE_DIST)
  162. {
  163. scan_fire_x = 0;
  164. if( ++scan_fire_y >= SCAN_FIRE_DIST)
  165. scan_fire_y =0;
  166. }
  167. }
  168. //----------- End of function World::process ------------//
  169. //----------- Begin of function World::next_day ------------//
  170. //
  171. // Called every frame
  172. //
  173. void World::next_day()
  174. {
  175. plant_ops();
  176. weather = weather_forecast[0];
  177. for(int foreDay=0; foreDay < MAX_WEATHER_FORECAST-1; ++foreDay)
  178. {
  179. weather_forecast[foreDay] = weather_forecast[foreDay+1];
  180. }
  181. weather_forecast[MAX_WEATHER_FORECAST-1].next_day();
  182. // ####### begin Gilbert 11/7 #########//
  183. magic_weather.next_day();
  184. // ####### end Gilbert 11/7 #########//
  185. if(weather.has_tornado() && config.weather_effect)
  186. {
  187. tornado_array.add_tornado(weather.tornado_x_loc(max_x_loc, max_y_loc),
  188. weather.tornado_y_loc(max_x_loc, max_y_loc), 600);
  189. }
  190. // ######## begin Gilbert 31/7 #######//
  191. if( weather.is_quake() && config.random_event_frequency)
  192. // ######## end Gilbert 31/7 #######//
  193. {
  194. earth_quake();
  195. }
  196. //-------- Debug code: BUGHERE ----------//
  197. #ifdef DEBUG
  198. Location* locPtr = loc_matrix;
  199. for( int y=0 ; y<MAX_WORLD_Y_LOC ; y++ )
  200. {
  201. for( int x=0 ; x<MAX_WORLD_X_LOC ; x++ )
  202. {
  203. if( locPtr->has_unit(UNIT_LAND) )
  204. {
  205. err_when( unit_array.is_truly_deleted( locPtr->unit_recno(UNIT_LAND) ) );
  206. }
  207. locPtr++;
  208. }
  209. }
  210. #endif
  211. }
  212. //----------- End of function World::next_day ------------//
  213. //----------- Begin of function World::detect ------------//
  214. //
  215. // Detect mouse action from user
  216. //
  217. // Return : 1 - mouse pressed on World area
  218. // 0 - mouse not pressed on World area
  219. //
  220. int World::detect()
  221. {
  222. if( map_matrix->detect() )
  223. return 1;
  224. if( zoom_matrix->detect() )
  225. return 1;
  226. if( detect_scroll() )
  227. return 1;
  228. // ##### begin Gilbert 16/9 #######//
  229. // return detect_firm_town();
  230. return 0;
  231. // ##### end Gilbert 16/9 #######//
  232. }
  233. //----------- End of function World::detect ------------//
  234. //--------- Begin of function World::detect_scroll ---------//
  235. //
  236. // Detect if the mouse cursor is pushed towards the border
  237. // of the screen to scroll the zoom window.
  238. //
  239. int World::detect_scroll()
  240. {
  241. if( mouse_cursor.frame_flag ) // if it's now in frame selection mode
  242. return 0;
  243. if( next_scroll_time && m.get_time() < next_scroll_time ) // just scrolled not too long ago, wait for a little while before next scroll.
  244. return 0;
  245. int rc=0;
  246. //----- scroll left -----//
  247. if( mouse.cur_x == mouse.bound_x1 )
  248. {
  249. zoom_matrix->scroll(-1,0);
  250. rc = 1;
  251. }
  252. //---- scroll right -----//
  253. if( mouse.cur_x == mouse.bound_x2 )
  254. {
  255. zoom_matrix->scroll(1,0);
  256. rc = 1;
  257. }
  258. //---- scroll top -------//
  259. if( mouse.cur_y == mouse.bound_y1 )
  260. {
  261. zoom_matrix->scroll(0,-1);
  262. rc = 1;
  263. }
  264. //---- scroll bottom ----//
  265. if( mouse.cur_y == mouse.bound_y2 )
  266. {
  267. zoom_matrix->scroll(0,1);
  268. rc = 1;
  269. }
  270. //----- set next scroll time based on scroll_speed -----//
  271. //
  272. // slowest scroll speed: 500/1 = 500 milliseconds or 1/2 second
  273. // fastest scroll speed: 500/10 = 50 milliseconds or 1/20 second
  274. //
  275. //------------------------------------------------------//
  276. if( rc )
  277. {
  278. sys.zoom_need_redraw = 1; // ask the zoom window to refresh next time
  279. next_scroll_time = m.get_time() + 500/(config.scroll_speed+1);
  280. }
  281. return rc;
  282. }
  283. //----------- End of function World::detect_scroll -----------//
  284. //--------- Begin of function World::go_loc --------//
  285. //
  286. // Go to a specified location.
  287. //
  288. // <int> xLoc, yLoc - location to go to.
  289. // [int] selectFlag - whether should the object on the location if
  290. // there is one. (default: 0)
  291. //
  292. void World::go_loc(int xLoc, int yLoc, int selectFlag)
  293. {
  294. //------- set location ---------//
  295. zoom_matrix->cur_x_loc = xLoc;
  296. zoom_matrix->cur_y_loc = yLoc;
  297. map_matrix->cur_x_loc = xLoc - zoom_matrix->disp_x_loc/2;
  298. map_matrix->cur_y_loc = yLoc - zoom_matrix->disp_y_loc/2;
  299. //--------- refresh ------------//
  300. map_matrix->valid_cur_box();
  301. zoom_matrix->top_x_loc = map_matrix->cur_x_loc;
  302. zoom_matrix->top_y_loc = map_matrix->cur_y_loc;
  303. sys.zoom_need_redraw = 1;
  304. //---- if should select the object on the location ----//
  305. if( selectFlag )
  306. {
  307. Location* locPtr = world.get_loc(xLoc, yLoc);
  308. if( locPtr->has_any_unit() )
  309. {
  310. int mobileType;
  311. int unitRecno = locPtr->get_any_unit( mobileType );
  312. power.reset_selection();
  313. unit_array[unitRecno]->selected_flag = 1;
  314. unit_array.selected_recno = unitRecno;
  315. unit_array.selected_count++;
  316. }
  317. else if( locPtr->is_firm() )
  318. {
  319. power.reset_selection();
  320. firm_array.selected_recno = locPtr->firm_recno();
  321. }
  322. else if( locPtr->is_town() )
  323. {
  324. power.reset_selection();
  325. town_array.selected_recno = locPtr->town_recno();
  326. }
  327. else if( locPtr->has_site() )
  328. {
  329. power.reset_selection();
  330. site_array.selected_recno = locPtr->site_recno();
  331. }
  332. }
  333. //------- refresh the display -------//
  334. info.disp();
  335. }
  336. //----------- End of function World::go_loc --------//
  337. //-------- Begin of function World::unveil ---------//
  338. //
  339. // Unveil all surrounding areas of the given object.
  340. //
  341. // <int> xLoc1, yLoc1 = the position of the object.
  342. // <int> xLoc2, yLoc2 = the position of the object.
  343. //
  344. void World::unveil(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
  345. {
  346. if( config.explore_whole_map )
  347. return;
  348. xLoc1 = max( 0, xLoc1 - EXPLORE_RANGE);
  349. yLoc1 = max( 0, yLoc1 - EXPLORE_RANGE);
  350. xLoc2 = min( MAX_WORLD_X_LOC-1, xLoc2 + EXPLORE_RANGE);
  351. yLoc2 = min( MAX_WORLD_Y_LOC-1, yLoc2 + EXPLORE_RANGE);
  352. explore( xLoc1, yLoc1, xLoc2, yLoc2 );
  353. }
  354. //--------- End of function World::unveil ---------//
  355. //-------- Begin of function World::explore ---------//
  356. //
  357. // Explore a specific area. No further exploration around the area.
  358. //
  359. // <int> xLoc1, yLoc1 = the position of the area.
  360. // <int> xLoc2, yLoc2 = the position of the area.
  361. //
  362. void World::explore(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
  363. {
  364. if( config.explore_whole_map )
  365. return;
  366. int xLoc, yLoc;
  367. Location* locPtr;
  368. char* imageBuf = map_matrix->save_image_buf + sizeof(short)*2;
  369. char* nationColorArray = nation_array.nation_power_color_array;
  370. char* writePtr;
  371. int shadowMapDist = max_x_loc + 1;
  372. int tileYOffset;
  373. Location *northWestPtr;
  374. char tilePixel;
  375. for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
  376. {
  377. locPtr = get_loc(xLoc1, yLoc);
  378. for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
  379. {
  380. if( !locPtr->explored() )
  381. {
  382. locPtr->explored_on();
  383. //-------- draw pixel ----------//
  384. writePtr = imageBuf+MAP_WIDTH*yLoc+xLoc;
  385. switch( world.map_matrix->map_mode )
  386. {
  387. case MAP_MODE_TERRAIN:
  388. if( locPtr->fire_str() > 0)
  389. *writePtr = (char) FIRE_COLOR;
  390. else if( locPtr->is_plant() )
  391. *writePtr = plant_res.plant_map_color;
  392. else
  393. {
  394. tileYOffset = (yLoc & TERRAIN_TILE_Y_MASK) * TERRAIN_TILE_WIDTH;
  395. tilePixel = terrain_res.get_map_tile(locPtr->terrain_id)[tileYOffset + (xLoc & TERRAIN_TILE_X_MASK)];
  396. if( xLoc == 0 || yLoc == 0)
  397. {
  398. *writePtr = tilePixel;
  399. }
  400. else
  401. {
  402. northWestPtr = locPtr - shadowMapDist;
  403. if( (terrain_res[locPtr->terrain_id]->average_type >=
  404. terrain_res[northWestPtr->terrain_id]->average_type) )
  405. {
  406. *writePtr = tilePixel;
  407. }
  408. else
  409. {
  410. *writePtr = (char) VGA_GRAY;
  411. }
  412. }
  413. break;
  414. }
  415. break;
  416. case MAP_MODE_SPOT:
  417. if( locPtr->sailable() )
  418. *writePtr = (char) 0x32;
  419. else if( locPtr->has_hill() )
  420. *writePtr = (char) V_BROWN;
  421. else if( locPtr->is_plant() )
  422. *writePtr = (char) V_DARK_GREEN;
  423. else
  424. *writePtr = (char) VGA_GRAY+10;
  425. break;
  426. case MAP_MODE_POWER:
  427. if( locPtr->sailable() )
  428. *writePtr = (char) 0x32;
  429. else if( locPtr->has_hill() )
  430. *writePtr = (char) V_BROWN;
  431. else if( locPtr->is_plant() )
  432. *writePtr = (char) V_DARK_GREEN;
  433. else
  434. *writePtr = nationColorArray[locPtr->power_nation_recno];
  435. break;
  436. }
  437. //---- if the command base of the opponent revealed, establish contact ----//
  438. if( locPtr->is_firm() )
  439. {
  440. Firm* firmPtr = firm_array[locPtr->firm_recno()];
  441. if( firmPtr->nation_recno > 0 && nation_array.player_recno )
  442. {
  443. NationRelation *relation = (~nation_array)->get_relation(firmPtr->nation_recno);
  444. if( !relation->has_contact )
  445. {
  446. if( !remote.is_enable() )
  447. {
  448. (~nation_array)->establish_contact(firmPtr->nation_recno);
  449. }
  450. else
  451. {
  452. if( !relation->contact_msg_flag )
  453. {
  454. // packet structure : <player nation> <explored nation>
  455. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_NATION_CONTACT, 2*sizeof(short));
  456. *shortPtr = nation_array.player_recno;
  457. shortPtr[1] = firmPtr->nation_recno;
  458. relation->contact_msg_flag = 1;
  459. }
  460. }
  461. }
  462. }
  463. }
  464. if( locPtr->is_town() )
  465. {
  466. Town* townPtr = town_array[locPtr->town_recno()];
  467. if( townPtr->nation_recno > 0 && nation_array.player_recno )
  468. {
  469. NationRelation *relation = (~nation_array)->get_relation(townPtr->nation_recno);
  470. if( !relation->has_contact )
  471. {
  472. if( !remote.is_enable() )
  473. {
  474. (~nation_array)->establish_contact(townPtr->nation_recno);
  475. }
  476. else
  477. {
  478. if( !relation->contact_msg_flag )
  479. {
  480. // packet structure : <player nation> <explored nation>
  481. short *shortPtr = (short *)remote.new_send_queue_msg(MSG_NATION_CONTACT, 2*sizeof(short));
  482. *shortPtr = nation_array.player_recno;
  483. shortPtr[1] = townPtr->nation_recno;
  484. relation->contact_msg_flag = 1;
  485. }
  486. }
  487. }
  488. }
  489. }
  490. }
  491. }
  492. }
  493. }
  494. //--------- End of function World::explore ---------//
  495. //-------- Begin of function World::is_explored ---------//
  496. //
  497. // Check if the whole area has been explored or not.
  498. //
  499. // <int> xLoc1, yLoc1 = the coordination of the area to explore
  500. // <int> xLoc2, yLoc2 = the coordination of the area to explore
  501. //
  502. int World::is_explored(int xLoc1, int yLoc1, int xLoc2, int yLoc2)
  503. {
  504. if( config.explore_whole_map )
  505. return 1;
  506. int xLoc, yLoc;
  507. Location* locPtr;
  508. for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
  509. {
  510. locPtr = get_loc(xLoc1, yLoc);
  511. for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
  512. {
  513. if( !locPtr->explored() )
  514. return 0;
  515. }
  516. }
  517. return 1;
  518. }
  519. //--------- End of function World::is_explored ---------//
  520. //----------- Begin of function World::load_map ------------//
  521. //
  522. // Load a custom map file.
  523. //
  524. void World::load_map(char* fileName)
  525. {
  526. generate_map();
  527. return;
  528. //---------- initialize the map matrix --------//
  529. max_x_loc = 200;
  530. max_y_loc = 200;
  531. loc_matrix = (Location*) mem_resize( loc_matrix , max_x_loc * max_y_loc * sizeof(Location) );
  532. memset( loc_matrix, 0, sizeof(Location) * max_x_loc * max_y_loc );
  533. int baseType = TERRAIN_DARK_DIRT;
  534. int terrainId = terrain_res.scan(baseType, MIDDLE_MASK, baseType, MIDDLE_MASK,
  535. baseType, MIDDLE_MASK, baseType, MIDDLE_MASK, 1); // 1-get the first instance
  536. for( int i=0 ; i<max_x_loc*max_y_loc ; i++ )
  537. {
  538. loc_matrix[i].terrain_id = terrainId+m.random(3);
  539. }
  540. assign_map();
  541. return;
  542. //---------- initialize the map matrix --------//
  543. max_x_loc = 120;
  544. max_y_loc = 120;
  545. loc_matrix = (Location*) mem_resize( loc_matrix , max_x_loc * max_y_loc * sizeof(Location) );
  546. //-------------- read in the map -------------//
  547. File mapFile;
  548. mapFile.file_open(fileName);
  549. mapFile.file_read(loc_matrix, sizeof(Location)*MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC );
  550. mapFile.file_close();
  551. //----- assign the map to MapMatrix and ZoomMatrix -----//
  552. assign_map();
  553. }
  554. //----------- End of function World::load_map ------------//
  555. //-------- Begin of function World::check_unit_space ------//
  556. //
  557. // To check whether or not the area bounded by the upper left
  558. // corner (xLoc1, yLoc1) and lower right corner (xLoc2, yLoc2)
  559. // can be built.
  560. //
  561. // <int> xLoc1 = the upper left x
  562. // <int> yLoc1 = the upper left y
  563. // <int> xLoc2 = the lower right x
  564. // <int> yLoc2 = the lower right y
  565. // [int] mobileType = mobile type (default: UNIT_LAND)
  566. // [int] buildFlag = whether the located area is for building a firm/town
  567. // if so, the location must no have any raw site.
  568. // (default: 0)
  569. //
  570. // return 1 for true. 0 for false
  571. //
  572. inline int World::check_unit_space(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int mobileType, int buildFlag)
  573. {
  574. if(xLoc1<0 || xLoc1>=MAX_WORLD_X_LOC)
  575. return 0;
  576. if(yLoc1<0 || yLoc1>=MAX_WORLD_Y_LOC)
  577. return 0;
  578. if(xLoc2<0 || xLoc2>=MAX_WORLD_X_LOC)
  579. return 0;
  580. if(yLoc2<0 || yLoc2>=MAX_WORLD_Y_LOC)
  581. return 0;
  582. Location* locPtr = world.get_loc(xLoc1, yLoc1);
  583. int x, y;
  584. int canBuildFlag = 1;
  585. for(y=yLoc1; y<=yLoc2; y++)
  586. {
  587. locPtr = world.get_loc(xLoc1, y);
  588. for(x=xLoc1; x<=xLoc2; x++, locPtr++)
  589. {
  590. if( !locPtr->can_move(mobileType) ||
  591. ( buildFlag && (locPtr->is_power_off() || locPtr->has_site()) ) ) // if build a firm/town, there must not be any sites in the area
  592. {
  593. canBuildFlag=0;
  594. break;
  595. }
  596. }
  597. if(canBuildFlag==0)
  598. break;
  599. }
  600. if( canBuildFlag )
  601. return 1;
  602. else
  603. return 0;
  604. }
  605. //-------- End of function World::check_unit_space ------//
  606. //-------- Begin of function World::locate_space ------//
  607. //
  608. // Locate an area in the world map around the firm to place
  609. // the unit
  610. //
  611. // <int&> xLoc1 = the upper left x location of the building, also for returning the result location
  612. // <int&> yLoc1 = the upper left y location of the building
  613. // <int> xLoc2 = the lower right x location of the building
  614. // <int> yLoc2 = the lower right y location of the building
  615. // <int> spaceLocWidth = the location width of the required space
  616. // <int> spaceLocHeight = the location height of the required space
  617. // [int] mobileType = mobile type (default: UNIT_LAND)
  618. // [int] regionId = specify the region no. of the location to locate
  619. // (default: region no. of xLoc1, yLoc1)
  620. // [int] buildFlag = whether the located area is for building a firm/town
  621. // if so, the location must no have any raw site.
  622. // (default: 0)
  623. //
  624. // return : <int> 1 - free space found
  625. // 0 - free space not found
  626. //
  627. int World::locate_space(int& xLoc1, int& yLoc1, int xLoc2, int yLoc2,
  628. int spaceLocWidth, int spaceLocHeight, int mobileType, int regionId, int buildFlag)
  629. {
  630. if( !regionId )
  631. regionId = get_loc(xLoc1, yLoc1)->region_id;
  632. int isPlateau = get_loc(xLoc1, yLoc1)->is_plateau();
  633. //-----------------------------------------------------------//
  634. // xLoc, yLoc is the adjusted upper left corner location of
  635. // the firm. with the adjustment, it is easier to do the following
  636. // checking.
  637. //-----------------------------------------------------------//
  638. Location* locPtr;
  639. int xLoc = xLoc1 - spaceLocWidth + 1;
  640. int yLoc = yLoc1 - spaceLocHeight + 1;
  641. if(xLoc < 0)
  642. xLoc = 0;
  643. if(yLoc < 0)
  644. yLoc = 0;
  645. int width = xLoc2 - xLoc + 1;
  646. int height = yLoc2 - yLoc + 1;
  647. int loopCount=0;
  648. while(1)
  649. {
  650. err_when( ++loopCount > MAX_WORLD_X_LOC * MAX_WORLD_Y_LOC * 4 );
  651. //-----------------------------------------------------------//
  652. // step 1
  653. //-----------------------------------------------------------//
  654. int xOffset = width/2;
  655. int yOffset = height;
  656. int x, y;
  657. x = xLoc + xOffset;
  658. y = yLoc + yOffset;
  659. if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
  660. {
  661. if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
  662. {
  663. locPtr = get_loc(x,y);
  664. if( locPtr->region_id == regionId &&
  665. locPtr->is_plateau() == isPlateau &&
  666. check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
  667. {
  668. xLoc1 = x;
  669. yLoc1 = y;
  670. return 1;
  671. }
  672. }
  673. }
  674. int sign = -1;
  675. int i, j, k, limit;
  676. //-----------------------------------------------------------//
  677. // step 2
  678. //-----------------------------------------------------------//
  679. //y = yLoc + yOffset;
  680. limit = width + 2;
  681. for(i=1; i<limit; i++)
  682. {
  683. xOffset += sign * i;
  684. x = xLoc + xOffset;
  685. if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
  686. {
  687. if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
  688. {
  689. locPtr = get_loc(x,y);
  690. if( locPtr->region_id == regionId &&
  691. locPtr->is_plateau() == isPlateau &&
  692. check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
  693. {
  694. xLoc1 = x;
  695. yLoc1 = y;
  696. return 1;
  697. }
  698. }
  699. }
  700. sign *= -1;
  701. }
  702. //-----------------------------------------------------------//
  703. // step 3
  704. //-----------------------------------------------------------//
  705. i = limit-1;
  706. limit = (height+1)*2;
  707. int r = sign*i;
  708. int lastX = xOffset;
  709. //int lastY = yOffset;
  710. for(j=0; j<limit; j++)
  711. {
  712. if(j%2)
  713. {
  714. //x = xLoc + lastX;
  715. xOffset = lastX;
  716. x = xLoc + xOffset;
  717. //y = yLoc + yOffset;
  718. if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
  719. {
  720. if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
  721. {
  722. locPtr = get_loc(x,y);
  723. if( locPtr->region_id == regionId &&
  724. locPtr->is_plateau() == isPlateau &&
  725. check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
  726. {
  727. xLoc1 = x;
  728. yLoc1 = y;
  729. return 1;
  730. }
  731. }
  732. }
  733. }
  734. else
  735. {
  736. xOffset = lastX + r;
  737. yOffset--;
  738. x = xLoc + xOffset;
  739. y = yLoc + yOffset;
  740. if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
  741. {
  742. if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
  743. {
  744. locPtr = get_loc(x,y);
  745. if( locPtr->region_id == regionId &&
  746. locPtr->is_plateau() == isPlateau &&
  747. check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
  748. {
  749. xLoc1 = x;
  750. yLoc1 = y;
  751. return 1;
  752. }
  753. }
  754. }
  755. }
  756. }
  757. //-----------------------------------------------------------//
  758. // step 4
  759. //-----------------------------------------------------------//
  760. y = yLoc + yOffset;
  761. for(k=0; k<=width; k++)
  762. {
  763. sign *= -1;
  764. i--;
  765. r = sign*i;
  766. xOffset -= r;
  767. x = xLoc + xOffset;
  768. if(x>=0 && y>=0 && x+spaceLocWidth-1<MAX_WORLD_X_LOC && y+spaceLocHeight-1<MAX_WORLD_Y_LOC)
  769. {
  770. if(mobileType==UNIT_LAND || (x%2==0 && y%2==0))
  771. {
  772. locPtr = get_loc(x,y);
  773. if( locPtr->region_id == regionId &&
  774. locPtr->is_plateau() == isPlateau &&
  775. check_unit_space(x, y, x+spaceLocWidth-1, y+spaceLocHeight-1, mobileType, buildFlag))
  776. {
  777. xLoc1 = x;
  778. yLoc1 = y;
  779. return 1;
  780. }
  781. }
  782. }
  783. }
  784. //-----------------------------------------------------------//
  785. // re-init the parameters
  786. //-----------------------------------------------------------//
  787. if(xLoc<=0 && yLoc<=0 && width>=MAX_WORLD_X_LOC && height>=MAX_WORLD_Y_LOC)
  788. break; // the whole map has been checked
  789. width += 2;
  790. height += 2;
  791. xLoc -= 1;
  792. yLoc -= 1;
  793. if(xLoc<0)
  794. {
  795. xLoc = 0;
  796. width--;
  797. }
  798. if(yLoc<0)
  799. {
  800. yLoc=0;
  801. height--;
  802. }
  803. if(xLoc+width>MAX_WORLD_X_LOC)
  804. width--;
  805. if(yLoc+height>MAX_WORLD_Y_LOC)
  806. height--;
  807. //if(width==xLoc2-xLoc1+spaceLocWidth && height==yLoc2-yLoc1+spaceLocHeight) // terminate the checking
  808. // return 0;
  809. }
  810. return 0;
  811. }
  812. //-------- End of function World::locate_space ------//
  813. //-------- Begin of function World::locate_space_random ------//
  814. //
  815. // Locate an area of space in the world map randomly. Pick any
  816. // space available in that area without a specific scanning order.
  817. //
  818. // <int&> xLoc1 = the scaning range, also for returning the result location
  819. // <int&> yLoc1 = the scaning range
  820. // <int> xLoc2 = the scaning range
  821. // <int> yLoc2 = the scaning range
  822. // <int> spaceLocWidth = the location width of the required space
  823. // <int> spaceLocHeight = the location height of the required space
  824. // <int> maxTries = maximum no. of tries
  825. // [int] regionId = if this is specified, the result location will
  826. // be in this region.
  827. // [int] buildSite = whether locating space for building a site
  828. // (default: 0)
  829. // [char] teraMask = terrain mask (default: 1)
  830. //
  831. // return : <int> 1 - free space found
  832. // 0 - free space found
  833. //
  834. int World::locate_space_random(int& xLoc1, int& yLoc1, int xLoc2, int yLoc2,
  835. int spaceLocWidth, int spaceLocHeight, int maxTries,
  836. int regionId, int buildSite, char teraMask)
  837. {
  838. int i, x, y, xTemp, xLoc, yLoc, canBuildFlag;
  839. int scanWidth = xLoc2-xLoc1-spaceLocWidth+2; //xLoc2-xLoc1+1-spaceLocWidth+1;
  840. int scanHeight = yLoc2-yLoc1-spaceLocHeight+2; //yLoc2-yLoc1+1-spaceLocHeight+1;
  841. Location* locPtr;
  842. for( i=0 ; i<maxTries ; i++ )
  843. {
  844. xLoc = xLoc1 + m.random(scanWidth);
  845. yLoc = yLoc1 + m.random(scanHeight);
  846. canBuildFlag=1;
  847. //---------- check if the area is all free ----------//
  848. xTemp = xLoc+spaceLocWidth-1;
  849. for( y=yLoc+spaceLocHeight-1; y>=yLoc; y-- )
  850. {
  851. locPtr = world.get_loc(xTemp, y);
  852. for(x=xTemp; x>=xLoc; x--, locPtr-- )
  853. {
  854. if( ( buildSite ? !locPtr->can_build_site(teraMask) : !locPtr->can_build_firm(teraMask) ) ||
  855. locPtr->is_power_off() )
  856. {
  857. canBuildFlag=0;
  858. break;
  859. }
  860. }
  861. if(!canBuildFlag)
  862. break;
  863. }
  864. if( !canBuildFlag )
  865. continue;
  866. //------ check region id. ------------//
  867. locPtr = world.get_loc(xLoc, yLoc);
  868. if( regionId && locPtr->region_id != regionId )
  869. continue;
  870. //------------------------------------//
  871. xLoc1 = xLoc;
  872. yLoc1 = yLoc;
  873. err_when(buildSite && !locPtr->can_build_site(teraMask));//-*** hard codes for mine size 3x3
  874. return 1;
  875. }
  876. return 0;
  877. }
  878. //-------- End of function World::locate_space_random ------//
  879. //-------- Begin of function World::can_build_firm ---------//
  880. //
  881. // Check if it is free to construct a building on the specific area.
  882. //
  883. // <int> xLoc1, yLoc1 = the coordination of the area to can_build
  884. // <int> firmId = id. of the firm
  885. // [short] unitRecno = the unit recno of the unit to build the firm
  886. // if the builder unit stands on the building area, still consider the area as buildable
  887. // (default: -1, do not take the builder into account)
  888. //
  889. int World::can_build_firm(int xLoc1, int yLoc1, int firmId, short unitRecno)
  890. {
  891. if( xLoc1 < 0 || yLoc1 < 0 || xLoc1 > MAX_WORLD_X_LOC || yLoc1 > MAX_WORLD_Y_LOC )
  892. return 0;
  893. //------------------------------------------//
  894. FirmInfo* firmInfo = firm_res[firmId];
  895. int xLoc, yLoc;
  896. int xLoc2 = xLoc1 + firmInfo->loc_width - 1;
  897. int yLoc2 = yLoc1 + firmInfo->loc_height - 1;
  898. if(xLoc2>=max_x_loc || yLoc2>max_y_loc)
  899. return 0;
  900. Location* locPtr;
  901. char teraMask, pierFlag;
  902. switch(firmInfo->tera_type)
  903. {
  904. case 1: // default : land firm
  905. case 2: // sea firm
  906. case 3: // land or sea firm
  907. teraMask = firmInfo->tera_type;
  908. for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
  909. {
  910. locPtr = get_loc(xLoc1, yLoc);
  911. for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
  912. {
  913. // ##### patch begin Gilbert 14/3 ######//
  914. if(!locPtr->can_build_firm(teraMask) &&
  915. (!locPtr->has_unit(UNIT_LAND) || locPtr->unit_recno(UNIT_LAND)!=unitRecno))
  916. return 0;
  917. // ##### patch end Gilbert 14/3 ######//
  918. if( firmId != FIRM_MINE && locPtr->has_site() ) // don't allow building any buildings other than mines on a location with a site
  919. return 0;
  920. }
  921. }
  922. return 1;
  923. case 4: // special firm, such as harbor
  924. // must be 3x3,
  925. // centre square of one side is land (teraMask=1),
  926. // two squares on that side can be land or sea (teraMask=3)
  927. // and other (6 squares) are sea (teraMask=2)
  928. if( firmInfo->loc_width != 3 ||
  929. firmInfo->loc_height != 3)
  930. return 0;
  931. pierFlag = 1|2|4|8; // bit0=north, bit1=south, bit2=west, bit3=east
  932. for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
  933. {
  934. locPtr = get_loc(xLoc1, yLoc);
  935. for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
  936. {
  937. if( locPtr->has_site() ) // don't allow building any buildings other than mines on a location with a site
  938. return 0;
  939. static char northPierTera[3][3] = { {2,2,2},{2,2,2},{3,1,3} };
  940. static char southPierTera[3][3] = { {3,1,3},{2,2,2},{2,2,2} };
  941. static char westPierTera[3][3] = { {2,2,3},{2,2,1},{2,2,3} };
  942. static char eastPierTera[3][3] = { {3,2,2},{1,2,2},{3,2,2} };
  943. int x = xLoc - xLoc1;
  944. int y = yLoc - yLoc1;
  945. if(!locPtr->can_build_harbor(northPierTera[y][x]) )
  946. pierFlag &= ~1;
  947. if(!locPtr->can_build_harbor(southPierTera[y][x]) )
  948. pierFlag &= ~2;
  949. if(!locPtr->can_build_harbor(westPierTera[y][x]) )
  950. pierFlag &= ~4;
  951. if(!locPtr->can_build_harbor(eastPierTera[y][x]) )
  952. pierFlag &= ~8;
  953. }
  954. }
  955. err_when( pierFlag != 0 && pierFlag != 1 && pierFlag != 2 &&
  956. pierFlag != 4 && pierFlag != 8 );
  957. return pierFlag;
  958. break;
  959. // other tera_type here
  960. default:
  961. err_here();
  962. return 0;
  963. }
  964. }
  965. //--------- End of function World::can_build_firm ---------//
  966. //-------- Begin of function World::can_build_town ---------//
  967. //
  968. // <int> xLoc1, yLoc1 = the coordination of the area to can_build
  969. // [short] unitRecno = the unit recno of the unit to build the town
  970. // if the builder unit stands on the building area, still consider the area as buildable
  971. // (default: -1, do not take the builder into account)
  972. //
  973. int World::can_build_town(int xLoc1, int yLoc1, short unitRecno)
  974. {
  975. int xLoc, yLoc;
  976. int xLoc2 = xLoc1 + STD_TOWN_LOC_WIDTH - 1;
  977. int yLoc2 = yLoc1 + STD_TOWN_LOC_HEIGHT - 1;
  978. if(xLoc2>=max_x_loc || yLoc2>=max_y_loc)
  979. return 0;
  980. Location* locPtr;
  981. for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
  982. {
  983. locPtr = get_loc(xLoc1, yLoc);
  984. for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
  985. {
  986. // ##### patch begin Gilbert 14/3 ######//
  987. // allow the building unit to stand in the area
  988. if( !locPtr->can_build_town() &&
  989. (!locPtr->has_unit(UNIT_LAND) || locPtr->unit_recno(UNIT_LAND)!=unitRecno) )
  990. return 0;
  991. // ##### patch end Gilbert 14/3 ######//
  992. }
  993. }
  994. return 1;
  995. }
  996. //--------- End of function World::can_build_town ---------//
  997. //-------- Begin of function World::can_build_wall ---------//
  998. //
  999. // <int> xLoc, yLoc = the coordination of the area to can_build
  1000. // <int> nationRecno = recno of the builder nation.
  1001. //
  1002. int World::can_build_wall(int xLoc, int yLoc, short nationRecno)
  1003. {
  1004. Location* locPtr = get_loc(xLoc, yLoc);
  1005. return locPtr->can_build_wall() && locPtr->power_nation_recno == nationRecno;
  1006. }
  1007. //--------- End of function World::can_build_wall ---------//
  1008. //-------- Begin of function World::can_destruct_wall ---------//
  1009. //
  1010. // <int> xLoc, yLoc = the coordination of the area to can_build
  1011. // <int> nationRecno = recno of the builder nation.
  1012. //
  1013. int World::can_destruct_wall(int xLoc, int yLoc, short nationRecno)
  1014. {
  1015. Location* locPtr = get_loc(xLoc, yLoc);
  1016. return locPtr->is_wall() && locPtr->power_nation_recno == nationRecno;
  1017. }
  1018. //--------- End of function World::can_destruct_wall ---------//
  1019. //---------- Begin of function World::draw_link_line -----------//
  1020. //
  1021. // <int> srcFirmId - id. of the source firm.
  1022. // 0 if the source is a town
  1023. // <int> srcTownRecno - town recno of the source town
  1024. // 0 if the source is a firm
  1025. // <int> srcXLoc1, srcYLoc1 - the location of the source area
  1026. // srcXLoc2, srcYLoc2
  1027. //
  1028. // [int] giveEffectiveDis - use this value as the effective distance if this is given
  1029. // (default: 0)
  1030. //
  1031. void World::draw_link_line(int srcFirmId, int srcTownRecno, int srcXLoc1,
  1032. int srcYLoc1, int srcXLoc2, int srcYLoc2, int givenEffectiveDis)
  1033. {
  1034. if( srcFirmId == FIRM_INN ) // FirmInn's link is only for scan for neighbor inns quickly, the link line is not displayed
  1035. return;
  1036. //--------------------------------------//
  1037. int srcXLoc = (srcXLoc1 + srcXLoc2)/2;
  1038. int srcYLoc = (srcYLoc1 + srcYLoc2)/2;
  1039. int srcX = ( ZOOM_X1 + (srcXLoc1-zoom_matrix->top_x_loc) * ZOOM_LOC_WIDTH
  1040. + ZOOM_X1 + (srcXLoc2-zoom_matrix->top_x_loc+1) * ZOOM_LOC_WIDTH ) / 2;
  1041. int srcY = ( ZOOM_Y1 + (srcYLoc1-zoom_matrix->top_y_loc) * ZOOM_LOC_HEIGHT
  1042. + ZOOM_Y1 + (srcYLoc2-zoom_matrix->top_y_loc+1) * ZOOM_LOC_HEIGHT ) / 2;
  1043. //------- draw lines connected to town ---------//
  1044. int i, townX, townY, effectiveDis;
  1045. Town* townPtr;
  1046. if( givenEffectiveDis )
  1047. effectiveDis = givenEffectiveDis;
  1048. else
  1049. {
  1050. if( srcFirmId )
  1051. effectiveDis = EFFECTIVE_FIRM_TOWN_DISTANCE;
  1052. else
  1053. effectiveDis = EFFECTIVE_TOWN_TOWN_DISTANCE;
  1054. }
  1055. if( !srcFirmId || firm_res[srcFirmId]->is_linkable_to_town ) // don't draw link line to town if it's an inn
  1056. {
  1057. for( i=town_array.size() ; i>0 ; i-- )
  1058. {
  1059. if( town_array.is_deleted(i) )
  1060. continue;
  1061. townPtr = town_array[i];
  1062. if( srcTownRecno && townPtr->town_recno != srcTownRecno )
  1063. continue;
  1064. //-------- check the distance --------//
  1065. if( m.points_distance( townPtr->center_x, townPtr->center_y,
  1066. srcXLoc, srcYLoc ) > effectiveDis )
  1067. {
  1068. continue;
  1069. }
  1070. //------ check if both are on the same terrain type ------//
  1071. if( (world.get_loc(townPtr->center_x, townPtr->center_y)->is_plateau()==1)
  1072. != (world.get_loc(srcXLoc, srcYLoc)->is_plateau()==1) )
  1073. {
  1074. continue;
  1075. }
  1076. //---------- draw line now -----------//
  1077. townX = ( ZOOM_X1 + (townPtr->loc_x1-zoom_matrix->top_x_loc) * ZOOM_LOC_WIDTH
  1078. + ZOOM_X1 + (townPtr->loc_x2-zoom_matrix->top_x_loc+1) * ZOOM_LOC_WIDTH ) / 2;
  1079. townY = ( ZOOM_Y1 + (townPtr->loc_y1-zoom_matrix->top_y_loc) * ZOOM_LOC_HEIGHT
  1080. + ZOOM_Y1 + (townPtr->loc_y2-zoom_matrix->top_y_loc+1) * ZOOM_LOC_HEIGHT ) / 2;
  1081. anim_line.draw_line(&vga_back, srcX, srcY, townX, townY);
  1082. }
  1083. }
  1084. //------- draw lines connected to firms ---------//
  1085. if( givenEffectiveDis )
  1086. effectiveDis = givenEffectiveDis;
  1087. else
  1088. {
  1089. if( srcFirmId )
  1090. effectiveDis = EFFECTIVE_FIRM_FIRM_DISTANCE;
  1091. else
  1092. effectiveDis = EFFECTIVE_FIRM_TOWN_DISTANCE;
  1093. }
  1094. int firmX, firmY, linkFlag;
  1095. Firm* firmPtr;
  1096. for( i=firm_array.size() ; i>0 ; i-- )
  1097. {
  1098. if( firm_array.is_deleted(i) )
  1099. continue;
  1100. firmPtr = firm_array[i];
  1101. //------ only link if the firms have relationship -----//
  1102. if( srcFirmId )
  1103. linkFlag = firm_res[firmPtr->firm_id]->is_linkable_to_firm(srcFirmId);
  1104. else
  1105. linkFlag = firm_res[firmPtr->firm_id]->is_linkable_to_town;
  1106. if( !linkFlag )
  1107. continue;
  1108. //-------- check the distance --------//
  1109. if( m.points_distance( firmPtr->center_x, firmPtr->center_y,
  1110. srcXLoc, srcYLoc ) > effectiveDis )
  1111. {
  1112. continue;
  1113. }
  1114. //------ check if both are on the same terrain type ------//
  1115. if( (world.get_loc(firmPtr->center_x, firmPtr->center_y)->is_plateau()==1)
  1116. != (world.get_loc(srcXLoc, srcYLoc)->is_plateau()==1) )
  1117. {
  1118. continue;
  1119. }
  1120. //---------- draw line now -----------//
  1121. firmX = ( ZOOM_X1 + (firmPtr->loc_x1-zoom_matrix->top_x_loc) * ZOOM_LOC_WIDTH
  1122. + ZOOM_X1 + (firmPtr->loc_x2-zoom_matrix->top_x_loc+1) * ZOOM_LOC_WIDTH ) / 2;
  1123. firmY = ( ZOOM_Y1 + (firmPtr->loc_y1-zoom_matrix->top_y_loc) * ZOOM_LOC_HEIGHT
  1124. + ZOOM_Y1 + (firmPtr->loc_y2-zoom_matrix->top_y_loc+1) * ZOOM_LOC_HEIGHT ) / 2;
  1125. anim_line.draw_line(&vga_back, srcX, srcY, firmX, firmY);
  1126. }
  1127. }
  1128. //----------- End of function World::draw_link_line ------------//
  1129. //-------- Begin of function World::set_surr_power_off ---------//
  1130. void World::set_surr_power_off(int xLoc, int yLoc)
  1131. {
  1132. if(xLoc>0) // west
  1133. get_loc(xLoc-1, yLoc)->set_power_off();
  1134. if(xLoc<max_x_loc-1)
  1135. get_loc(xLoc+1, yLoc)->set_power_off();
  1136. if(yLoc>0) // north
  1137. get_loc(xLoc, yLoc-1)->set_power_off();
  1138. if(yLoc<max_y_loc-1) // south
  1139. get_loc(xLoc, yLoc+1)->set_power_off();
  1140. }
  1141. //----------- End of function World::set_surr_power_off ------------//
  1142. //-------- Begin of function World::set_all_power ---------//
  1143. //
  1144. void World::set_all_power()
  1145. {
  1146. //--------- set town's influence -----------//
  1147. Town* townPtr;
  1148. int i;
  1149. for( i=town_array.size() ; i>0 ; i-- )
  1150. {
  1151. if( town_array.is_deleted(i) )
  1152. continue;
  1153. townPtr = town_array[i];
  1154. if( !townPtr->nation_recno )
  1155. continue;
  1156. //------- set the influence range of this town -----//
  1157. set_power(townPtr->loc_x1, townPtr->loc_y1, townPtr->loc_x2, townPtr->loc_y2, (char)townPtr->nation_recno);
  1158. }
  1159. //--------- set firm's influence -----------//
  1160. Firm* firmPtr;
  1161. for( i=firm_array.size() ; i>0 ; i-- )
  1162. {
  1163. if( firm_array.is_deleted(i) )
  1164. continue;
  1165. firmPtr = firm_array[i];
  1166. if( !firmPtr->nation_recno )
  1167. continue;
  1168. if( !firmPtr->should_set_power )
  1169. continue;
  1170. //------- set the influence range of this firm -----//
  1171. set_power(firmPtr->loc_x1, firmPtr->loc_y1, firmPtr->loc_x2, firmPtr->loc_y2, (char)firmPtr->nation_recno);
  1172. }
  1173. }
  1174. //--------- End of function World::set_all_power ---------//
  1175. //-------- Begin of function World::set_power ---------//
  1176. //
  1177. // <int> xLoc1, yLoc1, - area on the map which the power should be set
  1178. // xLoc2, yLoc2
  1179. //
  1180. // <int> nationRcno - nation recno
  1181. //
  1182. void World::set_power(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int nationRecno)
  1183. {
  1184. //------- reset power_nation_recno first ------//
  1185. int plateauResult = (get_loc((xLoc1+xLoc2)/2, (yLoc1+yLoc2)/2)->is_plateau()==1);
  1186. int xLoc, yLoc, centerY, t;
  1187. Location* locPtr = loc_matrix;
  1188. xLoc1 = max( 0, xLoc1 - EFFECTIVE_POWER_DISTANCE+1);
  1189. yLoc1 = max( 0, yLoc1 - EFFECTIVE_POWER_DISTANCE+1);
  1190. xLoc2 = min( MAX_WORLD_X_LOC-1, xLoc2 + EFFECTIVE_POWER_DISTANCE-1);
  1191. yLoc2 = min( MAX_WORLD_Y_LOC-1, yLoc2 + EFFECTIVE_POWER_DISTANCE-1);
  1192. centerY = (yLoc1+yLoc2) / 2;
  1193. for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
  1194. {
  1195. t=abs(yLoc-centerY)/2;
  1196. for( xLoc=xLoc1+t ; xLoc<=xLoc2-t ; xLoc++, locPtr++ )
  1197. {
  1198. locPtr = get_loc(xLoc, yLoc);
  1199. if(locPtr->sailable())//if(!locPtr->walkable())
  1200. continue;
  1201. if(locPtr->is_power_off())
  1202. continue;
  1203. if((locPtr->is_plateau()==1) != plateauResult)
  1204. continue;
  1205. if(locPtr->power_nation_recno==0)
  1206. {
  1207. locPtr->power_nation_recno = nationRecno;
  1208. sys.map_need_redraw = 1; // request redrawing the map next time
  1209. }
  1210. }
  1211. }
  1212. }
  1213. //--------- End of function World::set_power ---------//
  1214. //-------- Begin of function World::restore_power ---------//
  1215. //
  1216. // <int> xLoc1, yLoc1, - area on the map which the power should be restored
  1217. // xLoc2, yLoc2
  1218. //
  1219. // <int> townRecno, firmRecno - either one
  1220. //
  1221. void World::restore_power(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int townRecno, int firmRecno)
  1222. {
  1223. int nationRecno;
  1224. if( townRecno )
  1225. {
  1226. nationRecno = town_array[townRecno]->nation_recno;
  1227. town_array[townRecno]->nation_recno = 0;
  1228. }
  1229. if( firmRecno )
  1230. {
  1231. nationRecno = firm_array[firmRecno]->nation_recno;
  1232. firm_array[firmRecno]->nation_recno = 0;
  1233. }
  1234. //------- reset power_nation_recno first ------//
  1235. int xLoc, yLoc, centerY, t;
  1236. Location* locPtr = loc_matrix;
  1237. xLoc1 = max( 0, xLoc1 - EFFECTIVE_POWER_DISTANCE+1);
  1238. yLoc1 = max( 0, yLoc1 - EFFECTIVE_POWER_DISTANCE+1);
  1239. xLoc2 = min( MAX_WORLD_X_LOC-1, xLoc2 + EFFECTIVE_POWER_DISTANCE-1);
  1240. yLoc2 = min( MAX_WORLD_Y_LOC-1, yLoc2 + EFFECTIVE_POWER_DISTANCE-1);
  1241. centerY = (yLoc1+yLoc2) / 2;
  1242. for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
  1243. {
  1244. t=abs(yLoc-centerY)/2;
  1245. for( xLoc=xLoc1+t ; xLoc<=xLoc2-t ; xLoc++, locPtr++ )
  1246. {
  1247. locPtr = get_loc(xLoc, yLoc);
  1248. if( locPtr->power_nation_recno==nationRecno )
  1249. {
  1250. locPtr->power_nation_recno = 0;
  1251. sys.map_need_redraw = 1; // request redrawing the map next time
  1252. }
  1253. }
  1254. }
  1255. //--- if some power areas are freed up, see if neighbor towns/firms should take up these power areas ----//
  1256. if( sys.map_need_redraw ) // when calls set_all_power(), the nation_recno of the calling firm must be reset
  1257. set_all_power();
  1258. //------- restore the nation recno of the calling town/firm -------//
  1259. if( townRecno )
  1260. town_array[townRecno]->nation_recno = nationRecno;
  1261. if( firmRecno )
  1262. firm_array[firmRecno]->nation_recno = nationRecno;
  1263. }
  1264. //--------- End of function World::restore_power ---------//
  1265. //-------- Begin of function World::detect_firm_town ---------//
  1266. //
  1267. int World::detect_firm_town()
  1268. {
  1269. // ##### begin Gilbert 19/9 ########//
  1270. // int rc = mouse.single_click(ZOOM_X1, ZOOM_Y1, ZOOM_X2, ZOOM_Y2, 2);
  1271. if( !mouse.any_click(ZOOM_X1, ZOOM_Y1, ZOOM_X2, ZOOM_Y2, 2) )
  1272. return 0;
  1273. // ##### end Gilbert 19/9 ########//
  1274. //------ detect pressing on link enable/disable sign -----//
  1275. Firm* firmPtr;
  1276. if( firm_array.selected_recno )
  1277. {
  1278. firmPtr = firm_array[firm_array.selected_recno];
  1279. if( firmPtr->should_show_info() && // only if should_show_info() is 1, we can detect links from this firm (it is not limited to player firms, as firms with player's workers should be allowed for resigning the player worker from the firm
  1280. firmPtr->draw_detect_link_line(1) ) // 1-detect action
  1281. {
  1282. return 1;
  1283. }
  1284. }
  1285. Town* townPtr;
  1286. if( town_array.selected_recno )
  1287. {
  1288. townPtr = town_array[town_array.selected_recno];
  1289. if( townPtr->nation_recno==nation_array.player_recno &&
  1290. townPtr->draw_detect_link_line(1) ) // 1-detect action
  1291. {
  1292. return 1;
  1293. }
  1294. }
  1295. // ####### begin Gilbert 12/9 #########// see Power::detect_select
  1296. /*
  1297. //--------------- detect firm ------------------//
  1298. if( rc==1 ) // left click
  1299. {
  1300. int mouseAbsX = mouse.cur_x - ZOOM_X1 + World::view_top_x;
  1301. int mouseAbsY = mouse.cur_y - ZOOM_Y1 + World::view_top_y;
  1302. int i;
  1303. for( i=firm_array.size() ; i>0 ; i-- )
  1304. {
  1305. if( firm_array.is_deleted(i) )
  1306. continue;
  1307. firmPtr = firm_array[i];
  1308. if( m.is_touch( mouseAbsX, mouseAbsY, mouseAbsX, mouseAbsY,
  1309. firmPtr->abs_x1, firmPtr->abs_y1, firmPtr->abs_x2, firmPtr->abs_y2 ) )
  1310. {
  1311. power.reset_selection();
  1312. firm_array.selected_recno = i;
  1313. info.disp();
  1314. // -------- sound effect -----------//
  1315. if( firmPtr->nation_recno == nation_array.player_recno && se_res.mark_select_object_time() )
  1316. {
  1317. se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
  1318. 'F', firmPtr->firm_id, firmPtr->under_construction ? "SELU" : "SEL" );
  1319. }
  1320. return 1;
  1321. }
  1322. }
  1323. //----------- detect town section --------------//
  1324. for( i=town_array.size() ; i>0 ; i-- )
  1325. {
  1326. if( town_array.is_deleted(i) )
  1327. continue;
  1328. townPtr = town_array[i];
  1329. if( m.is_touch( mouseAbsX, mouseAbsY, mouseAbsX, mouseAbsY,
  1330. townPtr->abs_x1, townPtr->abs_y1, townPtr->abs_x2, townPtr->abs_y2 ) )
  1331. {
  1332. power.reset_selection();
  1333. town_array.selected_recno = i;
  1334. info.disp();
  1335. // -------- sound effect -----------//
  1336. if( townPtr->nation_recno == nation_array.player_recno
  1337. && se_res.mark_select_object_time() )
  1338. {
  1339. se_res.sound(townPtr->center_x, townPtr->center_y, 1,
  1340. 'T', 0, "SEL" );
  1341. }
  1342. return 1;
  1343. }
  1344. }
  1345. }
  1346. */
  1347. return 0;
  1348. }
  1349. //-------- End of function World::detect_firm_town ---------//
  1350. //-------- Begin of function World::earth_equake ------//
  1351. void World::earth_quake()
  1352. {
  1353. Location *locPtr;
  1354. int x,y;
  1355. for(y = 0; y < max_y_loc; ++y)
  1356. {
  1357. locPtr = get_loc(0,y);
  1358. for( x = 0; x < max_x_loc; ++x, ++locPtr)
  1359. {
  1360. if(locPtr->is_wall() )
  1361. {
  1362. locPtr->attack_wall( weather.quake_rate(x,y) /2 );
  1363. }
  1364. }
  1365. }
  1366. int firmDamage = 0;
  1367. int firmDie = 0;
  1368. int i;
  1369. for( i=firm_array.size() ; i>0 ; i-- )
  1370. {
  1371. if( firm_array.is_deleted(i) || !firm_res[firm_array[i]->firm_id]->buildable)
  1372. continue;
  1373. Firm *firmPtr = firm_array[i];
  1374. x = firmPtr->center_x;
  1375. y = firmPtr->center_y;
  1376. firmPtr->hit_points -= weather.quake_rate(x,y);
  1377. if( firmPtr->own_firm() )
  1378. firmDamage++;
  1379. if( firmPtr->hit_points <= 0)
  1380. {
  1381. firmPtr->hit_points = (float) 0;
  1382. if( firmPtr->own_firm() )
  1383. firmDie++;
  1384. se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
  1385. 'F', firmPtr->firm_id, "DIE" );
  1386. firm_array.del_firm(i);
  1387. }
  1388. }
  1389. int townDamage = 0;
  1390. for( i=town_array.size() ; i>0 ; i-- )
  1391. {
  1392. if( town_array.is_deleted(i) )
  1393. continue;
  1394. Town *townPtr = town_array[i];
  1395. int ownTown = townPtr->nation_recno == nation_array.player_recno;
  1396. short beforePopulation = townPtr->population;
  1397. short causalty = weather.quake_rate(townPtr->center_x, townPtr->center_y) / 10;
  1398. for( ; causalty > 0 && !town_array.is_deleted(i); --causalty )
  1399. {
  1400. townPtr->kill_town_people(0);
  1401. }
  1402. if( town_array.is_deleted(i) )
  1403. causalty = beforePopulation;
  1404. else
  1405. causalty = beforePopulation - townPtr->population;
  1406. if(ownTown)
  1407. townDamage += causalty;
  1408. }
  1409. int unitDamage = 0;
  1410. int unitDie = 0;
  1411. for( i=unit_array.size(); i > 0; i-- )
  1412. {
  1413. if( unit_array.is_deleted(i))
  1414. continue;
  1415. Unit *unitPtr = unit_array[i];
  1416. // ###### begin Gilbert 30/8 ######//
  1417. // no damage to air unit , sea unit or overseer
  1418. if( !unitPtr->is_visible() || unitPtr->mobile_type == UNIT_AIR
  1419. || unitPtr->mobile_type == UNIT_SEA)
  1420. continue;
  1421. // ###### end Gilbert 30/8 ######//
  1422. float damage = (float) weather.quake_rate(unitPtr->cur_x_loc(),unitPtr->cur_y_loc() ) *
  1423. unitPtr->max_hit_points / 200;
  1424. if( damage >= unitPtr->hit_points)
  1425. damage = unitPtr->hit_points -1;
  1426. if( damage < (float) 5)
  1427. damage = (float) 5;
  1428. unitPtr->hit_points -= damage;
  1429. if( unitPtr->is_own() )
  1430. unitDamage++;
  1431. if( unitPtr->hit_points <= 0)
  1432. {
  1433. unitPtr->hit_points = (float) 0;
  1434. if( unitPtr->is_own() )
  1435. unitDie++;
  1436. }
  1437. else
  1438. {
  1439. if( unit_res[unitPtr->unit_id]->solider_id &&
  1440. weather.quake_rate(unitPtr->cur_x_loc(),unitPtr->cur_y_loc()) >= 60)
  1441. {
  1442. ((UnitVehicle *)unitPtr)->dismount();
  1443. }
  1444. }
  1445. }
  1446. news_array.earthquake_damage(unitDamage-unitDie, unitDie, townDamage, firmDamage-firmDie, firmDie);
  1447. }
  1448. //-------- End of function World::earth_equake ------//
  1449. //-------- Begin of function World::lightning_strike ------//
  1450. void World::lightning_strike(short cx, short cy, short radius)
  1451. {
  1452. short x, y;
  1453. for( y = cy-radius; y <= cy+radius; ++y)
  1454. {
  1455. if( y < 0 || y >= max_y_loc)
  1456. continue;
  1457. for( x = cx-radius; x <= cx+radius; ++x)
  1458. {
  1459. if( x < 0 || x >= max_x_loc)
  1460. continue;
  1461. Location *locPtr = get_loc(x,y);
  1462. if( locPtr->is_plant() )
  1463. {
  1464. // ---- add a fire on it ------//
  1465. locPtr->set_fire_str(80);
  1466. // ##### begin Gilbert 11/8 #####//
  1467. if( locPtr->can_set_fire() && locPtr->fire_str() < 5 )
  1468. locPtr->set_fire_str(5);
  1469. // ##### end Gilbert 11/8 #####//
  1470. }
  1471. }
  1472. }
  1473. // ------ check hitting units -------//
  1474. int i;
  1475. for( i=unit_array.size(); i > 0; i-- )
  1476. {
  1477. if( unit_array.is_deleted(i))
  1478. continue;
  1479. Unit *unitPtr = unit_array[i];
  1480. // no damage to overseer
  1481. if( !unitPtr->is_visible())
  1482. continue;
  1483. if( unitPtr->cur_x_loc() <= cx+ radius &&
  1484. unitPtr->cur_x_loc() + unitPtr->sprite_info->loc_width > cx-radius &&
  1485. unitPtr->cur_y_loc() <= cy+radius &&
  1486. unitPtr->cur_y_loc() + unitPtr->sprite_info->loc_height > cy-radius )
  1487. {
  1488. unitPtr->hit_points -= (float) unitPtr->sprite_info->lightning_damage / ATTACK_SLOW_DOWN;
  1489. // ---- add news -------//
  1490. if( unitPtr->is_own() )
  1491. news_array.lightning_damage(unitPtr->cur_x_loc(), unitPtr->cur_y_loc(),
  1492. NEWS_LOC_UNIT, i, unitPtr->hit_points <= (float) 0);
  1493. if( unitPtr->hit_points <= 0)
  1494. unitPtr->hit_points = (float) 0;
  1495. }
  1496. }
  1497. for( i=firm_array.size() ; i>0 ; i-- )
  1498. {
  1499. if( firm_array.is_deleted(i) || !firm_res[firm_array[i]->firm_id]->buildable)
  1500. continue;
  1501. Firm *firmPtr = firm_array[i];
  1502. if( firmPtr->loc_x1 <= cx+radius &&
  1503. firmPtr->loc_x2 >= cx-radius &&
  1504. firmPtr->loc_y1 <= cy+radius &&
  1505. firmPtr->loc_y2 >= cy-radius)
  1506. {
  1507. firmPtr->hit_points -= (float) 50 / ATTACK_SLOW_DOWN;
  1508. // ---- add news -------//
  1509. if( firmPtr->own_firm() )
  1510. news_array.lightning_damage(firmPtr->center_x, firmPtr->center_y,
  1511. NEWS_LOC_FIRM, i, firmPtr->hit_points <= (float) 0);
  1512. // ---- add a fire on it ------//
  1513. Location *locPtr = get_loc(firmPtr->center_x, firmPtr->center_y);
  1514. if( locPtr->can_set_fire() && locPtr->fire_str() < 5 )
  1515. locPtr->set_fire_str(5);
  1516. if( firmPtr->hit_points <= 0)
  1517. {
  1518. firmPtr->hit_points = (float) 0;
  1519. se_res.sound(firmPtr->center_x, firmPtr->center_y, 1,
  1520. 'F', firmPtr->firm_id, "DIE" );
  1521. firm_array.del_firm(i);
  1522. }
  1523. }
  1524. }
  1525. for( i=town_array.size() ; i>0 ; i-- )
  1526. {
  1527. if( town_array.is_deleted(i))
  1528. continue;
  1529. Town *townPtr = town_array[i];
  1530. if( townPtr->loc_x1 <= cx+radius &&
  1531. townPtr->loc_x2 >= cx-radius &&
  1532. townPtr->loc_y1 <= cy+radius &&
  1533. townPtr->loc_y2 >= cy-radius)
  1534. {
  1535. // ---- add news -------//
  1536. if( townPtr->nation_recno == nation_array.player_recno )
  1537. news_array.lightning_damage(townPtr->center_x, townPtr->center_y,
  1538. NEWS_LOC_TOWN, i, 0);
  1539. // ---- add a fire on it ------//
  1540. // ####### begin Gilbert 11/8 #########//
  1541. Location *locPtr = get_loc(townPtr->center_x, townPtr->center_y);
  1542. if( locPtr->can_set_fire() && locPtr->fire_str() < 5)
  1543. locPtr->set_fire_str(5);
  1544. // ####### end Gilbert 11/8 #########//
  1545. townPtr->kill_town_people(0);
  1546. }
  1547. }
  1548. }
  1549. //-------- End of function World::lightning_strike -------//
  1550. // ------- Begin of function World::visit -----------//
  1551. // set the visit_level surrounding unit, town and firm
  1552. void World::visit(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int range, int extend)
  1553. {
  1554. if(config.fog_of_war)
  1555. {
  1556. int left = max( 0, xLoc1 - range);
  1557. int top = max( 0, yLoc1 - range);
  1558. int right = min( MAX_WORLD_X_LOC-1, xLoc2 + range);
  1559. int bottom = min( MAX_WORLD_Y_LOC-1, yLoc2 + range);
  1560. // ----- mark the visit_level of the square around the unit ------//
  1561. for( int yLoc=top ; yLoc<=bottom ; yLoc++ )
  1562. {
  1563. Location *locPtr = get_loc(left, yLoc);
  1564. for( int xLoc=left ; xLoc<=right ; xLoc++, locPtr++ )
  1565. {
  1566. locPtr->set_visited();
  1567. }
  1568. }
  1569. // ----- visit_level decreasing outside the visible range ------//
  1570. if( extend > 0)
  1571. {
  1572. int visitLevel = FULL_VISIBILITY;
  1573. int levelDrop = (FULL_VISIBILITY - EXPLORED_VISIBILITY) / (extend+1);
  1574. xLoc1 -= range;
  1575. xLoc2 += range;
  1576. yLoc1 -= range;
  1577. yLoc2 += range;
  1578. for( ++range; extend > 0; --extend, ++range)
  1579. {
  1580. xLoc1--;
  1581. xLoc2++;
  1582. yLoc1--;
  1583. yLoc2++;
  1584. visitLevel -= levelDrop;
  1585. visit_shell(xLoc1, yLoc1, xLoc2, yLoc2, visitLevel);
  1586. }
  1587. }
  1588. }
  1589. }
  1590. // ------- End of function World::visit -----------//
  1591. // ------- Begin of function World::visit_shell -----------//
  1592. // set specific visit_level on the surrounding unit, town and firm
  1593. void World::visit_shell(int xLoc1, int yLoc1, int xLoc2, int yLoc2, int visitLevel)
  1594. {
  1595. int left = max( 0, xLoc1 );
  1596. int top = max( 0, yLoc1 );
  1597. int right = min( MAX_WORLD_X_LOC-1, xLoc2);
  1598. int bottom = min( MAX_WORLD_Y_LOC-1, yLoc2);
  1599. // ------- top side ---------//
  1600. if( yLoc1 >= 0)
  1601. {
  1602. Location *locPtr = get_loc( left, yLoc1);
  1603. for( int x = left; x <= right; ++x, ++locPtr)
  1604. locPtr->set_visited(visitLevel);
  1605. }
  1606. // ------- bottom side ---------//
  1607. if( yLoc2 < max_y_loc)
  1608. {
  1609. Location *locPtr = get_loc( left, yLoc2);
  1610. for( int x = left; x <= right; ++x, ++locPtr)
  1611. locPtr->set_visited(visitLevel);
  1612. }
  1613. // ------- left side -----------//
  1614. if( xLoc1 >= 0)
  1615. {
  1616. for( int y = top; y <= bottom; ++y)
  1617. {
  1618. get_loc(xLoc1,y)->set_visited(visitLevel);
  1619. }
  1620. }
  1621. // ------- right side -----------//
  1622. if( xLoc2 < max_x_loc)
  1623. {
  1624. for( int y = top; y <= bottom; ++y)
  1625. {
  1626. get_loc(xLoc2,y)->set_visited(visitLevel);
  1627. }
  1628. }
  1629. }
  1630. // ------- End of function World::visit_shell -----------//
  1631. //------- Begin of function World::process_visibility -----------//
  1632. void World::process_visibility()
  1633. {
  1634. if( config.fog_of_war )
  1635. {
  1636. // ###### begin Gilbert 13/10 ########//
  1637. //for( int y = 0; y < max_y_loc; ++y)
  1638. //{
  1639. // Location *locPtr = get_loc(0,y);
  1640. // for( int x = 0; x < max_x_loc; ++x, ++locPtr)
  1641. // {
  1642. // locPtr->dec_visibility();
  1643. // }
  1644. //}
  1645. int count = max_x_loc * max_y_loc;
  1646. const int sizeOfLoc = sizeof(Location);
  1647. unsigned char *locVisitLevel = &get_loc(0,0)->visit_level;
  1648. unsigned char decVisitLevel = EXPLORED_VISIBILITY*2+1;
  1649. /* Original Visual C++ assembly code for reference
  1650. _asm
  1651. {
  1652. mov ecx, count
  1653. mov ebx, locVisitLevel
  1654. mov edx, sizeOfLoc
  1655. mov ah, decVisitLevel
  1656. process_visit_level_1:
  1657. mov al,[ebx]
  1658. cmp al,ah // if(al > EXPLORED_VISIBILITY*2) al--;
  1659. cmc
  1660. sbb al,0
  1661. mov [ebx],al
  1662. add ebx, edx
  1663. loop process_visit_level_1
  1664. }
  1665. */
  1666. __asm__ __volatile__ (
  1667. "movb %0, %%ah\n"
  1668. "process_visit_level_1:\n\t"
  1669. "movb (%%ebx), %%al\n\t"
  1670. "cmpb %%ah, %%al\n\t"
  1671. "cmc\n\t"
  1672. "sbbb $0, %%al\n\t"
  1673. "movb %%al, (%%ebx)\n\t"
  1674. "addl %%edx, %%ebx\n\t"
  1675. "loop process_visit_level_1\n\t"
  1676. :
  1677. : "m"(decVisitLevel), "b"(locVisitLevel), "c"(count), "d"(sizeOfLoc)
  1678. : "%eax"
  1679. );
  1680. // ###### end Gilbert 13/10 ########//
  1681. }
  1682. }
  1683. //------- End of function World::process_visibility -----------//
  1684. //--------- Begin of function World::disp_next --------//
  1685. //
  1686. // Display the next object of the same type.
  1687. //
  1688. // <int> seekDir : -1 - display the previous one in the list.
  1689. // 1 - display the next one in the list.
  1690. //
  1691. // <int> sameNation - whether display the next object of the same
  1692. // nation only or of any nation.
  1693. //
  1694. void World::disp_next(int seekDir, int sameNation)
  1695. {
  1696. //--- if the selected one is a unit ----//
  1697. if( unit_array.selected_recno )
  1698. {
  1699. int unitRecno = unit_array.selected_recno;
  1700. Unit* unitPtr = unit_array[unit_array.selected_recno];
  1701. int unitClass = unit_res[unitPtr->unit_id]->unit_class;
  1702. int nationRecno = unitPtr->nation_recno;
  1703. while(1)
  1704. {
  1705. if( seekDir < 0 )
  1706. {
  1707. unitRecno--;
  1708. if( unitRecno < 1 )
  1709. unitRecno = unit_array.size();
  1710. }
  1711. else
  1712. {
  1713. unitRecno++;
  1714. if( unitRecno > unit_array.size() )
  1715. unitRecno = 1;
  1716. }
  1717. if( unit_array.is_deleted(unitRecno) )
  1718. continue;
  1719. unitPtr = unit_array[unitRecno];
  1720. if( !unitPtr->is_visible() )
  1721. continue;
  1722. //--- check if the location of the unit has been explored ---//
  1723. if( !world.get_loc(unitPtr->next_x_loc(), unitPtr->next_y_loc())->explored() )
  1724. continue;
  1725. //-------- if are of the same nation --------//
  1726. if( sameNation && unitPtr->nation_recno != nationRecno )
  1727. continue;
  1728. //---------------------------------//
  1729. if( unit_res[unitPtr->unit_id]->unit_class == unitClass )
  1730. {
  1731. power.reset_selection();
  1732. unitPtr->selected_flag = 1;
  1733. unit_array.selected_recno = unitRecno;
  1734. unit_array.selected_count++;
  1735. world.go_loc( unitPtr->cur_x_loc(), unitPtr->cur_y_loc() );
  1736. return;
  1737. }
  1738. //--- if the recno loops back to the starting one ---//
  1739. if( unitRecno == unit_array.selected_recno )
  1740. break;
  1741. }
  1742. }
  1743. //--- if the selected one is a firm ----//
  1744. if( firm_array.selected_recno )
  1745. {
  1746. int firmRecno = firm_array.selected_recno;
  1747. Firm* firmPtr = firm_array[firm_array.selected_recno];
  1748. int firmId = firmPtr->firm_id;
  1749. int nationRecno = firmPtr->nation_recno;
  1750. while(1)
  1751. {
  1752. if( seekDir < 0 )
  1753. {
  1754. firmRecno--;
  1755. if( firmRecno < 1 )
  1756. firmRecno = firm_array.size();
  1757. }
  1758. else
  1759. {
  1760. firmRecno++;
  1761. if( firmRecno > firm_array.size() )
  1762. firmRecno = 1;
  1763. }
  1764. if( firm_array.is_deleted(firmRecno) )
  1765. continue;
  1766. firmPtr = firm_array[firmRecno];
  1767. //-------- if are of the same nation --------//
  1768. if( sameNation && firmPtr->nation_recno != nationRecno )
  1769. continue;
  1770. //--- check if the location of this firm has been explored ---//
  1771. if( !world.get_loc(firmPtr->center_x, firmPtr->center_y)->explored() )
  1772. continue;
  1773. //---------------------------------//
  1774. if( firmPtr->firm_id == firmId )
  1775. {
  1776. power.reset_selection();
  1777. firm_array.selected_recno = firmRecno;
  1778. world.go_loc( firmPtr->center_x, firmPtr->center_y );
  1779. return;
  1780. }
  1781. //--- if the recno loops back to the starting one ---//
  1782. if( firmRecno == firm_array.selected_recno )
  1783. break;
  1784. }
  1785. }
  1786. //--- if the selected one is a town ----//
  1787. if( town_array.selected_recno )
  1788. {
  1789. int townRecno = town_array.selected_recno;
  1790. int nationRecno = town_array[townRecno]->nation_recno;
  1791. Town* townPtr;
  1792. while(1)
  1793. {
  1794. if( seekDir < 0 )
  1795. {
  1796. townRecno--;
  1797. if( townRecno < 1 )
  1798. townRecno = town_array.size();
  1799. }
  1800. else
  1801. {
  1802. townRecno++;
  1803. if( townRecno > town_array.size() )
  1804. townRecno = 1;
  1805. }
  1806. if( town_array.is_deleted(townRecno) )
  1807. continue;
  1808. townPtr = town_array[townRecno];
  1809. //-------- if are of the same nation --------//
  1810. if( sameNation && townPtr->nation_recno != nationRecno )
  1811. continue;
  1812. //--- check if the location of this town has been explored ---//
  1813. if( !world.get_loc(townPtr->center_x, townPtr->center_y)->explored() )
  1814. continue;
  1815. //---------------------------------//
  1816. power.reset_selection();
  1817. town_array.selected_recno = townRecno;
  1818. world.go_loc( townPtr->center_x, townPtr->center_y );
  1819. return;
  1820. //--- if the recno loops back to the starting one ---//
  1821. if( townRecno == town_array.selected_recno )
  1822. break;
  1823. }
  1824. }
  1825. //--- if the selected one is a natural resource site ----//
  1826. if( site_array.selected_recno )
  1827. {
  1828. int siteRecno = site_array.selected_recno;
  1829. Site* sitePtr = site_array[site_array.selected_recno];
  1830. int siteType = sitePtr->site_type;
  1831. while(1)
  1832. {
  1833. if( seekDir < 0 )
  1834. {
  1835. siteRecno--;
  1836. if( siteRecno < 1 )
  1837. siteRecno = site_array.size();
  1838. }
  1839. else
  1840. {
  1841. siteRecno++;
  1842. if( siteRecno > site_array.size() )
  1843. siteRecno = 1;
  1844. }
  1845. if( site_array.is_deleted(siteRecno) )
  1846. continue;
  1847. sitePtr = site_array[siteRecno];
  1848. //--- check if the location of this site has been explored ---//
  1849. if( !world.get_loc(sitePtr->map_x_loc, sitePtr->map_y_loc)->explored() )
  1850. continue;
  1851. //---------------------------------//
  1852. if( sitePtr->site_type == siteType )
  1853. {
  1854. power.reset_selection();
  1855. site_array.selected_recno = siteRecno;
  1856. world.go_loc( sitePtr->map_x_loc, sitePtr->map_y_loc );
  1857. return;
  1858. }
  1859. //--- if the recno loops back to the starting one ---//
  1860. if( siteRecno == site_array.selected_recno )
  1861. break;
  1862. }
  1863. }
  1864. }
  1865. //----------- End of function World::disp_next --------//
  1866. #ifdef DEBUG3
  1867. //--------- Begin of function World::get_loc --------//
  1868. //
  1869. Location* World::get_loc(int xLoc, int yLoc)
  1870. {
  1871. err_when( xLoc<0 || xLoc>=MAX_WORLD_X_LOC );
  1872. err_when( yLoc<0 || yLoc>=MAX_WORLD_Y_LOC );
  1873. return loc_matrix + MAX_WORLD_X_LOC * yLoc + xLoc;
  1874. }
  1875. //----------- End of function World::get_loc --------//
  1876. //--------- Begin of function World::get_region_id --------//
  1877. //
  1878. BYTE World::get_region_id(int xLoc, int yLoc)
  1879. {
  1880. err_when( xLoc<0 || xLoc>=MAX_WORLD_X_LOC );
  1881. err_when( yLoc<0 || yLoc>=MAX_WORLD_Y_LOC );
  1882. return loc_matrix[MAX_WORLD_X_LOC*yLoc+xLoc].region_id;
  1883. }
  1884. //----------- End of function World::get_region_id --------//
  1885. #endif
  1886. // ####### begin Gilbert 25/7 #########//
  1887. // return true if any location adjacent to (x,y) is on a particular region
  1888. int World::is_adjacent_region(int x, int y, int regionId)
  1889. {
  1890. if( y > 0 )
  1891. {
  1892. if( x > 0 )
  1893. {
  1894. if( get_region_id(x-1,y-1) == regionId )
  1895. return 1;
  1896. }
  1897. if( get_region_id(x,y-1) == regionId )
  1898. return 1;
  1899. if( x < max_x_loc-1 )
  1900. {
  1901. if( get_region_id(x+1,y-1) == regionId )
  1902. return 1;
  1903. }
  1904. }
  1905. if( x > 0 )
  1906. {
  1907. if( get_region_id(x-1,y) == regionId )
  1908. return 1;
  1909. }
  1910. if( x < max_x_loc-1 )
  1911. {
  1912. if( get_region_id(x+1,y) == regionId )
  1913. return 1;
  1914. }
  1915. if( y < max_y_loc-1)
  1916. {
  1917. if( x > 0 )
  1918. {
  1919. if( get_region_id(x-1,y+1) == regionId )
  1920. return 1;
  1921. }
  1922. if( get_region_id(x,y+1) == regionId )
  1923. return 1;
  1924. if( x < max_x_loc-1 )
  1925. {
  1926. if( get_region_id(x+1,y+1) == regionId )
  1927. return 1;
  1928. }
  1929. }
  1930. return 0;
  1931. }
  1932. // ####### end Gilbert 25/7 #########//